@clawos-dev/clawd 0.2.261 → 0.2.263

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/dist/cli.cjs CHANGED
@@ -4149,346 +4149,6 @@ var init_zod = __esm({
4149
4149
  }
4150
4150
  });
4151
4151
 
4152
- // ../protocol/src/methods.ts
4153
- var METHOD_NAMES, RPC_METHOD_STATUSES, RpcMethodStatusSchema, RpcMethodInfoSchema, MetaMethodsResultSchema;
4154
- var init_methods = __esm({
4155
- "../protocol/src/methods.ts"() {
4156
- "use strict";
4157
- init_zod();
4158
- METHOD_NAMES = [
4159
- "session:create",
4160
- "session:list",
4161
- "session:get",
4162
- "session:update",
4163
- "session:delete",
4164
- "session:send",
4165
- // per-turn sender 2026-07-08 spec §4.6:MCP servers (ticket / inbox ...) 走 HTTP RPC
4166
- // /rpc/session:currentTurnSender(Bearer)拉当前 turn caller;WS handler 同名
4167
- "session:currentTurnSender",
4168
- "session:stop",
4169
- // 温柔中断当前轮次,不杀进程(走 CC IPC control_request.subtype=interrupt)
4170
- "session:interrupt",
4171
- // 回滚到指定 user message,并撤销其后 CC 的文件编辑(走 CC IPC control_request.subtype=rewind_files)
4172
- "session:rewind",
4173
- // Rewind 预览:daemon 读 ~/.claude/file-history 快照 + 磁盘现状算真实 diff,不依赖 CC 进程
4174
- "session:rewind-diff",
4175
- // 打开 session 时一次性拿到"有真实 diff"的 user message id 集合,UI heuristic 据此过滤按钮显示
4176
- "session:rewindable-message-ids",
4177
- // 从指定 message uuid 处 fork 出新 transcript(截断 + 重写 sessionId/parentUuid + forkedFrom)
4178
- // daemon 只生成新 jsonl 文件并返回新 toolSessionId;UI 自行决定是否走 session:create 拉起 resume
4179
- "session:fork",
4180
- "session:new",
4181
- "session:resume",
4182
- "session:observe",
4183
- "session:events",
4184
- "session:subscribe",
4185
- "session:unsubscribe",
4186
- "session:pin",
4187
- // 清共享未读标记(SessionFile.unreadAt → null)+ 广播 session:info;幂等
4188
- "session:markRead",
4189
- "session:reorderPins",
4190
- // mirror peer sessions (2026-05-26): owner-only RPC,写/删本机 mirror SessionFile —
4191
- // mirror 是「**我**在朋友 daemon 上自己创建的 session」的本机持久化副本(不是朋友的会话),
4192
- // 方便 sidebar 跨设备聚合。daemon dumb 写删,**不广播任何 push 帧** (不发 session:info /
4193
- // session:deleted);UI 是写入唯一源,双写完成后通过 cache.setData('sessions', ...) 同步
4194
- // 本地 sidebar state。native session:* handler 完全不感知 mirror (UI 操作 mirror 不复用
4195
- // native 路径)。
4196
- "peerSession:upsert",
4197
- "peerSession:remove",
4198
- "permission:respond",
4199
- // AskUserQuestion 表单回写:UI 答完所有 question 后调用,daemon 把答案合并进 updated_input
4200
- // 写一条 control_response 到 CC stdin(详见 events.ts session:question JSDoc)
4201
- "session:answerQuestion",
4202
- // AskUserQuestion 用户跳过:daemon 向 CC 回 allow + answers={} 让 tool 走空答案路径,
4203
- // 同时广播 cleared 帧(无 answers)让所有客户端 UI 卡片转 Ended
4204
- "session:cancelQuestion",
4205
- "history:projects",
4206
- "history:list",
4207
- "history:read",
4208
- "history:subagents",
4209
- "history:subagent-read",
4210
- "history:recentDirs",
4211
- "workspace:list",
4212
- "workspace:read",
4213
- "shift:list",
4214
- // ---- shift-internal:* (cc 内 shift MCP server 管理 owner 排班,spec 2026-06-24-clawd-shift) ----
4215
- // 统一 RPC 鉴权(spec 2026-07-28)后经 /rpc + Bearer owner token 调;personaId 归因
4216
- // 从 body 来(env CLAWD_PERSONA_ID),handler 内 createdByPersona 自检防跨 persona 误操作。
4217
- "shift-internal:add",
4218
- "shift-internal:list",
4219
- "shift-internal:cancel",
4220
- "shift-internal:update",
4221
- "shift-internal:history",
4222
- "skills:list",
4223
- "agents:list",
4224
- "git:root",
4225
- "git:branch",
4226
- "git:branches",
4227
- "capabilities:get",
4228
- // ---- persona:* (persona 管理) ----
4229
- // persona:list 响应 shape 不分流(统一返 PersonaFile[]),但 daemon handler 按
4230
- // ConnectionContext 投影不同子集:
4231
- // owner ctx → 返全量 personas(含 private)
4232
- // guest ctx → persona.public === true ∧ assertGrant(ctx.grants, {persona,p.id}, 'read')
4233
- // method-grants.ts: persona:list 是 CAPABILITY_SCOPED;其它 persona:* 仍 ADMIN_ANY。
4234
- "persona:create",
4235
- "persona:list",
4236
- "persona:get",
4237
- "persona:update",
4238
- "persona:delete",
4239
- // ---- personaDispatch:* (dispatch 全家,spec 2026-07-28-unify-rpc-auth 统一登记) ----
4240
- // run:本地 MCP server 经 /rpc(Bearer owner token);跨设备 A 的 peer daemon 经 /rpc
4241
- //(Bearer connect token)。capability-scoped(handler 自检 persona.public + assertGrant(send))。
4242
- // complete / list:B / A 本机 MCP server 调(owner token → ADMIN_ANY)。
4243
- // get:跨设备轮询——A 端 daemon 凭 connect token 查 B 台账终态;handler 校验行归属。
4244
- "personaDispatch:run",
4245
- "personaDispatch:complete",
4246
- "personaDispatch:list",
4247
- "personaDispatch:get",
4248
- // ---- peerExec:run (跨设备 exec,spec 2026-07-16-cross-device-exec-mcp) ----
4249
- // A 侧本机 MCP server 经 /rpc(Bearer owner token)带 peerDeviceId → daemon forward;
4250
- // B 侧对端经 /rpc(Bearer connect token)无 peerDeviceId → 本地 spawn。METHOD_GRANT_MAP
4251
- // 设 public,handler 内判 remoteAccessAllowed(跟 inbox:postMessage 同款)。
4252
- "peerExec:run",
4253
- // ---- session:pty 双向透传(仅 CLAWD_CC_MODE=tui 才生效,对应 session:pty push 帧的上行) ----
4254
- // session:pty:input — UI 把用户键盘字节(base64 UTF-8)发给 daemon,daemon 直写 pty stdin。
4255
- // 高频帧(每次按键 1 帧),不入 reducer / 不广播。response 是 fire-and-forget 风格 ack。
4256
- // session:pty:resize — UI 端 xterm 尺寸(cols/rows)变化时同步给 daemon 调 pty resize;
4257
- // 触发频率低(仅 window resize),response 也是 ack。
4258
- "session:pty:input",
4259
- "session:pty:resize",
4260
- // session:pty:snapshot — UI XtermPanel 重新挂载(切 session 回来 / 刷新)时主动拉一次当前
4261
- // 屏幕全量快照,再开始消费 incremental session:pty。daemon 调 manager.getPtyReplay(sessionId)
4262
- // 先 drain detector parse queue 再 serialize,保证 atSeq 与 buffer 内容严格对齐。
4263
- // response 字段:
4264
- // - data:当前屏幕 + scrollback 的 ANSI 字节串(base64-utf8),与 session:pty push 帧同格式
4265
- // - atSeq:此 snapshot 覆盖到的最后一帧 session:pty 的 seq(即 detector 已 parse 完成的最大 seq)
4266
- // UI 端 flush 时丢弃 pending 中 seq ≤ atSeq 的帧
4267
- // - popupKind:当前 detector 检测到的 popup 类型(null = 无 popup)
4268
- // session 不存在 / 非 tui / pty 已 exit 时 data=null, atSeq=0。
4269
- "session:pty:snapshot",
4270
- // ---- attachment.* file-sharing(详见 attachment-schemas.ts) ----
4271
- // 命名警告:这里的 `attachment.*` RPC 与 CC v2.x 上行 `type:"attachment"` 系统行
4272
- // (attachment-skills / attachment-deferred-tools / attachment_memories)是不同概念。
4273
- // 全部管理类 RPC dispatcher grant 限 owner(capability admin-only);
4274
- // 实际文件传输走 HTTP 路由(GET /files?p=&e=&s=,HMAC 签名自包含,不在白名单内)。
4275
- "attachment.signUrl",
4276
- "attachment.groupAdd",
4277
- "attachment.groupRemove",
4278
- "attachment.groupList",
4279
- // ---- inbox:* (capability platform Phase 3 跨用户通知 + Phase 4 DM) ----
4280
- // owner 接 guest 的 cross-principal 消息事件 + DM 双向私聊.
4281
- // inbox:list / markRead: admin-only (Phase 3); inbox:postMessage: DM 自带能力,
4282
- // 任何 principal (owner/guest) 可调 (Phase 4).
4283
- "inbox:list",
4284
- "inbox:markRead",
4285
- "inbox:postMessage",
4286
- // inbox:sendDm——persona 代发 DM 编排(inbox MCP server 经 /rpc + Bearer owner token 调)。
4287
- // sender/mode 由 handler 按 body.sessionId 反查 session scope 归因(业务逻辑非鉴权)。
4288
- "inbox:sendDm",
4289
- // ---- contact:* (联系人列表) ----
4290
- // 飞书统一身份 Phase 3 (决策 #14): received-capability:* 正名为 contact:*——Phase 2 后
4291
- // 联系人身份由中心 server introspect 背书,不再是"对方颁发的 capability"。
4292
- // 写入路径:device:connect 落 store + 自动反向(决策 #11);list / remove 作联系人列表读删。
4293
- "contact:list",
4294
- "contact:pin",
4295
- "contact:remove",
4296
- // ---- contact:setRemoteAccess (远程访问授权,spec 2026-07-16) ----
4297
- // owner UI 授权 contact 反向操作我的设备(跨设备 exec 开关 remoteAccessAllowed)。
4298
- // 详见 protocol/src/contact-remote-access.ts.
4299
- "contact:setRemoteAccess",
4300
- // ---- contact:handshake (双向确认建联握手, spec 2026-07-22) ----
4301
- // device:connect 临时连接调用;被调方同步落库+broadcast 后回 ok(携带身份载荷)。
4302
- // 替代旧 whoami+auto-reverse 组合;whoami 对 connect-token guest 已封(旧客户端拦截)。
4303
- "contact:handshake",
4304
- // ---- visitor:* (web 访客 · persona web 分享,spec 2026-06-24-persona-web-share-design) ----
4305
- // owner-only:列出登录访问过本机 public persona 的 web 访客(零安装、飞书登录、daemon 自签
4306
- // visitor token)。存储 ~/.clawd/visitors.json(VisitorStore),登录(exchange)即 upsert;
4307
- // 访客身份用 TTC unique_id,会话按 creatorPrincipalId='visitor-<id>' 进现有会话用户分组。
4308
- // 访客换 token 走 HTTP-only 公开路由 POST /share/exchange(非 WS method)。
4309
- "visitor:list",
4310
- // ---- whoami (v2 capability platform) ----
4311
- // 任何 authed connection 都能调;返回 owner 显示名 + 当前 capability wire 形态 +
4312
- // grants 对应的 persona 元数据 (id + displayName)。UI 端 AddRemotePersonaDialog
4313
- // 的 preview 一次性临时 client 用它判定身份和可用 persona。
4314
- "whoami",
4315
- "info",
4316
- "ping",
4317
- // ---- meta:methods (RPC 自省) ----
4318
- // 任何 authed connection 都能调(同 whoami):返回 METHOD_NAMES 全集 + **对本连接**
4319
- // 的可调用性三态。agent 侧 clawd-rpc 的 list tool 是唯一消费方——统一鉴权删掉白名单后
4320
- // agent 面前是 104 个 method,没有自省就只能靠试错。
4321
- "meta:methods",
4322
- // ---- extension runtime (v1: local mode only, no host-bridge —
4323
- // see clawd/superpowers/specs/2026-05-27-clawd-extensions-v1-design.md) ----
4324
- "extension.list",
4325
- "extension.open",
4326
- "extension.close",
4327
- "extension.uninstall",
4328
- // ---- extension sharing v1 (spec 2026-05-28-clawd-extension-sharing-design) ----
4329
- // owner-side: 公开 / 撤回 / 查 publish 状态(owner-only ADMIN_ANY)
4330
- "extension.publish",
4331
- "extension.unpublish",
4332
- "extension.publish:status",
4333
- // cross-tunnel: guest 从 owner 拉 published list + bundle(CAPABILITY_SCOPED)
4334
- "extension.list-published",
4335
- "extension.fetchBundle",
4336
- // guest-self: guest 在自己 daemon 上做安装与更新(ADMIN_ANY,guest 是 owner of self daemon).
4337
- // 无 subscription 持久化:guest 端身份完全来自文件系统 + reconciled publishedExtensions.
4338
- "extension.install-from-channel",
4339
- "extension.update-from-channel",
4340
- // ---- auth:* 飞书统一身份 Phase 1 (spec 2026-06-01-feishu-identity-design) ----
4341
- // owner-only:daemon loopback 登录流程(auth:login:start 起 state → HTTP /auth/callback
4342
- // 回调落盘 → auth:login:done 事件)。中央字面量见 protocol/feishu-auth.ts FEISHU_AUTH_METHODS。
4343
- "auth:login:start",
4344
- "auth:getIdentity",
4345
- "auth:logout",
4346
- // ---- device:* 设备目录 + 连接(决策 #15:deviceId + 自包含 token) ----
4347
- // owner-only:公共设备目录 + audience 绑定设备的签名 token 连接(daemon 代理中心 server)。
4348
- // 中央字面量见 protocol/feishu-auth.ts DEVICE_METHODS。
4349
- "device:list",
4350
- "device:connect",
4351
- // ---- app-builder Project (spec 2026-06-01 picker → 2026-06-02 单栏默认 refactor) ----
4352
- // persona-app-builder Project 管理;schemas: ProjectMetadataSchema + 5 个 args/result 对。
4353
- // listProjects: readdir projects/,按目录读 .clawd-project.json
4354
- // createProject: 校验 personaId/未绑 + 校验名 + 从 6173-6182 段分配端口 + 写元数据 + 创建空目录
4355
- // + daemon 内部 mutate session.appBuilderProject + 起 dev server(单栏 refactor 后唯一绑定入口)
4356
- // deleteProject: 停 dev server + rm -rf 目录(绑定 session 由 session:delete 联动 / 不在这里删)
4357
- // updateProjectPort: 校验新端口段内 + 未被别的 project 占 + 重启 dev server
4358
- // setProdUrl: 发布上线后 assistant 调一次写入 .clawd-project.json.prodUrl(取代 prod marker)
4359
- "appBuilder:listProjects",
4360
- // getProject:按 sessionId 取单个绑定 project(含 status)。people/mirror 跨 daemon 场景:
4361
- // 本机 owner 在远端是 guest,listProjects 被 per-user 隔离拿不到别人的 project;getProject
4362
- // 按 session 可见性授权(ensureSessionAccess read)放行。本地也复用(省掉拉全量再 find)。
4363
- "appBuilder:getProject",
4364
- "appBuilder:createProject",
4365
- "appBuilder:deleteProject",
4366
- "appBuilder:updateProjectPort",
4367
- "appBuilder:setProdUrl",
4368
- // 单栏 refactor stage fix (spec 2026-06-02-app-builder-single-pane-default-design §5.6.2):
4369
- // createProject 时不再立即起 dev server(fresh 目录必崩)。assistant scaffold + pnpm install
4370
- // 完成后调 startDevServer 显式触发 supervisor spawn;中间用 reportStage 上报进度(scaffolding
4371
- // / installing 等),daemon broadcast appBuilder:project-updated 帧让 UI PreviewPane 切阶段。
4372
- "appBuilder:startDevServer",
4373
- "appBuilder:reportStage",
4374
- // 显式控制 fix (spec 2026-06-02-app-builder-explicit-dev-server-control):用户点"收起预览"按钮触发,
4375
- // 对称 startDevServer。砍掉了 setActiveSession(dev server 不再跟用户 focus 走),切 session 不动 dev server。
4376
- "appBuilder:stopDevServer",
4377
- // 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design):
4378
- // publish:PreviewPane「发布上线」按钮 onClick 调本 RPC,daemon 内串行化 + spawn publish.sh +
4379
- // 广播阶段进度帧 (appBuilder:publish-progress / publish-failed)。同 project 已有 in-flight job
4380
- // 返回 already-publishing + 既有 jobId(UI 不报错继续订阅)。失败时 daemon 调 manager.send()
4381
- // 注入 user_text 到 chat,由 assistant 接管完成部署。
4382
- // dismissPublishJob:取消 in-flight publish(SIGTERM 子进程 + 清字段)或清掉 daemon 崩溃留下的
4383
- // 中断残骸 publishJob 字段。UI 端 [取消] / [interrupted 取消] 都走这个 RPC。
4384
- "appBuilder:publish",
4385
- "appBuilder:dismissPublishJob"
4386
- ];
4387
- RPC_METHOD_STATUSES = ["allowed", "conditional", "denied"];
4388
- RpcMethodStatusSchema = external_exports.enum(RPC_METHOD_STATUSES);
4389
- RpcMethodInfoSchema = external_exports.object({
4390
- /** canonical method 名,直接可作为 clawd-rpc call 的 method 参数 */
4391
- name: external_exports.string().min(1),
4392
- status: RpcMethodStatusSchema,
4393
- /**
4394
- * `denied` 必带:daemon error code(`UNAUTHORIZED` / `FEISHU_LOGIN_REQUIRED` /
4395
- * `METHOD_NOT_IMPLEMENTED`)。`conditional` 必带:谁来做二次校验。
4396
- * `allowed` 恒无。
4397
- */
4398
- reason: external_exports.string().optional()
4399
- });
4400
- MetaMethodsResultSchema = external_exports.object({
4401
- type: external_exports.literal("meta:methods"),
4402
- /** METHOD_NAMES 全集,顺序与之一致 */
4403
- methods: external_exports.array(RpcMethodInfoSchema)
4404
- });
4405
- }
4406
- });
4407
-
4408
- // ../protocol/src/events.ts
4409
- var DAEMON_MODE_VALUES, SESSION_STATUS_VALUES, HISTORY_USER_META_VALUES, SKILL_SOURCE_VALUES, AGENT_SOURCE_VALUES, ASK_USER_QUESTION_TOOL_NAME;
4410
- var init_events = __esm({
4411
- "../protocol/src/events.ts"() {
4412
- "use strict";
4413
- DAEMON_MODE_VALUES = ["sdk", "tui"];
4414
- SESSION_STATUS_VALUES = [
4415
- "idle",
4416
- "running",
4417
- "running-idle",
4418
- "stopped",
4419
- "error",
4420
- "observing"
4421
- ];
4422
- HISTORY_USER_META_VALUES = [
4423
- "task-notification",
4424
- "slash-command",
4425
- "local-command",
4426
- "system-reminder",
4427
- "skill-hint",
4428
- "meta-text",
4429
- "attachment-skills",
4430
- "attachment-deferred-tools"
4431
- ];
4432
- SKILL_SOURCE_VALUES = ["builtin", "global", "project", "plugin"];
4433
- AGENT_SOURCE_VALUES = [
4434
- "builtin",
4435
- "global",
4436
- "project",
4437
- "policy",
4438
- "plugin"
4439
- ];
4440
- ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
4441
- }
4442
- });
4443
-
4444
- // ../protocol/src/errors.ts
4445
- var ERROR_CODES, ClawdError;
4446
- var init_errors2 = __esm({
4447
- "../protocol/src/errors.ts"() {
4448
- "use strict";
4449
- ERROR_CODES = {
4450
- SESSION_NOT_FOUND: "SESSION_NOT_FOUND",
4451
- SESSION_BUSY: "SESSION_BUSY",
4452
- INVALID_CWD: "INVALID_CWD",
4453
- INVALID_PATH: "INVALID_PATH",
4454
- TOOL_NOT_SUPPORTED: "TOOL_NOT_SUPPORTED",
4455
- CLAUDE_NOT_FOUND: "CLAUDE_NOT_FOUND",
4456
- SPAWN_FAILED: "SPAWN_FAILED",
4457
- INVALID_PERMISSION_MODE: "INVALID_PERMISSION_MODE",
4458
- METHOD_NOT_IMPLEMENTED: "METHOD_NOT_IMPLEMENTED",
4459
- METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED",
4460
- VALIDATION_ERROR: "VALIDATION_ERROR",
4461
- PERMISSION_REQUEST_STALE: "PERMISSION_REQUEST_STALE",
4462
- FILE_TOO_LARGE: "FILE_TOO_LARGE",
4463
- INTERNAL: "INTERNAL",
4464
- UNAUTHORIZED: "UNAUTHORIZED",
4465
- FORBIDDEN: "FORBIDDEN",
4466
- INVALID_PARAM: "INVALID_PARAM",
4467
- // 飞书统一身份(spec 2026-06-01 决策 #9):People/远程体系强制飞书登录。
4468
- // daemon 进程身份未激活为飞书 unionId 时,FEISHU_GATED_METHODS 内的 RPC 一律返回此错误;
4469
- // UI 据此显示登录引导(区别于 UNAUTHORIZED 的越权语义)。
4470
- FEISHU_LOGIN_REQUIRED: "FEISHU_LOGIN_REQUIRED",
4471
- // app-builder 单栏默认 refactor (spec 2026-06-02-app-builder-single-pane-default-design):
4472
- // appBuilder:createProject 加 personaId + session 未绑校验后抛的两个错码。
4473
- WRONG_PERSONA: "WRONG_PERSONA",
4474
- SESSION_ALREADY_BOUND: "SESSION_ALREADY_BOUND",
4475
- // 2026-07-02 unified people sidebar: contact:pin 时 deviceId 不在 store(可能被别处删了)
4476
- CONTACT_NOT_FOUND: "CONTACT_NOT_FOUND",
4477
- // 统一 RPC 鉴权(spec 2026-07-28):personaDispatch:get 查不到台账行,或 guest ctx
4478
- // 查非自己发起的行(越权与未知 id 同码,不泄露存在性)。A 端轮询遇此码立即判失败。
4479
- DISPATCH_NOT_FOUND: "DISPATCH_NOT_FOUND"
4480
- };
4481
- ClawdError = class extends Error {
4482
- constructor(code, message) {
4483
- super(message);
4484
- this.code = code;
4485
- this.name = "ClawdError";
4486
- }
4487
- code;
4488
- };
4489
- }
4490
- });
4491
-
4492
4152
  // ../protocol/src/attachment-schemas.ts
4493
4153
  var TOKEN_ROLES, GROUP_FILE_SOURCES, GroupFileEntrySchema, AttachmentSignUrlArgs, AttachmentSignUrlResponseSchema, AttachmentGroupAddArgs, AttachmentGroupAddResponseSchema, AttachmentGroupRemoveArgs, AttachmentGroupRemoveResponseSchema, AttachmentGroupListArgs, AttachmentGroupListResponseSchema, AttachmentUploadResponseSchema;
4494
4154
  var init_attachment_schemas = __esm({
@@ -4573,59 +4233,736 @@ var init_attachment_schemas = __esm({
4573
4233
  }
4574
4234
  });
4575
4235
 
4576
- // ../protocol/src/principal.ts
4577
- function makeOwnerPrincipal(id, displayName, feishuUnionId) {
4578
- return PrincipalSchema.parse({
4579
- id,
4580
- kind: "owner",
4581
- displayName,
4582
- ...feishuUnionId ? { feishuUnionId } : {}
4583
- });
4584
- }
4585
- function principalToSender(p2) {
4586
- return {
4587
- did: p2.id,
4588
- displayName: p2.displayName,
4589
- principal: p2.kind,
4590
- ...p2.feishuUnionId ? { feishuUnionId: p2.feishuUnionId } : {}
4591
- };
4592
- }
4593
- function makeGuestSender(did, displayName, feishuUnionId) {
4594
- return SenderInfoSchema.parse({
4595
- did,
4596
- displayName,
4597
- principal: "guest",
4598
- ...feishuUnionId ? { feishuUnionId } : {}
4599
- });
4600
- }
4601
- var PrincipalKindSchema, PrincipalSchema, SenderInfoSchema;
4602
- var init_principal = __esm({
4603
- "../protocol/src/principal.ts"() {
4236
+ // ../protocol/src/capability.ts
4237
+ var ResourceSchema, ActionSchema, GrantSchema, CapabilitySchema, CapabilityWireSchema, WhoamiResponseSchema, PERSONAL_CAP_GRANTS;
4238
+ var init_capability = __esm({
4239
+ "../protocol/src/capability.ts"() {
4604
4240
  "use strict";
4605
4241
  init_zod();
4606
- PrincipalKindSchema = external_exports.enum(["owner", "guest"]);
4607
- PrincipalSchema = external_exports.object({
4242
+ ResourceSchema = external_exports.discriminatedUnion("type", [
4243
+ external_exports.object({ type: external_exports.literal("persona"), id: external_exports.string().min(1) }).strict(),
4244
+ external_exports.object({ type: external_exports.literal("chat"), id: external_exports.string().min(1) }).strict(),
4245
+ external_exports.object({ type: external_exports.literal("*") }).strict()
4246
+ ]);
4247
+ ActionSchema = external_exports.enum(["read", "send", "admin"]);
4248
+ GrantSchema = external_exports.object({
4249
+ resource: ResourceSchema,
4250
+ actions: external_exports.array(ActionSchema).min(1)
4251
+ }).strict();
4252
+ CapabilitySchema = external_exports.object({
4608
4253
  id: external_exports.string().min(1),
4609
- kind: PrincipalKindSchema,
4254
+ // sha256(token) hex 64
4255
+ secretHash: external_exports.string().regex(/^[a-f0-9]{64}$/),
4610
4256
  displayName: external_exports.string(),
4257
+ // 空数组合法 = 纯访客(只能 DM)
4258
+ grants: external_exports.array(GrantSchema),
4259
+ issuedAt: external_exports.number().int().nonnegative(),
4260
+ expiresAt: external_exports.number().int().positive().optional(),
4261
+ maxUses: external_exports.number().int().positive().optional(),
4262
+ usedCount: external_exports.number().int().nonnegative(),
4611
4263
  /**
4612
- * 飞书 union_id。owner: 本机 daemon 已飞书登录时透传自 owner-identity.json;未登录 undefined。
4613
- * guest: v1 保持 undefined(connect token 当前不携带 unionId;未来若签名 payload 加字段可透传)。
4614
- * 消费方(如 ticket MCP / 未来别的飞书身份挂钩场景)按 undefined 决定是否降级;本层不做 fallback。
4264
+ * guest auth 帧捎带 selfPrincipalId 时由 AuthGate.authenticate 回写;
4265
+ * 未被消费的 cap 此字段缺失。
4615
4266
  */
4616
- feishuUnionId: external_exports.string().optional()
4267
+ peerOwnerId: external_exports.string().min(1).optional(),
4268
+ /** 首次 client hello 时间戳(与 peerOwnerId 同步写入) */
4269
+ firstUsedByPeerAt: external_exports.number().int().positive().optional(),
4270
+ /**
4271
+ * 对方 daemon owner 的 displayName,guest auth 帧 selfDisplayName 触发
4272
+ * recordPeerHello 时同步回写。视角 B (2026-05-23) UI 派生联系人列表用此字段
4273
+ * 显示对方名字(避免 fallback 到我颁 cap 时填的 displayName)。
4274
+ */
4275
+ peerDisplayName: external_exports.string().optional()
4617
4276
  }).strict();
4618
- SenderInfoSchema = external_exports.object({
4619
- /** = principal.id = deviceId(决策 #16)。稳定路由 id */
4620
- did: external_exports.string().min(1),
4277
+ CapabilityWireSchema = CapabilitySchema.omit({ secretHash: true });
4278
+ WhoamiResponseSchema = external_exports.object({
4279
+ type: external_exports.literal("whoami:ok"),
4280
+ owner: external_exports.object({
4281
+ id: external_exports.string(),
4282
+ kind: external_exports.enum(["owner", "guest"]),
4283
+ displayName: external_exports.string(),
4284
+ /** 归属人 id(决策 #16:TTC unique_id 等,落 contact.ownerId) */
4285
+ ownerId: external_exports.string(),
4286
+ /** 身份来源(决策 #16:'ttc'/'google',落 contact.provider) */
4287
+ provider: external_exports.string()
4288
+ }).strict(),
4289
+ capability: CapabilityWireSchema,
4290
+ grantedPersonas: external_exports.array(
4291
+ external_exports.object({
4292
+ id: external_exports.string().min(1),
4293
+ displayName: external_exports.string()
4294
+ }).strict()
4295
+ )
4296
+ }).strict();
4297
+ PERSONAL_CAP_GRANTS = Object.freeze([
4298
+ Object.freeze({
4299
+ resource: Object.freeze({ type: "persona", id: "*" }),
4300
+ actions: Object.freeze(["read", "send"])
4301
+ })
4302
+ ]);
4303
+ }
4304
+ });
4305
+
4306
+ // ../protocol/src/contact-handshake.ts
4307
+ var ContactHandshakeArgsSchema, ContactHandshakeOkSchema;
4308
+ var init_contact_handshake = __esm({
4309
+ "../protocol/src/contact-handshake.ts"() {
4310
+ "use strict";
4311
+ init_zod();
4312
+ init_capability();
4313
+ ContactHandshakeArgsSchema = external_exports.object({
4314
+ selfUrl: external_exports.string().min(1)
4315
+ });
4316
+ ContactHandshakeOkSchema = external_exports.object({
4317
+ type: external_exports.literal("contact:handshake:ok"),
4318
+ owner: external_exports.object({
4319
+ /** 被调方 deviceId(路由主键;调用方落 Contact 的主键用自己请求的 args.deviceId,此值供校验/展示) */
4320
+ id: external_exports.string(),
4321
+ /** 归属人(落 Contact.ownerId / provider,显示分组用) */
4322
+ ownerId: external_exports.string(),
4323
+ provider: external_exports.string(),
4324
+ displayName: external_exports.string()
4325
+ }),
4326
+ /** 被调方授调用方的 grants(落 Contact.grants) */
4327
+ grants: external_exports.array(GrantSchema)
4328
+ });
4329
+ }
4330
+ });
4331
+
4332
+ // ../protocol/src/contact-remote-access.ts
4333
+ var ContactSetRemoteAccessArgsSchema, ContactSetRemoteAccessOkSchema, ContactRemoteAccessUpdatedFrameSchema;
4334
+ var init_contact_remote_access = __esm({
4335
+ "../protocol/src/contact-remote-access.ts"() {
4336
+ "use strict";
4337
+ init_zod();
4338
+ ContactSetRemoteAccessArgsSchema = external_exports.object({
4339
+ deviceId: external_exports.string().min(1),
4340
+ remoteAccessAllowed: external_exports.boolean()
4341
+ }).strict();
4342
+ ContactSetRemoteAccessOkSchema = external_exports.object({
4343
+ type: external_exports.literal("contact:setRemoteAccess:ok"),
4344
+ deviceId: external_exports.string().min(1),
4345
+ remoteAccessAllowed: external_exports.boolean()
4346
+ }).strict();
4347
+ ContactRemoteAccessUpdatedFrameSchema = external_exports.object({
4348
+ type: external_exports.literal("contact:remote-access-updated"),
4349
+ deviceId: external_exports.string().min(1),
4350
+ remoteAccessAllowed: external_exports.boolean()
4351
+ }).strict();
4352
+ }
4353
+ });
4354
+
4355
+ // ../protocol/src/contact.ts
4356
+ var ContactSchema, ContactWireSchema, ContactRemoveArgsSchema, ContactRemoveOkSchema, ContactListOkSchema, ContactAddedFrameSchema, ContactRemovedFrameSchema, ContactPinArgsSchema, ContactPinOkSchema, ContactPinnedFrameSchema;
4357
+ var init_contact = __esm({
4358
+ "../protocol/src/contact.ts"() {
4359
+ "use strict";
4360
+ init_zod();
4361
+ init_capability();
4362
+ ContactSchema = external_exports.object({
4363
+ /**
4364
+ * 对方设备标识(主键):对方 daemon 自己生成并持久化的标识(auth.json deviceId,
4365
+ * 如 dev-<uuid>),provider 无关。同 deviceId 重复 upsert 覆盖。
4366
+ */
4367
+ deviceId: external_exports.string().min(1),
4368
+ /**
4369
+ * 归属人 id(决策 #16):TTC unique_id 等,由 connect token subOwner 签名背书。
4370
+ * 与 provider 一起唯一标识一个人。DM 不再按它路由(路由用 deviceId),仅显示/分组用。
4371
+ */
4372
+ ownerId: external_exports.string().min(1),
4373
+ /** 身份来源(决策 #16):'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...,token 背书 */
4374
+ provider: external_exports.string().min(1),
4375
+ /** 联系人显示名 */
4621
4376
  displayName: external_exports.string(),
4622
- /** owner 未登录 / guest 无飞书身份时缺省。消费方各自决定是否降级 */
4623
- feishuUnionId: external_exports.string().optional(),
4624
- principal: PrincipalKindSchema
4377
+ /** 该设备可达的 ws/tunnel 地址 */
4378
+ remoteUrl: external_exports.string().min(1),
4379
+ // 自动反向建立联系人(spec 决策 #11):被连接方本地验票成功后自动落 A 为
4380
+ // 联系人,但它不持有 A 颁发的 token(A 从未给它换票)→ connectToken 为空串。
4381
+ // device:connect 出站路径仍存中心 server 签发的真实 connect token(断线重连复用)。
4382
+ // 不用 .min(1):自动反向路径合法地存空串,禁止填假 token 占位(不造假数据)。
4383
+ connectToken: external_exports.string(),
4384
+ grants: external_exports.array(GrantSchema),
4385
+ addedAt: external_exports.number().int().nonnegative(),
4386
+ /**
4387
+ * pin 时间戳(ms,Date.now() 语义);null = 未 pin。sidebar 顶部固定区渲染由此驱动。
4388
+ * 老 contacts.json 缺此字段 → zod default 补 null(无破坏性升级;不 orphan)。
4389
+ * 对齐 SessionFile.pinnedAt 语义(daemon 侧持久化,contact:pin RPC 更新 → contact:pinned push)。
4390
+ */
4391
+ pinnedAt: external_exports.number().int().nullable().default(null),
4392
+ /**
4393
+ * 远程访问授权(spec 2026-07-16)。owner 视角:允许该 contact 反向操作我的设备——
4394
+ * 跨设备 exec 的总开关(peerExec:run handler 运行时判它)。default=false,owner 显式开。
4395
+ * 授权粒度 per-people (per-contact):借用别人 persona 本来就带信任对方本人的前提。
4396
+ */
4397
+ remoteAccessAllowed: external_exports.boolean().default(false)
4398
+ }).strict();
4399
+ ContactWireSchema = ContactSchema;
4400
+ ContactRemoveArgsSchema = external_exports.object({
4401
+ deviceId: external_exports.string().min(1)
4402
+ }).strict();
4403
+ ContactRemoveOkSchema = external_exports.object({
4404
+ type: external_exports.literal("contact:remove:ok"),
4405
+ deviceId: external_exports.string().min(1)
4406
+ }).strict();
4407
+ ContactListOkSchema = external_exports.object({
4408
+ type: external_exports.literal("contact:list:ok"),
4409
+ contacts: external_exports.array(ContactWireSchema)
4410
+ }).strict();
4411
+ ContactAddedFrameSchema = external_exports.object({
4412
+ type: external_exports.literal("contact:added"),
4413
+ contact: ContactWireSchema
4414
+ }).strict();
4415
+ ContactRemovedFrameSchema = external_exports.object({
4416
+ type: external_exports.literal("contact:removed"),
4417
+ deviceId: external_exports.string().min(1)
4418
+ }).strict();
4419
+ ContactPinArgsSchema = external_exports.object({
4420
+ deviceId: external_exports.string().min(1),
4421
+ pinned: external_exports.boolean()
4422
+ }).strict();
4423
+ ContactPinOkSchema = external_exports.object({
4424
+ type: external_exports.literal("contact:pin:ok"),
4425
+ deviceId: external_exports.string().min(1),
4426
+ pinnedAt: external_exports.number().int().nullable()
4427
+ }).strict();
4428
+ ContactPinnedFrameSchema = external_exports.object({
4429
+ type: external_exports.literal("contact:pinned"),
4430
+ deviceId: external_exports.string().min(1),
4431
+ pinnedAt: external_exports.number().int().nullable()
4625
4432
  }).strict();
4626
4433
  }
4627
4434
  });
4628
4435
 
4436
+ // ../protocol/src/feishu-auth.ts
4437
+ var FEISHU_GATED_METHODS, DeviceEntrySchema, DeviceListResponseSchema, DeviceConnectArgsSchema, DeviceConnectResponseSchema, FeishuIdentitySchema, AuthLoginStartResponseSchema, AuthGetIdentityResponseSchema, AuthLogoutResponseSchema, AuthLoginDoneEventSchema, AuthLoginFailedEventSchema;
4438
+ var init_feishu_auth = __esm({
4439
+ "../protocol/src/feishu-auth.ts"() {
4440
+ "use strict";
4441
+ init_zod();
4442
+ FEISHU_GATED_METHODS = [
4443
+ // 联系人列表(device:connect 落同一 store;list 读 / remove 删)
4444
+ "contact:list",
4445
+ "contact:remove",
4446
+ // DM / 跨用户通知
4447
+ "inbox:list",
4448
+ "inbox:markRead",
4449
+ "inbox:postMessage",
4450
+ // mirror peer sessions(远端会话镜像)
4451
+ "peerSession:upsert",
4452
+ "peerSession:remove",
4453
+ // 设备目录 + 连接(决策 #15:daemon 代理中心 server,需要 owner 的 ttcJwt)
4454
+ "device:list",
4455
+ "device:connect"
4456
+ ];
4457
+ DeviceEntrySchema = external_exports.object({
4458
+ /**
4459
+ * 设备标识(决策 #15:daemon 本地生成的 dev-<uuid>,与人的身份 unionId 无关)。
4460
+ * 中心 server clawd_devices 注册表仅作服务发现(url 下发 + 目录),不在安全路径上。
4461
+ */
4462
+ deviceId: external_exports.string().min(1),
4463
+ /** 显示名 */
4464
+ name: external_exports.string().min(1),
4465
+ /** ws/tunnel 地址 */
4466
+ url: external_exports.string().min(1)
4467
+ });
4468
+ DeviceListResponseSchema = external_exports.object({
4469
+ type: external_exports.literal("device:list:ok"),
4470
+ devices: external_exports.array(DeviceEntrySchema)
4471
+ });
4472
+ DeviceConnectArgsSchema = external_exports.object({
4473
+ /** 目标设备的 deviceId(对方 daemon 生成的 dev-<uuid>) */
4474
+ deviceId: external_exports.string().min(1),
4475
+ /**
4476
+ * 目标设备的 ws/tunnel 地址(可选):
4477
+ * - 公开目录点击:带 url(device:list 已下发,省一次 server 查询)
4478
+ * - 凭 deviceId 连接:缺省 url → daemon exchange 时由中心 server 下发该设备上报的 url
4479
+ * - 注册表不在安全路径上:知道对方 url 时显式传入即可连接(不依赖中心 server 服务发现)
4480
+ */
4481
+ url: external_exports.string().min(1).optional(),
4482
+ /** 显示名(公共设备来自目录;缺省时连上后用 whoami 回填) */
4483
+ name: external_exports.string().optional()
4484
+ });
4485
+ DeviceConnectResponseSchema = external_exports.object({
4486
+ type: external_exports.literal("device:connect:ok"),
4487
+ /** 连接的目标设备标识(= 请求 args.deviceId) */
4488
+ deviceId: external_exports.string(),
4489
+ name: external_exports.string(),
4490
+ url: external_exports.string()
4491
+ });
4492
+ FeishuIdentitySchema = external_exports.object({
4493
+ /** 归属人 id(决策 #16:TTC unique_id,取代飞书 union_id;跨登录方式稳定) */
4494
+ ownerId: external_exports.string().min(1),
4495
+ /** 身份来源:'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...(决策 #16,拓展用) */
4496
+ provider: external_exports.string().min(1),
4497
+ /** 显示名。TTC user_info 接口 data.name */
4498
+ displayName: external_exports.string().min(1),
4499
+ /** TTC user_info 接口 data.avatar_url,可缺省 */
4500
+ avatarUrl: external_exports.string().optional(),
4501
+ /** TTC user_info 接口 data.union_id(飞书 union_id;dataclaw 可信入口 X-User-UnionId 用),可缺省 */
4502
+ unionId: external_exports.string().optional()
4503
+ });
4504
+ AuthLoginStartResponseSchema = external_exports.object({
4505
+ type: external_exports.literal("auth:login:start:ok"),
4506
+ /** 完整 TTC 授权页 URL(含 callback_url + state + auto=1),UI 直接 window.open */
4507
+ authUrl: external_exports.string().min(1),
4508
+ /** 防 CSRF 的一次性 nonce;回调时 daemon 校验 */
4509
+ state: external_exports.string().min(1)
4510
+ });
4511
+ AuthGetIdentityResponseSchema = external_exports.object({
4512
+ type: external_exports.literal("auth:getIdentity:ok"),
4513
+ /** null = 未登录 */
4514
+ identity: FeishuIdentitySchema.nullable(),
4515
+ /**
4516
+ * 本机设备标识(决策 #15:daemon 生成并持久化在 auth.json,如 dev-<uuid>)。
4517
+ * 设备属性,与登录态无关、登录登出不变。UI"我的设备标识"用它拼
4518
+ * clawos://device/<deviceId>(替代旧的 unionId——不再向外暴露人的身份标识)。
4519
+ */
4520
+ deviceId: external_exports.string().min(1)
4521
+ });
4522
+ AuthLogoutResponseSchema = external_exports.object({
4523
+ type: external_exports.literal("auth:logout:ok")
4524
+ });
4525
+ AuthLoginDoneEventSchema = external_exports.object({
4526
+ type: external_exports.literal("auth:login:done"),
4527
+ identity: FeishuIdentitySchema
4528
+ });
4529
+ AuthLoginFailedEventSchema = external_exports.object({
4530
+ type: external_exports.literal("auth:login:failed"),
4531
+ reason: external_exports.string()
4532
+ });
4533
+ }
4534
+ });
4535
+
4536
+ // ../protocol/src/dispatch.ts
4537
+ var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema, DISPATCH_STATUSES, DispatchStatusSchema, DispatchRecordSchema, DispatchListArgsSchema, DispatchListResultSchema, DispatchGetArgsSchema, DispatchGetOkSchema;
4538
+ var init_dispatch = __esm({
4539
+ "../protocol/src/dispatch.ts"() {
4540
+ "use strict";
4541
+ init_zod();
4542
+ DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
4543
+ external_exports.object({
4544
+ kind: external_exports.literal("success"),
4545
+ text: external_exports.string(),
4546
+ filePaths: external_exports.array(external_exports.string()).optional()
4547
+ }),
4548
+ external_exports.object({
4549
+ kind: external_exports.literal("failure"),
4550
+ reason: external_exports.string()
4551
+ })
4552
+ ]);
4553
+ DispatchRunArgsSchema = external_exports.object({
4554
+ // 新开必填;续派(dispatchId 非空)时可省略——targetPersonaId 从台账行取。
4555
+ targetPersona: external_exports.string().min(1).optional(),
4556
+ // 续派(spec 2026-07-21,单 dispatchId 语义:一件事一行一 id):非空 = 把 prompt
4557
+ // 作为新 turn 打进该 dispatch 的原 worker session 接着干(台账行复位 running)。
4558
+ // 省略 = 新开一件事,daemon 铸新 id。
4559
+ dispatchId: external_exports.string().min(1).optional(),
4560
+ prompt: external_exports.string(),
4561
+ // 跨设备 dispatch:非空 = A 角色,转发到该 contact deviceId 的 peer daemon;
4562
+ // 省略 = 本地 dispatch / B 角色本地执行。A 转发给 B 时 body 不带此字段。
4563
+ targetDeviceId: external_exports.string().min(1).optional(),
4564
+ // 可选:override B session 使用的 claude 模型。缺省 = 用 persona 默认。
4565
+ // 合法值集与 claude adapter capabilities.models[].id 一致(见 daemon
4566
+ // tools/claude.ts CLAUDE_MODEL_IDS);handler 层做二次校验,非法值 fail-fast。
4567
+ // protocol 层保持 string 便于未来跨 tool 扩展(届时 union 收合法字面量)。
4568
+ model: external_exports.string().min(1).optional(),
4569
+ // 可选:给新 worker session 起 label(写入 SessionFile.label,sidebar 显示)。
4570
+ // 仅在**新开 dispatch**(dispatchId 缺席)时生效;续派(dispatchId 非空)
4571
+ // 时 daemon 层静默丢弃(避免半途改 label 造成 sidebar 抖动)。
4572
+ // 上限 60 字符——sidebar 显示 tolerance,卡在 dispatch 入口即可。
4573
+ // 协议层不硬拒 sessionLabel + dispatchId 同传,保留 forward-compat。
4574
+ sessionLabel: external_exports.string().min(1).max(60).optional()
4575
+ }).refine((v2) => v2.targetPersona !== void 0 || v2.dispatchId !== void 0, {
4576
+ message: "either targetPersona (new dispatch) or dispatchId (follow-up) is required"
4577
+ }).refine((v2) => !(v2.dispatchId !== void 0 && v2.targetDeviceId !== void 0), {
4578
+ message: "cross-device dispatch cannot be continued (dispatchId + targetDeviceId are mutually exclusive)"
4579
+ });
4580
+ DispatchCompleteArgsSchema = external_exports.object({
4581
+ dispatchId: external_exports.string().min(1),
4582
+ outcome: DispatchOutcomeSchema
4583
+ });
4584
+ DISPATCH_STATUSES = ["running", "completed", "failed"];
4585
+ DispatchStatusSchema = external_exports.enum(DISPATCH_STATUSES);
4586
+ DispatchRecordSchema = external_exports.object({
4587
+ dispatchId: external_exports.string().min(1),
4588
+ sourceSessionId: external_exports.string().min(1),
4589
+ sourcePersonaId: external_exports.string().min(1).optional(),
4590
+ targetPersonaId: external_exports.string().min(1),
4591
+ /** B 的 sessionId;registerBSession 后回填 */
4592
+ workerSessionId: external_exports.string().min(1).optional(),
4593
+ /** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
4594
+ taskText: external_exports.string(),
4595
+ status: DispatchStatusSchema,
4596
+ outcome: DispatchOutcomeSchema.optional(),
4597
+ /** 上层消费者语义(如司礼监的口谕/验收状态),daemon 不解释 */
4598
+ meta: external_exports.record(external_exports.unknown()).optional(),
4599
+ createdAt: external_exports.string().min(1),
4600
+ completedAt: external_exports.string().min(1).optional(),
4601
+ /** 结果注入 source session 成功时戳,兼当投递 dedup 标记 */
4602
+ deliveredAt: external_exports.string().min(1).optional()
4603
+ });
4604
+ DispatchListArgsSchema = external_exports.object({
4605
+ sourceSessionId: external_exports.string().min(1).optional()
4606
+ });
4607
+ DispatchListResultSchema = external_exports.object({
4608
+ records: external_exports.array(DispatchRecordSchema)
4609
+ });
4610
+ DispatchGetArgsSchema = external_exports.object({
4611
+ dispatchId: external_exports.string().min(1)
4612
+ });
4613
+ DispatchGetOkSchema = external_exports.object({
4614
+ type: external_exports.literal("personaDispatch:get:ok"),
4615
+ status: DispatchStatusSchema,
4616
+ outcome: DispatchOutcomeSchema.optional()
4617
+ });
4618
+ }
4619
+ });
4620
+
4621
+ // ../protocol/src/extension.ts
4622
+ function isAllowedHostedUrl(raw) {
4623
+ let u;
4624
+ try {
4625
+ u = new URL(raw);
4626
+ } catch {
4627
+ return false;
4628
+ }
4629
+ if (u.protocol === "https:") return true;
4630
+ if (u.protocol === "http:" && LOCALHOST_HOSTS.has(u.hostname)) return true;
4631
+ return false;
4632
+ }
4633
+ function manifestMode(m2) {
4634
+ return m2.entry?.url ? "hosted" : "local";
4635
+ }
4636
+ function ownerNamespace(ownerPrincipalId) {
4637
+ let h = 2166136261;
4638
+ for (let i = 0; i < ownerPrincipalId.length; i++) {
4639
+ h ^= ownerPrincipalId.charCodeAt(i);
4640
+ h = Math.imul(h, 16777619) >>> 0;
4641
+ }
4642
+ return (h >>> 0).toString(16).padStart(8, "0");
4643
+ }
4644
+ function namespacedExtId(slug, ownerPrincipalId) {
4645
+ return `${slug}-${ownerNamespace(ownerPrincipalId)}`;
4646
+ }
4647
+ function validateSimpleSemver(v2) {
4648
+ if (typeof v2 !== "string") {
4649
+ return { ok: false, reason: "version must be a string" };
4650
+ }
4651
+ const parts = v2.split(".");
4652
+ if (parts.length !== 3) {
4653
+ return { ok: false, reason: `"${v2}" \u2014 only MAJOR.MINOR.PATCH allowed` };
4654
+ }
4655
+ for (const p2 of parts) {
4656
+ if (!/^\d+$/.test(p2)) {
4657
+ return { ok: false, reason: `"${v2}" \u2014 only numeric segments allowed` };
4658
+ }
4659
+ }
4660
+ return { ok: true };
4661
+ }
4662
+ function compareSimpleSemver(a, b2) {
4663
+ const pa = parseOrThrow(a);
4664
+ const pb = parseOrThrow(b2);
4665
+ for (let i = 0; i < 3; i++) {
4666
+ if (pa[i] < pb[i]) return -1;
4667
+ if (pa[i] > pb[i]) return 1;
4668
+ }
4669
+ return 0;
4670
+ }
4671
+ function parseOrThrow(v2) {
4672
+ const r = validateSimpleSemver(v2);
4673
+ if (!r.ok) throw new Error(r.reason);
4674
+ const [a, b2, c] = v2.split(".").map((p2) => parseInt(p2, 10));
4675
+ return [a, b2, c];
4676
+ }
4677
+ var EXT_ID_REGEX, ExtensionStateSchema, LOCALHOST_HOSTS, ExtensionManifestSchema, ExtensionTargetSchema, ExtensionRecordSchema, PublishedSnapshotSchema, ChannelRefSchema, SourceRefSchema, PublishedExtensionRecordSchema, PublishCheckSchema, PublishStatusResultSchema, ExtensionPublishArgs, ExtensionIdArgs, ExtensionFetchBundleArgs, ExtensionFromChannelArgs;
4678
+ var init_extension = __esm({
4679
+ "../protocol/src/extension.ts"() {
4680
+ "use strict";
4681
+ init_zod();
4682
+ EXT_ID_REGEX = /^[a-z0-9][a-z0-9-]*$/;
4683
+ ExtensionStateSchema = external_exports.enum([
4684
+ "stopped",
4685
+ "starting",
4686
+ "running",
4687
+ "crashed",
4688
+ "invalid"
4689
+ ]);
4690
+ LOCALHOST_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
4691
+ ExtensionManifestSchema = external_exports.object({
4692
+ id: external_exports.string().regex(EXT_ID_REGEX),
4693
+ name: external_exports.string().min(1),
4694
+ version: external_exports.string().min(1),
4695
+ apiVersion: external_exports.literal("1"),
4696
+ runtime: external_exports.object({ startCommand: external_exports.string().min(1) }).passthrough().optional(),
4697
+ entry: external_exports.object({
4698
+ url: external_exports.string().url().refine(isAllowedHostedUrl, {
4699
+ message: "INVALID_URL_SCHEME: only https or http://localhost is allowed"
4700
+ })
4701
+ }).strict().optional()
4702
+ }).passthrough().superRefine((m2, ctx) => {
4703
+ const hasRuntime = !!m2.runtime;
4704
+ const hasUrl = !!m2.entry?.url;
4705
+ if (hasRuntime && hasUrl) {
4706
+ ctx.addIssue({
4707
+ code: external_exports.ZodIssueCode.custom,
4708
+ message: "INVALID_MANIFEST: entry.url and runtime cannot coexist"
4709
+ });
4710
+ }
4711
+ if (!hasRuntime && !hasUrl) {
4712
+ ctx.addIssue({
4713
+ code: external_exports.ZodIssueCode.custom,
4714
+ message: "INVALID_MANIFEST: must have either entry.url or runtime"
4715
+ });
4716
+ }
4717
+ });
4718
+ ExtensionTargetSchema = external_exports.discriminatedUnion("kind", [
4719
+ external_exports.object({ kind: external_exports.literal("local"), port: external_exports.number().int().min(1).max(65535) }),
4720
+ external_exports.object({ kind: external_exports.literal("hosted"), url: external_exports.string().url() })
4721
+ ]);
4722
+ ExtensionRecordSchema = external_exports.discriminatedUnion("state", [
4723
+ external_exports.object({
4724
+ extId: external_exports.string(),
4725
+ manifest: ExtensionManifestSchema,
4726
+ state: external_exports.literal("stopped")
4727
+ }),
4728
+ external_exports.object({
4729
+ extId: external_exports.string(),
4730
+ manifest: ExtensionManifestSchema,
4731
+ state: external_exports.literal("starting")
4732
+ }),
4733
+ external_exports.object({
4734
+ extId: external_exports.string(),
4735
+ manifest: ExtensionManifestSchema,
4736
+ state: external_exports.literal("running"),
4737
+ target: ExtensionTargetSchema
4738
+ }),
4739
+ external_exports.object({
4740
+ extId: external_exports.string(),
4741
+ manifest: ExtensionManifestSchema,
4742
+ state: external_exports.literal("crashed")
4743
+ }),
4744
+ external_exports.object({
4745
+ extId: external_exports.string(),
4746
+ manifest: external_exports.unknown().nullable(),
4747
+ state: external_exports.literal("invalid"),
4748
+ invalidReason: external_exports.string().min(1)
4749
+ })
4750
+ ]);
4751
+ PublishedSnapshotSchema = external_exports.object({
4752
+ snapshotHash: external_exports.string().min(1),
4753
+ version: external_exports.string().min(1),
4754
+ publishedAt: external_exports.number()
4755
+ });
4756
+ ChannelRefSchema = external_exports.discriminatedUnion("kind", [
4757
+ external_exports.object({
4758
+ kind: external_exports.literal("p2p-tunnel"),
4759
+ ownerPrincipalId: external_exports.string().min(1),
4760
+ extId: external_exports.string().min(1)
4761
+ })
4762
+ ]);
4763
+ SourceRefSchema = external_exports.discriminatedUnion("kind", [
4764
+ external_exports.object({
4765
+ kind: external_exports.literal("p2p-tunnel"),
4766
+ ownerPrincipalId: external_exports.string().min(1),
4767
+ extId: external_exports.string().min(1),
4768
+ snapshotHash: external_exports.string().min(1)
4769
+ })
4770
+ ]);
4771
+ PublishedExtensionRecordSchema = external_exports.object({
4772
+ extId: external_exports.string().min(1),
4773
+ name: external_exports.string().min(1),
4774
+ version: external_exports.string().min(1),
4775
+ contentHash: external_exports.string().min(1),
4776
+ publishedAt: external_exports.number()
4777
+ });
4778
+ PublishCheckSchema = external_exports.discriminatedUnion("kind", [
4779
+ external_exports.object({ kind: external_exports.literal("clean") }),
4780
+ external_exports.object({
4781
+ kind: external_exports.literal("ready-new-version"),
4782
+ fromVersion: external_exports.string().min(1),
4783
+ toVersion: external_exports.string().min(1)
4784
+ }),
4785
+ external_exports.object({
4786
+ kind: external_exports.literal("error-same-hash"),
4787
+ version: external_exports.string().min(1)
4788
+ }),
4789
+ external_exports.object({
4790
+ kind: external_exports.literal("error-version-not-bumped"),
4791
+ localVersion: external_exports.string().min(1),
4792
+ publishedVersion: external_exports.string().min(1)
4793
+ }),
4794
+ external_exports.object({
4795
+ kind: external_exports.literal("error-version-regression"),
4796
+ localVersion: external_exports.string().min(1),
4797
+ publishedVersion: external_exports.string().min(1)
4798
+ })
4799
+ ]);
4800
+ PublishStatusResultSchema = external_exports.object({
4801
+ localManifest: external_exports.object({
4802
+ name: external_exports.string().min(1),
4803
+ version: external_exports.string().min(1),
4804
+ contentHash: external_exports.string().min(1)
4805
+ }),
4806
+ publishState: external_exports.discriminatedUnion("kind", [
4807
+ external_exports.object({ kind: external_exports.literal("unpublished") }),
4808
+ external_exports.object({
4809
+ kind: external_exports.literal("published"),
4810
+ version: external_exports.string().min(1),
4811
+ contentHash: external_exports.string().min(1),
4812
+ publishedAt: external_exports.number()
4813
+ })
4814
+ ]),
4815
+ check: PublishCheckSchema
4816
+ });
4817
+ ExtensionPublishArgs = external_exports.object({
4818
+ extId: external_exports.string().min(1),
4819
+ /**
4820
+ * 可选版本号:给了就在 publish-check 之前重写 manifest.json 的 version。
4821
+ * nullish 而非 optional —— 改造前的 pickOptionalString 显式把 null 当「没给」处理,
4822
+ * 换成纯 optional 会让 `newVersion: null` 从「不 bump」变成 INVALID_PARAM。
4823
+ */
4824
+ newVersion: external_exports.string().min(1).nullish()
4825
+ });
4826
+ ExtensionIdArgs = external_exports.object({
4827
+ extId: external_exports.string().min(1)
4828
+ });
4829
+ ExtensionFetchBundleArgs = external_exports.object({
4830
+ extId: external_exports.string().min(1),
4831
+ snapshotHash: external_exports.string().min(1)
4832
+ });
4833
+ ExtensionFromChannelArgs = external_exports.object({
4834
+ channelRef: ChannelRefSchema,
4835
+ snapshotHash: external_exports.string().min(1),
4836
+ zipBase64: external_exports.string().min(1)
4837
+ });
4838
+ }
4839
+ });
4840
+
4841
+ // ../protocol/src/inbox.ts
4842
+ var InboxMessageSchema, InboxPostMessageArgsSchema, InboxListArgsSchema, InboxMarkReadArgsSchema, InboxSendDmArgsSchema;
4843
+ var init_inbox = __esm({
4844
+ "../protocol/src/inbox.ts"() {
4845
+ "use strict";
4846
+ init_zod();
4847
+ InboxMessageSchema = external_exports.object({
4848
+ id: external_exports.string().min(1),
4849
+ peerDeviceId: external_exports.string().min(1),
4850
+ senderDeviceId: external_exports.string().min(1),
4851
+ text: external_exports.string().min(1),
4852
+ createdAt: external_exports.number().int().nonnegative(),
4853
+ readBy: external_exports.record(external_exports.string().min(1), external_exports.number().int().positive()).default({}),
4854
+ // persona 代发署名(B 版设计):非空 = 该消息由某 persona 代发,非真人手打。
4855
+ // 缺省 = 真人。routing 身份仍看 senderDeviceId;origin 只用于末端 UI 渲染来源。
4856
+ origin: external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }).optional()
4857
+ }).strict();
4858
+ InboxPostMessageArgsSchema = external_exports.object({
4859
+ peerDeviceId: external_exports.string().min(1).optional(),
4860
+ id: external_exports.string().min(1),
4861
+ text: external_exports.string().min(1),
4862
+ createdAt: external_exports.number().int().nonnegative(),
4863
+ // persona 代发署名(跨 daemon forward 时随远程腿透传;真人发缺省)。
4864
+ origin: external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }).optional()
4865
+ }).strict();
4866
+ InboxListArgsSchema = external_exports.object({
4867
+ peerDeviceId: external_exports.string().min(1),
4868
+ sinceCreatedAt: external_exports.number().int().nonnegative().optional()
4869
+ }).strict();
4870
+ InboxMarkReadArgsSchema = external_exports.object({
4871
+ peerDeviceId: external_exports.string().min(1),
4872
+ upToCreatedAt: external_exports.number().int().nonnegative()
4873
+ }).strict();
4874
+ InboxSendDmArgsSchema = external_exports.object({
4875
+ peerDeviceId: external_exports.string().min(1).optional(),
4876
+ text: external_exports.string().min(1)
4877
+ });
4878
+ }
4879
+ });
4880
+
4881
+ // ../protocol/src/peer-exec.ts
4882
+ var PeerExecRunArgsSchema, PeerExecRunOkSchema;
4883
+ var init_peer_exec = __esm({
4884
+ "../protocol/src/peer-exec.ts"() {
4885
+ "use strict";
4886
+ init_zod();
4887
+ PeerExecRunArgsSchema = external_exports.object({
4888
+ /** A 侧发起时带:目标设备 deviceId。peer-forward 转发前 strip 掉,B 侧本地执行时无此字段。 */
4889
+ peerDeviceId: external_exports.string().min(1).optional(),
4890
+ /** 交给对端 `bash -c` 的命令;cc 自拼完整路径(一发一收,无跨命令会话状态)。 */
4891
+ command: external_exports.string().min(1),
4892
+ /** 超时上限(ms);缺省用 handler 默认 30_000,clamp 300_000。 */
4893
+ timeoutMs: external_exports.number().int().positive().optional()
4894
+ }).strict();
4895
+ PeerExecRunOkSchema = external_exports.object({
4896
+ type: external_exports.literal("peerExec:run:ok"),
4897
+ stdout: external_exports.string(),
4898
+ stderr: external_exports.string(),
4899
+ /** 进程退出码;被超时 kill 时 null。 */
4900
+ exitCode: external_exports.number().int().nullable(),
4901
+ timedOut: external_exports.boolean(),
4902
+ stdoutTruncated: external_exports.boolean(),
4903
+ stderrTruncated: external_exports.boolean()
4904
+ }).strict();
4905
+ }
4906
+ });
4907
+
4908
+ // ../protocol/src/shift-internal.ts
4909
+ var ShiftScheduleSchema, personaId, ShiftInternalAddArgs, ShiftInternalListArgs, ShiftInternalCancelArgs, ShiftPatchSchema, ShiftInternalUpdateArgs, ShiftInternalHistoryArgs;
4910
+ var init_shift_internal = __esm({
4911
+ "../protocol/src/shift-internal.ts"() {
4912
+ "use strict";
4913
+ init_zod();
4914
+ ShiftScheduleSchema = external_exports.discriminatedUnion("kind", [
4915
+ /** ISO-8601 时间点;时区随字符串自带 */
4916
+ external_exports.object({ kind: external_exports.literal("at"), at: external_exports.string().min(1) }),
4917
+ /** 固定间隔;anchorMs 缺省 = 从登记时刻起算 */
4918
+ external_exports.object({
4919
+ kind: external_exports.literal("every"),
4920
+ everyMs: external_exports.number().int().positive(),
4921
+ anchorMs: external_exports.number().int().nonnegative().optional()
4922
+ }),
4923
+ /** 5 字段 cron 表达式;tz 缺省 = 系统本地时区 */
4924
+ external_exports.object({ kind: external_exports.literal("cron"), expr: external_exports.string().min(1), tz: external_exports.string().min(1).optional() })
4925
+ ]);
4926
+ personaId = external_exports.string().trim().min(1);
4927
+ ShiftInternalAddArgs = external_exports.object({
4928
+ personaId,
4929
+ name: external_exports.string().min(1),
4930
+ schedule: ShiftScheduleSchema,
4931
+ prompt: external_exports.string().min(1),
4932
+ /** 缺省 = 派给调用方自己 */
4933
+ targetPersona: external_exports.string().min(1).optional(),
4934
+ timeoutMs: external_exports.number().int().positive().optional()
4935
+ });
4936
+ ShiftInternalListArgs = external_exports.object({
4937
+ personaId,
4938
+ /** 缺省 true —— 只列本 persona 建的 */
4939
+ onlyMine: external_exports.boolean().optional()
4940
+ });
4941
+ ShiftInternalCancelArgs = external_exports.object({
4942
+ personaId,
4943
+ shiftId: external_exports.string().min(1)
4944
+ });
4945
+ ShiftPatchSchema = external_exports.object({
4946
+ name: external_exports.string().min(1).optional(),
4947
+ schedule: ShiftScheduleSchema.optional(),
4948
+ prompt: external_exports.string().min(1).optional(),
4949
+ targetPersona: external_exports.string().min(1).optional(),
4950
+ timeoutMs: external_exports.number().int().positive().optional(),
4951
+ enabled: external_exports.boolean().optional()
4952
+ });
4953
+ ShiftInternalUpdateArgs = external_exports.object({
4954
+ personaId,
4955
+ shiftId: external_exports.string().min(1),
4956
+ patch: ShiftPatchSchema
4957
+ });
4958
+ ShiftInternalHistoryArgs = external_exports.object({
4959
+ personaId,
4960
+ shiftId: external_exports.string().min(1),
4961
+ limit: external_exports.number().int().positive().optional()
4962
+ });
4963
+ }
4964
+ });
4965
+
4629
4966
  // ../protocol/src/persona-schemas.ts
4630
4967
  var PersonaFileSchema, PersonaSkillSummarySchema, PersonaPluginSummarySchema, PersonaSandboxSettingsSchema, PersonaInfoResponseSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema, CodexSandboxSettingsSchema;
4631
4968
  var init_persona_schemas = __esm({
@@ -4726,8 +5063,97 @@ var init_persona_schemas = __esm({
4726
5063
  }
4727
5064
  });
4728
5065
 
5066
+ // ../protocol/src/events.ts
5067
+ var DAEMON_MODE_VALUES, SESSION_STATUS_VALUES, HISTORY_USER_META_VALUES, SKILL_SOURCE_VALUES, AGENT_SOURCE_VALUES, ASK_USER_QUESTION_TOOL_NAME;
5068
+ var init_events = __esm({
5069
+ "../protocol/src/events.ts"() {
5070
+ "use strict";
5071
+ DAEMON_MODE_VALUES = ["sdk", "tui"];
5072
+ SESSION_STATUS_VALUES = [
5073
+ "idle",
5074
+ "running",
5075
+ "running-idle",
5076
+ "stopped",
5077
+ "error",
5078
+ "observing"
5079
+ ];
5080
+ HISTORY_USER_META_VALUES = [
5081
+ "task-notification",
5082
+ "slash-command",
5083
+ "local-command",
5084
+ "system-reminder",
5085
+ "skill-hint",
5086
+ "meta-text",
5087
+ "attachment-skills",
5088
+ "attachment-deferred-tools"
5089
+ ];
5090
+ SKILL_SOURCE_VALUES = ["builtin", "global", "project", "plugin"];
5091
+ AGENT_SOURCE_VALUES = [
5092
+ "builtin",
5093
+ "global",
5094
+ "project",
5095
+ "policy",
5096
+ "plugin"
5097
+ ];
5098
+ ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
5099
+ }
5100
+ });
5101
+
5102
+ // ../protocol/src/principal.ts
5103
+ function makeOwnerPrincipal(id, displayName, feishuUnionId) {
5104
+ return PrincipalSchema.parse({
5105
+ id,
5106
+ kind: "owner",
5107
+ displayName,
5108
+ ...feishuUnionId ? { feishuUnionId } : {}
5109
+ });
5110
+ }
5111
+ function principalToSender(p2) {
5112
+ return {
5113
+ did: p2.id,
5114
+ displayName: p2.displayName,
5115
+ principal: p2.kind,
5116
+ ...p2.feishuUnionId ? { feishuUnionId: p2.feishuUnionId } : {}
5117
+ };
5118
+ }
5119
+ function makeGuestSender(did, displayName, feishuUnionId) {
5120
+ return SenderInfoSchema.parse({
5121
+ did,
5122
+ displayName,
5123
+ principal: "guest",
5124
+ ...feishuUnionId ? { feishuUnionId } : {}
5125
+ });
5126
+ }
5127
+ var PrincipalKindSchema, PrincipalSchema, SenderInfoSchema;
5128
+ var init_principal = __esm({
5129
+ "../protocol/src/principal.ts"() {
5130
+ "use strict";
5131
+ init_zod();
5132
+ PrincipalKindSchema = external_exports.enum(["owner", "guest"]);
5133
+ PrincipalSchema = external_exports.object({
5134
+ id: external_exports.string().min(1),
5135
+ kind: PrincipalKindSchema,
5136
+ displayName: external_exports.string(),
5137
+ /**
5138
+ * 飞书 union_id。owner: 本机 daemon 已飞书登录时透传自 owner-identity.json;未登录 undefined。
5139
+ * guest: v1 保持 undefined(connect token 当前不携带 unionId;未来若签名 payload 加字段可透传)。
5140
+ * 消费方(如 ticket MCP / 未来别的飞书身份挂钩场景)按 undefined 决定是否降级;本层不做 fallback。
5141
+ */
5142
+ feishuUnionId: external_exports.string().optional()
5143
+ }).strict();
5144
+ SenderInfoSchema = external_exports.object({
5145
+ /** = principal.id = deviceId(决策 #16)。稳定路由 id */
5146
+ did: external_exports.string().min(1),
5147
+ displayName: external_exports.string(),
5148
+ /** owner 未登录 / guest 无飞书身份时缺省。消费方各自决定是否降级 */
5149
+ feishuUnionId: external_exports.string().optional(),
5150
+ principal: PrincipalKindSchema
5151
+ }).strict();
5152
+ }
5153
+ });
5154
+
4729
5155
  // ../protocol/src/schemas.ts
4730
- var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, ToolFeaturesSchema, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionListArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionSubscribeArgs, SessionPinArgs, PeerSessionUpsertArgs, PeerSessionUpsertResponseSchema, PeerSessionRemoveArgs, PeerSessionRemoveResponseSchema, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelReadyEventSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema, PROJECT_PORT_MIN, PROJECT_PORT_MAX, projectNameRegex, DEFAULT_DEV_COMMAND, ProjectMetadataSchema, PROJECT_STAGE_VALUES, ProjectStageSchema, ProjectWithStatusSchema, ListProjectsArgsSchema, ListProjectsResultSchema, GetProjectArgsSchema, GetProjectResultSchema, CreateProjectArgsSchema, CreateProjectResultSchema, DeleteProjectArgsSchema, DeleteProjectResultSchema, UpdateProjectPortArgsSchema, UpdateProjectPortResultSchema, SetProdUrlArgsSchema, SetProdUrlResultSchema, StartDevServerArgsSchema, StartDevServerResultSchema, ASSISTANT_REPORTABLE_STAGES, ReportStageArgsSchema, ReportStageResultSchema, StopDevServerArgsSchema, StopDevServerResultSchema, AppBuilderProjectUpdatedEventSchema, PublishArgsSchema, PublishResultSchema, DismissPublishJobArgsSchema, DismissPublishJobResultSchema, AppBuilderPublishProgressEventSchema, AppBuilderPublishFailedEventSchema;
5156
+ var SessionStatusSchema, UsageSchema, ContextUsageSchema, sessionMetaShape, SessionMetaSchema, ModelInfoSchema, ModeInfoSchema, ConfigFieldSchemaSchema, CapabilitiesGetArgs, ToolFeaturesSchema, CapabilitiesResponseSchema, AllowRuleSchema, SessionFileSchema, ParsedEventBase, HistoryUserMetaSchema, SubagentToolStatsSchema, StructuredPatchHunkSchema, ToolResultExtraSchema, MemoryEntrySchema, AskQuestionOptionSchema, AskQuestionItemSchema, ParsedEventSchema, SessionCreateArgs, SessionListArgs, SessionIdArgs, SessionUpdateArgs, SessionSendArgs, SessionInterruptArgs, SessionRewindArgs, SessionRewindResponseSchema, SessionRewindDiffArgs, RewindDiffHunkSchema, RewindDiffFileSchema, SessionRewindDiffResponseSchema, SessionRewindableMessageIdsArgs, SessionRewindableMessageIdsResponseSchema, SessionResumeArgs, SessionForkArgs, SessionForkResponseSchema, SessionObserveArgs, SessionEventsArgs, PermissionRespondArgs, HistoryListArgs, HistoryReadArgs, HistorySubagentsArgs, HistorySubagentReadArgs, WorkspaceListArgs, WorkspaceReadArgs, SkillsListArgs, SkillEntrySchema, AgentEntrySchema, AgentsListArgs, AgentsListResponseSchema, SessionCurrentTurnSenderArgs, SessionSubscribeArgs, SessionPinArgs, PeerSessionUpsertArgs, PeerSessionUpsertResponseSchema, PeerSessionRemoveArgs, PeerSessionRemoveResponseSchema, SessionReorderPinsArgs, GitRootArgs, GitRootResponseSchema, GitBranchArgs, GitBranchResponseSchema, GitBranchesArgs, GitBranchesResponseSchema, HistoryRecentDirsArgs, RecentDirEntrySchema, HistoryRecentDirsResponseSchema, SessionQuestionFrameSchema, SessionQuestionClearedFrameSchema, AnswerQuestionArgs, AnswerQuestionResponseSchema, CancelQuestionArgs, CancelQuestionResponseSchema, AuthRequestFrameSchema, AuthOkFrameSchema, TunnelReadyEventSchema, TunnelExitedEventSchema, TunnelUnavailableEventSchema, InfoRunningSessionSchema, InfoResponseSchema, PROJECT_PORT_MIN, PROJECT_PORT_MAX, projectNameRegex, DEFAULT_DEV_COMMAND, ProjectMetadataSchema, PROJECT_STAGE_VALUES, ProjectStageSchema, ProjectWithStatusSchema, ListProjectsArgsSchema, ListProjectsResultSchema, GetProjectArgsSchema, GetProjectResultSchema, CreateProjectArgsSchema, CreateProjectResultSchema, DeleteProjectArgsSchema, DeleteProjectResultSchema, UpdateProjectPortArgsSchema, UpdateProjectPortResultSchema, SetProdUrlArgsSchema, SetProdUrlResultSchema, StartDevServerArgsSchema, StartDevServerResultSchema, ASSISTANT_REPORTABLE_STAGES, ReportStageArgsSchema, ReportStageResultSchema, StopDevServerArgsSchema, StopDevServerResultSchema, AppBuilderProjectUpdatedEventSchema, PublishArgsSchema, PublishResultSchema, DismissPublishJobArgsSchema, DismissPublishJobResultSchema, AppBuilderPublishProgressEventSchema, AppBuilderPublishFailedEventSchema;
4731
5157
  var init_schemas = __esm({
4732
5158
  "../protocol/src/schemas.ts"() {
4733
5159
  "use strict";
@@ -5214,6 +5640,7 @@ var init_schemas = __esm({
5214
5640
  sessionId: external_exports.string().min(1),
5215
5641
  text: external_exports.string()
5216
5642
  });
5643
+ SessionInterruptArgs = SessionIdArgs;
5217
5644
  SessionRewindArgs = external_exports.object({
5218
5645
  sessionId: external_exports.string().min(1),
5219
5646
  userMessageId: external_exports.string().min(1),
@@ -5344,7 +5771,12 @@ var init_schemas = __esm({
5344
5771
  AgentsListResponseSchema = external_exports.object({
5345
5772
  agents: external_exports.array(AgentEntrySchema)
5346
5773
  });
5347
- SessionSubscribeArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
5774
+ SessionCurrentTurnSenderArgs = external_exports.object({
5775
+ // 刻意不加 .min(1):空串是被依赖的软路径(handler 见空即返 sender:null,
5776
+ // session-current-turn-sender.spec 有用例守着)。加了 min 会把它变成硬报错。
5777
+ sessionId: external_exports.string().optional()
5778
+ });
5779
+ SessionSubscribeArgs = external_exports.object({ sessionId: external_exports.string().min(1).optional() });
5348
5780
  SessionPinArgs = external_exports.object({
5349
5781
  sessionId: external_exports.string().min(1),
5350
5782
  pinned: external_exports.boolean()
@@ -5583,7 +6015,9 @@ var init_schemas = __esm({
5583
6015
  CreateProjectArgsSchema = external_exports.object({
5584
6016
  /** 必填:caller session,daemon 自动绑过去(spec 2026-06-02 §3 invariant 1 Session ↔ 1 Project) */
5585
6017
  sessionId: external_exports.string().min(1),
5586
- name: external_exports.string()
6018
+ // .min(1):改造前手写校验是 `!f.name` 明确拒空串;空 name 会让 projectDir('')
6019
+ // 落到 projects 根目录,scaffold 往根上铺模板。
6020
+ name: external_exports.string().min(1)
5587
6021
  }).strict();
5588
6022
  CreateProjectResultSchema = external_exports.object({
5589
6023
  project: ProjectMetadataSchema
@@ -5607,733 +6041,607 @@ var init_schemas = __esm({
5607
6041
  project: ProjectMetadataSchema
5608
6042
  }).strict();
5609
6043
  StartDevServerArgsSchema = external_exports.object({
5610
- sessionId: external_exports.string().min(1),
5611
- force: external_exports.boolean().optional()
5612
- }).strict();
5613
- StartDevServerResultSchema = external_exports.object({
5614
- project: ProjectMetadataSchema
5615
- }).strict();
5616
- ASSISTANT_REPORTABLE_STAGES = [
5617
- "installing",
5618
- "failed"
5619
- ];
5620
- ReportStageArgsSchema = external_exports.object({
5621
- sessionId: external_exports.string().min(1),
5622
- stage: external_exports.enum(ASSISTANT_REPORTABLE_STAGES),
5623
- /** stage='failed' 时必填的原因(一句话),其它 stage optional */
5624
- reason: external_exports.string().optional()
5625
- }).strict();
5626
- ReportStageResultSchema = external_exports.object({
5627
- ok: external_exports.literal(true)
5628
- }).strict();
5629
- StopDevServerArgsSchema = external_exports.object({
5630
- sessionId: external_exports.string().min(1)
5631
- }).strict();
5632
- StopDevServerResultSchema = external_exports.object({
5633
- ok: external_exports.literal(true)
5634
- }).strict();
5635
- AppBuilderProjectUpdatedEventSchema = external_exports.object({
5636
- type: external_exports.literal("appBuilder:project-updated"),
5637
- project: ProjectWithStatusSchema,
5638
- stage: ProjectStageSchema,
5639
- /** stage='failed' 时的失败原因 */
5640
- stageReason: external_exports.string().optional()
5641
- }).strict();
5642
- PublishArgsSchema = external_exports.object({
5643
- name: external_exports.string().regex(projectNameRegex)
5644
- });
5645
- PublishResultSchema = external_exports.object({
5646
- jobId: external_exports.string().min(1),
5647
- status: external_exports.enum(["started", "already-publishing"])
5648
- }).strict();
5649
- DismissPublishJobArgsSchema = external_exports.object({
5650
- name: external_exports.string().regex(projectNameRegex)
5651
- });
5652
- DismissPublishJobResultSchema = external_exports.object({
5653
- ok: external_exports.literal(true)
5654
- }).strict();
5655
- AppBuilderPublishProgressEventSchema = external_exports.object({
5656
- type: external_exports.literal("appBuilder:publish-progress"),
5657
- name: external_exports.string().regex(projectNameRegex),
5658
- jobId: external_exports.string().min(1),
5659
- stage: external_exports.enum(["build", "deploy", "verify"]),
5660
- status: external_exports.enum(["started", "completed"])
5661
- }).strict();
5662
- AppBuilderPublishFailedEventSchema = external_exports.object({
5663
- type: external_exports.literal("appBuilder:publish-failed"),
5664
- name: external_exports.string().regex(projectNameRegex),
5665
- jobId: external_exports.string().min(1),
5666
- stage: external_exports.enum(["build", "deploy", "verify", "unknown"]),
5667
- errorSummary: external_exports.string()
5668
- }).strict();
5669
- }
5670
- });
5671
-
5672
- // ../protocol/src/frames.ts
5673
- var PROTOCOL_VERSION, DISPATCH_MCP_ID;
5674
- var init_frames = __esm({
5675
- "../protocol/src/frames.ts"() {
5676
- "use strict";
5677
- PROTOCOL_VERSION = 1;
5678
- DISPATCH_MCP_ID = "dispatch";
5679
- }
5680
- });
5681
-
5682
- // ../protocol/src/persona-mode.ts
5683
- var init_persona_mode = __esm({
5684
- "../protocol/src/persona-mode.ts"() {
5685
- "use strict";
5686
- }
5687
- });
5688
-
5689
- // ../protocol/src/capability.ts
5690
- var ResourceSchema, ActionSchema, GrantSchema, CapabilitySchema, CapabilityWireSchema, WhoamiResponseSchema, PERSONAL_CAP_GRANTS;
5691
- var init_capability = __esm({
5692
- "../protocol/src/capability.ts"() {
5693
- "use strict";
5694
- init_zod();
5695
- ResourceSchema = external_exports.discriminatedUnion("type", [
5696
- external_exports.object({ type: external_exports.literal("persona"), id: external_exports.string().min(1) }).strict(),
5697
- external_exports.object({ type: external_exports.literal("chat"), id: external_exports.string().min(1) }).strict(),
5698
- external_exports.object({ type: external_exports.literal("*") }).strict()
5699
- ]);
5700
- ActionSchema = external_exports.enum(["read", "send", "admin"]);
5701
- GrantSchema = external_exports.object({
5702
- resource: ResourceSchema,
5703
- actions: external_exports.array(ActionSchema).min(1)
5704
- }).strict();
5705
- CapabilitySchema = external_exports.object({
5706
- id: external_exports.string().min(1),
5707
- // sha256(token) hex 64
5708
- secretHash: external_exports.string().regex(/^[a-f0-9]{64}$/),
5709
- displayName: external_exports.string(),
5710
- // 空数组合法 = 纯访客(只能 DM)
5711
- grants: external_exports.array(GrantSchema),
5712
- issuedAt: external_exports.number().int().nonnegative(),
5713
- expiresAt: external_exports.number().int().positive().optional(),
5714
- maxUses: external_exports.number().int().positive().optional(),
5715
- usedCount: external_exports.number().int().nonnegative(),
5716
- /**
5717
- * guest 在 auth 帧捎带 selfPrincipalId 时由 AuthGate.authenticate 回写;
5718
- * 未被消费的 cap 此字段缺失。
5719
- */
5720
- peerOwnerId: external_exports.string().min(1).optional(),
5721
- /** 首次 client hello 时间戳(与 peerOwnerId 同步写入) */
5722
- firstUsedByPeerAt: external_exports.number().int().positive().optional(),
5723
- /**
5724
- * 对方 daemon owner 的 displayName,guest auth 帧 selfDisplayName 触发
5725
- * recordPeerHello 时同步回写。视角 B (2026-05-23) UI 派生联系人列表用此字段
5726
- * 显示对方名字(避免 fallback 到我颁 cap 时填的 displayName)。
5727
- */
5728
- peerDisplayName: external_exports.string().optional()
5729
- }).strict();
5730
- CapabilityWireSchema = CapabilitySchema.omit({ secretHash: true });
5731
- WhoamiResponseSchema = external_exports.object({
5732
- type: external_exports.literal("whoami:ok"),
5733
- owner: external_exports.object({
5734
- id: external_exports.string(),
5735
- kind: external_exports.enum(["owner", "guest"]),
5736
- displayName: external_exports.string(),
5737
- /** 归属人 id(决策 #16:TTC unique_id 等,落 contact.ownerId) */
5738
- ownerId: external_exports.string(),
5739
- /** 身份来源(决策 #16:'ttc'/'google',落 contact.provider) */
5740
- provider: external_exports.string()
5741
- }).strict(),
5742
- capability: CapabilityWireSchema,
5743
- grantedPersonas: external_exports.array(
5744
- external_exports.object({
5745
- id: external_exports.string().min(1),
5746
- displayName: external_exports.string()
5747
- }).strict()
5748
- )
5749
- }).strict();
5750
- PERSONAL_CAP_GRANTS = Object.freeze([
5751
- Object.freeze({
5752
- resource: Object.freeze({ type: "persona", id: "*" }),
5753
- actions: Object.freeze(["read", "send"])
5754
- })
5755
- ]);
5756
- }
5757
- });
5758
-
5759
- // ../protocol/src/inbox.ts
5760
- var InboxMessageSchema, InboxPostMessageArgsSchema, InboxListArgsSchema, InboxMarkReadArgsSchema, InboxSendDmArgsSchema;
5761
- var init_inbox = __esm({
5762
- "../protocol/src/inbox.ts"() {
5763
- "use strict";
5764
- init_zod();
5765
- InboxMessageSchema = external_exports.object({
5766
- id: external_exports.string().min(1),
5767
- peerDeviceId: external_exports.string().min(1),
5768
- senderDeviceId: external_exports.string().min(1),
5769
- text: external_exports.string().min(1),
5770
- createdAt: external_exports.number().int().nonnegative(),
5771
- readBy: external_exports.record(external_exports.string().min(1), external_exports.number().int().positive()).default({}),
5772
- // persona 代发署名(B 版设计):非空 = 该消息由某 persona 代发,非真人手打。
5773
- // 缺省 = 真人。routing 身份仍看 senderDeviceId;origin 只用于末端 UI 渲染来源。
5774
- origin: external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }).optional()
5775
- }).strict();
5776
- InboxPostMessageArgsSchema = external_exports.object({
5777
- peerDeviceId: external_exports.string().min(1).optional(),
5778
- id: external_exports.string().min(1),
5779
- text: external_exports.string().min(1),
5780
- createdAt: external_exports.number().int().nonnegative(),
5781
- // persona 代发署名(跨 daemon forward 时随远程腿透传;真人发缺省)。
5782
- origin: external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }).optional()
5783
- }).strict();
5784
- InboxListArgsSchema = external_exports.object({
5785
- peerDeviceId: external_exports.string().min(1),
5786
- sinceCreatedAt: external_exports.number().int().nonnegative().optional()
5787
- }).strict();
5788
- InboxMarkReadArgsSchema = external_exports.object({
5789
- peerDeviceId: external_exports.string().min(1),
5790
- upToCreatedAt: external_exports.number().int().nonnegative()
5791
- }).strict();
5792
- InboxSendDmArgsSchema = external_exports.object({
5793
- peerDeviceId: external_exports.string().min(1).optional(),
5794
- text: external_exports.string().min(1)
5795
- });
5796
- }
5797
- });
5798
-
5799
- // ../protocol/src/contact.ts
5800
- var ContactSchema, ContactWireSchema, ContactRemoveArgsSchema, ContactRemoveOkSchema, ContactListOkSchema, ContactAddedFrameSchema, ContactRemovedFrameSchema, ContactPinArgsSchema, ContactPinOkSchema, ContactPinnedFrameSchema;
5801
- var init_contact = __esm({
5802
- "../protocol/src/contact.ts"() {
5803
- "use strict";
5804
- init_zod();
5805
- init_capability();
5806
- ContactSchema = external_exports.object({
5807
- /**
5808
- * 对方设备标识(主键):对方 daemon 自己生成并持久化的标识(auth.json deviceId,
5809
- * 如 dev-<uuid>),provider 无关。同 deviceId 重复 upsert 覆盖。
5810
- */
5811
- deviceId: external_exports.string().min(1),
5812
- /**
5813
- * 归属人 id(决策 #16):TTC unique_id 等,由 connect token subOwner 签名背书。
5814
- * 与 provider 一起唯一标识一个人。DM 不再按它路由(路由用 deviceId),仅显示/分组用。
5815
- */
5816
- ownerId: external_exports.string().min(1),
5817
- /** 身份来源(决策 #16):'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...,token 背书 */
5818
- provider: external_exports.string().min(1),
5819
- /** 联系人显示名 */
5820
- displayName: external_exports.string(),
5821
- /** 该设备可达的 ws/tunnel 地址 */
5822
- remoteUrl: external_exports.string().min(1),
5823
- // 自动反向建立联系人(spec 决策 #11):被连接方本地验票成功后自动落 A 为
5824
- // 联系人,但它不持有 A 颁发的 token(A 从未给它换票)→ connectToken 为空串。
5825
- // device:connect 出站路径仍存中心 server 签发的真实 connect token(断线重连复用)。
5826
- // 不用 .min(1):自动反向路径合法地存空串,禁止填假 token 占位(不造假数据)。
5827
- connectToken: external_exports.string(),
5828
- grants: external_exports.array(GrantSchema),
5829
- addedAt: external_exports.number().int().nonnegative(),
5830
- /**
5831
- * pin 时间戳(ms,Date.now() 语义);null = 未 pin。sidebar 顶部固定区渲染由此驱动。
5832
- * 老 contacts.json 缺此字段 → zod default 补 null(无破坏性升级;不 orphan)。
5833
- * 对齐 SessionFile.pinnedAt 语义(daemon 侧持久化,contact:pin RPC 更新 → contact:pinned push)。
5834
- */
5835
- pinnedAt: external_exports.number().int().nullable().default(null),
5836
- /**
5837
- * 远程访问授权(spec 2026-07-16)。owner 视角:允许该 contact 反向操作我的设备——
5838
- * 跨设备 exec 的总开关(peerExec:run handler 运行时判它)。default=false,owner 显式开。
5839
- * 授权粒度 per-people (per-contact):借用别人 persona 本来就带信任对方本人的前提。
5840
- */
5841
- remoteAccessAllowed: external_exports.boolean().default(false)
5842
- }).strict();
5843
- ContactWireSchema = ContactSchema;
5844
- ContactRemoveArgsSchema = external_exports.object({
5845
- deviceId: external_exports.string().min(1)
5846
- }).strict();
5847
- ContactRemoveOkSchema = external_exports.object({
5848
- type: external_exports.literal("contact:remove:ok"),
5849
- deviceId: external_exports.string().min(1)
5850
- }).strict();
5851
- ContactListOkSchema = external_exports.object({
5852
- type: external_exports.literal("contact:list:ok"),
5853
- contacts: external_exports.array(ContactWireSchema)
5854
- }).strict();
5855
- ContactAddedFrameSchema = external_exports.object({
5856
- type: external_exports.literal("contact:added"),
5857
- contact: ContactWireSchema
5858
- }).strict();
5859
- ContactRemovedFrameSchema = external_exports.object({
5860
- type: external_exports.literal("contact:removed"),
5861
- deviceId: external_exports.string().min(1)
5862
- }).strict();
5863
- ContactPinArgsSchema = external_exports.object({
5864
- deviceId: external_exports.string().min(1),
5865
- pinned: external_exports.boolean()
5866
- }).strict();
5867
- ContactPinOkSchema = external_exports.object({
5868
- type: external_exports.literal("contact:pin:ok"),
5869
- deviceId: external_exports.string().min(1),
5870
- pinnedAt: external_exports.number().int().nullable()
5871
- }).strict();
5872
- ContactPinnedFrameSchema = external_exports.object({
5873
- type: external_exports.literal("contact:pinned"),
5874
- deviceId: external_exports.string().min(1),
5875
- pinnedAt: external_exports.number().int().nullable()
5876
- }).strict();
5877
- }
5878
- });
5879
-
5880
- // ../protocol/src/contact-handshake.ts
5881
- var ContactHandshakeArgsSchema, ContactHandshakeOkSchema;
5882
- var init_contact_handshake = __esm({
5883
- "../protocol/src/contact-handshake.ts"() {
5884
- "use strict";
5885
- init_zod();
5886
- init_capability();
5887
- ContactHandshakeArgsSchema = external_exports.object({
5888
- selfUrl: external_exports.string().min(1)
5889
- });
5890
- ContactHandshakeOkSchema = external_exports.object({
5891
- type: external_exports.literal("contact:handshake:ok"),
5892
- owner: external_exports.object({
5893
- /** 被调方 deviceId(路由主键;调用方落 Contact 的主键用自己请求的 args.deviceId,此值供校验/展示) */
5894
- id: external_exports.string(),
5895
- /** 归属人(落 Contact.ownerId / provider,显示分组用) */
5896
- ownerId: external_exports.string(),
5897
- provider: external_exports.string(),
5898
- displayName: external_exports.string()
5899
- }),
5900
- /** 被调方授调用方的 grants(落 Contact.grants) */
5901
- grants: external_exports.array(GrantSchema)
5902
- });
5903
- }
5904
- });
5905
-
5906
- // ../protocol/src/contact-remote-access.ts
5907
- var ContactSetRemoteAccessArgsSchema, ContactSetRemoteAccessOkSchema, ContactRemoteAccessUpdatedFrameSchema;
5908
- var init_contact_remote_access = __esm({
5909
- "../protocol/src/contact-remote-access.ts"() {
5910
- "use strict";
5911
- init_zod();
5912
- ContactSetRemoteAccessArgsSchema = external_exports.object({
5913
- deviceId: external_exports.string().min(1),
5914
- remoteAccessAllowed: external_exports.boolean()
5915
- }).strict();
5916
- ContactSetRemoteAccessOkSchema = external_exports.object({
5917
- type: external_exports.literal("contact:setRemoteAccess:ok"),
5918
- deviceId: external_exports.string().min(1),
5919
- remoteAccessAllowed: external_exports.boolean()
5920
- }).strict();
5921
- ContactRemoteAccessUpdatedFrameSchema = external_exports.object({
5922
- type: external_exports.literal("contact:remote-access-updated"),
5923
- deviceId: external_exports.string().min(1),
5924
- remoteAccessAllowed: external_exports.boolean()
5925
- }).strict();
5926
- }
5927
- });
5928
-
5929
- // ../protocol/src/peer-exec.ts
5930
- var PeerExecRunArgsSchema, PeerExecRunOkSchema;
5931
- var init_peer_exec = __esm({
5932
- "../protocol/src/peer-exec.ts"() {
5933
- "use strict";
5934
- init_zod();
5935
- PeerExecRunArgsSchema = external_exports.object({
5936
- /** A 侧发起时带:目标设备 deviceId。peer-forward 转发前 strip 掉,B 侧本地执行时无此字段。 */
5937
- peerDeviceId: external_exports.string().min(1).optional(),
5938
- /** 交给对端 `bash -c` 的命令;cc 自拼完整路径(一发一收,无跨命令会话状态)。 */
5939
- command: external_exports.string().min(1),
5940
- /** 超时上限(ms);缺省用 handler 默认 30_000,clamp 300_000。 */
5941
- timeoutMs: external_exports.number().int().positive().optional()
5942
- }).strict();
5943
- PeerExecRunOkSchema = external_exports.object({
5944
- type: external_exports.literal("peerExec:run:ok"),
5945
- stdout: external_exports.string(),
5946
- stderr: external_exports.string(),
5947
- /** 进程退出码;被超时 kill 时 null。 */
5948
- exitCode: external_exports.number().int().nullable(),
5949
- timedOut: external_exports.boolean(),
5950
- stdoutTruncated: external_exports.boolean(),
5951
- stderrTruncated: external_exports.boolean()
5952
- }).strict();
5953
- }
5954
- });
5955
-
5956
- // ../protocol/src/extension.ts
5957
- function isAllowedHostedUrl(raw) {
5958
- let u;
5959
- try {
5960
- u = new URL(raw);
5961
- } catch {
5962
- return false;
5963
- }
5964
- if (u.protocol === "https:") return true;
5965
- if (u.protocol === "http:" && LOCALHOST_HOSTS.has(u.hostname)) return true;
5966
- return false;
5967
- }
5968
- function manifestMode(m2) {
5969
- return m2.entry?.url ? "hosted" : "local";
5970
- }
5971
- function ownerNamespace(ownerPrincipalId) {
5972
- let h = 2166136261;
5973
- for (let i = 0; i < ownerPrincipalId.length; i++) {
5974
- h ^= ownerPrincipalId.charCodeAt(i);
5975
- h = Math.imul(h, 16777619) >>> 0;
5976
- }
5977
- return (h >>> 0).toString(16).padStart(8, "0");
5978
- }
5979
- function namespacedExtId(slug, ownerPrincipalId) {
5980
- return `${slug}-${ownerNamespace(ownerPrincipalId)}`;
5981
- }
5982
- function validateSimpleSemver(v2) {
5983
- if (typeof v2 !== "string") {
5984
- return { ok: false, reason: "version must be a string" };
5985
- }
5986
- const parts = v2.split(".");
5987
- if (parts.length !== 3) {
5988
- return { ok: false, reason: `"${v2}" \u2014 only MAJOR.MINOR.PATCH allowed` };
5989
- }
5990
- for (const p2 of parts) {
5991
- if (!/^\d+$/.test(p2)) {
5992
- return { ok: false, reason: `"${v2}" \u2014 only numeric segments allowed` };
5993
- }
5994
- }
5995
- return { ok: true };
5996
- }
5997
- function compareSimpleSemver(a, b2) {
5998
- const pa = parseOrThrow(a);
5999
- const pb = parseOrThrow(b2);
6000
- for (let i = 0; i < 3; i++) {
6001
- if (pa[i] < pb[i]) return -1;
6002
- if (pa[i] > pb[i]) return 1;
6003
- }
6004
- return 0;
6005
- }
6006
- function parseOrThrow(v2) {
6007
- const r = validateSimpleSemver(v2);
6008
- if (!r.ok) throw new Error(r.reason);
6009
- const [a, b2, c] = v2.split(".").map((p2) => parseInt(p2, 10));
6010
- return [a, b2, c];
6011
- }
6012
- var EXT_ID_REGEX, ExtensionStateSchema, LOCALHOST_HOSTS, ExtensionManifestSchema, ExtensionTargetSchema, ExtensionRecordSchema, PublishedSnapshotSchema, ChannelRefSchema, SourceRefSchema, PublishedExtensionRecordSchema, PublishCheckSchema, PublishStatusResultSchema;
6013
- var init_extension = __esm({
6014
- "../protocol/src/extension.ts"() {
6015
- "use strict";
6016
- init_zod();
6017
- EXT_ID_REGEX = /^[a-z0-9][a-z0-9-]*$/;
6018
- ExtensionStateSchema = external_exports.enum([
6019
- "stopped",
6020
- "starting",
6021
- "running",
6022
- "crashed",
6023
- "invalid"
6024
- ]);
6025
- LOCALHOST_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
6026
- ExtensionManifestSchema = external_exports.object({
6027
- id: external_exports.string().regex(EXT_ID_REGEX),
6028
- name: external_exports.string().min(1),
6029
- version: external_exports.string().min(1),
6030
- apiVersion: external_exports.literal("1"),
6031
- runtime: external_exports.object({ startCommand: external_exports.string().min(1) }).passthrough().optional(),
6032
- entry: external_exports.object({
6033
- url: external_exports.string().url().refine(isAllowedHostedUrl, {
6034
- message: "INVALID_URL_SCHEME: only https or http://localhost is allowed"
6035
- })
6036
- }).strict().optional()
6037
- }).passthrough().superRefine((m2, ctx) => {
6038
- const hasRuntime = !!m2.runtime;
6039
- const hasUrl = !!m2.entry?.url;
6040
- if (hasRuntime && hasUrl) {
6041
- ctx.addIssue({
6042
- code: external_exports.ZodIssueCode.custom,
6043
- message: "INVALID_MANIFEST: entry.url and runtime cannot coexist"
6044
- });
6045
- }
6046
- if (!hasRuntime && !hasUrl) {
6047
- ctx.addIssue({
6048
- code: external_exports.ZodIssueCode.custom,
6049
- message: "INVALID_MANIFEST: must have either entry.url or runtime"
6050
- });
6051
- }
6052
- });
6053
- ExtensionTargetSchema = external_exports.discriminatedUnion("kind", [
6054
- external_exports.object({ kind: external_exports.literal("local"), port: external_exports.number().int().min(1).max(65535) }),
6055
- external_exports.object({ kind: external_exports.literal("hosted"), url: external_exports.string().url() })
6056
- ]);
6057
- ExtensionRecordSchema = external_exports.discriminatedUnion("state", [
6058
- external_exports.object({
6059
- extId: external_exports.string(),
6060
- manifest: ExtensionManifestSchema,
6061
- state: external_exports.literal("stopped")
6062
- }),
6063
- external_exports.object({
6064
- extId: external_exports.string(),
6065
- manifest: ExtensionManifestSchema,
6066
- state: external_exports.literal("starting")
6067
- }),
6068
- external_exports.object({
6069
- extId: external_exports.string(),
6070
- manifest: ExtensionManifestSchema,
6071
- state: external_exports.literal("running"),
6072
- target: ExtensionTargetSchema
6073
- }),
6074
- external_exports.object({
6075
- extId: external_exports.string(),
6076
- manifest: ExtensionManifestSchema,
6077
- state: external_exports.literal("crashed")
6078
- }),
6079
- external_exports.object({
6080
- extId: external_exports.string(),
6081
- manifest: external_exports.unknown().nullable(),
6082
- state: external_exports.literal("invalid"),
6083
- invalidReason: external_exports.string().min(1)
6084
- })
6085
- ]);
6086
- PublishedSnapshotSchema = external_exports.object({
6087
- snapshotHash: external_exports.string().min(1),
6088
- version: external_exports.string().min(1),
6089
- publishedAt: external_exports.number()
6090
- });
6091
- ChannelRefSchema = external_exports.discriminatedUnion("kind", [
6092
- external_exports.object({
6093
- kind: external_exports.literal("p2p-tunnel"),
6094
- ownerPrincipalId: external_exports.string().min(1),
6095
- extId: external_exports.string().min(1)
6096
- })
6097
- ]);
6098
- SourceRefSchema = external_exports.discriminatedUnion("kind", [
6099
- external_exports.object({
6100
- kind: external_exports.literal("p2p-tunnel"),
6101
- ownerPrincipalId: external_exports.string().min(1),
6102
- extId: external_exports.string().min(1),
6103
- snapshotHash: external_exports.string().min(1)
6104
- })
6105
- ]);
6106
- PublishedExtensionRecordSchema = external_exports.object({
6107
- extId: external_exports.string().min(1),
6108
- name: external_exports.string().min(1),
6109
- version: external_exports.string().min(1),
6110
- contentHash: external_exports.string().min(1),
6111
- publishedAt: external_exports.number()
6044
+ sessionId: external_exports.string().min(1),
6045
+ force: external_exports.boolean().optional()
6046
+ }).strict();
6047
+ StartDevServerResultSchema = external_exports.object({
6048
+ project: ProjectMetadataSchema
6049
+ }).strict();
6050
+ ASSISTANT_REPORTABLE_STAGES = [
6051
+ "installing",
6052
+ "failed"
6053
+ ];
6054
+ ReportStageArgsSchema = external_exports.object({
6055
+ sessionId: external_exports.string().min(1),
6056
+ stage: external_exports.enum(ASSISTANT_REPORTABLE_STAGES),
6057
+ /** stage='failed' 时必填的原因(一句话),其它 stage optional */
6058
+ reason: external_exports.string().optional()
6059
+ }).strict();
6060
+ ReportStageResultSchema = external_exports.object({
6061
+ ok: external_exports.literal(true)
6062
+ }).strict();
6063
+ StopDevServerArgsSchema = external_exports.object({
6064
+ sessionId: external_exports.string().min(1)
6065
+ }).strict();
6066
+ StopDevServerResultSchema = external_exports.object({
6067
+ ok: external_exports.literal(true)
6068
+ }).strict();
6069
+ AppBuilderProjectUpdatedEventSchema = external_exports.object({
6070
+ type: external_exports.literal("appBuilder:project-updated"),
6071
+ project: ProjectWithStatusSchema,
6072
+ stage: ProjectStageSchema,
6073
+ /** stage='failed' 时的失败原因 */
6074
+ stageReason: external_exports.string().optional()
6075
+ }).strict();
6076
+ PublishArgsSchema = external_exports.object({
6077
+ name: external_exports.string().regex(projectNameRegex)
6112
6078
  });
6113
- PublishCheckSchema = external_exports.discriminatedUnion("kind", [
6114
- external_exports.object({ kind: external_exports.literal("clean") }),
6115
- external_exports.object({
6116
- kind: external_exports.literal("ready-new-version"),
6117
- fromVersion: external_exports.string().min(1),
6118
- toVersion: external_exports.string().min(1)
6119
- }),
6120
- external_exports.object({
6121
- kind: external_exports.literal("error-same-hash"),
6122
- version: external_exports.string().min(1)
6123
- }),
6124
- external_exports.object({
6125
- kind: external_exports.literal("error-version-not-bumped"),
6126
- localVersion: external_exports.string().min(1),
6127
- publishedVersion: external_exports.string().min(1)
6128
- }),
6129
- external_exports.object({
6130
- kind: external_exports.literal("error-version-regression"),
6131
- localVersion: external_exports.string().min(1),
6132
- publishedVersion: external_exports.string().min(1)
6133
- })
6134
- ]);
6135
- PublishStatusResultSchema = external_exports.object({
6136
- localManifest: external_exports.object({
6137
- name: external_exports.string().min(1),
6138
- version: external_exports.string().min(1),
6139
- contentHash: external_exports.string().min(1)
6140
- }),
6141
- publishState: external_exports.discriminatedUnion("kind", [
6142
- external_exports.object({ kind: external_exports.literal("unpublished") }),
6143
- external_exports.object({
6144
- kind: external_exports.literal("published"),
6145
- version: external_exports.string().min(1),
6146
- contentHash: external_exports.string().min(1),
6147
- publishedAt: external_exports.number()
6148
- })
6149
- ]),
6150
- check: PublishCheckSchema
6079
+ PublishResultSchema = external_exports.object({
6080
+ jobId: external_exports.string().min(1),
6081
+ status: external_exports.enum(["started", "already-publishing"])
6082
+ }).strict();
6083
+ DismissPublishJobArgsSchema = external_exports.object({
6084
+ name: external_exports.string().regex(projectNameRegex)
6151
6085
  });
6086
+ DismissPublishJobResultSchema = external_exports.object({
6087
+ ok: external_exports.literal(true)
6088
+ }).strict();
6089
+ AppBuilderPublishProgressEventSchema = external_exports.object({
6090
+ type: external_exports.literal("appBuilder:publish-progress"),
6091
+ name: external_exports.string().regex(projectNameRegex),
6092
+ jobId: external_exports.string().min(1),
6093
+ stage: external_exports.enum(["build", "deploy", "verify"]),
6094
+ status: external_exports.enum(["started", "completed"])
6095
+ }).strict();
6096
+ AppBuilderPublishFailedEventSchema = external_exports.object({
6097
+ type: external_exports.literal("appBuilder:publish-failed"),
6098
+ name: external_exports.string().regex(projectNameRegex),
6099
+ jobId: external_exports.string().min(1),
6100
+ stage: external_exports.enum(["build", "deploy", "verify", "unknown"]),
6101
+ errorSummary: external_exports.string()
6102
+ }).strict();
6152
6103
  }
6153
6104
  });
6154
6105
 
6155
- // ../protocol/src/feishu-auth.ts
6156
- var FEISHU_GATED_METHODS, DeviceEntrySchema, DeviceListResponseSchema, DeviceConnectArgsSchema, DeviceConnectResponseSchema, FeishuIdentitySchema, AuthLoginStartResponseSchema, AuthGetIdentityResponseSchema, AuthLogoutResponseSchema, AuthLoginDoneEventSchema, AuthLoginFailedEventSchema;
6157
- var init_feishu_auth = __esm({
6158
- "../protocol/src/feishu-auth.ts"() {
6106
+ // ../protocol/src/methods.ts
6107
+ function methodArgFields(method) {
6108
+ let schema = METHOD_DOCS[method].args;
6109
+ if (!schema) return null;
6110
+ for (let i = 0; i < 5 && schema && !schema.shape; i += 1) {
6111
+ schema = schema._def?.schema;
6112
+ }
6113
+ const shape = schema?.shape;
6114
+ if (!shape) return null;
6115
+ return Object.entries(shape).map(([name, def]) => ({ name, required: !def.isOptional() }));
6116
+ }
6117
+ var NO_ARGS, METHOD_DOCS, METHOD_NAMES, RPC_METHOD_STATUSES, RpcMethodStatusSchema, RpcMethodInfoSchema, MetaMethodsResultSchema;
6118
+ var init_methods = __esm({
6119
+ "../protocol/src/methods.ts"() {
6159
6120
  "use strict";
6160
6121
  init_zod();
6161
- FEISHU_GATED_METHODS = [
6162
- // 联系人列表(device:connect 落同一 store;list 读 / remove 删)
6163
- "contact:list",
6164
- "contact:remove",
6165
- // DM / 跨用户通知
6166
- "inbox:list",
6167
- "inbox:markRead",
6168
- "inbox:postMessage",
6169
- // mirror peer sessions(远端会话镜像)
6170
- "peerSession:upsert",
6171
- "peerSession:remove",
6172
- // 设备目录 + 连接(决策 #15:daemon 代理中心 server,需要 owner 的 ttcJwt)
6173
- "device:list",
6174
- "device:connect"
6175
- ];
6176
- DeviceEntrySchema = external_exports.object({
6177
- /**
6178
- * 设备标识(决策 #15:daemon 本地生成的 dev-<uuid>,与人的身份 unionId 无关)。
6179
- * 中心 server clawd_devices 注册表仅作服务发现(url 下发 + 目录),不在安全路径上。
6180
- */
6181
- deviceId: external_exports.string().min(1),
6182
- /** 显示名 */
6122
+ init_attachment_schemas();
6123
+ init_contact_handshake();
6124
+ init_contact_remote_access();
6125
+ init_contact();
6126
+ init_feishu_auth();
6127
+ init_dispatch();
6128
+ init_extension();
6129
+ init_inbox();
6130
+ init_peer_exec();
6131
+ init_shift_internal();
6132
+ init_persona_schemas();
6133
+ init_schemas();
6134
+ NO_ARGS = external_exports.object({});
6135
+ METHOD_DOCS = {
6136
+ "session:create": {
6137
+ summary: "\u65B0\u5EFA\u4F1A\u8BDD\u5E76\u62C9\u8D77 tool \u8FDB\u7A0B\uFF08claude / codex\uFF09\u3002**cwd \u4E0E ownerPersonaId \u81F3\u5C11\u4F20\u4E00\u4E2A**\uFF08\u5E26 ownerPersonaId \u65F6 cwd \u7531 daemon \u6D3E\u751F\uFF09\u2014\u2014\u8FD9\u6761\u4E92\u65A5\u7EA6\u675F\u662F schema \u7684 refine\uFF0C\u53CD\u5C04\u4E0D\u51FA\u6765",
6138
+ args: SessionCreateArgs
6139
+ },
6140
+ "session:list": {
6141
+ summary: "\u5217\u51FA\u5F53\u524D\u8EAB\u4EFD\u53EF\u89C1\u7684\u4F1A\u8BDD\uFF08owner \u5168\u91CF\uFF1Bguest \u9650\u88AB\u6388\u6743 persona\uFF09",
6142
+ args: SessionListArgs
6143
+ },
6144
+ "session:get": {
6145
+ summary: "\u53D6\u5355\u4E2A\u4F1A\u8BDD\u7684\u5B8C\u6574 SessionFile\uFF08\u5143\u6570\u636E + \u72B6\u6001\uFF09",
6146
+ args: SessionIdArgs
6147
+ },
6148
+ "session:update": {
6149
+ summary: "\u6539\u4F1A\u8BDD\u5143\u6570\u636E\uFF0C\u4E0D\u5F71\u54CD\u8FDB\u7A0B\u3002patch \u5141\u8BB8\u7684\u952E\uFF1Alabel / model / permissionMode / effort / cwd / iconKey\u2014\u2014**\u4F20\u522B\u7684\u952E\u4F1A\u88AB\u9759\u9ED8\u4E22\u5F03**\uFF08zod strip\uFF09\uFF0Chandler \u7167\u6837\u8FD4 ok",
6150
+ args: SessionUpdateArgs
6151
+ },
6152
+ "session:delete": {
6153
+ summary: "\u5220\u4F1A\u8BDD\uFF1A\u505C\u8FDB\u7A0B + \u5220 SessionFile\uFF0C\u5E76\u8054\u52A8\u6E05\u7406\u7ED1\u5B9A\u7684 app-builder project",
6154
+ args: SessionIdArgs
6155
+ },
6156
+ "session:send": {
6157
+ summary: "\u5411\u4F1A\u8BDD\u53D1\u4E00\u6761\u7528\u6237\u6D88\u606F\uFF08\u89E6\u53D1\u65B0\u4E00\u8F6E turn\uFF09",
6158
+ args: SessionSendArgs
6159
+ },
6160
+ "session:currentTurnSender": {
6161
+ summary: "\u67E5\u5F53\u524D turn \u7684\u9A71\u52A8\u8005\uFF08owner / guest \u7684 SenderInfo\uFF09\u3002\u7701\u7565 sessionId \u6216\u4F20\u7A7A\u4E32 \u2192 \u76F4\u63A5\u8FD4 sender:null\uFF0C\u4E0D\u62A5\u9519",
6162
+ args: SessionCurrentTurnSenderArgs
6163
+ },
6164
+ "session:stop": {
6165
+ summary: "\u505C\u6389\u4F1A\u8BDD\u7684 tool \u8FDB\u7A0B\uFF08\u6740\u8FDB\u7A0B\uFF0C\u4F1A\u8BDD\u672C\u8EAB\u4FDD\u7559\uFF09",
6166
+ args: SessionIdArgs
6167
+ },
6168
+ "session:interrupt": {
6169
+ summary: "\u6E29\u67D4\u4E2D\u65AD\u5F53\u524D\u8F6E\u6B21\uFF0C\u4E0D\u6740\u8FDB\u7A0B\uFF08\u8D70 CC IPC control_request.subtype=interrupt\uFF09",
6170
+ args: SessionInterruptArgs
6171
+ },
6172
+ "session:rewind": {
6173
+ summary: "\u56DE\u6EDA\u5230\u6307\u5B9A user message\uFF0C\u5E76\u64A4\u9500\u5176\u540E CC \u505A\u7684\u6587\u4EF6\u7F16\u8F91",
6174
+ args: SessionRewindArgs
6175
+ },
6176
+ "session:rewind-diff": {
6177
+ summary: "\u56DE\u6EDA\u9884\u89C8\uFF1A\u8BFB ~/.claude/file-history \u5FEB\u7167 + \u78C1\u76D8\u73B0\u72B6\u7B97\u771F\u5B9E diff\uFF0C\u4E0D\u4F9D\u8D56 CC \u8FDB\u7A0B",
6178
+ args: SessionRewindDiffArgs
6179
+ },
6180
+ "session:rewindable-message-ids": {
6181
+ summary: "\u4E00\u6B21\u6027\u62FF\u5230\u300C\u6709\u771F\u5B9E diff\u300D\u7684 user message id \u96C6\u5408\uFF0CUI \u636E\u6B64\u51B3\u5B9A\u54EA\u4E9B\u6D88\u606F\u663E\u793A\u56DE\u6EDA\u6309\u94AE",
6182
+ args: SessionRewindableMessageIdsArgs
6183
+ },
6184
+ "session:fork": {
6185
+ summary: "\u4ECE\u6307\u5B9A message \u5904 fork \u51FA\u65B0 transcript\uFF08\u622A\u65AD + \u91CD\u5199 sessionId/parentUuid\uFF09\uFF0C\u8FD4\u56DE\u65B0 toolSessionId\uFF1B\u4E0D\u81EA\u52A8\u62C9\u8D77\u8FDB\u7A0B",
6186
+ args: SessionForkArgs
6187
+ },
6188
+ "session:new": {
6189
+ summary: "\u5728**\u5DF2\u6709**\u4F1A\u8BDD\u4E0A\u6E05\u7A7A\u4E0A\u4E0B\u6587\u5F00\u65B0\u4E00\u8F6E\uFF0C\u76F8\u5F53\u4E8E CC \u7684 /clear\uFF08\u4E0D\u662F\u5EFA\u65B0\u4F1A\u8BDD\u2014\u2014\u5EFA\u65B0\u4F1A\u8BDD\u7528 session:create\uFF09",
6190
+ args: SessionIdArgs
6191
+ },
6192
+ "session:resume": {
6193
+ summary: "\u628A\u4F1A\u8BDD\u6062\u590D\u5230\u6307\u5B9A\u7684 tool \u4F1A\u8BDD\uFF08CC transcript\uFF09\u4E0A\u7EE7\u7EED",
6194
+ args: SessionResumeArgs
6195
+ },
6196
+ "session:observe": {
6197
+ summary: "\u6302 observer \u76D1\u542C\u8BE5\u4F1A\u8BDD\u7684 CC jsonl\uFF0C\u628A daemon \u4E4B\u5916\u542F\u52A8\u7684 CC \u6D3B\u52A8\u56DE\u704C\u8FDB\u6765\uFF08\u591A\u7AEF\u5171\u4EAB / \u63A5\u7BA1\u5916\u90E8\u4F1A\u8BDD\uFF09\u3002\u4EC5 claude \u652F\u6301",
6198
+ args: SessionObserveArgs
6199
+ },
6200
+ "session:events": {
6201
+ summary: "\u62C9\u53D6\u4F1A\u8BDD\u7684\u5386\u53F2\u4E8B\u4EF6\uFF08\u6309 seq \u589E\u91CF\uFF09\uFF0C\u7528\u4E8E\u65AD\u7EBF\u91CD\u8FDE\u8865\u5E27",
6202
+ args: SessionEventsArgs
6203
+ },
6204
+ "session:subscribe": {
6205
+ summary: "\u8BA2\u9605\u8BE5\u4F1A\u8BDD\u7684 push \u5E27\uFF08\u672C\u8FDE\u63A5\u751F\u6548\uFF0CrefCount \u8BA1\u6570\uFF09\u3002**\u7701\u7565 sessionId = \u4E0D\u5EFA\u7ACB\u4EFB\u4F55\u8BA2\u9605**\uFF0C\u4F46\u7167\u6837\u8FD4 subscribed \u2014\u2014 \u4E0D\u662F\u300C\u8BA2\u9605\u5168\u90E8\u300D",
6206
+ args: SessionSubscribeArgs
6207
+ },
6208
+ "session:unsubscribe": {
6209
+ summary: "\u53D6\u6D88\u8BA2\u9605\u8BE5\u4F1A\u8BDD\u7684 push \u5E27\u3002\u7701\u7565 sessionId \u65F6\u4E0D\u53D6\u6D88\u4EFB\u4F55\u8BA2\u9605\uFF0C\u7167\u6837\u8FD4 ok",
6210
+ args: SessionSubscribeArgs
6211
+ },
6212
+ "session:pin": {
6213
+ summary: "\u7F6E\u9876 / \u53D6\u6D88\u7F6E\u9876\u4F1A\u8BDD",
6214
+ args: SessionPinArgs
6215
+ },
6216
+ "session:markRead": {
6217
+ summary: "\u6E05\u6389\u4F1A\u8BDD\u7684\u5171\u4EAB\u672A\u8BFB\u6807\u8BB0\u5E76\u5E7F\u64AD session:info\uFF1B\u5E42\u7B49",
6218
+ args: SessionIdArgs
6219
+ },
6220
+ "session:reorderPins": {
6221
+ summary: "\u6574\u4F53\u91CD\u5199\u6240\u6709\u7F6E\u9876\u4F1A\u8BDD\u7684\u6392\u5E8F\uFF08sidebar \u62D6\u62FD\u5B8C\u6210\u65F6\u8C03\uFF09",
6222
+ args: SessionReorderPinsArgs
6223
+ },
6224
+ "peerSession:upsert": {
6225
+ summary: "\u5199\u5165 / \u66F4\u65B0\u4E00\u6761 mirror SessionFile \u2014\u2014 \u300C\u6211\u5728\u670B\u53CB daemon \u4E0A\u521B\u5EFA\u7684\u4F1A\u8BDD\u300D\u5728\u672C\u673A\u7684\u526F\u672C\uFF0C\u4EC5\u4F9B sidebar \u8DE8\u8BBE\u5907\u805A\u5408\uFF1Bdaemon \u53EA dumb \u5199\uFF0C\u4E0D\u5E7F\u64AD\u4EFB\u4F55 push \u5E27",
6226
+ args: PeerSessionUpsertArgs
6227
+ },
6228
+ "peerSession:remove": {
6229
+ summary: "\u5220\u9664\u4E00\u6761 mirror SessionFile\uFF08\u540C\u6837\u4E0D\u5E7F\u64AD\uFF09",
6230
+ args: PeerSessionRemoveArgs
6231
+ },
6232
+ "permission:respond": {
6233
+ summary: "\u56DE\u5E94 CC \u7684\u6743\u9650\u8BF7\u6C42\uFF08\u5141\u8BB8 / \u62D2\u7EDD / \u8BB0\u4F4F\u89C4\u5219\uFF09",
6234
+ args: PermissionRespondArgs
6235
+ },
6236
+ "session:answerQuestion": {
6237
+ summary: "\u56DE\u586B AskUserQuestion \u8868\u5355\u7B54\u6848\uFF0Cdaemon \u5408\u5E76\u8FDB updated_input \u5199 control_response \u7ED9 CC",
6238
+ args: AnswerQuestionArgs
6239
+ },
6240
+ "session:cancelQuestion": {
6241
+ summary: "\u7528\u6237\u8DF3\u8FC7 AskUserQuestion\uFF1Adaemon \u56DE allow + \u7A7A\u7B54\u6848\u8BA9 tool \u8D70\u7A7A\u8DEF\u5F84\uFF0C\u5E76\u5E7F\u64AD cleared \u5E27",
6242
+ args: CancelQuestionArgs
6243
+ },
6244
+ "history:projects": {
6245
+ summary: "\u5217\u51FA CC \u5386\u53F2\u91CC\u7684\u5168\u90E8\u9879\u76EE\uFF08\u6309 projectPath \u805A\u5408\uFF09\uFF1Bguest \u53EA\u770B\u5230\u81EA\u5DF1\u88AB\u6388\u6743 persona \u5B50\u6811\u4E0B\u7684",
6246
+ args: NO_ARGS
6247
+ },
6248
+ "history:list": {
6249
+ summary: "\u5217\u51FA\u67D0\u4E2A\u9879\u76EE\u4E0B\u7684\u5386\u53F2\u4F1A\u8BDD",
6250
+ args: HistoryListArgs
6251
+ },
6252
+ "history:read": {
6253
+ summary: "\u8BFB\u4E00\u6761\u5386\u53F2\u4F1A\u8BDD\u7684\u5B8C\u6574\u6D88\u606F\uFF08\u89E3\u6790 CC jsonl\uFF09",
6254
+ args: HistoryReadArgs
6255
+ },
6256
+ "history:subagents": {
6257
+ summary: "\u5217\u51FA\u67D0\u6B21\u4F1A\u8BDD\u91CC\u7684 subagent \u8FD0\u884C\u8BB0\u5F55",
6258
+ args: HistorySubagentsArgs
6259
+ },
6260
+ "history:subagent-read": {
6261
+ summary: "\u8BFB\u4E00\u6761 subagent \u7684\u5B8C\u6574\u8BB0\u5F55",
6262
+ args: HistorySubagentReadArgs
6263
+ },
6264
+ "history:recentDirs": {
6265
+ summary: "\u6700\u8FD1\u7528\u8FC7\u7684\u5DE5\u4F5C\u76EE\u5F55\u5217\u8868\uFF08\u6309 cwd \u53BB\u91CD\u3001\u53D6\u6700\u65B0 updatedAt\uFF09\u3002\u65E0\u53C2\u6570",
6266
+ args: NO_ARGS
6267
+ },
6268
+ "workspace:list": {
6269
+ summary: "\u5217\u76EE\u5F55\u5185\u5BB9\uFF08\u6587\u4EF6\u6D4F\u89C8\uFF09\uFF1Bguest \u88AB\u9650\u5236\u5728\u88AB\u6388\u6743 persona \u5B50\u6811\u5185",
6270
+ args: WorkspaceListArgs
6271
+ },
6272
+ "workspace:read": {
6273
+ summary: "\u8BFB\u6587\u4EF6\u5185\u5BB9\uFF1Bguest \u8DEF\u5F84\u8FB9\u754C\u4E0E workspace:list \u540C",
6274
+ args: WorkspaceReadArgs
6275
+ },
6276
+ "shift:list": {
6277
+ summary: "\u5217\u51FA owner \u7684\u5168\u90E8 shift\uFF08\u6392\u73ED\uFF09\uFF0C\u7ED9 UI \u65E5\u5386\u6E32\u67D3\u7528\uFF1Bowner-only",
6278
+ args: NO_ARGS
6279
+ },
6280
+ "shift-internal:add": {
6281
+ summary: "\u6392\u4E00\u4E2A shift\uFF08\u5230\u70B9\u81EA\u52A8\u62C9\u8D77 persona \u5E72\u6D3B\uFF09\u3002\u7701\u7565 targetPersona = \u6D3E\u7ED9\u8C03\u7528\u65B9\u81EA\u5DF1",
6282
+ args: ShiftInternalAddArgs
6283
+ },
6284
+ "shift-internal:list": {
6285
+ summary: "\u5217 shift\u3002\u7701\u7565 onlyMine \u9ED8\u8BA4 true \u2014\u2014 \u53EA\u5217\u672C persona \u5EFA\u7684",
6286
+ args: ShiftInternalListArgs
6287
+ },
6288
+ "shift-internal:cancel": {
6289
+ summary: "\u53D6\u6D88 shift\uFF08\u4EC5\u521B\u5EFA\u5B83\u7684 persona \u53EF\u64CD\u4F5C\uFF09",
6290
+ args: ShiftInternalCancelArgs
6291
+ },
6292
+ "shift-internal:update": {
6293
+ summary: "\u4FEE\u6539 shift \u5B57\u6BB5\uFF08\u4EC5\u521B\u5EFA\u8005\uFF09\u3002patch \u5141\u8BB8\u7684\u952E\uFF1Aname / schedule / prompt / targetPersona / timeoutMs / enabled\uFF1Bschedule \u53D8\u4E86 store \u81EA\u52A8\u91CD\u7B97 nextRunAtMs",
6294
+ args: ShiftInternalUpdateArgs
6295
+ },
6296
+ "shift-internal:history": {
6297
+ summary: "\u67E5 shift \u7684\u6267\u884C\u5386\u53F2\uFF08\u4EC5\u521B\u5EFA\u8005\uFF09",
6298
+ args: ShiftInternalHistoryArgs
6299
+ },
6300
+ "skills:list": {
6301
+ summary: "\u626B\u63CF\u5E76\u5217\u51FA\u8BE5\u76EE\u5F55\u53EF\u7528\u7684 skill",
6302
+ args: SkillsListArgs
6303
+ },
6304
+ "agents:list": {
6305
+ summary: "\u626B\u63CF\u5E76\u5217\u51FA\u8BE5\u76EE\u5F55\u53EF\u7528\u7684 subagent \u5B9A\u4E49",
6306
+ args: AgentsListArgs
6307
+ },
6308
+ "git:root": {
6309
+ summary: "\u53D6\u8BE5\u8DEF\u5F84\u6240\u5C5E git \u4ED3\u5E93\u7684\u6839\u76EE\u5F55\uFF08\u4E0D\u5728\u4ED3\u5E93\u91CC\u8FD4 null\uFF09",
6310
+ args: GitRootArgs
6311
+ },
6312
+ "git:branch": {
6313
+ summary: "\u53D6\u5F53\u524D\u5206\u652F\u540D",
6314
+ args: GitBranchArgs
6315
+ },
6316
+ "git:branches": {
6317
+ summary: "\u5217\u51FA\u672C\u5730\u5206\u652F",
6318
+ args: GitBranchesArgs
6319
+ },
6320
+ "capabilities:get": {
6321
+ summary: "\u53D6\u67D0\u4E2A tool \u7684\u80FD\u529B\u96C6\uFF1A\u53EF\u7528\u6A21\u578B\u5217\u8868 / permissionModes / configSchema",
6322
+ args: CapabilitiesGetArgs
6323
+ },
6324
+ "persona:create": {
6325
+ summary: "\u65B0\u5EFA persona\uFF08\u5199 PersonaFile + CLAUDE.md \u9AA8\u67B6\uFF09\u3002owner-only",
6326
+ args: PersonaCreateArgsSchema
6327
+ },
6328
+ "persona:list": {
6329
+ summary: "\u5217\u51FA persona \u5143\u6570\u636E\uFF08\u4E0D\u542B CLAUDE.md \u6B63\u6587\uFF09\u3002owner \u8FD4\u5168\u91CF\u542B private\uFF1Bguest \u53EA\u8FD4 public \u4E14\u88AB\u6388\u6743\u7684",
6330
+ args: NO_ARGS
6331
+ },
6332
+ "persona:get": {
6333
+ summary: "\u53D6\u5355\u4E2A persona \u8BE6\u60C5\uFF0C**\u542B personality\uFF08CLAUDE.md \u6B63\u6587\uFF09**\u2014\u2014\u552F\u4E00\u643A\u5E26\u6B63\u6587\u7684 method",
6334
+ args: PersonaIdArgsSchema
6335
+ },
6336
+ "persona:update": {
6337
+ summary: "\u6539 persona\uFF08label / model / public / CLAUDE.md \u7B49\uFF09\u3002owner-only",
6338
+ args: PersonaUpdateArgsSchema
6339
+ },
6340
+ "persona:delete": {
6341
+ summary: "\u5220 persona\u3002owner-only",
6342
+ args: PersonaIdArgsSchema
6343
+ },
6344
+ "personaDispatch:run": {
6345
+ summary: "\u628A\u4EFB\u52A1\u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A persona\uFF08\u53EF\u8DE8\u8BBE\u5907\uFF09\uFF0C\u5F02\u6B65\u79D2\u56DE { dispatchId }\u3002targetPersona \u4E0E dispatchId **\u81F3\u5C11\u7ED9\u4E00\u4E2A**\uFF08\u524D\u8005\u65B0\u5F00\u3001\u540E\u8005\u7EED\u6D3E\uFF09\uFF1BdispatchId \u4E0E targetDeviceId **\u4E92\u65A5**",
6346
+ args: DispatchRunArgsSchema
6347
+ },
6348
+ "personaDispatch:complete": {
6349
+ summary: '\u88AB\u59D4\u6D3E\u65B9\u56DE\u62A5\u7ED3\u679C\uFF1A\u5199\u53F0\u8D26\u5E76\u628A\u7ED3\u679C\u6295\u9012\u56DE\u53D1\u8D77\u65B9\u4F1A\u8BDD\u3002outcome \u662F { kind:"success", text, filePaths? } \u6216 { kind:"failure", reason } \u4E8C\u9009\u4E00',
6350
+ args: DispatchCompleteArgsSchema
6351
+ },
6352
+ "personaDispatch:list": {
6353
+ summary: "\u67E5 dispatch \u53F0\u8D26\uFF08\u72B6\u6001 / \u7ED3\u679C / \u65F6\u95F4\u6233\uFF09\u3002\u7701\u7565 sourceSessionId = \u8FD4\u5168\u91CF",
6354
+ args: DispatchListArgsSchema
6355
+ },
6356
+ "personaDispatch:get": {
6357
+ summary: "\u67E5\u5355\u6761 dispatch \u53F0\u8D26\u7EC8\u6001\uFF1B\u8DE8\u8BBE\u5907\u65F6 A \u7AEF\u51ED connect token \u8F6E\u8BE2 B \u7AEF\u7528",
6358
+ args: DispatchGetArgsSchema
6359
+ },
6360
+ "peerExec:run": {
6361
+ summary: "\u5728\u8054\u7CFB\u4EBA\u8BBE\u5907\u4E0A\u8DD1\u4E00\u6761 bash \u547D\u4EE4\uFF08\u4E00\u53D1\u4E00\u6536\uFF0C\u65E0\u8DE8\u547D\u4EE4\u4F1A\u8BDD\u72B6\u6001\uFF09\u3002**\u672C\u673A\u53D1\u8D77\u5FC5\u586B peerDeviceId**\u2014\u2014\u7701\u7565\u4EC5\u7528\u4E8E\u5BF9\u7AEF guest \u53CD\u5411\u5165\u53E3\uFF0Cowner ctx \u7701\u7565\u4F1A\u88AB\u62D2\uFF1B\u9700\u5BF9\u65B9\u5F00\u4E86 remoteAccess",
6362
+ args: PeerExecRunArgsSchema
6363
+ },
6364
+ "session:pty:input": {
6365
+ summary: "\u628A\u7528\u6237\u952E\u76D8\u5B57\u8282\u5199\u8FDB pty stdin\uFF08\u4EC5 CLAWD_CC_MODE=tui\uFF09\u3002\u9AD8\u9891\u5E27\uFF0C\u4E0D\u5165 reducer\u3002body: { sessionId, data\uFF08base64-utf8\uFF09 }"
6366
+ },
6367
+ "session:pty:resize": {
6368
+ summary: "\u540C\u6B65\u7EC8\u7AEF\u5C3A\u5BF8\u7ED9 pty\uFF08\u4EC5 tui \u6A21\u5F0F\uFF09\u3002body: { sessionId, cols, rows }"
6369
+ },
6370
+ "session:pty:snapshot": {
6371
+ summary: "\u62C9\u5F53\u524D pty \u5C4F\u5E55\u5168\u91CF\u5FEB\u7167\uFF08\u5207\u56DE\u4F1A\u8BDD / \u5237\u65B0\u65F6\u7528\uFF09\uFF0C\u8FD4\u56DE { data, atSeq, popupKind }\uFF1B\u975E tui \u6216\u5DF2\u9000\u51FA\u65F6 data=null\u3002body: { sessionId }"
6372
+ },
6373
+ "attachment.signUrl": {
6374
+ summary: "\u7ED9\u5DF2\u5165\u7FA4\u7684\u6587\u4EF6\u7B7E\u53D1 HMAC \u4E0B\u8F7D URL\uFF08\u8DE8\u8BBE\u5907\u53EF\u76F4\u63A5\u6253\u5F00\uFF09",
6375
+ args: AttachmentSignUrlArgs
6376
+ },
6377
+ "attachment.groupAdd": {
6378
+ summary: "\u628A\u6587\u4EF6\u767B\u8BB0\u8FDB\u672C\u4F1A\u8BDD\u7684\u5171\u4EAB\u6E05\u5355\uFF08\u7B7E URL \u524D\u5FC5\u987B\u5148\u5165\u7FA4\uFF09",
6379
+ args: AttachmentGroupAddArgs
6380
+ },
6381
+ "attachment.groupRemove": {
6382
+ summary: "\u628A\u6587\u4EF6\u79FB\u51FA\u5171\u4EAB\u6E05\u5355",
6383
+ args: AttachmentGroupRemoveArgs
6384
+ },
6385
+ "attachment.groupList": {
6386
+ summary: "\u5217\u51FA\u672C\u4F1A\u8BDD\u5171\u4EAB\u6E05\u5355\u91CC\u7684\u6587\u4EF6",
6387
+ args: AttachmentGroupListArgs
6388
+ },
6389
+ "inbox:list": {
6390
+ summary: "\u62C9\u67D0\u4E2A peer \u7684 DM / \u901A\u77E5\u961F\u5217",
6391
+ args: InboxListArgsSchema
6392
+ },
6393
+ "inbox:markRead": {
6394
+ summary: "\u628A\u67D0 peer \u961F\u5217\u6807\u8BB0\u4E3A\u5DF2\u8BFB\u5230\u67D0\u65F6\u95F4\u70B9",
6395
+ args: InboxMarkReadArgsSchema
6396
+ },
6397
+ "inbox:postMessage": {
6398
+ summary: "\u6295\u9012\u4E00\u6761 P2P IM \u6D88\u606F\uFF08\u53CC\u6295\uFF1A\u672C\u673A\u843D\u5E93 + \u8F6C\u53D1\u5BF9\u7AEF\uFF09\u3002**owner \u8C03\u7528\u5FC5\u586B peerDeviceId**\uFF0C\u4EC5 guest \u53EF\u7701\uFF08\u4ECE ctx \u63A8\uFF09",
6399
+ args: InboxPostMessageArgsSchema
6400
+ },
6401
+ "inbox:sendDm": {
6402
+ summary: "\u4EE5\u5F53\u524D\u4F1A\u8BDD\u7684\u8EAB\u4EFD\u53D1\u4E00\u6761 DM\uFF08\u53D1\u4FE1\u4EBA\u7531 session scope \u5F52\u56E0\uFF0C\u4E0D\u53EF\u4F2A\u9020\uFF09\u3002**owner \u9A71\u52A8\u7684\u4F1A\u8BDD\u5FC5\u586B peerDeviceId**\uFF0Cguest \u9A71\u52A8\u7684\u53EF\u7701",
6403
+ args: InboxSendDmArgsSchema
6404
+ },
6405
+ "contact:list": {
6406
+ summary: "\u5217\u51FA\u8054\u7CFB\u4EBA\uFF08\u5DF2\u5EFA\u8054\u7684\u8BBE\u5907\uFF09\u3002owner-only",
6407
+ args: NO_ARGS
6408
+ },
6409
+ "contact:pin": {
6410
+ summary: "\u7F6E\u9876 / \u53D6\u6D88\u7F6E\u9876\u8054\u7CFB\u4EBA",
6411
+ args: ContactPinArgsSchema
6412
+ },
6413
+ "contact:remove": {
6414
+ summary: "\u5220\u9664\u8054\u7CFB\u4EBA\u5E76\u6E05\u6389\u5BF9\u5E94\u7684 inbox \u961F\u5217",
6415
+ args: ContactRemoveArgsSchema
6416
+ },
6417
+ "contact:setRemoteAccess": {
6418
+ summary: "\u5F00\u5173\u67D0\u8054\u7CFB\u4EBA\u7684\u8FDC\u7A0B\u8BBF\u95EE\u6388\u6743\uFF08\u63A7\u5236\u5B83\u80FD\u5426\u53CD\u5411 peerExec \u6211\u7684\u8BBE\u5907\uFF09",
6419
+ args: ContactSetRemoteAccessArgsSchema
6420
+ },
6421
+ "contact:handshake": {
6422
+ summary: "\u53CC\u5411\u786E\u8BA4\u5EFA\u8054\u63E1\u624B\uFF1A\u8FDE\u63A5\u65B9\u81EA\u62A5 selfUrl\uFF0C\u88AB\u8FDE\u65B9\u843D\u5E93 + \u5E7F\u64AD\u540E\u56DE\u8EAB\u4EFD\u8F7D\u8377\u3002\u7531 device:connect \u7684\u4E34\u65F6\u8FDE\u63A5\u8C03\u7528",
6423
+ args: ContactHandshakeArgsSchema
6424
+ },
6425
+ "visitor:list": {
6426
+ summary: "\u5217\u51FA\u767B\u5F55\u8BBF\u95EE\u8FC7\u672C\u673A public persona \u7684 web \u8BBF\u5BA2\u3002owner-only",
6427
+ args: NO_ARGS
6428
+ },
6429
+ "whoami": {
6430
+ summary: "\u8FD4\u56DE\u672C\u8FDE\u63A5\u7684\u8EAB\u4EFD\uFF1Aowner \u663E\u793A\u540D + capability wire \u5F62\u6001 + \u88AB\u6388\u6743\u7684 persona \u5217\u8868\u3002\u4EFB\u4F55 authed \u8FDE\u63A5\u53EF\u8C03",
6431
+ args: NO_ARGS
6432
+ },
6433
+ "info": {
6434
+ summary: "daemon \u8FD0\u884C\u65F6\u4FE1\u606F\uFF1A\u7248\u672C / \u534F\u8BAE\u7248\u672C / \u4E3B\u673A / \u53EF\u7528 tool / \u5728\u8DD1\u7684\u4F1A\u8BDD / tunnel URL \u7B49",
6435
+ args: NO_ARGS
6436
+ },
6437
+ "ping": {
6438
+ summary: "\u5B58\u6D3B\u63A2\u6D4B\uFF0C\u56DE pong",
6439
+ args: NO_ARGS
6440
+ },
6441
+ "meta:methods": {
6442
+ summary: "RPC \u81EA\u7701\uFF1A\u8FD4\u56DE METHOD_NAMES \u5168\u96C6 + **\u5BF9\u672C\u8FDE\u63A5**\u7684\u53EF\u8C03\u7528\u6027\u4E09\u6001\uFF08allowed / conditional / denied\uFF09+ \u6BCF\u6761\u7684\u8BF4\u660E\u3002agent \u4FA7 clawd-rpc \u7684 list tool \u662F\u552F\u4E00\u6D88\u8D39\u65B9",
6443
+ args: NO_ARGS
6444
+ },
6445
+ "extension.list": {
6446
+ summary: "\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 extension",
6447
+ args: NO_ARGS
6448
+ },
6449
+ "extension.open": {
6450
+ summary: "\u62C9\u8D77\u67D0\u4E2A extension\uFF08local-spawn \u8D77\u8FDB\u7A0B\u5E76\u7B49 healthz\uFF09",
6451
+ args: ExtensionIdArgs
6452
+ },
6453
+ "extension.close": {
6454
+ summary: "\u5173\u6389\u67D0\u4E2A\u6B63\u5728\u8DD1\u7684 extension",
6455
+ args: ExtensionIdArgs
6456
+ },
6457
+ "extension.uninstall": {
6458
+ summary: "\u5378\u8F7D extension\uFF08\u5220\u5B89\u88C5\u76EE\u5F55\uFF09",
6459
+ args: ExtensionIdArgs
6460
+ },
6461
+ "extension.publish": {
6462
+ summary: "\u628A\u672C\u673A extension \u516C\u5F00\u5230\u5206\u4EAB\u9891\u9053\uFF0C\u4F9B\u8054\u7CFB\u4EBA\u62C9\u53D6\u3002owner-only",
6463
+ args: ExtensionPublishArgs
6464
+ },
6465
+ "extension.unpublish": {
6466
+ summary: "\u64A4\u56DE\u5DF2\u516C\u5F00\u7684 extension\u3002owner-only",
6467
+ args: ExtensionIdArgs
6468
+ },
6469
+ "extension.publish:status": {
6470
+ summary: "\u67E5\u67D0\u4E2A extension \u7684\u516C\u5F00\u72B6\u6001\u3002owner-only",
6471
+ args: ExtensionIdArgs
6472
+ },
6473
+ "extension.list-published": {
6474
+ summary: "\uFF08\u8DE8\u8BBE\u5907\uFF09\u4ECE\u5BF9\u7AEF owner \u62C9\u5B83\u516C\u5F00\u7684 extension \u6E05\u5355",
6475
+ args: NO_ARGS
6476
+ },
6477
+ "extension.fetchBundle": {
6478
+ summary: "\uFF08\u8DE8\u8BBE\u5907\uFF09\u4ECE\u5BF9\u7AEF owner \u4E0B\u8F7D extension bundle \u5B57\u8282\u3002extId \u5FC5\u4F20\u4F46\u4E0D\u53C2\u4E0E\u7D22\u5F15\u2014\u2014\u771F\u6B63\u7684\u952E\u662F snapshotHash\uFF08publish \u90A3\u523B\u51BB\u7ED3\u7684\u90A3\u4EFD\uFF0C\u4E0E owner \u5DE5\u4F5C\u76EE\u5F55\u540E\u7EED\u53D8\u5316\u89E3\u8026\uFF09",
6479
+ args: ExtensionFetchBundleArgs
6480
+ },
6481
+ "extension.install-from-channel": {
6482
+ summary: "\u5728\u81EA\u5DF1 daemon \u4E0A\u4ECE\u5206\u4EAB\u9891\u9053\u5B89\u88C5 extension",
6483
+ args: ExtensionFromChannelArgs
6484
+ },
6485
+ "extension.update-from-channel": {
6486
+ summary: "\u5728\u81EA\u5DF1 daemon \u4E0A\u628A\u5DF2\u88C5 extension \u66F4\u65B0\u5230\u9891\u9053\u6700\u65B0\u7248",
6487
+ args: ExtensionFromChannelArgs
6488
+ },
6489
+ "auth:login:start": {
6490
+ summary: "\u8D77\u98DE\u4E66\u767B\u5F55\u6D41\u7A0B\uFF1A\u751F\u6210 state \u5E76\u8FD4\u56DE\u6388\u6743 URL\uFF0C\u56DE\u8C03\u8D70 HTTP /auth/callback \u843D\u76D8\u3002owner-only",
6491
+ args: NO_ARGS
6492
+ },
6493
+ "auth:getIdentity": {
6494
+ summary: "\u53D6\u672C\u673A owner \u7684\u98DE\u4E66\u8EAB\u4EFD\uFF08ownerId / provider / displayName / unionId\uFF09+ **\u672C\u673A deviceId**\uFF08\u8BBE\u5907\u5C5E\u6027\uFF0C\u4E0E\u767B\u5F55\u6001\u65E0\u5173\uFF1Bdevice:connect / contact:* / inbox:* \u7684\u4E3B\u952E\u90FD\u662F\u5B83\uFF09\uFF1B\u7EDD\u4E0D\u8FD4\u56DE ttcToken",
6495
+ args: NO_ARGS
6496
+ },
6497
+ "auth:logout": {
6498
+ summary: "\u767B\u51FA\u98DE\u4E66\u8EAB\u4EFD\uFF08\u6E05 owner-identity \u843D\u76D8\uFF09\u3002owner-only",
6499
+ args: NO_ARGS
6500
+ },
6501
+ "device:list": {
6502
+ summary: "\u5217\u51FA\u516C\u5171\u8BBE\u5907\u76EE\u5F55\u91CC\u53EF\u8FDE\u63A5\u7684\u8BBE\u5907\uFF08daemon \u4EE3\u7406\u4E2D\u5FC3 server\uFF09\u3002owner-only",
6503
+ args: NO_ARGS
6504
+ },
6505
+ "device:connect": {
6506
+ summary: "\u8FDE\u63A5\u76EE\u6807\u8BBE\u5907\uFF1A\u6362 aud \u7ED1\u5B9A\u7684\u7B7E\u540D token \u5E76\u8D70 contact:handshake \u5EFA\u8054\u3002owner-only",
6507
+ args: DeviceConnectArgsSchema
6508
+ },
6509
+ "appBuilder:listProjects": {
6510
+ summary: "\u5217\u51FA app-builder project\uFF08\u542B dev server \u72B6\u6001\uFF09",
6511
+ args: ListProjectsArgsSchema
6512
+ },
6513
+ "appBuilder:getProject": {
6514
+ summary: "\u6309 sessionId \u53D6\u5355\u4E2A\u7ED1\u5B9A\u7684 project\uFF08\u542B status\uFF09",
6515
+ args: GetProjectArgsSchema
6516
+ },
6517
+ "appBuilder:createProject": {
6518
+ summary: "\u7ED9\u4F1A\u8BDD\u7ED1\u5B9A\u65B0 project\uFF1A\u6821\u9A8C\u540D + \u4ECE 6173-6182 \u6BB5\u5206\u914D\u7AEF\u53E3 + \u5EFA\u76EE\u5F55\u5199\u5143\u6570\u636E",
6519
+ args: CreateProjectArgsSchema
6520
+ },
6521
+ "appBuilder:deleteProject": {
6522
+ summary: "\u505C dev server + \u5220 project \u76EE\u5F55\uFF08\u7ED1\u5B9A\u7684\u4F1A\u8BDD\u4E0D\u5728\u8FD9\u91CC\u5220\uFF09",
6523
+ args: DeleteProjectArgsSchema
6524
+ },
6525
+ "appBuilder:updateProjectPort": {
6526
+ summary: "\u6539 dev server \u7AEF\u53E3\uFF08\u6821\u9A8C\u6BB5\u5185 + \u4E0D\u649E\u8F66\uFF09\u5E76\u91CD\u542F",
6527
+ args: UpdateProjectPortArgsSchema
6528
+ },
6529
+ "appBuilder:setProdUrl": {
6530
+ summary: "\u53D1\u5E03\u4E0A\u7EBF\u540E\u56DE\u586B\u7EBF\u4E0A\u5730\u5740\u5230 .clawd-project.json",
6531
+ args: SetProdUrlArgsSchema
6532
+ },
6533
+ "appBuilder:startDevServer": {
6534
+ summary: "scaffold + \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210\u540E\u663E\u5F0F\u62C9\u8D77 dev server\uFF08createProject \u4E0D\u518D\u81EA\u52A8\u8D77\uFF09",
6535
+ args: StartDevServerArgsSchema
6536
+ },
6537
+ "appBuilder:reportStage": {
6538
+ summary: "\u4E0A\u62A5\u811A\u624B\u67B6\u9636\u6BB5\uFF08scaffolding / installing / failed \u7B49\uFF09\uFF0Cdaemon \u5E7F\u64AD\u5E27\u8BA9 UI \u5207 PreviewPane",
6539
+ args: ReportStageArgsSchema
6540
+ },
6541
+ "appBuilder:stopDevServer": {
6542
+ summary: "\u6536\u8D77\u9884\u89C8\uFF1A\u505C\u6389 dev server\uFF08\u5BF9\u79F0 startDevServer\uFF09",
6543
+ args: StopDevServerArgsSchema
6544
+ },
6545
+ "appBuilder:publish": {
6546
+ summary: "\u53D1\u5E03\u4E0A\u7EBF\uFF1A\u4E32\u884C\u5316 spawn publish.sh \u5E76\u5E7F\u64AD\u9636\u6BB5\u8FDB\u5EA6\u5E27\uFF1B\u540C project \u5DF2\u6709 in-flight job \u65F6\u8FD4\u56DE already-publishing",
6547
+ args: PublishArgsSchema
6548
+ },
6549
+ "appBuilder:dismissPublishJob": {
6550
+ summary: "\u53D6\u6D88 in-flight publish\uFF08SIGTERM \u5B50\u8FDB\u7A0B\uFF09\u6216\u6E05\u6389 daemon \u5D29\u6E83\u7559\u4E0B\u7684\u6B8B\u9AB8 publishJob \u5B57\u6BB5",
6551
+ args: DismissPublishJobArgsSchema
6552
+ }
6553
+ };
6554
+ METHOD_NAMES = Object.keys(METHOD_DOCS);
6555
+ RPC_METHOD_STATUSES = ["allowed", "conditional", "denied"];
6556
+ RpcMethodStatusSchema = external_exports.enum(RPC_METHOD_STATUSES);
6557
+ RpcMethodInfoSchema = external_exports.object({
6558
+ /** canonical method 名,直接可作为 clawd-rpc call 的 method 参数 */
6183
6559
  name: external_exports.string().min(1),
6184
- /** ws/tunnel 地址 */
6185
- url: external_exports.string().min(1)
6186
- });
6187
- DeviceListResponseSchema = external_exports.object({
6188
- type: external_exports.literal("device:list:ok"),
6189
- devices: external_exports.array(DeviceEntrySchema)
6190
- });
6191
- DeviceConnectArgsSchema = external_exports.object({
6192
- /** 目标设备的 deviceId(对方 daemon 生成的 dev-<uuid>) */
6193
- deviceId: external_exports.string().min(1),
6560
+ status: RpcMethodStatusSchema,
6561
+ /** 该 method 干什么,取自 {@link METHOD_DOCS} 的 summary */
6562
+ description: external_exports.string().min(1),
6194
6563
  /**
6195
- * 目标设备的 ws/tunnel 地址(可选):
6196
- * - 公开目录点击:带 url(device:list 已下发,省一次 server 查询)
6197
- * - 凭 deviceId 连接:缺省 url → daemon exchange 时由中心 server 下发该设备上报的 url
6198
- * - 注册表不在安全路径上:知道对方 url 时显式传入即可连接(不依赖中心 server 服务发现)
6564
+ * 参数字段,从 {@link METHOD_DOCS} 的 args schema **反射**得来(不手写)。
6565
+ * `null` = method 还没有中央 zod schema(欠账,见 RpcMethodDoc),调用方需自行试探。
6199
6566
  */
6200
- url: external_exports.string().min(1).optional(),
6201
- /** 显示名(公共设备来自目录;缺省时连上后用 whoami 回填) */
6202
- name: external_exports.string().optional()
6203
- });
6204
- DeviceConnectResponseSchema = external_exports.object({
6205
- type: external_exports.literal("device:connect:ok"),
6206
- /** 连接的目标设备标识(= 请求 args.deviceId) */
6207
- deviceId: external_exports.string(),
6208
- name: external_exports.string(),
6209
- url: external_exports.string()
6210
- });
6211
- FeishuIdentitySchema = external_exports.object({
6212
- /** 归属人 id(决策 #16:TTC unique_id,取代飞书 union_id;跨登录方式稳定) */
6213
- ownerId: external_exports.string().min(1),
6214
- /** 身份来源:'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...(决策 #16,拓展用) */
6215
- provider: external_exports.string().min(1),
6216
- /** 显示名。TTC user_info 接口 data.name */
6217
- displayName: external_exports.string().min(1),
6218
- /** TTC user_info 接口 data.avatar_url,可缺省 */
6219
- avatarUrl: external_exports.string().optional(),
6220
- /** TTC user_info 接口 data.union_id(飞书 union_id;dataclaw 可信入口 X-User-UnionId 用),可缺省 */
6221
- unionId: external_exports.string().optional()
6222
- });
6223
- AuthLoginStartResponseSchema = external_exports.object({
6224
- type: external_exports.literal("auth:login:start:ok"),
6225
- /** 完整 TTC 授权页 URL(含 callback_url + state + auto=1),UI 直接 window.open */
6226
- authUrl: external_exports.string().min(1),
6227
- /** 防 CSRF 的一次性 nonce;回调时 daemon 校验 */
6228
- state: external_exports.string().min(1)
6229
- });
6230
- AuthGetIdentityResponseSchema = external_exports.object({
6231
- type: external_exports.literal("auth:getIdentity:ok"),
6232
- /** null = 未登录 */
6233
- identity: FeishuIdentitySchema.nullable(),
6567
+ args: external_exports.array(external_exports.object({ name: external_exports.string(), required: external_exports.boolean() })).nullable(),
6234
6568
  /**
6235
- * 本机设备标识(决策 #15:daemon 生成并持久化在 auth.json,如 dev-<uuid>)。
6236
- * 设备属性,与登录态无关、登录登出不变。UI"我的设备标识"用它拼
6237
- * clawos://device/<deviceId>(替代旧的 unionId——不再向外暴露人的身份标识)。
6569
+ * `denied` 必带:daemon error code(`UNAUTHORIZED` / `FEISHU_LOGIN_REQUIRED` /
6570
+ * `METHOD_NOT_IMPLEMENTED`)。`conditional` 必带:谁来做二次校验。
6571
+ * `allowed` 恒无。
6238
6572
  */
6239
- deviceId: external_exports.string().min(1)
6240
- });
6241
- AuthLogoutResponseSchema = external_exports.object({
6242
- type: external_exports.literal("auth:logout:ok")
6243
- });
6244
- AuthLoginDoneEventSchema = external_exports.object({
6245
- type: external_exports.literal("auth:login:done"),
6246
- identity: FeishuIdentitySchema
6573
+ reason: external_exports.string().optional()
6247
6574
  });
6248
- AuthLoginFailedEventSchema = external_exports.object({
6249
- type: external_exports.literal("auth:login:failed"),
6250
- reason: external_exports.string()
6575
+ MetaMethodsResultSchema = external_exports.object({
6576
+ type: external_exports.literal("meta:methods"),
6577
+ /** METHOD_NAMES 全集,顺序与之一致 */
6578
+ methods: external_exports.array(RpcMethodInfoSchema)
6251
6579
  });
6252
6580
  }
6253
6581
  });
6254
6582
 
6255
- // ../protocol/src/dispatch.ts
6256
- var DispatchOutcomeSchema, DispatchRunArgsSchema, DispatchCompleteArgsSchema, DISPATCH_STATUSES, DispatchStatusSchema, DispatchRecordSchema, DispatchListArgsSchema, DispatchListResultSchema, DispatchGetArgsSchema, DispatchGetOkSchema;
6257
- var init_dispatch = __esm({
6258
- "../protocol/src/dispatch.ts"() {
6583
+ // ../protocol/src/errors.ts
6584
+ var ERROR_CODES, ClawdError;
6585
+ var init_errors2 = __esm({
6586
+ "../protocol/src/errors.ts"() {
6587
+ "use strict";
6588
+ ERROR_CODES = {
6589
+ SESSION_NOT_FOUND: "SESSION_NOT_FOUND",
6590
+ SESSION_BUSY: "SESSION_BUSY",
6591
+ INVALID_CWD: "INVALID_CWD",
6592
+ INVALID_PATH: "INVALID_PATH",
6593
+ TOOL_NOT_SUPPORTED: "TOOL_NOT_SUPPORTED",
6594
+ CLAUDE_NOT_FOUND: "CLAUDE_NOT_FOUND",
6595
+ SPAWN_FAILED: "SPAWN_FAILED",
6596
+ INVALID_PERMISSION_MODE: "INVALID_PERMISSION_MODE",
6597
+ METHOD_NOT_IMPLEMENTED: "METHOD_NOT_IMPLEMENTED",
6598
+ METHOD_NOT_ALLOWED: "METHOD_NOT_ALLOWED",
6599
+ VALIDATION_ERROR: "VALIDATION_ERROR",
6600
+ PERMISSION_REQUEST_STALE: "PERMISSION_REQUEST_STALE",
6601
+ FILE_TOO_LARGE: "FILE_TOO_LARGE",
6602
+ INTERNAL: "INTERNAL",
6603
+ UNAUTHORIZED: "UNAUTHORIZED",
6604
+ FORBIDDEN: "FORBIDDEN",
6605
+ INVALID_PARAM: "INVALID_PARAM",
6606
+ // 飞书统一身份(spec 2026-06-01 决策 #9):People/远程体系强制飞书登录。
6607
+ // daemon 进程身份未激活为飞书 unionId 时,FEISHU_GATED_METHODS 内的 RPC 一律返回此错误;
6608
+ // UI 据此显示登录引导(区别于 UNAUTHORIZED 的越权语义)。
6609
+ FEISHU_LOGIN_REQUIRED: "FEISHU_LOGIN_REQUIRED",
6610
+ // app-builder 单栏默认 refactor (spec 2026-06-02-app-builder-single-pane-default-design):
6611
+ // appBuilder:createProject 加 personaId + session 未绑校验后抛的两个错码。
6612
+ WRONG_PERSONA: "WRONG_PERSONA",
6613
+ SESSION_ALREADY_BOUND: "SESSION_ALREADY_BOUND",
6614
+ // 2026-07-02 unified people sidebar: contact:pin 时 deviceId 不在 store(可能被别处删了)
6615
+ CONTACT_NOT_FOUND: "CONTACT_NOT_FOUND",
6616
+ // 统一 RPC 鉴权(spec 2026-07-28):personaDispatch:get 查不到台账行,或 guest ctx
6617
+ // 查非自己发起的行(越权与未知 id 同码,不泄露存在性)。A 端轮询遇此码立即判失败。
6618
+ DISPATCH_NOT_FOUND: "DISPATCH_NOT_FOUND"
6619
+ };
6620
+ ClawdError = class extends Error {
6621
+ constructor(code, message) {
6622
+ super(message);
6623
+ this.code = code;
6624
+ this.name = "ClawdError";
6625
+ }
6626
+ code;
6627
+ };
6628
+ }
6629
+ });
6630
+
6631
+ // ../protocol/src/frames.ts
6632
+ var PROTOCOL_VERSION, DISPATCH_MCP_ID;
6633
+ var init_frames = __esm({
6634
+ "../protocol/src/frames.ts"() {
6635
+ "use strict";
6636
+ PROTOCOL_VERSION = 1;
6637
+ DISPATCH_MCP_ID = "dispatch";
6638
+ }
6639
+ });
6640
+
6641
+ // ../protocol/src/persona-mode.ts
6642
+ var init_persona_mode = __esm({
6643
+ "../protocol/src/persona-mode.ts"() {
6259
6644
  "use strict";
6260
- init_zod();
6261
- DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
6262
- external_exports.object({
6263
- kind: external_exports.literal("success"),
6264
- text: external_exports.string(),
6265
- filePaths: external_exports.array(external_exports.string()).optional()
6266
- }),
6267
- external_exports.object({
6268
- kind: external_exports.literal("failure"),
6269
- reason: external_exports.string()
6270
- })
6271
- ]);
6272
- DispatchRunArgsSchema = external_exports.object({
6273
- // 新开必填;续派(dispatchId 非空)时可省略——targetPersonaId 从台账行取。
6274
- targetPersona: external_exports.string().min(1).optional(),
6275
- // 续派(spec 2026-07-21,单 dispatchId 语义:一件事一行一 id):非空 = 把 prompt
6276
- // 作为新 turn 打进该 dispatch 的原 worker session 接着干(台账行复位 running)。
6277
- // 省略 = 新开一件事,daemon 铸新 id。
6278
- dispatchId: external_exports.string().min(1).optional(),
6279
- prompt: external_exports.string(),
6280
- // 跨设备 dispatch:非空 = A 角色,转发到该 contact deviceId 的 peer daemon;
6281
- // 省略 = 本地 dispatch / B 角色本地执行。A 转发给 B 时 body 不带此字段。
6282
- targetDeviceId: external_exports.string().min(1).optional(),
6283
- // 可选:override B session 使用的 claude 模型。缺省 = 用 persona 默认。
6284
- // 合法值集与 claude adapter capabilities.models[].id 一致(见 daemon
6285
- // tools/claude.ts CLAUDE_MODEL_IDS);handler 层做二次校验,非法值 fail-fast。
6286
- // protocol 层保持 string 便于未来跨 tool 扩展(届时 union 收合法字面量)。
6287
- model: external_exports.string().min(1).optional(),
6288
- // 可选:给新 worker session 起 label(写入 SessionFile.label,sidebar 显示)。
6289
- // 仅在**新开 dispatch**(dispatchId 缺席)时生效;续派(dispatchId 非空)
6290
- // 时 daemon 层静默丢弃(避免半途改 label 造成 sidebar 抖动)。
6291
- // 上限 60 字符——sidebar 显示 tolerance,卡在 dispatch 入口即可。
6292
- // 协议层不硬拒 sessionLabel + dispatchId 同传,保留 forward-compat。
6293
- sessionLabel: external_exports.string().min(1).max(60).optional()
6294
- }).refine((v2) => v2.targetPersona !== void 0 || v2.dispatchId !== void 0, {
6295
- message: "either targetPersona (new dispatch) or dispatchId (follow-up) is required"
6296
- }).refine((v2) => !(v2.dispatchId !== void 0 && v2.targetDeviceId !== void 0), {
6297
- message: "cross-device dispatch cannot be continued (dispatchId + targetDeviceId are mutually exclusive)"
6298
- });
6299
- DispatchCompleteArgsSchema = external_exports.object({
6300
- dispatchId: external_exports.string().min(1),
6301
- outcome: DispatchOutcomeSchema
6302
- });
6303
- DISPATCH_STATUSES = ["running", "completed", "failed"];
6304
- DispatchStatusSchema = external_exports.enum(DISPATCH_STATUSES);
6305
- DispatchRecordSchema = external_exports.object({
6306
- dispatchId: external_exports.string().min(1),
6307
- sourceSessionId: external_exports.string().min(1),
6308
- sourcePersonaId: external_exports.string().min(1).optional(),
6309
- targetPersonaId: external_exports.string().min(1),
6310
- /** B 的 sessionId;registerBSession 后回填 */
6311
- workerSessionId: external_exports.string().min(1).optional(),
6312
- /** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
6313
- taskText: external_exports.string(),
6314
- status: DispatchStatusSchema,
6315
- outcome: DispatchOutcomeSchema.optional(),
6316
- /** 上层消费者语义(如司礼监的口谕/验收状态),daemon 不解释 */
6317
- meta: external_exports.record(external_exports.unknown()).optional(),
6318
- createdAt: external_exports.string().min(1),
6319
- completedAt: external_exports.string().min(1).optional(),
6320
- /** 结果注入 source session 成功时戳,兼当投递 dedup 标记 */
6321
- deliveredAt: external_exports.string().min(1).optional()
6322
- });
6323
- DispatchListArgsSchema = external_exports.object({
6324
- sourceSessionId: external_exports.string().min(1).optional()
6325
- });
6326
- DispatchListResultSchema = external_exports.object({
6327
- records: external_exports.array(DispatchRecordSchema)
6328
- });
6329
- DispatchGetArgsSchema = external_exports.object({
6330
- dispatchId: external_exports.string().min(1)
6331
- });
6332
- DispatchGetOkSchema = external_exports.object({
6333
- type: external_exports.literal("personaDispatch:get:ok"),
6334
- status: DispatchStatusSchema,
6335
- outcome: DispatchOutcomeSchema.optional()
6336
- });
6337
6645
  }
6338
6646
  });
6339
6647
 
@@ -6413,6 +6721,7 @@ var init_runtime = __esm({
6413
6721
  init_dispatch();
6414
6722
  init_log();
6415
6723
  init_visitor_schemas();
6724
+ init_shift_internal();
6416
6725
  }
6417
6726
  });
6418
6727
 
@@ -41624,21 +41933,21 @@ var SessionStoreFactory = class {
41624
41933
  bareRoot() {
41625
41934
  return path5.join(this.dataDir, "sessions");
41626
41935
  }
41627
- vmOwnerRoot(personaId) {
41936
+ vmOwnerRoot(personaId2) {
41628
41937
  return path5.join(
41629
41938
  this.dataDir,
41630
41939
  "personas",
41631
- safeFileName(personaId),
41940
+ safeFileName(personaId2),
41632
41941
  ".clawd",
41633
41942
  "sessions",
41634
41943
  "owner"
41635
41944
  );
41636
41945
  }
41637
- vmGuestRoot(personaId, capId) {
41946
+ vmGuestRoot(personaId2, capId) {
41638
41947
  return path5.join(
41639
41948
  this.dataDir,
41640
41949
  "personas",
41641
- safeFileName(personaId),
41950
+ safeFileName(personaId2),
41642
41951
  ".clawd",
41643
41952
  "sessions",
41644
41953
  "guests",
@@ -41652,19 +41961,19 @@ var SessionStoreFactory = class {
41652
41961
  }
41653
41962
  return this.bareStore;
41654
41963
  }
41655
- forVmOwner(personaId) {
41656
- const key = personaId;
41964
+ forVmOwner(personaId2) {
41965
+ const key = personaId2;
41657
41966
  const cached = this.vmOwnerStores.get(key);
41658
41967
  if (cached) return cached;
41659
- const st = new SessionStore({ root: this.vmOwnerRoot(personaId) });
41968
+ const st = new SessionStore({ root: this.vmOwnerRoot(personaId2) });
41660
41969
  this.vmOwnerStores.set(key, st);
41661
41970
  return st;
41662
41971
  }
41663
- forVmGuest(personaId, capId) {
41664
- const key = `${personaId}::${capId}`;
41972
+ forVmGuest(personaId2, capId) {
41973
+ const key = `${personaId2}::${capId}`;
41665
41974
  const cached = this.vmGuestStores.get(key);
41666
41975
  if (cached) return cached;
41667
- const st = new SessionStore({ root: this.vmGuestRoot(personaId, capId) });
41976
+ const st = new SessionStore({ root: this.vmGuestRoot(personaId2, capId) });
41668
41977
  this.vmGuestStores.set(key, st);
41669
41978
  return st;
41670
41979
  }
@@ -41712,7 +42021,7 @@ function buildGuestSettingsV1() {
41712
42021
  denyWrite: [],
41713
42022
  // **不放 '~/'**(写是白名单制,home 自动不可写);persona(cwd) 由 compose 强制 deny
41714
42023
  allowRead: [],
41715
- // 不放 cwd(persona);userWorkDir 由 compose 注入,profile 加工具链精确路径
42024
+ // userWorkDir + persona cwd 由 compose 强制注入,profile 加工具链精确路径
41716
42025
  allowWrite: []
41717
42026
  }
41718
42027
  }
@@ -41750,7 +42059,7 @@ function composeGuestSandbox(base, userWorkDir, spawnCwd) {
41750
42059
  s.sandbox.allowUnsandboxedCommands = false;
41751
42060
  fsv.denyRead = unionArr(fsv.denyRead, FORCED_DENY_READ);
41752
42061
  fsv.denyWrite = unionArr((fsv.denyWrite ?? []).filter((p2) => p2 !== "~/"), [spawnCwd]);
41753
- fsv.allowRead = unionArr(fsv.allowRead, [userWorkDir]);
42062
+ fsv.allowRead = unionArr(fsv.allowRead, [userWorkDir, spawnCwd]);
41754
42063
  fsv.allowWrite = unionArr(fsv.allowWrite, [userWorkDir]);
41755
42064
  return s;
41756
42065
  }
@@ -42146,8 +42455,8 @@ function buildSpawnContext(state, deps) {
42146
42455
  if (clawosApi) env.CLAWOS_API = clawosApi;
42147
42456
  const dispatchId = deps.lookupDispatchByBSessionId?.(file.sessionId);
42148
42457
  if (dispatchId) env.CLAWD_DISPATCH_ID = dispatchId;
42149
- const personaId = file.ownerPersonaId;
42150
- if (personaId) env.CLAWD_PERSONA_ID = personaId;
42458
+ const personaId2 = file.ownerPersonaId;
42459
+ if (personaId2) env.CLAWD_PERSONA_ID = personaId2;
42151
42460
  const mcpConfigs = deps.getMcpConfigs?.() ?? [];
42152
42461
  const ctx = {
42153
42462
  cwd: file.cwd,
@@ -42162,7 +42471,7 @@ function buildSpawnContext(state, deps) {
42162
42471
  ...mcpConfigs.length > 0 ? { mcpConfigs } : {},
42163
42472
  // shift v1:把 SessionFile.ownerPersonaId 透传到 SpawnContext;buildSpawnArgs 等下游
42164
42473
  // 不直接读这个字段(只读 env),但保留显式字段方便 daemon 内部诊断/日志。
42165
- personaId
42474
+ personaId: personaId2
42166
42475
  };
42167
42476
  const meta = state.subSessionMeta;
42168
42477
  if (meta?.personaMode) {
@@ -43456,14 +43765,14 @@ When done, call the \`personaDispatchComplete\` tool from the \`clawd-dispatch\`
43456
43765
  dispatchId for this task: ${args.dispatchId}`;
43457
43766
  }
43458
43767
  function derivePersonaSpawnCwd(file, personaRoot) {
43459
- const personaId = file.ownerPersonaId;
43460
- if (!personaId) return file.cwd;
43768
+ const personaId2 = file.ownerPersonaId;
43769
+ if (!personaId2) return file.cwd;
43461
43770
  if (!personaRoot) {
43462
43771
  throw new Error(
43463
- `derivePersonaSpawnCwd: personaRoot missing for owner session ${file.sessionId} (ownerPersonaId=${personaId})`
43772
+ `derivePersonaSpawnCwd: personaRoot missing for owner session ${file.sessionId} (ownerPersonaId=${personaId2})`
43464
43773
  );
43465
43774
  }
43466
- return import_node_path9.default.join(personaRoot, safeFileName(personaId));
43775
+ return import_node_path9.default.join(personaRoot, safeFileName(personaId2));
43467
43776
  }
43468
43777
  function makeInitialState(file, subSessionMeta) {
43469
43778
  return {
@@ -43613,12 +43922,12 @@ var SessionManager = class {
43613
43922
  // 扫某 persona 下 guests/ 子目录, 拿所有 capId.
43614
43923
  // 路径: <dataDir>/personas/<pid>/.clawd/sessions/guests/<capId>/
43615
43924
  // 只在 storeFactory 注入 (新布局) 下生效, 老布局无 guest 目录.
43616
- listGuestCapIdsForPersona(personaId) {
43925
+ listGuestCapIdsForPersona(personaId2) {
43617
43926
  if (!this.deps.dataDir || !this.deps.storeFactory) return [];
43618
43927
  const root = import_node_path9.default.join(
43619
43928
  this.deps.dataDir,
43620
43929
  "personas",
43621
- personaId,
43930
+ personaId2,
43622
43931
  ".clawd",
43623
43932
  "sessions",
43624
43933
  "guests"
@@ -43650,12 +43959,12 @@ var SessionManager = class {
43650
43959
  if (runner) return runner.getState().file;
43651
43960
  const dflt = this.deps.store.read(sessionId);
43652
43961
  if (dflt) return dflt;
43653
- for (const personaId of this.listPersonaIdsOnDisk()) {
43654
- const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
43962
+ for (const personaId2 of this.listPersonaIdsOnDisk()) {
43963
+ const ownerStore = this.storeFor({ kind: "persona", personaId: personaId2, mode: "owner" });
43655
43964
  const found = ownerStore.read(sessionId);
43656
43965
  if (found) return found;
43657
- for (const capId of this.listGuestCapIdsForPersona(personaId)) {
43658
- const guestStore = this.storeFor({ kind: "persona", personaId, mode: "guest", capId });
43966
+ for (const capId of this.listGuestCapIdsForPersona(personaId2)) {
43967
+ const guestStore = this.storeFor({ kind: "persona", personaId: personaId2, mode: "guest", capId });
43659
43968
  const g2 = guestStore.read(sessionId);
43660
43969
  if (g2) return g2;
43661
43970
  }
@@ -43684,11 +43993,11 @@ var SessionManager = class {
43684
43993
  listAllOwned() {
43685
43994
  const out = [];
43686
43995
  out.push(...this.deps.store.list());
43687
- for (const personaId of this.listPersonaIdsOnDisk()) {
43688
- const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
43996
+ for (const personaId2 of this.listPersonaIdsOnDisk()) {
43997
+ const ownerStore = this.storeFor({ kind: "persona", personaId: personaId2, mode: "owner" });
43689
43998
  out.push(...ownerStore.list());
43690
- for (const capId of this.listGuestCapIdsForPersona(personaId)) {
43691
- const guestStore = this.storeFor({ kind: "persona", personaId, mode: "guest", capId });
43999
+ for (const capId of this.listGuestCapIdsForPersona(personaId2)) {
44000
+ const guestStore = this.storeFor({ kind: "persona", personaId: personaId2, mode: "guest", capId });
43692
44001
  out.push(...guestStore.list());
43693
44002
  }
43694
44003
  }
@@ -43716,11 +44025,11 @@ var SessionManager = class {
43716
44025
  // 删除 owned SessionFile(default / persona owner / persona guest),与 findOwnedSession 对称扫盘.
43717
44026
  deleteOwned(sessionId) {
43718
44027
  if (this.deps.store.delete(sessionId)) return true;
43719
- for (const personaId of this.listPersonaIdsOnDisk()) {
43720
- const ownerStore = this.storeFor({ kind: "persona", personaId, mode: "owner" });
44028
+ for (const personaId2 of this.listPersonaIdsOnDisk()) {
44029
+ const ownerStore = this.storeFor({ kind: "persona", personaId: personaId2, mode: "owner" });
43721
44030
  if (ownerStore.delete(sessionId)) return true;
43722
- for (const capId of this.listGuestCapIdsForPersona(personaId)) {
43723
- const guestStore = this.storeFor({ kind: "persona", personaId, mode: "guest", capId });
44031
+ for (const capId of this.listGuestCapIdsForPersona(personaId2)) {
44032
+ const guestStore = this.storeFor({ kind: "persona", personaId: personaId2, mode: "guest", capId });
43724
44033
  if (guestStore.delete(sessionId)) return true;
43725
44034
  }
43726
44035
  }
@@ -45418,19 +45727,19 @@ var PersonaStore = class {
45418
45727
  fs10.mkdirSync(root, { recursive: true });
45419
45728
  }
45420
45729
  root;
45421
- personaDir(personaId) {
45422
- return path12.join(this.root, safeFileName(personaId));
45730
+ personaDir(personaId2) {
45731
+ return path12.join(this.root, safeFileName(personaId2));
45423
45732
  }
45424
- metaPath(personaId) {
45425
- return path12.join(this.personaDir(personaId), ".clawd", "persona.json");
45733
+ metaPath(personaId2) {
45734
+ return path12.join(this.personaDir(personaId2), ".clawd", "persona.json");
45426
45735
  }
45427
- claudeMdPath(personaId) {
45428
- return path12.join(this.personaDir(personaId), "CLAUDE.md");
45736
+ claudeMdPath(personaId2) {
45737
+ return path12.join(this.personaDir(personaId2), "CLAUDE.md");
45429
45738
  }
45430
45739
  // codex 原生读 cwd 的 AGENTS.md。人格双写镜像:claude 读 CLAUDE.md、codex 读 AGENTS.md,
45431
45740
  // 两份内容恒一致,persona 切 tool 零迁移。
45432
- agentsMdPath(personaId) {
45433
- return path12.join(this.personaDir(personaId), "AGENTS.md");
45741
+ agentsMdPath(personaId2) {
45742
+ return path12.join(this.personaDir(personaId2), "AGENTS.md");
45434
45743
  }
45435
45744
  /**
45436
45745
  * persona 级 sandbox base 落盘路径 —— 故意放 `.clawd/` 而非 `.claude/`,让 CC 的 project
@@ -45438,8 +45747,8 @@ var PersonaStore = class {
45438
45747
  * 这份是 guest 沙箱的 **base 真源**(manager compose 读它当 base);guest 实际加载的是 manager
45439
45748
  * spawn 前 per-guest 动态拼到各自 session 目录的那份(base + 强制底座 + 本 guest userWorkDir carve)。
45440
45749
  */
45441
- sandboxSettingsPath(personaId) {
45442
- return path12.join(this.personaDir(personaId), ".clawd", "sandbox-settings.json");
45750
+ sandboxSettingsPath(personaId2) {
45751
+ return path12.join(this.personaDir(personaId2), ".clawd", "sandbox-settings.json");
45443
45752
  }
45444
45753
  write(persona, personality) {
45445
45754
  const dir = this.personaDir(persona.personaId);
@@ -45449,9 +45758,9 @@ var PersonaStore = class {
45449
45758
  this.writeSandboxSettings(persona.personaId, buildGuestSettingsV1());
45450
45759
  this.atomicWrite(this.metaPath(persona.personaId), JSON.stringify(persona, null, 2));
45451
45760
  }
45452
- writePersonality(personaId, personality) {
45453
- this.atomicWrite(this.claudeMdPath(personaId), personality);
45454
- this.atomicWrite(this.agentsMdPath(personaId), personality);
45761
+ writePersonality(personaId2, personality) {
45762
+ this.atomicWrite(this.claudeMdPath(personaId2), personality);
45763
+ this.atomicWrite(this.agentsMdPath(personaId2), personality);
45455
45764
  }
45456
45765
  /**
45457
45766
  * 历史 persona 补 AGENTS.md:人格双写镜像是 codex 适配后才加的,更早落盘的 persona 只有
@@ -45459,9 +45768,9 @@ var PersonaStore = class {
45459
45768
  * migrate(见 seed.migrateAgentsMirror)。幂等:已有 AGENTS.md(含用户手改的)不覆盖;
45460
45769
  * 无 CLAUDE.md 不凭空造。返回是否实际补写。
45461
45770
  */
45462
- ensureAgentsMirror(personaId) {
45463
- const claudeMd = this.claudeMdPath(personaId);
45464
- const agentsMd = this.agentsMdPath(personaId);
45771
+ ensureAgentsMirror(personaId2) {
45772
+ const claudeMd = this.claudeMdPath(personaId2);
45773
+ const agentsMd = this.agentsMdPath(personaId2);
45465
45774
  if (!fs10.existsSync(claudeMd)) return false;
45466
45775
  if (fs10.existsSync(agentsMd)) return false;
45467
45776
  this.atomicWrite(agentsMd, fs10.readFileSync(claudeMd, "utf8"));
@@ -45474,25 +45783,25 @@ var PersonaStore = class {
45474
45783
  * 写入时强制注入本 persona 的 Edit-deny('~/<persona>/**' 按实际 persona dir 算)+ 剥掉历史相对 'Edit(./**)',
45475
45784
  * 让落盘 base 就是 source of truth(compose 不再运行时替换 permission deny)。
45476
45785
  */
45477
- writeSandboxSettings(personaId, settings) {
45786
+ writeSandboxSettings(personaId2, settings) {
45478
45787
  this.atomicWrite(
45479
- this.sandboxSettingsPath(personaId),
45480
- JSON.stringify(this.injectPersonaEditDeny(personaId, settings), null, 2)
45788
+ this.sandboxSettingsPath(personaId2),
45789
+ JSON.stringify(this.injectPersonaEditDeny(personaId2, settings), null, 2)
45481
45790
  );
45482
45791
  }
45483
45792
  /** 把 persona Edit-deny(绝对 '~/<persona>/**')并进 settings.permissions.deny,剥掉历史相对 'Edit(./**)'。 */
45484
- injectPersonaEditDeny(personaId, settings) {
45793
+ injectPersonaEditDeny(personaId2, settings) {
45485
45794
  const s = settings;
45486
- const rule = personaEditDeny(this.personaDir(personaId));
45795
+ const rule = personaEditDeny(this.personaDir(personaId2));
45487
45796
  const prev = (s.permissions?.deny ?? []).filter((r) => r !== "Edit(./**)" && r !== rule);
45488
45797
  return { ...s, permissions: { ...s.permissions ?? {}, deny: [...prev, rule] } };
45489
45798
  }
45490
- codexSandboxSettingsPath(personaId) {
45491
- return path12.join(this.personaDir(personaId), ".clawd", "codex-sandbox.json");
45799
+ codexSandboxSettingsPath(personaId2) {
45800
+ return path12.join(this.personaDir(personaId2), ".clawd", "codex-sandbox.json");
45492
45801
  }
45493
45802
  /** 读 codex-sandbox.json;不存在/损坏 → null。 */
45494
- readCodexSandboxSettings(personaId) {
45495
- const p2 = this.codexSandboxSettingsPath(personaId);
45803
+ readCodexSandboxSettings(personaId2) {
45804
+ const p2 = this.codexSandboxSettingsPath(personaId2);
45496
45805
  if (!fs10.existsSync(p2)) return null;
45497
45806
  try {
45498
45807
  return CodexSandboxSettingsSchema.parse(JSON.parse(fs10.readFileSync(p2, "utf8")));
@@ -45501,16 +45810,16 @@ var PersonaStore = class {
45501
45810
  }
45502
45811
  }
45503
45812
  /** 覆盖写 codex-sandbox.json(seed/migrate 用)。 */
45504
- writeCodexSandboxSettings(personaId, settings) {
45505
- const dir = path12.join(this.personaDir(personaId), ".clawd");
45813
+ writeCodexSandboxSettings(personaId2, settings) {
45814
+ const dir = path12.join(this.personaDir(personaId2), ".clawd");
45506
45815
  fs10.mkdirSync(dir, { recursive: true });
45507
- this.atomicWrite(this.codexSandboxSettingsPath(personaId), JSON.stringify(settings, null, 2));
45816
+ this.atomicWrite(this.codexSandboxSettingsPath(personaId2), JSON.stringify(settings, null, 2));
45508
45817
  }
45509
45818
  writeMeta(persona) {
45510
45819
  this.atomicWrite(this.metaPath(persona.personaId), JSON.stringify(persona, null, 2));
45511
45820
  }
45512
- read(personaId) {
45513
- const p2 = this.metaPath(personaId);
45821
+ read(personaId2) {
45822
+ const p2 = this.metaPath(personaId2);
45514
45823
  if (!fs10.existsSync(p2)) return null;
45515
45824
  const raw = JSON.parse(fs10.readFileSync(p2, "utf8"));
45516
45825
  if (raw && typeof raw === "object" && "tokenMap" in raw) {
@@ -45519,13 +45828,13 @@ var PersonaStore = class {
45519
45828
  }
45520
45829
  return PersonaFileSchema.parse(raw);
45521
45830
  }
45522
- has(personaId) {
45523
- return fs10.existsSync(this.metaPath(personaId));
45831
+ has(personaId2) {
45832
+ return fs10.existsSync(this.metaPath(personaId2));
45524
45833
  }
45525
- readPersonality(personaId) {
45526
- const claudeMd = this.claudeMdPath(personaId);
45834
+ readPersonality(personaId2) {
45835
+ const claudeMd = this.claudeMdPath(personaId2);
45527
45836
  if (fs10.existsSync(claudeMd)) return fs10.readFileSync(claudeMd, "utf8");
45528
- const agentsMd = this.agentsMdPath(personaId);
45837
+ const agentsMd = this.agentsMdPath(personaId2);
45529
45838
  if (fs10.existsSync(agentsMd)) return fs10.readFileSync(agentsMd, "utf8");
45530
45839
  return null;
45531
45840
  }
@@ -45533,8 +45842,8 @@ var PersonaStore = class {
45533
45842
  * 读 sandbox-settings.json 当前内容;文件不存在 / JSON 解析失败均返回 null。
45534
45843
  * owner 手改文件可能写出非法形状,daemon 不强校验,UI 拿到 null → 显示空状态。
45535
45844
  */
45536
- readSandboxSettings(personaId) {
45537
- const p2 = this.sandboxSettingsPath(personaId);
45845
+ readSandboxSettings(personaId2) {
45846
+ const p2 = this.sandboxSettingsPath(personaId2);
45538
45847
  if (!fs10.existsSync(p2)) return null;
45539
45848
  try {
45540
45849
  return JSON.parse(fs10.readFileSync(p2, "utf8"));
@@ -45543,15 +45852,15 @@ var PersonaStore = class {
45543
45852
  }
45544
45853
  }
45545
45854
  /** Persona 私有 skills 目录路径:<personaDir>/.claude/skills */
45546
- skillsDir(personaId) {
45547
- return path12.join(this.personaDir(personaId), ".claude", "skills");
45855
+ skillsDir(personaId2) {
45856
+ return path12.join(this.personaDir(personaId2), ".claude", "skills");
45548
45857
  }
45549
45858
  /**
45550
45859
  * Claude Code 项目级 settings 路径:`<personaDir>/.claude/settings.json`。
45551
45860
  * 这里只读 `enabledPlugins` 字段,由 owner 通过 CC `/plugin` 之类命令维护,daemon 不写。
45552
45861
  */
45553
- claudeSettingsPath(personaId) {
45554
- return path12.join(this.personaDir(personaId), ".claude", "settings.json");
45862
+ claudeSettingsPath(personaId2) {
45863
+ return path12.join(this.personaDir(personaId2), ".claude", "settings.json");
45555
45864
  }
45556
45865
  /**
45557
45866
  * 读取 persona 的 `.claude/settings.json` 中 `enabledPlugins` map,把 value === true
@@ -45564,8 +45873,8 @@ var PersonaStore = class {
45564
45873
  * - 单 value 非 boolean → 跳过该 entry
45565
45874
  * 其他错误(fs 权限等)原样抛出,由上层 handler 转 ws error 帧。
45566
45875
  */
45567
- readEnabledPlugins(personaId) {
45568
- const p2 = this.claudeSettingsPath(personaId);
45876
+ readEnabledPlugins(personaId2) {
45877
+ const p2 = this.claudeSettingsPath(personaId2);
45569
45878
  if (!fs10.existsSync(p2)) return [];
45570
45879
  let raw;
45571
45880
  try {
@@ -45588,12 +45897,12 @@ var PersonaStore = class {
45588
45897
  return fs10.existsSync(path12.join(this.root, name, ".clawd", "persona.json"));
45589
45898
  });
45590
45899
  }
45591
- remove(personaId) {
45592
- const dir = this.personaDir(personaId);
45900
+ remove(personaId2) {
45901
+ const dir = this.personaDir(personaId2);
45593
45902
  if (fs10.existsSync(dir)) fs10.rmSync(dir, { recursive: true, force: true });
45594
45903
  }
45595
- personaDirPath(personaId) {
45596
- return this.personaDir(personaId);
45904
+ personaDirPath(personaId2) {
45905
+ return this.personaDir(personaId2);
45597
45906
  }
45598
45907
  atomicWrite(file, content) {
45599
45908
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
@@ -45625,15 +45934,15 @@ var PersonaRegistry = class {
45625
45934
  }
45626
45935
  }
45627
45936
  }
45628
- get(personaId) {
45629
- return this.cache.get(personaId);
45937
+ get(personaId2) {
45938
+ return this.cache.get(personaId2);
45630
45939
  }
45631
45940
  /** PersonaManager 写盘后同步 cache;不主动写盘 */
45632
45941
  set(file) {
45633
45942
  this.cache.set(file.personaId, file);
45634
45943
  }
45635
- remove(personaId) {
45636
- this.cache.delete(personaId);
45944
+ remove(personaId2) {
45945
+ this.cache.delete(personaId2);
45637
45946
  }
45638
45947
  list() {
45639
45948
  return Array.from(this.cache.values());
@@ -45923,10 +46232,10 @@ var PersonaManager = class {
45923
46232
  }
45924
46233
  deps;
45925
46234
  create(args) {
45926
- const personaId = this.generatePersonaId(args.label);
46235
+ const personaId2 = this.generatePersonaId(args.label);
45927
46236
  const now = Date.now();
45928
46237
  const persona = {
45929
- personaId,
46238
+ personaId: personaId2,
45930
46239
  label: args.label,
45931
46240
  model: args.model,
45932
46241
  tool: args.tool,
@@ -45939,9 +46248,9 @@ var PersonaManager = class {
45939
46248
  this.deps.registry.set(persona);
45940
46249
  return persona;
45941
46250
  }
45942
- update(personaId, patch, personality) {
45943
- const existing = this.deps.registry.get(personaId);
45944
- if (!existing) throw new Error(`persona not found: ${personaId}`);
46251
+ update(personaId2, patch, personality) {
46252
+ const existing = this.deps.registry.get(personaId2);
46253
+ if (!existing) throw new Error(`persona not found: ${personaId2}`);
45945
46254
  const { iconKey: iconKeyPatch, ...restPatch } = patch;
45946
46255
  const updated = {
45947
46256
  ...existing,
@@ -45954,30 +46263,30 @@ var PersonaManager = class {
45954
46263
  updated.iconKey = iconKeyPatch;
45955
46264
  }
45956
46265
  if (personality !== void 0) {
45957
- this.deps.store.writePersonality(personaId, personality);
46266
+ this.deps.store.writePersonality(personaId2, personality);
45958
46267
  }
45959
46268
  this.deps.store.writeMeta(updated);
45960
46269
  this.deps.registry.set(updated);
45961
46270
  return updated;
45962
46271
  }
45963
46272
  /** 读取 CLAUDE.md 内容;persona 目录或文件不存在时返回 null。透传给 handler 拼响应。 */
45964
- readPersonality(personaId) {
45965
- return this.deps.store.readPersonality(personaId);
46273
+ readPersonality(personaId2) {
46274
+ return this.deps.store.readPersonality(personaId2);
45966
46275
  }
45967
46276
  /** 扫 persona 私有 skills 目录;目录不存在返回空数组。供 persona:get handler 拼响应。 */
45968
- listSkills(personaId) {
45969
- return listSkillsForDir(this.deps.store.skillsDir(personaId), "project");
46277
+ listSkills(personaId2) {
46278
+ return listSkillsForDir(this.deps.store.skillsDir(personaId2), "project");
45970
46279
  }
45971
46280
  /**
45972
46281
  * 读取 persona `.claude/settings.json` 中已启用的插件列表(value === true 的 key)。
45973
46282
  * 文件不存在 / 解析失败 / 字段缺失 → 空数组。供 persona:get handler 拼响应。
45974
46283
  */
45975
- listEnabledPlugins(personaId) {
45976
- return this.deps.store.readEnabledPlugins(personaId);
46284
+ listEnabledPlugins(personaId2) {
46285
+ return this.deps.store.readEnabledPlugins(personaId2);
45977
46286
  }
45978
46287
  /** 读 sandbox-settings.json;不存在 / 损坏返回 null。供 persona:get handler 拼响应。 */
45979
- readSandboxSettings(personaId) {
45980
- return this.deps.store.readSandboxSettings(personaId);
46288
+ readSandboxSettings(personaId2) {
46289
+ return this.deps.store.readSandboxSettings(personaId2);
45981
46290
  }
45982
46291
  /**
45983
46292
  * 删除 persona。
@@ -45985,9 +46294,9 @@ var PersonaManager = class {
45985
46294
  * (含 .clawd/sessions/owner/ 和 .clawd/sessions/guests/<capId>/),rmSync
45986
46295
  * recursive force 一锅清。
45987
46296
  */
45988
- delete(personaId) {
45989
- this.deps.store.remove(personaId);
45990
- this.deps.registry.remove(personaId);
46297
+ delete(personaId2) {
46298
+ this.deps.store.remove(personaId2);
46299
+ this.deps.registry.remove(personaId2);
45991
46300
  }
45992
46301
  /**
45993
46302
  * label 转 4-16 char slug。优先用 `persona-<slug>`;若 slug 已被占用,追加 4 char
@@ -46317,15 +46626,15 @@ function refreshSandboxSettings(args) {
46317
46626
  }
46318
46627
  function migrateAgentsMirror(args) {
46319
46628
  let mirrored = 0;
46320
- for (const personaId of args.store.list()) {
46629
+ for (const personaId2 of args.store.list()) {
46321
46630
  try {
46322
- if (args.store.ensureAgentsMirror(personaId)) {
46631
+ if (args.store.ensureAgentsMirror(personaId2)) {
46323
46632
  mirrored++;
46324
- args.logger.info("persona.agents-mirror.synced", { personaId });
46633
+ args.logger.info("persona.agents-mirror.synced", { personaId: personaId2 });
46325
46634
  }
46326
46635
  } catch (err) {
46327
46636
  args.logger.warn("persona.agents-mirror.failed", {
46328
- personaId,
46637
+ personaId: personaId2,
46329
46638
  error: err instanceof Error ? err.message : String(err)
46330
46639
  });
46331
46640
  }
@@ -46335,15 +46644,15 @@ function migrateAgentsMirror(args) {
46335
46644
  function migrateCodexSandbox(args) {
46336
46645
  const entries = args.entries ?? DEFAULT_PERSONAS;
46337
46646
  let n = 0;
46338
- for (const personaId of args.store.list()) {
46339
- if (args.store.readCodexSandboxSettings(personaId)) continue;
46647
+ for (const personaId2 of args.store.list()) {
46648
+ if (args.store.readCodexSandboxSettings(personaId2)) continue;
46340
46649
  try {
46341
- const def = entries.find((e) => e.personaId === personaId)?.codexSandbox ?? { writableRoots: [], denyRead: [], network: false };
46342
- args.store.writeCodexSandboxSettings(personaId, def);
46650
+ const def = entries.find((e) => e.personaId === personaId2)?.codexSandbox ?? { writableRoots: [], denyRead: [], network: false };
46651
+ args.store.writeCodexSandboxSettings(personaId2, def);
46343
46652
  n++;
46344
- args.logger.info("persona.codex-sandbox.synced", { personaId });
46653
+ args.logger.info("persona.codex-sandbox.synced", { personaId: personaId2 });
46345
46654
  } catch (err) {
46346
- args.logger.warn("persona.codex-sandbox.failed", { personaId, error: err instanceof Error ? err.message : String(err) });
46655
+ args.logger.warn("persona.codex-sandbox.failed", { personaId: personaId2, error: err instanceof Error ? err.message : String(err) });
46347
46656
  }
46348
46657
  }
46349
46658
  if (n > 0) args.logger.info("persona.codex-sandbox.done", { migrated: n });
@@ -49193,16 +49502,17 @@ function createShiftSpawnFn(deps) {
49193
49502
  };
49194
49503
  }
49195
49504
 
49196
- // src/handlers/shift-internal.ts
49197
- function readPersonaId(frame) {
49198
- const raw = frame.personaId;
49199
- if (typeof raw !== "string" || raw.trim() === "") {
49200
- throw new Error(
49201
- "shift-internal: missing personaId (mcp-server should set CLAWD_PERSONA_ID env)"
49202
- );
49203
- }
49204
- return raw;
49505
+ // src/handlers/types.ts
49506
+ init_protocol();
49507
+ function parseArgs2(schema, frame, what, code = ERROR_CODES.VALIDATION_ERROR) {
49508
+ const effective = typeof schema.strip === "function" ? schema.strip() : schema;
49509
+ const r = effective.safeParse(frame);
49510
+ if (!r.success) throw new ClawdError(code, `${what}: ${r.error.message}`);
49511
+ return r.data;
49205
49512
  }
49513
+
49514
+ // src/handlers/shift-internal.ts
49515
+ init_protocol();
49206
49516
  function validateSchedule(schedule) {
49207
49517
  const next = computeNextRunAtMs(schedule, Date.now());
49208
49518
  if (next === null) {
@@ -49213,10 +49523,9 @@ function validateSchedule(schedule) {
49213
49523
  }
49214
49524
  function buildShiftInternalHandlers(deps) {
49215
49525
  const add = async (frame) => {
49216
- const persona = readPersonaId(frame);
49217
49526
  const callerSessionId = typeof frame.sessionId === "string" ? frame.sessionId : void 0;
49218
- const { type: _t, requestId: _r, personaId: _p, sessionId: _s, ...rest } = frame;
49219
- const args = rest;
49527
+ const args = parseArgs2(ShiftInternalAddArgs, frame, "shift-internal:add");
49528
+ const persona = args.personaId;
49220
49529
  validateSchedule(args.schedule);
49221
49530
  const shift = deps.store.add({
49222
49531
  ownerId: deps.ownerIdProvider(),
@@ -49234,17 +49543,15 @@ function buildShiftInternalHandlers(deps) {
49234
49543
  };
49235
49544
  };
49236
49545
  const list = async (frame) => {
49237
- const persona = readPersonaId(frame);
49238
- const { type: _t, requestId: _r, personaId: _p, sessionId: _s, ...rest } = frame;
49239
- const args = rest;
49546
+ const args = parseArgs2(ShiftInternalListArgs, frame, "shift-internal:list");
49547
+ const persona = args.personaId;
49240
49548
  const onlyMine = args.onlyMine !== false;
49241
49549
  const filter = onlyMine ? { ownerId: deps.ownerIdProvider(), createdByPersona: persona } : { ownerId: deps.ownerIdProvider() };
49242
49550
  return { response: { shifts: deps.store.list(filter) } };
49243
49551
  };
49244
49552
  const cancel = async (frame) => {
49245
- const persona = readPersonaId(frame);
49246
- const { type: _t, requestId: _r, personaId: _p, sessionId: _s, ...rest } = frame;
49247
- const args = rest;
49553
+ const args = parseArgs2(ShiftInternalCancelArgs, frame, "shift-internal:cancel");
49554
+ const persona = args.personaId;
49248
49555
  const shift = deps.store.get(args.shiftId);
49249
49556
  if (!shift) {
49250
49557
  throw new Error(`shift-internal:cancel: shift not found: ${args.shiftId}`);
@@ -49258,9 +49565,8 @@ function buildShiftInternalHandlers(deps) {
49258
49565
  return { response: { ok: true } };
49259
49566
  };
49260
49567
  const update = async (frame) => {
49261
- const persona = readPersonaId(frame);
49262
- const { type: _t, requestId: _r, personaId: _p, sessionId: _s, ...rest } = frame;
49263
- const args = rest;
49568
+ const args = parseArgs2(ShiftInternalUpdateArgs, frame, "shift-internal:update");
49569
+ const persona = args.personaId;
49264
49570
  const shift = deps.store.get(args.shiftId);
49265
49571
  if (!shift) {
49266
49572
  throw new Error(`shift-internal:update: shift not found: ${args.shiftId}`);
@@ -49280,9 +49586,8 @@ function buildShiftInternalHandlers(deps) {
49280
49586
  };
49281
49587
  };
49282
49588
  const history = async (frame) => {
49283
- const persona = readPersonaId(frame);
49284
- const { type: _t, requestId: _r, personaId: _p, sessionId: _s, ...rest } = frame;
49285
- const args = rest;
49589
+ const args = parseArgs2(ShiftInternalHistoryArgs, frame, "shift-internal:history");
49590
+ const persona = args.personaId;
49286
49591
  const shift = deps.store.get(args.shiftId);
49287
49592
  if (!shift) {
49288
49593
  throw new Error(`shift-internal:history: shift not found: ${args.shiftId}`);
@@ -49338,9 +49643,9 @@ function canAccessSession(ctx, sessionId, action, deps) {
49338
49643
  if (!file) return true;
49339
49644
  return canAccessPersona(ctx.grants, file.ownerPersonaId, action);
49340
49645
  }
49341
- function canAccessPersona(grants, personaId, action) {
49342
- if (!personaId) return false;
49343
- const resource = { type: "persona", id: personaId };
49646
+ function canAccessPersona(grants, personaId2, action) {
49647
+ if (!personaId2) return false;
49648
+ const resource = { type: "persona", id: personaId2 };
49344
49649
  return assertGrant(grants, resource, action);
49345
49650
  }
49346
49651
 
@@ -50685,7 +50990,7 @@ function listRegistered() {
50685
50990
 
50686
50991
  // ../node_modules/.pnpm/ws@8.20.0/node_modules/ws/wrapper.mjs
50687
50992
  var import_stream = __toESM(require_stream(), 1);
50688
- var import_extension = __toESM(require_extension(), 1);
50993
+ var import_extension2 = __toESM(require_extension(), 1);
50689
50994
  var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
50690
50995
  var import_receiver = __toESM(require_receiver(), 1);
50691
50996
  var import_sender = __toESM(require_sender(), 1);
@@ -54287,14 +54592,14 @@ function buildSessionHandlers(deps) {
54287
54592
  );
54288
54593
  }
54289
54594
  };
54290
- const ensurePersonaAccess = (ctx, personaId, action) => {
54595
+ const ensurePersonaAccess = (ctx, personaId2, action) => {
54291
54596
  if (!ctx) return;
54292
54597
  if (ctx.principal.kind === "owner") return;
54293
- const ok = canAccessPersona(ctx.grants, personaId, action);
54598
+ const ok = canAccessPersona(ctx.grants, personaId2, action);
54294
54599
  if (!ok) {
54295
54600
  throw new ClawdError(
54296
54601
  ERROR_CODES.UNAUTHORIZED,
54297
- `principal ${ctx.principal.kind}:${ctx.principal.id} cannot ${action} on persona:${personaId ?? "<none>"}`
54602
+ `principal ${ctx.principal.kind}:${ctx.principal.id} cannot ${action} on persona:${personaId2 ?? "<none>"}`
54298
54603
  );
54299
54604
  }
54300
54605
  };
@@ -54405,7 +54710,7 @@ function buildSessionHandlers(deps) {
54405
54710
  return { response: { type: "session:send", ok: true }, broadcast };
54406
54711
  };
54407
54712
  const currentTurnSender = async (frame, _client, ctx) => {
54408
- const sid = typeof frame === "object" && frame != null && "sessionId" in frame ? String(frame.sessionId) : "";
54713
+ const sid = SessionCurrentTurnSenderArgs.parse(frame).sessionId ?? "";
54409
54714
  if (!sid) {
54410
54715
  return { response: { type: "session:currentTurnSender", sender: null } };
54411
54716
  }
@@ -54510,19 +54815,20 @@ function buildSessionHandlers(deps) {
54510
54815
  return { response: { type: "session:events", ...response } };
54511
54816
  };
54512
54817
  const subscribe = async (frame, client, ctx) => {
54513
- if (typeof frame.sessionId === "string") {
54514
- ensureSessionAccess(ctx, frame.sessionId, "read");
54515
- addSubscription(client, frame.sessionId);
54818
+ const args = SessionSubscribeArgs.parse(frame);
54819
+ if (args.sessionId !== void 0) {
54820
+ ensureSessionAccess(ctx, args.sessionId, "read");
54821
+ addSubscription(client, args.sessionId);
54516
54822
  }
54517
54823
  return {
54518
- response: { type: "subscribed", sessionId: frame.sessionId }
54824
+ response: { type: "subscribed", sessionId: args.sessionId }
54519
54825
  };
54520
54826
  };
54521
54827
  const unsubscribe = async (frame, client) => {
54522
- if (typeof frame.sessionId === "string")
54523
- removeSubscription(client, frame.sessionId);
54828
+ const args = SessionSubscribeArgs.parse(frame);
54829
+ if (args.sessionId !== void 0) removeSubscription(client, args.sessionId);
54524
54830
  return {
54525
- response: { type: "unsubscribed", sessionId: frame.sessionId }
54831
+ response: { type: "unsubscribed", sessionId: args.sessionId }
54526
54832
  };
54527
54833
  };
54528
54834
  const pin = async (frame, _client, ctx) => {
@@ -54721,11 +55027,11 @@ function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userW
54721
55027
  if (!target.startsWith(root + sep3)) return false;
54722
55028
  const rel = path56.relative(root, target);
54723
55029
  if (!rel || rel.startsWith("..")) return false;
54724
- const personaId = rel.split(path56.sep)[0];
54725
- if (!personaId) return false;
55030
+ const personaId2 = rel.split(path56.sep)[0];
55031
+ if (!personaId2) return false;
54726
55032
  const allowed = getAllowedPersonaIds(grants, action);
54727
55033
  if (allowed === "*") return true;
54728
- return allowed.has(personaId);
55034
+ return allowed.has(personaId2);
54729
55035
  }
54730
55036
  function personaIdFromPath(absPath, personaRoot) {
54731
55037
  const root = path56.resolve(personaRoot);
@@ -54743,9 +55049,9 @@ function isPathWithin(dir, absPath) {
54743
55049
  const sep3 = d.endsWith(path56.sep) ? "" : path56.sep;
54744
55050
  return t === d || t.startsWith(d + sep3);
54745
55051
  }
54746
- function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
55052
+ function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
54747
55053
  if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
54748
- return personaIdFromPath(path56.resolve(absPath), personaRoot) === personaId;
55054
+ return personaIdFromPath(path56.resolve(absPath), personaRoot) === personaId2;
54749
55055
  }
54750
55056
 
54751
55057
  // src/handlers/history.ts
@@ -54878,9 +55184,9 @@ var path58 = __toESM(require("path"), 1);
54878
55184
  var os16 = __toESM(require("os"), 1);
54879
55185
  init_protocol();
54880
55186
  init_protocol();
54881
- function buildEnabledPluginNames(personaManager, personaId) {
55187
+ function buildEnabledPluginNames(personaManager, personaId2) {
54882
55188
  const out = /* @__PURE__ */ new Set();
54883
- for (const p2 of personaManager.listEnabledPlugins(personaId)) {
55189
+ for (const p2 of personaManager.listEnabledPlugins(personaId2)) {
54884
55190
  const name = p2.id.includes("@") ? p2.id.slice(0, p2.id.indexOf("@")) : p2.id;
54885
55191
  if (name) out.add(name);
54886
55192
  }
@@ -54935,8 +55241,8 @@ function buildWorkspaceHandlers(deps) {
54935
55241
  assertGuestPath2(ctx, cwdAbs, personaRoot, "skills:list", usersRoot);
54936
55242
  const list2 = await getSkillsForTool(args.tool ?? "claude", cwdAbs);
54937
55243
  if (ctx?.principal.kind === "guest" && personaRoot) {
54938
- const personaId = personaIdFromPath(cwdAbs, personaRoot);
54939
- const enabled = personaId ? buildEnabledPluginNames(personaManager, personaId) : /* @__PURE__ */ new Set();
55244
+ const personaId2 = personaIdFromPath(cwdAbs, personaRoot);
55245
+ const enabled = personaId2 ? buildEnabledPluginNames(personaManager, personaId2) : /* @__PURE__ */ new Set();
54940
55246
  return { response: { type: "skills:list", skills: filterGuestSkills(list2, enabled) } };
54941
55247
  }
54942
55248
  return { response: { type: "skills:list", skills: list2 } };
@@ -54950,8 +55256,8 @@ function buildWorkspaceHandlers(deps) {
54950
55256
  }
54951
55257
  const list2 = agents.list(args);
54952
55258
  if (ctx?.principal.kind === "guest" && personaRoot) {
54953
- const personaId = personaIdFromPath(cwdAbs, personaRoot);
54954
- const enabled = personaId ? buildEnabledPluginNames(personaManager, personaId) : /* @__PURE__ */ new Set();
55259
+ const personaId2 = personaIdFromPath(cwdAbs, personaRoot);
55260
+ const enabled = personaId2 ? buildEnabledPluginNames(personaManager, personaId2) : /* @__PURE__ */ new Set();
54955
55261
  return { response: { type: "agents:list", agents: filterGuestAgents(list2, enabled) } };
54956
55262
  }
54957
55263
  return { response: { type: "agents:list", agents: list2 } };
@@ -55124,8 +55430,7 @@ function resolvePeerDeviceId(ctx, argsPeerDeviceId) {
55124
55430
  function buildInboxHandlers(deps) {
55125
55431
  const { manager } = deps;
55126
55432
  const postMessage = async (frame, _client, ctx) => {
55127
- const { type: _t, requestId: _r, ...rest } = frame;
55128
- const args = InboxPostMessageArgsSchema.parse(rest);
55433
+ const args = parseArgs2(InboxPostMessageArgsSchema, frame, "inbox:postMessage");
55129
55434
  if (!ctx) {
55130
55435
  throw new ClawdError(ERROR_CODES.INTERNAL, "inbox:postMessage: missing ConnectionContext");
55131
55436
  }
@@ -55143,8 +55448,7 @@ function buildInboxHandlers(deps) {
55143
55448
  };
55144
55449
  };
55145
55450
  const list = async (frame, _client, ctx) => {
55146
- const { type: _t, requestId: _r, ...rest } = frame;
55147
- const args = InboxListArgsSchema.parse(rest);
55451
+ const args = parseArgs2(InboxListArgsSchema, frame, "inbox:list");
55148
55452
  if (!ctx) {
55149
55453
  throw new ClawdError(ERROR_CODES.INTERNAL, "inbox:list: missing ConnectionContext");
55150
55454
  }
@@ -55155,8 +55459,7 @@ function buildInboxHandlers(deps) {
55155
55459
  };
55156
55460
  };
55157
55461
  const markRead = async (frame, _client, ctx) => {
55158
- const { type: _t, requestId: _r, ...rest } = frame;
55159
- const args = InboxMarkReadArgsSchema.parse(rest);
55462
+ const args = parseArgs2(InboxMarkReadArgsSchema, frame, "inbox:markRead");
55160
55463
  if (!ctx) {
55161
55464
  throw new ClawdError(ERROR_CODES.INTERNAL, "inbox:markRead: missing ConnectionContext");
55162
55465
  }
@@ -55178,7 +55481,7 @@ function buildInboxHandlers(deps) {
55178
55481
  const sendDm = async (frame) => {
55179
55482
  const { type: _t, requestId: _r, ...rest } = frame;
55180
55483
  const sessionId = typeof rest.sessionId === "string" ? rest.sessionId : void 0;
55181
- const args = InboxSendDmArgsSchema.parse(rest);
55484
+ const args = parseArgs2(InboxSendDmArgsSchema, frame, "inbox:sendDm");
55182
55485
  const d = deps.sendDmDeps;
55183
55486
  if (!d) throw new ClawdError(ERROR_CODES.INTERNAL, "inbox:sendDm not wired");
55184
55487
  if (!sessionId) {
@@ -55339,8 +55642,7 @@ function buildContactHandlers(deps) {
55339
55642
  };
55340
55643
  const pin = async (frame, _client, ctx) => {
55341
55644
  ensureOwner(ctx);
55342
- const { type: _t, requestId: _r, ...rest } = frame;
55343
- const args = ContactPinArgsSchema.parse(rest);
55645
+ const args = parseArgs2(ContactPinArgsSchema, frame, "contact:pin");
55344
55646
  const pinnedAt = args.pinned ? deps.now() : null;
55345
55647
  const hit = deps.store.setPin(args.deviceId, pinnedAt);
55346
55648
  if (!hit) {
@@ -55364,8 +55666,7 @@ function buildContactHandlers(deps) {
55364
55666
  };
55365
55667
  const remove = async (frame, _client, ctx) => {
55366
55668
  ensureOwner(ctx);
55367
- const { type: _t, requestId: _r, ...rest } = frame;
55368
- const args = ContactRemoveArgsSchema.parse(rest);
55669
+ const args = parseArgs2(ContactRemoveArgsSchema, frame, "contact:remove");
55369
55670
  deps.store.removeByDeviceId(args.deviceId);
55370
55671
  deps.broadcast({
55371
55672
  type: "contact:removed",
@@ -55385,8 +55686,7 @@ function buildContactHandlers(deps) {
55385
55686
  "contact:handshake \u4EC5\u63A5\u53D7 connect-token \u8FDE\u63A5\uFF08\u8BBE\u5907\u4E92\u8FDE\u63E1\u624B\u4E13\u7528\uFF09"
55386
55687
  );
55387
55688
  }
55388
- const { type: _t, requestId: _r, ...rest } = frame;
55389
- const args = ContactHandshakeArgsSchema.parse(rest);
55689
+ const args = parseArgs2(ContactHandshakeArgsSchema, frame, "contact:handshake");
55390
55690
  const contact = upsertPeerContact({
55391
55691
  store: deps.store,
55392
55692
  broadcast: deps.broadcast,
@@ -55437,8 +55737,7 @@ function ensureOwner2(ctx) {
55437
55737
  function buildContactRemoteAccessHandlers(deps) {
55438
55738
  const setRemoteAccess = async (frame, _client, ctx) => {
55439
55739
  ensureOwner2(ctx);
55440
- const { type: _t, requestId: _r, ...rest } = frame;
55441
- const args = ContactSetRemoteAccessArgsSchema.parse(rest);
55740
+ const args = parseArgs2(ContactSetRemoteAccessArgsSchema, frame, "contact:setRemoteAccess");
55442
55741
  const hit = deps.store.setRemoteAccess(args.deviceId, {
55443
55742
  remoteAccessAllowed: args.remoteAccessAllowed
55444
55743
  });
@@ -55880,24 +56179,28 @@ function computeGrant(method) {
55880
56179
  }
55881
56180
  function computeMethodAccess(args) {
55882
56181
  const { method, grants, feishuActive, isImplemented } = args;
56182
+ const description = METHOD_DOCS[method].summary;
56183
+ const argFields = methodArgFields(method);
55883
56184
  if (!isImplemented(method)) {
55884
- return { name: method, status: "denied", reason: "METHOD_NOT_IMPLEMENTED" };
56185
+ return { name: method, description, args: argFields, status: "denied", reason: "METHOD_NOT_IMPLEMENTED" };
55885
56186
  }
55886
56187
  if (!feishuActive && FEISHU_GATED_METHODS.includes(method)) {
55887
- return { name: method, status: "denied", reason: "FEISHU_LOGIN_REQUIRED" };
56188
+ return { name: method, description, args: argFields, status: "denied", reason: "FEISHU_LOGIN_REQUIRED" };
55888
56189
  }
55889
56190
  if (METHOD_GRANT_MAP[method]?.kind === "capability-scoped") {
55890
56191
  return {
55891
56192
  name: method,
56193
+ description,
56194
+ args: argFields,
55892
56195
  status: "conditional",
55893
56196
  reason: "handler checks your grants for the target resource"
55894
56197
  };
55895
56198
  }
55896
56199
  const verdict = computeGrant(method);
55897
56200
  if (verdict.kind === "check" && !assertGrant(grants, verdict.resource, verdict.action)) {
55898
- return { name: method, status: "denied", reason: "UNAUTHORIZED" };
56201
+ return { name: method, description, args: argFields, status: "denied", reason: "UNAUTHORIZED" };
55899
56202
  }
55900
- return { name: method, status: "allowed" };
56203
+ return { name: method, description, args: argFields, status: "allowed" };
55901
56204
  }
55902
56205
 
55903
56206
  // src/version.ts
@@ -55973,7 +56276,7 @@ function buildPersonaHandlers(deps) {
55973
56276
  const { personaManager, personaRegistry } = deps;
55974
56277
  const create = async (frame) => {
55975
56278
  const { type: _type, requestId: _requestId, ...rest } = frame;
55976
- const args = PersonaCreateArgsSchema.parse(rest);
56279
+ const args = parseArgs2(PersonaCreateArgsSchema, frame, "persona:create");
55977
56280
  const persona = personaManager.create(args);
55978
56281
  return { response: { type: "persona:info", ...persona } };
55979
56282
  };
@@ -55989,7 +56292,7 @@ function buildPersonaHandlers(deps) {
55989
56292
  };
55990
56293
  };
55991
56294
  const get = async (frame, _client, ctx) => {
55992
- const args = PersonaIdArgsSchema.parse(frame);
56295
+ const args = parseArgs2(PersonaIdArgsSchema, frame, "persona:get");
55993
56296
  const persona = personaRegistry.get(args.personaId) ?? null;
55994
56297
  if (!persona) {
55995
56298
  return { response: { type: "persona:info", persona: null } };
@@ -56018,13 +56321,13 @@ function buildPersonaHandlers(deps) {
56018
56321
  };
56019
56322
  const update = async (frame) => {
56020
56323
  const { type: _type, requestId: _requestId, ...rest } = frame;
56021
- const args = PersonaUpdateArgsSchema.parse(rest);
56324
+ const args = parseArgs2(PersonaUpdateArgsSchema, frame, "persona:update");
56022
56325
  const { personality, ...metaPatch } = args.patch;
56023
56326
  const persona = personaManager.update(args.personaId, metaPatch, personality);
56024
56327
  return { response: { type: "persona:info", ...persona } };
56025
56328
  };
56026
56329
  const del = async (frame) => {
56027
- const args = PersonaIdArgsSchema.parse(frame);
56330
+ const args = parseArgs2(PersonaIdArgsSchema, frame, "persona:get");
56028
56331
  personaManager.delete(args.personaId);
56029
56332
  return {
56030
56333
  response: { type: "persona:deleted", personaId: args.personaId }
@@ -56582,32 +56885,6 @@ async function rollback(deps, localExtId, liveDir, prevDir) {
56582
56885
  }
56583
56886
 
56584
56887
  // src/handlers/extension.ts
56585
- function pickChannelRef(frame) {
56586
- const ref = frame.channelRef;
56587
- const parsed = ChannelRefSchema.safeParse(ref);
56588
- if (!parsed.success) {
56589
- throw new ClawdError(
56590
- ERROR_CODES.INVALID_PARAM,
56591
- `channelRef invalid: ${parsed.error.issues.map((i) => i.message).join("; ")}`
56592
- );
56593
- }
56594
- return parsed.data;
56595
- }
56596
- function pickStringField(frame, name) {
56597
- const v2 = frame[name];
56598
- if (typeof v2 !== "string" || v2.length === 0) {
56599
- throw new ClawdError(ERROR_CODES.INVALID_PARAM, `${name} required`);
56600
- }
56601
- return v2;
56602
- }
56603
- function pickOptionalString(frame, name) {
56604
- const v2 = frame[name];
56605
- if (v2 === void 0 || v2 === null) return null;
56606
- if (typeof v2 !== "string") {
56607
- throw new ClawdError(ERROR_CODES.INVALID_PARAM, `${name} must be string`);
56608
- }
56609
- return v2;
56610
- }
56611
56888
  async function rewriteManifestVersion(root, extId, newVersion, previousPublishedVersion) {
56612
56889
  const v2 = validateSimpleSemver(newVersion);
56613
56890
  if (!v2.ok) {
@@ -56665,13 +56942,6 @@ function assertOwner(ctx) {
56665
56942
  throw new ClawdError(ERROR_CODES.FORBIDDEN, "owner only");
56666
56943
  }
56667
56944
  }
56668
- function pickExtId(frame) {
56669
- const extId = frame.extId;
56670
- if (typeof extId !== "string") {
56671
- throw new ClawdError(ERROR_CODES.INVALID_PARAM, "extId required");
56672
- }
56673
- return extId;
56674
- }
56675
56945
  function composeState(rec3, running, crashed, getPort) {
56676
56946
  if (rec3.state === "invalid") return rec3;
56677
56947
  if (manifestMode(rec3.manifest) === "hosted") {
@@ -56705,19 +56975,19 @@ function buildExtensionHandlers(deps) {
56705
56975
  };
56706
56976
  const open = async (frame, _client, ctx) => {
56707
56977
  assertOwner(ctx);
56708
- const extId = pickExtId(frame);
56978
+ const { extId } = parseArgs2(ExtensionIdArgs, frame, "extension", ERROR_CODES.INVALID_PARAM);
56709
56979
  const target = await deps.runtime.open(extId);
56710
56980
  return { response: target };
56711
56981
  };
56712
56982
  const close = async (frame, _client, ctx) => {
56713
56983
  assertOwner(ctx);
56714
- const extId = pickExtId(frame);
56984
+ const { extId } = parseArgs2(ExtensionIdArgs, frame, "extension", ERROR_CODES.INVALID_PARAM);
56715
56985
  await deps.runtime.close(extId);
56716
56986
  return { response: { ok: true } };
56717
56987
  };
56718
56988
  const uninstall2 = async (frame, _client, ctx) => {
56719
56989
  assertOwner(ctx);
56720
- const extId = pickExtId(frame);
56990
+ const { extId } = parseArgs2(ExtensionIdArgs, frame, "extension", ERROR_CODES.INVALID_PARAM);
56721
56991
  await deps.uninstall({ root: deps.root, extId, runtime: deps.runtime });
56722
56992
  return { response: { ok: true } };
56723
56993
  };
@@ -56728,9 +56998,8 @@ function buildExtensionHandlers(deps) {
56728
56998
  }
56729
56999
  const publish = async (frame, _client, ctx) => {
56730
57000
  assertOwner(ctx);
56731
- const extId = pickExtId(frame);
56732
- const newVersion = pickOptionalString(frame, "newVersion");
56733
- if (newVersion !== null) {
57001
+ const { extId, newVersion } = parseArgs2(ExtensionPublishArgs, frame, "publish", ERROR_CODES.INVALID_PARAM);
57002
+ if (newVersion != null) {
56734
57003
  await rewriteManifestVersion(deps.root, extId, newVersion, deps.publishedChannelStore.get(extId)?.version);
56735
57004
  }
56736
57005
  const { manifest, contentHash, buffer } = await buildSnapshotMeta(extId);
@@ -56774,7 +57043,7 @@ function buildExtensionHandlers(deps) {
56774
57043
  };
56775
57044
  const unpublish = async (frame, _client, ctx) => {
56776
57045
  assertOwner(ctx);
56777
- const extId = pickExtId(frame);
57046
+ const { extId } = parseArgs2(ExtensionIdArgs, frame, "extension", ERROR_CODES.INVALID_PARAM);
56778
57047
  const head = deps.publishedChannelStore.get(extId);
56779
57048
  await deps.publishedChannelStore.delete(extId);
56780
57049
  if (head) {
@@ -56784,7 +57053,7 @@ function buildExtensionHandlers(deps) {
56784
57053
  };
56785
57054
  const publishStatus = async (frame, _client, ctx) => {
56786
57055
  assertOwner(ctx);
56787
- const extId = pickExtId(frame);
57056
+ const { extId } = parseArgs2(ExtensionIdArgs, frame, "extension", ERROR_CODES.INVALID_PARAM);
56788
57057
  const { manifest, contentHash } = await buildSnapshotMeta(extId);
56789
57058
  const head = deps.publishedChannelStore.get(extId);
56790
57059
  const check = computePublishCheck({
@@ -56833,8 +57102,7 @@ function buildExtensionHandlers(deps) {
56833
57102
  if (!ctx || ctx.principal.kind !== "guest") {
56834
57103
  throw new ClawdError(ERROR_CODES.FORBIDDEN, "guest only");
56835
57104
  }
56836
- pickExtId(frame);
56837
- const expectedHash = pickStringField(frame, "snapshotHash");
57105
+ const { snapshotHash: expectedHash } = parseArgs2(ExtensionFetchBundleArgs, frame, "fetchBundle", ERROR_CODES.INVALID_PARAM);
56838
57106
  const cached = await deps.bundleCache.read(expectedHash);
56839
57107
  if (cached === null) {
56840
57108
  throw new ClawdError(
@@ -56846,9 +57114,7 @@ function buildExtensionHandlers(deps) {
56846
57114
  };
56847
57115
  const installFromChannelHandler = async (frame, _client, ctx) => {
56848
57116
  assertOwner(ctx);
56849
- const channelRef = pickChannelRef(frame);
56850
- const snapshotHash = pickStringField(frame, "snapshotHash");
56851
- const zipBase64 = pickStringField(frame, "zipBase64");
57117
+ const { channelRef, snapshotHash, zipBase64 } = parseArgs2(ExtensionFromChannelArgs, frame, "fromChannel", ERROR_CODES.INVALID_PARAM);
56852
57118
  const bundleZip = Buffer.from(zipBase64, "base64");
56853
57119
  try {
56854
57120
  const { extId, installedVersion } = await installFromChannel(
@@ -56868,9 +57134,7 @@ function buildExtensionHandlers(deps) {
56868
57134
  };
56869
57135
  const updateFromChannelHandler = async (frame, _client, ctx) => {
56870
57136
  assertOwner(ctx);
56871
- const channelRef = pickChannelRef(frame);
56872
- const snapshotHash = pickStringField(frame, "snapshotHash");
56873
- const zipBase64 = pickStringField(frame, "zipBase64");
57137
+ const { channelRef, snapshotHash, zipBase64 } = parseArgs2(ExtensionFromChannelArgs, frame, "fromChannel", ERROR_CODES.INVALID_PARAM);
56874
57138
  const bundleZip = Buffer.from(zipBase64, "base64");
56875
57139
  try {
56876
57140
  const result = await updateFromChannel(
@@ -57635,10 +57899,7 @@ function buildAppBuilderHandlers(deps) {
57635
57899
  return { response: { projects: metas.map(toProjectWithStatus) } };
57636
57900
  };
57637
57901
  const getProject = async (frame, _client, ctx) => {
57638
- const f = frame;
57639
- if (typeof f.sessionId !== "string" || !f.sessionId) {
57640
- throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "getProject: sessionId required");
57641
- }
57902
+ const f = parseArgs2(GetProjectArgsSchema, frame, "getProject");
57642
57903
  if (ctx && !canAccessSession(ctx, f.sessionId, "read", {
57643
57904
  readSession: (sid) => sessionManager.findOwnedSession(sid) ?? null
57644
57905
  })) {
@@ -57653,13 +57914,7 @@ function buildAppBuilderHandlers(deps) {
57653
57914
  return { response: { project: meta ? toProjectWithStatus(meta) : null } };
57654
57915
  };
57655
57916
  const createProject = async (frame, _client, ctx) => {
57656
- const f = frame;
57657
- if (typeof f.sessionId !== "string" || !f.sessionId) {
57658
- throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "createProject: sessionId required");
57659
- }
57660
- if (typeof f.name !== "string" || !f.name) {
57661
- throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "createProject: name required");
57662
- }
57917
+ const f = parseArgs2(CreateProjectArgsSchema, frame, "createProject");
57663
57918
  const session = sessionManager.findOwnedSession(f.sessionId);
57664
57919
  if (!session) {
57665
57920
  throw new ClawdError(ERROR_CODES.SESSION_NOT_FOUND, `session ${f.sessionId} not found`);
@@ -57713,8 +57968,7 @@ function buildAppBuilderHandlers(deps) {
57713
57968
  return { response: { project, projectDir: userStore.projectDir(project.name) }, broadcast };
57714
57969
  };
57715
57970
  const deleteProject = async (frame, _client, ctx) => {
57716
- const name = frame.name;
57717
- if (typeof name !== "string") throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "deleteProject: name required");
57971
+ const { name } = parseArgs2(DeleteProjectArgsSchema, frame, "deleteProject");
57718
57972
  const userStore = resolveStore({ ctx, projectName: name });
57719
57973
  await devServerLifecycle.stopForProject(name);
57720
57974
  await userStore.delete(name);
@@ -57722,9 +57976,7 @@ function buildAppBuilderHandlers(deps) {
57722
57976
  return { response: {} };
57723
57977
  };
57724
57978
  const updateProjectPort = async (frame, _client, ctx) => {
57725
- const f = frame;
57726
- if (typeof f.name !== "string") throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "updateProjectPort: name required");
57727
- if (typeof f.newPort !== "number") throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "updateProjectPort: newPort required");
57979
+ const f = parseArgs2(UpdateProjectPortArgsSchema, frame, "updateProjectPort");
57728
57980
  const userStore = resolveStore({ ctx, projectName: f.name });
57729
57981
  await devServerLifecycle.stopForProject(f.name);
57730
57982
  const project = await userStore.updatePort(f.name, f.newPort);
@@ -57732,9 +57984,7 @@ function buildAppBuilderHandlers(deps) {
57732
57984
  return { response: { project } };
57733
57985
  };
57734
57986
  const setProdUrl = async (frame, _client, ctx) => {
57735
- const f = frame;
57736
- if (typeof f.name !== "string") throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "setProdUrl: name required");
57737
- if (typeof f.url !== "string") throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "setProdUrl: url required");
57987
+ const f = parseArgs2(SetProdUrlArgsSchema, frame, "setProdUrl");
57738
57988
  ensureProjectWriteAccess(ctx, { projectName: f.name });
57739
57989
  const userStore = resolveStore({ ctx, projectName: f.name });
57740
57990
  const project = await userStore.setProdUrl(f.name, f.url);
@@ -57743,10 +57993,7 @@ function buildAppBuilderHandlers(deps) {
57743
57993
  return { response: { project } };
57744
57994
  };
57745
57995
  const startDevServer = async (frame, _client, ctx) => {
57746
- const f = frame;
57747
- if (typeof f.sessionId !== "string" || !f.sessionId) {
57748
- throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "startDevServer: sessionId required");
57749
- }
57996
+ const f = parseArgs2(StartDevServerArgsSchema, frame, "startDevServer");
57750
57997
  const force = f.force === true;
57751
57998
  ensureProjectWriteAccess(ctx, { sessionId: f.sessionId });
57752
57999
  const session = sessionManager.findOwnedSession(f.sessionId);
@@ -57805,13 +58052,7 @@ function buildAppBuilderHandlers(deps) {
57805
58052
  return { response: { project: meta } };
57806
58053
  };
57807
58054
  const reportStage = async (frame, _client, ctx) => {
57808
- const f = frame;
57809
- if (typeof f.sessionId !== "string" || !f.sessionId) {
57810
- throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "reportStage: sessionId required");
57811
- }
57812
- if (typeof f.stage !== "string") {
57813
- throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "reportStage: stage required");
57814
- }
58055
+ const f = parseArgs2(ReportStageArgsSchema, frame, "reportStage");
57815
58056
  if (!ASSISTANT_REPORTABLE_STAGES.includes(f.stage)) {
57816
58057
  throw new ClawdError(
57817
58058
  ERROR_CODES.VALIDATION_ERROR,
@@ -57839,10 +58080,7 @@ function buildAppBuilderHandlers(deps) {
57839
58080
  return { response: { ok: true } };
57840
58081
  };
57841
58082
  const stopDevServer = async (frame, _client, ctx) => {
57842
- const f = frame;
57843
- if (typeof f.sessionId !== "string" || !f.sessionId) {
57844
- throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "stopDevServer: sessionId required");
57845
- }
58083
+ const f = parseArgs2(StopDevServerArgsSchema, frame, "stopDevServer");
57846
58084
  ensureProjectWriteAccess(ctx, { sessionId: f.sessionId });
57847
58085
  const session = sessionManager.findOwnedSession(f.sessionId);
57848
58086
  if (!session) {
@@ -58652,6 +58890,7 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
58652
58890
  };
58653
58891
 
58654
58892
  // src/handlers/dispatch-rpc.ts
58893
+ init_zod();
58655
58894
  init_protocol();
58656
58895
  async function dispatchRpc(method, frame, client, ctx, deps) {
58657
58896
  if (!METHOD_NAMES.includes(method)) {
@@ -58675,7 +58914,14 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
58675
58914
  );
58676
58915
  }
58677
58916
  }
58678
- return handler(frame, client, ctx);
58917
+ try {
58918
+ return await handler(frame, client, ctx);
58919
+ } catch (err) {
58920
+ if (err instanceof ZodError) {
58921
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, err.message);
58922
+ }
58923
+ throw err;
58924
+ }
58679
58925
  }
58680
58926
 
58681
58927
  // src/extension/runtime.ts
@@ -59383,7 +59629,7 @@ async function startDaemon(config) {
59383
59629
  personaRoot: import_node_path62.default.join(config.dataDir, "personas"),
59384
59630
  // dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
59385
59631
  // personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
59386
- getPersonaTool: (personaId) => personaRegistry.get(personaId)?.tool,
59632
+ getPersonaTool: (personaId2) => personaRegistry.get(personaId2)?.tool,
59387
59633
  usersRoot,
59388
59634
  personaStore,
59389
59635
  ownerDisplayName,
@@ -59805,7 +60051,7 @@ async function startDaemon(config) {
59805
60051
  // 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
59806
60052
  deployKitRoot: import_node_path62.default.join(config.dataDir, "deploy-kit"),
59807
60053
  // scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
59808
- resolvePersonaRoot: (personaId) => import_node_path62.default.join(config.dataDir, "personas", personaId),
60054
+ resolvePersonaRoot: (personaId2) => import_node_path62.default.join(config.dataDir, "personas", personaId2),
59809
60055
  // 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
59810
60056
  // 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
59811
60057
  // 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
@@ -59899,9 +60145,9 @@ async function startDaemon(config) {
59899
60145
  });
59900
60146
  },
59901
60147
  // B 角色:判断 targetPersona 是否 public(跨设备授权边界,private 拒)。
59902
- getPersonaPublic: (personaId) => personaRegistry.get(personaId)?.public ?? false,
60148
+ getPersonaPublic: (personaId2) => personaRegistry.get(personaId2)?.public ?? false,
59903
60149
  // model 校验按 target persona 绑定 tool 选表(claude / codex 模型集不同)
59904
- getPersonaTool: (personaId) => personaRegistry.get(personaId)?.tool
60150
+ getPersonaTool: (personaId2) => personaRegistry.get(personaId2)?.tool
59905
60151
  });
59906
60152
  handlers = { ...handlers, ...dispatchHandlers };
59907
60153
  const shiftHandlers = buildShiftInternalHandlers({