Skip to content

feat(desktop): manage the supervised Local Host - #4161

Merged
M4n5ter merged 3 commits into
mainfrom
feat/local-managed-host-management
Aug 29, 2026
Merged

feat(desktop): manage the supervised Local Host#4161
M4n5ter merged 3 commits into
mainfrom
feat/local-managed-host-management

Conversation

@M4n5ter

@M4n5ter M4n5ter commented Aug 29, 2026

Copy link
Copy Markdown
Member
English

Summary

Enabling remote access promotes the built-in Local Host from a Desktop child process to a system-supervised service. Desktop now keeps Local as the connection identity while exposing the same service-management surface used for managed SSH Hosts, without creating a duplicate remote profile or a second lifecycle authority.

  • Route Local status, start, restart, logs, update, update policy, reconciliation, project-root configuration, and uninstall through the deployment-bound local operator.
  • Keep the Local lifecycle receipt as Desktop's sole authority and serialize service changes, Local ownership retirement, and reconnect through one controller.
  • Recover setup, peer changes, and uninstall from persisted intent before an ephemeral Local Host can reclaim the root.
  • Adopt committed managed authority even when Direct peer support is unavailable, so turning off Direct peer connectivity does not hide or strand the supervised service.
  • Allow service recovery and mutations while no Runtime Host candidate is connected, while preserving explicit active-task interruption authority for restart.
  • Keep Direct peer connectivity and shared-access controls on the Local Remote access row; the shared management dialog exposes only capabilities owned by that surface.
  • Use target-neutral management and uninstall copy for Local and SSH Hosts.

Builds on the Local lifecycle ownership and cleanup semantics in #4146.

Verification

  • 22 focused Local lifecycle and shared-management tests passed on the rebased merge tree
  • npm run lint — 2,944 files checked, no findings
  • git diff --check
  • Parallel correctness, design, lifecycle/security, and simplification review loops reached no remaining findings

The repository-wide Desktop typecheck/build is currently blocked by UI API drift already present on origin/main (autoScroll in packages/ui/src/chat-surface-layout.tsx and scrollOwner in quote-companion-panel.tsx); both files are byte-identical to origin/main and outside this PR's diff.

Electron dogfood on macOS with an isolated user-data directory verified that Local management reads the supervised service status, PID, version, update policy, and project roots; disabling Direct peer connectivity preserves the managed service and Manage entry; unified uninstall removes the lifecycle receipt, deployment, and background process.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex implemented and reviewed the change, added focused tests, and exercised the Electron workflow. Every affected commit contains a Generated-by: OpenAI Codex trailer.

Checklist

  • Tests cover the decision-relevant lifecycle boundaries
  • Lint, typecheck, build, and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No
简体中文

概要

开启远程访问会把内置 Local Host 从 Desktop 子进程提升为系统托管服务。Desktop 保留 Local 作为连接身份,同时复用托管 SSH Host 的服务管理界面,不创建重复的远程 Profile,也不引入第二套生命周期 authority。

  • 通过绑定具体 deployment 的本地 operator,统一提供状态、启动、重启、日志、更新、更新策略、reconciliation、项目根目录配置与卸载能力。
  • Local lifecycle receipt 仍是 Desktop 唯一 authority;服务变更、Local ownership 退役与重连由同一个 controller 串行协调。
  • 在临时 Local Host 重新占用 root 前,根据持久化 intent 恢复 setup、peer 变更与卸载。
  • 即使 Direct peer 不可用,也会采用已经提交的 managed authority;关闭 Direct peer 不会隐藏或遗留系统托管服务。
  • 没有 Runtime Host candidate 连接时,仍可执行服务恢复与管理操作;重启活动任务仍要求显式中断授权。
  • Direct peer 连接与共享访问仍由 Local 的远程访问行管理;统一管理弹窗只展示其真正拥有的能力。
  • Local 与 SSH Host 共用跨目标类型的管理和卸载文案。

本 PR 基于 #4146 已提供的 Local 生命周期 ownership 与清理语义。

验证

  • rebase 后的 merge tree 上,22 个聚焦 Local 生命周期和统一管理边界的测试通过
  • lint 检查 2,944 个文件,无 finding
  • git diff --check 通过
  • correctness、design、lifecycle/security 与 simplification 并行审查循环均已归零

仓库级 Desktop typecheck/build 当前被 origin/main 已存在的 UI API 漂移阻塞(packages/ui/src/chat-surface-layout.tsxautoScrollquote-companion-panel.tsxscrollOwner);两个文件均与 origin/main 完全一致,不在本 PR diff 中。

在 macOS 隔离用户目录中完成 Electron 实机验证:Local 管理界面可读取系统托管服务的状态、PID、版本、更新策略和项目根目录;关闭 Direct peer 后,托管服务与 管理 入口仍保留;统一卸载会移除 lifecycle receipt、deployment 与后台进程。

AI 使用

OpenAI Codex 参与了实现、审查、聚焦测试与 Electron 流程验证。所有受影响提交均包含 Generated-by: OpenAI Codex trailer。

检查项

高价值生命周期边界已有测试覆盖;lint 与受影响测试套件均通过;行为变化已在概要中说明。

@M4n5ter M4n5ter changed the title feat/local managed host management feat(desktop): manage the supervised Local Host Aug 29, 2026

@jackwener jackwener left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I cannot approve 21da4582138931eb7a03ec754db7290c75223f70 yet because two merge-blocking defects remain.

  1. [P1] The renderer no longer type-checks. In runtime-host-profiles-section.tsx, the profile.transport.kind === "ssh" narrowing is not preserved inside the onClick callback, so profile.transport.destination fails with TS2339. npx tsc -p apps/desktop/tsconfig.renderer.json --noEmit reproduces this on the exact head. Capture the SSH destination while the transport is narrowed, or narrow it again inside the callback.

  2. [P1] A stopped Local service cannot be started from the new management dialog. Status and logs intentionally bypass Host retirement, so a deployment-bound operator can report state: "stopped" and the dialog displays Start. The mutation then enters runManagedServiceChange(). For an unavailable supervised target, retireOwnedLocalHost() returns not_owned, and line 617 calls runManagedLocalHostChange(), whose lifecycle.quiesce() requires a ready candidate and throws before the operator is invoked. A production-seam probe with a real managed lifecycle receipt returned status: "stopped", then both Start and Uninstall failed with Runtime Host reconnect lifecycle is closed; the operator saw only the status call. Uninstall had already persisted state: "uninstalling", so startup recovery repeats the same failure. Please keep the manager mutation serialization, but allow the bound operator change to run when there is no current supervised candidate, then schedule reconnect. Add a stopped-service regression through the Local lifecycle/provider seam.

The Desktop main/preload/overlay build, 25 focused management tests, Biome, and git diff --check pass. The current-main merge tree is clean, and the exact-head package check is green, but neither covers the failing renderer type-check or the stopped-service path above.


Posted by an automated review agent operated by @WAWQAQ. This is not an
independent human review and does not satisfy the committer review required by
CONTRIBUTING.md. A human is accountable for this comment — please push back if
anything here is wrong.

简体中文

本条评论由 @WAWQAQ 运行的自动化审查程序发出。它不构成 CONTRIBUTING.md
所要求的独立人类审查,也不能替代人类审查。有人类对本条评论负责,如有错误请直接指出。

@M4n5ter

M4n5ter commented Aug 29, 2026

Copy link
Copy Markdown
Member Author

Both blockers are fixed in f72b893c2.

  1. The SSH destination is captured while the transport is narrowed, and the complete Desktop typecheck now passes.
  2. Managed Local service changes now suspend the reconnect lifecycle without requiring a ready candidate. The deployment-bound operator can start, recover, or uninstall a stopped service, then the shared controller schedules reconnection. Restart still requires explicit authority before interrupting active work.

The follow-up review loop also closed the related recovery boundaries: persisted peer changes and uninstall replay through the exact canonical operator before Local startup, and committed managed authority is adopted independently of Direct peer availability.

Validation: Desktop typecheck and build, 22 focused lifecycle/management tests, lint, and git diff --check. Parallel correctness, design, lifecycle/security, and simplification reviews report no remaining findings.

简体中文

两个 blocker 均已在 f72b893c2 中修复。

  1. SSH destination 在 transport narrowing 有效时捕获,Desktop 完整 typecheck 已通过。
  2. Local 托管服务变更会在不要求 ready candidate 的情况下 suspend reconnect lifecycle。绑定 deployment 的 operator 可以启动、恢复或卸载已停止的服务,随后由统一 controller 安排重连;重启活动任务仍需要显式中断授权。

后续审查同时关闭了相关恢复边界:持久化 peer 变更与卸载会在 Local 启动前通过精确的 canonical operator 重放;已经提交的 managed authority 不再依赖 Direct peer 能力即可采用。

验证包括 Desktop typecheck 与构建、22 个聚焦生命周期/管理测试、lint 和 git diff --check。correctness、design、lifecycle/security 与 simplification 并行审查均无剩余 finding。

@M4n5ter
M4n5ter marked this pull request as ready for review August 29, 2026 11:38
@M4n5ter
M4n5ter force-pushed the feat/local-managed-host-management branch from f72b893 to 4f85193 Compare August 29, 2026 11:39
@M4n5ter
M4n5ter changed the base branch from fix/peer-mesh-cleanup to main August 29, 2026 11:39

@jackwener jackwener left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The two blockers from my previous review are closed on 4f85193acca39bebb7aedde3b28f18642ebbfdbe.

  • The SSH destination is captured while the transport remains narrowed, so the PR no longer produces the profile.transport.destination type error.
  • Managed Local changes now suspend the reconnect lifecycle across both a ready supervised candidate and a connection gap. Pre-start recovery also completes persisted peer-change and uninstall intents directly through the exact deployment-bound operator before an ephemeral Host can claim the root.

I found no remaining P0–P2 issues. The affected Runtime Host build and 82 focused reconnect/Desktop lifecycle/management tests pass, along with Biome and git diff --check. The two remaining Desktop renderer type errors are byte-for-byte inherited from current main (scrollOwner in app-shell.tsx and quote-companion-panel.tsx), not introduced by this PR. The exact head merges cleanly with current main.


Posted by an automated review agent operated by @WAWQAQ. This is not an
independent human review and does not satisfy the committer review required by
CONTRIBUTING.md. A human is accountable for this comment — please push back if
anything here is wrong.

简体中文

本条评论由 @WAWQAQ 运行的自动化审查程序发出。它不构成 CONTRIBUTING.md
所要求的独立人类审查,也不能替代人类审查。有人类对本条评论负责,如有错误请直接指出。

Reuse the managed Runtime Host management surface for the built-in Local Host after remote access promotes it to a supervised service. Preserve Local lifecycle authority while routing service operations through the deployment-bound operator.

Generated-by: OpenAI Codex
Keep Local service management on the shared surface without inventing Direct peer or credential operations that belong to remote profiles. Gate the renderer by the target capability and make confirmation copy valid for every Host.

Generated-by: OpenAI Codex
Make managed Local lifecycle recovery independent of Direct peer availability, preserve exact operator authority across setup and uninstall replay, and let service changes proceed while no Runtime Host candidate is connected.

Consolidate the shared management controller and retain only focused lifecycle tests.

Generated-by: OpenAI Codex
@M4n5ter
M4n5ter force-pushed the feat/local-managed-host-management branch from 4f85193 to 88d6527 Compare August 29, 2026 13:40
@M4n5ter
M4n5ter merged commit c3d4eae into main Aug 29, 2026
14 checks passed
@M4n5ter
M4n5ter deleted the feat/local-managed-host-management branch August 29, 2026 14:03
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.

2 participants