Skip to content

refactor(cli): extract sandbox doctor action - #2893

Merged
cv merged 6 commits into
mainfrom
refactor/oclif-extract-sandbox-doctor-action
May 4, 2026
Merged

refactor(cli): extract sandbox doctor action#2893
cv merged 6 commits into
mainfrom
refactor/oclif-extract-sandbox-doctor-action

Conversation

@cv

@cv cv commented May 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extract sandbox doctor diagnostics from src/nemoclaw.ts into a dedicated action module and route the command through oclif. This removes another legacy-dispatched public sandbox command while preserving the existing host, gateway, sandbox, inference, messaging, and local service diagnostics.

Stack Navigation

Changes

  • Added src/lib/sandbox-doctor-action.ts for doctor checks and report rendering.
  • Added src/lib/sandbox-doctor-cli-command.ts and registered sandbox:doctor in the oclif command map.
  • Updated legacy sandbox dispatch to route doctor through oclif instead of the legacy target path.
  • Removed doctor-specific helpers and sandboxDoctor from src/nemoclaw.ts.
  • Added a dispatch unit test for the new doctor route.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Verification

  • npx prek run --all-files passes
  • npm test passes
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • make docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Carlos Villela cvillela@nvidia.com

Summary by CodeRabbit

Release Notes

  • New Features
    • Added sandbox doctor command to diagnose sandbox and gateway health, running comprehensive checks across host, gateway, inference, messaging, and local services.
    • Supports --json flag for structured diagnostic output with status details and summary.

@cv cv self-assigned this May 3, 2026
@copy-pr-bot

copy-pr-bot Bot commented May 3, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The doctor command is migrated from a legacy dispatch system to the oclif command framework. A new comprehensive sandbox diagnostics implementation runs health checks across host, gateway, sandbox, inference, messaging, and local services. Legacy doctor code is removed from nemoclaw.ts, and routing is updated to dispatch through oclif instead.

Changes

Sandbox Doctor Command Migration

Layer / File(s) Summary
Core Implementation
src/lib/sandbox-doctor-action.ts
Implements runSandboxDoctor() orchestrator and helpers: environment/service health checks (Host, Gateway, Sandbox, Inference, Messaging, Local services), report rendering with JSON/human-readable output, and Docker/OpenShell integration for diagnostics.
CLI Command Definition
src/lib/sandbox-doctor-cli-command.ts
New oclif command sandbox:doctor that parses sandbox name and remaining args, delegates to runSandboxDoctor(), supports non-strict parsing and --json output.
Integration & Dispatch Routing
src/lib/legacy-oclif-dispatch.ts, src/lib/oclif-commands.ts
Updates LegacyDispatch type to remove "doctor" target; routes doctor action to oclif dispatch (sandbox:doctor) instead of legacy handler; registers new command in oclif command registry.
Tests & Validation
src/lib/legacy-oclif-dispatch.test.ts
Adds test case verifying that sandbox doctor command with --json flag is routed through oclif dispatch with correct commandId and args.
Legacy Code Removal
src/nemoclaw.ts
Deletes legacy doctor dispatch case, DoctorStatus/DoctorCheck/CommandCapture type definitions, and old sandboxDoctor() implementation.

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A doctor hops to oclif's door,
With checks aplenty, checks galore—
Health diagnostics, checks arranged,
From legacy paths to modern staged!
Gateway, sandbox, inference too—
All measured, rendered, fresh and true.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor(cli): extract sandbox doctor action' clearly and concisely summarizes the main change: moving the sandbox doctor diagnostics from the monolithic src/nemoclaw.ts into dedicated modular components (action and CLI command).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/oclif-extract-sandbox-doctor-action

Review rate limit: 9/10 reviews remaining, refill in 6 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@cv cv added the v0.0.34 label May 4, 2026
cv added a commit that referenced this pull request May 4, 2026
## Summary
Extract the sandbox status implementation from `src/nemoclaw.ts` into a
dedicated action module. This removes `sandboxStatus` from the
transitional runtime bridge while preserving the existing status output,
gateway reconciliation, process health, and NIM reporting behavior.

## Stack Navigation
- Position: 4 of 60
- Previous PR: [#2891 — refactor(cli): extract sandbox connect
action](#2891)
- Next PR: [#2893 — refactor(cli): extract sandbox doctor
action](#2893)

## Changes
- Added `src/lib/sandbox-status-action.ts` for sandbox status rendering,
gateway lookup handling, local inference health, active session
reporting, process health, and NIM status.
- Updated `src/lib/sandbox-runtime-actions.ts` to call the extracted
status action.
- Removed `sandboxStatus` from `src/nemoclaw.ts` and
`NemoClawRuntimeBridge`.

## Type of Change
- [x] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Verification
- [x] `npx prek run --all-files` passes
- [x] `npm test` passes
- [ ] Tests added or updated for new or changed behavior
- [x] No secrets, API keys, or credentials committed
- [ ] Docs updated for user-facing behavior changes
- [ ] `make docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

---
Signed-off-by: Carlos Villela <cvillela@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactoring**
* Reorganized sandbox status command implementation for improved
maintainability.

* **Improvements**
* Enhanced sandbox status reporting with comprehensive diagnostics
including model information, provider details, inference status, GPU
information, and policy checks.
* Improved sandbox health verification with better error detection and
guidance when state issues are encountered.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv
cv changed the base branch from refactor/oclif-extract-sandbox-status-action to main May 4, 2026 18:44
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv
cv marked this pull request as ready for review May 4, 2026 18:48

@prekshivyas prekshivyas left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — clean extraction of sandboxDoctor into src/lib/sandbox-doctor-action.ts with a thin oclif wrapper at src/lib/sandbox-doctor-cli-command.ts. Public surface preserved (<name> doctor [--json]), exit codes preserved, dispatch test added for the new oclif route. LegacyDispatch.target correctly narrowed.

Nits (non-blocking):

  1. Orphan imports in src/nemoclaw.ts — this extraction was the last consumer of six imports that are now unused; please clean up here or in a stack-end cleanup PR linked from this one:

    • line 7: GATEWAY_PORT, OLLAMA_PORT (in destructure with the still-used DASHBOARD_PORT)
    • line 46: probeProviderHealth
    • line 47: buildStatusCommandDeps
    • line 59: recoverNamedGatewayRuntime (in destructure)
    • line 71: isErrnoException

    Plus the carryover parseForwardList at line 79 from #2891 that's now drifted through two more PRs.

  2. Self-hosted e2e suite still in flight at review time (build-sandbox-images in progress, test-e2e-sandbox/test-e2e-gateway-isolation queued). Worth confirming green for this hash before merging — stack-tip green isn't enough since each link should stand alone.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/lib/sandbox-doctor-action.ts (1)

429-430: ⚡ Quick win

Replace the ESLint suppression with the repo’s Biome linting path.

// eslint-disable-next-line complexity is out of band for the JS/TS tooling this repo says to use, so this exception will not be enforced consistently. Use the Biome equivalent or split runSandboxDoctor enough to drop the suppression.

As per coding guidelines, "Use Biome config in biome.json for linting and formatting JavaScript and TypeScript files".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/sandbox-doctor-action.ts` around lines 429 - 430, The file currently
disables ESLint complexity for the function runSandboxDoctor via "//
eslint-disable-next-line complexity"; remove that ESLint suppression and either
(A) replace it with the repo's Biome directive (use the Biome inline
comment/annotation supported by the project's biome configuration) or (B)
refactor runSandboxDoctor to reduce complexity (extract logical blocks into
smaller functions e.g., parseArgs, validateSandbox, performChecks) until the
complexity rule is not violated; update or add any needed JSDoc/comments
referencing runSandboxDoctor, parseArgs, validateSandbox or performChecks so
linting passes under the Biome-based rules defined in biome.json.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/sandbox-doctor-cli-command.ts`:
- Around line 10-19: The command is peeling this.argv which misparses positional
args/flags; instead declare oclif metadata on SandboxDoctorCliCommand: add
static args = [{ name: "sandboxName", required: true }] and static flags = {
json: Flags.boolean({ char: "j", description: "output JSON" }) } (and set static
strict = true), then in run() call const { args, flags } =
this.parse(SandboxDoctorCliCommand) and pass args.sandboxName to
runSandboxDoctor and include the json flag appropriately (e.g. await
runSandboxDoctor(args.sandboxName, flags.json ? ["--json"] : [] or merge with
any actionArgs) so flags are parsed/validated by oclif instead of reading
this.argv.

---

Nitpick comments:
In `@src/lib/sandbox-doctor-action.ts`:
- Around line 429-430: The file currently disables ESLint complexity for the
function runSandboxDoctor via "// eslint-disable-next-line complexity"; remove
that ESLint suppression and either (A) replace it with the repo's Biome
directive (use the Biome inline comment/annotation supported by the project's
biome configuration) or (B) refactor runSandboxDoctor to reduce complexity
(extract logical blocks into smaller functions e.g., parseArgs, validateSandbox,
performChecks) until the complexity rule is not violated; update or add any
needed JSDoc/comments referencing runSandboxDoctor, parseArgs, validateSandbox
or performChecks so linting passes under the Biome-based rules defined in
biome.json.
🪄 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: Enterprise

Run ID: 2c3c7427-527a-48cb-8aa2-874f04d2ed3c

📥 Commits

Reviewing files that changed from the base of the PR and between 1824bc1 and 3e2e30c.

📒 Files selected for processing (6)
  • src/lib/legacy-oclif-dispatch.test.ts
  • src/lib/legacy-oclif-dispatch.ts
  • src/lib/oclif-commands.ts
  • src/lib/sandbox-doctor-action.ts
  • src/lib/sandbox-doctor-cli-command.ts
  • src/nemoclaw.ts
💤 Files with no reviewable changes (1)
  • src/nemoclaw.ts

Comment on lines +284 to +308
function readProcessCommandLine(pid: number): string | null {
if (process.platform === "win32") {
return null;
}
try {
return fs.readFileSync(`/proc/${pid}/cmdline`, "utf-8");
} catch {
try {
return execFileSync("ps", ["-p", String(pid), "-o", "comm=", "-o", "args="], {
encoding: "utf-8",
stdio: ["ignore", "pipe", "ignore"],
timeout: 1000,
});
} catch {
return null;
}
}
}

function isCloudflaredProcess(pid: number): boolean {
const commandLine = readProcessCommandLine(pid);
if (commandLine === null) {
return false;
}
return commandLineNamesCloudflared(commandLine);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve “unknown” process identity instead of reporting a stale PID.

On Windows, Lines 285-287 always return null, and this helper turns that into false. That makes Line 326 classify any live cloudflared PID as stale even when process.kill(pid, 0) succeeds. Return a tri-state here or add a Windows-specific lookup so the doctor does not misreport healthy tunnels.

Comment on lines +10 to +19
export default class SandboxDoctorCliCommand extends Command {
static id = "sandbox:doctor";
static strict = false;
static summary = "Diagnose sandbox and gateway health";
static description = "Run host, gateway, sandbox, inference, messaging, and local service diagnostics.";
static usage = ["<name> doctor [--json]"];

public async run(): Promise<void> {
const [sandboxName, ...actionArgs] = this.argv;
await runSandboxDoctor(sandboxName, actionArgs);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# Check the target file exists and view its content
head -40 src/lib/sandbox-doctor-cli-command.ts

Repository: NVIDIA/NemoClaw

Length of output: 864


🏁 Script executed:

# Find where runSandboxDoctor is defined to understand its signature
rg -n "runSandboxDoctor" --type ts

Repository: NVIDIA/NemoClaw

Length of output: 388


🏁 Script executed:

# Check how oclif Command class is used elsewhere in the codebase for comparison
rg -n "extends Command" --type ts -A 5 | head -100

Repository: NVIDIA/NemoClaw

Length of output: 7275


Declare the sandbox name and --json with oclif args/flags instead of peeling this.argv.

With static strict = false and no args/flags metadata, a direct sandbox:doctor invocation passes undefined as sandboxName (when called with no args), and a sandbox:doctor --json invocation binds "--json" as sandboxName. Declaring a required positional arg and a boolean flag through oclif gives built-in validation and help/usage errors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/sandbox-doctor-cli-command.ts` around lines 10 - 19, The command is
peeling this.argv which misparses positional args/flags; instead declare oclif
metadata on SandboxDoctorCliCommand: add static args = [{ name: "sandboxName",
required: true }] and static flags = { json: Flags.boolean({ char: "j",
description: "output JSON" }) } (and set static strict = true), then in run()
call const { args, flags } = this.parse(SandboxDoctorCliCommand) and pass
args.sandboxName to runSandboxDoctor and include the json flag appropriately
(e.g. await runSandboxDoctor(args.sandboxName, flags.json ? ["--json"] : [] or
merge with any actionArgs) so flags are parsed/validated by oclif instead of
reading this.argv.

@cv
cv merged commit 2ac6420 into main May 4, 2026
18 checks passed
cv added a commit that referenced this pull request May 4, 2026
## Summary
Extract sandbox destroy and image cleanup helpers from `src/nemoclaw.ts`
into a dedicated action module. This removes `sandboxDestroy` from the
transitional runtime bridge while preserving sandbox deletion, messaging
provider cleanup, gateway teardown, and Docker image cleanup behavior.

## Stack Navigation
- Position: 6 of 60
- Previous PR: [#2893 — refactor(cli): extract sandbox doctor
action](#2893)
- Next PR: [#2896 — refactor(cli): extract sandbox rebuild
action](#2896)

## Changes
- Added `src/lib/sandbox-destroy-action.ts` for sandbox destroy
orchestration, delete-result classification, gateway cleanup, service
cleanup, and image cleanup helpers.
- Updated `src/lib/sandbox-runtime-actions.ts` to call the extracted
destroy action.
- Removed `sandboxDestroy` and destroy-specific helpers from
`src/nemoclaw.ts` and `NemoClawRuntimeBridge`.
- Updated rebuild to use the extracted image/registry removal helper.
- Reworked image cleanup tests to cover helper behavior instead of
source-shape assertions against `src/nemoclaw.ts`.

## Type of Change
- [x] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Verification
- [x] `npx prek run --all-files` passes
- [x] `npm test` passes
- [x] Tests added or updated for new or changed behavior
- [x] No secrets, API keys, or credentials committed
- [ ] Docs updated for user-facing behavior changes
- [ ] `make docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

---
Signed-off-by: Carlos Villela <cvillela@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved handling for sandbox deletion when the sandbox has already
been removed.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv
cv deleted the refactor/oclif-extract-sandbox-doctor-action branch May 27, 2026 21:18
@wscurran wscurran added the refactor PR restructures code without intended behavior change label Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor PR restructures code without intended behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants