dsh-device-fleet 0.0.0-stage → 0.1.0-dev.2
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/CONTEXT.md +123 -0
- package/LICENSE +21 -0
- package/README.md +133 -2
- package/cordis.patch.yml +26 -0
- package/docs/adr/0001-fleet-enrollment-over-account-auto-discovery.md +17 -0
- package/docs/adr/0002-shared-room-as-coordination-unit.md +17 -0
- package/docs/adr/0003-direct-call-and-room-as-two-channels.md +22 -0
- package/docs/adr/0004-direct-call-policy-owned-by-target-device.md +23 -0
- package/docs/adr/0005-upgrade-session-to-room-host.md +22 -0
- package/docs/adr/0006-addressed-messages-and-any-device-speaks.md +16 -0
- package/docs/adr/0007-user-speech-decoupled-from-device.md +21 -0
- package/docs/adr/0008-extend-global-task-list-as-room-board.md +21 -0
- package/docs/adr/0009-room-policy-configured-at-creation.md +21 -0
- package/docs/adr/0010-room-policy-v1-fields-and-custom-room-types.md +24 -0
- package/docs/adr/0011-room-board-lifecycle-and-hooks.md +27 -0
- package/docs/adr/0012-lazy-wake-and-directed-speech.md +22 -0
- package/docs/adr/0013-direct-call-as-device-agnostic-functions.md +26 -0
- package/docs/adr/0014-fleet-call-unified-entry-with-typed-shortcuts.md +22 -0
- package/docs/adr/0015-room-plus-local-teams-and-delegation.md +22 -0
- package/docs/adr/0016-delegation-upgrade-reuses-session.md +20 -0
- package/docs/adr/0017-network-phases-direct-and-relay.md +21 -0
- package/docs/adr/0018-offline-fail-fast-and-durable-room-log.md +21 -0
- package/docs/adr/0019-execution-context-configured-locally.md +24 -0
- package/docs/adr/0020-approval-inbox-with-scoped-grants.md +22 -0
- package/docs/adr/0021-room-visibility-user-full-agents-scoped.md +26 -0
- package/docs/adr/0022-tool-adoption-mechanisms.md +23 -0
- package/docs/adr/0023-reuse-session-trajectory-for-call-details.md +22 -0
- package/docs/adr/0024-strict-version-match-with-reserved-capabilities.md +22 -0
- package/docs/notes/design-decisions-summary.md +49 -0
- package/docs/notes/dev-release.md +28 -0
- package/docs/notes/dsh-global-task-list-evaluation.md +54 -0
- package/docs/notes/network-v1-v2-implementation.md +71 -0
- package/docs/notes/step1-host-plugin-and-direct-call.md +57 -0
- package/package.json +42 -3
- package/src/host/direct-call.js +190 -0
- package/src/host/execution-slot.js +82 -0
- package/src/host/index.js +6 -0
- package/src/host/store.js +128 -0
- package/src/host/tool-policy.js +150 -0
- package/src/host/tools.js +215 -0
- package/src/index.js +3 -0
- package/src/net/direct.js +69 -0
- package/src/net/discovery.js +105 -0
- package/src/net/fleet-node.js +414 -0
- package/src/net/identity.js +156 -0
- package/src/net/index.js +9 -0
- package/src/net/protocol.js +73 -0
- package/src/net/relay-client.js +258 -0
- package/src/net/relay-server.js +366 -0
- package/src/net/secure-channel.js +538 -0
- package/src/plugin/index.js +285 -0
|
@@ -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,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,28 @@
|
|
|
1
|
+
# 开发版发布记录
|
|
2
|
+
|
|
3
|
+
- 包名:`dsh-device-fleet`
|
|
4
|
+
- 版本:`0.1.0-dev.1`
|
|
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.1.tgz>
|
|
8
|
+
- 本地离线包:`dsh-device-fleet-0.1.0-dev.1.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.1`,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 防火墙可能弹窗,需允许。
|
|
@@ -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 过渡)。
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# 网络层 v1/v2 实现说明
|
|
2
|
+
|
|
3
|
+
状态:**已实现并通过本机双端测试**(2026-11-09)。对应 ADR:[0017 网络层分阶段](../adr/0017-network-phases-direct-and-relay.md)。
|
|
4
|
+
|
|
5
|
+
## 文件
|
|
6
|
+
|
|
7
|
+
| 文件 | 作用 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `src/net/identity.js` | 设备身份(Ed25519 签名 + X25519 协商)、`fleetKey` 邀请编解码、成员证明 HMAC、账号指纹、Relay 注册 token |
|
|
10
|
+
| `src/net/secure-channel.js` | 端到端安全通道:HELLO/HELLO_ACK 握手、签名与成员证明校验、X25519+HKDF 派生、AES-256-GCM 帧、计数防重放 |
|
|
11
|
+
| `src/net/protocol.js` | 版本号、帧类型(rpc.req/res/err、event、ping/pong、ready)、稳定 JSON、错误序列化 |
|
|
12
|
+
| `src/net/direct.js` | v1 直连:TCP 监听器 + 出站拨号(带超时) |
|
|
13
|
+
| `src/net/discovery.js` | v1 局域网发现:UDP 组播公告(fleetHash + deviceId + 直连端口) |
|
|
14
|
+
| `src/net/relay-server.js` | v2 Relay:控制面(注册/连接/接受/拒绝)+ 数据面(两条 TCP 拼接,只搬密文) |
|
|
15
|
+
| `src/net/relay-client.js` | v2 客户端:控制连接、自动重连、请求/接受连接、数据 socket |
|
|
16
|
+
| `src/net/fleet-node.js` | 设备门面:roster/TOFU、直连/发现/Relay 选择、RPC、事件、关闭 |
|
|
17
|
+
| `test/net.test.mjs` | 7 个测试(见下) |
|
|
18
|
+
|
|
19
|
+
## 线格式
|
|
20
|
+
|
|
21
|
+
### 安全通道握手(换行分隔 JSON)
|
|
22
|
+
|
|
23
|
+
1. 发起方 → 响应方 `hello`:`{t:'hello', v:1, fleetId, deviceId, name, edPublic, xPublic, ephX, nonce, ts, accountFingerprint, proof, sig}`
|
|
24
|
+
- `proof = HMAC(fleetKey, "member|fleetId|deviceId|edPublic|xPublic|accountFingerprint")`
|
|
25
|
+
- `sig = Ed25519(稳定 JSON(除 sig 外的全部字段))`
|
|
26
|
+
2. 响应方校验 fleet/时间戳/签名/成员证明/账号指纹/已固定公钥,回复 `hello.ack`(同构)。
|
|
27
|
+
3. 双方以 `X25519(ephX_i, ephX_r)` 为 IKM、`sha256(稳定 JSON(hello,ack))` 为 salt,HKDF 派生:
|
|
28
|
+
- 发起→响应 32B key + 4B nonce 前缀;响应→发起 32B key + 4B nonce 前缀。
|
|
29
|
+
4. 双方各发一条加密 `ready` 帧;收到对方 `ready` 后通道可用(`ready` 事件)。
|
|
30
|
+
|
|
31
|
+
### 加密帧
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
| u32be length | AES-256-GCM ciphertext | 16B tag |
|
|
35
|
+
nonce = 4B 方向前缀 || u64be 计数器;AAD = "dsh-device-fleet/frame/v1"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
计数器严格递增、按 TCP 顺序校验,重放/乱序/篡改都会使 `openFrame` 失败并断链。
|
|
39
|
+
|
|
40
|
+
## Relay 协议(v2)
|
|
41
|
+
|
|
42
|
+
控制面(TCP,换行分隔 JSON):
|
|
43
|
+
- `register {fleetId, deviceId, ts, token}` → `register.ok`;`token = HMAC(fleetKey, "relay-register|fleetId|deviceId|ts")`;Relay 用配置的 fleetKey 校验,时间戳 ±120s。
|
|
44
|
+
- `connect {reqId, targetDeviceId}` → 请求方收 `connect.pending`,目标方收 `incoming {reqId, fromDeviceId}`。
|
|
45
|
+
- 目标方 `accept {reqId}` → 双方收 `connect.ready {reqId, dataPort, token}`;`reject` → 请求方收 `connect.fail`。
|
|
46
|
+
- 心跳 `ping`/`pong`。
|
|
47
|
+
|
|
48
|
+
数据面(第二个 TCP 端口):双方分别连接并发送一行头
|
|
49
|
+
`{fleetId, deviceId, reqId, token}\n`,Relay 校验后把两条 socket 的原始字节互相 pipe。**Relay 不解析、不终止加密**,与 secure-channel 的密文完全兼容。
|
|
50
|
+
|
|
51
|
+
## 已验证(`node test/net.test.mjs`,7/7 通过)
|
|
52
|
+
|
|
53
|
+
1. 邀请编解码携带 fleet/账号指纹/Relay 地址;
|
|
54
|
+
2. v1 直连:认证握手 + RPC echo + 双向 roster TOFU 固定;
|
|
55
|
+
3. 不同 fleet 或不同账号指纹的握手被拒;
|
|
56
|
+
4. roster 中固定公钥与对端不一致时被拒;
|
|
57
|
+
5. v2 Relay:两设备经中继完成加密 RPC,Relay 记录到 splice;
|
|
58
|
+
6. Relay 拒绝不知道 fleetKey 的客户端;
|
|
59
|
+
7. LAN 组播发现发现对端并通过发现地址直连(组播不可用时测试自动跳过)。
|
|
60
|
+
|
|
61
|
+
运行:`node test/net.test.mjs`(受限沙箱里 `node --test test/` 需要 spawn 子进程,可能被拒;直接跑测试文件即可)。
|
|
62
|
+
|
|
63
|
+
## 当前限制 / 后续
|
|
64
|
+
|
|
65
|
+
- **无 NAT 打洞**:跨网一律走 Relay(v3 再做打洞)。
|
|
66
|
+
- **Relay 控制面为明文 TCP**:部署时应在 TLS/反代之后,或后续加 TLS。
|
|
67
|
+
- **TOFU 无密钥轮换/吊销**:Roster 只固定公钥,设备重装会变新身份;后续加签名 roster 与吊销。
|
|
68
|
+
- **无二进制流式分块**:RPC 参数/结果为 JSON(大文件需后续加 chunk 帧)。
|
|
69
|
+
- **无重放窗口**:严格顺序计数已防重放;断线重连即新会话,不做跨会话恢复。
|
|
70
|
+
- **无速率限制/审计**:Relay 与节点都未做限流;上线前补。
|
|
71
|
+
- **账号指纹需上层注入**:网络层只接收 `accountFingerprint` 字符串,由 Host 插件从 `deepseekAccount.getDeviceIdentity()` 派生。
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Step 1:Host 插件接入 + 直调 MVP(实现说明)
|
|
2
|
+
|
|
3
|
+
状态:**代码完成、单元测试通过(net 8/8 + host 6/6),尚未在真实 DSH 进程内安装联调**。
|
|
4
|
+
|
|
5
|
+
## 本轮落地
|
|
6
|
+
|
|
7
|
+
| 文件 | 内容 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `src/plugin/index.js` | Cordis Host 插件入口:`name`/`inject`/`Config`/`apply`;加载持久状态、启动 FleetNode、注册 6 个 `fleet_*` 工具、常驻提示 section、首次使用手册、编排钩子一行提示、账号指纹绑定、退出清理 |
|
|
10
|
+
| `src/host/store.js` | `$DSH_HOME/device-fleet/` 下的身份/Fleet/roster/config/enrollment 持久化(原子写);邀请创建与接受;账号指纹比对 |
|
|
11
|
+
| `src/host/tool-policy.js` | 设备本地 Tool Policy:allowedRoots、read/list/grep/fetch/run/tool 六种能力的 auto/ask/deny、原始工具 allowlist、一次性/TTL 授权 |
|
|
12
|
+
| `src/host/execution-slot.js` | Execution Slot:懒创建隐藏 DSH 会话(`sessionController.create` → `resolveAgent`),用 `ctx.tools.execute` 在该 agent 上下文里执行工具,不跑模型 |
|
|
13
|
+
| `src/host/direct-call.js` | `DirectCallHost`(B 侧:`fleet.ping/info/tools/call`,策略→审批→执行)、`DirectCallClient`(A 侧 RPC 封装与结果渲染) |
|
|
14
|
+
| `src/host/tools.js` | 6 个工具定义:`fleet_list` / `fleet_tools` / `fleet_call` + `fleet_read` / `fleet_fetch` / `fleet_run`(typed 快捷工具走同一 `fleet.call` 路径) |
|
|
15
|
+
| `cordis.patch.yml` | 插件挂载行与安全默认配置 |
|
|
16
|
+
| 网络层 | 握手新增 `pluginVersion` / `dshVersion` / `capabilities` 严格校验(ADR-0024);新增版本不匹配测试 |
|
|
17
|
+
|
|
18
|
+
## 配置示例(profile patch / 插件设置页)
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
- id: device-fleet
|
|
22
|
+
config:
|
|
23
|
+
deviceName: desktop
|
|
24
|
+
discovery: true
|
|
25
|
+
relay: { host: relay.local, port: 47800, dataPort: 47801 }
|
|
26
|
+
execution:
|
|
27
|
+
cwd: D:/work # Execution Slot 的工作目录
|
|
28
|
+
agentPreset: standard # 必须是本机存在的 preset
|
|
29
|
+
shellTool: pwsh
|
|
30
|
+
policy:
|
|
31
|
+
allowedRoots: [D:/work] # 直调只能访问这些根
|
|
32
|
+
capabilities: { read: auto, list: auto, grep: auto, fetch: auto, run: ask, tool: deny }
|
|
33
|
+
allowedTools: []
|
|
34
|
+
approvalTtlMs: 900000
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 已测试
|
|
38
|
+
|
|
39
|
+
- 网络层 8 个测试:直连 RPC、组播发现、Relay 加密中继、跨 fleet/跨账号/固定公钥/版本不匹配拒绝、Relay 鉴权失败;
|
|
40
|
+
- Host 层 6 个测试:状态持久化与邀请入网、Tool Policy(根目录/能力档位/allowlist/TTL)、Execution Slot 懒创建与结果归一、DirectCallHost 的策略/审批/执行、工具 handler 的列表与快捷路由、客户端渲染;
|
|
41
|
+
- 全部 `src/**/*.js` 通过 `node --check`。
|
|
42
|
+
|
|
43
|
+
## 未验证 / 已知缺口
|
|
44
|
+
|
|
45
|
+
1. **未在真实 DSH 进程里加载**:`@deepseek-ai/dsh-tools`/`schemastery`/`dsh-llm` 的 peer 解析、Config schema 校验、`ctx.*` API 细节需要在安装后确认(sandbox 里无法 import profile 依赖)。
|
|
46
|
+
2. **审批收件箱 UI 未实现**:`ask` 档当前 fail-closed(`autoApproveAsk: true` 仅供开发);收件箱、TTL 授权、通知属于下一步。
|
|
47
|
+
3. **`fleet_run` 参数尚简单**:目前只传 `command`;cwd/超时/环境变量待补。
|
|
48
|
+
4. **`fleet_fetch` 只返回文本**(≤ 限制内),大文件/二进制与写入 A 侧工作区待做。
|
|
49
|
+
5. **Room / Board / 委派 / UI 未开始**;插件尚未安装到 profile(需要一次 danger-full-access 审批)。
|
|
50
|
+
6. 账号服务不可用时 `accountFingerprint = null`,握手不做账号比对;需要在真实登录态下验证。
|
|
51
|
+
|
|
52
|
+
## 下一步
|
|
53
|
+
|
|
54
|
+
1. 安装 bundle 到 `desktop` profile(`plugin_manager install_bundle`,需批准);
|
|
55
|
+
2. 在真实 DSH 里验证:插件加载、6 个工具出现在模型工具表、`fleet_list` 正常;
|
|
56
|
+
3. 用第二台设备(或第二个 DSH_HOME/实例)完成一次"fleet_read 读对端文件 + fleet_run 跑命令(带 B 侧审批)"的端到端联调;
|
|
57
|
+
4. 再进入 Room / Board / 委派与审批 UI。
|
package/package.json
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-device-fleet",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0-dev.2",
|
|
4
|
+
"description": "DeepSeek Harness device fleet: enroll devices, direct-call remote tools, shared Rooms with lazy-woken agents, and delegated subagents across devices.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/plugin/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/plugin/index.js",
|
|
9
|
+
"./net": "./src/net/index.js",
|
|
10
|
+
"./host": "./src/host/index.js",
|
|
11
|
+
"./package.json": "./package.json"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=22"
|
|
15
|
+
},
|
|
16
|
+
"dsh": {
|
|
17
|
+
"bundle": {
|
|
18
|
+
"patch": "./cordis.patch.yml"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@deepseek-ai/cordis": "~4.1.0",
|
|
23
|
+
"@deepseek-ai/dsh-tools": "^0.2.2-rc.1",
|
|
24
|
+
"@deepseek-ai/dsh-llm": "^0.2.2-rc.1",
|
|
25
|
+
"@deepseek-ai/schemastery": "~3.19.0"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"test": "node test/net.test.mjs && node test/host.test.mjs",
|
|
29
|
+
"test:net": "node test/net.test.mjs",
|
|
30
|
+
"test:host": "node test/host.test.mjs"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"src",
|
|
34
|
+
"cordis.patch.yml",
|
|
35
|
+
"README.md",
|
|
36
|
+
"CONTEXT.md",
|
|
37
|
+
"docs",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public",
|
|
42
|
+
"tag": "dev"
|
|
43
|
+
},
|
|
44
|
+
"license": "MIT"
|
|
6
45
|
}
|