fix(cli): bind dashboard forward to all interfaces under WSL2#1503
fix(cli): bind dashboard forward to all interfaces under WSL2#1503ericksoa merged 9 commits intoNVIDIA:mainfrom
Conversation
The dashboard port forward bound to 127.0.0.1, which is not reachable from Windows browsers when NemoClaw runs inside WSL2. Detect WSL and bind to 0.0.0.0 instead so the dashboard is accessible via the WSL host IP. Also adds a VS Code/WSL-friendly URL to the dashboard access info that uses the WSL host IP from hostname -I. Signed-off-by: Darren McLeod <tempuskg@gmail.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:
📝 WalkthroughWalkthroughAdds WSL-aware dashboard forwarding and access utilities: new helpers for forward port/command, authenticated URLs, WSL host probing, access/guidance generation, and updates printDashboard() and ensureDashboardForward() to handle WSL-specific targets and port resolution. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Onboard as "Onboard Module"
participant WSL as "WSL Host (hostname -I)"
participant Forwarder as "Sandbox Forwarder"
User->>Onboard: request dashboard info / start forward
Onboard->>WSL: probe host IP (hostname -I) [if isWsl]
Onboard->>Forwarder: build & send forward command (127.0.0.1 or 0.0.0.0:${CONTROL_UI_PORT})
Forwarder-->>Onboard: forward started
Onboard-->>User: return labeled URLs (loopback, Alt n, VS Code/WSL) and guidance lines
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
Adds WSL-specific handling for the CLI dashboard port-forward and access URL generation so the dashboard remains reachable from the Windows host when NemoClaw runs inside WSL2.
Changes:
- Introduces helpers to (a) choose a WSL-friendly forward bind target and (b) generate dashboard access URLs, including a WSL host-IP URL derived from
hostname -I. - Adds guidance-string helper(s) intended to improve user-facing instructions for dashboard access under WSL.
- Adds unit tests covering WSL bind target selection and WSL URL generation.
Reviewed changes
Copilot reviewed 1 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
bin/lib/onboard.js |
Adds new dashboard/WSL helper functions and exports them for use by the CLI. |
test/onboard.test.js |
Adds tests validating the new helper behavior for WSL binding and URL generation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@bin/lib/onboard.js`:
- Around line 3759-3821: Ensure the runtime onboarding flow uses the new
helpers: update ensureDashboardForward() so it no longer computes the bind
target directly with resolveDashboardForwardTarget(chatUiUrl) or hardcode
127.0.0.1; instead call getDashboardForwardStartCommand(sandboxName, {
...options, /* preserve chatUiUrl when remote-host */ }) or otherwise use
getWslHostAddress/options to pick the correct forwardTarget so WSL binds to the
WSL host IP when appropriate; update getDashboardForwardStartCommand to
accept/preserve a chatUiUrl/remote-host flag if needed rather than always using
127.0.0.1. Also change printDashboard() to render the URLs from
getDashboardAccessInfo(sandboxName, options) and the lines from
getDashboardGuidanceLines(dashboardAccess) instead of directly calling
buildControlUiUrls(), so the VS Code/WSL URL generated by
buildAuthenticatedDashboardUrl shows up to users.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: eef2eaaa-811a-467c-b806-4b874a755f12
📒 Files selected for processing (2)
bin/lib/onboard.jstest/onboard.test.js
Route ensureDashboardForward() through isWsl() so the port forward actually binds to 0.0.0.0 under WSL2. Update printDashboard() to use getDashboardAccessInfo() and getDashboardGuidanceLines() so users see the VS Code/WSL URL at onboard time. Split the brittle forward-command test assertion into individual toContain checks per Copilot review feedback, and make the createSandbox integration test WSL-aware. Signed-off-by: Darren McLeod <tempuskg@gmail.com>
|
✨ Thanks for submitting this fix, which proposes a way to bind the dashboard forward to all interfaces under WSL2, making it accessible from Windows browsers. |
cv
left a comment
There was a problem hiding this comment.
LGTM — security review PASS.
0.0.0.0bind correctly gated behindisWsl()(4-signal detection)- Non-WSL systems unaffected — stay on loopback
- WSL2 network exposure is an accepted trade-off, mitigated by token auth
hostname -Ioutput is display-only (console URL for user)- Good test coverage with injected options for deterministic WSL simulation
No concerns.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@test/onboard.test.ts`:
- Around line 401-413: The test is calling getDashboardForwardStartCommand which
triggers the openshell binary resolution and may call process.exit(1) when the
binary is missing; to make the test hermetic, mock/stub the openshell-resolution
path so it returns a valid dummy path (or stub the specific resolver function
that checks for the openshell binary) before invoking
getDashboardForwardStartCommand, or alternatively spy on process.exit to prevent
exiting and assert it was not called; ensure you restore the stub/spy after the
test. Use the symbol getDashboardForwardStartCommand to locate the call site and
the resolver function (the module that looks up the openshell binary) to apply
the mock.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 8c4ab6c8-a595-4a35-b2de-075105f86feb
📒 Files selected for processing (2)
src/lib/onboard.tstest/onboard.test.ts
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
test/onboard.test.ts (1)
401-413:⚠️ Potential issue | 🔴 CriticalMake this WSL forward-bind test hermetic (still host-dependent).
At Line 402, this test calls
getDashboardForwardStartCommand(...)without stubbing the openshell binary resolution path, so it can still fail withprocess.exit(1)on hosts whereopenshellis unavailable.🔧 Suggested fix
it("binds the dashboard forward to all interfaces under WSL", () => { - const command = getDashboardForwardStartCommand("the-crucible", { - env: { WSL_DISTRO_NAME: "Ubuntu" }, - platform: "linux", - release: "6.6.87.2-microsoft-standard-WSL2", - }); - - expect(command).toContain("forward"); - expect(command).toContain("start"); - expect(command).toContain("--background"); - expect(command).toContain("0.0.0.0:18789"); - expect(command).toContain("the-crucible"); + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-wsl-forward-")); + const fakeBin = path.join(tmpDir, "bin"); + fs.mkdirSync(fakeBin, { recursive: true }); + fs.writeFileSync(path.join(fakeBin, "openshell"), "#!/usr/bin/env bash\nexit 0\n", { + mode: 0o755, + }); + const previousPath = process.env.PATH; + process.env.PATH = `${fakeBin}:${previousPath || ""}`; + try { + const command = getDashboardForwardStartCommand("the-crucible", { + env: { WSL_DISTRO_NAME: "Ubuntu" }, + platform: "linux", + release: "6.6.87.2-microsoft-standard-WSL2", + }); + + expect(command).toContain("forward"); + expect(command).toContain("start"); + expect(command).toContain("--background"); + expect(command).toContain("0.0.0.0:18789"); + expect(command).toContain("the-crucible"); + } finally { + process.env.PATH = previousPath; + fs.rmSync(tmpDir, { recursive: true, force: true }); + } });#!/bin/bash # Verify whether getDashboardForwardStartCommand still depends on openshell resolution rg -n -C3 "function getDashboardForwardStartCommand|getDashboardForwardStartCommand\\(|openshellShellCommand|getOpenshellBinary|process\\.exit\\(1\\)" src/lib/onboard.ts # Re-check current test body around the WSL forward bind case sed -n '398,416p' test/onboard.test.tsAs per coding guidelines, "Mock external dependencies in unit tests; do not call real NVIDIA APIs."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/onboard.test.ts` around lines 401 - 413, The test calls getDashboardForwardStartCommand and still relies on the openshell binary resolution which can trigger process.exit(1); update the test to stub/mock the openshell resolution used by getDashboardForwardStartCommand (e.g., mock getOpenshellBinary or openshellShellCommand) to return a valid path/string so the function does not attempt to resolve the real binary or call process.exit(1), then re-run the assertions; ensure the mock is scoped to the WSL test case and restored after the test.
🤖 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 4176-4184: The code currently computes portToStop from chatUiUrl
but the forward/start logic always targets CONTROL_UI_PORT (18789), so stale
forwards remain when chatUiUrl specifies a different port; update the forwarding
start/stop logic to use the parsed portToStop (derived from chatUiUrl) as the
forward target instead of hardcoding CONTROL_UI_PORT, while keeping
CONTROL_UI_PORT as the fallback when chatUiUrl has no port, and ensure both the
forward creation and the stop/cleanup call reference the same portToStop
variable (check usages around portToStop, CONTROL_UI_PORT, and any forward/start
or stop functions that manage the dashboard tunnel).
---
Duplicate comments:
In `@test/onboard.test.ts`:
- Around line 401-413: The test calls getDashboardForwardStartCommand and still
relies on the openshell binary resolution which can trigger process.exit(1);
update the test to stub/mock the openshell resolution used by
getDashboardForwardStartCommand (e.g., mock getOpenshellBinary or
openshellShellCommand) to return a valid path/string so the function does not
attempt to resolve the real binary or call process.exit(1), then re-run the
assertions; ensure the mock is scoped to the WSL test case and restored after
the test.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 46c4e1ad-a68e-4849-b664-5823fde437fb
📒 Files selected for processing (2)
src/lib/onboard.tstest/onboard.test.ts
ericksoa
left a comment
There was a problem hiding this comment.
The checks CI job is failing because the new getDashboardForwardStartCommand test calls openshellShellCommand → getOpenshellBinary(), which hits process.exit(1) when openshell isn't installed in CI (src/lib/onboard.ts:454).
The first test (getDashboardAccessInfo) passes because it only builds URLs. The second test needs the openshell binary path resolved, which isn't available in the CI environment.
Please fix the test so it doesn't require an actual openshell installation — e.g., accept an openshellBinary override in the options, or mock the binary resolution.
|
Fixed in the latest commit (c002986). getDashboardForwardStartCommand now accepts an openshellBinary override in its options object, which is threaded through from openshellShellCommand. The WSL bind test uses this to inject a static path (/usr/bin/openshell) instead of triggering binary resolution — so the test no longer calls process.exit(1) when OpenShell isn't installed in CI. All 99 onboard tests pass on the updated branch. |
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/lib/onboard.ts (1)
4173-4186:⚠️ Potential issue | 🟠 MajorStill hardcoding
18789in the forward commands.The agent UI path here already builds URLs against an arbitrary
port, butensureDashboardForward()andgetDashboardForwardStartCommand()still startCONTROL_UI_PORTunconditionally and only parsechatUiUrlfor the stop call. Any non-default dashboard port will stop one tunnel and start another.🔧 Suggested direction
-function getDashboardForwardPort() { - return CONTROL_UI_PORT; +function getDashboardForwardPort(chatUiUrl = `http://127.0.0.1:${CONTROL_UI_PORT}`) { + try { + return String( + new URL(/^[a-z]+:\/\//i.test(chatUiUrl) ? chatUiUrl : `http://${chatUiUrl}`).port || + CONTROL_UI_PORT, + ); + } catch { + return String(CONTROL_UI_PORT); + } +} + +function getDashboardForwardTarget( + chatUiUrl = `http://127.0.0.1:${CONTROL_UI_PORT}`, + options = {}, +) { + const port = getDashboardForwardPort(chatUiUrl); + const bindAll = isWsl(options) || resolveDashboardForwardTarget(chatUiUrl).includes(":"); + return bindAll ? `0.0.0.0:${port}` : port; }function ensureDashboardForward(sandboxName, chatUiUrl = `http://127.0.0.1:${CONTROL_UI_PORT}`) { - const forwardTarget = isWsl() - ? `0.0.0.0:${CONTROL_UI_PORT}` - : resolveDashboardForwardTarget(chatUiUrl); - let portToStop = String(CONTROL_UI_PORT); - try { - portToStop = String( - new URL(/^[a-z]+:\/\//i.test(chatUiUrl) ? chatUiUrl : `http://${chatUiUrl}`).port || - CONTROL_UI_PORT, - ); - } catch { - // Fall back to the default dashboard port when chatUiUrl is not URL-shaped. - } + const portToStop = getDashboardForwardPort(chatUiUrl); + const forwardTarget = getDashboardForwardTarget(chatUiUrl); runOpenshell(["forward", "stop", portToStop], { ignoreError: true }); runOpenshell(["forward", "start", "--background", forwardTarget, sandboxName], { ignoreError: true, stdio: ["ignore", "ignore", "ignore"], }); } function getDashboardForwardStartCommand(sandboxName, options = {}) { - const forwardTarget = isWsl(options) - ? `0.0.0.0:${CONTROL_UI_PORT}` - : resolveDashboardForwardTarget(`http://127.0.0.1:${CONTROL_UI_PORT}`); + const chatUiUrl = options.chatUiUrl ?? `http://127.0.0.1:${CONTROL_UI_PORT}`; + const forwardTarget = getDashboardForwardTarget(chatUiUrl, options); return `${openshellShellCommand( ["forward", "start", "--background", forwardTarget, sandboxName], options, )}`; }Also applies to: 4242-4254, 4344-4352
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/onboard.ts` around lines 4173 - 4186, ensureDashboardForward (and related helpers like getDashboardForwardStartCommand) still use the hardcoded CONTROL_UI_PORT for starting the forward while only parsing chatUiUrl for the stop command; parse the effective port from chatUiUrl (fallback to CONTROL_UI_PORT if parse fails) up front, use that parsed port variable for both the forward stop and forward start commands and when building forwardTarget (respecting isWsl by binding to 0.0.0.0:<parsedPort> if needed), and replace any direct uses of CONTROL_UI_PORT in runOpenshell(["forward", ...]) and in resolveDashboardForwardTarget/chatUiUrl handling with the parsed port variable so start/stop always target the same port.
🧹 Nitpick comments (2)
src/lib/onboard.ts (2)
4901-4905: Consider exportinggetWslHostAddress()with the rest of this helper set.Every other new dashboard utility is exported here, so this one is the odd one out. If direct reuse or unit testing is part of the intent, add it to
module.exports; otherwise I’d make the private scope more explicit.♻️ Small follow-up
getDashboardForwardStartCommand, getDashboardGuidanceLines, + getWslHostAddress, startGatewayForRecovery,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/onboard.ts` around lines 4901 - 4905, The helper getWslHostAddress is not exported alongside the other dashboard utilities (buildAuthenticatedDashboardUrl, getDashboardAccessInfo, getDashboardForwardPort, getDashboardForwardStartCommand, getDashboardGuidanceLines); either add getWslHostAddress to the same module.exports/export list so it can be reused and unit-tested, or explicitly mark it private by moving it out of the public export block and documenting its local-only intent; update the export list where the other functions are exported to include the getWslHostAddress symbol if you choose to make it public.
460-462: Sync the typedopenshellShellCommandcallback signature with its implementation.The function now accepts an optional
optionsparameter (src/lib/onboard.ts:460), butOnboardContext.openshellShellCommandinsrc/lib/agent-onboard.ts:21still declares only a single argument. The runtime works because the second parameter is optional, but the type signature should reflect the actual helper API for type-checked reuse.Suggested refactor
// src/lib/agent-onboard.ts - openshellShellCommand: (args: string[]) => string; + openshellShellCommand: ( + args: string[], + opts?: { openshellBinary?: string } + ) => string;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/onboard.ts` around lines 460 - 462, The declared callback type OnboardContext.openshellShellCommand must include the optional options parameter to match the implementation of openshellShellCommand; update the type/signature for OnboardContext.openshellShellCommand to accept (args: string[], options?: { openshellBinary?: string } | Record<string, any>) => string (or a matching options type used elsewhere), and update any related type alias or interface so callers are type-checked against the two-argument form; ensure the implementation name openshellShellCommand remains unchanged and that all call sites still pass one or two arguments as before.
🤖 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 4173-4186: ensureDashboardForward (and related helpers like
getDashboardForwardStartCommand) still use the hardcoded CONTROL_UI_PORT for
starting the forward while only parsing chatUiUrl for the stop command; parse
the effective port from chatUiUrl (fallback to CONTROL_UI_PORT if parse fails)
up front, use that parsed port variable for both the forward stop and forward
start commands and when building forwardTarget (respecting isWsl by binding to
0.0.0.0:<parsedPort> if needed), and replace any direct uses of CONTROL_UI_PORT
in runOpenshell(["forward", ...]) and in resolveDashboardForwardTarget/chatUiUrl
handling with the parsed port variable so start/stop always target the same
port.
---
Nitpick comments:
In `@src/lib/onboard.ts`:
- Around line 4901-4905: The helper getWslHostAddress is not exported alongside
the other dashboard utilities (buildAuthenticatedDashboardUrl,
getDashboardAccessInfo, getDashboardForwardPort,
getDashboardForwardStartCommand, getDashboardGuidanceLines); either add
getWslHostAddress to the same module.exports/export list so it can be reused and
unit-tested, or explicitly mark it private by moving it out of the public export
block and documenting its local-only intent; update the export list where the
other functions are exported to include the getWslHostAddress symbol if you
choose to make it public.
- Around line 460-462: The declared callback type
OnboardContext.openshellShellCommand must include the optional options parameter
to match the implementation of openshellShellCommand; update the type/signature
for OnboardContext.openshellShellCommand to accept (args: string[], options?: {
openshellBinary?: string } | Record<string, any>) => string (or a matching
options type used elsewhere), and update any related type alias or interface so
callers are type-checked against the two-argument form; ensure the
implementation name openshellShellCommand remains unchanged and that all call
sites still pass one or two arguments as before.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 33c22961-a0be-4f3d-9583-5fc5e09b0fb0
📒 Files selected for processing (2)
src/lib/onboard.tstest/onboard.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- test/onboard.test.ts
Superseded: the test now injects openshellBinary, the branch is rebased onto main, dashboard port overrides are honored under WSL, and the full PR workflow is green.
ericksoa
left a comment
There was a problem hiding this comment.
Reviewed: WSL detection is cleanly dependency-injected, 0.0.0.0 bind correctly gated behind isWsl(), custom port preservation is solid. No regression risk to non-WSL paths.
…#1503) <!-- markdownlint-disable MD041 --> ## Summary The dashboard port-forward command binds to `127.0.0.1`, making it unreachable from Windows browsers when NemoClaw runs inside WSL2. This PR detects WSL and binds to `0.0.0.0` instead, and adds a VS Code/WSL-friendly URL using the WSL host IP from `hostname -I`. ## Related Issue None. ## Changes - Add `getDashboardForwardStartCommand()` helper that detects WSL via `isWsl()` and binds to `0.0.0.0:18789` instead of the default loopback address. - Add `getDashboardAccessInfo()` helper that appends a `VS Code/WSL` dashboard URL entry when running under WSL. - Add `buildAuthenticatedDashboardUrl()`, `getWslHostAddress()`, `getDashboardForwardPort()`, and `getDashboardGuidanceLines()` helpers. - Add two unit tests covering WSL bind address and WSL dashboard URL generation. ## Type of Change - [x] Code change for a new feature, bug fix, or refactor. - [ ] Code change with doc updates. - [ ] Doc only. Prose changes without code sample modifications. - [ ] Doc only. Includes code sample changes. ## Testing - [x] `npx prek run --all-files` passes (or equivalently `make check`). - [x] `npm test` passes. - [ ] `make docs` builds without warnings. (for doc-only changes) 52/52 onboard tests pass. Full suite: 960 passed with 6 pre-existing failures that also occur on upstream `main` (cli.test.js, install-preflight.test.js, nemoclaw-cli-recovery.test.js). ## Checklist ### General - [x] I have read and followed the [contributing guide](https://github.com/NVIDIA/NemoClaw/blob/main/CONTRIBUTING.md). ### Code Changes - [x] Formatters applied — `npx prek run --all-files` auto-fixes formatting (or `make format` for targeted runs). - [x] Tests added or updated for new or changed behavior. - [x] No secrets, API keys, or credentials committed. - [ ] Doc pages updated for any user-facing behavior changes (new commands, changed defaults, new features, bug fixes that contradict existing docs). --- Signed-off-by: Darren Kattan <darren@kattan.dev> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved dashboard forwarding with WSL support (binds to all interfaces when appropriate). * New dashboard utilities to standardize access URLs, authenticated links, and WSL host probing. * Console guidance now produces labeled dashboard entries (Dashboard, Alt n, VS Code/WSL) and clearer messaging. * **Bug Fixes** * More robust dashboard port resolution with sensible defaults. * **Tests** * Added tests for WSL dashboard URLs and forwarding command variations. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Darren McLeod <tempuskg@gmail.com> Co-authored-by: Carlos Villela <cvillela@nvidia.com> Co-authored-by: Aaron Erickson 🦞 <aerickson@nvidia.com>
…#1503) <!-- markdownlint-disable MD041 --> ## Summary The dashboard port-forward command binds to `127.0.0.1`, making it unreachable from Windows browsers when NemoClaw runs inside WSL2. This PR detects WSL and binds to `0.0.0.0` instead, and adds a VS Code/WSL-friendly URL using the WSL host IP from `hostname -I`. ## Related Issue None. ## Changes - Add `getDashboardForwardStartCommand()` helper that detects WSL via `isWsl()` and binds to `0.0.0.0:18789` instead of the default loopback address. - Add `getDashboardAccessInfo()` helper that appends a `VS Code/WSL` dashboard URL entry when running under WSL. - Add `buildAuthenticatedDashboardUrl()`, `getWslHostAddress()`, `getDashboardForwardPort()`, and `getDashboardGuidanceLines()` helpers. - Add two unit tests covering WSL bind address and WSL dashboard URL generation. ## Type of Change - [x] Code change for a new feature, bug fix, or refactor. - [ ] Code change with doc updates. - [ ] Doc only. Prose changes without code sample modifications. - [ ] Doc only. Includes code sample changes. ## Testing - [x] `npx prek run --all-files` passes (or equivalently `make check`). - [x] `npm test` passes. - [ ] `make docs` builds without warnings. (for doc-only changes) 52/52 onboard tests pass. Full suite: 960 passed with 6 pre-existing failures that also occur on upstream `main` (cli.test.js, install-preflight.test.js, nemoclaw-cli-recovery.test.js). ## Checklist ### General - [x] I have read and followed the [contributing guide](https://github.com/NVIDIA/NemoClaw/blob/main/CONTRIBUTING.md). ### Code Changes - [x] Formatters applied — `npx prek run --all-files` auto-fixes formatting (or `make format` for targeted runs). - [x] Tests added or updated for new or changed behavior. - [x] No secrets, API keys, or credentials committed. - [ ] Doc pages updated for any user-facing behavior changes (new commands, changed defaults, new features, bug fixes that contradict existing docs). --- Signed-off-by: Darren Kattan <darren@kattan.dev> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved dashboard forwarding with WSL support (binds to all interfaces when appropriate). * New dashboard utilities to standardize access URLs, authenticated links, and WSL host probing. * Console guidance now produces labeled dashboard entries (Dashboard, Alt n, VS Code/WSL) and clearer messaging. * **Bug Fixes** * More robust dashboard port resolution with sensible defaults. * **Tests** * Added tests for WSL dashboard URLs and forwarding command variations. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Darren McLeod <tempuskg@gmail.com> Co-authored-by: Carlos Villela <cvillela@nvidia.com> Co-authored-by: Aaron Erickson 🦞 <aerickson@nvidia.com> Signed-off-by: ColinM-sys <cmcdonough@50words.com>
Summary
The dashboard port-forward command binds to
127.0.0.1, making it unreachable from Windows browsers when NemoClaw runs inside WSL2. This PR detects WSL and binds to0.0.0.0instead, and adds a VS Code/WSL-friendly URL using the WSL host IP fromhostname -I.Related Issue
None.
Changes
getDashboardForwardStartCommand()helper that detects WSL viaisWsl()and binds to0.0.0.0:18789instead of the default loopback address.getDashboardAccessInfo()helper that appends aVS Code/WSLdashboard URL entry when running under WSL.buildAuthenticatedDashboardUrl(),getWslHostAddress(),getDashboardForwardPort(), andgetDashboardGuidanceLines()helpers.Type of Change
Testing
npx prek run --all-filespasses (or equivalentlymake check).npm testpasses.make docsbuilds without warnings. (for doc-only changes)52/52 onboard tests pass. Full suite: 960 passed with 6 pre-existing failures that also occur on upstream
main(cli.test.js, install-preflight.test.js, nemoclaw-cli-recovery.test.js).Checklist
General
Code Changes
npx prek run --all-filesauto-fixes formatting (ormake formatfor targeted runs).Signed-off-by: Darren Kattan darren@kattan.dev
Summary by CodeRabbit
New Features
Bug Fixes
Tests