Skip to content

fix(cli): bind dashboard forward to all interfaces under WSL2#1503

Merged
ericksoa merged 9 commits intoNVIDIA:mainfrom
Tempuskg:fix/wsl-dashboard-bind
Apr 14, 2026
Merged

fix(cli): bind dashboard forward to all interfaces under WSL2#1503
ericksoa merged 9 commits intoNVIDIA:mainfrom
Tempuskg:fix/wsl-dashboard-bind

Conversation

@Tempuskg
Copy link
Copy Markdown
Contributor

@Tempuskg Tempuskg commented Apr 5, 2026

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

  • 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

  • npx prek run --all-files passes (or equivalently make check).
  • 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

Code Changes

  • Formatters applied — npx prek run --all-files auto-fixes formatting (or make format for targeted runs).
  • Tests added or updated for new or changed behavior.
  • 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

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.

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>
Copilot AI review requested due to automatic review settings April 5, 2026 16:34
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 5, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds 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

Cohort / File(s) Summary
Dashboard Utilities & Onboard Logic
src/lib/onboard.ts
Introduces WSL-aware branching in ensureDashboardForward() (use 0.0.0.0:${CONTROL_UI_PORT} on WSL); default forward-stop port to CONTROL_UI_PORT unless chatUiUrl is URL-shaped; adds and exports getDashboardForwardPort(), getDashboardForwardStartCommand(), buildAuthenticatedDashboardUrl(), getWslHostAddress(), getDashboardAccessInfo(), getDashboardGuidanceLines(); updates printDashboard() to use these helpers and de-duplicate/tokenize WSL URLs.
Tests
test/onboard.test.ts
Imports new helpers and adds WSL-specific tests: validate getDashboardAccessInfo() returns loopback + probed WSL host URL (both tokenized), and getDashboardForwardStartCommand() uses 0.0.0.0:<port> target; relaxes sandbox creation assertion to accept loopback or WSL forward variants.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I sniffed the WSL breeze tonight,
Found an IP and made it right,
Two URLs to hop between,
Tokens tucked and ports made seen,
Dashboard ready — hop delight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: binding the dashboard forward to all interfaces (0.0.0.0) specifically for WSL2 environments to enable Windows browser access.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Comment thread test/onboard.test.js Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between c99e3e8 and cf963b5.

📒 Files selected for processing (2)
  • bin/lib/onboard.js
  • test/onboard.test.js

Comment thread src/lib/onboard.ts
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>
@wscurran wscurran added Platform: Windows/WSL Support for Windows Subsystem for Linux NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). fix labels Apr 6, 2026
@wscurran
Copy link
Copy Markdown
Contributor

wscurran commented Apr 6, 2026

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

Copy link
Copy Markdown
Contributor

@cv cv left a comment

Choose a reason for hiding this comment

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

LGTM — security review PASS.

  • 0.0.0.0 bind correctly gated behind isWsl() (4-signal detection)
  • Non-WSL systems unaffected — stay on loopback
  • WSL2 network exposure is an accepted trade-off, mitigated by token auth
  • hostname -I output is display-only (console URL for user)
  • Good test coverage with injected options for deterministic WSL simulation

No concerns.

@cv cv added v0.0.11 Release target v0.0.12 Release target and removed v0.0.11 Release target labels Apr 9, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5b56a42 and 8c31d2a.

📒 Files selected for processing (2)
  • src/lib/onboard.ts
  • test/onboard.test.ts

Comment thread test/onboard.test.ts
@cv cv added v0.0.13 Release target and removed v0.0.12 Release target labels Apr 10, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
test/onboard.test.ts (1)

401-413: ⚠️ Potential issue | 🔴 Critical

Make 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 with process.exit(1) on hosts where openshell is 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.ts

As 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8c31d2a and 6743ecf.

📒 Files selected for processing (2)
  • src/lib/onboard.ts
  • test/onboard.test.ts

Comment thread src/lib/onboard.ts Outdated
Copy link
Copy Markdown
Contributor

@ericksoa ericksoa left a comment

Choose a reason for hiding this comment

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

The checks CI job is failing because the new getDashboardForwardStartCommand test calls openshellShellCommandgetOpenshellBinary(), 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.

@Tempuskg
Copy link
Copy Markdown
Contributor Author

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
src/lib/onboard.ts (1)

4173-4186: ⚠️ Potential issue | 🟠 Major

Still hardcoding 18789 in the forward commands.

The agent UI path here already builds URLs against an arbitrary port, but ensureDashboardForward() and getDashboardForwardStartCommand() still start CONTROL_UI_PORT unconditionally and only parse chatUiUrl for 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 exporting getWslHostAddress() 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 typed openshellShellCommand callback signature with its implementation.

The function now accepts an optional options parameter (src/lib/onboard.ts:460), but OnboardContext.openshellShellCommand in src/lib/agent-onboard.ts:21 still 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

📥 Commits

Reviewing files that changed from the base of the PR and between 6743ecf and c002986.

📒 Files selected for processing (2)
  • src/lib/onboard.ts
  • test/onboard.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/onboard.test.ts

@cv cv added v0.0.15 Release target and removed v0.0.13 Release target labels Apr 13, 2026
@cv cv dismissed ericksoa’s stale review April 14, 2026 00:25

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 ericksoa added v0.0.16 Release target and removed v0.0.15 Release target labels Apr 14, 2026
Copy link
Copy Markdown
Contributor

@ericksoa ericksoa left a comment

Choose a reason for hiding this comment

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

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.

@ericksoa ericksoa merged commit e1c734d into NVIDIA:main Apr 14, 2026
8 checks passed
@ericksoa ericksoa added v0.0.15 Release target and removed v0.0.16 Release target labels Apr 14, 2026
ericksoa added a commit to cheese-head/NemoClaw that referenced this pull request Apr 14, 2026
…#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>
ColinM-sys pushed a commit to ColinM-sys/NemoClaw that referenced this pull request Apr 14, 2026
…#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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). Platform: Windows/WSL Support for Windows Subsystem for Linux v0.0.15 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants