feat(cli): manage Linux Runtime Host services - #3205
Conversation
📝 WalkthroughProblem solvedThis PR adds managed Runtime Host service lifecycle support to the CLI. Users can install, inspect, start, stop, restart, and uninstall a Runtime Host service. Linux uses a systemd user service, so the Runtime Host can continue after an SSH session ends. The service:
The PR also adds English and Chinese documentation and updates installation and uninstall guidance. Source of truth and solution scopeThe PR extends the existing CLI command path and Runtime Host configuration model. It does not create a parallel CLI. The platform-neutral service manager owns lifecycle rules, validation, persistence, locking, readiness checks, rollback, and uninstall behavior. The Linux systemd backend owns systemd-specific operations. This separation provides one lifecycle authority and isolates platform-specific behavior. The solution is the smallest coherent design supported by the current evidence. The manager, backend, CLI entry point, validation, persistence, and tests are necessary for the stated lifecycle contract and clean-uninstall behavior. The XDG configuration fallback supports reliable configuration resolution for the managed service. Simplification opportunitiesNo clear deletion or simplification is supported by the current evidence. The tests cover parsing, lifecycle actions, reinstall behavior, configuration repair, argument escaping, prerequisite errors, rollback, operation serialization, and State Root retention. Removing these tests would weaken regression coverage. Dependency injection and backend overrides provide test seams without changing the production path. They should remain unless equivalent existing seams are identified. Validation and concrete risksReported validation covered:
The final status of required checks is unverified from direct repository evidence. Concrete risks include:
Complexity deltaThe PR adds:
The PR removes no existing authority or lifecycle path. It avoids duplicating lifecycle rules inside the systemd backend, but it adds configuration, public API surface, operational branches, and test-maintenance burden. Total maintenance complexity increases. The increase is justified by the platform-neutral lifecycle contract, clean-uninstall requirements, rollback behavior, and backend separation. The current evidence does not show a reduction in overall complexity. Review-relevant risksThe diff changes user-visible CLI behavior, documentation, service persistence, uninstall behavior, configuration resolution, and the exported TypeScript API. Material changes in these areas require independent human review under repository policy. The diff adds Linux systemd service installation, process execution, executable-path pinning, loopback binding, and service replacement. These changes affect security and operational behavior. Material changes in these areas require independent human review under repository policy. The diff affects release packaging and installation paths. Material changes in releases require independent human review under repository policy. The person performing the merge reviews the final diff. A maintainer makes the final determination. WalkthroughThe CLI now supports persistent Linux systemd user services for the Runtime Host. It validates and stores service configuration, manages lifecycle actions, verifies readiness, supports rollback, reports structured errors, and documents installation and removal behavior. ChangesManaged Runtime Host service
Estimated code review effort: 4 (Complex) | ~45 minutes Merge Risk: 🟡 Moderate · up to The CLI’s managed-service status path can report an installed service as not installed when systemd metadata is incomplete, and executable paths containing spaces are not fully protected by tests, which could allow service startup failures to escape. Merge should wait for these bounded correctness risks to be fixed or explicitly accepted. Sequence Diagram(s)sequenceDiagram
participant RuntimeHostCLI
participant ServiceManagementCLI
participant ServiceManager
participant SystemdUserService
participant Filesystem
RuntimeHostCLI->>ServiceManagementCLI: Parse service action and options
ServiceManagementCLI->>ServiceManager: Manage service configuration
ServiceManager->>SystemdUserService: Validate and execute lifecycle action
SystemdUserService->>Filesystem: Write or remove unit file
SystemdUserService-->>ServiceManager: Return backend status
ServiceManager->>Filesystem: Persist or remove managed configuration
ServiceManager-->>ServiceManagementCLI: Return structured result
ServiceManagementCLI-->>RuntimeHostCLI: Print human-readable or JSON output
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
PR Summary by QodoAdd managed Linux Runtime Host service lifecycle
AI Description
Diagram
High-Level Assessment
Files changed (10)
|
There was a problem hiding this comment.
Actionable comments posted: 4
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 9ea4f8f8-7283-4513-8372-416623e18876
📒 Files selected for processing (10)
docs/runtime-host-remote-access.mddocs/runtime-host-remote-access.zh-CN.mdpackages/cli/README.mdpackages/cli/README.zh-CN.mdpackages/cli/src/__tests__/runtime-host-service-manager.test.tspackages/cli/src/cli-core.tspackages/cli/src/runtime-host-cli.tspackages/cli/src/runtime-host-service-management-command.tspackages/cli/src/runtime-host-service-manager.tspackages/cli/src/runtime-host-systemd-service.ts
Included review availability: Your plan includes up to 3 reviews per rolling hour; 2 remain after this review.
Code Review by Qodo
1.
|
Astro-Han
left a comment
There was a problem hiding this comment.
The platform-neutral lifecycle and Linux backend are separated cleanly, and the loopback binding, exact executable paths, linger preflight, restrictive umask, and retained State Root are good boundaries. Existing reviews already cover the failure-atomic reinstall, systemd error classification, and readiness gaps, so I am not duplicating those threads.
The first-principles simplification is still one transactional launch authority: validate every path/argument first, stage config and unit together, activate, prove Runtime Host readiness, then commit—or restore the previous pair. That removes mixed states instead of adding more status heuristics. The two inline findings below are additional input-corruption/validation gaps on the latest head.
Review performed with three Codex reviewer agents and DeepSeek V4 Flash as advisory tools; I verified the novel findings against the latest head and live green CI.
中文评论
平台无关 lifecycle 与 Linux backend 的分层清晰;loopback binding、精确 executable path、linger preflight、限制性 umask 和保留 State Root 都是正确边界。已有 review 已覆盖 reinstall 非原子、systemd 错误分类和 readiness,我不重复这些线程。
更符合第一性原理的简化仍是单一、事务性的 launch authority:先验证所有 path/argument,再一起 stage config 与 unit,激活并证明 Runtime Host ready,最后 commit;任何失败恢复上一对配置。这样可直接消除 mixed state,而不是增加更多 status heuristic。以下两个行内问题是最新 head 上额外的输入破坏/验证缺口。
本次审查使用了三位 Codex reviewer agents 与 DeepSeek V4 Flash 作为辅助工具;我已依据最新 head 和实时绿色 CI 复核新增问题。
8f9ea9f to
1408c1c
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/cli/src/__tests__/runtime-host-service-manager.test.ts (1)
101-111: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueOptional: Remove the exact systemctl command snapshot.
This assertion couples the lifecycle test to internal
systemctlcall order and query flags. Keep assertions for required lifecycle effects, such as the unit file, enabled state, and active state.As per path instructions, flag tests that assert implementation details.
Proposed simplification
- assert.deepEqual(systemd.calls.slice(0, 4), [ - ['show-environment'], - [ - 'show', - 'maka-runtime-host.service', - '--property=LoadState,ActiveState,SubState,UnitFileState,MainPID,ExecMainStatus', - '--no-pager', - ], - ['daemon-reload'], - ['enable', 'maka-runtime-host.service'], - ]);Source: Path instructions
packages/cli/src/runtime-host-systemd-service.ts (1)
294-301: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDelete the unreachable
?? 'loaded'fallback (optional).Line 297 throws when
reportedLoadStateisundefined. Line 301 can therefore never apply the'loaded'default. The leftover fallback suggests a second source of truth forloadStatethat no longer exists.♻️ Proposed simplification
const properties = parseProperties(result.stdout); - const reportedLoadState = properties.get('LoadState'); + const loadState = properties.get('LoadState'); if ( - (result.exitCode !== 0 && reportedLoadState !== 'not-found') || - reportedLoadState === undefined + loadState === undefined || + (result.exitCode !== 0 && loadState !== 'not-found') ) { throw managerError('Reading Runtime Host service status failed', result); } - const loadState = reportedLoadState ?? 'loaded'; return {Source: Path instructions
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: eb8215c0-0e2d-4df4-af22-d6d1a20a3685
📒 Files selected for processing (10)
docs/runtime-host-remote-access.mddocs/runtime-host-remote-access.zh-CN.mdpackages/cli/README.mdpackages/cli/README.zh-CN.mdpackages/cli/src/__tests__/runtime-host-service-manager.test.tspackages/cli/src/cli-core.tspackages/cli/src/runtime-host-service-manager.tspackages/cli/src/runtime-host-systemd-service.tspackages/storage/src/__tests__/workspace-root.test.tspackages/storage/src/workspace-root.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- packages/cli/src/cli-core.ts
- packages/cli/README.zh-CN.md
- docs/runtime-host-remote-access.md
- packages/cli/README.md
- docs/runtime-host-remote-access.zh-CN.md
Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.
Astro-Han
left a comment
There was a problem hiding this comment.
The latest head resolves the earlier failure-atomic install, readiness/PID ownership, project-root canonicalization, and systemd error-reporting findings. One remaining authority collision prevents approval: the persisted config is profile/data-root scoped, but the systemd unit identity is global to the Unix user.
The first-principles fix is to give the managed service the same identity as its configuration authority. Either derive a stable unit name from the Maka profile/data-root identity, or explicitly reject service management from non-release/non-default profiles. One profile must never control another profile's process.
Reviewed with Codex using two independent review passes and DeepSeek V4 Flash as an external adversarial pass; I verified the identity paths against this exact head and current main.
中文
最新 head 已修复之前的原子安装、readiness/PID 归属、project root 规范化和 systemd 错误投影问题。仍有一个权威冲突:配置按 profile/data root 隔离,但 systemd unit 对同一 Unix 用户是全局的。
最小修复是让 service identity 与配置 authority 一致:unit 名包含稳定的 profile/data-root identity,或明确禁止非发布/非默认 profile 使用 service management。一个 profile 不能控制另一个 profile 的进程。
本次由 Codex 两轮独立审查,并使用 DeepSeek V4 Flash 做外部对抗审查;我核对了当前 head 与最新 main。
Add a platform-neutral service lifecycle with a systemd user backend so a remote Host can persist beyond SSH sessions. Installation pins exact Node and CLI paths and clean uninstall retains the State Root while removing managed service state. Generated-by: Codex
Wait for application readiness before committing replacements, and restore the prior systemd deployment and configuration when any step fails. Serialize lifecycle operations and reject invalid roots, transient launch paths, and unavailable service-manager state. Generated-by: Codex
Derive each platform service identity from its Client Data Root so release and development profiles cannot control one another. Move lifecycle locking to the configuration authority and keep an unconfigured status query free of filesystem side effects. Generated-by: Codex
1408c1c to
fc93a21
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/cli/src/runtime-host-systemd-service.ts (1)
169-169: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRemove the unnecessary network ordering (optional).
The managed WebSocket host is fixed to
127.0.0.1. The shown unit has no network dependency. DeleteAfter=network.targetto keep the unit at the smallest required behavior.As per path instructions, choose deletion before adding behavior when it satisfies the invariant.
Source: Path instructions
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: a74fc7c0-1525-423d-baf4-b34e8fb22a5f
📒 Files selected for processing (4)
packages/cli/src/__tests__/runtime-host-service-manager.test.tspackages/cli/src/runtime-host-service-management-command.tspackages/cli/src/runtime-host-service-manager.tspackages/cli/src/runtime-host-systemd-service.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/cli/src/runtime-host-service-manager.ts
- packages/cli/src/runtime-host-service-management-command.ts
Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.
Astro-Han
left a comment
There was a problem hiding this comment.
The current head resolves the earlier service-identity collision and the previous lifecycle blockers. The managed unit is now scoped to the Client Data Root identity; install/reinstall is failure-atomic; readiness proves Runtime Host ownership; project roots are canonicalized and validated; and systemd failures remain failures rather than being projected as not_installed. The implementation now has one coherent configuration/service authority without adding a parallel lifecycle path.
I found no reproducible P0–P3 issue on this head. All current required checks are green.
AI-assisted review disclosure: Codex performed the final review using two independent reviewer passes and OpenCode Go DeepSeek V4 Flash (high effort) as an adversarial advisory pass. I verified the identity, rollback, readiness, and validation paths against exact head fc93a2167 and live CI.
中文评论
当前 head 已解决此前的 service identity 冲突和 lifecycle 阻塞项。managed unit 现在与 Client Data Root 身份一致;install/reinstall 具备失败原子性;readiness 会验证 Runtime Host 归属;project root 会做规范化和目录校验;systemd 失败也不会再被投影成 not_installed。整体保持了单一、连贯的配置与服务权威,没有引入并行 lifecycle。
当前 head 未发现可复现的 P0–P3 问题,所有必需检查均已通过。
AI 辅助审查说明:Codex 使用两轮独立 reviewer 审查,并以 OpenCode Go DeepSeek V4 Flash(high effort)进行对抗性辅助审查;我已针对精确 head fc93a2167 与实时 CI 复核 identity、rollback、readiness 和 validation 路径。
Summary
English
Add a managed Runtime Host service lifecycle to the CLI so a Linux Host can remain available after its SSH session ends.
The lifecycle contract, persisted configuration, normalized status, and clean-uninstall behavior are platform-neutral. Linux supplies a systemd user backend; a future macOS LaunchAgent backend can reuse the same CLI and lifecycle semantics. Installation pins the exact Node.js and Maka CLI paths, binds the WebSocket listener to loopback, and preserves the existing port and project roots on reinstall. Uninstall removes the managed unit and configuration while retaining the State Root and user data.
Refs #2522
中文
为 CLI 增加 managed Runtime Host service lifecycle,使 Linux Host 能在 SSH 会话结束后继续运行。
Lifecycle contract、持久配置、归一化状态和 clean uninstall 均保持平台无关;Linux 仅提供 systemd user backend,未来 macOS LaunchAgent backend 可以复用相同的 CLI 与 lifecycle 语义。安装会固定精确的 Node.js 与 Maka CLI 路径、只监听 loopback,并在重复安装时保留已有端口和 Project roots。卸载会移除托管 unit 与配置,同时保留 State Root 和用户数据。
Refs #2522
Verification
English
npm --workspace maka-agent test— 269 tests passednpm run build— passednpm run typecheck— all workspaces passed after a clean dependency install and buildnpm run lintandnpm run format:check— passed中文
npm --workspace maka-agent test— 269 项测试通过npm run build— 通过npm run typecheck— 干净安装依赖并构建后,所有 workspace 通过npm run lint与npm run format:check— 通过AI use
Select exactly one:
Tool(s) and scope: Codex assisted with implementation, tests, documentation, and validation under maintainer direction. The commit includes the required
Generated-by: Codextrailer.Checklist
Does this PR entail a change in behavior?