refactor(cli): migrate runtime-recovery.js to TypeScript#1268
Conversation
…ript modules Move ~210 lines of pure, side-effect-free functions from the 3,800-line onboard.js into five typed TypeScript modules under src/lib/: - gateway-state.ts: gateway/sandbox state classification - validation.ts: failure classification, API key validation, model ID checks - url-utils.ts: URL normalization, text compaction, env formatting - build-context.ts: Docker build context filtering, recovery hints - dashboard.ts: dashboard URL resolution and construction Infrastructure: - tsconfig.src.json compiles src/ → dist/ as CJS (dist/ already gitignored) - tsconfig.cli.json updated to type-check src/ - npm run build:cli added to package.json - Pre-commit test-cli hook builds TS and includes dist/lib/ in coverage onboard.js imports from compiled dist/lib/ output. All 542 CLI tests pass. No user-facing behavior changes. Closes #1237. Relates to #924 (shell consolidation). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
56 new tests across three co-located test files: - src/lib/validation.test.ts: classifyValidationFailure, classifyApplyFailure, classifySandboxCreateFailure, validateNvidiaApiKeyValue, isSafeModelId - src/lib/dashboard.test.ts: resolveDashboardForwardTarget, buildControlUiUrls - src/lib/url-utils.test.ts: compactText, stripEndpointSuffix, normalizeProviderBaseUrl, isLoopbackHostname, formatEnvAssignment, parsePolicyPresetEnv vitest.config.ts updated to include src/**/*.test.ts in the CLI project. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The existing callsite in printDashboard calls buildControlUiUrls() with no arguments when no token is available. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The tsc-js pre-push hook (jsconfig.json) type-checks bin/lib/onboard.js which requires dist/lib/ to exist. CI was not running npm run build:cli before the prek checks, causing TS2307 "Cannot find module" errors. - Add npm run build:cli step to .github/actions/basic-checks - Update tsc-js hook to run build:cli before tsc Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…law into cv/extract-onboard-pure-fns
## Summary - Convert `bin/lib/preflight.js` (357 lines) to `src/lib/preflight.ts` with full type definitions - Typed interfaces for all opts objects and return types: `PortProbeResult`, `MemoryInfo`, `SwapResult`, `CheckPortOpts`, `GetMemoryInfoOpts`, `EnsureSwapOpts` - Extract `parseLsofLines` helper to reduce duplication in `checkPortAvailable` - Incorporate #1227 fix: `sudo` → `sudo -n` (non-interactive) for lsof retry - `bin/lib/preflight.js` becomes a thin re-export shim — existing consumers unaffected - Co-locate tests: `test/preflight.test.js` → `src/lib/preflight.test.ts` - Add real net probe tests (EADDRINUSE detection on occupied ports) - Fix all co-located test imports to use `dist/` paths for coverage attribution - Add targeted dashboard/validation branch tests to maintain ratchet Stacked on #1240. Not touched by any #924 blocker PR. ## Test plan - [x] 612 CLI tests pass (601 existing + 11 new) - [x] `tsc -p tsconfig.src.json` compiles cleanly - [x] `tsc -p tsconfig.cli.json` type-checks cleanly - [x] `tsc -p jsconfig.json` type-checks cleanly (the pre-push check that caught the union issue) - [x] Coverage ratchet passes Relates to #924 (shell consolidation). Supersedes #1227. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Convert bin/lib/runtime-recovery.js (84 lines) to src/lib/runtime-recovery.ts with typed StateClassification interface. 5 pure classifiers/parsers + 1 I/O function (getRecoveryCommand). Co-locates tests with additional edge case coverage. 617 CLI tests pass. Coverage ratchet passes. Relates to #924 (shell consolidation). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe PR moves runtime-recovery logic into a new TypeScript module ( Changes
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 docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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/runtime-recovery.js`:
- Line 7: The bin shims (e.g., bin/lib/runtime-recovery.js,
bin/lib/preflight.js, bin/lib/onboard.js) currently require compiled modules
from dist/lib/ which are missing on fresh checkouts; fix by converting these
shims back to true CommonJS sources that directly export the runtime logic
instead of proxying to dist—restore or reimplement the CommonJS exports for
runtime-recovery, preflight and onboard (and the dependent modules
gateway-state, validation, url-utils, build-context, dashboard) inside bin/lib
so module.exports contains the implementation (or requires the original source
CommonJS files) and no longer points at ../../dist; alternatively, if you prefer
keeping compiled artifacts, update package.json to include dist/ in "files" and
add the build:cli step to the prepare hook so dist gets produced on
install—choose the CommonJS conversion (preferred) and ensure the exported
identifiers and require paths used by bin/* match the original API.
In `@src/lib/runtime-recovery.test.ts`:
- Around line 6-12: The test imports runtime helpers (classifyGatewayStatus,
classifySandboxLookup, parseLiveSandboxNames, shouldAttemptGatewayRecovery) from
the compiled dist which can be missing locally; either update the test imports
to point at the TypeScript source module (change the import path to the src/lib
runtime-recovery module) so tests run against source, or add a pretest npm hook
to package.json (e.g. "pretest": "npm run build:cli") to ensure
dist/lib/runtime-recovery is built before running tests.
In `@src/lib/runtime-recovery.ts`:
- Around line 64-66: The condition in the runtime-recovery check uses
/Connected/i which also matches "Disconnected"; update the check to only match
the standalone word "Connected" (or at start of string) so "Disconnected" won't
match: change the regex in the if that tests the variable clean (currently if
(/Connected/i.test(clean)) ...) to something like /\bConnected\b/i or
/^Connected\b/i so only an exact/whole-word "Connected" (or beginning-with
"Connected") returns { state: "connected", reason: "ok" } in the
runtime-recovery logic.
🪄 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: ae93df98-dcae-4ca9-a429-e62650c60fa4
📒 Files selected for processing (3)
bin/lib/runtime-recovery.jssrc/lib/runtime-recovery.test.tssrc/lib/runtime-recovery.ts
| parseLiveSandboxNames, | ||
| shouldAttemptGatewayRecovery, | ||
| }; | ||
| module.exports = require("../../dist/lib/runtime-recovery"); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Check whether dist target exists without building =="
if [ -f dist/lib/runtime-recovery.js ]; then
echo "FOUND: dist/lib/runtime-recovery.js"
else
echo "MISSING: dist/lib/runtime-recovery.js"
fi
echo
echo "== Find references to runtime-recovery from bin/scripts =="
rg -n -C2 --type=js '\bruntime-recovery\b' bin scripts || true
echo
echo "== Inspect package scripts for enforced build-before-cli/test =="
rg -n '"(build|build:cli|test|test:cli|pretest|prepare|prepack|postinstall)"\s*:' package.json || trueRepository: NVIDIA/NemoClaw
Length of output: 1447
🏁 Script executed:
#!/bin/bash
# Get full package.json to see all scripts
cat -n package.json | head -50
echo "=== Check for build:all or other build targets ==="
rg -n '"(build|build:all|compile|prebuild|postinstall)"\s*:' package.json
echo "=== Check if dist/ is version controlled or generated ==="
git ls-files dist/ 2>/dev/null | head -20 || echo "dist/ not in git or git command failed"
echo "=== Check git ignore for dist/ ==="
cat .gitignore | grep -E 'dist|build' || echo "No dist/build in .gitignore"
echo "=== Check tsconfig files ==="
fd -t f 'tsconfig.*\.json$' -x basename {}Repository: NVIDIA/NemoClaw
Length of output: 2384
🏁 Script executed:
#!/bin/bash
# Check the actual source file to understand the pattern
echo "=== Check src/lib/runtime-recovery.ts ==="
if [ -f src/lib/runtime-recovery.ts ]; then
head -20 src/lib/runtime-recovery.ts
else
echo "File not found, searching for it:"
fd 'runtime-recovery' --type f
fi
echo
echo "=== Check other shims in bin/lib for pattern ==="
ls -la bin/lib/ | grep -E '\.js$' || true
echo
echo "=== Check content of other shim files ==="
for shim in bin/lib/*.js; do
if [ -f "$shim" ]; then
echo "--- $shim ---"
head -10 "$shim"
fi
doneRepository: NVIDIA/NemoClaw
Length of output: 7681
🏁 Script executed:
#!/bin/bash
# Verify tsconfig.src.json outputs to dist/
echo "=== tsconfig.src.json ==="
cat tsconfig.src.json
echo
echo "=== All files in bin/lib that require dist ==="
rg -n 'require.*dist' bin/lib/
echo
echo "=== Check if dist/ gets created during dev setup ==="
ls -la dist/ 2>/dev/null | head -5 || echo "dist/ directory does not exist"Repository: NVIDIA/NemoClaw
Length of output: 1245
Multiple critical dependencies on missing dist/ directory — CLI and test flows broken in fresh checkout.
The shim in line 7 (bin/lib/runtime-recovery.js) and related shims (bin/lib/preflight.js, bin/lib/onboard.js) require compiled modules from dist/lib/ that do not exist without an explicit build step. Additionally:
dist/lib/is excluded from package.json"files"field (only"nemoclaw/dist/"is included), sonpm installwill not provide these files- The
preparehook does not invokebuild:cli, leaving no automatic build step testand CLI execution will fail withMODULE_NOT_FOUNDon fresh checkout or afternpm install
Affected imports:
bin/lib/runtime-recovery.js:7→dist/lib/runtime-recoverybin/lib/preflight.js:7→dist/lib/preflightbin/lib/onboard.js:59-63→dist/lib/gateway-state,validation,url-utils,build-context,dashboard
Either add dist/ to the "files" field and build:cli to prepare, or convert these modules back to CommonJS sources in bin/lib/ (preferred per guidelines: "bin/lib/**/*.js modules are expected to remain CommonJS").
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@bin/lib/runtime-recovery.js` at line 7, The bin shims (e.g.,
bin/lib/runtime-recovery.js, bin/lib/preflight.js, bin/lib/onboard.js) currently
require compiled modules from dist/lib/ which are missing on fresh checkouts;
fix by converting these shims back to true CommonJS sources that directly export
the runtime logic instead of proxying to dist—restore or reimplement the
CommonJS exports for runtime-recovery, preflight and onboard (and the dependent
modules gateway-state, validation, url-utils, build-context, dashboard) inside
bin/lib so module.exports contains the implementation (or requires the original
source CommonJS files) and no longer points at ../../dist; alternatively, if you
prefer keeping compiled artifacts, update package.json to include dist/ in
"files" and add the build:cli step to the prepare hook so dist gets produced on
install—choose the CommonJS conversion (preferred) and ensure the exported
identifiers and require paths used by bin/* match the original API.
| // Import from compiled dist/ for correct coverage attribution. | ||
| import { | ||
| classifyGatewayStatus, | ||
| classifySandboxLookup, | ||
| parseLiveSandboxNames, | ||
| shouldAttemptGatewayRecovery, | ||
| } from "../bin/lib/runtime-recovery"; | ||
| } from "../../dist/lib/runtime-recovery"; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Check test-related scripts for guaranteed build-before-test =="
rg -n '"(build|build:cli|test|test:cli|pretest|prepare)"\s*:' package.json || true
echo
echo "== Check CI workflows for build step before vitest/test commands =="
fd -HI -t f -i 'yml' .github/workflows -x rg -n -C2 '(vitest|npm run test|pnpm test|yarn test|build:cli|npm run build|pnpm build|yarn build)' {}Repository: NVIDIA/NemoClaw
Length of output: 608
🏁 Script executed:
cat -n package.jsonRepository: NVIDIA/NemoClaw
Length of output: 2418
🏁 Script executed:
find .github/workflows -type f -name "*.yml" -o -name "*.yaml" 2>/dev/null | head -20Repository: NVIDIA/NemoClaw
Length of output: 481
🏁 Script executed:
cat -n src/lib/runtime-recovery.test.ts | head -40Repository: NVIDIA/NemoClaw
Length of output: 1694
🏁 Script executed:
cat -n .github/workflows/pr.yaml | head -80Repository: NVIDIA/NemoClaw
Length of output: 963
🏁 Script executed:
cat -n .github/workflows/main.yaml | head -80Repository: NVIDIA/NemoClaw
Length of output: 1097
🏁 Script executed:
find . -maxdepth 1 -name "vitest.config.*" -o -name "vite.config.*" 2>/dev/null | xargs cat -n 2>/dev/null || echo "No vitest/vite config found"Repository: NVIDIA/NemoClaw
Length of output: 1326
🏁 Script executed:
ls -la dist/lib/runtime-recovery.* 2>/dev/null || echo "dist/lib/runtime-recovery files not found"Repository: NVIDIA/NemoClaw
Length of output: 100
🏁 Script executed:
cat -n .github/actions/basic-checks/action.yamlRepository: NVIDIA/NemoClaw
Length of output: 1733
🏁 Script executed:
find . -name "runtime-recovery.ts" -not -path "*/node_modules/*" 2>/dev/nullRepository: NVIDIA/NemoClaw
Length of output: 88
🏁 Script executed:
cat -n src/lib/runtime-recovery.ts | head -50Repository: NVIDIA/NemoClaw
Length of output: 1996
Either import directly from source TypeScript or add a pretest build hook.
The test script in package.json does not include a build step, so running npm test locally without first running npm run build:cli will fail since dist/lib/runtime-recovery.ts is not built. While the CI workflows (pr.yaml, main.yaml) enforce builds before testing via the basic-checks action, local development can run tests against non-existent or stale dist files. Either add a pretest hook ("pretest": "npm run build:cli") to guarantee build ordering, or import directly from the TypeScript source (src/lib/runtime-recovery.ts) for unit tests.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/lib/runtime-recovery.test.ts` around lines 6 - 12, The test imports
runtime helpers (classifyGatewayStatus, classifySandboxLookup,
parseLiveSandboxNames, shouldAttemptGatewayRecovery) from the compiled dist
which can be missing locally; either update the test imports to point at the
TypeScript source module (change the import path to the src/lib runtime-recovery
module) so tests run against source, or add a pretest npm hook to package.json
(e.g. "pretest": "npm run build:cli") to ensure dist/lib/runtime-recovery is
built before running tests.
The regex /Connected/i matched "Disconnected" as a substring, causing disconnected gateways to be classified as connected and blocking recovery. Use word boundary \bConnected\b with explicit Disconnected exclusion. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/lib/runtime-recovery.ts (1)
64-73:⚠️ Potential issue | 🟠 MajorLine 64 can still misclassify
Not connectedasconnected.The current
\bConnected\bcheck matches negative phrases likeStatus: Not connected. Also, checking unavailable states first is safer when output contains mixed lines.Proposed fix
export function classifyGatewayStatus(output = ""): StateClassification { const clean = stripAnsi(output).trim(); if (!clean) { return { state: "inactive", reason: "empty" }; } - if (/\bConnected\b/i.test(clean) && !/\bDisconnected\b/i.test(clean)) { - return { state: "connected", reason: "ok" }; - } if ( /No active gateway|transport error|client error|Connection reset by peer|Connection refused|Gateway: .*Error/i.test( clean, ) ) { return { state: "unavailable", reason: "gateway_unavailable" }; } + if (/^\s*(?:Status:\s*)?Connected\s*$/im.test(clean)) { + return { state: "connected", reason: "ok" }; + } return { state: "inactive", reason: "not_connected" }; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/runtime-recovery.ts` around lines 64 - 73, Swap the checks so the unavailable regex block runs before the connected check and tighten the connected detection to avoid matching negative phrases: in the function that tests the string variable `clean` (the two regex branches shown), first test the unavailable pattern as-is, then for the connected case require that `clean` matches Connected but does NOT match /\bNot\s+connected\b/i (or use a negative lookbehind /(?<!\bNot\s)\bConnected\b/i if supported), then return { state: "connected", reason: "ok" } only when that stricter check passes.
🧹 Nitpick comments (2)
src/lib/runtime-recovery.test.ts (1)
70-77: Add a regression assertion forStatus: Not connected.Given the connected-status parsing sensitivity, add an explicit expectation for
"Status: Not connected"to remaininactive.Proposed test addition
it("classifies gateway status output for restart recovery", () => { expect(classifyGatewayStatus("Gateway: nemoclaw\nStatus: Connected").state).toBe("connected"); expect(classifyGatewayStatus("Error: × No active gateway").state).toBe("unavailable"); expect(classifyGatewayStatus("").state).toBe("inactive"); + expect(classifyGatewayStatus("Gateway: nemoclaw\nStatus: Not connected").state).toBe( + "inactive", + ); expect(classifyGatewayStatus("Gateway: nemoclaw\nStatus: Disconnected").state).toBe( "inactive", ); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/runtime-recovery.test.ts` around lines 70 - 77, Add a regression assertion in the test that ensures classifyGatewayStatus treats "Status: Not connected" as inactive: update the "classifies gateway status output for restart recovery" test to include an expect call invoking classifyGatewayStatus("Gateway: nemoclaw\nStatus: Not connected").state and assert it toBe("inactive"); this references the classifyGatewayStatus function in src/lib/runtime-recovery.test.ts used elsewhere in the test block.src/lib/runtime-recovery.ts (1)
20-23: TightenStateClassificationwith literal unions.Using
stringforstate/reasonweakens compile-time guarantees and allows silent typos in classifier returns.Proposed refactor
+export type RecoveryState = "missing" | "present" | "unavailable" | "inactive" | "connected"; +export type RecoveryReason = + | "empty" + | "not_found" + | "gateway_unavailable" + | "ok" + | "not_connected"; + export interface StateClassification { - state: string; - reason: string; + state: RecoveryState; + reason: RecoveryReason; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/runtime-recovery.ts` around lines 20 - 23, The StateClassification interface currently uses broad string types for state and reason which allows silent typos; change StateClassification so state and reason are literal union types (e.g., define a StateClassificationState = 'healthy' | 'degraded' | 'failed' | ... and a StateClassificationReason = 'timeout' | 'validation_error' | 'resource_exhausted' | ... and use those unions on the state and reason fields) and update any functions that construct or return StateClassification to return one of the defined union members (locate usages by the symbol StateClassification and any classifier functions that produce a StateClassification) so the compiler will enforce valid values.
🤖 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/runtime-recovery.ts`:
- Around line 64-73: Swap the checks so the unavailable regex block runs before
the connected check and tighten the connected detection to avoid matching
negative phrases: in the function that tests the string variable `clean` (the
two regex branches shown), first test the unavailable pattern as-is, then for
the connected case require that `clean` matches Connected but does NOT match
/\bNot\s+connected\b/i (or use a negative lookbehind
/(?<!\bNot\s)\bConnected\b/i if supported), then return { state: "connected",
reason: "ok" } only when that stricter check passes.
---
Nitpick comments:
In `@src/lib/runtime-recovery.test.ts`:
- Around line 70-77: Add a regression assertion in the test that ensures
classifyGatewayStatus treats "Status: Not connected" as inactive: update the
"classifies gateway status output for restart recovery" test to include an
expect call invoking classifyGatewayStatus("Gateway: nemoclaw\nStatus: Not
connected").state and assert it toBe("inactive"); this references the
classifyGatewayStatus function in src/lib/runtime-recovery.test.ts used
elsewhere in the test block.
In `@src/lib/runtime-recovery.ts`:
- Around line 20-23: The StateClassification interface currently uses broad
string types for state and reason which allows silent typos; change
StateClassification so state and reason are literal union types (e.g., define a
StateClassificationState = 'healthy' | 'degraded' | 'failed' | ... and a
StateClassificationReason = 'timeout' | 'validation_error' |
'resource_exhausted' | ... and use those unions on the state and reason fields)
and update any functions that construct or return StateClassification to return
one of the defined union members (locate usages by the symbol
StateClassification and any classifier functions that produce a
StateClassification) so the compiler will enforce valid values.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d231d260-9ee7-46ff-a91b-1f72eac58e9b
📒 Files selected for processing (2)
src/lib/runtime-recovery.test.tssrc/lib/runtime-recovery.ts
…d" (#1288) ## Summary The `classifyGatewayStatus` regex matched "Not connected" as connected because `\bConnected\b` matches the substring. This was partially fixed in #1268 (added Disconnected guard) but "Not connected" still slipped through. Fix: - Move unavailable-pattern check before connected check - Use strict line-anchored regex: `/^\s*(?:Status:\s*)?Connected\s*$/im` - Add regression tests for "Status: Not connected" → inactive This fix was intended for #1268 but the auto-merge squashed before the commit landed. Fixes #1279. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved gateway connection status detection to handle edge cases and properly classify various status formats, ensuring more accurate connection state reporting. * **Tests** * Added test coverage for additional gateway status variations. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary - Convert `bin/lib/runtime-recovery.js` (84 lines) to `src/lib/runtime-recovery.ts` - Typed `StateClassification` interface for sandbox/gateway state - 5 pure classifiers/parsers + 1 I/O function (`getRecoveryCommand`) - Co-locate tests with additional edge cases Stacked on #1240. 617 CLI tests pass. Coverage ratchet passes. Relates to #924 (shell consolidation). 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved runtime recovery logic to better parse CLI output and determine recovery actions, including more reliable sandbox/gateway state classification and recovery command selection. * **Bug Fixes** * Correctly treats "Disconnected" gateway status as inactive and handles error/empty lines when listing sandboxes. * **Tests** * Expanded test coverage for edge cases, malformed input, and empty states. * **Refactor** * Runtime recovery helpers consolidated to a shared compiled module. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d" (#1288) ## Summary The `classifyGatewayStatus` regex matched "Not connected" as connected because `\bConnected\b` matches the substring. This was partially fixed in #1268 (added Disconnected guard) but "Not connected" still slipped through. Fix: - Move unavailable-pattern check before connected check - Use strict line-anchored regex: `/^\s*(?:Status:\s*)?Connected\s*$/im` - Add regression tests for "Status: Not connected" → inactive This fix was intended for #1268 but the auto-merge squashed before the commit landed. Fixes #1279. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved gateway connection status detection to handle edge cases and properly classify various status formats, ensuring more accurate connection state reporting. * **Tests** * Added test coverage for additional gateway status variations. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary - Convert `bin/lib/runtime-recovery.js` (84 lines) to `src/lib/runtime-recovery.ts` - Typed `StateClassification` interface for sandbox/gateway state - 5 pure classifiers/parsers + 1 I/O function (`getRecoveryCommand`) - Co-locate tests with additional edge cases Stacked on NVIDIA#1240. 617 CLI tests pass. Coverage ratchet passes. Relates to NVIDIA#924 (shell consolidation). 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved runtime recovery logic to better parse CLI output and determine recovery actions, including more reliable sandbox/gateway state classification and recovery command selection. * **Bug Fixes** * Correctly treats "Disconnected" gateway status as inactive and handles error/empty lines when listing sandboxes. * **Tests** * Expanded test coverage for edge cases, malformed input, and empty states. * **Refactor** * Runtime recovery helpers consolidated to a shared compiled module. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d" (NVIDIA#1288) ## Summary The `classifyGatewayStatus` regex matched "Not connected" as connected because `\bConnected\b` matches the substring. This was partially fixed in NVIDIA#1268 (added Disconnected guard) but "Not connected" still slipped through. Fix: - Move unavailable-pattern check before connected check - Use strict line-anchored regex: `/^\s*(?:Status:\s*)?Connected\s*$/im` - Add regression tests for "Status: Not connected" → inactive This fix was intended for NVIDIA#1268 but the auto-merge squashed before the commit landed. Fixes NVIDIA#1279. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved gateway connection status detection to handle edge cases and properly classify various status formats, ensuring more accurate connection state reporting. * **Tests** * Added test coverage for additional gateway status variations. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
bin/lib/runtime-recovery.js(84 lines) tosrc/lib/runtime-recovery.tsStateClassificationinterface for sandbox/gateway stategetRecoveryCommand)Stacked on #1240. 617 CLI tests pass. Coverage ratchet passes.
Relates to #924 (shell consolidation).
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Refactor