dsh-device-fleet 0.0.0-stage → 0.1.0-dev.10

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.
Files changed (60) hide show
  1. package/CONTEXT.md +123 -0
  2. package/LICENSE +21 -0
  3. package/README.md +135 -2
  4. package/client.js +167 -0
  5. package/cordis.patch.yml +26 -0
  6. package/docs/adr/0001-fleet-enrollment-over-account-auto-discovery.md +17 -0
  7. package/docs/adr/0002-shared-room-as-coordination-unit.md +17 -0
  8. package/docs/adr/0003-direct-call-and-room-as-two-channels.md +22 -0
  9. package/docs/adr/0004-direct-call-policy-owned-by-target-device.md +23 -0
  10. package/docs/adr/0005-upgrade-session-to-room-host.md +22 -0
  11. package/docs/adr/0006-addressed-messages-and-any-device-speaks.md +16 -0
  12. package/docs/adr/0007-user-speech-decoupled-from-device.md +21 -0
  13. package/docs/adr/0008-extend-global-task-list-as-room-board.md +21 -0
  14. package/docs/adr/0009-room-policy-configured-at-creation.md +21 -0
  15. package/docs/adr/0010-room-policy-v1-fields-and-custom-room-types.md +24 -0
  16. package/docs/adr/0011-room-board-lifecycle-and-hooks.md +27 -0
  17. package/docs/adr/0012-lazy-wake-and-directed-speech.md +22 -0
  18. package/docs/adr/0013-direct-call-as-device-agnostic-functions.md +26 -0
  19. package/docs/adr/0014-fleet-call-unified-entry-with-typed-shortcuts.md +22 -0
  20. package/docs/adr/0015-room-plus-local-teams-and-delegation.md +22 -0
  21. package/docs/adr/0016-delegation-upgrade-reuses-session.md +20 -0
  22. package/docs/adr/0017-network-phases-direct-and-relay.md +21 -0
  23. package/docs/adr/0018-offline-fail-fast-and-durable-room-log.md +21 -0
  24. package/docs/adr/0019-execution-context-configured-locally.md +24 -0
  25. package/docs/adr/0020-approval-inbox-with-scoped-grants.md +22 -0
  26. package/docs/adr/0021-room-visibility-user-full-agents-scoped.md +26 -0
  27. package/docs/adr/0022-tool-adoption-mechanisms.md +23 -0
  28. package/docs/adr/0023-reuse-session-trajectory-for-call-details.md +22 -0
  29. package/docs/adr/0024-strict-version-match-with-reserved-capabilities.md +22 -0
  30. package/docs/notes/approval-inbox-phase.md +31 -0
  31. package/docs/notes/design-decisions-summary.md +49 -0
  32. package/docs/notes/dev-release.md +67 -0
  33. package/docs/notes/dsh-global-task-list-evaluation.md +54 -0
  34. package/docs/notes/network-v1-v2-implementation.md +71 -0
  35. package/docs/notes/pairing-session-2026-11-09.md +30 -0
  36. package/docs/notes/remote-tests-2026-11-09.md +33 -0
  37. package/docs/notes/room-logic-phase.md +31 -0
  38. package/docs/notes/step1-host-plugin-and-direct-call.md +57 -0
  39. package/package.json +51 -3
  40. package/src/host/approval-inbox.js +135 -0
  41. package/src/host/approval-web.js +95 -0
  42. package/src/host/delegation.js +127 -0
  43. package/src/host/direct-call.js +209 -0
  44. package/src/host/execution-slot.js +96 -0
  45. package/src/host/index.js +10 -0
  46. package/src/host/room-service.js +324 -0
  47. package/src/host/store.js +156 -0
  48. package/src/host/tool-policy.js +151 -0
  49. package/src/host/tools.js +590 -0
  50. package/src/index.js +3 -0
  51. package/src/net/direct.js +69 -0
  52. package/src/net/discovery.js +105 -0
  53. package/src/net/fleet-node.js +509 -0
  54. package/src/net/identity.js +167 -0
  55. package/src/net/index.js +9 -0
  56. package/src/net/protocol.js +73 -0
  57. package/src/net/relay-client.js +258 -0
  58. package/src/net/relay-server.js +366 -0
  59. package/src/net/secure-channel.js +538 -0
  60. package/src/plugin/index.js +380 -0
@@ -0,0 +1,21 @@
1
+ # Room 由显式命令创建,并携带可配置的 Room Policy
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ Room 只在用户显式命令下创建(升级当前会话或新建房间),因此创建之前用户可以在插件设置里预设"房间类型与权限";不同协作场景需要不同规则(私密房间只让 Host 拉人,团队房间允许任意成员邀请并自动通过)。把这些行为硬编码会逼用户改代码。
8
+
9
+ ## Decision
10
+ - 插件提供**默认 Room Policy 与命名预设(Room Type)**,例如私密、团队、只读;
11
+ - 创建房间(升级当前会话或新建)时,把所选类型解析成一份**策略快照**,写进房间创建事件并广播给成员;
12
+ - 邀请权、加入方式(自动/需确认)、成员上限、任务板写权限等协作规则由该策略决定,而不是硬编码;
13
+ - 默认取插件配置,创建时可覆盖;Host 可在创建后修改协作类策略(记录并广播),但不追溯驱逐既有成员;
14
+ - **边界**:Room Policy 只管协作规则;资源访问(直调某设备的工具、读写其文件)仍由各设备的 Tool Policy 决定,两者不重叠。
15
+
16
+ ## Considered Options
17
+ - 硬编码"仅 Host 邀请 + 自动加入"——无法按场景配置,否决。
18
+ - 全局唯一策略——无法同时支持私密房间与团队房间,否决。
19
+
20
+ ## Consequences
21
+ 房间事件需要持久化策略快照;房间 UI 要显示当前策略;策略修改要审计;实现上必须明确 Room Policy 与设备 Tool Policy 的分界,避免"房间允许"被误当成"资源允许"。
@@ -0,0 +1,24 @@
1
+ # Room Policy v1:可配置协作规则与可保存的 Room Type
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 不同协作场景需要不同规则;而且 Room 由用户显式命令创建,用户应当在创建前就能在插件里配好"房间类型与权限",而不是被硬编码规则限制。当前 Fleet 是**单用户**模型(同一账号 = 同一个人),成员即用户自己的设备。
8
+
9
+ ## Decision
10
+ v1 Room Policy 字段:
11
+ - `invite`: `host-only | members`(谁能邀请新成员)
12
+ - `join`: `auto | confirm`(被邀请设备自动加入,还是需要本机确认)
13
+ - `maxMembers`: 默认 8
14
+ - `boardWrite`: `members | host`(谁能改共享任务板)
15
+ - `remove`: `members | host-only`(成员可主动移除他人,或只有 Host 能移除)
16
+
17
+ Room Type 是命名预设(内置私密/团队/只读),用户可**自定义并保存**;创建房间时解析成一份 Room Policy 快照,写入房间创建事件并广播。Host 可在创建后修改协作类策略并广播;修改不追溯驱逐已有成员,`join` 变更只影响后续加入。
18
+
19
+ ## Considered Options
20
+ - 只做内置硬编码策略——不满足"创建前按场景配置",否决。
21
+ - 策略放到设备级 Tool Policy——混淆了协作规则与资源访问,否决。
22
+
23
+ ## Consequences
24
+ 需要插件设置页管理自定义 Room Type;房间事件持久化策略快照;成员移除/加入规则变更需要广播与审计;"成员可移除他人"依赖单用户 Fleet 假设,未来支持多人房间时必须重新设计。
@@ -0,0 +1,27 @@
1
+ # Room Board 与房间同生命周期,更新由钩子驱动
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ Room Board 要解决"被唤醒的 agent 不必读全量聊天记录就能进入状态"以及"多 agent 串行/并行推进同一件事时状态不丢"。若沿用本机全局任务库,生命周期与房间不一致;若每次变化广播给所有成员,又会造成重复唤醒与 token 浪费。
8
+
9
+ ## Decision
10
+ - **Room Board 与 Room 同生命周期**:随房间创建/归档;Host 权威、参与设备只读镜像(扩展 `dsh-global-task-list` 的 `task_ui`,加 `roomId`)。
11
+ - **Room 中至少存在一个 agent**(Host 的 agent 即成员);每个成员的执行单元是 **Task Block**。
12
+ - **任务按块分配**:
13
+ - 串行块:上一块完成后,其负责人更新 Room Board,Host 将下一块标记为 ready 并向下一块的负责人发一条点名消息(唤醒它接手);
14
+ - 并行块:各成员只更新自己块的状态,不阻塞/不改变其他块;下一阶段开始时读取当前 Board 即可了解全貌。
15
+ - **更新由钩子驱动**:
16
+ - 成员被唤醒领取一块任务时,任务简报里包含该块 + 相关 Board 切片,并提醒开始执行时标记状态;
17
+ - 成员结束一轮时,Host 检查其负责块的 Board 状态;若明显未更新,发一条(最多一次)提醒消息;
18
+ - 任何成员开始新块前自行读取 Board(拉取),不要求全量推送。
19
+ - 其他成员不需要在每次变化时被唤醒;只在被点名(含"下一块 ready")时唤醒。
20
+
21
+ ## Considered Options
22
+ - 沿用全局个人任务库、不区分房间——生命周期不一致,个人任务与房间任务互相污染,否决。
23
+ - 每次 Board 变化广播唤醒所有成员——token 浪费、互相打断,否决。
24
+ - 完全依赖模型自觉更新——task-list 的经验表明会漏更新,否决。
25
+
26
+ ## Consequences
27
+ 需要在 turn 边界做 Board 一致性检查与有限提醒;串行交接会产生点名唤醒消息;Board 需要版本号/CAS 防止覆盖;参与设备的镜像是只读的,写入统一回 Host。
@@ -0,0 +1,22 @@
1
+ # 惰性唤醒与定向发言
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 多设备协作里最贵的资源是"唤醒一个 agent 跑一轮模型":既花 token,也占用该设备用户的时间与注意力。广播式协作会唤醒不必要的 agent,导致重复工作与互相打断。
8
+
9
+ ## Decision
10
+ - **按需唤醒**:只有被点名(Addressing)或被分配 Task Block 的 agent 才被唤醒;未点名成员不启动、不跑模型。
11
+ - **Participant agent 惰性创建**:加入房间时只建立成员记录与只读 Board 镜像;该成员第一次被点名/领取任务时才创建它的本地会话并注入 Participant Brief。直调工具不经过 agent,走 Execution Slot。
12
+ - **广播不是默认行为**:`*` 需要显式授权/确认(受 Room Policy 约束)。
13
+ - **定向发言**:任何成员都可以向任意一个或多个成员说话;相同内容发给多人 = 一条带收件人集合的消息;对每个成员说不同的话 = 多条消息(可用一次批量调用按顺序追加,保持审计与顺序)。
14
+ - 离线成员的消息持久在 Host 日志;唤醒是尽力而为,成员回归时按"自上次已读"补摘要(离线投递细节待定)。
15
+
16
+ ## Considered Options
17
+ - 全员广播、每条消息唤醒所有成员——token 与注意力最差,否决。
18
+ - 加入房间即创建每个成员的 agent——房间多几个不活跃成员就多几个空闲会话,否决。
19
+ - 由发件人本地转发、不经 Host——没有统一顺序与审计,否决。
20
+
21
+ ## Consequences
22
+ 首次唤醒多一次会话创建成本;协议需要 wake/assignment 事件与 turn/end 上报;批量定向消息要保证顺序与可审计;Room Policy 需要约束广播权限。
@@ -0,0 +1,26 @@
1
+ # 直调工具面:设备无关的能力函数 + device 参数
2
+
3
+ ## Status
4
+ amended by ADR-0014 —— 能力目录改为 `fleet_call` 统一入口 + 少量 typed 快捷工具;本文中"设备无关、device 参数、Execution Slot 映射、稳定错误码"仍然有效。
5
+
6
+ ## Status
7
+ accepted
8
+
9
+ ## Context
10
+ 把每台设备的远程工具都镜像到本地,会让工具表随"设备数 × 工具数"膨胀,设备上下线还会改变 schema、打掉 KV cache;而纯通用的 `remote_call(device, tool, args)` 又要求模型先查目录,不够"原生 function calling"。
11
+
12
+ ## Decision
13
+ 直调工具注册为**与设备无关的固定函数**,统一带 `device` 参数(设备 id 或唯一名):
14
+ - `fleet_list()` 返回成员 id/名称/在线状态/能力/Tool Policy 摘要;
15
+ - 能力函数按固定目录、在所有设备上同构注册,例如 `fleet_read(device, path, ...)`、`fleet_list_dir(device, path)`、`fleet_grep(device, pattern, path)`、`fleet_fetch(device, path, ...)`、`fleet_run(device, command, cwd?, timeoutMs?)`;
16
+ - `device` 在 schema 中用字符串而不是枚举:schema 保持稳定(KV cache 友好),运行时按 Fleet 成员表校验;
17
+ - 目标设备把能力映射到本地 tool(如 `fleet_read` → `read`),以 Execution Slot 执行;是否免审/需审批/拒绝由该设备的 Tool Policy 决定;
18
+ - 未纳入目录的冷门工具可通过可选的 `fleet_call(device, tool, args)` 兜底(默认关闭)。
19
+
20
+ ## Considered Options
21
+ - 每设备镜像工具——schema 随设备变化、工具表膨胀,否决。
22
+ - 纯通用 `remote_call` + 目录查询——每次新工具都要先查一次,不够原生,否决。
23
+ - MCP 桥接——无 wait/cancel 语义、本构建无 server SDK,不作为核心路径,否决。
24
+
25
+ ## Consequences
26
+ 需要一张"能力 → 本地工具"映射表与稳定错误码(`device_not_found` / `offline` / `unsupported` / `denied` / `approval_timeout` / `tool_failed`);能力目录按插件版本固定,设备间能力差异靠运行时校验;模型需要先用 `fleet_list` 拿到 device id。
@@ -0,0 +1,22 @@
1
+ # fleet_call 统一执行入口 + 少量 typed 快捷工具
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 纯 typed 能力目录要求每台设备、每个新工具都同步进插件工具表;纯 `fleet_call` 又让模型拿不到目标工具的精确 JSON Schema,复杂参数会在目标设备校验失败、白跑一次往返,且必须先查目录。
8
+
9
+ ## Decision
10
+ 直调只有一个执行原语:`fleet_call(device, tool, parameters)`。
11
+ - `fleet_tools(device)` 返回目标设备**可被远端调用**的工具名、JSON Schema 与 Tool Policy 摘要;
12
+ - `fleet_call` 的 `parameters` 在目标设备按其真实 schema 校验,错误原样回传;
13
+ - 另注册少量高频 **typed 快捷工具**:`fleet_read` / `fleet_fetch` / `fleet_run`,它们只是 `fleet_call` 的薄包装,提供精确 schema 与更好的 function-calling 保真度;
14
+ - 任何设备新增的工具无需插件升级即可通过 `fleet_call` 使用(仍受该设备 Tool Policy 约束);快捷工具集合可配置。
15
+
16
+ ## Considered Options
17
+ - 纯 typed 能力目录——新增工具要改插件,否决。
18
+ - 纯 `fleet_call`——参数保真度差、发现往返多,否决。
19
+ - 动态按需镜像(查目录后临时注册 typed 工具)——会动态改工具表、打掉 KV cache,复杂度高,否决。
20
+
21
+ ## Consequences
22
+ 工具表固定为 `fleet_list` / `fleet_tools` / `fleet_call` + 三个快捷工具;模型对未 typed 工具需先 `fleet_tools` 发现;审计与限额统一在一条执行路径上做。
@@ -0,0 +1,22 @@
1
+ # 协作形态:Room 之下的本地团队与跨设备委派
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 两台设备要"看起来无缝衔接、agent 自由运行",同时每个 agent 也应保留自己原有的组织能力(本地 Agent Team、subagent)。把这些都塞进 Room 会让房间成员爆炸、上下文互相污染;完全隔离又失去跨设备合作。
8
+
9
+ ## Decision
10
+ 采用"房间 + 逐 agent 私有团队 + 跨设备委派"的三层模型:
11
+ - **Room**:跨设备协作的共享层。每个成员设备在房间里只有一个**代表 agent**(Participant),共享 Room Board、点名与消息。
12
+ - **Local Team**:每个代表 agent 在自己设备上仍可自由使用本地 Agent Team / subagent 干活;这些本地成员**对 Room 不可见、不被点名、不写 Room Board**,只由代表 agent 把结果带回房间。
13
+ - **Delegation(跨设备委派)**:成员 agent 可把一次性任务交给另一台成员设备上的 agent 执行并取回结果;被委派方使用**独立的一次性子会话**(不进入 Room、不共享房间历史、不可续聊),对应 DSH 外部 `SubagentProvider` 的 one-shot 语义。
14
+ - **边界**:跨设备委派有深度上限(默认 1,禁止 A→B→A 回环);被委派的远程子 agent 不能创建/加入 Room,也不能再唤醒第三方成员;Room 成员之间才谈"合作",委派只谈"派活"。
15
+
16
+ ## Considered Options
17
+ - 所有协作都塞进 Room——成员与上下文膨胀,否决。
18
+ - 禁止 agent 使用本地团队——与"agent 自由运行"相悖,否决。
19
+ - 远程子 agent 直接复用目标设备 Room 里的代表会话——会抢上下文与写锁,否决。
20
+
21
+ ## Consequences
22
+ 需要区分"房间成员"与"委派子会话"两种远程 agent 身份;委派结果只回到委派者;深度与回环需要协议层限制;本地团队的成本与行为仍由各设备自己负责。
@@ -0,0 +1,20 @@
1
+ # 委派升级为 Room 时复用原委派会话
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 用户常常先让 B 的 agent 做一次性任务(委派),随后才发现要继续合作。重新委派或新建 Participant 会话会丢掉上下文、cwd 与已完成的中间状态;而把"委派"和"合作"做成两套互不相通的东西,又违背"无缝衔接"的目标。
8
+
9
+ ## Decision
10
+ - 委派升级为 Room 是**显式动作**(`room.upgrade` 携带 delegation id):A 的当前会话成为 Room Host;B 上原委派子会话**直接绑定为 Participant**(保留 sessionId、上下文、cwd、中间状态),不新建会话。
11
+ - 升级后该成员只走 Room 语义;Room 日志以系统事件记录"该 Participant 由某次委派升格而来",原委派对话留在参与者本地会话,Room 只接收摘要/指针,不整段回放。
12
+ - Room 内**新发起**的委派仍创建隔离的一次性会话,结果只回发起者,不自动成为 Participant;需要长期参与时再显式升级。
13
+
14
+ ## Considered Options
15
+ - 新建 Participant 会话 + 用委派结果当简报——丢失工作现场,否决。
16
+ - 不升级、继续"再委派 + 摘要"——长期合作持续浪费,否决。
17
+ - 自动隐式升级——用户会不知道"什么时候变成了房间",否决。
18
+
19
+ ## Consequences
20
+ 委派记录必须保存目标会话 id 与可升级性;房间成员记录要允许"绑定已有会话"而不只是"新建会话";升级时 Room 与参与者两侧的历史衔接需要摘要规则(不整段回放)。
@@ -0,0 +1,21 @@
1
+ # 网络层分阶段:v1 直连、v2 自建 Relay,先不做 P2P 打洞
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 设备可能在同一局域网,也可能在不同网络。远程软件(UU 远程等)的通用原理是"信令 + NAT 打洞 + Relay 兜底 + 端到端加密",但我们传输的是 RPC、消息与任务状态,不是低延迟视频流:中继兜底已经够用,自研 NAT 打洞成本高、调试 NAT 场景耗时。
8
+
9
+ ## Decision
10
+ 网络层分阶段实现:
11
+ - **v1(本期)**:局域网/Overlay 直连。手动地址 + UDP 广播发现;跨网由用户已有的 Tailscale/WireGuard 等提供可达性。设备身份 = Ed25519 静态密钥 + 邀请携带的 fleetKey;安全通道 = X25519 ECDH + HKDF + AES-256-GCM 帧;所有业务帧端到端加密。
12
+ - **v2(本期)**:自建轻量 Relay。控制通道用 fleetKey HMAC 注册与鉴权;数据面是 Relay 拼接的两条 TCP(只搬密文),两端在拼接字节流上跑同一套安全通道;**不实现 NAT 打洞**。
13
+ - **v3(后续可选)**:P2P 打洞优化,真需要低延迟时再做。
14
+
15
+ ## Considered Options
16
+ - 一步到位自建完整"信令 + 打洞 + 中继"——工作量最大,否决。
17
+ - 长期只依赖第三方 overlay——用户需要装 VPN,否决为长期方案(可作 v1 跨网兜底)。
18
+ - 集成 libp2p/WebRTC——依赖重、Node 端调试成本高,暂不采用。
19
+
20
+ ## Consequences
21
+ Relay 只能看到密文与元数据,必须"可信可用、不可读";没有 NAT 打洞时跨网流量走中继有延迟与带宽成本;协议从 v1 起就带版本号与能力协商,便于后续加打洞。
@@ -0,0 +1,21 @@
1
+ # 离线成员:直调/委派快速失败,房间日志承担持久补发
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 设备会离线。把工具执行或委派任务排队到目标恢复后再执行,会让过期指令在数小时后突然生效,语义与安全都不可控;而 Room 又需要让离线成员回归后能接上协作现场。
8
+
9
+ ## Decision
10
+ - **直调与委派立即失败**:目标设备离线时返回明确错误(`offline`,附最后在线时间),不排队;由本地 agent 决定重试、换设备、或改为发 Room 消息/任务。
11
+ - **Room 消息持久化**:Host 权威日志就是离线消息的归宿;离线成员不被唤醒。成员回归后按"自上次已读"补一份**摘要 + 被点名的消息**,**最多唤醒一次**,不逐条重放。
12
+ - **离线成员的 Task Block** 保留在 Room Board 上,Host 不代其执行;成员回归后按 Board 切片继续。
13
+ - 需要"离线也能跑"的场景,后续再引入显式 outbox(v1 不做)。
14
+
15
+ ## Considered Options
16
+ - 全部排队(直调短暂排队、委派持久 outbox、Room 逐条补发)——过期指令风险高、语义复杂,否决。
17
+ - 混合排队——多一套 outbox 与过期策略,v1 不必要,否决。
18
+ - 按房间/设备可配置——灵活性留到以后,v1 用统一语义,否决。
19
+
20
+ ## Consequences
21
+ 没有"离线执行保证";Room 可能积累未读(需要每成员已读游标与摘要生成);离线成员的 Block 可能长期停留,需要 Room UI 标注 stale/offline。
@@ -0,0 +1,24 @@
1
+ # 执行上下文由设备本地配置,远端只能请求
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ Execution Slot(直调)与 Participant Session(Room 参与者 agent)都执行在资源所有者设备上,需要 cwd、允许根、沙箱档位、可用工具与模型;这些资源属于该设备,远端或房间不应直接改写。
8
+
9
+ ## Decision
10
+ - 每台设备在自己的插件设置里配置:
11
+ - **Execution Slot**:工作目录、`allowedRoots`、沙箱档位(默认 read-only)、可用工具与 Tool Policy(默认只读免审、执行/写需审批、危险默认拒绝);
12
+ - **Participant Session**:Room 使用的 preset、房间工作目录策略(从允许根里选)、模型选择与沙箱。
13
+ - 远端与 Room 只能**请求能力**(如"需要执行代码"),最终由该设备的配置决定允许/拒绝/降级,远端不能覆盖。
14
+ - 默认值必须安全:`allowedRoots` 为空时直调读文件一律拒绝;执行类默认需本机审批;Participant 使用设备默认 preset 与模型。
15
+ - 配置变更只影响**新的**调用与新的 Participant 会话;运行中的通道/会话保留其创建时的配置快照;撤销允许根后新的调用即失败。
16
+ - Room Type 可以携带"期望能力"作为提示,但必须由每台设备自己的配置解析。
17
+
18
+ ## Considered Options
19
+ - 房间创建时由 Host 指定 cwd/preset——把资源所有权交给 A,否决。
20
+ - 每次调用显式传 cwd/preset——模型易乱传、边界难守,否决。
21
+ - 默认本地配置 + 房间协商覆盖——灵活性留到后续,v1 不做。
22
+
23
+ ## Consequences
24
+ 每台设备使用前需要一次配置(配对/设备页要引导);Room 的能力提示要逐设备解析;审计记录"由哪份配置授权"。
@@ -0,0 +1,22 @@
1
+ # B 侧审批:请求面板、超时失败、限次/限时/限房间授权
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ Tool Policy 的"需审批"档需要一个本机交互面:B 的资源由 B 授权;B 可能无人值守;一个多步任务如果每次弹窗会逼用户改成永久允许。
8
+
9
+ ## Decision
10
+ - 审批请求出现在 **B 的插件请求面板(待办收件箱)**:显示来源设备、agent/会话、能力/工具名、参数摘要、目标 cwd/允许根、风险类与超时倒计时。
11
+ - 默认 **60 秒**无响应即 fail-closed(可配置);B 离线/无人值守时不弹窗、直接失败。
12
+ - 批准的授权范围三选一:**仅本次** / **本任务内有效(TTL 默认 15 分钟)** / **本 Room 会话内有效**。
13
+ - **永久授权只允许在设备设置页按"设备 × 能力"显式开启**,不在逐次弹窗中提供,防止手滑。
14
+ - 所有请求与结果写入 B 的审计日志;A 侧只能看到 `approval_pending` / `denied` / `approval_timeout`,看不到 B 的审批界面。
15
+
16
+ ## Considered Options
17
+ - 转发到 A 的用户确认——把 B 的资源授权交给 A,违背资源所有者原则,否决。
18
+ - 纯配置自动判定、无交互——"需审批"档失去意义,否决。
19
+ - 每次强制弹窗、无 TTL——多步任务反复打断,用户最终会改成永久允许,否决。
20
+
21
+ ## Consequences
22
+ 需要请求收件箱 UI 与通知;TTL 授权要在到期/房间结束/任务结束时自动失效;A 侧 agent 要能区分"被拒/超时/等待中"并据此重试或换方案。
@@ -0,0 +1,26 @@
1
+ # Room 可见性:用户看完整对话,agent 只看自己的与点名给它的
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 用户需要一份完整、可回看的房间对话;但把房间全部历史注入每个 agent 的上下文,会浪费 token、分散注意力,也会让 agent 看到与自己无关的工作细节。点名机制(ADR-0006)已经提供了天然的可见性边界。
8
+
9
+ ## Decision
10
+ - **Room 日志是完整、append-only 的**:所有消息(用户与 agent、含 agent 之间的消息)、成员/策略变更、Board 审计指针都写入 Host 会话日志;任意成员设备上的 Room UI 都渲染**完整对话**,用户是单一身份。
11
+ - **每个 agent 的上下文只包含**:
12
+ 1. 它自己的会话历史(自己的动作、工具调用与结果、自己的回合);
13
+ 2. 点名发给它的消息(来自用户或其他 agent);
14
+ 3. 它自己发出的消息;
15
+ 4. 与它负责的 Task Block 相关的 Board 切片。
16
+ 未被点名给它的消息、其他 agent 的工作与私有上下文,**不会进入它的 prompt**。
17
+ - **Host 的 agent 同样遵守**:Host 会话日志里的 `room/*` 事件是 log-only;只有点名给它的消息才以带发送者归属的 user 消息注入它的对话。
18
+ - **唤醒简报** = 任务块 + 点名消息 + Board 切片 + 版本,不是房间历史。
19
+ - 存储采用双轨:消息/成员/策略/生命周期在会话日志,Room Board 任务在扩展后的 `task_ui` 域(权限 ADR-0008);两者通过 room 投影组合。
20
+
21
+ ## Considered Options
22
+ - 所有房间消息都注入所有 agent——token 与注意力浪费、无关信息干扰,否决。
23
+ - 用户只能看到与自己相关的消息——违背"完整对话"诉求,否决。
24
+
25
+ ## Consequences
26
+ 需要按成员维护"已读游标"与消息路由;Room UI 需要完整历史视图与成员过滤视图;agent 之间的消息对用户可见(可审计);agent 的私有工作轨迹留在各自设备的会话里,默认不并入房间记录(避免噪声与跨设备内部信息泄露)。
@@ -0,0 +1,23 @@
1
+ # Fleet 工具的采用机制
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 模型不会主动想到"可以用另一台设备"。`dsh-global-task-list` 的经验证明:只写工具描述不够,需要在模型组织工作时主动提醒、首次使用时给手册、写错时即时纠偏。同时提醒不能按"在线成员"门控——离线成员的存在也是客观状态。
8
+
9
+ ## Decision
10
+ 采用四层机制:
11
+ 1. **工具描述**:`fleet_list` / `fleet_tools` / `fleet_call` / `fleet_read` / `fleet_fetch` / `fleet_run` / `room_*` / `fleet_delegate` 的描述写清"何时用、边界、直调 vs Room vs 委派"的选择。
12
+ 2. **常驻 system prompt section**:当 Fleet 有至少一台成员(含离线)且工具在当前 scope 可调用时渲染一句;只列**稳定的成员名单**(名字/角色),在线状态不进 prompt(保护 KV cache,状态放 `fleet_list` 结果)。
13
+ 3. **首次使用手册**:第一次调用任一 fleet 工具时,把内置 skill `fleet` 的手册挂到**这次工具结果**里(同一 turn 生效、每 session 一次);完整手册不常驻。
14
+ 4. **编排钩子 + 即时纠偏**:`tools/post-execute` 在 `todo_write` / `subagent*` / `workflow` / `ralph` 后注入**一行**跨设备提示(每 session 一次,与手册投递互斥);`fleet_call` 被拒/离线/审批超时、Room 消息缺收件人、Board 未更新时,在工具结果里给出针对本次调用的纠偏。
15
+ 5. **可选**:`agent/pre-step` 意图检测(用户消息提到设备名/"另一台/远程"等关键词时注入设备清单),默认关闭,作为设置项。
16
+
17
+ ## Considered Options
18
+ - 只靠工具描述——模型常常想不到用,否决。
19
+ - 每轮强制检查清单——token 最贵、打断思考,否决。
20
+ - 与 task-list 手册同时注入大段文本——上下文膨胀,否决(因此钩子只发一行,完整手册走首次调用)。
21
+
22
+ ## Consequences
23
+ 需要 once-per-session 投递状态与两个投递通道互斥;常驻 section 只在有成员时渲染、成员列表变化才更新;在线状态查询有额外一次工具调用成本。
@@ -0,0 +1,22 @@
1
+ # 调用细节复用会话轨迹,不自建 trace UI
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 用户想看跨设备调用的"整个流程"。DSH 已经为每个会话提供轨迹视图(turn/tool 调用/结果),再自建一套 trace UI 会重复渲染、数据模型也会分叉。
8
+
9
+ ## Decision
10
+ - Room UI 只负责**房间层面的视图**:完整对话(用户视角)、成员/策略、Room Board。
11
+ - **执行细节复用 DSH 的会话轨迹**:
12
+ - Host 的 Room 会话轨迹:Host agent 的动作 + `room/*` 事件;
13
+ - 每个 Participant 设备的本地会话轨迹:该 agent 自己的 turn、工具调用与结果、自己的上下文。
14
+ - Room UI 提供"查看细节"入口:定位/打开**所属设备**上的会话轨迹(v1 不把远端轨迹镜像到房间);用户要看 B 的细节就去 B 的设备界面(或后续做只读镜像)。
15
+ - **远端轨迹只读镜像**(在一个界面看所有设备细节)作为后续增强,需要会话事件同步与脱敏,v1 不做。
16
+
17
+ ## Considered Options
18
+ - 在 Room UI 自建工具调用详情渲染——重复实现、与 DSH 轨迹不一致,否决。
19
+ - 把所有 Participant 的会话事件回放进 Host 日志——房间日志膨胀、跨设备信息泄露风险,否决。
20
+
21
+ ## Consequences
22
+ v1 查看另一台设备的细节需要切换设备;房间记录保持"消息 + Board + 审计指针"的干净模型;后续镜像需要定义哪些事件可跨设备、如何脱敏。
@@ -0,0 +1,22 @@
1
+ # 协议版本严格同版本,能力字段预留
2
+
3
+ ## Status
4
+ accepted
5
+
6
+ ## Context
7
+ 插件会升级,Room Board 与工具面也会演进;如果握手只校验协议版本、不校验插件版本,会出现"能连上但行为不一致"的隐藏 bug;而 v1 阶段设备数量少、升级由用户自己控制,做完整能力协商性价比低。
8
+
9
+ ## Decision
10
+ - 握手交换并校验 **`protocolVersion`、`pluginVersion`、`dshVersion`**,并预留 `capabilities[]` 字段(v1 只交换与记录,不做降级)。
11
+ - v1 采用**严格同版本**:`protocolVersion`、`pluginVersion` 必须一致;`dshVersion` 必须属于同一发布线(如 `0.2.2-rc.1`)。不匹配直接拒绝,返回可操作的错误("两端插件版本不一致,请把两台设备都升级到 x.y.z")。
12
+ - 需要某能力但对方未声明时,按明确的"不支持"错误失败,而不是静默降级。
13
+ - Relay 只校验 `fleetKey`,不参与版本判定;版本由设备在握手时互相校验。
14
+ - 未来升级到"版本区间/能力协商"(ADR 候选 B/C)时,复用预留的 `capabilities[]`,不改变线格式的骨架。
15
+
16
+ ## Considered Options
17
+ - 版本区间 + 共同最高版本——实现与测试成本翻倍,v1 不需要。
18
+ - 完整能力协商 + 降级——稳定期再做。
19
+ - 宽松兼容——隐藏不兼容风险最高,否决。
20
+
21
+ ## Consequences
22
+ 升级需要两台设备同时进行;错误信息必须包含双方版本与升级建议;`capabilities[]` 需要有明确的命名与文档,避免成为无意义的装饰。
@@ -0,0 +1,31 @@
1
+ # 审批收件箱(逻辑层,dev.7)
2
+
3
+ ## 实现
4
+
5
+ - `src/host/approval-inbox.js`:`ApprovalInbox`
6
+ - `request()`:排队、60s(可配)超时 fail-closed、事件 `request/approved/denied/expired/closed`;
7
+ - `list()`:待审列表(来源设备、能力、工具、参数摘要、剩余时间);
8
+ - `approve(id, {scope})`:`once` / `ttl`(TTL 由 Tool Policy 的 `approvalTtlMs` 控制);
9
+ - `deny(id, reason)`;`close()` 时全部失败关闭。
10
+ - `DirectCallHost` / `DelegationHost` 的 `ask` 档改为等待收件箱结果(不再一律拒绝),批准后按 scope 写入 Tool Policy 授权。
11
+ - 新工具:`fleet_approvals` / `fleet_approve` / `fleet_deny`;`fleet_simulate_request`(仅 `approvals.simulation: true`)用于本机无第二台设备时演练。
12
+ - 配置:`approvals: {ttlMs, maxPending, simulation}`。
13
+
14
+ ## 已验证
15
+
16
+ 单元测试(`node test/host.test.mjs`,10/10):
17
+ - 收件箱排队/批准/拒绝/超时/关闭/上限;
18
+ - DirectCallHost 在 `run=ask` 时阻塞等待收件箱批准后才执行;
19
+ - 工具 handler 的列表/批准/拒绝/模拟。
20
+
21
+ 当前 DSH 环境内模拟(dev.7,无需第二台设备):
22
+ 1. `fleet_simulate_request` 创建一条 `run/pwsh` 请求,`fleet_approvals` 显示 `58328ms left`;
23
+ 2. `fleet_approve(id, scope="ttl")` → `approved … (ttl)`,再次 `fleet_approvals` 为 `(no pending approvals)`;
24
+ 3. 再模拟一条 `delegate` 请求,`fleet_deny` → `denied …`;
25
+ 4. 对不存在的 id 调 `fleet_approve` → `Error: [unknown-request]`。
26
+
27
+ ## 未完成
28
+
29
+ - **Client UI 审批面板/通知**(需 Client bundle):当前只能通过工具或后续 UI 应答;Host 侧已发出 `request/approved/denied/expired` 事件,面板可直接消费;
30
+ - `room` 级授权 scope(需 Room 概念落地后再加);
31
+ - 审批结果持久化审计日志(后续与 Room 事件一起做)。
@@ -0,0 +1,49 @@
1
+ # 设计决策总览(ADR 索引)
2
+
3
+ 设备联邦的设计阶段已完成:24 条 ADR 覆盖入网、协作、执行、安全与网络。实现状态:网络层 v1/v2 已通过本机双端测试;Host 插件与业务面待实现。
4
+
5
+ ## 核心原则
6
+
7
+ 1. **成员制**:同账号 + 都装插件 + 显式入网才互通;账号只做成员校验与隔离。
8
+ 2. **资源所有者原则**:谁能碰文件/执行代码,由那台设备配置与审批决定(Tool Policy、执行上下文、审批收件箱)。
9
+ 3. **两条通道**:直调(无 Room、无对话上下文)与协作(Room,共享 Board、共享对话记录)。
10
+ 4. **按需唤醒**:只有被点名或被分配任务块的 agent 才启动;其余不跑模型。
11
+ 5. **动静分离**:稳定成员信息进 prompt,在线状态/任务细节进工具结果与 Board,保护 KV cache。
12
+ 6. **严格同版本**:v1 宁可拒绝连接,也不接受"能连但行为不一致"。
13
+
14
+ ## ADR 索引
15
+
16
+ | # | 决策 | 一句话 |
17
+ |---|---|---|
18
+ | 0001 | 显式入网而非账号自动互联 | 邀请码/Fleet 密钥;账号只做校验 |
19
+ | 0002 | 共享 Room 作协调单位 | 替代两两配对与星型转发 |
20
+ | 0003 | 直调与 Room 两条通道 | 工具调用不塞进房间;有状态工具用执行槽 |
21
+ | 0004 | 直调授权由目标设备决定 | 只读免审、执行需审批、危险默认拒绝 |
22
+ | 0005 | 会话可就地升级为 Room Host | roomId = Host 会话 id;fork 不继承房间 |
23
+ | 0006 | 消息必须点名、每个成员设备都能发言 | 只有被点名才唤醒 |
24
+ | 0007 | 用户发言与设备解耦 | 用户是单一身份;设备只是审计来源 |
25
+ | 0008 | 复用并扩展 dsh-global-task-list 作 Room Board | 加 roomId/owner/版本/CAS + 只读镜像 |
26
+ | 0009 | Room Policy 在创建时配置 | 房间类型/权限来自插件预设,可覆盖 |
27
+ | 0010 | Room Policy v1 字段 + 自定义 Room Type | invite/join/maxMembers/boardWrite/remove |
28
+ | 0011 | Room Board 与房间同生命周期,钩子驱动更新 | 开始/完成时提醒;串行交接点名下一块 |
29
+ | 0012 | 惰性唤醒与定向发言 | 未点名不启动;可对不同成员说不同的话 |
30
+ | 0013 | 直调工具设备无关(被 0014 修订) | device 参数、执行槽、稳定错误码 |
31
+ | 0014 | `fleet_call` 统一入口 + 少量 typed 快捷工具 | list/tools/call + read/fetch/run |
32
+ | 0015 | Room + 本地团队 + 跨设备委派 | 三层协作模型;委派一次性、不进房间 |
33
+ | 0016 | 委派升级为 Room 复用原会话 | 显式 upgrade,B 的委派会话绑定为 Participant |
34
+ | 0017 | 网络层分阶段:v1 直连、v2 Relay | 先不做 NAT 打洞;Relay 只见密文 |
35
+ | 0018 | 离线成员快速失败 + 房间日志持久补发 | 直调/委派不排队;回归摘要唤醒一次 |
36
+ | 0019 | 执行上下文由设备本地配置 | 远端只能请求能力,不能改 cwd/preset |
37
+ | 0020 | B 侧审批收件箱 + 限次/限时/限房间授权 | 60s 超时失败;永久授权只在设置页 |
38
+ | 0021 | 用户看完整对话,agent 只看自己的与点名消息 | 存储双轨:日志 + task_ui 域 |
39
+ | 0022 | 工具采用机制四层 | 描述 + 常驻一句 + 首次手册 + 编排钩子/纠偏 |
40
+ | 0023 | 调用细节复用会话轨迹 | Room UI 不自建 trace;远端轨迹 v1 不镜像 |
41
+ | 0024 | 协议版本严格同版本,能力字段预留 | 不匹配直接拒绝 |
42
+
43
+ ## 待实现(按依赖顺序)
44
+
45
+ 1. **Host 插件接入**:`$DSH_HOME` 身份/邀请/Fleet 配置持久化;`FleetNode` 挂 Cordis;账号指纹注入;握手补 `pluginVersion`/`dshVersion`/`capabilities`。
46
+ 2. **直调 MVP**:`fleet_list` / `fleet_tools` / `fleet_call` + `fleet_read` / `fleet_fetch` / `fleet_run`;B 侧 Tool Policy + Execution Slot + 审批收件箱;A 侧工具结果与错误码。
47
+ 3. **Room**:会话升级、`room_*` 工具、`room/*` 事件与投影、Room Board(扩展 task-list)、点名/惰性唤醒、Board 钩子。
48
+ 4. **委派**:`fleet_delegate`、一次性子会话、委派升级为 Room。
49
+ 5. **UI**:设备页/配对/审批收件箱/房间视图/Room 设置;打成可安装 bundle。
@@ -0,0 +1,67 @@
1
+ # 开发版发布记录
2
+
3
+ - 包名:`dsh-device-fleet`
4
+ - 版本:`0.1.0-dev.3`
5
+ - dist-tag:`dev`(同时也可用精确版本安装)
6
+ - registry:<https://registry.npmjs.org/dsh-device-fleet>
7
+ - tarball:<https://registry.npmjs.org/dsh-device-fleet/-/dsh-device-fleet-0.1.0-dev.3.tgz>
8
+ - 本地离线包:`dsh-device-fleet-0.1.0-dev.3.tgz`(仓库根目录,可拷贝安装)
9
+ - 发布时间:2026-11-09(Asia/Shanghai)
10
+ - 内容:网络层 v1/v2 + Host 插件 + 直调 MVP(`fleet_invite/join/list/tools/call/read/fetch/run`);Room/Board/委派/审批 UI 未包含。
11
+
12
+ ## 安装
13
+
14
+ ```sh
15
+ dsh plugin --profile web add dsh-device-fleet@dev
16
+ # 桌面 app:完全退出后
17
+ dsh plugin --profile desktop add dsh-device-fleet@dev
18
+ ```
19
+
20
+ 发布时 npm 对新包做了短暂的处理/占位(`0.0.0-stage`),约几分钟后真实版本生效;后续版本号递增、tag 复用 `dev`。
21
+
22
+ ## 已知限制
23
+
24
+ - 严格同版本:两台设备必须安装同一 `0.1.0-dev.3`,DSH 版本也要同一发布线;
25
+ - `fleet_run` 的 `ask` 审批目前 fail-closed(审批收件箱未实现);
26
+ - `fleet_fetch` 仅返回文本;
27
+ - 首次加载会在 `$DSH_HOME/device-fleet/` 自动创建身份与独立 Fleet;加入已有 Fleet 需要先 `fleet_join` 再重启;
28
+ - 默认 `direct.host=0.0.0.0` + UDP 组播发现;Windows 防火墙可能弹窗,需允许。
29
+
30
+ ## 安装激活记录(本机 desktop profile,2026-11-09)
31
+
32
+ - 第一次 install_bundle 被拒:`package.json` 带 UTF-8 BOM → 去掉 BOM 后通过;
33
+ - 第一次 activate 失败:`@deepseek-ai/schemastery` 只有默认导出(`import Schema from ...`),改为默认导入;
34
+ - 第二次 activate 失败:Cordis 直接访问未 inject 的服务会抛错 → 可选服务统一走 `ctx.get(name)`;
35
+ - 最终 `set_plugin include:device-fleet enabled=true` → `application: applied`,8 个 `fleet_*` 工具出现在模型工具表,`fleet_list` 返回本机 device id,`taskui_probe` 仍为 v0.4.2 / tasks=247(与 task-list 无冲突)。
36
+ - 已发布 `0.1.0-dev.3`(包含上述激活修复);`0.1.0-dev.1` 会激活失败,不要使用。
37
+ ## 0.1.0-dev.3(本次)
38
+
39
+ - 邀请里新增 `endpoints`(创建者的局域网/热点 IPv4 + direct 端口),加入方重启后自动向这些地址回连,绕开组播发现失败;
40
+ - 新增 `fleet_status`(deviceId/直连端口/发现/连接/roster/hints)与 `fleet_connect(host, port)`(手动直连,成功后会从握手学到对端 deviceId);
41
+ - `fleet_list` 仍是本地视图;配对成功后双方 roster 会自动固定对端公钥。
42
+ ## 0.1.0-dev.9(稳定化)
43
+
44
+ - 直连端口可固定(profile `direct.port`),插件重载不再换端口;
45
+ - 连接断开后自动重试已知地址(不再只在启动时试一次);
46
+ - `fleet_connect` 手动地址会持久化到 `peer-hints.json`,重启后继续回连;
47
+ - 新增 `fleet_delegate`(dev.5):目标设备用 `SubagentProvider` + `delivery:'caller'` 跑 agent 并返回最终结果。
48
+ ## 0.1.0-dev.9(审批收件箱,逻辑层)
49
+
50
+ - 新增 `ApprovalInbox`:ask 档请求排队、超时 fail-closed、approve(once/ttl)/deny、关闭时全部失败关闭;
51
+ - 直调与委派的 ask 档改为等待本机收件箱结果(不再一律拒绝);
52
+ - 新工具:`fleet_approvals` / `fleet_approve` / `fleet_deny`;`fleet_simulate_request`(仅 `approvals.simulation: true`)用于本机无第二台设备时演练流程;
53
+ - 审批面板(Client UI)与通知尚未实现,当前通过工具/后续 UI 应答。
54
+ ## 0.1.0-dev.9(Room 逻辑层,本机模拟)
55
+
56
+ - `RoomService`:当前会话升级为 Room Host;本地模拟参与者(真实 DSH session/agent);
57
+ - 寻址消息:`room_send` 只唤醒被点名成员,Host 会话写权威 `room/message` 事件;
58
+ - 可见性:`room_messages` 提供完整 transcript;未点名成员不运行;
59
+ - Room Board:`room_task_add/update/list`,`dependsOn` 串行交接(前置完成时唤醒下一个 owner),无依赖任务并行不受影响;
60
+ - 工具:`room_create / room_add_local / room_remove_member / room_send / room_messages / room_status / room_task_* / room_close`;
61
+ - 远程参与者传输与 Client UI 未做(下一步)。
62
+ ## 0.1.0-dev.9(审批面板 UI,第一版)
63
+
64
+ - Host 新增本地 HTTP 数据面:GET `/device-fleet/approvals`、POST `/device-fleet/approvals/decide`(仅本机 web 载体,决策仍走 ApprovalInbox);
65
+ - Client half:`client.js` 闭包工厂,注册 `shell.overlay` 浮动「Fleet 审批」按钮 + 面板,轮询待审批列表,支持允许一次 / 允许 15 分钟 / 拒绝;
66
+ - package.json 增加 `dsh.client` 与 `./client` 导出;`files` 增加 client.js;
67
+ - Client 视觉验证需要刷新页面;当前无浏览器控制,仅验证了 bundle 语法与 Host 路由注册。
@@ -0,0 +1,54 @@
1
+ # dsh-global-task-list 可复用性评估(v0.4.2)
2
+
3
+ 源码位置:`C:\Users\PS\.dsh\plugins\dsh-global-task-list`(profile 以 `link:` 引用,desktop profile 已启用)。
4
+ 结论:**数据模型与面板 UI 大部分可复用;作为"跨设备共享任务板"不能直接复用**,缺共享数据源、room/owner 维度、程序化读写 API 与远端镜像模式。
5
+
6
+ ## 事实
7
+
8
+ ### 数据模型(`src/index.ts`)
9
+
10
+ `storageDomain` 域 `task_ui` v1,表 `tasks`,记录字段:
11
+
12
+ `title, status(pending|running|done|blocked|failed), description, nextStep, steps[{text,state:done|current|next|todo}], parentId, dependsOn[], surface(生成式 UI 文档), progress{text,percent?}, jobId, createdAt, updatedAt` + 行主键 `id`。
13
+
14
+ - 任务**刻意 session-independent**:README「Tasks are session-independent by design」,记录里没有 session/owner 字段,跨会话交接是设计目标。
15
+ - 存储是 `storageDomain`(本机 `$DSH_HOME` 持久化),跨会话、跨重启;**不跨设备**。
16
+
17
+ ### Host 对外面
18
+
19
+ - 模型工具(6 个):`task_add / task_list / task_get / task_update / task_delete / taskui_probe`。
20
+ - HTTP 路由(浏览器面板用):
21
+ - `GET /task-ui/tasks` 快照(附派生 `jobStale`)
22
+ - `POST /task-ui/status` 只改 status
23
+ - `POST /task-ui/delete` 删除
24
+ - `POST /task-ui/ask` 生成式 UI 的"追问",给某个 master agent 排队一条 user 消息
25
+ - `GET /task-ui/events` SSE:无 payload,只是"变了,重新拉"通知
26
+ - 无 `ctx.provide` 的 Host service、无 Typert `@Remote` 命名空间、无导出给其他插件用的编程 API(package exports 只有 `.` 与 `./client`)。
27
+ - HTTP 路由未走 `connection.admit` 认证(面板同源使用);不适合直接当作跨设备 API。
28
+
29
+ ### Client 面板
30
+
31
+ - `conversation.input.dock` slot 的常驻面板:折叠分组(running / other open / done)、步骤流、拖动改宽、SSE 刷新、状态/删除/拆分操作、zh/en 本地化。
32
+ - 数据源写死为**本机** `/task-ui/tasks` + `/task-ui/events`;没有"远端只读/镜像"数据源接口。
33
+
34
+ ### 与 Room 任务板的对齐度
35
+
36
+ | Room 板需要 | task_ui 现状 | 复用判断 |
37
+ |---|---|---|
38
+ | goal / tasks / 负责人 / 状态 / 依赖 | 有 title/status/parentId/dependsOn/steps/progress,无 owner/member 字段 | 字段 80% 可映射;需加 room 作用域与 owner |
39
+ | 产物指针(device + path) | 无;`surface` 可承载任意 JSON | 可放 surface 或加字段 |
40
+ | Host 权威、参与设备镜像 | 严格本机存储 | 需新增同步层 |
41
+ | 任何设备都能看/操作同一份板 | 面板只读本机路由 | 需新增数据源/镜像模式 |
42
+ | agent 低成本读写 | 已有 task_* 工具与 prompt 引导 | 可直接复用(加 room 参数) |
43
+ | 并发更新防覆盖 | 单进程 domain,无跨设备 CAS | 需在同步层做版本号/CAS |
44
+
45
+ ## 三条整合路径
46
+
47
+ **A. 扩展本插件(推荐,前提是代码可改)**
48
+ 加 `roomId`(或 scope)与 `ownerMember`、版本号;加 Host 侧编程 API(service 或 Remote)供 Fleet 插件读写;Room Host 权威、参与设备镜像到本地 `task_ui`(镜像只读,写回 Host);面板按 room 分组并标记只读镜像。保留现有工具名(`task_*` 增加可选 `roomId`)或新增 `room_task_*`。工作量:中。
49
+
50
+ **B. Fork UI/schema 进 Fleet 插件**
51
+ 把 TASK_SCHEMA、面板组件、surface 渲染器复制进新插件(MIT),独立演进。避免跨插件耦合与版本兼容,但要维护 ~48KB 面板 + CSS 的副本。工作量:中大。
52
+
53
+ **C. 仅存引用**
54
+ Room 板只存 `{deviceId, taskId}` 指针,各设备用本地 task_ui 记录,Host 聚合指针状态。插件零改动;但没有统一视图、状态要轮询、agent 两头维护,不推荐作为最终形态(可作 PoC 过渡)。