Skip to content

feat(cli): support Cloudflare named tunnels#4134

Merged
cv merged 7 commits into
mainfrom
feat/cloudflare-named-tunnels
May 24, 2026
Merged

feat(cli): support Cloudflare named tunnels#4134
cv merged 7 commits into
mainfrom
feat/cloudflare-named-tunnels

Conversation

@cv
Copy link
Copy Markdown
Collaborator

@cv cv commented May 23, 2026

Summary

Adds Cloudflare named tunnel support to nemoclaw tunnel start using CLOUDFLARE_TUNNEL_TOKEN.
Named tunnel tokens are passed to cloudflared through TUNNEL_TOKEN instead of argv, and status/banner URL detection now handles named tunnel hostnames as well as quick tunnel URLs.

Changes

  • src/lib/tunnel/services.ts starts cloudflared tunnel run when CLOUDFLARE_TUNNEL_TOKEN is set, otherwise preserving quick-tunnel behavior.
  • src/lib/tunnel/services.ts adds getTunnelUrl() parsing for named tunnel config= log entries and quick tunnel URLs.
  • src/lib/tunnel/services.test.ts adds coverage for named tunnel URL parsing and verifies the token is not placed in cloudflared argv.
  • docs/reference/commands.mdx and docs/manage-sandboxes/messaging-channels.mdx document named tunnel usage for nemoclaw tunnel start.

Type of Change

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

Verification

Targeted checks run locally: npm run build:cli, npm run typecheck:cli, and npx vitest run src/lib/tunnel/services.test.ts passed.
Full npx prek run --all-files and npm test are left for CI because local hooks/tests are currently hanging on this machine.

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

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

Summary by CodeRabbit

  • New Features
    • Support starting Cloudflare named tunnels via a configurable token (alternative to quick-tunnel URLs).
  • Documentation
    • Expanded tunnel command docs with step‑by‑step guidance on named tunnels, token usage, URL behavior, and hostname routing.
  • Tests
    • Added tests for public URL detection and to verify the token is supplied securely to tunnel tooling.
  • Refactor
    • Introduced and reused a shared JSON-record type and runtime guard across multiple modules.

Review Change Stack

@cv cv added documentation Improvements or additions to documentation NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). labels May 23, 2026
@cv cv self-assigned this May 23, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 23, 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 optional ServiceOptions.cloudflareTunnelToken, implements getTunnelUrl to prefer named-tunnel HTTPS hostnames from cloudflared ingress JSON (fallback to trycloudflare), updates startAll/showStatus to use it and to pass the token via TUNNEL_TOKEN, centralizes isRecord/UnknownRecord, updates tests and docs.

Changes

Cloudflare Named Tunnel Support

Layer / File(s) Summary
ServiceOptions interface and public URL extraction
src/lib/tunnel/services.ts
Adds optional cloudflareTunnelToken. Implements named-tunnel URL extraction by parsing cloudflared ingress config entries matching the dashboard port, normalizing to HTTPS, with a regex fallback to trycloudflare extraction.
Tunnel startup and status integration
src/lib/tunnel/services.ts
startAll reads cloudflareTunnelToken / CLOUDFLARE_TUNNEL_TOKEN and launches cloudflared tunnel run with TUNNEL_TOKEN when present; otherwise falls back to tunnel --url http://localhost:<dashboardPort>. The wait loop and final URL use getTunnelUrl. showStatus uses getTunnelUrl.
getTunnelUrl and token-based startup test suite
src/lib/tunnel/services.test.ts
Adds getTunnelUrl tests (missing log, quick-tunnel fragment stripping, named-tunnel extraction). Updates startAll tests to snapshot/restore CLOUDFLARE_TUNNEL_TOKEN and adds a test ensuring the token is provided via TUNNEL_TOKEN env (not argv) while returning the expected named hostname URL.
User-facing documentation
docs/manage-sandboxes/messaging-channels.mdx, docs/reference/commands.mdx
Adds note to set CLOUDFLARE_TUNNEL_TOKEN before nemoclaw tunnel start for named tunnels and expands nemoclaw tunnel start docs to explain quick-tunnel behavior, named-tunnel token usage, required dashboard hostname routing, and that the token is passed via TUNNEL_TOKEN (not shown in argv).
Shared JSON record types and adopters
src/lib/core/json-types.ts, src/lib/shields/timer.ts, src/lib/skill-install.ts, src/lib/state/sandbox.ts
Exports UnknownRecord and isRecord; consumer modules import and use the shared type guard, removing local duplicates.

Sequence Diagram

sequenceDiagram
  participant startAll
  participant cloudflared
  participant cloudflared_log as cloudflared.log
  participant getTunnelUrl

  startAll->>cloudflared: spawn (tunnel run with TUNNEL_TOKEN) or (tunnel --url ...)
  cloudflared->>cloudflared_log: write ingress/config JSON or quick-tunnel lines
  getTunnelUrl->>cloudflared_log: read & parse ingress JSON or trycloudflare URL
  getTunnelUrl-->>startAll: return named HTTPS URL or trycloudflare URL
Loading

Estimated code review effort:
🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers:

  • ericksoa

"A rabbit hops across the log and shell,
Tokens tucked safe, no argv to tell,
Ingress maps whisper hostnames true,
Quick tunnels or named — the view is new,
I cheer for tunnels, hopping 🐇🌐"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main feature addition: support for Cloudflare named tunnels in the CLI, which is the primary change across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cloudflare-named-tunnels

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 23, 2026

PR Review Advisor

Findings: 2 needs attention, 2 worth checking, 0 nice ideas
Since last review: 0 prior items resolved, 4 still apply, 0 new items found

Review findings

🛠️ Needs attention

  • Tunnel service monolith grew instead of being split (src/lib/tunnel/services.ts:192): The PR still adds named-tunnel URL parsing, hostname validation, service matching, token selection, and start-mode branching directly into the already-large tunnel lifecycle module. This is a security-sensitive public tunnel lifecycle path, and the trusted monolith delta still reports growth above the repository threshold.
    • Recommendation: Move Cloudflare named-tunnel URL parsing and/or start argument construction into a focused helper module, with services.ts delegating to that helper. Alternatively offset the growth with an equivalent extraction from this file before merging.
    • Evidence: Previous advisor finding still applies. Trusted monolith delta: src/lib/tunnel/services.ts baseLines=626, headLines=706, delta=80, severity=blocker. The diff adds formatNamedTunnelUrl, serviceTargetsDashboard, getConfigIngressEntries, extractNamedCloudflareUrl, exported getTunnelUrl, and startAll branching on CLOUDFLARE_TUNNEL_TOKEN in services.ts.
  • Tunnel service test monolith grew with new cases (src/lib/tunnel/services.test.ts:27): The PR still adds named-tunnel parsing and argv/token tests directly to the existing service test file. The trusted monolith delta reports continued growth above the repository threshold, making the service tests more of a catch-all for unrelated tunnel lifecycle behavior.
    • Recommendation: Split the new named-tunnel parsing/start tests into a dedicated test file or extract shared fake-cloudflared setup helpers so this test file does not continue growing as a catch-all.
    • Evidence: Previous advisor finding still applies. Trusted monolith delta: src/lib/tunnel/services.test.ts baseLines=350, headLines=417, delta=67, severity=blocker. New getTunnelUrl tests are added near the top of the file and the named tunnel startAll test is added later in the same file.

🔎 Worth checking

  • New public env var is not listed in the environment-variable reference (docs/reference/commands.mdx:1245): The tunnel command section documents CLOUDFLARE_TUNNEL_TOKEN, but the reference page's environment-variable table still does not include this new user-facing variable. Users who discover configuration through the env-var index will miss the named-tunnel option.
    • Recommendation: Add a row for CLOUDFLARE_TUNNEL_TOKEN to the environment-variable reference table, describing that it selects Cloudflare named-tunnel mode for nemoclaw tunnel start and is forwarded to cloudflared as TUNNEL_TOKEN.
    • Evidence: Previous advisor finding still applies. The diff adds command guidance for `export CLOUDFLARE_TUNNEL_TOKEN=<cloudflare-tunnel-token>` before `nemoclaw tunnel start`, while the previous review reports the environment-variable table beginning near line 1245 lists NEMOCLAW_* variables but no CLOUDFLARE_TUNNEL_TOKEN row.
  • Security-sensitive named cloudflared behavior still lacks runtime validation (src/lib/tunnel/services.test.ts:243): The unit coverage uses a fake cloudflared shell script and validates the important argv/env contract, but the changed behavior depends on real cloudflared named-tunnel process behavior and log shape. Because this is a public tunnel path carrying a credential via environment, runtime validation is still warranted beyond synthetic logs.
    • Recommendation: Add or identify targeted runtime/integration validation for the named-tunnel path, especially that real cloudflared tunnel run emits a parseable dashboard route and does not expose the token in command-line arguments or logs. Also consider negative parser tests for malformed named-tunnel config, invalid hostnames, non-dashboard ingress services, and 127.0.0.1/localhost variants.
    • Evidence: Previous advisor finding still applies. Trusted testDepth verdict is runtime_validation_recommended for src/lib/tunnel/services.ts. The current named-tunnel startAll test creates a fake cloudflared script, checks `argv:tunnel run` and `token-env-present`, and emits a synthetic `config=` log line.

🌱 Nice ideas

  • None.
Since last review details

Current findings:

  • Tunnel service monolith grew instead of being split (src/lib/tunnel/services.ts:192): The PR still adds named-tunnel URL parsing, hostname validation, service matching, token selection, and start-mode branching directly into the already-large tunnel lifecycle module. This is a security-sensitive public tunnel lifecycle path, and the trusted monolith delta still reports growth above the repository threshold.
    • Recommendation: Move Cloudflare named-tunnel URL parsing and/or start argument construction into a focused helper module, with services.ts delegating to that helper. Alternatively offset the growth with an equivalent extraction from this file before merging.
    • Evidence: Previous advisor finding still applies. Trusted monolith delta: src/lib/tunnel/services.ts baseLines=626, headLines=706, delta=80, severity=blocker. The diff adds formatNamedTunnelUrl, serviceTargetsDashboard, getConfigIngressEntries, extractNamedCloudflareUrl, exported getTunnelUrl, and startAll branching on CLOUDFLARE_TUNNEL_TOKEN in services.ts.
  • Tunnel service test monolith grew with new cases (src/lib/tunnel/services.test.ts:27): The PR still adds named-tunnel parsing and argv/token tests directly to the existing service test file. The trusted monolith delta reports continued growth above the repository threshold, making the service tests more of a catch-all for unrelated tunnel lifecycle behavior.
    • Recommendation: Split the new named-tunnel parsing/start tests into a dedicated test file or extract shared fake-cloudflared setup helpers so this test file does not continue growing as a catch-all.
    • Evidence: Previous advisor finding still applies. Trusted monolith delta: src/lib/tunnel/services.test.ts baseLines=350, headLines=417, delta=67, severity=blocker. New getTunnelUrl tests are added near the top of the file and the named tunnel startAll test is added later in the same file.
  • New public env var is not listed in the environment-variable reference (docs/reference/commands.mdx:1245): The tunnel command section documents CLOUDFLARE_TUNNEL_TOKEN, but the reference page's environment-variable table still does not include this new user-facing variable. Users who discover configuration through the env-var index will miss the named-tunnel option.
    • Recommendation: Add a row for CLOUDFLARE_TUNNEL_TOKEN to the environment-variable reference table, describing that it selects Cloudflare named-tunnel mode for nemoclaw tunnel start and is forwarded to cloudflared as TUNNEL_TOKEN.
    • Evidence: Previous advisor finding still applies. The diff adds command guidance for `export CLOUDFLARE_TUNNEL_TOKEN=<cloudflare-tunnel-token>` before `nemoclaw tunnel start`, while the previous review reports the environment-variable table beginning near line 1245 lists NEMOCLAW_* variables but no CLOUDFLARE_TUNNEL_TOKEN row.
  • Security-sensitive named cloudflared behavior still lacks runtime validation (src/lib/tunnel/services.test.ts:243): The unit coverage uses a fake cloudflared shell script and validates the important argv/env contract, but the changed behavior depends on real cloudflared named-tunnel process behavior and log shape. Because this is a public tunnel path carrying a credential via environment, runtime validation is still warranted beyond synthetic logs.
    • Recommendation: Add or identify targeted runtime/integration validation for the named-tunnel path, especially that real cloudflared tunnel run emits a parseable dashboard route and does not expose the token in command-line arguments or logs. Also consider negative parser tests for malformed named-tunnel config, invalid hostnames, non-dashboard ingress services, and 127.0.0.1/localhost variants.
    • Evidence: Previous advisor finding still applies. Trusted testDepth verdict is runtime_validation_recommended for src/lib/tunnel/services.ts. The current named-tunnel startAll test creates a fake cloudflared script, checks `argv:tunnel run` and `token-env-present`, and emits a synthetic `config=` log line.

Workflow run details

This is an automated advisory review. A human maintainer must make the final merge decision.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 23, 2026

E2E Advisor Recommendation

Required E2E: tunnel-lifecycle-e2e
Optional E2E: state-backup-restore-e2e, shields-config-e2e, skill-agent-e2e

Dispatch hint: tunnel-lifecycle-e2e

Auto-dispatched E2E: tunnel-lifecycle-e2e via nightly-e2e.yaml at 0fb3aced637c4ef652434287ed78a9e7b149daacnightly run

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • tunnel-lifecycle-e2e (high; provisions a sandbox and installs/runs cloudflared): Required because the PR changes runtime behavior for nemoclaw tunnel start, cloudflared process launch, public URL detection, nemoclaw status, and tunnel stop cleanup. This existing E2E validates the real tunnel start/probe/status/stop flow.

Optional E2E

  • state-backup-restore-e2e (high; sandbox backup/restore lifecycle): Useful confidence for the shared isRecord refactor in sandbox manifest validation, but the changed code is type/helper consolidation rather than intended behavior change.
  • shields-config-e2e (medium; sandbox plus shields/config lifecycle): Useful confidence because shields timer state parsing now depends on the shared record helper; not merge-blocking because the logic is unchanged.
  • skill-agent-e2e (medium; installs and verifies a skill in a sandbox): Useful confidence for the SKILL.md frontmatter validation refactor in skill-install.ts; not merge-blocking because behavior appears unchanged and unit coverage was updated elsewhere.

New E2E recommendations

  • deployment / named Cloudflare tunnel (high): Existing tunnel-lifecycle-e2e validates quick tunnels and greps *.trycloudflare.com; it does not appear to exercise CLOUDFLARE_TUNNEL_TOKEN, cloudflared tunnel run, token-not-in-argv behavior, or named-hostname status output.
    • Suggested test: Add a named-tunnel E2E path, either as a new named-tunnel-lifecycle-e2e job or an extension to test/e2e/test-tunnel-lifecycle.sh, using a controlled fake cloudflared or a CI-provisioned named tunnel secret to assert token is passed via env, not argv, and nemoclaw status reports the configured named hostname.

Dispatch hint

  • Workflow: nightly-e2e.yaml
  • jobs input: tunnel-lifecycle-e2e

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 23, 2026

E2E Scenario Advisor Recommendation

Required scenario E2E: None
Optional scenario E2E: None

Workflow run

Full scenario advisor summary

E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required scenario E2E

  • None. No scenario workflow, scenario metadata, scenario runtime, or validation-suite files changed.

Optional scenario E2E

  • None.

Relevant changed files

  • None.

@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26340733625
Target ref: ea4bf87514a763a9c86097e289e3180798c847e7
Workflow ref: main
Requested jobs: tunnel-lifecycle-e2e
Summary: 0 passed, 0 failed, 0 skipped

Job Result
tunnel-lifecycle-e2e ⚠️ cancelled

@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26340856367
Target ref: 0f6306db373c02c2adcb3e94ad25fd9026475de0
Workflow ref: main
Requested jobs: tunnel-lifecycle-e2e,state-backup-restore-e2e,skill-agent-e2e,shields-config-e2e
Summary: 0 passed, 0 failed, 0 skipped

Job Result
shields-config-e2e ⚠️ cancelled
skill-agent-e2e ⚠️ cancelled
state-backup-restore-e2e ⚠️ cancelled
tunnel-lifecycle-e2e ⚠️ cancelled

@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ❌ Some jobs failed

Run: 26340961619
Target ref: 02b1f6c63ad0c95ebd52e8bc5d7f3027a00c7f1a
Workflow ref: main
Requested jobs: tunnel-lifecycle-e2e,shields-config-e2e,state-backup-restore-e2e,skill-agent-e2e
Summary: 3 passed, 1 failed, 0 skipped

Job Result
shields-config-e2e ✅ success
skill-agent-e2e ❌ failure
state-backup-restore-e2e ✅ success
tunnel-lifecycle-e2e ✅ success

Failed jobs: skill-agent-e2e. Check run artifacts for logs.

@cv cv enabled auto-merge (squash) May 23, 2026 20:14
@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26342326438
Target ref: f5197c0b0874c4eb53249772afcabeb809f5e24f
Workflow ref: main
Requested jobs: tunnel-lifecycle-e2e,state-backup-restore-e2e,shields-config-e2e,skill-agent-e2e
Summary: 4 passed, 0 failed, 0 skipped

Job Result
shields-config-e2e ✅ success
skill-agent-e2e ✅ success
state-backup-restore-e2e ✅ success
tunnel-lifecycle-e2e ✅ success

@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26344160470
Target ref: 4a9f4ca3303544877b191dcf1670f874ebb85855
Workflow ref: main
Requested jobs: tunnel-lifecycle-e2e,shields-config-e2e,state-backup-restore-e2e,skill-agent-e2e
Summary: 4 passed, 0 failed, 0 skipped

Job Result
shields-config-e2e ✅ success
skill-agent-e2e ✅ success
state-backup-restore-e2e ✅ success
tunnel-lifecycle-e2e ✅ success

@cv cv added the v0.0.51 Release target label May 23, 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/tunnel/services.ts (1)

137-152: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Prefer the newest tunnel URL from cloudflared.log.

Both parsers return the first match from the top of the log, but this file is append-only while cloudflared runs. After a reconnect or config reload, showStatus() and startAll() can keep surfacing the stale earlier URL instead of the current one.

Suggested fix
 function extractTryCloudflareUrl(log: string): string | null {
+  let latestUrl: string | null = null;
   for (const rawToken of log.split(/\s+/)) {
     const candidate = rawToken.replace(/^[<("']+|[>),."']+$/g, "");
     try {
       const url = new URL(candidate);
       if (url.protocol !== "https:") continue;
       if (url.hostname === "trycloudflare.com" || url.hostname.endsWith(".trycloudflare.com")) {
         url.hash = "";
-        return url.toString();
+        latestUrl = url.toString();
       }
     } catch {
       // Not a URL token.
     }
   }
-  return null;
+  return latestUrl;
 }
 
 function extractNamedCloudflareUrl(log: string, dashboardPort: number): string | null {
+  let latestUrl: string | null = null;
   for (const match of log.matchAll(/config="((?:\\"|[^"])*)"/g)) {
     const escapedConfig = match[1];
     if (!escapedConfig) continue;
     try {
       const configText = JSON.parse(`"${escapedConfig}"`) as string;
       const entries = getConfigIngressEntries(JSON.parse(configText) as unknown);
       for (const entry of entries) {
         if (!serviceTargetsDashboard(entry.service, dashboardPort)) continue;
         const url = formatNamedTunnelUrl(entry.hostname);
-        if (url) return url;
+        if (url) latestUrl = url;
       }
     } catch {
       // Fall through to the regex parser below for partial or unusual log lines.
     }
   }
 
   const port = String(dashboardPort).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
   const servicePattern = new RegExp(`\\\\"service\\\\"\\s*:\\s*\\\\"http://localhost:${port}/?\\\\"`, "g");
   for (const line of log.split(/\r?\n/)) {
     for (const serviceMatch of line.matchAll(servicePattern)) {
       const prefix = line.slice(0, serviceMatch.index ?? 0);
       let hostname: string | null = null;
       for (const hostnameMatch of prefix.matchAll(/\\"hostname\\"\s*:\s*\\"([^"\\]+)\\"/g)) {
         hostname = hostnameMatch[1] ?? null;
       }
       if (!hostname) continue;
       const url = formatNamedTunnelUrl(hostname);
-      if (url) return url;
+      if (url) latestUrl = url;
     }
   }
 
-  return null;
+  return latestUrl;
 }

Also applies to: 189-229

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

In `@src/lib/tunnel/services.ts` around lines 137 - 152, extractTryCloudflareUrl
currently returns the first (oldest) match because it scans the log forward;
change it to prefer the newest URL by scanning the log from the end (e.g., split
log into tokens or lines and iterate in reverse) and return the first https
trycloudflare.com match found; apply the same reverse-scan approach to the other
parser(s) in this file (the second tryCloudflare parser around the later block)
so showStatus()/startAll() surface the most recent tunnel URL instead of an
earlier one.
🧹 Nitpick comments (2)
src/lib/state/sandbox.ts (1)

33-33: Run the state lifecycle E2E suite before merge.

Because this file governs backup/restore/snapshot/rebuild persistence paths, run the recommended state E2Es on this branch.

As per coding guidelines "src/lib/state/sandbox.ts: This file manages sandbox state (backup, restore, rebuild, snapshot). Changes affect data persistence across sandbox lifecycle operations." and E2E recommendations "state-backup-restore-e2e, snapshot-commands-e2e, rebuild-openclaw-e2e".

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

In `@src/lib/state/sandbox.ts` at line 33, This change touches sandbox state
persistence in src/lib/state/sandbox.ts (imports like isRecord/UnknownRecord) so
run the full state lifecycle E2E suites: state-backup-restore-e2e,
snapshot-commands-e2e, and rebuild-openclaw-e2e; verify backup, restore,
snapshot and rebuild scenarios pass, capture any failing case, and fix issues in
the sandbox backup/restore/snapshot/rebuild handlers (the functions exported
from sandbox.ts that implement those flows) until all three E2E suites succeed
before merging.
src/lib/shields/timer.ts (1)

13-13: Run the shields lifecycle E2E job before merge.

Given this path controls shields timer behavior, run shields-config-e2e for regression confidence.

As per coding guidelines "src/lib/shields/**: These files control shields down/up, config mutability, audit trail, and auto-restore timer." and "E2E test recommendation: shields-config-e2e — shields lifecycle + config get/set/rotate".

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

In `@src/lib/shields/timer.ts` at line 13, This change affects shields timer
behavior in src/lib/shields/timer.ts (and related files under
src/lib/shields/**), so before merging run the shields-config-e2e job (shields
lifecycle + config get/set/rotate) to provide regression confidence; ensure the
shields-config-e2e pipeline completes green, attach the job run/results to the
PR, and do not merge until the E2E passes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/lib/tunnel/services.ts`:
- Around line 137-152: extractTryCloudflareUrl currently returns the first
(oldest) match because it scans the log forward; change it to prefer the newest
URL by scanning the log from the end (e.g., split log into tokens or lines and
iterate in reverse) and return the first https trycloudflare.com match found;
apply the same reverse-scan approach to the other parser(s) in this file (the
second tryCloudflare parser around the later block) so showStatus()/startAll()
surface the most recent tunnel URL instead of an earlier one.

---

Nitpick comments:
In `@src/lib/shields/timer.ts`:
- Line 13: This change affects shields timer behavior in
src/lib/shields/timer.ts (and related files under src/lib/shields/**), so before
merging run the shields-config-e2e job (shields lifecycle + config
get/set/rotate) to provide regression confidence; ensure the shields-config-e2e
pipeline completes green, attach the job run/results to the PR, and do not merge
until the E2E passes.

In `@src/lib/state/sandbox.ts`:
- Line 33: This change touches sandbox state persistence in
src/lib/state/sandbox.ts (imports like isRecord/UnknownRecord) so run the full
state lifecycle E2E suites: state-backup-restore-e2e, snapshot-commands-e2e, and
rebuild-openclaw-e2e; verify backup, restore, snapshot and rebuild scenarios
pass, capture any failing case, and fix issues in the sandbox
backup/restore/snapshot/rebuild handlers (the functions exported from sandbox.ts
that implement those flows) until all three E2E suites succeed before merging.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: bfa92dcb-41ae-4cd9-81c4-f01311e5f664

📥 Commits

Reviewing files that changed from the base of the PR and between 4a9f4ca and 0fb3ace.

📒 Files selected for processing (5)
  • src/lib/shields/timer.ts
  • src/lib/skill-install.ts
  • src/lib/state/sandbox.ts
  • src/lib/tunnel/services.test.ts
  • src/lib/tunnel/services.ts

@cv cv merged commit c864979 into main May 24, 2026
30 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

Selective E2E Results — ✅ All requested jobs passed

Run: 26374556015
Target ref: 0fb3aced637c4ef652434287ed78a9e7b149daac
Workflow ref: main
Requested jobs: tunnel-lifecycle-e2e
Summary: 1 passed, 0 failed, 0 skipped

Job Result
tunnel-lifecycle-e2e ✅ success

@miyoungc miyoungc mentioned this pull request May 26, 2026
12 tasks
miyoungc added a commit that referenced this pull request May 26, 2026
## Summary
Refresh NemoClaw documentation and generated user skills for the v0.0.50
and v0.0.51 release-prep window.
Remove obsolete legacy docs version metadata now that Fern docs no
longer use `docs/project.json`, `docs/versions1.json`, or the legacy
Sphinx config.

## Source summary
- #1757 -> `docs/manage-sandboxes/messaging-channels.mdx`,
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Document
Slack channel allowlisting with `SLACK_ALLOWED_CHANNELS`.
- #4134 -> `docs/manage-sandboxes/messaging-channels.mdx`,
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Document
Cloudflare named tunnel support through `CLOUDFLARE_TUNNEL_TOKEN`.
- #4186 and #4135 -> `docs/inference/use-local-inference.mdx`,
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Document
Ollama upgrade and user-local install behavior.
- #4185 -> `docs/network-policy/integration-policy-examples.mdx`,
`docs/about/release-notes.mdx`: Clarify Jira policy validation probes.
- Release cleanup ->
`.claude/skills/nemoclaw-contributor-update-docs/SKILL.md`,
`docs/CONTRIBUTING.md`, `.github/PULL_REQUEST_TEMPLATE.md`,
`scripts/bump-version.ts`: Stop using legacy docs version JSON files and
align docs verification on `npm run docs`.

## Changes
- Add v0.0.50 and v0.0.51 release notes.
- Regenerate NemoClaw user skills from the current Fern docs.
- Remove obsolete `docs/conf.py`, `docs/project.json`, and
`docs/versions1.json`.
- Update docs workflow guidance and PR templates to use `npm run docs`
instead of `make docs`.
- Remove release-version JSON handling from `scripts/bump-version.ts`.

## 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
- [ ] `npx prek run --all-files` passes
- [ ] `npm test` passes
- [ ] 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
- [ ] `npm run 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)

Additional verification:
- `python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix
nemoclaw-user --doc-platform fern-mdx`
- `npm run build:cli`
- `npx tsc --noEmit --allowSyntheticDefaultImports --module NodeNext
--moduleResolution NodeNext --target ES2022 --types node
scripts/bump-version.ts`
- `ReadLints` on touched docs, skills, template, and script files
- Searched for stale `versions1.json`, `project.json`, and `make docs`
references

Known gaps:
- `npm run docs` was not rerun after cleanup because the earlier Fern
CLI fetch failed with npm registry `403 Forbidden` in this environment.
- A broad `npm run typecheck -- --noEmit` hit an unrelated existing
`scripts/dev-tier-selector.js` type error.

---
Signed-off-by: Miyoung Cho <miyoungc@nvidia.com>

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

* **New Features**
* Added resource profiling with CPU/RAM configuration controls for
sandboxes
* Enhanced local Ollama inference with automatic GPU memory-aware model
fallback
* Added `nemoclaw resources` command to display host hardware inventory
* Enabled Cloudflare named tunnel support via environment configuration

* **Documentation**
* Improved setup guides for local inference, sandbox hardening, and
policy validation
* Enhanced troubleshooting for messaging delivery and host service
routing
  * Added release notes for v0.0.50 and v0.0.51

* **Chores**
* Updated build documentation commands from `make docs` to `npm run
docs`

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/NVIDIA/NemoClaw/pull/4262?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation NemoClaw CLI Use this label to identify issues with the NemoClaw command-line interface (CLI). v0.0.51 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants