@@ -41,6 +41,14 @@ const onboardSession = require("./lib/onboard-session");
4141const { parseLiveSandboxNames } = require ( "./lib/runtime-recovery" ) ;
4242const { NOTICE_ACCEPT_ENV , NOTICE_ACCEPT_FLAG } = require ( "./lib/usage-notice" ) ;
4343const { runDebugCommand } = require ( "../dist/lib/debug-command" ) ;
44+ const {
45+ captureOpenshellCommand,
46+ getInstalledOpenshellVersion,
47+ runOpenshellCommand,
48+ stripAnsi,
49+ versionGte,
50+ } = require ( "../dist/lib/openshell" ) ;
51+ const { listSandboxesCommand, showStatusCommand } = require ( "../dist/lib/inventory-commands" ) ;
4452const { executeDeploy } = require ( "../dist/lib/deploy" ) ;
4553const { runStartCommand, runStopCommand } = require ( "../dist/lib/services-command" ) ;
4654const {
@@ -86,30 +94,24 @@ function getOpenshellBinary() {
8694}
8795
8896function runOpenshell ( args , opts = { } ) {
89- const result = spawnSync ( getOpenshellBinary ( ) , args , {
97+ return runOpenshellCommand ( getOpenshellBinary ( ) , args , {
9098 cwd : ROOT ,
91- env : { ...process . env , ...opts . env } ,
92- encoding : "utf-8" ,
93- stdio : opts . stdio ?? "inherit" ,
99+ env : opts . env ,
100+ stdio : opts . stdio ,
101+ ignoreError : opts . ignoreError ,
102+ errorLine : console . error ,
103+ exit : ( code ) => process . exit ( code ) ,
94104 } ) ;
95- if ( result . status !== 0 && ! opts . ignoreError ) {
96- console . error ( ` Command failed (exit ${ result . status } ): openshell ${ args . join ( " " ) } ` ) ;
97- process . exit ( result . status || 1 ) ;
98- }
99- return result ;
100105}
101106
102107function captureOpenshell ( args , opts = { } ) {
103- const result = spawnSync ( getOpenshellBinary ( ) , args , {
108+ return captureOpenshellCommand ( getOpenshellBinary ( ) , args , {
104109 cwd : ROOT ,
105- env : { ...process . env , ...opts . env } ,
106- encoding : "utf-8" ,
107- stdio : [ "ignore" , "pipe" , "pipe" ] ,
110+ env : opts . env ,
111+ ignoreError : opts . ignoreError ,
112+ errorLine : console . error ,
113+ exit : ( code ) => process . exit ( code ) ,
108114 } ) ;
109- return {
110- status : result . status ?? 1 ,
111- output : `${ result . stdout || "" } ${ opts . ignoreError ? "" : result . stderr || "" } ` . trim ( ) ,
112- } ;
113115}
114116
115117function cleanupGatewayAfterLastSandbox ( ) {
@@ -143,36 +145,10 @@ function getSandboxDeleteOutcome(deleteResult) {
143145 } ;
144146}
145147
146- function parseVersionFromText ( value = "" ) {
147- const match = String ( value || "" ) . match ( / ( [ 0 - 9 ] + \. [ 0 - 9 ] + \. [ 0 - 9 ] + ) / ) ;
148- return match ? match [ 1 ] : null ;
149- }
150-
151- function versionGte ( left = "0.0.0" , right = "0.0.0" ) {
152- const lhs = String ( left )
153- . split ( "." )
154- . map ( ( part ) => Number . parseInt ( part , 10 ) || 0 ) ;
155- const rhs = String ( right )
156- . split ( "." )
157- . map ( ( part ) => Number . parseInt ( part , 10 ) || 0 ) ;
158- const length = Math . max ( lhs . length , rhs . length ) ;
159- for ( let index = 0 ; index < length ; index += 1 ) {
160- const a = lhs [ index ] || 0 ;
161- const b = rhs [ index ] || 0 ;
162- if ( a > b ) return true ;
163- if ( a < b ) return false ;
164- }
165- return true ;
166- }
167-
168- function getInstalledOpenshellVersion ( ) {
169- const versionResult = captureOpenshell ( [ "--version" ] , { ignoreError : true } ) ;
170- return parseVersionFromText ( versionResult . output ) ;
171- }
172-
173- function stripAnsi ( value = "" ) {
174- // eslint-disable-next-line no-control-regex
175- return String ( value ) . replace ( / \x1b \[ [ 0 - 9 ; ] * m / g, "" ) ;
148+ function getInstalledOpenshellVersionOrNull ( ) {
149+ return getInstalledOpenshellVersion ( getOpenshellBinary ( ) , {
150+ cwd : ROOT ,
151+ } ) ;
176152}
177153
178154// ── Sandbox process health (OpenClaw gateway inside the sandbox) ─────────
@@ -891,76 +867,24 @@ function uninstall(args) {
891867}
892868
893869function showStatus ( ) {
894- // Show sandbox registry
895- const { sandboxes, defaultSandbox } = registry . listSandboxes ( ) ;
896- if ( sandboxes . length > 0 ) {
897- const live = parseGatewayInference (
898- captureOpenshell ( [ "inference" , "get" ] , { ignoreError : true } ) . output ,
899- ) ;
900- console . log ( "" ) ;
901- console . log ( " Sandboxes:" ) ;
902- for ( const sb of sandboxes ) {
903- const def = sb . name === defaultSandbox ? " *" : "" ;
904- const model = ( live && live . model ) || sb . model ;
905- console . log ( ` ${ sb . name } ${ def } ${ model ? ` (${ model } )` : "" } ` ) ;
906- }
907- console . log ( "" ) ;
908- }
909-
910- // Show service status
911870 const { showStatus : showServiceStatus } = require ( "./lib/services" ) ;
912- showServiceStatus ( { sandboxName : defaultSandbox || undefined } ) ;
871+ showStatusCommand ( {
872+ listSandboxes : ( ) => registry . listSandboxes ( ) ,
873+ getLiveInference : ( ) =>
874+ parseGatewayInference ( captureOpenshell ( [ "inference" , "get" ] , { ignoreError : true } ) . output ) ,
875+ showServiceStatus,
876+ log : console . log ,
877+ } ) ;
913878}
914879
915880async function listSandboxes ( ) {
916- const recovery = await recoverRegistryEntries ( ) ;
917- const { sandboxes, defaultSandbox } = recovery ;
918- if ( sandboxes . length === 0 ) {
919- console . log ( "" ) ;
920- const session = onboardSession . loadSession ( ) ;
921- if ( session ?. sandboxName ) {
922- console . log (
923- ` No sandboxes registered locally, but the last onboarded sandbox was '${ session . sandboxName } '.` ,
924- ) ;
925- console . log (
926- " Retry `nemoclaw <name> connect` or `nemoclaw <name> status` once the gateway/runtime is healthy." ,
927- ) ;
928- } else {
929- console . log ( " No sandboxes registered. Run `nemoclaw onboard` to get started." ) ;
930- }
931- console . log ( "" ) ;
932- return ;
933- }
934-
935- // Query live gateway inference once; prefer it over stale registry values.
936- const live = parseGatewayInference (
937- captureOpenshell ( [ "inference" , "get" ] , { ignoreError : true } ) . output ,
938- ) ;
939-
940- console . log ( "" ) ;
941- if ( recovery . recoveredFromSession ) {
942- console . log ( " Recovered sandbox inventory from the last onboard session." ) ;
943- console . log ( "" ) ;
944- }
945- if ( recovery . recoveredFromGateway > 0 ) {
946- console . log (
947- ` Recovered ${ recovery . recoveredFromGateway } sandbox entr${ recovery . recoveredFromGateway === 1 ? "y" : "ies" } from the live OpenShell gateway.` ,
948- ) ;
949- console . log ( "" ) ;
950- }
951- console . log ( " Sandboxes:" ) ;
952- for ( const sb of sandboxes ) {
953- const def = sb . name === defaultSandbox ? " *" : "" ;
954- const model = ( live && live . model ) || sb . model || "unknown" ;
955- const provider = ( live && live . provider ) || sb . provider || "unknown" ;
956- const gpu = sb . gpuEnabled ? "GPU" : "CPU" ;
957- const presets = sb . policies && sb . policies . length > 0 ? sb . policies . join ( ", " ) : "none" ;
958- console . log ( ` ${ sb . name } ${ def } ` ) ;
959- console . log ( ` model: ${ model } provider: ${ provider } ${ gpu } policies: ${ presets } ` ) ;
960- }
961- console . log ( "" ) ;
962- console . log ( " * = default sandbox" ) ;
963- console . log ( "" ) ;
881+ await listSandboxesCommand ( {
882+ recoverRegistryEntries : ( ) => recoverRegistryEntries ( ) ,
883+ getLiveInference : ( ) =>
884+ parseGatewayInference ( captureOpenshell ( [ "inference" , "get" ] , { ignoreError : true } ) . output ) ,
885+ loadLastSession : ( ) => onboardSession . loadSession ( ) ,
886+ log : console . log ,
887+ } ) ;
964888}
965889
966890// ── Sandbox-scoped actions ───────────────────────────────────────
@@ -1099,7 +1023,7 @@ async function sandboxStatus(sandboxName) {
10991023}
11001024
11011025function sandboxLogs ( sandboxName , follow ) {
1102- const installedVersion = getInstalledOpenshellVersion ( ) ;
1026+ const installedVersion = getInstalledOpenshellVersionOrNull ( ) ;
11031027 if ( installedVersion && ! versionGte ( installedVersion , MIN_LOGS_OPENSHELL_VERSION ) ) {
11041028 printOldLogsCompatibilityGuidance ( installedVersion ) ;
11051029 process . exit ( 1 ) ;
0 commit comments