Skip to content

feat(cli): add embeddable node lifecycle#1269

Open
khaliqgant wants to merge 12 commits into
mainfrom
feature/embedded-node-lifecycle
Open

feat(cli): add embeddable node lifecycle#1269
khaliqgant wants to merge 12 commits into
mainfrom
feature/embedded-node-lifecycle

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Jul 15, 2026

Copy link
Copy Markdown
Member

Summary

  • publish agent-relay/node-embedded with structured startEmbeddedNode, downEmbeddedNode, and statusEmbeddedNode results
  • reuse the existing runUpCommand / runDownCommand / runStatusCommand lifecycle implementation through CoreDependencies injection
  • replace process exit with BrokerLifecycleExitError, capture lifecycle signal handlers behind an idempotent handle, isolate the host environment, and route CLI/provider output without global console or inherited Python-provider stdio ownership
  • bump the published CLI, config, and harness-driver packages to 10.3.0 and document the API

Lifecycle ownership

Embedded startup supports foreground mode only. Any truthy background value returns a structured code-2 failure. The value forwarded to runUpCommand is authoritatively set to false after spreading caller options, so stateful JavaScript getters/proxies cannot reach the detached-spawn path. The host forwards its own signals through handle.stop(); Relay does not install SIGINT/SIGTERM listeners on the host.

Exit-site audit

All 14 deps.exit sites were traced on the final lifecycle implementation: 11 in runUpCommand, 0 in runDownCommand, and 3 in runStatusCommand.

  • Background-only runUpCommand exits at current lines 1129, 1133, 1148, 1195, and 1201 are structurally unreachable because embedded startup always forwards a plain background: false. Static truthy values and false-then-true accessors were independently probed with zero detached spawns.
  • Foreground exits at lines 1235 and 1314, plus their shared outer catch at 1366, receive the injected BrokerLifecycleExitError; host-process survival was independently exercised through both nested chains.
  • The second-SIGINT exit at line 1336 is unreachable through the public idempotent handle/no-global-listener API, but its captured handler closes over the same injected exit. First-SIGINT and SIGTERM exits at lines 1342 and 1349 are invoked only through the returned handle and convert to structured success.
  • runStatusCommand exits at lines 1520, 1531, and 1563 all receive the injected dependencies and return structured failures; stopped-after-wait, live-PID/API-unavailable, and invalid-wait paths were exercised.

A static regression test pins the 11 + 0 + 3 count and bans raw process.exit, SIGINT/SIGTERM process.on, direct console.*, and inherited stdio from the embedded lifecycle implementation.

Verification

  • npm run typecheck
  • npm --prefix packages/cli run lint (passes with pre-existing warnings only)
  • full Vitest suite: 98 files passed, 1 skipped; 1234 tests passed, 11 skipped
  • independent adversarial review: host survival, signal/console/listener isolation, static and stateful background bypasses, env isolation, stderr classification, shutdown failures/state retention, and nested-CWD marker discovery
  • npm --prefix packages/cli run build
  • installed-workspace subpath import smoke for agent-relay/node-embedded
  • CLI/config package dry-runs at 10.3.0; CLI tarball contains the new JS and declarations
  • npm ci --dry-run --ignore-scripts

The CodeQL regex annotation is pre-existing at blame commit 83a19438ab and outside this PR's changed hunks.

No publish or deploy performed.

Review in cubic

@khaliqgant
khaliqgant requested a review from willwashburn as a code owner July 15, 2026 13:05
@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a process-safe embedded Node.js broker lifecycle API with structured startup, shutdown, status, output capture, dependency injection, package exports, documentation, and tests.

Changes

Embedded Node lifecycle

Layer / File(s) Summary
Lifecycle contracts and runtime seams
packages/cli/src/cli/commands/core.ts, packages/cli/src/cli/lib/broker-lifecycle.ts
Exports lifecycle option types and adds injectable environment, logging, output, and Python-provider stdio controls.
Embedded lifecycle execution
packages/cli/src/cli/lib/node-embedded.ts
Implements foreground startup, readiness handling, structured results, output recording, idempotent shutdown, and embedded down/status commands.
Lifecycle validation and process-safety coverage
packages/cli/src/node-embedded.test.ts
Tests existing-broker failures, shutdown behavior, output forwarding, unsupported background mode, status validation, and process-exit boundaries.
Public module and package distribution
packages/cli/src/node-embedded.ts, packages/cli/package.json, packages/cli/README.md, packages/cli/tsconfig.json, CHANGELOG.md
Adds the public entry point, package export and version, compiler inclusion formatting, usage documentation, and changelog entry.

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

Sequence Diagram(s)

sequenceDiagram
  participant Host
  participant startEmbeddedNode
  participant runUpCommand
  participant CoreRelay
  Host->>startEmbeddedNode: startEmbeddedNode(options, runtime)
  startEmbeddedNode->>runUpCommand: run up with embedded dependencies
  runUpCommand->>CoreRelay: create relay and start broker
  CoreRelay-->>startEmbeddedNode: readiness and lifecycle output
  startEmbeddedNode-->>Host: return handle and completion
  Host->>startEmbeddedNode: handle.stop('SIGTERM')
  startEmbeddedNode->>runUpCommand: invoke registered shutdown handler
  runUpCommand-->>Host: return structured completion
Loading

Possibly related PRs

Suggested labels: size:XL

Suggested reviewers: willwashburn

Poem

I’m a rabbit in a broker burrow,
Starting nodes without farewell.
Signals hop through careful paws,
Logs stream softly, errors tell.
Stop twice? No fright, I’ve planned—
One neat handle, safely spanned.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The summary is strong, but the required Test Plan section is missing and Screenshots is not addressed. Add a Test Plan section with tested commands/results and include Screenshots only if applicable to the change.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title clearly matches the main change: adding an embeddable node lifecycle API for the CLI.
✨ 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 feature/embedded-node-lifecycle

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81c6267166

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

releaseHold: Deferred<void>,
dependencyOverrides: Partial<CoreDependencies>
): CoreDependencies {
const env = { ...(runtime.env ?? dependencyOverrides.env ?? process.env) };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Isolate embedded broker env from the host

When an embedder supplies runtime.env to isolate the broker, this clone is later passed through createDefaultRelay/createRuntimeClient into buildBrokerSpawnConfig, which still merges process.env as the parent environment before applying the supplied env. In embedded hosts with host-only RELAY_*, AGENT_RELAY_*, or secret variables, those values still leak into the spawned broker and can select the wrong workspace/state or expose host credentials despite the API contract saying the broker only sees the provided env.

Useful? React with 👍 / 👎.

onStderr: (line) => recorder.emit('error', [`[broker] ${line}`]),
}));

return withDefaults({

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Resolve the MCP helper from the package

Embedded callers inherit withDefaults()'s cliScript value, which is derived from process.argv[1] (the host application's entrypoint), not from the installed agent-relay package. In a normal embedded app that means ensureBundledAgentRelayMcpCommand() looks next to the host script, fails to find dist/cli/agent-relay-mcp.js, and the broker falls back to npx -y agent-relay mcp for spawned agents, causing offline/version-mismatched embeds instead of using the bundled MCP server.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

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

Inline comments:
In `@packages/cli/src/cli/lib/node-embedded.ts`:
- Around line 110-113: Bound the output recorder in the emit function used by
the embedded node so it retains only a fixed maximum number of recent entries.
After adding each new entry to output, remove the oldest entries when the cap is
exceeded, preserving the final command snapshot while preventing unbounded
growth during long-lived runs.
- Around line 121-133: Update resultFrom so the error === undefined path always
returns a successful result without inspecting historical snapshot entries. For
actual failures, replace the error-only lookup with findLast to select the most
recent entry whose level is error or warn, preserving the existing fallback
message and returned output.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 339370b3-994f-4c19-973e-deced49943fb

📥 Commits

Reviewing files that changed from the base of the PR and between e93e5c7 and 3056e5f.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • packages/cli/README.md
  • packages/cli/package.json
  • packages/cli/src/cli/commands/core.ts
  • packages/cli/src/cli/lib/broker-lifecycle.ts
  • packages/cli/src/cli/lib/node-embedded.ts
  • packages/cli/src/node-embedded.test.ts
  • packages/cli/src/node-embedded.ts
  • packages/cli/tsconfig.json

Comment thread packages/cli/src/cli/lib/node-embedded.ts
Comment thread packages/cli/src/cli/lib/node-embedded.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/cli/src/cli/lib/node-embedded.ts
Comment thread packages/cli/src/cli/lib/node-embedded.ts
Comment thread packages/cli/src/cli/lib/node-embedded.ts
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
putComment timed out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant