From 6d5cf800cc3bb589fab41a04de3ed69c111ccc3a Mon Sep 17 00:00:00 2001 From: sevenc Date: Tue, 7 Apr 2026 10:10:35 +0000 Subject: [PATCH 1/2] fix(cli): auto-cleanup orphaned gateway container on re-onboard When Ctrl+C interrupts `nemoclaw onboard` during gateway startup, the Docker container (openshell-cluster-nemoclaw) keeps running but OpenShell has no metadata for it. On re-onboard, preflight returns "missing" gateway state and skips cleanup, causing port 8080 conflict. Add orphaned container detection in preflight: when gateway state is "missing", check if the Docker container exists via `docker inspect`. If found, stop and remove it along with associated volumes before proceeding to port checks. Co-Authored-By: Claude Opus 4.6 (1M context) --- bin/lib/onboard.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/bin/lib/onboard.js b/bin/lib/onboard.js index ace8d6e97..36147dbae 100644 --- a/bin/lib/onboard.js +++ b/bin/lib/onboard.js @@ -388,6 +388,28 @@ async function preflight() { console.log(" ✓ Previous session cleaned up"); } + // Clean up orphaned Docker containers from interrupted onboard (e.g. Ctrl+C + // during gateway start). The container may still be running even though + // OpenShell has no metadata for it (gatewayReuseState === "missing"). + if (gatewayReuseState === "missing") { + const containerName = `openshell-cluster-${GATEWAY_NAME}`; + const inspectResult = run( + `docker inspect --type container --format '{{.State.Status}}' ${containerName} 2>/dev/null`, + { ignoreError: true, suppressOutput: true }, + ); + if (inspectResult.status === 0) { + console.log(" Cleaning up orphaned gateway container..."); + run(`docker stop ${containerName} >/dev/null 2>&1`, { ignoreError: true, suppressOutput: true }); + run(`docker rm ${containerName} >/dev/null 2>&1`, { ignoreError: true, suppressOutput: true }); + run( + `docker volume ls -q --filter "name=openshell-cluster-${GATEWAY_NAME}" | grep . && docker volume ls -q --filter "name=openshell-cluster-${GATEWAY_NAME}" | xargs docker volume rm 2>/dev/null || true`, + { ignoreError: true, suppressOutput: true }, + ); + registry.clearAll(); + console.log(" ✓ Orphaned gateway container removed"); + } + } + // Required ports — gateway (8080) and dashboard (18789) const requiredPorts = [ { port: 8080, label: "OpenShell gateway" }, From aea111204af9f836a6e522d6c9b602ffcac1eb2e Mon Sep 17 00:00:00 2001 From: Se7en Date: Tue, 7 Apr 2026 19:15:31 +0800 Subject: [PATCH 2/2] Update bin/lib/onboard.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- bin/lib/onboard.js | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/bin/lib/onboard.js b/bin/lib/onboard.js index a53050b60..4c0eec3be 100644 --- a/bin/lib/onboard.js +++ b/bin/lib/onboard.js @@ -1607,14 +1607,31 @@ async function preflight() { ); if (inspectResult.status === 0) { console.log(" Cleaning up orphaned gateway container..."); - run(`docker stop ${containerName} >/dev/null 2>&1`, { ignoreError: true, suppressOutput: true }); - run(`docker rm ${containerName} >/dev/null 2>&1`, { ignoreError: true, suppressOutput: true }); - run( - `docker volume ls -q --filter "name=openshell-cluster-${GATEWAY_NAME}" | grep . && docker volume ls -q --filter "name=openshell-cluster-${GATEWAY_NAME}" | xargs docker volume rm 2>/dev/null || true`, - { ignoreError: true, suppressOutput: true }, + run(`docker stop ${containerName} >/dev/null 2>&1`, { + ignoreError: true, + suppressOutput: true, + }); + run(`docker rm ${containerName} >/dev/null 2>&1`, { + ignoreError: true, + suppressOutput: true, + }); + const postInspectResult = run( + `docker inspect --type container ${containerName} 2>/dev/null`, + { + ignoreError: true, + suppressOutput: true, + }, ); - registry.clearAll(); - console.log(" ✓ Orphaned gateway container removed"); + if (postInspectResult.status !== 0) { + run( + `docker volume ls -q --filter "name=openshell-cluster-${GATEWAY_NAME}" | grep . && docker volume ls -q --filter "name=openshell-cluster-${GATEWAY_NAME}" | xargs docker volume rm 2>/dev/null || true`, + { ignoreError: true, suppressOutput: true }, + ); + registry.clearAll(); + console.log(" ✓ Orphaned gateway container removed"); + } else { + console.warn(" ! Found an orphaned gateway container, but automatic cleanup failed."); + } } }