cockpit-daemon
v0.0.3
Published
云展 Cockpit — 被控端 daemon:装在用户机器上,包装真实 claude code CLI,按 wire 协议端到端加密同步到 relay,并接收 console 下发的 RPC。
Maintainers
Readme
@cockpit/daemon — 云展 Cockpit 被控端 daemon
装在用户机器上跑,包装真实 claude CLI(stream-json 模式),按 @cockpit/wire 协议端到端加密同步到中继服务器,并接收 console 下发的 RPC。
运行
# 开发(从源码跑)
pnpm --filter cockpit-daemon dev --server http://localhost:3005 --agent claude
# 安装后(npm 发布后)—— 生产:relay 与 console 不同域名,必须传 --console
npx cockpit-daemon --server https://relay.mvp.restry.cn --console https://cockpit.mvp.restry.cn --agent claude启动后打印配对 PIN 与链接 → 在 console 输入 PIN 批准 → 即可远程控制本机 claude。
--console决定配对链接(/pair路由在 console 那侧)。本地开发不传时按 relay 地址推导(:3005→:5173);生产 relay/console 分域名,必须显式传--console, 否则打印的配对链接会错误地指向 relay。也可用环境变量$COCKPIT_CONSOLE。
发布到 npm 的步骤、版本管理、
npx演示见PUBLISH.md。
结构
| 文件 | 职责 |
|---|---|
| src/handshake.ts | 配对(NaCl Box)+ Ed25519 认证 + 会话 DEK 派生(deriveKey(masterSecret, sessionId),两端确定性一致) |
| src/agent.ts | 抽象 Agent 基类 + 事件/权限类型(接 codex/cursor 只需新增子类) |
| src/agents/claude.ts | ClaudeAgent:spawn claude -p --input-format stream-json --output-format stream-json,解析 stream-json → SessionEvent,control 协议处理工具权限 |
| src/session.ts | 单会话:AES-256-GCM 加密事件上行 relay,路由 console RPC 到 agent |
| src/daemon.ts | 编排器 RelayDaemon:配对→连接→注册→路由 rpc-request;AGENT_REGISTRY |
| src/cli.ts | cockpit-daemon CLI 入口 |
打包:
tsup(tsup.config.ts)把@cockpit/wire+@cockpit/cryptoinline 进dist/cli.js,socket.io-client/tweetnacl/zod/cuid2保留为 runtime 依赖。bin/cockpit-daemon.mjs指向dist/cli.js。
协议映射(claude stream-json → wire SessionEvent)
| claude 输出 | SessionEvent |
|---|---|
| assistant.content[].text | {t:"text"} |
| assistant.content[].thinking | {t:"text", thinking:true} |
| assistant.content[].tool_use | {t:"tool-call-start"} |
| user.content[].tool_result | {t:"tool-call-end"} |
| control_request(can_use_tool) | {t:"permission-request"} → console 批准/拒绝 → control_response{behavior} |
| result | {t:"turn-end", usage, model} |
console RPC → claude:approve/deny-permission → control_response;answer-question → 新 user 消息(stdin);abort → interrupt + SIGINT;stop-session → dispose。
已知 limitation(留给爸爸知道)
- 构建产物 inline 协议包:
dist/已把@cockpit/wire+crypto打进去,故协议层有 breaking 改动时要重新build并 bump 版本(见 PUBLISH.md §4)。 - claude CLI flags 因版本而异:
-p --input-format stream-json --output-format stream-json --permission-mode的精确组合在不同 claude 版本可能要调;权限 control 协议在bypassPermissions模式下不触发。 - DEK 派生 vs 控制台:daemon 用
deriveKey(masterSecret, sessionId)确定性派生会话 DEK(正确的 E2E,relay 看不到)。但当前 console 仍走 dev 快捷端点/v1/dev/dek取 DEK——要真正跨机 E2E,需把 console 也改成从 masterSecret 派生(待办)。--dev-dek-file仅供本地联调。 - 结构化提问(single-select 等)是模拟器特性:真 claude 一轮结束即等待,用户通过 composer 回复(
answer-question无 requestId → 新 user 轮次)。 - 只接了 claude:codex / cursor / gemini 等留好了
Agent抽象与AGENT_REGISTRY接口,尚未实现。 - outbox 无持久重试:事件上行是 best-effort,relay nack/超时即丢(未做磁盘 outbox)。
