refactor(cli): extract OpenShell command helpers#1544
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughCentralizes OpenShell invocation and sandbox inventory rendering: adds Changes
Sequence Diagram(s)sequenceDiagram
participant CLI as "bin/nemoclaw.js"
participant Inventory as "inventory-commands"
participant OpenShell as "openshell"
participant ShellBin as "openshell binary"
participant Registry as "registry / last-session"
participant Service as "showServiceStatus"
CLI->>Inventory: listSandboxesCommand(deps)
Inventory->>Registry: recoverRegistryEntries() / loadLastSession()
Inventory-->>CLI: formatted sandbox list (logs)
CLI->>OpenShell: getInstalledOpenshellVersion(...) / run/capture commands
OpenShell->>ShellBin: spawnSync(args)
ShellBin-->>OpenShell: stdout / stderr / status
OpenShell-->>CLI: parsed version / {status, output}
CLI->>Service: showServiceStatus({ sandboxName })
Service-->>CLI: service status output
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/lib/openshell.test.ts (1)
6-13: Point this suite at the source module, notdist.Importing
../../dist/lib/openshellmakesvitestdepend on a priorbuild:cliand can let stale emitted output mask source regressions. Importing./openshellkeeps the test focused on the code under review.Suggested fix
import { captureOpenshellCommand, getInstalledOpenshellVersion, parseVersionFromText, runOpenshellCommand, stripAnsi, versionGte, -} from "../../dist/lib/openshell"; +} from "./openshell";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/openshell.test.ts` around lines 6 - 13, The test imports the compiled module at "../../dist/lib/openshell" which forces a build and can hide source issues; update the import to point at the source module (the local openshell module) instead so vitest runs against current source. Locate the import statement that brings in captureOpenshellCommand, getInstalledOpenshellVersion, parseVersionFromText, runOpenshellCommand, stripAnsi, and versionGte and change its path to the source file (e.g., the local ./openshell module) so the tests reference the source implementation.bin/nemoclaw.js (1)
91-97: Let the extracted helper own the default env merge.These wrappers still spread
process.env, even though the shared helper already does that. Removing the duplicate merge keeps the wrapper truly thin and avoids encoding the same default in two places.Suggested fix
function runOpenshell(args, opts = {}) { return runOpenshellCommand(getOpenshellBinary(), args, { cwd: ROOT, - env: { ...process.env, ...opts.env }, + env: opts.env, stdio: opts.stdio, ignoreError: opts.ignoreError, errorLine: console.error, exit: (code) => process.exit(code), }); } function captureOpenshell(args, opts = {}) { return captureOpenshellCommand(getOpenshellBinary(), args, { cwd: ROOT, - env: { ...process.env, ...opts.env }, + env: opts.env, ignoreError: opts.ignoreError, }); } @@ function getInstalledOpenshellVersionOrNull() { return getInstalledOpenshellVersion(getOpenshellBinary(), { cwd: ROOT, - env: process.env, }); }Also applies to: 102-105, 140-144
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@bin/nemoclaw.js` around lines 91 - 97, The wrapper calls to runOpenshellCommand in bin/nemoclaw.js currently re-merge process.env (e.g., the options object built at the return of runOpenshellCommand(getOpenshellBinary(), args, { cwd: ROOT, env: { ...process.env, ...opts.env }, ... })) — remove the duplicate merge so the wrapper simply passes opts.env (or undefined) and lets the shared helper perform the default merge; update the other similar wrappers mentioned (the calls around lines 102-105 and 140-144 that set env) to stop spreading process.env and just forward opts.env to runOpenshellCommand/getOpenshellBinary invocations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/lib/openshell.ts`:
- Around line 67-78: In runOpenshellCommand and captureOpenshellCommand, add an
explicit check for spawnSyncImpl's result.error immediately after the call
(before checking result.status), and when present log the error via
(opts.errorLine ?? console.error) including result.error.message/details and
return via (opts.exit ?? ((code) => process.exit(code))) with a non-zero code
(e.g., 1); only then proceed to the existing result.status handling (use
result.status ?? 1 for exit codes in captureOpenshellCommand) so startup
failures (binary not found / permission denied) are reported and handled
correctly.
---
Nitpick comments:
In `@bin/nemoclaw.js`:
- Around line 91-97: The wrapper calls to runOpenshellCommand in bin/nemoclaw.js
currently re-merge process.env (e.g., the options object built at the return of
runOpenshellCommand(getOpenshellBinary(), args, { cwd: ROOT, env: {
...process.env, ...opts.env }, ... })) — remove the duplicate merge so the
wrapper simply passes opts.env (or undefined) and lets the shared helper perform
the default merge; update the other similar wrappers mentioned (the calls around
lines 102-105 and 140-144 that set env) to stop spreading process.env and just
forward opts.env to runOpenshellCommand/getOpenshellBinary invocations.
In `@src/lib/openshell.test.ts`:
- Around line 6-13: The test imports the compiled module at
"../../dist/lib/openshell" which forces a build and can hide source issues;
update the import to point at the source module (the local openshell module)
instead so vitest runs against current source. Locate the import statement that
brings in captureOpenshellCommand, getInstalledOpenshellVersion,
parseVersionFromText, runOpenshellCommand, stripAnsi, and versionGte and change
its path to the source file (e.g., the local ./openshell module) so the tests
reference the source implementation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 8852a87b-09fe-48e2-913c-fa4af221db02
📒 Files selected for processing (3)
bin/nemoclaw.jssrc/lib/openshell.test.tssrc/lib/openshell.ts
## Summary Extract the top-level `list` and `status` command handlers from `bin/nemoclaw.js` into a typed module under `src/lib/inventory-commands.ts`. ## Why This continues the #924 follow-through by shrinking the monolithic dispatcher and moving command logic into reusable typed modules. ## Changes - add `src/lib/inventory-commands.ts` with: - `listSandboxesCommand()` - `showStatusCommand()` - add focused tests in `src/lib/inventory-commands.test.ts` - reduce `bin/nemoclaw.js` to thin wrappers that inject legacy dependencies ## Testing - `npm run build:cli` - `npx vitest run src/lib/inventory-commands.test.ts test/cli.test.js` - `npx vitest run --project cli` ## Stack Depends on #1544 (`refactor(cli): extract OpenShell command helpers`). Once that merges, this PR can be retargeted to `main`. Relates to #924.
…to cv/extract-openshell-helpers
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/lib/inventory-commands.ts (1)
19-22: Consider importingGatewayInferencefrominference-config.tsinstead of duplicating.Per context snippet 3, this interface is already defined in
src/lib/inference-config.ts. Duplicating it here risks divergence if the original is modified.Suggested change
+import type { GatewayInference } from "./inference-config"; + export interface SandboxEntry { ... } export interface RecoveryResult { ... } -export interface GatewayInference { - provider: string | null; - model: string | null; -} +export type { GatewayInference };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/inventory-commands.ts` around lines 19 - 22, Remove the duplicated GatewayInference interface declaration and import the shared type from src/lib/inference-config.ts; update this file to replace the local declaration with an import statement for GatewayInference and ensure all uses in this module reference the imported type (look for the GatewayInference symbol to locate usages), so the project uses the single source of truth in inference-config.ts.src/lib/inventory-commands.test.ts (1)
6-6: Consider importing from source instead ofdist/.Importing from
../../dist/lib/inventory-commandsrequires a build step before tests can run and may cause stale results if the build is outdated. Typically, test files import directly from source (e.g.,./inventory-commandsor./inventory-commands.ts) so that changes are immediately reflected.Suggested change
-import { listSandboxesCommand, showStatusCommand } from "../../dist/lib/inventory-commands"; +import { listSandboxesCommand, showStatusCommand } from "./inventory-commands";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/inventory-commands.test.ts` at line 6, The test imports listSandboxesCommand and showStatusCommand from the built output (dist), causing a build dependency and potential stale code; update the import to reference the source module (the inventory-commands source file) so tests load the unbuilt code directly and reflect changes immediately, and then run tests to ensure listSandboxesCommand and showStatusCommand resolve correctly; adjust any test tooling or tsconfig paths if necessary to allow importing the TypeScript source.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/lib/inventory-commands.ts`:
- Around line 94-98: The status output is incorrectly showing the live model for
every sandbox; change the model selection so only the default sandbox uses
live.model. In the loop over sandboxes (symbols: sandboxes, defaultSandbox,
live, sb), replace the current model assignment ((live && live.model) ||
sb.model) with logic that uses live.model only when sb.name === defaultSandbox
and live?.model is present, otherwise use sb.model; keep the def marker logic
unchanged and update the log call to use this new model variable.
- Around line 73-80: The loop currently applies live inference values to every
sandbox because it uses (live && live.model) and (live && live.provider) for all
sb entries; change it so live.model and live.provider are used only when the
current sb is the default sandbox (sb.name === defaultSandbox). Update the model
and provider assignments in the for-loop (where model and provider are computed)
to prefer sb.model/sb.provider for non-default sandboxes and only fall back to
live.model/live.provider when sb.name matches defaultSandbox.
---
Nitpick comments:
In `@src/lib/inventory-commands.test.ts`:
- Line 6: The test imports listSandboxesCommand and showStatusCommand from the
built output (dist), causing a build dependency and potential stale code; update
the import to reference the source module (the inventory-commands source file)
so tests load the unbuilt code directly and reflect changes immediately, and
then run tests to ensure listSandboxesCommand and showStatusCommand resolve
correctly; adjust any test tooling or tsconfig paths if necessary to allow
importing the TypeScript source.
In `@src/lib/inventory-commands.ts`:
- Around line 19-22: Remove the duplicated GatewayInference interface
declaration and import the shared type from src/lib/inference-config.ts; update
this file to replace the local declaration with an import statement for
GatewayInference and ensure all uses in this module reference the imported type
(look for the GatewayInference symbol to locate usages), so the project uses the
single source of truth in inference-config.ts.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 485cba4a-17f1-4fe9-a73d-3a50310f5fe6
📒 Files selected for processing (3)
bin/nemoclaw.jssrc/lib/inventory-commands.test.tssrc/lib/inventory-commands.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- bin/nemoclaw.js
Summary
Extract the reusable OpenShell command helpers from
bin/nemoclaw.jsinto a typed module undersrc/lib/openshell.ts.Why
This is one of the small follow-through PRs from #924: shrink the monolithic dispatcher and move reusable CLI logic into typed modules that future command wrappers can share.
Changes
src/lib/openshell.tswith:runOpenshellCommand()captureOpenshellCommand()stripAnsi()parseVersionFromText()versionGte()getInstalledOpenshellVersion()src/lib/openshell.test.tsbin/nemoclaw.jsto thin wrappers around the extracted helpersTesting
npm run build:clinpx vitest run src/lib/openshell.test.ts test/cli.test.jsRelates to #924.
Summary by CodeRabbit
Refactor
Tests