feat(onboard): add review summary + Y/n gate before destructive sandbox build#2221
Conversation
…ox build (closes NVIDIA#2165) nemoclaw onboard collected 8 inputs then immediately began a ~6-minute sandbox image build + provider/credential persistence with no final confirmation. Users who hit Enter by reflex at the sandbox-name prompt (where `[my-assistant]` is pre-filled) were locked into a build they did not intend to start. Add a compact summary + Y/n gate right after the sandbox-name prompt in createSandbox(), before any destructive action (docker build, patchStagedDockerfile, provider creation): ────────────────────────────────────────────────── Review configuration ────────────────────────────────────────────────── Provider: gemini-api Model: gemini-2.5-flash Web search: disabled Messaging: none Sandbox name: my-assistant ────────────────────────────────────────────────── Apply this configuration? [Y/n]: Default is Y so a confident user just hits Enter once. Answering n/no prints "Aborted. Re-run `nemoclaw onboard` to start over." and exits 0 (clean abort, not an error). Non-interactive runs (NEMOCLAW_NON_INTERACTIVE=1, or --dangerously-skip-permissions) still print the summary for log clarity but skip the gate — automated flows opted out of prompts. Extract the summary renderer into a pure formatOnboardConfigSummary() helper so the output shape is directly unit-testable without running the interactive path. Export it. Tests - test/onboard.test.ts: +1 case covering full-field render, empty channels -> "none", null webSearch -> "disabled", and the null-fields -> "(unset)" fallback (no stringified "undefined" leaks). - Full suite: 134 tests pass (was 133); test/runner.test.ts 60/60 pass. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdded and exported a formatter that prints a multi-line "Review configuration" summary during onboarding, moved sandbox-name prompt earlier, and introduced an interactive confirmation prompt (skipped in non-interactive or when skipping permissions) that can abort onboarding before any destructive build or provider setup. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI as Onboard CLI
participant Inference as setupInference
participant Build as SandboxBuilder
User->>CLI: Start 'onboard' (interactive)
CLI->>User: Prompt provider/model, API key, web-search, messaging
CLI->>User: Prompt sandbox name (validated)
CLI->>CLI: formatOnboardConfigSummary(...)
CLI->>User: Print "Review configuration" summary
alt User confirms
User->>CLI: Apply this configuration? [Y/n] -> yes
CLI->>Inference: setupInference(provider, model, creds)
CLI->>Build: start sandbox build/registration
else User rejects
User->>CLI: Apply this configuration? [Y/n] -> no
CLI->>User: Print abort guidance and exit 0
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
test/onboard.test.ts (1)
5385-5386: Tighten the web-search assertion to the full rendered field.
summary.includes("enabled")is broad and can pass for unrelated text. Assert the exact summary line instead.🔧 Suggested tweak
- assert.ok(summary.includes("enabled"), "summary includes web-search enabled"); + assert.ok(summary.includes("Web search: enabled"), "summary includes web-search enabled");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/onboard.test.ts` around lines 5385 - 5386, The first assertion in the test uses summary.includes("enabled") which is too broad; update the assertion that references the summary variable (the assert.ok line checking web-search) to assert the full rendered field text (e.g., the exact "web-search: enabled" line or exact substring rendered by the app) instead of just "enabled" so the test only passes when the web-search summary line is present; keep the channel assertion (the assert.ok checking "telegram, slack") as is.
🤖 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/onboard.ts`:
- Around line 3357-3373: The confirmation gate in createSandbox runs after
credential-persisting operations called earlier in onboard(), specifically
configureWebSearch() and setupMessagingChannels(), so aborting at the gate does
not undo side effects; move the confirmation block (the prompt using
formatOnboardConfigSummary, isNonInteractive and dangerouslySkipPermissions) to
run before calling configureWebSearch() and setupMessagingChannels(), or
alternatively delay any persistence by deferring saveCredential(...) calls until
after the user confirms; update createSandbox/onboard to ensure the prompt
always precedes any call to configureWebSearch, setupMessagingChannels or
saveCredential.
In `@test/onboard.test.ts`:
- Around line 5369-5372: Replace the dynamic CommonJS loading for
formatOnboardConfigSummary with a static ESM import: add
formatOnboardConfigSummary to the existing top-of-file ESM import list (instead
of using require(onboardPath)), and remove the delete require.cache[onboardPath]
and const { formatOnboardConfigSummary } = require(onboardPath) lines; ensure
any use of onboardPath is removed and tests reference the imported
formatOnboardConfigSummary directly.
---
Nitpick comments:
In `@test/onboard.test.ts`:
- Around line 5385-5386: The first assertion in the test uses
summary.includes("enabled") which is too broad; update the assertion that
references the summary variable (the assert.ok line checking web-search) to
assert the full rendered field text (e.g., the exact "web-search: enabled" line
or exact substring rendered by the app) instead of just "enabled" so the test
only passes when the web-search summary line is present; keep the channel
assertion (the assert.ok checking "telegram, slack") as is.
🪄 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 Plus
Run ID: 2280d770-9358-446c-92d9-9029b2bdccf9
📒 Files selected for processing (2)
src/lib/onboard.tstest/onboard.test.ts
…IA#2221) Addresses CodeRabbit review on NVIDIA#2221: > Confirmation gate is placed after credential-persisting steps in the > onboarding flow. configureWebSearch() and setupMessagingChannels() > run before this point, and those paths can persist credentials. So > "abort" here still leaves side effects. CodeRabbit is correct. The gate is intentionally scoped to guard the long destructive operations (docker build, provider creation on the gateway, sandbox registration) — matching the reporter's concern in NVIDIA#2165 about the ~6-minute reflex build. Moving the gate earlier would require a broader refactor of setupInference / setupMessagingChannels to defer saveCredential() calls, which is out of scope for this fix. Make the tradeoff explicit to users: - Inline comment documents the scope (what the gate guards vs. what is already persisted by the time the gate runs). - Abort message guides users to `nemoclaw credentials reset <KEY>` if they want to clear credentials entered during the aborted session. No behavior change beyond the message. The 6-minute build guard still works as designed. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/lib/onboard.ts (1)
3357-3383:⚠️ Potential issue | 🟠 MajorConfirmation gate still runs after credential persistence side effects
At Line 3357-Line 3383, aborting here still leaves previously saved credentials because
configureWebSearch()andsetupMessagingChannels()execute earlier inonboard()beforecreateSandbox(...). This is the same root concern raised previously; messaging clarification helps UX, but does not change side-effect timing.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/onboard.ts` around lines 3357 - 3383, The confirmation gate currently runs after side-effecting calls configureWebSearch() and setupMessagingChannels(), so aborting still leaves persisted credentials; move those persistence-causing calls (configureWebSearch, setupMessagingChannels, and any credential writes invoked before createSandbox) to occur only after the user confirms via promptOrDefault (or after checking dangerouslySkipPermissions / isNonInteractive), or alternatively introduce an earlier confirmation prompt before calling configureWebSearch/setupMessagingChannels; also update the summary/log text around formatOnboardConfigSummary and createSandbox to clearly state when credentials will be persisted in non-interactive flows.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@src/lib/onboard.ts`:
- Around line 3357-3383: The confirmation gate currently runs after
side-effecting calls configureWebSearch() and setupMessagingChannels(), so
aborting still leaves persisted credentials; move those persistence-causing
calls (configureWebSearch, setupMessagingChannels, and any credential writes
invoked before createSandbox) to occur only after the user confirms via
promptOrDefault (or after checking dangerouslySkipPermissions /
isNonInteractive), or alternatively introduce an earlier confirmation prompt
before calling configureWebSearch/setupMessagingChannels; also update the
summary/log text around formatOnboardConfigSummary and createSandbox to clearly
state when credentials will be persisted in non-interactive flows.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: fdf523f6-d98e-46f0-a2fa-8067d9af7890
📒 Files selected for processing (1)
src/lib/onboard.ts
… CR) Address CodeRabbit review on NVIDIA#2221: > Confirmation gate is placed after credential-persisting steps in the > onboarding flow. configureWebSearch() and setupMessagingChannels() > run before this point, and those paths can persist credentials. Move the gate out of createSandbox() and into onboard(), BEFORE the configureWebSearch + setupMessagingChannels calls. Prompt for the sandbox name early (using the existing promptValidatedSandboxName helper) so the summary can still reference the exact sandbox that will be built. createSandbox continues to receive the validated name via its existing sandboxNameOverride parameter and skips its own prompt in that case. Scope note in the inline comment: inference credentials collected in the earlier step remain persisted; an abort message still directs users to `nemoclaw credentials reset <KEY>`. Also address the paired ESM nit on the test: promote formatOnboardConfigSummary to the top-of-file static import list and drop the require/require.cache block per CodeRabbit's preferred pattern. Tests - test/onboard.test.ts: 134 tests pass (the new NVIDIA#2165 summary test still passes under the static-import pattern). Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
|
Applied both CodeRabbit suggestions:
Signed commit |
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/lib/onboard.ts (1)
3310-3334:⚠️ Potential issue | 🟠 MajorSummary output still omits API-key hint/location and optional notes requested by
#2165.
formatOnboardConfigSummary()currently renders only provider/model/web-search/messaging/sandbox-name. It still misses the API-key hint/location row and optional note lines (e.g., long-build warning) from the issue contract.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/onboard.ts` around lines 3310 - 3334, formatOnboardConfigSummary currently only prints provider/model/web-search/messaging/sandboxName; update it to also render an "API key" row (showing apiKeyHint or apiKeyLocation from the passed-in config) and an optional notes section (e.g., long-build warning) when present. Modify the function signature to accept the API key info and optional notes (or extract them from webSearchConfig if that object contains apiKeyHint/apiKeyLocation and notes), compute a string like apiKey = apiKeyHint ?? apiKeyLocation ?? "(not required/unspecified)" and append additional lines after the "Sandbox name" line for `API key:` and, if notes is truthy, one or more indented lines for the note text; keep the same bar separators and existing formatting style used in formatOnboardConfigSummary so spacing and join("\n") remain consistent.
🤖 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/onboard.ts`:
- Around line 6674-6698: The confirmation prompt runs after setupInference() has
already performed persistent changes (e.g., upsertProvider and inference set),
so move the interactive gate earlier or split setupInference into validate and
apply phases: either invoke the confirmation (the block using promptOrDefault /
isNonInteractive / dangerouslySkipPermissions) before calling setupInference(),
or refactor setupInference() into setupInferenceValidate(...) that only
checks/collects config and setupInferenceApply(...) that performs
upsertProvider/inference set and is called only after the confirmation; update
callers accordingly so no persistent mutations occur before the user affirms.
---
Duplicate comments:
In `@src/lib/onboard.ts`:
- Around line 3310-3334: formatOnboardConfigSummary currently only prints
provider/model/web-search/messaging/sandboxName; update it to also render an
"API key" row (showing apiKeyHint or apiKeyLocation from the passed-in config)
and an optional notes section (e.g., long-build warning) when present. Modify
the function signature to accept the API key info and optional notes (or extract
them from webSearchConfig if that object contains apiKeyHint/apiKeyLocation and
notes), compute a string like apiKey = apiKeyHint ?? apiKeyLocation ?? "(not
required/unspecified)" and append additional lines after the "Sandbox name" line
for `API key:` and, if notes is truthy, one or more indented lines for the note
text; keep the same bar separators and existing formatting style used in
formatOnboardConfigSummary so spacing and join("\n") remain consistent.
🪄 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 Plus
Run ID: a6ba01bf-fb9a-40eb-915d-4c7133245ab3
📒 Files selected for processing (2)
src/lib/onboard.tstest/onboard.test.ts
✅ Files skipped from review due to trivial changes (1)
- test/onboard.test.ts
…NVIDIA#2221 CR) Address CodeRabbit review nit A on NVIDIA#2221: > Summary output is still missing API-key hint/location and optional > build note from NVIDIA#2165. Extend formatOnboardConfigSummary() to accept: - credentialEnv: env-var name of the API key (e.g. "NVIDIA_API_KEY"). Rendered as "API key: <env> (stored in ~/.nemoclaw/credentials.json)" so users can see where the key was saved. When null, falls back to "(not required for <provider>)" for local providers like ollama-local. - notes: array of extra bullet lines. Callers pass "Sandbox build takes ~6 minutes on this host." (the hint the original NVIDIA#2165 reporter asked for under Build time). Updated onboard() call site to pass credentialEnv (already in outer scope, set during inference setup) and the build-time note. Tests - test/onboard.test.ts "NVIDIA#2165" case extended with assertions for API-key line, build-time note, null-credentialEnv provider-specific fallback. 134 tests pass. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
|
Follow-up applied: Nit A (summary fields) — extended Nit B (gate before setupInference) — I agree the gate should land before Signed commit |
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/lib/onboard.ts (1)
6682-6720:⚠️ Potential issue | 🟠 MajorConfirmation still runs after inference-side persistent mutations.
At Line 6631,
onboard()runssetupInference(...)before this gate, andsetupInferenceperforms persistent operations (upsertProvider,openshell inference set; see Line 4830-Line 4862). So aborting at Line 6710 exits cleanly but still leaves applied state behind.If this gate is meant to guard all persistence, move it before inference apply or split inference into validate/apply phases.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/onboard.ts` around lines 6682 - 6720, The confirmation prompt currently runs after persistent operations performed by setupInference (which calls upsertProvider and invokes the openshell inference set flow), so aborting still leaves state applied; move the confirmation gate (the prompt using promptOrDefault and the surrounding isNonInteractive/dangerouslySkipPermissions check that currently follows formatOnboardConfigSummary and promptValidatedSandboxName) to run before setupInference is executed in onboard(), or refactor setupInference into two functions (e.g., validateInferenceConfig and applyInferenceConfig) and call only validateInferenceConfig before the confirmation and applyInferenceConfig only after the user confirms; update references to setupInference, upsertProvider, and openshell inference set accordingly so no persistent mutations occur prior to user confirmation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@src/lib/onboard.ts`:
- Around line 6682-6720: The confirmation prompt currently runs after persistent
operations performed by setupInference (which calls upsertProvider and invokes
the openshell inference set flow), so aborting still leaves state applied; move
the confirmation gate (the prompt using promptOrDefault and the surrounding
isNonInteractive/dangerouslySkipPermissions check that currently follows
formatOnboardConfigSummary and promptValidatedSandboxName) to run before
setupInference is executed in onboard(), or refactor setupInference into two
functions (e.g., validateInferenceConfig and applyInferenceConfig) and call only
validateInferenceConfig before the confirmation and applyInferenceConfig only
after the user confirms; update references to setupInference, upsertProvider,
and openshell inference set accordingly so no persistent mutations occur prior
to user confirmation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 3d4cf0b5-34b9-4c6a-a604-96bb14aeda16
📒 Files selected for processing (2)
src/lib/onboard.tstest/onboard.test.ts
…CR) Address CodeRabbit review nit B on NVIDIA#2221: > Confirmation abort happens after earlier persistent mutations in > onboarding. By the time this gate runs, setupInference() has already > executed and can persist gateway/provider changes (upsertProvider, > inference set). Move the summary + Y/n gate up inside the inference retry loop, after setupNim() collects provider/model/credentialEnv in memory but BEFORE setupInference() calls upsertProvider and `openshell inference set`. Sandbox-name prompt moved up alongside the gate so the summary still references the exact sandbox that will be built. createSandbox() continues to skip its own name prompt when invoked with sandboxNameOverride. On retry (setupInference returns retry: "selection" because the API key was rejected), the loop re-runs the provider/model prompts and the user sees the summary + gate again with the refreshed config — so the gate remains authoritative even when inference validation fails the first time. Abort message and inline comment both acknowledge that credentials entered during the prompt step (setupNim credential prompt writes to ~/.nemoclaw/credentials.json via saveCredential) remain on disk; users are directed to `nemoclaw credentials reset <KEY>` to clear them. A follow-up to defer credential persistence entirely is a broader refactor (split the credentials-prompt helper into collect vs persist phases) and out of scope here. Remove the duplicate gate placement from the else-branch of resumeSandbox — the inside-loop gate is authoritative. Tests - test/onboard.test.ts "NVIDIA#2165" case: 134 tests pass. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
|
Nit B applied — moved the summary + Y/n gate up inside the inference retry loop, after The only remaining pre-gate persistence is the Signed commit |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/lib/onboard.ts (2)
6639-6650: Summary labels web/messaging as final before those prompts runAt Line 6643-Line 6645, the summary is printed before web search and messaging setup, so fresh runs usually show
disabled/noneeven when users will enable them immediately after. Consider rendering these as “pending” at this stage (or adjust heading text) to avoid false certainty.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/onboard.ts` around lines 6639 - 6650, The summary is being rendered before web search and messaging setup so formatOnboardConfigSummary(...) shows final "disabled/none" even though users will be prompted; update the call site to pass provisional values instead of definitive empties — e.g., for enabledChannels (selectedMessagingChannels) and webSearchConfig, pass a sentinel like "pending" (or a wrapper flag) when those arrays/configs are empty/undefined so formatOnboardConfigSummary and its consumers display "pending" rather than "disabled/none"; locate the call to formatOnboardConfigSummary, the selectedMessagingChannels variable, and the webSearchConfig variable and implement the conditional sentinel logic there.
3333-3335: API-key location line can be inaccurate in env-only runsAt Line 3334, the summary always says the key is stored in
~/.nemoclaw/credentials.json, but non-interactive flows may use only environment variables (not persisted). This can mislead users.Proposed adjustment
function formatOnboardConfigSummary({ provider, model, credentialEnv = null, + credentialLocation = null, webSearchConfig, enabledChannels, sandboxName, notes = [], }) { @@ - const apiKeyLine = credentialEnv - ? ` API key: ${credentialEnv} (stored in ~/.nemoclaw/credentials.json)` + const apiKeyLine = credentialEnv + ? ` API key: ${credentialEnv} (${credentialLocation || "source not specified"})` : ` API key: (not required for ${provider ?? "this provider"})`;Then pass
credentialLocationat call sites (for example:"stored in ~/.nemoclaw/credentials.json"vs"from environment for this run").🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/onboard.ts` around lines 3333 - 3335, The API key summary line currently always claims the key is "stored in ~/.nemoclaw/credentials.json" which is wrong for env-only runs; update the code that builds apiKeyLine (the variable apiKeyLine that uses credentialEnv and provider) to accept and use a credentialLocation parameter/variable instead of hardcoding the file path, and change call sites that invoke this onboarding message to pass the appropriate credentialLocation string (e.g., "stored in ~/.nemoclaw/credentials.json" vs "from environment for this run"). Ensure you update all places that construct or call the function that sets apiKeyLine so credentialLocation is provided and used when credentialEnv is truthy.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@src/lib/onboard.ts`:
- Around line 6639-6650: The summary is being rendered before web search and
messaging setup so formatOnboardConfigSummary(...) shows final "disabled/none"
even though users will be prompted; update the call site to pass provisional
values instead of definitive empties — e.g., for enabledChannels
(selectedMessagingChannels) and webSearchConfig, pass a sentinel like "pending"
(or a wrapper flag) when those arrays/configs are empty/undefined so
formatOnboardConfigSummary and its consumers display "pending" rather than
"disabled/none"; locate the call to formatOnboardConfigSummary, the
selectedMessagingChannels variable, and the webSearchConfig variable and
implement the conditional sentinel logic there.
- Around line 3333-3335: The API key summary line currently always claims the
key is "stored in ~/.nemoclaw/credentials.json" which is wrong for env-only
runs; update the code that builds apiKeyLine (the variable apiKeyLine that uses
credentialEnv and provider) to accept and use a credentialLocation
parameter/variable instead of hardcoding the file path, and change call sites
that invoke this onboarding message to pass the appropriate credentialLocation
string (e.g., "stored in ~/.nemoclaw/credentials.json" vs "from environment for
this run"). Ensure you update all places that construct or call the function
that sets apiKeyLine so credentialLocation is provided and used when
credentialEnv is truthy.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 7f45f4d6-87eb-4c87-8268-8a03825e3943
📒 Files selected for processing (1)
src/lib/onboard.ts
|
Follow-up filed as #2226 — defers |
|
✨ Thanks for submitting this PR that proposes a way to add a review summary and confirmation gate — this could help provide a more user-friendly experience for sandbox creation. Related open issues: |
ericksoa
left a comment
There was a problem hiding this comment.
Good UX improvement. The iterative refinement through 5 commits shows the gate was placed thoughtfully — final position is before setupInference() calls upsertProvider, which is the right boundary.
Looks good
- Gate placement — inside the inference retry loop, after provider/model/credentialEnv are collected in memory but before any gateway mutations. On retry, the user sees the updated summary and gate again. Correct.
- Non-interactive mode — prints summary for log clarity but skips the prompt. Automated flows are not blocked.
- Abort handling — exits 0 (clean, not error) with guidance to
nemoclaw credentials resetfor any credentials already persisted during the prompt phase. Honest about the scope. formatOnboardConfigSummaryis pure and exported — directly testable, no I/O.- Test coverage — covers full-field, empty channels, null webSearch, null credentialEnv fallback, and the "(unset)" null-field guard. Good.
- "Web search and messaging channels will be prompted next" — correctly sets expectations that the summary is a pre-build checkpoint, not a complete configuration review.
Minor (non-blocking)
- The "~6 minutes on this host" note is hardcoded. If it ever becomes misleading (fast machines, cached builds), consider deriving it from the previous build time or dropping it.
LGTM.
…IDIA#2221 tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… confirms Follow-up to NVIDIA#2221 addressing the remaining credential-persistence window CodeRabbit flagged: setupNim's credential prompt writes to ~/.nemoclaw/credentials.json via saveCredential as soon as the user types a key, so a later abort at the review gate still left that key on disk. The abort message worked around it by directing users to `nemoclaw credentials reset <KEY>`. Introduce a module-level defer flag so credential-prompt writes are held in memory (process.env only) and only flushed to disk after the review gate confirms. Mechanism - `beginDeferredCredentialPersistence()` — arm the flag and clear the pending set. Called once at the top of the inference retry loop in onboard(), only when the review gate will actually fire (interactive + not --dangerously-skip-permissions). - `replaceNamedCredential()` — when the flag is armed, set process.env and add the env name to `pendingDeferredCredentials`, skip the saveCredential call. Print "Key held in memory; will be saved to credentials.json on confirm." instead of the usual "Key saved". - `flushDeferredCredentials()` — iterate the pending set, call saveCredential(envName, process.env[envName]) for each, clear the set. Flag stays armed so retry-loop iterations after an inference validation failure continue to defer their replacement keys. - `discardDeferredCredentials()` — clear the set and disarm the flag. Called on gate abort — nothing ever reached disk. - `endDeferredCredentialPersistence()` — clear + disarm. Called after the retry loop breaks successfully so downstream prompts (Brave, messaging tokens — already after the gate, already after flush) use the normal immediate-persist path. Abort flow The gate's "n/no" branch now calls discardDeferredCredentials() and prints "No credentials were persisted to disk." — replacing the earlier "credentials are stored in ~/.nemoclaw/credentials.json; clear them with `nemoclaw credentials reset <KEY>`" workaround. Non-interactive and --dangerously-skip-permissions flows skip the deferral entirely (no gate to flush at) and use the existing immediate-persist path. Scope Touches only onboard.ts. The other saveCredential call sites (configureWebSearch, setupMessagingChannels, sandbox-channels, sandbox-config) already run after the gate and don't need deferral. Tests - test/onboard.test.ts — 134 tests pass (no regressions in the non-deferred or resume paths). The defer helpers themselves are module-scoped with no test seams that don't require stdin simulation; their correctness is covered by the existing onboard integration tests which exercise both the interactive (deferral on) and non-interactive (deferral off) code paths. Stacks on NVIDIA#2221 — depends on the gate and formatOnboardConfigSummary landing first. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
… confirms Follow-up to NVIDIA#2221 addressing the remaining credential-persistence window CodeRabbit flagged: setupNim's credential prompt writes to ~/.nemoclaw/credentials.json via saveCredential as soon as the user types a key, so a later abort at the review gate still left that key on disk. Introduce a module-level defer flag so credential-prompt writes are held in memory until the gate confirms, plus follow-up fixes addressing CodeRabbit review on b20e3b3. Mechanism - beginDeferredCredentialPersistence() arms the flag, clears the pending set, resets the flush-tracking bit. Called once at the top of the inference retry loop in onboard(), only when the review gate will actually fire (interactive + not --dangerously-skip-permissions). - replaceNamedCredential(), when the flag is armed, sets process.env and adds the env name to pendingDeferredCredentials, skipping the saveCredential call. Prints "Key held in memory; will be saved to credentials.json on confirm." instead of the usual "Key saved". - flushDeferredCredentials() iterates the pending set, calls saveCredential(envName, process.env[envName]) for each, clears the set, and marks deferredCredentialsFlushed so a subsequent abort after a confirmed-then-failed retry iteration tells the truth. - discardDeferredCredentials() now also clears the pending env vars from process.env, not just the set. Called on gate abort. - endDeferredCredentialPersistence() clears, disarms, resets the flush bit. Called after the retry loop breaks successfully so downstream prompts (Brave, messaging tokens) use the normal immediate path. - discardStagedCredential(envName) removes a single envName from the pending set and process.env. Used when setupNim goes back to selectionLoop after a credential was staged for an abandoned provider. setupNim changes (close CodeRabbit Majors at lines 761 and 6798) - In deferred mode only, route the NVIDIA API key prompt through replaceNamedCredential (respects the flag) instead of ensureApiKey (which writes immediately). Non-deferred mode still calls ensureApiKey so existing mocks and single-path flows are unchanged. The onboarding box UI is preserved inline; validateNvidiaApiKeyValue runs the same starts-with-nvapi- check ensureApiKey did. - Track stagedCredentialEnvThisIteration across selectionLoop iterations and discardStagedCredential() at the top of each new iteration so a user who enters key A for provider X, navigates back, then picks provider Y with key B only has B in pendingDeferredCredentials when the gate flushes. formatOnboardConfigSummary changes (close CodeRabbit Minor at line 3378) - New credentialStorageState parameter distinguishes "deferred" (key held in memory) from "persisted" (already on disk). The summary now says "held in memory — will be saved to ~/.nemoclaw/credentials.json on confirm" when the key is still pending so the gate's promise matches reality. The call site passes the state based on pendingDeferredCredentials membership. Abort flow (closes CodeRabbit Minor at line 6883) - The gate's n/no branch now checks haveDeferredCredentialsBeenFlushed() before printing its after-message. If no flush ever happened it says "No credentials were persisted to disk." as before. If an earlier retry iteration flushed and this iteration aborted, it acknowledges that "credentials confirmed in an earlier attempt are already in credentials.json" and points to nemoclaw credentials reset <KEY>. Non-interactive and --dangerously-skip-permissions flows skip the deferral entirely and use the existing immediate-persist path. Scope Touches only onboard.ts. The other saveCredential call sites (configureWebSearch, setupMessagingChannels, sandbox-channels, sandbox-config) already run after the gate and dont need deferral. Tests - test/onboard.test.ts — 135 tests pass. - test/onboard-selection.test.ts — 33 tests pass (verifies setupNim back-nav + NVIDIA Endpoints path). - Typecheck clean. Stacks on NVIDIA#2221 — depends on the gate and formatOnboardConfigSummary landing first. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
… confirms Follow-up to NVIDIA#2221 addressing the remaining credential-persistence window CodeRabbit flagged: setupNim's credential prompt writes to ~/.nemoclaw/credentials.json via saveCredential as soon as the user types a key, so a later abort at the review gate still left that key on disk. Introduce a module-level defer flag so credential-prompt writes are held in memory until the gate confirms, plus follow-up fixes addressing CodeRabbit review on b20e3b3. Mechanism - beginDeferredCredentialPersistence() arms the flag, clears the pending set, resets the flush-tracking bit. Called once at the top of the inference retry loop in onboard(), only when the review gate will actually fire (interactive + not --dangerously-skip-permissions). - replaceNamedCredential(), when the flag is armed, sets process.env and adds the env name to pendingDeferredCredentials, skipping the saveCredential call. Prints "Key held in memory; will be saved to credentials.json on confirm." instead of the usual "Key saved". - flushDeferredCredentials() iterates the pending set, calls saveCredential(envName, process.env[envName]) for each, clears the set, and marks deferredCredentialsFlushed so a subsequent abort after a confirmed-then-failed retry iteration tells the truth. - discardDeferredCredentials() now also clears the pending env vars from process.env, not just the set. Called on gate abort. - endDeferredCredentialPersistence() clears, disarms, resets the flush bit. Called after the retry loop breaks successfully so downstream prompts (Brave, messaging tokens) use the normal immediate path. - discardStagedCredential(envName) removes a single envName from the pending set and process.env. Used when setupNim goes back to selectionLoop after a credential was staged for an abandoned provider. setupNim changes (close CodeRabbit Majors at lines 761 and 6798) - In deferred mode only, route the NVIDIA API key prompt through replaceNamedCredential (respects the flag) instead of ensureApiKey (which writes immediately). Non-deferred mode still calls ensureApiKey so existing mocks and single-path flows are unchanged. The onboarding box UI is preserved inline; validateNvidiaApiKeyValue runs the same starts-with-nvapi- check ensureApiKey did. - Track stagedCredentialEnvThisIteration across selectionLoop iterations and discardStagedCredential() at the top of each new iteration so a user who enters key A for provider X, navigates back, then picks provider Y with key B only has B in pendingDeferredCredentials when the gate flushes. formatOnboardConfigSummary changes (close CodeRabbit Minor at line 3378) - New credentialStorageState parameter distinguishes "deferred" (key held in memory) from "persisted" (already on disk). The summary now says "held in memory — will be saved to ~/.nemoclaw/credentials.json on confirm" when the key is still pending so the gate's promise matches reality. The call site passes the state based on pendingDeferredCredentials membership. Abort flow (closes CodeRabbit Minor at line 6883) - The gate's n/no branch now checks haveDeferredCredentialsBeenFlushed() before printing its after-message. If no flush ever happened it says "No credentials were persisted to disk." as before. If an earlier retry iteration flushed and this iteration aborted, it acknowledges that "credentials confirmed in an earlier attempt are already in credentials.json" and points to nemoclaw credentials reset <KEY>. Non-interactive and --dangerously-skip-permissions flows skip the deferral entirely and use the existing immediate-persist path. Scope Touches only onboard.ts. The other saveCredential call sites (configureWebSearch, setupMessagingChannels, sandbox-channels, sandbox-config) already run after the gate and dont need deferral. Tests - test/onboard.test.ts — 135 tests pass. - test/onboard-selection.test.ts — 33 tests pass (verifies setupNim back-nav + NVIDIA Endpoints path). - Typecheck clean. Stacks on NVIDIA#2221 — depends on the gate and formatOnboardConfigSummary landing first. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
## Summary Catches up the user-facing docs for changes merged since v0.0.24 and bumps `docs/versions1.json` so the next docs build publishes as 0.0.25. ## Changes - `docs/reference/troubleshooting.md`: corrected the JetPack 7 (L4T 39.x) entry to reflect the new conditional `br_netfilter` auto-load on R39 hosts that lack it (from #2419), and added a new "DNS resolution from inside docker fails (corporate firewall)" section covering the new container-DNS preflight probe and platform-specific remediation paths (from #2349). - `docs/get-started/quickstart.md`: added a "Review the Configuration Before the Sandbox Build" subsection documenting the new `[Y/n]` review gate that fires after the sandbox-name prompt (from #2221). - `docs/versions1.json`: promoted 0.0.25 to `preferred: true`, demoted 0.0.24, and trimmed to ten entries to match what `scripts/bump-version.ts` writes. `docs/project.json` regenerates from `versions1.json` at build time and now reports `0.0.25`. - `.agents/skills/nemoclaw-user-get-started/` and `.agents/skills/nemoclaw-user-reference/`: regenerated via `scripts/docs-to-skills.py`. ## Type of Change - [ ] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [x] 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 - [x] Docs updated for user-facing behavior changes - [x] `make docs` builds without warnings (doc changes only) - [x] 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) ## AI Disclosure - [x] AI-assisted — tool: Claude Code --- Signed-off-by: Miyoung Choi <miyoungc@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Onboarding now shows a configuration review and requires explicit confirmation before building a sandbox; non-interactive mode prints the summary without prompting. * **Documentation** * Expanded Jetson troubleshooting for JetPack 7 / L4T 39.x and conditional br_netfilter guidance. * Added corporate-firewall DNS troubleshooting with platform-specific remediation and a verification nslookup step. * Quickstart updated to document the new confirmation flow. * **Chores** * Documentation version index updated. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… confirms Follow-up to NVIDIA#2221 addressing the remaining credential-persistence window CodeRabbit flagged: setupNim's credential prompt writes to ~/.nemoclaw/credentials.json via saveCredential as soon as the user types a key, so a later abort at the review gate still left that key on disk. Introduce a module-level defer flag so credential-prompt writes are held in memory until the gate confirms, plus follow-up fixes addressing CodeRabbit review on b20e3b3. Mechanism - beginDeferredCredentialPersistence() arms the flag, clears the pending set, resets the flush-tracking bit. Called once at the top of the inference retry loop in onboard(), only when the review gate will actually fire (interactive + not --dangerously-skip-permissions). - replaceNamedCredential(), when the flag is armed, sets process.env and adds the env name to pendingDeferredCredentials, skipping the saveCredential call. Prints "Key held in memory; will be saved to credentials.json on confirm." instead of the usual "Key saved". - flushDeferredCredentials() iterates the pending set, calls saveCredential(envName, process.env[envName]) for each, clears the set, and marks deferredCredentialsFlushed so a subsequent abort after a confirmed-then-failed retry iteration tells the truth. - discardDeferredCredentials() now also clears the pending env vars from process.env, not just the set. Called on gate abort. - endDeferredCredentialPersistence() clears, disarms, resets the flush bit. Called after the retry loop breaks successfully so downstream prompts (Brave, messaging tokens) use the normal immediate path. - discardStagedCredential(envName) removes a single envName from the pending set and process.env. Used when setupNim goes back to selectionLoop after a credential was staged for an abandoned provider. setupNim changes (close CodeRabbit Majors at lines 761 and 6798) - In deferred mode only, route the NVIDIA API key prompt through replaceNamedCredential (respects the flag) instead of ensureApiKey (which writes immediately). Non-deferred mode still calls ensureApiKey so existing mocks and single-path flows are unchanged. The onboarding box UI is preserved inline; validateNvidiaApiKeyValue runs the same starts-with-nvapi- check ensureApiKey did. - Track stagedCredentialEnvThisIteration across selectionLoop iterations and discardStagedCredential() at the top of each new iteration so a user who enters key A for provider X, navigates back, then picks provider Y with key B only has B in pendingDeferredCredentials when the gate flushes. formatOnboardConfigSummary changes (close CodeRabbit Minor at line 3378) - New credentialStorageState parameter distinguishes "deferred" (key held in memory) from "persisted" (already on disk). The summary now says "held in memory — will be saved to ~/.nemoclaw/credentials.json on confirm" when the key is still pending so the gate's promise matches reality. The call site passes the state based on pendingDeferredCredentials membership. Abort flow (closes CodeRabbit Minor at line 6883) - The gate's n/no branch now checks haveDeferredCredentialsBeenFlushed() before printing its after-message. If no flush ever happened it says "No credentials were persisted to disk." as before. If an earlier retry iteration flushed and this iteration aborted, it acknowledges that "credentials confirmed in an earlier attempt are already in credentials.json" and points to nemoclaw credentials reset <KEY>. Non-interactive and --dangerously-skip-permissions flows skip the deferral entirely and use the existing immediate-persist path. Scope Touches only onboard.ts. The other saveCredential call sites (configureWebSearch, setupMessagingChannels, sandbox-channels, sandbox-config) already run after the gate and dont need deferral. Tests - test/onboard.test.ts — 135 tests pass. - test/onboard-selection.test.ts — 33 tests pass (verifies setupNim back-nav + NVIDIA Endpoints path). - Typecheck clean. Stacks on NVIDIA#2221 — depends on the gate and formatOnboardConfigSummary landing first. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
… confirms Follow-up to NVIDIA#2221 addressing the remaining credential-persistence window CodeRabbit flagged: setupNim's credential prompt writes to ~/.nemoclaw/credentials.json via saveCredential as soon as the user types a key, so a later abort at the review gate still left that key on disk. Introduce a module-level defer flag so credential-prompt writes are held in memory until the gate confirms, plus follow-up fixes addressing CodeRabbit review on b20e3b3. Mechanism - beginDeferredCredentialPersistence() arms the flag, clears the pending set, resets the flush-tracking bit. Called once at the top of the inference retry loop in onboard(), only when the review gate will actually fire (interactive + not --dangerously-skip-permissions). - replaceNamedCredential(), when the flag is armed, sets process.env and adds the env name to pendingDeferredCredentials, skipping the saveCredential call. Prints "Key held in memory; will be saved to credentials.json on confirm." instead of the usual "Key saved". - flushDeferredCredentials() iterates the pending set, calls saveCredential(envName, process.env[envName]) for each, clears the set, and marks deferredCredentialsFlushed so a subsequent abort after a confirmed-then-failed retry iteration tells the truth. - discardDeferredCredentials() now also clears the pending env vars from process.env, not just the set. Called on gate abort. - endDeferredCredentialPersistence() clears, disarms, resets the flush bit. Called after the retry loop breaks successfully so downstream prompts (Brave, messaging tokens) use the normal immediate path. - discardStagedCredential(envName) removes a single envName from the pending set and process.env. Used when setupNim goes back to selectionLoop after a credential was staged for an abandoned provider. setupNim changes (close CodeRabbit Majors at lines 761 and 6798) - In deferred mode only, route the NVIDIA API key prompt through replaceNamedCredential (respects the flag) instead of ensureApiKey (which writes immediately). Non-deferred mode still calls ensureApiKey so existing mocks and single-path flows are unchanged. The onboarding box UI is preserved inline; validateNvidiaApiKeyValue runs the same starts-with-nvapi- check ensureApiKey did. - Track stagedCredentialEnvThisIteration across selectionLoop iterations and discardStagedCredential() at the top of each new iteration so a user who enters key A for provider X, navigates back, then picks provider Y with key B only has B in pendingDeferredCredentials when the gate flushes. formatOnboardConfigSummary changes (close CodeRabbit Minor at line 3378) - New credentialStorageState parameter distinguishes "deferred" (key held in memory) from "persisted" (already on disk). The summary now says "held in memory — will be saved to ~/.nemoclaw/credentials.json on confirm" when the key is still pending so the gate's promise matches reality. The call site passes the state based on pendingDeferredCredentials membership. Abort flow (closes CodeRabbit Minor at line 6883) - The gate's n/no branch now checks haveDeferredCredentialsBeenFlushed() before printing its after-message. If no flush ever happened it says "No credentials were persisted to disk." as before. If an earlier retry iteration flushed and this iteration aborted, it acknowledges that "credentials confirmed in an earlier attempt are already in credentials.json" and points to nemoclaw credentials reset <KEY>. Non-interactive and --dangerously-skip-permissions flows skip the deferral entirely and use the existing immediate-persist path. Scope Touches only onboard.ts. The other saveCredential call sites (configureWebSearch, setupMessagingChannels, sandbox-channels, sandbox-config) already run after the gate and dont need deferral. Tests - test/onboard.test.ts — 135 tests pass. - test/onboard-selection.test.ts — 33 tests pass (verifies setupNim back-nav + NVIDIA Endpoints path). - Typecheck clean. Stacks on NVIDIA#2221 — depends on the gate and formatOnboardConfigSummary landing first. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
… confirms Follow-up to NVIDIA#2221 addressing the remaining credential-persistence window CodeRabbit flagged: setupNim's credential prompt writes to ~/.nemoclaw/credentials.json via saveCredential as soon as the user types a key, so a later abort at the review gate still left that key on disk. Introduce a module-level defer flag so credential-prompt writes are held in memory until the gate confirms, plus follow-up fixes addressing CodeRabbit review on b20e3b3. Mechanism - beginDeferredCredentialPersistence() arms the flag, clears the pending set, resets the flush-tracking bit. Called once at the top of the inference retry loop in onboard(), only when the review gate will actually fire (interactive + not --dangerously-skip-permissions). - replaceNamedCredential(), when the flag is armed, sets process.env and adds the env name to pendingDeferredCredentials, skipping the saveCredential call. Prints "Key held in memory; will be saved to credentials.json on confirm." instead of the usual "Key saved". - flushDeferredCredentials() iterates the pending set, calls saveCredential(envName, process.env[envName]) for each, clears the set, and marks deferredCredentialsFlushed so a subsequent abort after a confirmed-then-failed retry iteration tells the truth. - discardDeferredCredentials() now also clears the pending env vars from process.env, not just the set. Called on gate abort. - endDeferredCredentialPersistence() clears, disarms, resets the flush bit. Called after the retry loop breaks successfully so downstream prompts (Brave, messaging tokens) use the normal immediate path. - discardStagedCredential(envName) removes a single envName from the pending set and process.env. Used when setupNim goes back to selectionLoop after a credential was staged for an abandoned provider. setupNim changes (close CodeRabbit Majors at lines 761 and 6798) - In deferred mode only, route the NVIDIA API key prompt through replaceNamedCredential (respects the flag) instead of ensureApiKey (which writes immediately). Non-deferred mode still calls ensureApiKey so existing mocks and single-path flows are unchanged. The onboarding box UI is preserved inline; validateNvidiaApiKeyValue runs the same starts-with-nvapi- check ensureApiKey did. - Track stagedCredentialEnvThisIteration across selectionLoop iterations and discardStagedCredential() at the top of each new iteration so a user who enters key A for provider X, navigates back, then picks provider Y with key B only has B in pendingDeferredCredentials when the gate flushes. formatOnboardConfigSummary changes (close CodeRabbit Minor at line 3378) - New credentialStorageState parameter distinguishes "deferred" (key held in memory) from "persisted" (already on disk). The summary now says "held in memory — will be saved to ~/.nemoclaw/credentials.json on confirm" when the key is still pending so the gate's promise matches reality. The call site passes the state based on pendingDeferredCredentials membership. Abort flow (closes CodeRabbit Minor at line 6883) - The gate's n/no branch now checks haveDeferredCredentialsBeenFlushed() before printing its after-message. If no flush ever happened it says "No credentials were persisted to disk." as before. If an earlier retry iteration flushed and this iteration aborted, it acknowledges that "credentials confirmed in an earlier attempt are already in credentials.json" and points to nemoclaw credentials reset <KEY>. Non-interactive and --dangerously-skip-permissions flows skip the deferral entirely and use the existing immediate-persist path. Scope Touches only onboard.ts. The other saveCredential call sites (configureWebSearch, setupMessagingChannels, sandbox-channels, sandbox-config) already run after the gate and dont need deferral. Tests - test/onboard.test.ts — 135 tests pass. - test/onboard-selection.test.ts — 33 tests pass (verifies setupNim back-nav + NVIDIA Endpoints path). - Typecheck clean. Stacks on NVIDIA#2221 — depends on the gate and formatOnboardConfigSummary landing first. Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
…ox build (NVIDIA#2221) ## Summary `nemoclaw onboard` collected 8 inputs then immediately began a ~6-minute sandbox image build + provider/credential persistence with **no final confirmation**. Users who hit Enter by reflex at the sandbox-name prompt (where `[my-assistant]` is pre-filled) were locked into a build they did not intend to start. This PR adds a compact summary + `[Y/n]` gate right after the sandbox-name prompt in `createSandbox()`, before any destructive action (docker build, `patchStagedDockerfile`, provider creation). ### Before ``` [6/8] Creating sandbox ────────────────────────────────────────────── Sandbox name (lowercase, starts with letter, hyphens ok) [my-assistant]: ← Enter pressed → [7/8] Building sandbox image... ← 6 minutes locked in ``` ### After ``` [6/8] Creating sandbox ────────────────────────────────────────────── Sandbox name (lowercase, starts with letter, hyphens ok) [my-assistant]: ← Enter pressed → ────────────────────────────────────────────────── Review configuration ────────────────────────────────────────────────── Provider: gemini-api Model: gemini-2.5-flash Web search: disabled Messaging: none Sandbox name: my-assistant ────────────────────────────────────────────────── Apply this configuration? [Y/n]: ``` Default is `Y` so a confident user still just hits Enter once. Answering `n`/`no` prints `"Aborted. Re-run nemoclaw onboard to start over."` and exits `0` (clean abort, not an error). Non-interactive runs (`NEMOCLAW_NON_INTERACTIVE=1`, or `--dangerously-skip-permissions`) still print the summary for log clarity but skip the gate — automated flows opted out of prompts. ## Related Issue Closes NVIDIA#2165 (priority:high, `Getting Started` label) ## Changes - **`src/lib/onboard.ts`** — added `formatOnboardConfigSummary()` (pure, exported for testing) and an inline confirm prompt in `createSandbox()` right after the sandbox-name validation. Non-interactive / dangerouslySkipPermissions skip the prompt but still emit the summary. ## Testing - [x] `npx vitest run test/onboard.test.ts` — 134 tests pass (+1 for new summary test) - [x] `npx vitest run test/runner.test.ts` — 60/60 pass (exercises create-sandbox e2e) - [x] `npm run build:cli` + `npm run typecheck:cli` clean Executed: - New test covers: full-field render (provider/model/web/messaging/sandbox name), empty channels → `"none"`, null webSearch → `"disabled"`, and null-field → `"(unset)"` fallback (guards against stringified `"undefined"` leaking). ## Checklist - [x] Follows [Conventional Commits](https://www.conventionalcommits.org/) - [x] Commit is signed (SSH) - [x] DCO Signed-off-by trailer present Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a configuration review summary showing provider, model, API credential hint (or "not required"), web search status, messaging channels (or "none"), sandbox name (prompted if missing), and optional notes. * Interactive confirmation prompt lets users approve or abort applying the configuration; abort prints guidance and exits onboarding (non-interactive runs skip the prompt but still display the summary). * **Tests** * Added tests validating the configuration summary formatting and placeholder rendering. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: latenighthackathon <latenighthackathon@users.noreply.github.com> Co-authored-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
## Summary Catches up the user-facing docs for changes merged since v0.0.24 and bumps `docs/versions1.json` so the next docs build publishes as 0.0.25. ## Changes - `docs/reference/troubleshooting.md`: corrected the JetPack 7 (L4T 39.x) entry to reflect the new conditional `br_netfilter` auto-load on R39 hosts that lack it (from NVIDIA#2419), and added a new "DNS resolution from inside docker fails (corporate firewall)" section covering the new container-DNS preflight probe and platform-specific remediation paths (from NVIDIA#2349). - `docs/get-started/quickstart.md`: added a "Review the Configuration Before the Sandbox Build" subsection documenting the new `[Y/n]` review gate that fires after the sandbox-name prompt (from NVIDIA#2221). - `docs/versions1.json`: promoted 0.0.25 to `preferred: true`, demoted 0.0.24, and trimmed to ten entries to match what `scripts/bump-version.ts` writes. `docs/project.json` regenerates from `versions1.json` at build time and now reports `0.0.25`. - `.agents/skills/nemoclaw-user-get-started/` and `.agents/skills/nemoclaw-user-reference/`: regenerated via `scripts/docs-to-skills.py`. ## Type of Change - [ ] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [x] 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 - [x] Docs updated for user-facing behavior changes - [x] `make docs` builds without warnings (doc changes only) - [x] 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) ## AI Disclosure - [x] AI-assisted — tool: Claude Code --- Signed-off-by: Miyoung Choi <miyoungc@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Onboarding now shows a configuration review and requires explicit confirmation before building a sandbox; non-interactive mode prints the summary without prompting. * **Documentation** * Expanded Jetson troubleshooting for JetPack 7 / L4T 39.x and conditional br_netfilter guidance. * Added corporate-firewall DNS troubleshooting with platform-specific remediation and a verification nslookup step. * Quickstart updated to document the new confirmation flow. * **Chores** * Documentation version index updated. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary Catches up the user-facing docs for changes merged since v0.0.24 and bumps `docs/versions1.json` so the next docs build publishes as 0.0.25. ## Changes - `docs/reference/troubleshooting.md`: corrected the JetPack 7 (L4T 39.x) entry to reflect the new conditional `br_netfilter` auto-load on R39 hosts that lack it (from NVIDIA#2419), and added a new "DNS resolution from inside docker fails (corporate firewall)" section covering the new container-DNS preflight probe and platform-specific remediation paths (from NVIDIA#2349). - `docs/get-started/quickstart.md`: added a "Review the Configuration Before the Sandbox Build" subsection documenting the new `[Y/n]` review gate that fires after the sandbox-name prompt (from NVIDIA#2221). - `docs/versions1.json`: promoted 0.0.25 to `preferred: true`, demoted 0.0.24, and trimmed to ten entries to match what `scripts/bump-version.ts` writes. `docs/project.json` regenerates from `versions1.json` at build time and now reports `0.0.25`. - `.agents/skills/nemoclaw-user-get-started/` and `.agents/skills/nemoclaw-user-reference/`: regenerated via `scripts/docs-to-skills.py`. ## Type of Change - [ ] Code change (feature, bug fix, or refactor) - [ ] Code change with doc updates - [x] 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 - [x] Docs updated for user-facing behavior changes - [x] `make docs` builds without warnings (doc changes only) - [x] 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) ## AI Disclosure - [x] AI-assisted — tool: Claude Code --- Signed-off-by: Miyoung Choi <miyoungc@nvidia.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Onboarding now shows a configuration review and requires explicit confirmation before building a sandbox; non-interactive mode prints the summary without prompting. * **Documentation** * Expanded Jetson troubleshooting for JetPack 7 / L4T 39.x and conditional br_netfilter guidance. * Added corporate-firewall DNS troubleshooting with platform-specific remediation and a verification nslookup step. * Quickstart updated to document the new confirmation flow. * **Chores** * Documentation version index updated. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
nemoclaw onboardcollected 8 inputs then immediately began a ~6-minute sandbox image build + provider/credential persistence with no final confirmation. Users who hit Enter by reflex at the sandbox-name prompt (where[my-assistant]is pre-filled) were locked into a build they did not intend to start.This PR adds a compact summary +
[Y/n]gate right after the sandbox-name prompt increateSandbox(), before any destructive action (docker build,patchStagedDockerfile, provider creation).Before
After
Default is
Yso a confident user still just hits Enter once. Answeringn/noprints"Aborted. Re-run nemoclaw onboard to start over."and exits0(clean abort, not an error).Non-interactive runs (
NEMOCLAW_NON_INTERACTIVE=1, or--dangerously-skip-permissions) still print the summary for log clarity but skip the gate — automated flows opted out of prompts.Related Issue
Closes #2165 (priority:high,
Getting Startedlabel)Changes
src/lib/onboard.ts— addedformatOnboardConfigSummary()(pure, exported for testing) and an inline confirm prompt increateSandbox()right after the sandbox-name validation. Non-interactive / dangerouslySkipPermissions skip the prompt but still emit the summary.Testing
npx vitest run test/onboard.test.ts— 134 tests pass (+1 for new summary test)npx vitest run test/runner.test.ts— 60/60 pass (exercises create-sandbox e2e)npm run build:cli+npm run typecheck:clicleanExecuted:
"none", null webSearch →"disabled", and null-field →"(unset)"fallback (guards against stringified"undefined"leaking).Checklist
Signed-off-by: latenighthackathon latenighthackathon@users.noreply.github.com
Summary by CodeRabbit
New Features
Tests