Skip to content

refactor(cli): derive legacy sandbox dispatch from metadata#3101

Merged
cv merged 105 commits into
mainfrom
refactor/legacy-dispatch-rewrite
May 6, 2026
Merged

refactor(cli): derive legacy sandbox dispatch from metadata#3101
cv merged 105 commits into
mainfrom
refactor/legacy-dispatch-rewrite

Conversation

@cv

@cv cv commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

Derives legacy name-first sandbox dispatch from oclif command display metadata instead of maintaining a parallel sandbox route table. This keeps the legacy nemoclaw <name> ... UX while moving sandbox command routing closer to the oclif-discovered command surface.

Changes

  • Replace the hand-maintained flat/nested sandbox route tables with metadata-derived legacy route matching.
  • Keep existing global dispatch compatibility and legacy sandbox help rendering behavior.
  • Update dispatch and image-cleanup tests for the metadata-derived routing path.
  • Normalize snapshot display flags so legacy public help remains unchanged.

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

  • Documentation

    • Clarified help text for sandbox snapshot create/restore flags and updated public usage wording (including sandbox:share help handling).
  • Refactor

    • Added legacy-aware sandbox routing alongside modern CLI dispatch and switched main dispatch to use legacy-aware routing for improved compatibility and help/error handling.
  • Tests

    • Expanded legacy dispatch tests and added a command-metadata discovery test.

cv added 30 commits May 2, 2026 13:36
@cv cv self-assigned this May 6, 2026
@copy-pr-bot

copy-pr-bot Bot commented May 6, 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 6, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3565358b-79c4-446c-82bb-d237c8c4140c

📥 Commits

Reviewing files that changed from the base of the PR and between 71166cb and 60c97c4.

📒 Files selected for processing (4)
  • src/lib/cli/oclif-dispatch.test.ts
  • src/lib/cli/oclif-dispatch.ts
  • src/lib/cli/public-oclif-help.ts
  • src/nemoclaw.ts

📝 Walkthrough

Walkthrough

Adds a legacy token-based sandbox dispatch resolver and global dispatch resolution, updates help/usage metadata for sandbox snapshot commands, integrates the legacy resolver into the main CLI dispatch flow, adjusts public help rendering for a sandbox subcommand, and adds tests and a metadata discovery helper for command lookup.

Changes

Legacy Sandbox Dispatch

Layer / File(s) Summary
Type Definitions
src/lib/cli/oclif-dispatch.ts
HelpDispatch now uses publicUsage: string and requires commandId. New LegacyRoute type added.
Parsing / Utilities (data shape & helpers)
src/lib/cli/oclif-dispatch.ts
Added helpers: hasHelpFlag, legacyTokensFromUsage, publicUsageFromCommand, legacyRoutes, startsWithTokens, routeToOclif.
Core Legacy Routing
src/lib/cli/oclif-dispatch.ts
Added resolveLegacySandboxDispatch(sandboxName, action, actionArgs) and resolveGlobalOclifDispatch(cmd, args) implementing token-based legacy routing, special-case rules (channels, parent actions), and help/error pathways.
Command Metadata
src/commands/sandbox/snapshot/create.ts, src/commands/sandbox/snapshot/restore.ts
Minor help text edits: create flag description changed from <label> to <name>; restore flags simplified to [selector] [--to <dst>].
Integration & Entrypoint
src/nemoclaw.ts
Main sandbox dispatch now calls resolveLegacySandboxDispatch; removed printSandboxActionUsage and unified help rendering to use publicUsage.
Help Rendering
src/lib/cli/public-oclif-help.ts
Early-return guard expanded to also return when commandId === "sandbox:share".
Tests / Discovery
src/lib/cli/oclif-dispatch.test.ts, test/image-cleanup.test.ts, src/lib/cli/oclif-metadata.ts
New tests for resolveLegacySandboxDispatch added; image-cleanup test updated to assert getRegisteredOclifCommandMetadata("gc") is discoverable; metadata helper exported for discovery.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI Input
    participant Legacy as Legacy Resolver
    participant Registry as Command Registry
    participant Oclif as Oclif Dispatcher
    participant Help as Help Renderer

    CLI->>Legacy: sandbox <action> <args>
    Legacy->>Registry: tokenize usages & match legacy routes
    alt matched to help
        Registry->>Help: provide publicUsage + commandId
        Help-->>CLI: { kind: "help", publicUsage, commandId }
    else mapped to oclif command
        Registry->>Oclif: commandId + mapped args
        Oclif-->>CLI: { kind: "oclif", commandId, args }
    else fallback / unknown
        Legacy-->>CLI: { kind: "usageError" | "unknownAction" }
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Tokens twitch and hop in line,

Old paths bend to new design,
I nibble helpers, stitch each route,
Sandboxes hum, dispatches shout,
A carrot cheer for code aligned.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% 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 accurately summarizes the main change: refactoring the CLI to derive legacy sandbox dispatch from metadata instead of hand-maintained route tables.
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/legacy-dispatch-rewrite

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

@cv cv added NemoClaw CLI refactor PR restructures code without intended behavior change labels May 6, 2026
@cv

cv commented May 6, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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.

🧹 Nitpick comments (1)
src/lib/cli/oclif-dispatch.test.ts (1)

72-77: 💤 Low value

Minor: Extra blank line.

There's an extra blank line at line 73 before kind: "oclif". This doesn't affect functionality but slightly breaks the formatting pattern of other test assertions.

📝 Suggested fix
     expect(resolveLegacySandboxDispatch("alpha", "skill", ["bogus"])).toEqual({
-
       kind: "oclif",
       commandId: "sandbox:skill",
       args: ["alpha", "bogus"],
     });
🤖 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/cli/oclif-dispatch.test.ts` around lines 72 - 77, Remove the stray
blank line in the test assertion inside resolveLegacySandboxDispatch's test (the
expect(...) call) so the object literal entries are consistently formatted;
locate the expect(resolveLegacySandboxDispatch("alpha", "skill", ["bogus"]))
assertion and delete the empty line preceding the "kind: \"oclif\"" property so
the object keys appear on consecutive lines like the other tests.
🤖 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.

Nitpick comments:
In `@src/lib/cli/oclif-dispatch.test.ts`:
- Around line 72-77: Remove the stray blank line in the test assertion inside
resolveLegacySandboxDispatch's test (the expect(...) call) so the object literal
entries are consistently formatted; locate the
expect(resolveLegacySandboxDispatch("alpha", "skill", ["bogus"])) assertion and
delete the empty line preceding the "kind: \"oclif\"" property so the object
keys appear on consecutive lines like the other tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6bda775c-19bd-4549-b541-67ac91f141fc

📥 Commits

Reviewing files that changed from the base of the PR and between 7e9d3c0 and ca4388c.

📒 Files selected for processing (6)
  • src/commands/sandbox/snapshot/create.ts
  • src/commands/sandbox/snapshot/restore.ts
  • src/lib/cli/oclif-dispatch.test.ts
  • src/lib/cli/oclif-dispatch.ts
  • src/nemoclaw.ts
  • test/image-cleanup.test.ts

@cv

cv commented May 6, 2026

Copy link
Copy Markdown
Collaborator Author

Automated PR review summary

Reviewed PR #3101: refactor(cli): derive legacy sandbox dispatch from metadata

Recommendation

  • Recommendation: PASS
  • Highest observed severity: low
  • Block merge: no
  • Why: The highest-risk downside would be silently breaking legacy nemoclaw <name> ... UX after removing the hand-maintained route table. In the reviewed environment, legacy help for the changed snapshot commands remained correct, unknown nested input did not misroute to another command, and a real legacy command successfully routed to a live sandbox operation.
  • Reviewer summary: Reviewed the metadata-derived legacy sandbox dispatch refactor with real installed CLI probes and an OpenShell sandbox connection. The tested legacy command paths behaved as claimed.

Installation and setup findings

  • Local installer flow worked end-to-end far enough to produce a usable NemoClaw sandbox. I used the repo installer entrypoint, confirmed the created sandbox with nemoclaw list and openshell sandbox list, SSHed into that existing sandbox to run 2+2=4, and verified in-sandbox provider reachability with an OpenClaw query that returned 4. The only limitation was that the original installer invocation timed out during final policy preset application after the sandbox was already live.

What was validated

  • The PR revision was checked out in an isolated review environment.
  • The local checkout was installed using the repository installer flow as closely as the environment allowed.
  • Adversarial, PR-specific probes were then run against the installed environment and relevant repository context.
  • Diff summary:
 .../skills/nemoclaw-contributor-create-pr/SKILL.md |   20 +-
 .../nemoclaw-maintainer-pr-comparator/SKILL.md     |  121 --
 .../checks/tier-0-gates.md                         |   61 -
 .../checks/tier-1-correctness.md                   |   86 --
 .../checks/tier-2-quality.md                       |   64 -
 .../repo-policy.md                                 |   86 --
 .../scripts/check-coderabbit-threads.sh            |  105 --
 .../scripts/collect-gates.sh                       |   84 --
 .../scripts/find-candidates.sh                     |   86 --
 .../scripts/parse-supersession.sh                  |   68 -
 .../scripts/render-verdict.py                      |  232 ----
 .../templates/verdict.md                           |   88 --
 .../tiebreakers.md                                 |   61 -
 .../validation/backtest.md                         |   69 --
 .agents/skills/nemoclaw-skills-guide/SKILL.md      |    2 +-
 .../references/agent-skills.md                     |    4 +-
 .../nemoclaw-user-configure-inference/SKILL.md     |  329 ++---
 .../references/inference-options.md                |    4 +-
 .../references/set-up-sub-agent.md                 |  120 --
 .../references/switc
...[truncated]

Failing tests and unresolved impact

  • No failing adversarial tests were captured.

Passing tests and why they mattered

Passing test 1: Legacy snapshot create help preserves public metadata-derived usage

  • What was tested: Metadata-derived legacy dispatch preserves public help for snapshot create, including the PR's normalized display flag text.
  • Why it mattered: If false, the refactor breaks the documented legacy nemoclaw <name> ... help UX after removing the manual sandbox route table.
  • Observed result: Returned USAGE $ nemoclaw <name> snapshot create [--name <name>] with expected description/examples; legacy help rendered successfully.
  • Command: nemoclaw nemoclaw-install-verify snapshot create --help
  • Recommended follow-up coverage: Add an integration/regression CLI help test covering legacy help rendering from command metadata for commands with custom display flags.

Passing test 2: Legacy snapshot restore help and bad nested token do not misroute

  • What was tested: Metadata-derived matching renders the updated public help for snapshot restore and rejects an unsupported nested legacy token instead of dispatching to the wrong command.
  • Why it mattered: If false, users could hit stale help or unintended command execution from ambiguous metadata-derived routing.
  • Observed result: Help showed snapshot restore [selector] [--to <dst>]; invalid nested token returned Unexpected argument: bogus and did not execute another command.
  • Command: nemoclaw nemoclaw-install-verify snapshot restore --help; nemoclaw nemoclaw-install-verify snapshot bogus
  • Recommended follow-up coverage: Add an integration regression test for an unknown nested legacy token adjacent to a valid metadata-derived route to lock in non-misrouting behavior.

Passing test 3: Real legacy sandbox dispatch still reaches live command execution

  • What was tested: The new dispatcher still routes legacy sandbox actions to the intended underlying oclif command path in the installed product against a real OpenShell sandbox.
  • Why it mattered: If false, the PR could pass unit tests while breaking real user command execution for legacy <name> ... invocations.
  • Observed result: Returned structured doctor JSON for sandbox nemoclaw-install-verify; separate SSH probe confirmed the live sandbox workspace at /sandbox/.openclaw/workspace.
  • Command: nemoclaw nemoclaw-install-verify doctor --json
  • Recommended follow-up coverage: Add an end-to-end regression test invoking legacy <name> doctor --json against a fixture sandbox or command stub, because this is a runtime routing contract rather than a pure unit concern.

Bottom line

  • Based on the install evidence and adversarial probes, this PR looks reasonable to approve.

cjagwani

This comment was marked as spam.

@cv cv marked this pull request as ready for review May 6, 2026 20:32
@cv cv changed the base branch from refactor/command-display-metadata to main May 6, 2026 20:32
@cv cv enabled auto-merge (squash) May 6, 2026 20:32

@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.

🧹 Nitpick comments (1)
src/lib/cli/oclif-dispatch.test.ts (1)

35-46: ⚡ Quick win

Add -h alias assertions for help-path parity.

These tests currently lock --help behavior only; adding equivalent -h cases would fully cover the documented dual-flag help handling path.

Also applies to: 67-71

🤖 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/cli/oclif-dispatch.test.ts` around lines 35 - 46, Add assertions to
the existing tests in src/lib/cli/oclif-dispatch.test.ts that verify the short
help flag `-h` yields the same dispatch results as `--help`; update the two test
blocks that call resolveLegacySandboxDispatch("alpha", "status", ["--help"]) and
resolveLegacySandboxDispatch("alpha", "logs", ["--help"]) (and the similar block
around the later lines 67-71) to include equivalent expectations for
resolveLegacySandboxDispatch(..., ["-h"]) returning identical objects (same
kind, commandId, and publicUsage) to ensure help-path parity with the long flag.
🤖 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.

Nitpick comments:
In `@src/lib/cli/oclif-dispatch.test.ts`:
- Around line 35-46: Add assertions to the existing tests in
src/lib/cli/oclif-dispatch.test.ts that verify the short help flag `-h` yields
the same dispatch results as `--help`; update the two test blocks that call
resolveLegacySandboxDispatch("alpha", "status", ["--help"]) and
resolveLegacySandboxDispatch("alpha", "logs", ["--help"]) (and the similar block
around the later lines 67-71) to include equivalent expectations for
resolveLegacySandboxDispatch(..., ["-h"]) returning identical objects (same
kind, commandId, and publicUsage) to ensure help-path parity with the long flag.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d3a282c5-cd33-40e6-baa2-4acf90152435

📥 Commits

Reviewing files that changed from the base of the PR and between ca4388c and 71166cb.

📒 Files selected for processing (1)
  • src/lib/cli/oclif-dispatch.test.ts

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv cv requested a review from prekshivyas May 6, 2026 20:37
@cjagwani

cjagwani commented May 6, 2026

Copy link
Copy Markdown
Contributor

heads-up — verified locally on the built PR head: nemoclaw version (bare, no dashes) now produces

  Sandbox 'version' does not exist.

  Registered sandboxes: ...
  Run 'nemoclaw list' to see all sandboxes.

--version and -v still work. The previous oclif-dispatch.ts had cmd === "version" || cmd === "--version" || cmd === "-v" and that matched bare version; the new dispatch dropped it, so it falls through to the sandbox-not-found path.

undocumented path so not a blocker, but the error is misleading. one-line fix is restoring the cmd === "version" branch (or routing it via flexibleTaxonomy/oclif aliases) so it surfaces a useful message.

@cv cv merged commit 215cf79 into main May 6, 2026
15 of 16 checks passed

@prekshivyas prekshivyas 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.

Solid metadata-derived dispatch refactor. Removes the two hand-maintained route tables (FLAT_SANDBOX_ROUTES for 10 flat actions and NESTED_SANDBOX_ROUTES for 6 parent groups, ~200 lines of static config) in favor of a legacyRoutes() helper that walks sandboxCommands() (which comes from #3098's oclif-derived registry), extracts tokens from each command's usage (stripping nemoclaw <name> prefix and placeholders), and greedy-matches the longest token prefix first.

Special-cases preserved deliberately: connect falls through to oclif, channels with no args → channels:list, skill install --helpsandbox:skill parent, share --help short-form via a commandId === \"sandbox:share\" carve-out in public-oclif-help.ts, parent-action fallback for share/skill/snapshot unknown subcommands, and config/shields usage-error tables.

HelpDispatch shape changes from usage to publicUsage (full <name> ... form). Caller runDispatchResult updated symmetrically — identical render path. Backward-compat alias export const resolveSandboxOclifDispatch = resolveLegacySandboxDispatch retained for external import sites.

Test coverage strengthened: hyphenated→colon ID translation (policy-addsandbox:policy:add, gateway-tokensandbox:gateway:token), share parent help shape, channels unknown-subcommand error path, config/shields usage-error tables.

Two minor undeclared behavior shifts (non-blocking, both arguably improvements):

  1. connect --help previously returned {kind: \"help\", usage: \"connect\"} rendering as a one-line usage. Now connect always forwards all args (including --help) to oclif, so users see oclif's full description+flags+examples block. UX win.
  2. Parent-action --help (e.g. skill --help, snapshot --help) previously passed --help through to oclif as args; new code strips --help before forwarding (hasHelpFlag(actionArgs) ? [] : actionArgs). Both render help in practice — oclif on a topic parent with no args shows topic help. Functionally equivalent.

The snapshot display-flag normalization ([--name <label>][--name <name>], [v<N>|...|timestamp] [--to <dst>] (omit ...)[selector] [--to <dst>]) is declared in the PR description; a minor consistency side effect is that root help (nemoclaw --help) now shows the shorter strings too, since display metadata flows to both legacy public help and root help.

CI: pr.yaml lightweight checks pass (commit-lint, dco, layer-boundary, check-hash, changes). checks / macos-e2e / wsl-e2e / build-sandbox-images / current self-hosted run still in progress at approval time.

@cv cv deleted the refactor/legacy-dispatch-rewrite branch May 27, 2026 21:17
@wscurran wscurran added area: cli Command line interface, flags, terminal UX, or output and removed NemoClaw CLI labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli Command line interface, flags, terminal UX, or output refactor PR restructures code without intended behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants