Skip to content

Route CLI management through Core commands - #273

Merged
TraderSamwise merged 10 commits into
masterfrom
feat/core-cli-sidecar
Jul 3, 2026
Merged

Route CLI management through Core commands#273
TraderSamwise merged 10 commits into
masterfrom
feat/core-cli-sidecar

Conversation

@TraderSamwise

@TraderSamwise TraderSamwise commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • add Core command bus operations for project list/ensure/stop and relay status/enable/disable
  • route daemon/host/project/remote CLI management commands through Core commands
  • cover project actor ensure/stop and project command validation in tests

Verification

  • yarn typecheck
  • yarn lint
  • yarn build
  • yarn vitest run src/core-command-contract.test.ts src/daemon.test.ts
  • yarn test

Summary by CodeRabbit

  • New Features
    • Added core-driven project lifecycle commands (ensure/stop/kill), project listing, and relay control (status/enable/disable).
    • Enhanced CLI control-plane flows to rely on core for project/daemon/relay operations and richer status output.
  • Bug Fixes
    • Validates projectRoot for project ensure/stop requests, returning HTTP 400 with projectRoot is required when missing.
    • Improves forceful project kill/stop behavior by ensuring stale metadata endpoints are removed before state refresh.
    • Daemon status now includes relay info and updated daemon timing fields when available.
  • Tests
    • Expanded coverage for core command contract, daemon routing, relay behavior, and core-command client auto-start.

@vercel

vercel Bot commented Jul 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment Jul 3, 2026 10:27am

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

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

This PR expands the core command contract with project and relay operations, updates daemon routing and lifecycle handling for those commands, and refactors CLI flows to use core command requests for project, daemon, and relay actions.

Changes

Core Command Bus Expansion

Layer / File(s) Summary
Core command contract: new project/relay types and mappings
src/core-command-contract.ts, src/core-command-contract.test.ts
Adds new command names, project and relay result types, extends the status result with relay data, expands payload/result mappings, and updates contract tests for relay status and missing projectRoot validation.
Core command client options and tests
src/core-command-client.ts, src/core-command-client.test.ts
Adds an ensureDaemon option to requestCoreCommand and adds Vitest coverage for default daemon startup and the false override.
Core project actor kill
src/core-project-actor.ts, src/core-project-actor.test.ts
Adds a kill() method to CoreProjectActor that stops the actor and logs a warning with project identifiers and process id, with tests covering timed cleanup behavior.
Daemon routing for project and relay commands
src/daemon.ts, src/daemon.test.ts
Makes routeCoreCommand async, validates payload.projectRoot, adds relay data to status responses, handles projectEnsure, projectStop, and projectKill, adds relay command cases, and removes metadata endpoints during project stop. The daemon tests add coverage for project ensure, project stop, project kill, and metadata cleanup.
CLI refactor to requestCoreCommand
src/main.ts
Updates CLI imports and helpers, then refactors serve, host status/stop/kill/restart, daemon ensure/status/projects/project-ensure, projects list, login/logout, and remote status/enable/disable to call requestCoreCommand instead of direct daemon HTTP helpers.

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

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant requestCoreCommand
  participant Daemon
  participant CoreProjectActor

  CLI->>requestCoreCommand: project/relay command
  requestCoreCommand->>Daemon: POST core command
  Daemon->>Daemon: routeCoreCommand(envelope)
  Daemon->>CoreProjectActor: stop() / kill()
  Daemon-->>requestCoreCommand: result
  requestCoreCommand-->>CLI: response
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: routing CLI management through Core commands.
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.
✨ 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/core-cli-sidecar

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

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/main.ts (1)

1274-1293: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

host kill still behaves like host stop for active project actors
host kill and host stop both go through CORE_COMMAND_NAMES.projectStop, and the daemon only sends SIGTERM/SIGKILL in the legacy no-actor fallback. When a CoreProjectActor exists, both commands take the same graceful actor.stop() path, so the force-kill semantics are missing.

🤖 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/main.ts` around lines 1274 - 1293, The hostCmd "kill" action is still
using the same CORE_COMMAND_NAMES.projectStop path as "stop", so it never gets
force-kill behavior when a CoreProjectActor exists. Update the kill command flow
in src/main.ts so it routes to a distinct kill/force-stop command or flag, and
make the daemon-side handling in the project stop logic choose a hard
termination path for CoreProjectActor instead of calling actor.stop(). Keep the
existing stop behavior unchanged, but ensure hostCmd.command("kill") produces a
different execution path from hostCmd.command("stop").
🧹 Nitpick comments (2)
src/daemon.ts (1)

876-899: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate projectRoot validation between projectEnsure and projectStop.

Both cases repeat the identical typeof payload?.projectRoot !== "string" || !payload.projectRoot.trim() check and 400 response shape. Extracting a small helper would reduce duplication and keep future project-scoped commands consistent.

♻️ Proposed helper extraction
+  private requireProjectRoot(
+    payload: { projectRoot?: unknown } | undefined,
+  ): { ok: true; projectRoot: string } | { ok: false; error: string } {
+    if (typeof payload?.projectRoot !== "string" || !payload.projectRoot.trim()) {
+      return { ok: false, error: "projectRoot is required" };
+    }
+    return { ok: true, projectRoot: payload.projectRoot };
+  }
+
   switch (command) {
     ...
     case CORE_COMMAND_NAMES.projectEnsure: {
-        if (typeof payload?.projectRoot !== "string" || !payload.projectRoot.trim()) {
-          return {
-            status: 400,
-            body: { ok: false, id, command, error: "projectRoot is required" },
-          };
-        }
+        const check = this.requireProjectRoot(payload);
+        if (!check.ok) return { status: 400, body: { ok: false, id, command, error: check.error } };
         return {
           status: 200,
-          body: { ok: true, id, command, issuedAt, result: { project: await this.ensureProject(payload.projectRoot) } },
+          body: { ok: true, id, command, issuedAt, result: { project: await this.ensureProject(check.projectRoot) } },
         };
+    }
🤖 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/daemon.ts` around lines 876 - 899, Duplicate projectRoot validation is
repeated in the projectEnsure and projectStop branches of the daemon command
handler. Extract the shared typeof payload?.projectRoot !== "string" ||
!payload.projectRoot.trim() check and the 400 response shape into a small helper
in src/daemon.ts, then reuse it from the switch cases so project-scoped commands
stay consistent and easier to extend.
src/core-command-contract.ts (1)

45-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider a concrete type instead of unknown for relay.

CoreStatusResult.relay and CoreRelayResult.relay are typed unknown, which forces every consumer to perform an unsafe cast (e.g. result.relay as { status?: string; relayUrl?: string } in main.ts). Since getRelayStatus()/enableRelay()/disableRelay() in daemon.ts return a well-defined shape (RelayStatusSnapshot | { status: "off" }), exposing that type here would remove the need for downstream casts and catch shape mismatches at compile time.

Also applies to: 73-75

🤖 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/core-command-contract.ts` around lines 45 - 47, Replace the `unknown`
type used for `relay` in `CoreStatusResult` and `CoreRelayResult` with the
concrete relay response type returned by `getRelayStatus()`, `enableRelay()`,
and `disableRelay()` in `daemon.ts` (the `RelayStatusSnapshot | { status: "off"
}` shape). Update the shared contract in `src/core-command-contract.ts` so
consumers like `main.ts` no longer need unsafe casts, and ensure any related
type references or exports use the same symbol consistently.
🤖 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 `@src/main.ts`:
- Around line 1230-1231: The `serve` flow lost its legacy drift-repair behavior
because it now only calls `requestCoreCommand(CORE_COMMAND_NAMES.projectEnsure,
{ projectRoot })` and logs the PID, without handling stale/mismatched services.
Restore the `isAimuxBuildDriftError` / `waitForVerifiedProjectService` repair
path in the `serve` command handler, or move that retry-and-verify logic into
`projectEnsure` so `serve` still recovers old project services. Keep the
existing `projectEnsure` call and add the verification/repair branch around the
`serve` startup path where the service PID is reported.

---

Outside diff comments:
In `@src/main.ts`:
- Around line 1274-1293: The hostCmd "kill" action is still using the same
CORE_COMMAND_NAMES.projectStop path as "stop", so it never gets force-kill
behavior when a CoreProjectActor exists. Update the kill command flow in
src/main.ts so it routes to a distinct kill/force-stop command or flag, and make
the daemon-side handling in the project stop logic choose a hard termination
path for CoreProjectActor instead of calling actor.stop(). Keep the existing
stop behavior unchanged, but ensure hostCmd.command("kill") produces a different
execution path from hostCmd.command("stop").

---

Nitpick comments:
In `@src/core-command-contract.ts`:
- Around line 45-47: Replace the `unknown` type used for `relay` in
`CoreStatusResult` and `CoreRelayResult` with the concrete relay response type
returned by `getRelayStatus()`, `enableRelay()`, and `disableRelay()` in
`daemon.ts` (the `RelayStatusSnapshot | { status: "off" }` shape). Update the
shared contract in `src/core-command-contract.ts` so consumers like `main.ts` no
longer need unsafe casts, and ensure any related type references or exports use
the same symbol consistently.

In `@src/daemon.ts`:
- Around line 876-899: Duplicate projectRoot validation is repeated in the
projectEnsure and projectStop branches of the daemon command handler. Extract
the shared typeof payload?.projectRoot !== "string" ||
!payload.projectRoot.trim() check and the 400 response shape into a small helper
in src/daemon.ts, then reuse it from the switch cases so project-scoped commands
stay consistent and easier to extend.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 26764ed9-1e3b-46ae-b396-61f625afc103

📥 Commits

Reviewing files that changed from the base of the PR and between d3cc970 and 555c833.

📒 Files selected for processing (5)
  • src/core-command-contract.test.ts
  • src/core-command-contract.ts
  • src/daemon.test.ts
  • src/daemon.ts
  • src/main.ts

Comment thread src/main.ts Outdated
@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

Independent review finding fixed in 4f14c62: aimux serve no longer treats every thrown Error as repairable; it only repairs explicit build drift, version mismatch, transient startup failures, and verified project-service readiness failures.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

Independent review finding fixed in 4f14c62: aimux host restart --serve now uses the same Core project ensure + verification + drift repair helper as serve, so stale control-plane repair semantics are preserved.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/core-command-contract.ts (1)

80-86: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate shape between CoreProjectKillResult and CoreProjectStopResult.

Both interfaces are structurally identical ({ project: CoreProjectServiceState | null }). Consider defining one as an alias of the other to avoid drift if the shapes diverge later.

♻️ Proposed refactor
-export interface CoreProjectKillResult {
-  project: CoreProjectServiceState | null;
-}
+export type CoreProjectKillResult = CoreProjectStopResult;
🤖 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/core-command-contract.ts` around lines 80 - 86, `CoreProjectKillResult`
duplicates the same `{ project: CoreProjectServiceState | null }` shape as
`CoreProjectStopResult`, so update the contract in `CoreProjectKillResult` to
reuse the existing type instead of redefining it. Keep the shared result shape
centralized in `src/core-command-contract.ts` by making one interface/type alias
refer to the other, and verify any references to `CoreProjectKillResult` and
`CoreProjectStopResult` still compile against the shared definition.
🤖 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 `@src/core-project-actor.ts`:
- Around line 92-99: The kill() method in coreProjectActor still only delegates
to stop(), so a forced termination request can hang if graceful cleanup stalls.
Update kill() to implement a true hard-stop path by adding a timeout and SIGKILL
fallback, or by moving the hard-termination logic into this method, while
keeping the existing log.warn call in coreProjectActor for the final
force-stopped event.

---

Nitpick comments:
In `@src/core-command-contract.ts`:
- Around line 80-86: `CoreProjectKillResult` duplicates the same `{ project:
CoreProjectServiceState | null }` shape as `CoreProjectStopResult`, so update
the contract in `CoreProjectKillResult` to reuse the existing type instead of
redefining it. Keep the shared result shape centralized in
`src/core-command-contract.ts` by making one interface/type alias refer to the
other, and verify any references to `CoreProjectKillResult` and
`CoreProjectStopResult` still compile against the shared definition.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 111b9b58-eee1-4511-aa8f-0ea27f28da5d

📥 Commits

Reviewing files that changed from the base of the PR and between 41e4dff and 6bb1f2f.

📒 Files selected for processing (6)
  • src/core-command-contract.test.ts
  • src/core-command-contract.ts
  • src/core-project-actor.ts
  • src/daemon.test.ts
  • src/daemon.ts
  • src/main.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/daemon.test.ts
  • src/core-command-contract.test.ts
  • src/daemon.ts
  • src/main.ts

Comment thread src/core-project-actor.ts
@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai 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.

Caution

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

⚠️ Outside diff range comments (1)
src/core-project-actor.ts (1)

94-133: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Await the in-flight cleanup before reusing the project root. kill() can return after the timeout while mux.cleanup() is still running in the background, so a fresh start() for the same project can overlap with teardown and race on tmux/process/metadata cleanup. Track the pending cleanup promise and await it before the next start, or add a stronger hard-stop path.

🤖 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/core-project-actor.ts` around lines 94 - 133, The kill() flow in
CoreProjectActor can time out and return while mux.cleanup() is still running,
which allows a later start() for the same projectRoot to overlap with teardown.
Update kill() to track the in-flight cleanup from mux.cleanup() in
CoreProjectActor and ensure the pending cleanup is awaited or otherwise
completed before the project root can be reused, or add a stronger hard-stop
path that fully stops the tmux/process/metadata teardown before returning.
🤖 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/core-project-actor.ts`:
- Around line 94-133: The kill() flow in CoreProjectActor can time out and
return while mux.cleanup() is still running, which allows a later start() for
the same projectRoot to overlap with teardown. Update kill() to track the
in-flight cleanup from mux.cleanup() in CoreProjectActor and ensure the pending
cleanup is awaited or otherwise completed before the project root can be reused,
or add a stronger hard-stop path that fully stops the tmux/process/metadata
teardown before returning.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 663c0516-762a-4d9c-9d2c-baed196f16f4

📥 Commits

Reviewing files that changed from the base of the PR and between 4ac7801 and 8b4ae23.

📒 Files selected for processing (3)
  • src/core-command-contract.ts
  • src/core-project-actor.test.ts
  • src/core-project-actor.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/core-command-contract.ts

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