@khorsheed/dsh-local-agent 0.1.0-rc.6 → 0.1.0-rc.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # 变更记录
2
+
3
+ ## 0.1.0-rc.8(2026-09-30)
4
+
5
+ 家族同版联动:加宽 `@deepseek-ai/dsh-*` peer 区间以覆盖宿主 0.2.0(0.2.0 的兼容闸会禁用 peer 区间不覆盖宿主版本的已装插件)。无功能变更。
6
+
7
+ ## 0.1.0-rc.7(2026-09-27)
8
+
9
+ 家族同版联动:随宿主 0.1.7-rc.2 基线发布波重发,全量构建+测试在 rc.2 基线通过(rc.1→rc.2 无触及本家族的宿主变更,逐类清点见 [Agent Note](../../.agents/notes/implemented/architecture/2026-09-27-host-017-rc2-breaking-changes.md))。README 按仓标准补齐双语。无功能变更。
10
+
11
+ ## 0.1.0-rc.6(2026-09-26)
12
+
13
+ 首个公开发布(local-agent 家族七包同版首发:core → tool-subagent / dsh-headless → kimi / codex / claude-code / dsh)。
package/README.en.md CHANGED
@@ -1,33 +1,37 @@
1
- # `@khorsheed/dsh-local-agent`
2
-
3
- Model/effort controls, directories and visible member output share one member subscription per page, keeping multiple members and member-session navigation from multiplying HTTP/1 connections. Core queues busy selections for the next complete turn; frozen evaluation members reject changes.
4
-
5
- Live member output uses a streaming Remote and public Conversation nodes. Browser updates are batched for at most 50ms, while incremental recovery checkpoints use an independent one-second cadence. Native final messages replace the transient presentation and retain usage, tools and session navigation. Reconnect obtains a fresh baseline; a host crash may lose the uncheckpointed tail, which remains visibly partial. Browser P95 acceptance remains part of the room coordinator proposal.
1
+ # @khorsheed/dsh-local-agent
6
2
 
7
3
  English | [中文](README.md)
8
4
 
9
- Run locally installed coding-agent CLIs — Kimi Code, Codex, Claude Code — from the dsh web GUI. Each CLI gets an isolated home, slash commands for login/sessions/status/logout, and an auth section in Settings.
5
+ Drive the coding-agent CLIs installed on this machine — Kimi Code, Codex, Claude Code, even another dsh — from the dsh web UI.
6
+
7
+ This is the local-agent family core: each CLI registers as one harness and gets an isolated scoped home under the shared homes root (created 0700 — your native CLI installation is never touched), a `/<harness> login|sessions|status|logout` slash-command family, and an auth card in Settings; the family's delegation ability — handing session work to a local CLI and resuming it later, even across host restarts — hangs off the same registry. The harnesses themselves ship as separate packages (`@khorsheed/dsh-local-agent-kimi` and friends); this package contains none.
10
8
 
11
- <img src="../../docs/screenshots/08-local-agent.png" width="480" alt="The Local Agent cards under Settings → Plugins, header dots showing each provider's auth state">
9
+ <img src="https://raw.githubusercontent.com/Khorsheed/dsh-basic/main/docs/screenshots/08-local-agent.png" width="640" alt="the Local Agent cards under Settings → Plugins, header dots showing each provider's auth state">
12
10
 
13
11
  ## Features
14
12
 
15
13
  - **Scoped homes per CLI** — isolated credential/session home under a shared root, created 0700; your native CLI installation is never touched.
16
- - **Slash commands** — `/<harness> login|sessions|status|logout`, with the device-code login URL in the reply.
17
- - **A settings card per provider** — on alpha.2 the bundle's own Plugins-page detail view (`plugins.bundle.config`, keyed by package name), on 0.1.5 Settings → Plugins → 可配置插件 (`settings.plugin.item`, keyed by the settings namespace): the auth status dot (visible on the collapsed 0.1.5 header), web login/sign-out, and the hot-swappable resident-mode (live) toggle with mirror granularity; cards compose this package's shared `ProviderAuthBlock`.
18
- - **Subagent delegation** — hand work to a local CLI and resume it later, even across host restarts.
14
+ - **Slash-command families** — `/<harness> login|sessions|status|logout`, with the device-code login URL in the reply; plus the family commands `/local-agent list` (the registered-harness roster) and `/local-agent stop <childSessionId>` (cancel an in-flight delegation).
15
+ - **A settings card per provider** — under Settings → Plugins → 可配置插件 (`settings.plugin.item`, keyed by the settings namespace): the auth status dot on the card header, web login/sign-out, and the hot-swappable resident-mode (live) toggle with mirror granularity; cards compose this package's shared `ProviderAuthBlock`.
16
+ - **Subagent delegation with resume** — hand work to a local CLI and resume it later, even across host restarts; delegation records persist per harness in the scoped home's `delegations.jsonl`.
17
+ - **Member sessions stay writable** — a delegated child session is not a read-only replay: the MemberComposer keeps it open for input (sending resumes it), live output streams in, and the model and reasoning effort switch from the member composer; a selection made while busy takes effect on the next complete turn, and frozen evaluation members refuse changes.
19
18
  - **Member sessions continue in the sidebar (host 0.1.6+)** — the official subagent directory gained an "Open in sidebar" row action: member sessions are one-shot subagents, so opened aside, this family's MemberComposer is elected as the writable composer — a zero-change benefit of this package; 0.1.5 hosts have no such entry and behave as before.
20
19
  - **Several logins per harness (named scopes)** — `/<harness> login --scope <name>` opens a second scoped home at `<homesRoot>/<harness>@<name>`: its own login, its own session records, its own `delegations.jsonl`, and nothing copied from the default one. An evaluation can therefore compare two accounts of one harness in a single run.
21
20
 
21
+ <img src="https://raw.githubusercontent.com/Khorsheed/dsh-basic/main/docs/screenshots/local-agent-member.png" width="640" alt="a member session delegated to a local CLI: live output streaming in, with the writable member composer and its model picker at the bottom">
22
+
22
23
  ## Install
23
24
 
24
- Install the core together with at least one harness bundle (`@khorsheed/dsh-local-agent-kimi`, `-codex`): `dsh plugin add` activates only *direct* dependencies, so the harness bundle's transitive dependency alone will not mount this core.
25
+ The core must be installed alongside at least one harness package — `dsh plugin add` activates only *direct* dependencies, so a harness package's transitive dependency alone never mounts this core:
25
26
 
26
27
  ```sh
27
28
  dsh plugin --profile web add @khorsheed/dsh-local-agent
29
+ dsh plugin --profile web add @khorsheed/dsh-local-agent-kimi # or -codex / -claude-code / -dsh
28
30
  ```
29
31
 
30
- Then restart the web instance. Uninstall:
32
+ To install the whole family at once (core + the four delegation providers), add the meta-package `@khorsheed/dsh-bundle-local-agent` instead.
33
+
34
+ Restart the web instance to activate. Uninstall:
31
35
 
32
36
  ```sh
33
37
  dsh plugin --profile web remove @khorsheed/dsh-local-agent
@@ -47,14 +51,14 @@ A custom composition mounts the core once:
47
51
  ## Compatibility
48
52
 
49
53
  - npm release line (`@deepseek-ai/dsh@0.1.5-rc.1`): ✅ full — adapted to 0.1.5-rc.1 (format v2/v3; handle-based sessionPersistence), full build+test green; minHost moves up to 0.1.5-rc.1 — older hosts stay on the previous release line.
50
- - source line (deepseek-harness master): ✅ (verifiedHost: 0.1.5-rc.1)
54
+ - source line (deepseek-harness master): ✅ (verifiedHost: 0.1.5-rc.1).
51
55
 
52
56
  ## Known Limitations
53
57
 
54
- - **Login is a captured prompt or a manual handoff** — the web GUI has no interactive terminal: device-code harnesses (kimi/codex) surface the URL in the command reply while the CLI polls in the background; a harness whose auth is TTY-only (claude ≥2.1) declares the manual variant — `/login` replies with the exact command to run in the user's own terminal, and the registry watches the scoped home for the credential.
58
+ - **Login is not an interactive terminal** — the web GUI has no interactive terminal surface, so each harness with a login flow takes an adapted lane: kimi's device-code URL lands in the command reply while the CLI polls in the background; codex's and claude's (≥2.1) auth runs only on a TTY, so the login command is spawned under a pseudo-terminal wrapper — the CLI opens the user's browser itself, an OAuth URL is scraped from its output as a fallback, and a code prompt is answered with `/<harness> code <value>` — while the registry watches the scoped home for the credential. The contract also carries a manual-handoff variant (the reply names the exact command for the user's own terminal); no family harness needs it today. The dsh harness has no login flow at all (it inherits the host instance's credential), and `/dsh login` says so.
55
59
  - **Homes root placement** — defaults to `$DSH_HOME/local-agent`, pending a standardized `var/state` layout.
56
60
  - **Delegation log growth** — each scoped home's `delegations.jsonl` is append-only with no rotation.
57
- - **One-sample shape** — the harness contract is induced from Kimi alone; not yet frozen.
61
+ - **The harness contract is not frozen** — the four existing providers (kimi / codex / claude-code / dsh) each induced their share of it, and the registration interface may still move before a new harness joins.
58
62
  - **The member channel authenticates on the per-run token alone** — the token is delivered through the CLI's scoped MCP config (the 0700 scoped home keeps other users out) and invalidated the moment the run settles; host 0.1.5 removed the child pid, so there is no second factor. **Residual exposure**: a same-host, same-user sibling member CLI (its model-driven bash) can read another member's token and replay it — the old pid check was a self-reported field and never stopped a deliberate forgery, so dropping it loses little; but a deliberately crafted cross-member call is now possible. Hardening (kernel-level socket peer credentials, or a spawn-time injected capability token) is tracked in `proposals/active/2026-09-10-member-channel-auth-hardening.md`.
59
63
 
60
64
  ## How it works
@@ -62,17 +66,19 @@ A custom composition mounts the core once:
62
66
  <details>
63
67
  <summary>Internals (click to expand)</summary>
64
68
 
65
- Each harness registers into `ctx.localAgent`: a scoped home, an optional login declaration (a device-code command, or the manual-handoff variant for a TTY-only CLI), a session-records adapter, and optional auth-status and sign-out probes. The glue provisions each home and registers the `/<harness> login|sessions|status|logout` command family; per-harness differences are just `homeEnvVar`, the login invocation, the records adapter, and the auth/sign-out probes.
69
+ Each harness registers into `ctx.localAgent`: a scoped home, an optional login declaration (a device-code command, a pty-wrapped TTY login, or the manual-handoff variant), a session-records adapter, and optional auth-status and sign-out probes. The glue provisions each home and registers the `/<harness> login|sessions|status|logout` command family; per-harness differences are just `homeEnvVar`, the login invocation, the records adapter, and the auth/sign-out probes.
66
70
 
67
71
  **Delegation stays out of this seam.** Each harness bundle mounts its own subagent-provider row into the existing `subagent` capability (subagent-acp for ACP-over-stdio harnesses, an app-server provider for Codex), reading the scoped home through `localAgent.homeDir(name)`.
68
72
 
69
73
  **Program queries ride a read-only Remote channel.** A `LocalAgentGateway` (service key `localAgentGateway`, generated `./remote`) exposes roster, per-harness status, and scoped sessions to the browser. It emits no session events, so UI polls leave no command nodes in the session log; login and logout stay on the slash-command channel, where a visible command node is the expected feedback.
70
74
 
75
+ **The member live-output pipeline.** A member's (delegated child session's) live output rides a streaming Remote and public Conversation nodes: the provider hands the round's increments to a `LiveStreamPublisher`, browser-side updates coalesce within at most 50ms (`LIVE_FLUSH_INTERVAL_MS`), and incremental recovery checkpoints append `local-agent/stream` events on an independent one-second cadence (`LIVE_CHECKPOINT_INTERVAL_MS`); once the native final message lands it replaces the transient presentation, keeping usage, tools, and session navigation. A reconnect reads a fresh baseline; a host crash can lose the uncheckpointed tail, and the recovered content is explicitly marked partial. Model/effort configuration, model directories, and the visible members' live output share one member subscription per page (`MemberFeeds`), so many members and member-session entries never saturate the HTTP/1 connection pool. Browser P95 acceptance remains part of the room coordinator proposal.
76
+
71
77
  **Evaluation snapshot (`effectiveSettings`).** Every harness may declare a snapshot of the fairness-relevant settings currently in force: drive (exec/live), the sandbox or permission boundary (in each harness's own vocabulary — codex reports its sandbox policy, claude-code its permission mode, kimi its auto-approve state; a harness with no such knob omits the field, and the absence is itself the honest condition-hash input), the reasoning effort, the configured model (each harness reads its own configuration surface — kimi's `default_model`, codex's `model`, claude-code's scoped `settings.json`, dsh's inherited host selection; unreadable means the field drops out, never a guessed default), whether a non-default endpoint is pinned (hostname only, never the full URL), and the CLI version (asked of the CLI itself: `probeCliVersion` runs one `<cli> --version`, cached against the executable's resolved path + mtime + size, so an upgrade re-probes by itself while a missing CLI, a timeout, a non-zero exit, or output with no version-shaped token all just leave the field out). The snapshot is a live read — a person-edited scoped config reports the edited values — pure JSON, never credentials. `registry.effectiveSettings(name)` serves the evaluator's condition hash, and the same snapshot rides `/<harness> status` and the `LocalAgentStatus` Remote (additive fields; existing clients are unaffected).
72
78
 
73
79
  **The credential status says only what is known (`credentialState`).** Beside the `authenticated` boolean, `LocalAgentStatus` carries a grade: `absent` (no credential record in the scoped home), `present-unverified` (a record exists, but nothing in this host process has exercised it — an expired, unrefreshable grant looks exactly like a working one, and saying so is the whole point of this grade), `verified` (a delegation round reached the endpoint and completed since the last login/logout), and `rejected` (a round's endpoint rejected the credential and no fresh login has rewritten the credential marker since). `authenticated` is unchanged and exactly equals `verified || present-unverified`, so the settings card and every existing client keep reading the boolean they always read. The grade is per host process: after a restart a present credential reports `present-unverified`, because that is what is actually known — an eager pre-run liveness probe is not this field's job. Providers call `reportAuthSuccess` when a round settles completed, the symmetric counterpart of the existing `reportAuthFailure`.
74
80
 
75
- **Browser half ships in this package.** The `./client` export mounts automatically via the `dsh.client` manifest: the member composer (delegated child sessions stay writable) plus the shared settings-card building blocks (`ProviderAuthBlock`, the auth-status bus, `AuthStatusDot`) — each provider package's settings card (the alpha.2 `plugins.bundle.config` page, the 0.1.5 `settings.plugin.item` card) composes them, keeping the UI provider-neutral (it consumes only the `/<harness>` command family and the read-only gateway).
81
+ **Browser half ships in this package.** The `./client` export mounts automatically via the `dsh.client` manifest: the member composer (delegated child sessions stay writable) plus the shared settings-card building blocks (`ProviderAuthBlock`, the auth-status bus, `AuthStatusDot`) — each provider package's settings card (the 0.1.5 `settings.plugin.item` card) composes them, keeping the UI provider-neutral (it consumes only the `/<harness>` command family and the read-only gateway).
76
82
 
77
83
  ### Adding a harness
78
84
 
package/README.i18n.yaml CHANGED
@@ -1,2 +1,6 @@
1
- packages/local-agent/README.en.md: 2a3f23b5efe415f8ac0a2dd1b5351572d87c1877
2
- packages/local-agent/README.md: 0b373ec0729ac90b5565af227da9d68c39e7194b
1
+ # Bilingual-pair consistency record: the git blob hash of each side as of the
2
+ # last confirmed-consistent state. Both languages carry equal authority; after
3
+ # editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write packages/local-agent/README.en.md
5
+ packages/local-agent/README.en.md: 131ab524efcb081b0cbd4f27f6bd2b221d58003f
6
+ packages/local-agent/README.md: 16d63a8046557a8f6d7582ec338f41a0f1774110
package/README.md CHANGED
@@ -1,33 +1,37 @@
1
- # `@khorsheed/dsh-local-agent`
2
-
3
- 模型/effort 配置、模型目录与可见成员的实时输出在每个页面共用一条成员订阅,避免多成员及成员会话入口占满 HTTP/1 连接池。运行中选项由 core 排到下一完整轮次,冻结评测成员拒绝变更。
4
-
5
- 成员实时输出通过流式 Remote 与公开 Conversation 节点呈现。浏览器更新最多合并 50ms,增量恢复检查点独立按一秒节奏保存。原生最终消息替换临时展示,保留用量、工具与会话导航。重连读取新基线;宿主崩溃可能丢失未落检查点的末段,恢复内容明确标为部分记录。浏览器 P95 仍需在 room 协调者提案中验收。
1
+ # @khorsheed/dsh-local-agent
6
2
 
7
3
  [English](README.en.md) | 中文
8
4
 
9
- 从 dsh web GUI 使用本机安装的编码 agent CLI——Kimi Code、Codex、Claude Code。每个 CLI 获得一个隔离的作用域目录、一组登录/会话/状态/退出的斜杠命令,以及设置里的认证分区。
5
+ 从 dsh web 界面驱动本机装好的编码 agent CLI——Kimi Code、Codex、Claude Code,甚至另一个 dsh。
6
+
7
+ 这是 local-agent 家族的核心包:每家 CLI 注册成一家 harness,得到共享 homes 根下一份 0700 的隔离作用域目录(你机器上原装的 CLI 安装绝不被动到)、一族 `/<harness> login|sessions|status|logout` 斜杠命令、设置里的一张认证卡片;家族的委派能力——把会话工作交给本机 CLI、之后跨宿主重启也能续跑——同样挂在这份注册表上。各家 harness 的实现在独立包里(`@khorsheed/dsh-local-agent-kimi` 等),本包自己一家都不含。
10
8
 
11
- <img src="../../docs/screenshots/08-local-agent.png" width="480" alt="设置 → 插件配置里的 Local Agent 卡片,卡头状态点一眼可见各 provider 授权状态">
9
+ <img src="https://raw.githubusercontent.com/Khorsheed/dsh-basic/main/docs/screenshots/08-local-agent.png" width="640" alt="设置 → 插件 → 可配置插件里的 Local Agent 卡片,卡头状态点一眼可见各 provider 授权状态">
12
10
 
13
11
  ## 特性
14
12
 
15
13
  - **每个 CLI 一个作用域目录**——共享 homes 根下的隔离凭据/会话目录,以 0700 创建;你的本地 CLI 安装绝不被动到。
16
- - **斜杠命令族**——`/<harness> login|sessions|status|logout`,device-code 登录 URL 通过命令回复呈现。
17
- - **每 provider 一张设置卡片**——alpha.2 落在各 bundle 的插件详情页(`plugins.bundle.config`,按包名派发),0.1.5 落在设置 → 插件 → 插件配置(`settings.plugin.item`,按设置命名空间派发):认证状态点(0.1.5 卡头可见)、网页登录/退出、常驻模式(live)热切开关与输出粒度;卡片直接复用本包 client 面的共享 `ProviderAuthBlock`。
18
- - **子 agent 委派**——把会话工作交给本机 CLI 并在之后 resume,宿主重启也能续上。
14
+ - **斜杠命令族**——`/<harness> login|sessions|status|logout`,device-code 登录 URL 通过命令回复呈现;另有家族命令 `/local-agent list`(已注册 harness 花名册)与 `/local-agent stop <childSessionId>`(取消在飞委派)。
15
+ - **每 provider 一张设置卡片**——落在设置 → 插件 → 可配置插件(`settings.plugin.item`,按设置命名空间派发):卡头认证状态点、网页登录/退出、常驻模式(live)热切开关与输出粒度;卡片直接复用本包 client 面的共享 `ProviderAuthBlock`。
16
+ - **子 agent 委派与续跑**——把会话工作交给本机 CLI 并在之后 resume,宿主重启也能续上;委派记录按 harness 持久化在作用域目录的 `delegations.jsonl`。
17
+ - **成员会话保持可写**——委派的子会话不是只读回放:MemberComposer 让它继续接受输入(发送即 resume),实时输出流式呈现,模型与推理强度可在成员输入栏切换;运行中选择排到下一完整轮次生效,冻结的评测成员拒绝变更。
19
18
  - **成员会话侧栏续写(宿主 0.1.6 起)**——官方 subagent 目录每行新增「在侧边栏打开」入口:成员会话本就是 one-shot subagent,侧栏内本家族 MemberComposer 自动当选为可写 composer,本包零改动受益;0.1.5 宿主没有该入口,行为不变。
20
19
  - **一家多份登录(命名 scope)**——`/<harness> login --scope <名>` 在 `<homesRoot>/<家名>@<名>` 里另开一份作用域目录:各自登录、各自会话记录、各自 `delegations.jsonl`,凭证不复制。评测因此能在同一次 run 里比较同一家的两个账号。
21
20
 
21
+ <img src="https://raw.githubusercontent.com/Khorsheed/dsh-basic/main/docs/screenshots/local-agent-member.png" width="640" alt="委派给本机 CLI 的成员会话:实时输出流式呈现,底部成员输入栏可继续对话并切换模型">
22
+
22
23
  ## 安装
23
24
 
24
- core 本身就是 bundle;请把它与至少一个 harness bundle(`@khorsheed/dsh-local-agent-kimi`、`-codex`)一起安装——`dsh plugin add` 只激活**直接**依赖,仅靠 harness bundle 的传递依赖不会挂载本 core。
25
+ core 必须与至少一个 harness 包一起装——`dsh plugin add` 只激活**直接**依赖,仅靠 harness 包的传递依赖不会挂载本 core:
25
26
 
26
27
  ```sh
27
28
  dsh plugin --profile web add @khorsheed/dsh-local-agent
29
+ dsh plugin --profile web add @khorsheed/dsh-local-agent-kimi # 或 -codex / -claude-code / -dsh
28
30
  ```
29
31
 
30
- 然后重启 web 实例。卸载:
32
+ 想一次装齐整个家族(core + 四个委派 provider),改装元包 `@khorsheed/dsh-bundle-local-agent`。
33
+
34
+ 重启 web 实例后生效。卸载:
31
35
 
32
36
  ```sh
33
37
  dsh plugin --profile web remove @khorsheed/dsh-local-agent
@@ -47,14 +51,14 @@ dsh plugin --profile web remove @khorsheed/dsh-local-agent
47
51
  ## Compatibility
48
52
 
49
53
  - npm 发布线(`@deepseek-ai/dsh@0.1.5-rc.1`):✅ 完整——适配 0.1.5-rc.1(format v2/v3;handle 制 sessionPersistence),全量构建测试通过;minHost 前移至 0.1.5-rc.1,旧宿主请停留在旧发布线。
50
- - 源码线(deepseek-harness master):✅(verifiedHost: 0.1.5-rc.1)
54
+ - 源码线(deepseek-harness master):✅(verifiedHost: 0.1.5-rc.1)。
51
55
 
52
56
  ## 已知限制
53
57
 
54
- - **登录为抓取式 prompt 或人工交接**——web GUI 没有交互式终端面:device-code harness(kimi/codex)的 URL 通过命令回复呈现、CLI 在后台轮询;认证只在 TTY 可用的 harness(claude ≥2.1)声明 manual 变体——`/login` 回复用户在自己终端运行的完整命令,registry 监听作用域目录识别登录完成。
58
+ - **登录不是交互式终端**——web GUI 没有交互式终端面,各家有登录流程的 harness 各走一条适配通道:kimi 的 device-code URL 由命令回复呈现、CLI 在后台轮询;codex 与 claude(≥2.1)的认证只在 TTY 上跑,登录命令在伪终端包装下 spawn——CLI 自己打开浏览器,输出里兜底解析 OAuth URL,要输码时用 `/<harness> code <值>` 粘贴——registry 监听作用域目录识别登录完成。契约里另有 manual 交接变体(回复一条让用户在自己终端运行的完整命令),目前家族没有 harness 需要它;dsh harness 没有登录流程(继承宿主实例的凭据),`/dsh login` 如实回答。
55
59
  - **homes 根位置**——默认 `$DSH_HOME/local-agent`,待 `var/state` 布局标准化后再议。
56
60
  - **委派日志增长**——每个作用域目录的 `delegations.jsonl` 只增不减、无轮转。
57
- - **单样本形状**——harness 契约仅由 Kimi 归纳,尚未冻结。
61
+ - **harness 契约尚未冻结**——现有四家 provider(kimi / codex / claude-code / dsh)各自归纳了自己的一份,新 harness 入局前注册接口仍可能调整。
58
62
  - **成员通道是 per-run token 单因子认证**——token 经 CLI 作用域 MCP 配置下发(0700 的 scoped home 挡住其他用户),run 落定即焚;宿主 0.1.5 移除子进程 pid 后没有第二因子。**残余风险**:同机同用户的兄弟成员 CLI(其模型驱动的 bash)能读到另一个成员的 token 并回放它——原 pid 校验也是自报字段,本就不防刻意伪造,去掉它没有实质降级;但刻意构造的跨成员调用现在是可能的。加固(socket 内核级 peer 凭证,或 spawn 时注入的 capability token)由 `proposals/active/2026-09-10-member-channel-auth-hardening.md` 跟踪。
59
63
 
60
64
  ## 实现原理
@@ -62,17 +66,19 @@ dsh plugin --profile web remove @khorsheed/dsh-local-agent
62
66
  <details>
63
67
  <summary>内部结构(点击展开)</summary>
64
68
 
65
- 每个 harness 向 `ctx.localAgent` 注册:一个作用域目录、一个可选的登录声明(device-code 命令,或 TTY-only CLI 的 manual 交接变体)、一个会话记录适配器,以及可选的认证状态与退出登录探测。glue 供给每个作用域目录并注册 `/<harness> login|sessions|status|logout` 命令族;harness 间差异只剩 `homeEnvVar`、登录调用、records 适配器与认证/退出探测。
69
+ 每个 harness 向 `ctx.localAgent` 注册:一个作用域目录、一个可选的登录声明(device-code 命令、伪终端包装的 TTY 登录,或 manual 交接变体)、一个会话记录适配器,以及可选的认证状态与退出登录探测。glue 供给每个作用域目录并注册 `/<harness> login|sessions|status|logout` 命令族;harness 间差异只剩 `homeEnvVar`、登录调用、records 适配器与认证/退出探测。
66
70
 
67
71
  **委派不属于这个 seam。** 每个 harness bundle 各自向既有的 `subagent` 能力挂载 subagent-provider 行(讲 stdio ACP 的 harness 用 subagent-acp,Codex 用其 app-server provider),经 `localAgent.homeDir(name)` 读取作用域目录。
68
72
 
69
73
  **程序查询走只读 Remote 通道。** `LocalAgentGateway`(服务键 `localAgentGateway`,生成物 `./remote`)通过 Typert Gateway 向浏览器暴露 roster、各 harness 状态与作用域会话。它不产生任何会话事件,因此 UI 轮询不会在会话日志里留下命令节点;登录与退出仍走斜杠命令通道——用户主动操作产生可见命令节点正是预期反馈。
70
74
 
75
+ **成员实时输出管线。** 成员(委派的子会话)的实时输出经流式 Remote 与公开 Conversation 节点呈现:provider 把一轮的增量交给 `LiveStreamPublisher`,浏览器侧更新最多合并 50ms(`LIVE_FLUSH_INTERVAL_MS`),增量恢复检查点按独立的一秒节奏追加 `local-agent/stream` 事件(`LIVE_CHECKPOINT_INTERVAL_MS`);原生最终消息落定后替换临时展示,用量、工具与会话导航全部保留。重连读取新基线;宿主崩溃可能丢失未落检查点的末段,恢复内容明确标为部分记录。模型/effort 配置、模型目录与可见成员的实时输出在每个页面共用一条成员订阅(`MemberFeeds`),多成员及成员会话入口不会占满 HTTP/1 连接池。浏览器 P95 仍需在 room 协调者提案中验收。
76
+
71
77
  **评测快照(effectiveSettings)。** 每个 harness 可声明一份当前生效的公平性相关设置:drive(exec/live)、沙箱或权限模式(各用自家词汇:codex 报 sandbox 策略、claude 报 permissionMode、kimi 报自动批准与否;没有该旋钮的 harness 字段缺位,缺位本身就是诚实的条件输入)、推理强度、已配置模型(各家读自家配置面:kimi 的 `default_model`、codex 的 `model`、claude 的作用域 `settings.json`、dsh 继承的宿主选择;读不到就不给字段,绝不猜默认值)、端点是否固定(只报主机名,绝不报完整 URL)、CLI 版本(问 CLI 自己:`probeCliVersion` 跑一次 `<cli> --version`,按可执行文件的解析路径+mtime+大小缓存,所以一次升级会自动重探,而没装、超时、非零退出、输出里没有版本形状的 token 都只是字段缺位)。快照是实时读——人改过的作用域配置报人改过的值——纯 JSON、绝不含凭证,`registry.effectiveSettings(name)` 供编排器读条件哈希,`/<harness> status` 与 `LocalAgentStatus` Remote 附带同一份(增量字段,旧客户端不受影响)。
72
78
 
73
79
  **凭证只说知道的(credentialState)。** `LocalAgentStatus` 除 `authenticated` 布尔外还带一档 `credentialState`:`absent`(作用域家目录里没有凭证记录)、`present-unverified`(有记录,但本宿主进程里还没有任何一轮委派碰过它——一份过期且刷不动的凭证和一份能用的凭证形状完全一样,说不知道正是这一档的意义)、`verified`(自上次登录/登出以来有一轮委派真的打通了端点并完成)、`rejected`(某轮的端点拒了这份凭证,且此后没有新登录重写凭证标记)。`authenticated` 保持不变,恒等于 `verified || present-unverified`,所以设置卡片与既有客户端读到的还是原来那个布尔。这一档是每宿主进程的:重启后一份在场的凭证回到 `present-unverified`,因为那才是当下真正知道的;开跑前的主动活性探测不归这个字段。provider 在一轮 settle 成 completed 时调 `reportAuthSuccess`,与既有的 `reportAuthFailure` 对称。
74
80
 
75
- **浏览器半身随本包提供。** `./client` 导出通过本包的 `dsh.client` manifest 自动挂载:成员 composer(委派的子会话可继续对话)+ 共享设置卡片构件(`ProviderAuthBlock`、认证状态总线、`AuthStatusDot`)——各 provider 包的设置卡片(alpha.2 `plugins.bundle.config` 页、0.1.5 `settings.plugin.item` 卡)直接组合它们,UI 保持 provider 无关(只消费 `/<harness>` 命令族和只读 gateway)。
81
+ **浏览器半身随本包提供。** `./client` 导出通过本包的 `dsh.client` manifest 自动挂载:成员 composer(委派的子会话可继续对话)+ 共享设置卡片构件(`ProviderAuthBlock`、认证状态总线、`AuthStatusDot`)——各 provider 包的设置卡片(0.1.5 `settings.plugin.item` 卡)直接组合它们,UI 保持 provider 无关(只消费 `/<harness>` 命令族和只读 gateway)。
76
82
 
77
83
  ### 新增一个 harness
78
84