@clawos-dev/clawd 0.2.262 → 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.
@@ -21114,54 +21114,6 @@ var import_node_child_process = require("child_process");
21114
21114
  var import_node_child_process2 = require("child_process");
21115
21115
  var import_node_fs2 = __toESM(require("fs"), 1);
21116
21116
 
21117
- // ../protocol/src/methods.ts
21118
- var RPC_METHOD_STATUSES = ["allowed", "conditional", "denied"];
21119
- var RpcMethodStatusSchema = external_exports.enum(RPC_METHOD_STATUSES);
21120
- var RpcMethodInfoSchema = external_exports.object({
21121
- /** canonical method 名,直接可作为 clawd-rpc call 的 method 参数 */
21122
- name: external_exports.string().min(1),
21123
- status: RpcMethodStatusSchema,
21124
- /**
21125
- * `denied` 必带:daemon error code(`UNAUTHORIZED` / `FEISHU_LOGIN_REQUIRED` /
21126
- * `METHOD_NOT_IMPLEMENTED`)。`conditional` 必带:谁来做二次校验。
21127
- * `allowed` 恒无。
21128
- */
21129
- reason: external_exports.string().optional()
21130
- });
21131
- var MetaMethodsResultSchema = external_exports.object({
21132
- type: external_exports.literal("meta:methods"),
21133
- /** METHOD_NAMES 全集,顺序与之一致 */
21134
- methods: external_exports.array(RpcMethodInfoSchema)
21135
- });
21136
-
21137
- // ../protocol/src/events.ts
21138
- var SESSION_STATUS_VALUES = [
21139
- "idle",
21140
- "running",
21141
- "running-idle",
21142
- "stopped",
21143
- "error",
21144
- "observing"
21145
- ];
21146
- var HISTORY_USER_META_VALUES = [
21147
- "task-notification",
21148
- "slash-command",
21149
- "local-command",
21150
- "system-reminder",
21151
- "skill-hint",
21152
- "meta-text",
21153
- "attachment-skills",
21154
- "attachment-deferred-tools"
21155
- ];
21156
- var SKILL_SOURCE_VALUES = ["builtin", "global", "project", "plugin"];
21157
- var AGENT_SOURCE_VALUES = [
21158
- "builtin",
21159
- "global",
21160
- "project",
21161
- "policy",
21162
- "plugin"
21163
- ];
21164
-
21165
21117
  // ../protocol/src/attachment-schemas.ts
21166
21118
  var TOKEN_ROLES = ["owner"];
21167
21119
  var GROUP_FILE_SOURCES = ["agent", "owner", "user-upload"];
@@ -21239,1575 +21191,2133 @@ var AttachmentUploadResponseSchema = external_exports.object({
21239
21191
  mimeType: external_exports.string().min(1)
21240
21192
  });
21241
21193
 
21242
- // ../protocol/src/principal.ts
21243
- var PrincipalKindSchema = external_exports.enum(["owner", "guest"]);
21244
- var PrincipalSchema = external_exports.object({
21194
+ // ../protocol/src/capability.ts
21195
+ var ResourceSchema2 = external_exports.discriminatedUnion("type", [
21196
+ external_exports.object({ type: external_exports.literal("persona"), id: external_exports.string().min(1) }).strict(),
21197
+ external_exports.object({ type: external_exports.literal("chat"), id: external_exports.string().min(1) }).strict(),
21198
+ external_exports.object({ type: external_exports.literal("*") }).strict()
21199
+ ]);
21200
+ var ActionSchema = external_exports.enum(["read", "send", "admin"]);
21201
+ var GrantSchema = external_exports.object({
21202
+ resource: ResourceSchema2,
21203
+ actions: external_exports.array(ActionSchema).min(1)
21204
+ }).strict();
21205
+ var CapabilitySchema = external_exports.object({
21245
21206
  id: external_exports.string().min(1),
21246
- kind: PrincipalKindSchema,
21207
+ // sha256(token) hex 64
21208
+ secretHash: external_exports.string().regex(/^[a-f0-9]{64}$/),
21247
21209
  displayName: external_exports.string(),
21210
+ // 空数组合法 = 纯访客(只能 DM)
21211
+ grants: external_exports.array(GrantSchema),
21212
+ issuedAt: external_exports.number().int().nonnegative(),
21213
+ expiresAt: external_exports.number().int().positive().optional(),
21214
+ maxUses: external_exports.number().int().positive().optional(),
21215
+ usedCount: external_exports.number().int().nonnegative(),
21248
21216
  /**
21249
- * 飞书 union_id。owner: 本机 daemon 已飞书登录时透传自 owner-identity.json;未登录 undefined。
21250
- * guest: v1 保持 undefined(connect token 当前不携带 unionId;未来若签名 payload 加字段可透传)。
21251
- * 消费方(如 ticket MCP / 未来别的飞书身份挂钩场景)按 undefined 决定是否降级;本层不做 fallback。
21217
+ * guest auth 帧捎带 selfPrincipalId 时由 AuthGate.authenticate 回写;
21218
+ * 未被消费的 cap 此字段缺失。
21252
21219
  */
21253
- feishuUnionId: external_exports.string().optional()
21220
+ peerOwnerId: external_exports.string().min(1).optional(),
21221
+ /** 首次 client hello 时间戳(与 peerOwnerId 同步写入) */
21222
+ firstUsedByPeerAt: external_exports.number().int().positive().optional(),
21223
+ /**
21224
+ * 对方 daemon owner 的 displayName,guest auth 帧 selfDisplayName 触发
21225
+ * recordPeerHello 时同步回写。视角 B (2026-05-23) UI 派生联系人列表用此字段
21226
+ * 显示对方名字(避免 fallback 到我颁 cap 时填的 displayName)。
21227
+ */
21228
+ peerDisplayName: external_exports.string().optional()
21254
21229
  }).strict();
21255
- var SenderInfoSchema = external_exports.object({
21256
- /** = principal.id = deviceId(决策 #16)。稳定路由 id */
21257
- did: external_exports.string().min(1),
21258
- displayName: external_exports.string(),
21259
- /** owner 未登录 / guest 无飞书身份时缺省。消费方各自决定是否降级 */
21260
- feishuUnionId: external_exports.string().optional(),
21261
- principal: PrincipalKindSchema
21230
+ var CapabilityWireSchema = CapabilitySchema.omit({ secretHash: true });
21231
+ var WhoamiResponseSchema = external_exports.object({
21232
+ type: external_exports.literal("whoami:ok"),
21233
+ owner: external_exports.object({
21234
+ id: external_exports.string(),
21235
+ kind: external_exports.enum(["owner", "guest"]),
21236
+ displayName: external_exports.string(),
21237
+ /** 归属人 id(决策 #16:TTC unique_id 等,落 contact.ownerId) */
21238
+ ownerId: external_exports.string(),
21239
+ /** 身份来源(决策 #16:'ttc'/'google',落 contact.provider) */
21240
+ provider: external_exports.string()
21241
+ }).strict(),
21242
+ capability: CapabilityWireSchema,
21243
+ grantedPersonas: external_exports.array(
21244
+ external_exports.object({
21245
+ id: external_exports.string().min(1),
21246
+ displayName: external_exports.string()
21247
+ }).strict()
21248
+ )
21262
21249
  }).strict();
21250
+ var PERSONAL_CAP_GRANTS = Object.freeze([
21251
+ Object.freeze({
21252
+ resource: Object.freeze({ type: "persona", id: "*" }),
21253
+ actions: Object.freeze(["read", "send"])
21254
+ })
21255
+ ]);
21263
21256
 
21264
- // ../protocol/src/persona-schemas.ts
21265
- var PersonaFileSchema = external_exports.object({
21266
- personaId: external_exports.string(),
21267
- label: external_exports.string(),
21268
- model: external_exports.string().optional(),
21269
- public: external_exports.boolean(),
21270
- // 8-key set defined UI-side in `lib/session-icons.ts`; protocol stays plain string
21271
- // for forward compatibility, consumer fallbacks to default when key not found.
21272
- iconKey: external_exports.string().optional(),
21273
- // 绑定的 agent tool('claude' / 'codex');缺省消费侧按 'claude' 兜底。
21274
- // 与 model 平行:persona 新建 session 的默认 tool,可平滑切换。
21275
- tool: external_exports.string().optional(),
21276
- createdAt: external_exports.number(),
21277
- updatedAt: external_exports.number()
21278
- }).strict();
21279
- var PersonaSkillSummarySchema = external_exports.object({
21280
- // 目录名作为 skill name(对齐 CC:frontmatter `name:` 仅作 displayName 用)
21281
- name: external_exports.string().min(1),
21282
- // SKILL.md frontmatter `description:`;缺省时省略字段
21283
- description: external_exports.string().optional()
21284
- });
21285
- var PersonaPluginSummarySchema = external_exports.object({
21286
- // settings.json 中 enabledPlugins 的 key,例如 'superpowers@claude-plugins-official'
21287
- id: external_exports.string().min(1)
21288
- });
21289
- var PersonaSandboxSettingsSchema = external_exports.object({
21290
- permissions: external_exports.object({
21291
- defaultMode: external_exports.string().optional(),
21292
- // CC 工具 allowlist('Bash'/'Read'/...)。per-persona profile 在最严格 base 上追加放开。
21293
- allow: external_exports.array(external_exports.string()).optional(),
21294
- // deny 优先级最高;强制底座(persona 私密区)由 daemon compose 强制 union,owner 删不掉。
21295
- deny: external_exports.array(external_exports.string()).optional()
21296
- }).optional(),
21297
- sandbox: external_exports.object({
21298
- enabled: external_exports.boolean().optional(),
21299
- autoAllowBashIfSandboxed: external_exports.boolean().optional(),
21300
- allowUnsandboxedCommands: external_exports.boolean().optional(),
21301
- // 命令前缀白名单(CC `sandbox.excludedCommands`):匹配的命令在沙箱外运行,
21302
- // 用于需逃出沙箱的工具(如 'docker *' / 'aliyun *' 要访问宿主 socket / 凭证)。
21303
- excludedCommands: external_exports.array(external_exports.string()).optional(),
21304
- filesystem: external_exports.object({
21305
- denyRead: external_exports.array(external_exports.string()).optional(),
21306
- allowRead: external_exports.array(external_exports.string()).optional(),
21307
- denyWrite: external_exports.array(external_exports.string()).optional(),
21308
- allowWrite: external_exports.array(external_exports.string()).optional()
21309
- }).optional(),
21310
- // 出站网络 + 本机端口。base 不放(空),profile 按需追加域名(app-builder = ['*'])。
21311
- network: external_exports.object({
21312
- allowedDomains: external_exports.array(external_exports.string()).optional(),
21313
- allowLocalBinding: external_exports.boolean().optional()
21314
- }).optional()
21315
- }).optional()
21257
+ // ../protocol/src/contact-handshake.ts
21258
+ var ContactHandshakeArgsSchema = external_exports.object({
21259
+ selfUrl: external_exports.string().min(1)
21316
21260
  });
21317
- var PersonaInfoResponseSchema = PersonaFileSchema.extend({
21318
- personality: external_exports.string().optional(),
21319
- // 仅 'persona:get' 携带;null = 文件不存在 / parse 失败;undefined = 不在该响应类型上
21320
- skills: external_exports.array(PersonaSkillSummarySchema).optional(),
21321
- // 仅 'persona:get' 携带;空数组 = 没启用任何插件 / settings.json 不存在;undefined = 不在该响应类型上
21322
- plugins: external_exports.array(PersonaPluginSummarySchema).optional(),
21323
- sandboxSettings: PersonaSandboxSettingsSchema.nullable().optional()
21261
+ var ContactHandshakeOkSchema = external_exports.object({
21262
+ type: external_exports.literal("contact:handshake:ok"),
21263
+ owner: external_exports.object({
21264
+ /** 被调方 deviceId(路由主键;调用方落 Contact 的主键用自己请求的 args.deviceId,此值供校验/展示) */
21265
+ id: external_exports.string(),
21266
+ /** 归属人(落 Contact.ownerId / provider,显示分组用) */
21267
+ ownerId: external_exports.string(),
21268
+ provider: external_exports.string(),
21269
+ displayName: external_exports.string()
21270
+ }),
21271
+ /** 被调方授调用方的 grants(落 Contact.grants) */
21272
+ grants: external_exports.array(GrantSchema)
21324
21273
  });
21325
- var PersonaCreateArgsSchema = external_exports.object({
21326
- label: external_exports.string().min(1),
21327
- personality: external_exports.string(),
21328
- model: external_exports.string().optional(),
21329
- tool: external_exports.string().optional(),
21330
- public: external_exports.boolean().optional(),
21331
- iconKey: external_exports.string().optional()
21274
+
21275
+ // ../protocol/src/contact-remote-access.ts
21276
+ var ContactSetRemoteAccessArgsSchema = external_exports.object({
21277
+ deviceId: external_exports.string().min(1),
21278
+ remoteAccessAllowed: external_exports.boolean()
21332
21279
  }).strict();
21333
- var PersonaIdArgsSchema = external_exports.object({
21334
- personaId: external_exports.string().min(1)
21335
- });
21336
- var PersonaUpdateArgsSchema = external_exports.object({
21337
- personaId: external_exports.string().min(1),
21338
- patch: external_exports.object({
21339
- label: external_exports.string().min(1).optional(),
21340
- model: external_exports.string().optional(),
21341
- tool: external_exports.string().optional(),
21342
- personality: external_exports.string().optional(),
21343
- public: external_exports.boolean().optional(),
21344
- // pass `null` to clear; daemon strips the field from PersonaFile on null
21345
- iconKey: external_exports.string().nullable().optional()
21346
- }).strict()
21280
+ var ContactSetRemoteAccessOkSchema = external_exports.object({
21281
+ type: external_exports.literal("contact:setRemoteAccess:ok"),
21282
+ deviceId: external_exports.string().min(1),
21283
+ remoteAccessAllowed: external_exports.boolean()
21347
21284
  }).strict();
21348
- var CodexSandboxSettingsSchema = external_exports.object({
21349
- // 额外可写的绝对路径或 ~ 路径(pnpm 工具链等);workspace(cwd) 和 userWorkDir 由 daemon 自动加,不用列。
21350
- writableRoots: external_exports.array(external_exports.string()).optional(),
21351
- // 禁读 glob(相对 workspace root 或绝对),如 ".secrets/**"、"**/*.env"。
21352
- denyRead: external_exports.array(external_exports.string()).optional(),
21353
- // true → 网络全放(*);缺省/false → 断网。
21354
- network: external_exports.boolean().optional()
21285
+ var ContactRemoteAccessUpdatedFrameSchema = external_exports.object({
21286
+ type: external_exports.literal("contact:remote-access-updated"),
21287
+ deviceId: external_exports.string().min(1),
21288
+ remoteAccessAllowed: external_exports.boolean()
21355
21289
  }).strict();
21356
21290
 
21357
- // ../protocol/src/schemas.ts
21358
- var SessionStatusSchema = external_exports.enum(SESSION_STATUS_VALUES);
21359
- var UsageSchema = external_exports.object({
21360
- input_tokens: external_exports.number().int().nonnegative().optional(),
21361
- cache_read_input_tokens: external_exports.number().int().nonnegative().optional(),
21362
- cache_creation_input_tokens: external_exports.number().int().nonnegative().optional(),
21363
- output_tokens: external_exports.number().int().nonnegative().optional()
21364
- });
21365
- var ContextUsageSchema = external_exports.object({
21366
- inputTokens: external_exports.number().int().nonnegative(),
21367
- outputTokens: external_exports.number().int().nonnegative(),
21368
- cacheReadTokens: external_exports.number().int().nonnegative().optional(),
21369
- cacheCreateTokens: external_exports.number().int().nonnegative().optional()
21370
- });
21371
- var sessionMetaShape = {
21372
- gitBranch: external_exports.string().optional(),
21373
- resolvedModel: external_exports.string().optional(),
21374
- contextUsage: ContextUsageSchema.optional(),
21375
- contextWindowSize: external_exports.number().int().positive().optional()
21376
- };
21377
- var SessionMetaSchema = external_exports.object(sessionMetaShape);
21378
- var ModelInfoSchema = external_exports.object({
21379
- id: external_exports.string().min(1),
21380
- label: external_exports.string().min(1),
21381
- description: external_exports.string().optional(),
21382
- contextWindowSize: external_exports.number().int().positive(),
21383
- default: external_exports.boolean().optional()
21384
- });
21385
- var ModeInfoSchema = external_exports.object({
21386
- id: external_exports.string().min(1),
21387
- label: external_exports.string().min(1),
21388
- description: external_exports.string().optional()
21389
- });
21390
- var ConfigFieldSchemaSchema = external_exports.object({
21391
- name: external_exports.string().min(1),
21392
- type: external_exports.enum(["string", "select", "toggle"]),
21393
- label: external_exports.string().min(1),
21394
- description: external_exports.string().optional(),
21395
- options: external_exports.array(
21396
- external_exports.object({
21397
- value: external_exports.string(),
21398
- label: external_exports.string(),
21399
- description: external_exports.string().optional()
21400
- })
21401
- ).optional(),
21402
- default: external_exports.unknown().optional(),
21403
- scope: external_exports.enum(["core", "tool-specific"])
21404
- });
21405
- var CapabilitiesGetArgs = external_exports.object({
21406
- tool: external_exports.string().min(1)
21407
- });
21408
- var ToolFeaturesSchema = external_exports.object({
21409
- rewind: external_exports.boolean(),
21410
- subagents: external_exports.boolean(),
21411
- tui: external_exports.boolean(),
21412
- observe: external_exports.boolean(),
21413
- fileSharing: external_exports.boolean(),
21414
- // fork:session:fork 走 forkSession(claude jsonl 专用,派生新 jsonl)。codex 无 claude jsonl
21415
- // → fork 不可用。UI 据此 gate assistant 消息上的 fork 按钮(codex 一轮多条消息会刷出一堆按钮且点了报错)。
21416
- fork: external_exports.boolean()
21417
- });
21418
- var CapabilitiesResponseSchema = external_exports.object({
21419
- tool: external_exports.string().min(1),
21420
- toolSessionIdLabel: external_exports.string().optional(),
21421
- models: external_exports.array(ModelInfoSchema),
21422
- permissionModes: external_exports.array(ModeInfoSchema),
21423
- configSchema: external_exports.array(ConfigFieldSchemaSchema),
21424
- features: ToolFeaturesSchema
21425
- });
21426
- var AllowRuleSchema = external_exports.object({
21427
- tool: external_exports.string().min(1),
21428
- pattern: external_exports.string().min(1),
21429
- createdAt: external_exports.string().min(1).optional()
21430
- });
21431
- var SessionFileSchema = external_exports.object({
21432
- sessionId: external_exports.string().min(1),
21433
- cwd: external_exports.string().min(1),
21434
- tool: external_exports.literal("claude").or(external_exports.string().min(1)).default("claude"),
21435
- // 归一化 tool 侧 session id(CC = claude session uuid,Codex = codex 自己的 id)
21436
- toolSessionId: external_exports.string().optional(),
21437
- label: external_exports.string().optional(),
21438
- model: external_exports.string().optional(),
21439
- permissionMode: external_exports.string().optional(),
21440
- effort: external_exports.string().optional(),
21441
- // 归一化运行时观测字段(daemon 独立计算,session:update 不接受;meta_update 事件投递)
21442
- ...sessionMetaShape,
21443
- permissionRules: external_exports.array(AllowRuleSchema).optional(),
21444
- // Sidebar 置顶时间戳;null/undefined 表示未置顶
21445
- pinnedAt: external_exports.number().int().nonnegative().nullable().optional(),
21446
- // pinned 行手动拖拽顺序;越小越靠前。session:reorderPins 整体重写所有 pinned 的此字段。
21447
- // 缺失时 view-state 排序回退到 pinnedAt desc(旧数据兼容)
21448
- pinSortOrder: external_exports.number().int().nullable().optional(),
21449
- // daemon 权威的共享未读标记(spec 2026-07-20-shared-session-unread):
21450
- // session wire status 从 running 跃迁为非 running 时 daemon 置为当时 ISO 时间戳;
21451
- // session:markRead RPC 或新 turn 开始(→ running)时清为 null。
21452
- // 所有客户端(desktop / mobile)共享同一份,任一端标读全端清。
21453
- unreadAt: external_exports.string().min(1).nullable().optional(),
21454
- // 用户在 NewSessionDialog 或 Edit modal 选择的 icon 标识;UI 端做 enum 兜底
21455
- iconKey: external_exports.string().optional(),
21456
- // 由 session:fork 派生的 session 在 create 时记录源 session 的 sessionId(稳定 key,
21457
- // 不受 parent clear / re-spawn 影响);sidebar 据此挂 fork 图标。非 fork session 该字段缺省。
21458
- // 旧字段 forkedFromToolSessionId 已弃用,daemon 启动时一次性迁移老数据
21459
- forkedFromSessionId: external_exports.string().min(1).optional(),
21460
- // 快速问答临时会话标记(spec 2026-06-23-fork-quick-ask):true = 关闭抽屉即删、
21461
- // 不进 sidebar 树、daemon 启动清扫孤儿。普通会话缺省。
21462
- ephemeral: external_exports.boolean().optional(),
21463
- // owner-mode persona session 身份标识;UI 用它在 SessionList 过滤 + jump,
21464
- // daemon 用它做 idempotent dedupe + spawn 时派生 ctx.personaMode='owner'
21465
- ownerPersonaId: external_exports.string().min(1).optional(),
21466
- // app-builder Project 反向索引(spec: superpowers/specs/2026-06-01-app-builder-project-picker-design.md)。
21467
- // 当此 session 绑定到某个 build 中的 project 时填写;name 与 projects/<name>/ 子目录同名,
21468
- // 受 projectNameSchema regex 约束。daemon session:resume 时校验该目录存在,不存在则拒。
21469
- appBuilderProject: external_exports.string().regex(/^[a-z][a-z0-9-]{0,39}$/).optional(),
21470
- // listener-mode sub-session 的原始 chatId(owner-mode 不写;listener-scope 强制写入)。
21471
- // 派生 sessionId 是单向 hash `${personaId}-${tokenHash12}-${chatHash8}`,必须保留原始 chatId
21472
- // 才能让 alice 重连同一 sub-session(持久化在 alice localStorage 之外,由 daemon push 同步)。
21473
- // optional 是因为 owner-mode session 不带;只要写入就是 listener-mode 必填三元组。
21474
- chatId: external_exports.string().min(1).optional(),
21475
- /**
21476
- * 创建该 session 的设备 id(决策 #16:从 ctx.principal.id 派生 = deviceId)。
21477
- * UI 端 self 判定收敛为单一比较 `!creatorPrincipalId || creatorPrincipalId === 本机 deviceId`
21478
- * → 「我自己创建」vs「别的设备接入创建」。MyPersonas 二级分组按 creatorPrincipalId(设备)
21479
- * 分桶、按 contact(deviceId→ownerName) 反查显示名。
21480
- *
21481
- * 命名保留 creatorPrincipalId(命名债,语义已是 creatorDeviceId);值由 connect token
21482
- * subDevice 背书(guest ctx)或本机 deviceId(owner ctx)。optional 兼容老 session。
21483
- *
21484
- * 决策 #16 删除了 creatorOwnerPrincipalId(personal token #735 遗留)——当年 guest 的
21485
- * principal.id 都是同张 cap.id 区分不了人才加它;现在 principal.id = 设备 deviceId、
21486
- * 归属人由 contact(deviceId→ownerId) 反查,该字段理由消失。
21487
- */
21488
- creatorPrincipalId: external_exports.string().min(1).optional(),
21291
+ // ../protocol/src/contact.ts
21292
+ var ContactSchema = external_exports.object({
21489
21293
  /**
21490
- * 创建该 session 的连接者飞书 displayName(一次性 stamp)。session:create handler
21491
- * ctx.principal.displayName 传入;newRunner 时读这个字段派生 SubSessionMeta.callerDisplayName,
21492
- * 注入到 cc system prompt 引导自我介绍(见 connection-prompt.ts)。
21493
- * Optional 兼容老 SessionFile——newRunner 读不到时 fallback ContactStore 反查(guest)
21494
- * 或 deps.ownerDisplayName(owner)。
21294
+ * 对方设备标识(主键):对方 daemon 自己生成并持久化的标识(auth.json deviceId,
21295
+ * dev-<uuid>),provider 无关。同 deviceId 重复 upsert 覆盖。
21495
21296
  */
21496
- creatorDisplayName: external_exports.string().min(1).optional(),
21297
+ deviceId: external_exports.string().min(1),
21497
21298
  /**
21498
- * 创建该 session 的连接者飞书 union_id(一次性 stamp,T-31 persona prompt injection)。
21499
- * session:create / dispatch spawnB handler 从 ctx.principal.feishuUnionId(guest 场景来自
21500
- * connect token subOwner)或 deps.ownerFeishuUnionId(owner 场景)传入;newRunner 时读这个
21501
- * 字段派生 SubSessionMeta.callerFeishuUnionId 注入 cc system prompt「身份卡」的 union_id 行。
21502
- * Optional:老 SessionFile / owner 未登飞书路径缺省,缺省时 prompt 不渲染该行(向后兼容)。
21299
+ * 归属人 id(决策 #16):TTC unique_id 等,由 connect token subOwner 签名背书。
21300
+ * provider 一起唯一标识一个人。DM 不再按它路由(路由用 deviceId),仅显示/分组用。
21503
21301
  */
21504
- creatorFeishuUnionId: external_exports.string().min(1).optional(),
21302
+ ownerId: external_exports.string().min(1),
21303
+ /** 身份来源(决策 #16):'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...,token 背书 */
21304
+ provider: external_exports.string().min(1),
21305
+ /** 联系人显示名 */
21306
+ displayName: external_exports.string(),
21307
+ /** 该设备可达的 ws/tunnel 地址 */
21308
+ remoteUrl: external_exports.string().min(1),
21309
+ // 自动反向建立联系人(spec 决策 #11):被连接方本地验票成功后自动落 A 为
21310
+ // 联系人,但它不持有 A 颁发的 token(A 从未给它换票)→ connectToken 为空串。
21311
+ // device:connect 出站路径仍存中心 server 签发的真实 connect token(断线重连复用)。
21312
+ // 不用 .min(1):自动反向路径合法地存空串,禁止填假 token 占位(不造假数据)。
21313
+ connectToken: external_exports.string(),
21314
+ grants: external_exports.array(GrantSchema),
21315
+ addedAt: external_exports.number().int().nonnegative(),
21505
21316
  /**
21506
- * Mirror peer sessions (2026-05-26): mirror 标识。**我在朋友 daemon 上创建的 session**,
21507
- * 远端是 source of truth,本机是持久化副本,方便 sidebar 跨设备聚合。
21508
- * 字段值 = 远端 daemon deviceId(决策 #16:朋友设备标识,即我接入的那台机器)。
21509
- *
21510
- * 语义关键澄清:mirror **不是朋友创建给我的会话**——它是我自己的会话,只是在朋友
21511
- * 的机器上跑。sidebar chip 显示 `@<朋友>` 暗示「位置」,不是「来源」。
21512
- *
21513
- * - undefined / 缺省 → 本机 native session(在我自己机器上跑)
21514
- * - 非空 → 我的会话在该 deviceId 朋友的 daemon 上跑,本机为持久化副本
21515
- *
21516
- * 四类 session 取值矩阵(决策 #16 deviceId 版,creatorOwnerPrincipalId 列已删):
21517
- * | 形态 | creatorPrincipalId(=设备) | originOwnerPrincipalId(=朋友设备) |
21518
- * |-------------------------------------|--------------------------|----------------------------------|
21519
- * | 本机 owner 自创 | 本机 deviceId | undefined |
21520
- * | 本机被别的设备接入创建 | 接入者 deviceId(token 背书) | undefined |
21521
- * | 我在朋友 daemon 上创建(mirror 回本机) | 我的 deviceId | 朋友 deviceId |
21522
- *
21523
- * UI 用法:
21524
- * - sidebar Active/Pinned/Recents 过滤:`origin 非空 → 一律视作 self`(绕过 #739 隔离)
21525
- * - 行内显示 `@<朋友>` chip 暗示位置
21526
- * - 进 ChatPanel 时按 origin 路由到 `pool.ensureRemoteForOwner(origin)` 走远端(按 deviceId)
21527
- *
21528
- * daemon 用法:
21529
- * - `peerSession:upsert` / `peerSession:remove` 一族 RPC 专管 mirror 写删;
21530
- * daemon dumb write/delete,**不广播任何 push 帧**,UI 是写入唯一源
21531
- * - native `session:*` handler 完全不感知 mirror(UI 操作 mirror 不走 native 路径)
21317
+ * pin 时间戳(ms,Date.now() 语义);null = pin。sidebar 顶部固定区渲染由此驱动。
21318
+ * contacts.json 缺此字段 zod default 补 null(无破坏性升级;不 orphan)。
21319
+ * 对齐 SessionFile.pinnedAt 语义(daemon 侧持久化,contact:pin RPC 更新 → contact:pinned push)。
21532
21320
  */
21533
- originOwnerPrincipalId: external_exports.string().min(1).optional(),
21321
+ pinnedAt: external_exports.number().int().nullable().default(null),
21534
21322
  /**
21535
- * Mirror 的 persona 身份(2026-07-17 android-dispatch-task spec §3.2):
21536
- * mirror 在朋友 daemon 上是用哪个 persona 创建的(朋友侧的 persona id)。
21537
- * originOwnerPrincipalId 平行的「位置」语义——**不参与**本机 persona 反查
21538
- * (那是 ownerPersonaId 的职责,mirror 上按 #750 防线 strip)。
21539
- * 消费方:mobile picker「借的」组按 (originOwnerPrincipalId, originOwnerPersonaId) 去重。
21540
- * 写入方:ui toMirrorSessionFile / mobile buildMirrorUpsertArgs 在 strip ownerPersonaId 时 stamp。
21323
+ * 远程访问授权(spec 2026-07-16)。owner 视角:允许该 contact 反向操作我的设备——
21324
+ * 跨设备 exec 的总开关(peerExec:run handler 运行时判它)。default=false,owner 显式开。
21325
+ * 授权粒度 per-people (per-contact):借用别人 persona 本来就带信任对方本人的前提。
21541
21326
  */
21542
- originOwnerPersonaId: external_exports.string().min(1).optional(),
21327
+ remoteAccessAllowed: external_exports.boolean().default(false)
21328
+ }).strict();
21329
+ var ContactWireSchema = ContactSchema;
21330
+ var ContactRemoveArgsSchema = external_exports.object({
21331
+ deviceId: external_exports.string().min(1)
21332
+ }).strict();
21333
+ var ContactRemoveOkSchema = external_exports.object({
21334
+ type: external_exports.literal("contact:remove:ok"),
21335
+ deviceId: external_exports.string().min(1)
21336
+ }).strict();
21337
+ var ContactListOkSchema = external_exports.object({
21338
+ type: external_exports.literal("contact:list:ok"),
21339
+ contacts: external_exports.array(ContactWireSchema)
21340
+ }).strict();
21341
+ var ContactAddedFrameSchema = external_exports.object({
21342
+ type: external_exports.literal("contact:added"),
21343
+ contact: ContactWireSchema
21344
+ }).strict();
21345
+ var ContactRemovedFrameSchema = external_exports.object({
21346
+ type: external_exports.literal("contact:removed"),
21347
+ deviceId: external_exports.string().min(1)
21348
+ }).strict();
21349
+ var ContactPinArgsSchema = external_exports.object({
21350
+ deviceId: external_exports.string().min(1),
21351
+ pinned: external_exports.boolean()
21352
+ }).strict();
21353
+ var ContactPinOkSchema = external_exports.object({
21354
+ type: external_exports.literal("contact:pin:ok"),
21355
+ deviceId: external_exports.string().min(1),
21356
+ pinnedAt: external_exports.number().int().nullable()
21357
+ }).strict();
21358
+ var ContactPinnedFrameSchema = external_exports.object({
21359
+ type: external_exports.literal("contact:pinned"),
21360
+ deviceId: external_exports.string().min(1),
21361
+ pinnedAt: external_exports.number().int().nullable()
21362
+ }).strict();
21363
+
21364
+ // ../protocol/src/feishu-auth.ts
21365
+ var DeviceEntrySchema = external_exports.object({
21543
21366
  /**
21544
- * Dispatch 派生的 session create 时记录源 session 的 sessionId(稳定 key);
21545
- * sidebar 据此把 dispatch 出来的 sub-session 折叠在源 session 下。非 dispatch session 缺省。
21546
- * mirror SessionFile 上必须 strip(朋友 daemon 上的 sessionId 在本机无意义,会让本机
21547
- * 反查路径走错;按 #750 一族防线处理,跟 ownerPersonaId 同地点 strip)。
21367
+ * 设备标识(决策 #15:daemon 本地生成的 dev-<uuid>,与人的身份 unionId 无关)。
21368
+ * 中心 server clawd_devices 注册表仅作服务发现(url 下发 + 目录),不在安全路径上。
21548
21369
  */
21549
- dispatchedFromSessionId: external_exports.string().min(1).optional(),
21370
+ deviceId: external_exports.string().min(1),
21371
+ /** 显示名 */
21372
+ name: external_exports.string().min(1),
21373
+ /** ws/tunnel 地址 */
21374
+ url: external_exports.string().min(1)
21375
+ });
21376
+ var DeviceListResponseSchema = external_exports.object({
21377
+ type: external_exports.literal("device:list:ok"),
21378
+ devices: external_exports.array(DeviceEntrySchema)
21379
+ });
21380
+ var DeviceConnectArgsSchema = external_exports.object({
21381
+ /** 目标设备的 deviceId(对方 daemon 生成的 dev-<uuid>) */
21382
+ deviceId: external_exports.string().min(1),
21550
21383
  /**
21551
- * Shift fire 派生的 session 记录调 addShift 的 source cc session id(稳定 key);
21552
- * sidebar 据此把 fire 出的 session 折叠在 source session 下,跟 dispatchedFromSessionId
21553
- * 平行但渲染不同 icon(AlarmClock 区别于 dispatch CornerDownRight),让 owner 一眼
21554
- * 分清"派生于人为委派"还是"派生于定时唤起"。非 shift fire session 缺省。
21555
- * 跟 dispatchedFromSessionId / forkedFromSessionId 三者互斥(同一 session 不会兼任)。
21556
- * mirror SessionFile 同 dispatchedFromSessionId 处理(shift fire 本地概念,理论上不会
21557
- * mirror,留 strip 防御)。
21384
+ * 目标设备的 ws/tunnel 地址(可选):
21385
+ * - 公开目录点击:带 url(device:list 已下发,省一次 server 查询)
21386
+ * - deviceId 连接:缺省 url daemon exchange 时由中心 server 下发该设备上报的 url
21387
+ * - 注册表不在安全路径上:知道对方 url 时显式传入即可连接(不依赖中心 server 服务发现)
21558
21388
  */
21559
- shiftFiredFromSessionId: external_exports.string().min(1).optional(),
21560
- createdAt: external_exports.string().min(1),
21561
- updatedAt: external_exports.string().min(1)
21389
+ url: external_exports.string().min(1).optional(),
21390
+ /** 显示名(公共设备来自目录;缺省时连上后用 whoami 回填) */
21391
+ name: external_exports.string().optional()
21562
21392
  });
21563
- var ParsedEventBase = {
21564
- seq: external_exports.number().int().nonnegative().optional(),
21565
- ts: external_exports.string().optional(),
21566
- // CC top-level uuid:同一逻辑帧从 stream-json stdout 和 JSONL 落地时携带相同值,
21567
- // reducer 用它做跨路径去重(managed stdout 和 observer JSONL 双写)。对齐 cc-direct cc-event-store
21568
- uuid: external_exports.string().optional()
21569
- };
21570
- var HistoryUserMetaSchema = external_exports.enum(HISTORY_USER_META_VALUES);
21571
- var SubagentToolStatsSchema = external_exports.object({
21572
- readCount: external_exports.number().int().nonnegative().optional(),
21573
- searchCount: external_exports.number().int().nonnegative().optional(),
21574
- bashCount: external_exports.number().int().nonnegative().optional(),
21575
- editFileCount: external_exports.number().int().nonnegative().optional(),
21576
- linesAdded: external_exports.number().int().nonnegative().optional(),
21577
- linesRemoved: external_exports.number().int().nonnegative().optional(),
21578
- otherToolCount: external_exports.number().int().nonnegative().optional()
21393
+ var DeviceConnectResponseSchema = external_exports.object({
21394
+ type: external_exports.literal("device:connect:ok"),
21395
+ /** 连接的目标设备标识(= 请求 args.deviceId) */
21396
+ deviceId: external_exports.string(),
21397
+ name: external_exports.string(),
21398
+ url: external_exports.string()
21579
21399
  });
21580
- var StructuredPatchHunkSchema = external_exports.object({
21581
- oldStart: external_exports.number().int().nonnegative(),
21582
- oldLines: external_exports.number().int().nonnegative(),
21583
- newStart: external_exports.number().int().nonnegative(),
21584
- newLines: external_exports.number().int().nonnegative(),
21585
- // 每行以 '+' / '-' / ' ' 开头(diff npm 包的标准 hunk lines)
21586
- lines: external_exports.array(external_exports.string())
21400
+ var FeishuIdentitySchema = external_exports.object({
21401
+ /** 归属人 id(决策 #16:TTC unique_id,取代飞书 union_id;跨登录方式稳定) */
21402
+ ownerId: external_exports.string().min(1),
21403
+ /** 身份来源:'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...(决策 #16,拓展用) */
21404
+ provider: external_exports.string().min(1),
21405
+ /** 显示名。TTC user_info 接口 data.name */
21406
+ displayName: external_exports.string().min(1),
21407
+ /** TTC user_info 接口 data.avatar_url,可缺省 */
21408
+ avatarUrl: external_exports.string().optional(),
21409
+ /** TTC user_info 接口 data.union_id(飞书 union_id;dataclaw 可信入口 X-User-UnionId 用),可缺省 */
21410
+ unionId: external_exports.string().optional()
21587
21411
  });
21588
- var ToolResultExtraSchema = external_exports.object({
21589
- agentId: external_exports.string().optional(),
21590
- agentType: external_exports.string().optional(),
21591
- status: external_exports.string().optional(),
21592
- prompt: external_exports.string().optional(),
21593
- // CC File*Tool 结果里的 filePath / structuredPatch:UI rewind 预览据此本地渲染 diff。
21594
- // 两者同时存在才有意义;缺任一则 UI 降级为仅显示"受影响文件"摘要
21595
- filePath: external_exports.string().optional(),
21596
- structuredPatch: external_exports.array(StructuredPatchHunkSchema).optional(),
21597
- stats: external_exports.object({
21598
- durationMs: external_exports.number().int().nonnegative().optional(),
21599
- tokens: external_exports.number().int().nonnegative().optional(),
21600
- toolUseCount: external_exports.number().int().nonnegative().optional(),
21601
- toolStats: SubagentToolStatsSchema.optional(),
21602
- usage: UsageSchema.optional()
21603
- }).optional()
21412
+ var AuthLoginStartResponseSchema = external_exports.object({
21413
+ type: external_exports.literal("auth:login:start:ok"),
21414
+ /** 完整 TTC 授权页 URL(含 callback_url + state + auto=1),UI 直接 window.open */
21415
+ authUrl: external_exports.string().min(1),
21416
+ /** 防 CSRF 的一次性 nonce;回调时 daemon 校验 */
21417
+ state: external_exports.string().min(1)
21604
21418
  });
21605
- var MemoryEntrySchema = external_exports.object({
21606
- path: external_exports.string(),
21607
- content: external_exports.string(),
21608
- mtimeMs: external_exports.number().optional()
21419
+ var AuthGetIdentityResponseSchema = external_exports.object({
21420
+ type: external_exports.literal("auth:getIdentity:ok"),
21421
+ /** null = 未登录 */
21422
+ identity: FeishuIdentitySchema.nullable(),
21423
+ /**
21424
+ * 本机设备标识(决策 #15:daemon 生成并持久化在 auth.json,如 dev-<uuid>)。
21425
+ * 设备属性,与登录态无关、登录登出不变。UI"我的设备标识"用它拼
21426
+ * clawos://device/<deviceId>(替代旧的 unionId——不再向外暴露人的身份标识)。
21427
+ */
21428
+ deviceId: external_exports.string().min(1)
21609
21429
  });
21610
- var AskQuestionOptionSchema = external_exports.object({
21611
- label: external_exports.string().min(1),
21612
- description: external_exports.string().optional()
21430
+ var AuthLogoutResponseSchema = external_exports.object({
21431
+ type: external_exports.literal("auth:logout:ok")
21613
21432
  });
21614
- var AskQuestionItemSchema = external_exports.object({
21615
- question: external_exports.string().min(1),
21616
- // multiSelect 必填(boolean 不给默认值):daemon emit 时必须显式传,避免 UI 端漂移
21617
- multiSelect: external_exports.boolean(),
21618
- options: external_exports.array(AskQuestionOptionSchema).min(1)
21433
+ var AuthLoginDoneEventSchema = external_exports.object({
21434
+ type: external_exports.literal("auth:login:done"),
21435
+ identity: FeishuIdentitySchema
21619
21436
  });
21620
- var ParsedEventSchema = external_exports.discriminatedUnion("kind", [
21621
- // session_init 仅携带 session 标识;resolvedModel 等元信息走 meta_update
21437
+ var AuthLoginFailedEventSchema = external_exports.object({
21438
+ type: external_exports.literal("auth:login:failed"),
21439
+ reason: external_exports.string()
21440
+ });
21441
+
21442
+ // ../protocol/src/dispatch.ts
21443
+ var DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
21622
21444
  external_exports.object({
21623
- ...ParsedEventBase,
21624
- kind: external_exports.literal("session_init"),
21625
- toolSessionId: external_exports.string().optional()
21445
+ kind: external_exports.literal("success"),
21446
+ text: external_exports.string(),
21447
+ filePaths: external_exports.array(external_exports.string()).optional()
21626
21448
  }),
21627
21449
  external_exports.object({
21628
- ...ParsedEventBase,
21629
- kind: external_exports.literal("thinking"),
21630
- text: external_exports.string(),
21631
- // 同一思考块的多次 stream_event 增量带相同 partialId(= `${sessionId}-${blockIndex}`);
21632
- // 不带表示是 assistant 帧的整段快照。UI 用 partialId 累积 / 用快照覆盖。
21633
- partialId: external_exports.string().optional()
21450
+ kind: external_exports.literal("failure"),
21451
+ reason: external_exports.string()
21452
+ })
21453
+ ]);
21454
+ var DispatchRunArgsSchema = external_exports.object({
21455
+ // 新开必填;续派(dispatchId 非空)时可省略——targetPersonaId 从台账行取。
21456
+ targetPersona: external_exports.string().min(1).optional(),
21457
+ // 续派(spec 2026-07-21,单 dispatchId 语义:一件事一行一 id):非空 = 把 prompt
21458
+ // 作为新 turn 打进该 dispatch 的原 worker session 接着干(台账行复位 running)。
21459
+ // 省略 = 新开一件事,daemon 铸新 id。
21460
+ dispatchId: external_exports.string().min(1).optional(),
21461
+ prompt: external_exports.string(),
21462
+ // 跨设备 dispatch:非空 = A 角色,转发到该 contact deviceId 的 peer daemon;
21463
+ // 省略 = 本地 dispatch / B 角色本地执行。A 转发给 B 时 body 不带此字段。
21464
+ targetDeviceId: external_exports.string().min(1).optional(),
21465
+ // 可选:override B session 使用的 claude 模型。缺省 = 用 persona 默认。
21466
+ // 合法值集与 claude adapter capabilities.models[].id 一致(见 daemon
21467
+ // tools/claude.ts CLAUDE_MODEL_IDS);handler 层做二次校验,非法值 fail-fast。
21468
+ // protocol 层保持 string 便于未来跨 tool 扩展(届时 union 收合法字面量)。
21469
+ model: external_exports.string().min(1).optional(),
21470
+ // 可选:给新 worker session 起 label(写入 SessionFile.label,sidebar 显示)。
21471
+ // 仅在**新开 dispatch**(dispatchId 缺席)时生效;续派(dispatchId 非空)
21472
+ // 时 daemon 层静默丢弃(避免半途改 label 造成 sidebar 抖动)。
21473
+ // 上限 60 字符——sidebar 显示 tolerance,卡在 dispatch 入口即可。
21474
+ // 协议层不硬拒 sessionLabel + dispatchId 同传,保留 forward-compat。
21475
+ sessionLabel: external_exports.string().min(1).max(60).optional()
21476
+ }).refine((v) => v.targetPersona !== void 0 || v.dispatchId !== void 0, {
21477
+ message: "either targetPersona (new dispatch) or dispatchId (follow-up) is required"
21478
+ }).refine((v) => !(v.dispatchId !== void 0 && v.targetDeviceId !== void 0), {
21479
+ message: "cross-device dispatch cannot be continued (dispatchId + targetDeviceId are mutually exclusive)"
21480
+ });
21481
+ var DispatchCompleteArgsSchema = external_exports.object({
21482
+ dispatchId: external_exports.string().min(1),
21483
+ outcome: DispatchOutcomeSchema
21484
+ });
21485
+ var DISPATCH_STATUSES = ["running", "completed", "failed"];
21486
+ var DispatchStatusSchema = external_exports.enum(DISPATCH_STATUSES);
21487
+ var DispatchRecordSchema = external_exports.object({
21488
+ dispatchId: external_exports.string().min(1),
21489
+ sourceSessionId: external_exports.string().min(1),
21490
+ sourcePersonaId: external_exports.string().min(1).optional(),
21491
+ targetPersonaId: external_exports.string().min(1),
21492
+ /** B 的 sessionId;registerBSession 后回填 */
21493
+ workerSessionId: external_exports.string().min(1).optional(),
21494
+ /** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
21495
+ taskText: external_exports.string(),
21496
+ status: DispatchStatusSchema,
21497
+ outcome: DispatchOutcomeSchema.optional(),
21498
+ /** 上层消费者语义(如司礼监的口谕/验收状态),daemon 不解释 */
21499
+ meta: external_exports.record(external_exports.unknown()).optional(),
21500
+ createdAt: external_exports.string().min(1),
21501
+ completedAt: external_exports.string().min(1).optional(),
21502
+ /** 结果注入 source session 成功时戳,兼当投递 dedup 标记 */
21503
+ deliveredAt: external_exports.string().min(1).optional()
21504
+ });
21505
+ var DispatchListArgsSchema = external_exports.object({
21506
+ sourceSessionId: external_exports.string().min(1).optional()
21507
+ });
21508
+ var DispatchListResultSchema = external_exports.object({
21509
+ records: external_exports.array(DispatchRecordSchema)
21510
+ });
21511
+ var DispatchGetArgsSchema = external_exports.object({
21512
+ dispatchId: external_exports.string().min(1)
21513
+ });
21514
+ var DispatchGetOkSchema = external_exports.object({
21515
+ type: external_exports.literal("personaDispatch:get:ok"),
21516
+ status: DispatchStatusSchema,
21517
+ outcome: DispatchOutcomeSchema.optional()
21518
+ });
21519
+
21520
+ // ../protocol/src/extension.ts
21521
+ var EXT_ID_REGEX = /^[a-z0-9][a-z0-9-]*$/;
21522
+ var ExtensionStateSchema = external_exports.enum([
21523
+ "stopped",
21524
+ "starting",
21525
+ "running",
21526
+ "crashed",
21527
+ "invalid"
21528
+ ]);
21529
+ var LOCALHOST_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
21530
+ function isAllowedHostedUrl(raw) {
21531
+ let u;
21532
+ try {
21533
+ u = new URL(raw);
21534
+ } catch {
21535
+ return false;
21536
+ }
21537
+ if (u.protocol === "https:") return true;
21538
+ if (u.protocol === "http:" && LOCALHOST_HOSTS.has(u.hostname)) return true;
21539
+ return false;
21540
+ }
21541
+ var ExtensionManifestSchema = external_exports.object({
21542
+ id: external_exports.string().regex(EXT_ID_REGEX),
21543
+ name: external_exports.string().min(1),
21544
+ version: external_exports.string().min(1),
21545
+ apiVersion: external_exports.literal("1"),
21546
+ runtime: external_exports.object({ startCommand: external_exports.string().min(1) }).passthrough().optional(),
21547
+ entry: external_exports.object({
21548
+ url: external_exports.string().url().refine(isAllowedHostedUrl, {
21549
+ message: "INVALID_URL_SCHEME: only https or http://localhost is allowed"
21550
+ })
21551
+ }).strict().optional()
21552
+ }).passthrough().superRefine((m, ctx) => {
21553
+ const hasRuntime = !!m.runtime;
21554
+ const hasUrl = !!m.entry?.url;
21555
+ if (hasRuntime && hasUrl) {
21556
+ ctx.addIssue({
21557
+ code: external_exports.ZodIssueCode.custom,
21558
+ message: "INVALID_MANIFEST: entry.url and runtime cannot coexist"
21559
+ });
21560
+ }
21561
+ if (!hasRuntime && !hasUrl) {
21562
+ ctx.addIssue({
21563
+ code: external_exports.ZodIssueCode.custom,
21564
+ message: "INVALID_MANIFEST: must have either entry.url or runtime"
21565
+ });
21566
+ }
21567
+ });
21568
+ var ExtensionTargetSchema = external_exports.discriminatedUnion("kind", [
21569
+ external_exports.object({ kind: external_exports.literal("local"), port: external_exports.number().int().min(1).max(65535) }),
21570
+ external_exports.object({ kind: external_exports.literal("hosted"), url: external_exports.string().url() })
21571
+ ]);
21572
+ var ExtensionRecordSchema = external_exports.discriminatedUnion("state", [
21573
+ external_exports.object({
21574
+ extId: external_exports.string(),
21575
+ manifest: ExtensionManifestSchema,
21576
+ state: external_exports.literal("stopped")
21634
21577
  }),
21635
21578
  external_exports.object({
21636
- ...ParsedEventBase,
21637
- kind: external_exports.literal("text"),
21638
- text: external_exports.string(),
21639
- // 同一文本块的多次 stream_event 增量带相同 partialId;语义同 thinking
21640
- partialId: external_exports.string().optional()
21579
+ extId: external_exports.string(),
21580
+ manifest: ExtensionManifestSchema,
21581
+ state: external_exports.literal("starting")
21641
21582
  }),
21642
- // 真实用户输入:daemon 通过 --replay-user-messages 拿到 stdin 回显,区分于 assistant text。
21643
- // meta 非空表示是 CC 注入的系统消息(task-notification / slash-command / system-reminder 等),
21644
- // UI 据此走低视觉权重渲染或子 agent 通知卡。
21645
- //
21646
- // sender(2026-07-08 spec §4.1):daemon 'send' 命令 synth 的 user_text 携带发起人 SenderInfo;
21647
- // observer 回灌路径(cc jsonl)永远不带 —— cc 自己写盘不知道 daemon 层身份。
21648
- // UI 端 sender 缺省 → 不渲染 displayName label;有 → 气泡下方渲染。
21649
21583
  external_exports.object({
21650
- ...ParsedEventBase,
21651
- kind: external_exports.literal("user_text"),
21652
- text: external_exports.string(),
21653
- meta: HistoryUserMetaSchema.optional(),
21654
- taskId: external_exports.string().optional(),
21655
- parentToolUseId: external_exports.string().optional(),
21656
- sender: SenderInfoSchema.optional()
21657
- }),
21658
- external_exports.object({
21659
- ...ParsedEventBase,
21660
- kind: external_exports.literal("tool_call"),
21661
- toolUseId: external_exports.string(),
21662
- tool: external_exports.string(),
21663
- // 等于 session.tool;UI 按 {toolKind, tool} 分派渲染。additive 可选,旧 adapter 不填也能解析
21664
- toolKind: external_exports.string().optional(),
21665
- input: external_exports.unknown()
21666
- }),
21667
- external_exports.object({
21668
- ...ParsedEventBase,
21669
- kind: external_exports.literal("tool_result"),
21670
- toolUseId: external_exports.string(),
21671
- output: external_exports.unknown().optional(),
21672
- error: external_exports.string().optional(),
21673
- // CC Agent / Task tool 完成后在 JSONL 顶层挂的 toolUseResult 元信息(非 content 字段)
21674
- // 老 CC 走 <task-notification> user 消息携带统计,新 CC 直接挂在这里——兼容期两者可能并存
21675
- toolResultExtra: ToolResultExtraSchema.optional(),
21676
- // 精确指向发起 tool 的 assistant 消息顶层 uuid;toolUseId 已够 UI 聚合,这个仅作调试辅助
21677
- sourceToolAssistantUUID: external_exports.string().optional(),
21678
- // AskUserQuestion 实时回放(plan: clawd-ask-user-question 任务 B 修复):
21679
- // CC 用户答完后把 answers 写在 user 帧顶层 toolUseResult.answers,daemon parser
21680
- // 抽到这里。UI eventsToLines 用 toolUseId 配对到 question-card line,把卡片转为
21681
- // 只读态显示用户的答案。仅 AskUserQuestion 配对的 tool_result 行携带;普通工具不带。
21682
- // 等价于 HistoryMessage.askQuestionAnswers(历史回放路径),两端字段名对齐。
21683
- askQuestionAnswers: external_exports.record(external_exports.string(), external_exports.string()).optional()
21584
+ extId: external_exports.string(),
21585
+ manifest: ExtensionManifestSchema,
21586
+ state: external_exports.literal("running"),
21587
+ target: ExtensionTargetSchema
21684
21588
  }),
21685
- // CC 命中项目记忆(`type:"attachment"`,`attachment.type:"memories"`)的独立事件;
21686
- // 其它 attachment 子类型(skills / hook_context / deferred_tools / hook_success / unknown)
21687
- // 视觉权重低,daemon 直接走 user_text + HistoryUserMeta 折叠,不另开 kind
21688
21589
  external_exports.object({
21689
- ...ParsedEventBase,
21690
- kind: external_exports.literal("attachment_memories"),
21691
- memories: external_exports.array(MemoryEntrySchema)
21590
+ extId: external_exports.string(),
21591
+ manifest: ExtensionManifestSchema,
21592
+ state: external_exports.literal("crashed")
21692
21593
  }),
21693
21594
  external_exports.object({
21694
- ...ParsedEventBase,
21695
- kind: external_exports.literal("permission_request"),
21696
- requestId: external_exports.string(),
21697
- tool: external_exports.string(),
21698
- input: external_exports.unknown(),
21699
- // CC `control_request.request.tool_use_id` 对应的 tool_use id;UI 用它把队列项与
21700
- // 后续 tool_result.toolUseId 关联做跨客户端 dequeue(plan permission-multi-pending-queue.md
21701
- // 选项 ii)。老 daemon / legacy CC 不发该字段时保持向后兼容(optional)。
21702
- toolUseId: external_exports.string().optional()
21703
- }),
21704
- // AskUserQuestion 工具调用的内联锚点(plan: clawd-ask-user-question 问题 1 修复):
21705
- // daemon parser assistant tool_use AskUserQuestion 翻译成本 kind(不是 permission_request、
21706
- // 也不是 tool_call),让 UI 在事件流自然位置渲染问答卡(紧跟 assistant 消息 / 在后续消息之前),
21707
- // 而不是被强行挂在末尾。permission_request 帧仍正常下发驱动 pendingQuestions 状态机,
21708
- // 但只走 wire 帧不入 ring buffer——状态由 daemon pendingQuestions 持有,
21709
- // 渲染锚点由本 kind 的 ParsedEvent 提供。
21710
- // 历史回放:history-to-lines.ts 在 jsonl tool_use AskUserQuestion 处插入对应 'question-card' line,
21711
- // 配对的 tool_result 携带 toolUseResult.answers,已答完的展示只读态。
21595
+ extId: external_exports.string(),
21596
+ manifest: external_exports.unknown().nullable(),
21597
+ state: external_exports.literal("invalid"),
21598
+ invalidReason: external_exports.string().min(1)
21599
+ })
21600
+ ]);
21601
+ var PublishedSnapshotSchema = external_exports.object({
21602
+ snapshotHash: external_exports.string().min(1),
21603
+ version: external_exports.string().min(1),
21604
+ publishedAt: external_exports.number()
21605
+ });
21606
+ var ChannelRefSchema = external_exports.discriminatedUnion("kind", [
21712
21607
  external_exports.object({
21713
- ...ParsedEventBase,
21714
- kind: external_exports.literal("ask_user_question"),
21715
- toolUseId: external_exports.string(),
21716
- questions: external_exports.array(AskQuestionItemSchema)
21717
- }),
21718
- // turn_end —— 一轮 AI 响应结束。消费者:reducer pushEventToBuffer 翻 turnOpen=false;
21719
- // UI useChatPanelState 收 "Claude is working" spinner(lastEventKind===turn_end)。
21720
- // 三个产生来源:
21721
- // ① SDK 模式 stream-json `result` 帧(claude.ts)—— stdout 最后一帧,可靠
21722
- // ② TUI 模式 observer 读 JSONL `system/turn_duration` 行(claude-tui.ts parseLine)
21723
- // ⚠️ CC 写此行早于该轮尾段正文落盘,可能被尾随 text 覆盖 lastEventKind(③ 存在的原因)
21724
- // ③ TUI 模式屏幕静止 AND observer 静止(observeScreenIdle + manager.observerIdleWaitMs 复合闸 →
21725
- // dispatchTurnIdle inject)—— 兜 ② 的覆盖;等尾随 text 全部 poll 落盘后补,排在 buffer 末条
21608
+ kind: external_exports.literal("p2p-tunnel"),
21609
+ ownerPrincipalId: external_exports.string().min(1),
21610
+ extId: external_exports.string().min(1)
21611
+ })
21612
+ ]);
21613
+ var SourceRefSchema = external_exports.discriminatedUnion("kind", [
21726
21614
  external_exports.object({
21727
- ...ParsedEventBase,
21728
- kind: external_exports.literal("turn_end")
21729
- }),
21730
- // SDK system 帧 task_started / task_progress / task_notification 的归一化产物:
21731
- // 子 agent 执行过程中实时上报 agentId / lastToolName / stats,UI pending 期就能开抽屉、看进度。
21732
- // toolUseId 对齐父 Agent 工具的 tool_use_id;status 由 SDK subtype 派生。
21615
+ kind: external_exports.literal("p2p-tunnel"),
21616
+ ownerPrincipalId: external_exports.string().min(1),
21617
+ extId: external_exports.string().min(1),
21618
+ snapshotHash: external_exports.string().min(1)
21619
+ })
21620
+ ]);
21621
+ var PublishedExtensionRecordSchema = external_exports.object({
21622
+ extId: external_exports.string().min(1),
21623
+ name: external_exports.string().min(1),
21624
+ version: external_exports.string().min(1),
21625
+ contentHash: external_exports.string().min(1),
21626
+ publishedAt: external_exports.number()
21627
+ });
21628
+ var PublishCheckSchema = external_exports.discriminatedUnion("kind", [
21629
+ external_exports.object({ kind: external_exports.literal("clean") }),
21733
21630
  external_exports.object({
21734
- ...ParsedEventBase,
21735
- kind: external_exports.literal("subagent_progress"),
21736
- toolUseId: external_exports.string(),
21737
- agentId: external_exports.string(),
21738
- status: external_exports.enum(["started", "running", "completed", "failed"]),
21739
- description: external_exports.string().optional(),
21740
- lastToolName: external_exports.string().optional(),
21741
- prompt: external_exports.string().optional(),
21742
- stats: external_exports.object({
21743
- durationMs: external_exports.number().int().nonnegative().optional(),
21744
- tokens: external_exports.number().int().nonnegative().optional(),
21745
- toolUseCount: external_exports.number().int().nonnegative().optional()
21746
- }).optional()
21631
+ kind: external_exports.literal("ready-new-version"),
21632
+ fromVersion: external_exports.string().min(1),
21633
+ toVersion: external_exports.string().min(1)
21747
21634
  }),
21748
21635
  external_exports.object({
21749
- ...ParsedEventBase,
21750
- kind: external_exports.literal("error"),
21751
- message: external_exports.string()
21636
+ kind: external_exports.literal("error-same-hash"),
21637
+ version: external_exports.string().min(1)
21752
21638
  }),
21753
- // 元信息投递:daemon adapter 从任意来源(stream-json / JSONL)抽出的 SessionMeta 子集
21754
- // reducer 做 patch merge + diff + persist + 广播 session:info;不入 ring buffer
21755
21639
  external_exports.object({
21756
- ...ParsedEventBase,
21757
- kind: external_exports.literal("meta_update"),
21758
- patch: SessionMetaSchema
21640
+ kind: external_exports.literal("error-version-not-bumped"),
21641
+ localVersion: external_exports.string().min(1),
21642
+ publishedVersion: external_exports.string().min(1)
21759
21643
  }),
21760
- // 系统消息(CC 自家系统提示 / 老板插话补充);persona 场景下区分两类:
21761
- // metaSource='cc' → CC 注入的系统消息(默认低视觉权重渲染)
21762
- // metaSource='owner' → 老板通过 persona:appendOwnerMessage 插入的话(蓝色气泡)
21763
- // 缺省视为 'cc';现有非 persona 场景保持兼容(不需要 owner 时不下发该字段)
21764
21644
  external_exports.object({
21765
- ...ParsedEventBase,
21766
- kind: external_exports.literal("meta-text"),
21767
- text: external_exports.string(),
21768
- metaSource: external_exports.enum(["cc", "owner"]).optional()
21645
+ kind: external_exports.literal("error-version-regression"),
21646
+ localVersion: external_exports.string().min(1),
21647
+ publishedVersion: external_exports.string().min(1)
21769
21648
  })
21770
21649
  ]);
21771
- var SessionCreateArgs = external_exports.object({
21772
- // 当 ownerPersonaId 存在时 cwd 由 daemon 派生,UI 可不传
21773
- cwd: external_exports.string().min(1).optional(),
21774
- tool: external_exports.string().optional(),
21775
- label: external_exports.string().optional(),
21776
- model: external_exports.string().optional(),
21777
- permissionMode: external_exports.string().optional(),
21778
- effort: external_exports.string().optional(),
21779
- // 用户在 NewSessionDialog 选择的 icon 标识;UI 端做 enum 兜底
21780
- iconKey: external_exports.string().optional(),
21781
- // session:fork 派生 session 时由 UI 传入源 sessionId,daemon 写到 SessionFile.forkedFromSessionId
21782
- forkedFromSessionId: external_exports.string().min(1).optional(),
21783
- // 快速问答:创建时打 ephemeral 标记,daemon 写到 SessionFile.ephemeral
21784
- ephemeral: external_exports.boolean().optional(),
21785
- // owner-mode persona session:传此字段时 daemon 自行派生 cwd 和启动参数,
21786
- // 且按 ownerPersonaId 做 idempotent dedupe(每 persona 永远只有一个 owner session)
21787
- ownerPersonaId: external_exports.string().min(1).optional()
21788
- // 单栏默认 refactor (spec 2026-06-02):appBuilderProject 字段已从 SessionCreateArgs 砍掉。
21789
- // 绑定路径收敛到 appBuilder:createProject —— 先创建空 session(仅传 ownerPersonaId=persona-app-builder),
21790
- // 后通过 createProject RPC 创建 project 并 daemon 内部 mutate 写入 appBuilderProject。
21791
- // SessionFile schema 仍保留该字段供 daemon 内部 mutate(manager.update 内部调用通道)。
21792
- }).refine((args) => args.cwd != null || args.ownerPersonaId != null, {
21793
- message: "cwd \u4E0E ownerPersonaId \u81F3\u5C11\u4F20\u4E00\u4E2A"
21650
+ var PublishStatusResultSchema = external_exports.object({
21651
+ localManifest: external_exports.object({
21652
+ name: external_exports.string().min(1),
21653
+ version: external_exports.string().min(1),
21654
+ contentHash: external_exports.string().min(1)
21655
+ }),
21656
+ publishState: external_exports.discriminatedUnion("kind", [
21657
+ external_exports.object({ kind: external_exports.literal("unpublished") }),
21658
+ external_exports.object({
21659
+ kind: external_exports.literal("published"),
21660
+ version: external_exports.string().min(1),
21661
+ contentHash: external_exports.string().min(1),
21662
+ publishedAt: external_exports.number()
21663
+ })
21664
+ ]),
21665
+ check: PublishCheckSchema
21794
21666
  });
21795
- var SessionListArgs = external_exports.object({
21796
- /** true = 只返回 mirror(originOwnerPrincipalId 非空,即「我在朋友 daemon 上创建」的本机存证)。 */
21797
- originOnly: external_exports.boolean().optional(),
21798
- /**
21799
- * 按 own persona 窄化(2026-07-21 self-persona-sessions 追加):只留
21800
- * `s.ownerPersonaId === args.ownerPersonaId` 的 sessions。
21801
- * - mirror 行(`ownerPersonaId` 恒 null)天然排除
21802
- * - 与 `originOnly=true` 同传恒返 0
21803
- * - 老 daemon 不识别时忽略字段返回全量,客户端消费侧本就自带过滤/截断,天然向后兼容
21804
- */
21805
- ownerPersonaId: external_exports.string().min(1).optional(),
21806
- /** 按 updatedAt desc(list 的既有排序)截断前 N 条。 */
21807
- limit: external_exports.number().int().positive().optional(),
21667
+ var ExtensionPublishArgs = external_exports.object({
21668
+ extId: external_exports.string().min(1),
21808
21669
  /**
21809
- * 分页起点(2026-07-18 android-tasks-tab 迭代追加):originOnly / ownerPersonaId 过滤后、
21810
- * limit 截断前跳过前 N 条。与 limit 组合 = updatedAt desc 序上的一页。响应带 total
21811
- * (过滤后总数,见 handler)供客户端判 hasMore。老 daemon 不识别时忽略 回全量,
21812
- * 客户端按全量兼容。
21670
+ * 可选版本号:给了就在 publish-check 之前重写 manifest.json version。
21671
+ * nullish 而非 optional —— 改造前的 pickOptionalString 显式把 null 当「没给」处理,
21672
+ * 换成纯 optional 会让 `newVersion: null` 从「不 bump」变成 INVALID_PARAM。
21813
21673
  */
21814
- offset: external_exports.number().int().nonnegative().optional()
21815
- });
21816
- var SessionIdArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
21817
- var SessionUpdateArgs = external_exports.object({
21818
- sessionId: external_exports.string().min(1),
21819
- patch: external_exports.object({
21820
- label: external_exports.string().optional(),
21821
- model: external_exports.string().optional(),
21822
- permissionMode: external_exports.string().optional(),
21823
- effort: external_exports.string().optional(),
21824
- cwd: external_exports.string().optional(),
21825
- // 用户在 Edit modal 选择的 icon 标识;UI 端做 enum 兜底
21826
- iconKey: external_exports.string().optional()
21827
- // 注意:appBuilderProject 字段已从 patch 中砍掉(spec 2026-06-02-app-builder-single-pane-default-design)。
21828
- // 绑定单向不可变 —— 由 appBuilder:createProject 在 daemon 内部一次写入;UI / assistant 不再
21829
- // 通过 sessionUpdate 修改这个字段。SessionFile 仍保留 appBuilderProject 字段供 daemon 内部 mutate。
21830
- })
21831
- });
21832
- var SessionSendArgs = external_exports.object({
21833
- sessionId: external_exports.string().min(1),
21834
- text: external_exports.string()
21674
+ newVersion: external_exports.string().min(1).nullish()
21835
21675
  });
21836
- var SessionRewindArgs = external_exports.object({
21837
- sessionId: external_exports.string().min(1),
21838
- userMessageId: external_exports.string().min(1),
21839
- dryRun: external_exports.boolean().optional()
21676
+ var ExtensionIdArgs = external_exports.object({
21677
+ extId: external_exports.string().min(1)
21840
21678
  });
21841
- var SessionRewindResponseSchema = external_exports.object({
21842
- canRewind: external_exports.boolean(),
21843
- error: external_exports.string().optional(),
21844
- filesChanged: external_exports.array(external_exports.string()).optional(),
21845
- insertions: external_exports.number().int().nonnegative().optional(),
21846
- deletions: external_exports.number().int().nonnegative().optional()
21679
+ var ExtensionFetchBundleArgs = external_exports.object({
21680
+ extId: external_exports.string().min(1),
21681
+ snapshotHash: external_exports.string().min(1)
21847
21682
  });
21848
- var SessionRewindDiffArgs = external_exports.object({
21849
- sessionId: external_exports.string().min(1),
21850
- userMessageId: external_exports.string().min(1)
21683
+ var ExtensionFromChannelArgs = external_exports.object({
21684
+ channelRef: ChannelRefSchema,
21685
+ snapshotHash: external_exports.string().min(1),
21686
+ zipBase64: external_exports.string().min(1)
21851
21687
  });
21852
- var RewindDiffHunkSchema = external_exports.object({
21853
- oldStart: external_exports.number().int().nonnegative(),
21854
- oldLines: external_exports.number().int().nonnegative(),
21855
- newStart: external_exports.number().int().nonnegative(),
21856
- newLines: external_exports.number().int().nonnegative(),
21857
- lines: external_exports.array(external_exports.string())
21858
- });
21859
- var RewindDiffFileSchema = external_exports.object({
21860
- filePath: external_exports.string().min(1),
21861
- hunks: external_exports.array(RewindDiffHunkSchema),
21862
- insertions: external_exports.number().int().nonnegative(),
21863
- deletions: external_exports.number().int().nonnegative(),
21864
- status: external_exports.enum(["modified", "added", "deleted"]).optional()
21865
- });
21866
- var SessionRewindDiffResponseSchema = external_exports.object({
21867
- canRewind: external_exports.boolean(),
21868
- error: external_exports.string().optional(),
21869
- files: external_exports.array(RewindDiffFileSchema),
21870
- totalInsertions: external_exports.number().int().nonnegative(),
21871
- totalDeletions: external_exports.number().int().nonnegative()
21872
- });
21873
- var SessionRewindableMessageIdsResponseSchema = external_exports.object({
21874
- userMessageIds: external_exports.array(external_exports.string())
21875
- });
21876
- var SessionResumeArgs = external_exports.object({
21877
- sessionId: external_exports.string().min(1),
21878
- toolSessionId: external_exports.string().min(1)
21879
- });
21880
- var SessionForkArgs = external_exports.object({
21881
- cwd: external_exports.string().min(1),
21882
- toolSessionId: external_exports.string().min(1),
21883
- messageUuid: external_exports.string().min(1)
21884
- });
21885
- var SessionForkResponseSchema = external_exports.object({
21886
- forkedToolSessionId: external_exports.string().min(1),
21887
- forkedFilePath: external_exports.string().min(1)
21888
- });
21889
- var SessionObserveArgs = external_exports.object({
21890
- sessionId: external_exports.string().min(1),
21891
- toolSessionId: external_exports.string().min(1),
21892
- jsonlPath: external_exports.string().optional()
21893
- });
21894
- var SessionEventsArgs = external_exports.object({
21895
- sessionId: external_exports.string().min(1),
21896
- // -1 表示"从头拉全量"(尚未见过任何事件);seq 从 0 起,所以合法下界是 -1
21897
- afterSeq: external_exports.number().int().min(-1)
21898
- });
21899
- var PermissionRespondArgs = external_exports.object({
21900
- sessionId: external_exports.string().min(1),
21901
- // 权限请求 id 用 `permissionRequestId`,**不能**叫 `requestId`:WS 传输层用帧顶层的
21902
- // `requestId` 做 RPC 请求/响应关联(daemon-client 发帧时 `{...args, type, requestId}`,
21903
- // 传输 id 在最后会覆盖 args 同名字段)。若沿用 `requestId`,权限 id 会被传输 id(如 "r61")
21904
- // 覆盖,daemon 查 pendingPermissions 永远 miss → 点了允许一直卡住。
21905
- permissionRequestId: external_exports.string().min(1),
21906
- allow: external_exports.boolean(),
21907
- permanent: external_exports.boolean().optional(),
21908
- pattern: external_exports.string().optional()
21909
- });
21910
- var HistoryListArgs = external_exports.object({ projectPath: external_exports.string().min(1) });
21911
- var HistoryReadArgs = external_exports.object({
21912
- sessionId: external_exports.string().min(1),
21913
- limit: external_exports.number().int().positive().max(5e3).optional(),
21914
- /** 不传时走 tail 语义:daemon 返回最后 limit 条(offset = max(0, total - limit)) */
21915
- offset: external_exports.number().int().nonnegative().optional(),
21916
- /**
21917
- * 瘦身投影(2026-07-18 android-tasks-tab 迭代,v2 语义):true = daemon 裁掉窄消费面客户端
21918
- * (mobile)不渲染的大字段(input / output / raw / toolResultExtra / memories /
21919
- * sourceToolAssistantUUID),meta 注入行 text 截 500 字符。**例外:出错的工具调用全量保留**——
21920
- * 本页内 error 非空的 tool_result 保留 output,且其同 toolUseId 的 tool_call 保留 input
21921
- * (用户要能看清「啥错了」;老板 2026-07-18 拍板:普通工具调用手机不渲染,错误全量展示)。
21922
- * desktop 渲染 tool card 需全文,不用此参数。老 daemon 不识别 → 回全量,客户端向后兼容。
21923
- */
21924
- slim: external_exports.boolean().optional()
21925
- });
21926
- var HistorySubagentsArgs = external_exports.object({
21927
- cwd: external_exports.string().min(1),
21928
- toolSessionId: external_exports.string().min(1)
21929
- });
21930
- var HistorySubagentReadArgs = external_exports.object({
21931
- cwd: external_exports.string().min(1),
21932
- toolSessionId: external_exports.string().min(1),
21933
- subagentId: external_exports.string().min(1)
21934
- });
21935
- var WorkspaceListArgs = external_exports.object({
21936
- // cwd 缺省则 daemon 兜底 os.homedir();UI 的 DirBrowser 首次浏览就走这条路径
21937
- cwd: external_exports.string().min(1).optional(),
21938
- path: external_exports.string().optional(),
21939
- showHidden: external_exports.boolean().optional()
21940
- });
21941
- var WorkspaceReadArgs = external_exports.object({
21942
- cwd: external_exports.string().min(1),
21943
- path: external_exports.string().min(1)
21688
+
21689
+ // ../protocol/src/inbox.ts
21690
+ var InboxMessageSchema = external_exports.object({
21691
+ id: external_exports.string().min(1),
21692
+ peerDeviceId: external_exports.string().min(1),
21693
+ senderDeviceId: external_exports.string().min(1),
21694
+ text: external_exports.string().min(1),
21695
+ createdAt: external_exports.number().int().nonnegative(),
21696
+ readBy: external_exports.record(external_exports.string().min(1), external_exports.number().int().positive()).default({}),
21697
+ // persona 代发署名(B 版设计):非空 = 该消息由某 persona 代发,非真人手打。
21698
+ // 缺省 = 真人。routing 身份仍看 senderDeviceId;origin 只用于末端 UI 渲染来源。
21699
+ origin: external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }).optional()
21700
+ }).strict();
21701
+ var InboxPostMessageArgsSchema = external_exports.object({
21702
+ peerDeviceId: external_exports.string().min(1).optional(),
21703
+ id: external_exports.string().min(1),
21704
+ text: external_exports.string().min(1),
21705
+ createdAt: external_exports.number().int().nonnegative(),
21706
+ // persona 代发署名(跨 daemon forward 时随远程腿透传;真人发缺省)。
21707
+ origin: external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }).optional()
21708
+ }).strict();
21709
+ var InboxListArgsSchema = external_exports.object({
21710
+ peerDeviceId: external_exports.string().min(1),
21711
+ sinceCreatedAt: external_exports.number().int().nonnegative().optional()
21712
+ }).strict();
21713
+ var InboxMarkReadArgsSchema = external_exports.object({
21714
+ peerDeviceId: external_exports.string().min(1),
21715
+ upToCreatedAt: external_exports.number().int().nonnegative()
21716
+ }).strict();
21717
+ var InboxSendDmArgsSchema = external_exports.object({
21718
+ peerDeviceId: external_exports.string().min(1).optional(),
21719
+ text: external_exports.string().min(1)
21944
21720
  });
21945
- var SkillsListArgs = external_exports.object({ cwd: external_exports.string().min(1), tool: external_exports.string().optional() });
21946
- var SkillEntrySchema = external_exports.object({
21721
+
21722
+ // ../protocol/src/peer-exec.ts
21723
+ var PeerExecRunArgsSchema = external_exports.object({
21724
+ /** A 侧发起时带:目标设备 deviceId。peer-forward 转发前 strip 掉,B 侧本地执行时无此字段。 */
21725
+ peerDeviceId: external_exports.string().min(1).optional(),
21726
+ /** 交给对端 `bash -c` 的命令;cc 自拼完整路径(一发一收,无跨命令会话状态)。 */
21727
+ command: external_exports.string().min(1),
21728
+ /** 超时上限(ms);缺省用 handler 默认 30_000,clamp 300_000。 */
21729
+ timeoutMs: external_exports.number().int().positive().optional()
21730
+ }).strict();
21731
+ var PeerExecRunOkSchema = external_exports.object({
21732
+ type: external_exports.literal("peerExec:run:ok"),
21733
+ stdout: external_exports.string(),
21734
+ stderr: external_exports.string(),
21735
+ /** 进程退出码;被超时 kill 时 null。 */
21736
+ exitCode: external_exports.number().int().nullable(),
21737
+ timedOut: external_exports.boolean(),
21738
+ stdoutTruncated: external_exports.boolean(),
21739
+ stderrTruncated: external_exports.boolean()
21740
+ }).strict();
21741
+
21742
+ // ../protocol/src/shift-internal.ts
21743
+ var ShiftScheduleSchema = external_exports.discriminatedUnion("kind", [
21744
+ /** ISO-8601 时间点;时区随字符串自带 */
21745
+ external_exports.object({ kind: external_exports.literal("at"), at: external_exports.string().min(1) }),
21746
+ /** 固定间隔;anchorMs 缺省 = 从登记时刻起算 */
21747
+ external_exports.object({
21748
+ kind: external_exports.literal("every"),
21749
+ everyMs: external_exports.number().int().positive(),
21750
+ anchorMs: external_exports.number().int().nonnegative().optional()
21751
+ }),
21752
+ /** 5 字段 cron 表达式;tz 缺省 = 系统本地时区 */
21753
+ external_exports.object({ kind: external_exports.literal("cron"), expr: external_exports.string().min(1), tz: external_exports.string().min(1).optional() })
21754
+ ]);
21755
+ var personaId = external_exports.string().trim().min(1);
21756
+ var ShiftInternalAddArgs = external_exports.object({
21757
+ personaId,
21947
21758
  name: external_exports.string().min(1),
21948
- source: external_exports.enum(SKILL_SOURCE_VALUES),
21949
- path: external_exports.string().optional(),
21950
- description: external_exports.string().optional(),
21951
- plugin: external_exports.string().optional()
21759
+ schedule: ShiftScheduleSchema,
21760
+ prompt: external_exports.string().min(1),
21761
+ /** 缺省 = 派给调用方自己 */
21762
+ targetPersona: external_exports.string().min(1).optional(),
21763
+ timeoutMs: external_exports.number().int().positive().optional()
21952
21764
  });
21953
- var AgentEntrySchema = external_exports.object({
21954
- name: external_exports.string().min(1),
21955
- source: external_exports.enum(AGENT_SOURCE_VALUES),
21956
- path: external_exports.string().optional(),
21957
- description: external_exports.string().optional(),
21958
- whenToUse: external_exports.string().optional(),
21959
- plugin: external_exports.string().optional()
21765
+ var ShiftInternalListArgs = external_exports.object({
21766
+ personaId,
21767
+ /** 缺省 true —— 只列本 persona 建的 */
21768
+ onlyMine: external_exports.boolean().optional()
21960
21769
  });
21961
- var AgentsListArgs = external_exports.object({ cwd: external_exports.string().min(1), tool: external_exports.string().optional() });
21962
- var AgentsListResponseSchema = external_exports.object({
21963
- agents: external_exports.array(AgentEntrySchema)
21770
+ var ShiftInternalCancelArgs = external_exports.object({
21771
+ personaId,
21772
+ shiftId: external_exports.string().min(1)
21964
21773
  });
21965
- var SessionSubscribeArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
21966
- var SessionPinArgs = external_exports.object({
21967
- sessionId: external_exports.string().min(1),
21968
- pinned: external_exports.boolean()
21774
+ var ShiftPatchSchema = external_exports.object({
21775
+ name: external_exports.string().min(1).optional(),
21776
+ schedule: ShiftScheduleSchema.optional(),
21777
+ prompt: external_exports.string().min(1).optional(),
21778
+ targetPersona: external_exports.string().min(1).optional(),
21779
+ timeoutMs: external_exports.number().int().positive().optional(),
21780
+ enabled: external_exports.boolean().optional()
21969
21781
  });
21970
- var PeerSessionUpsertResponseSchema = external_exports.object({
21971
- type: external_exports.literal("peerSession:upsert:ok")
21782
+ var ShiftInternalUpdateArgs = external_exports.object({
21783
+ personaId,
21784
+ shiftId: external_exports.string().min(1),
21785
+ patch: ShiftPatchSchema
21972
21786
  });
21973
- var PeerSessionRemoveArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
21974
- var PeerSessionRemoveResponseSchema = external_exports.object({
21975
- type: external_exports.literal("peerSession:remove:ok")
21787
+ var ShiftInternalHistoryArgs = external_exports.object({
21788
+ personaId,
21789
+ shiftId: external_exports.string().min(1),
21790
+ limit: external_exports.number().int().positive().optional()
21976
21791
  });
21977
- var SessionReorderPinsArgs = external_exports.object({
21978
- orderedIds: external_exports.array(external_exports.string().min(1)).min(1)
21792
+
21793
+ // ../protocol/src/persona-schemas.ts
21794
+ var PersonaFileSchema = external_exports.object({
21795
+ personaId: external_exports.string(),
21796
+ label: external_exports.string(),
21797
+ model: external_exports.string().optional(),
21798
+ public: external_exports.boolean(),
21799
+ // 8-key set defined UI-side in `lib/session-icons.ts`; protocol stays plain string
21800
+ // for forward compatibility, consumer fallbacks to default when key not found.
21801
+ iconKey: external_exports.string().optional(),
21802
+ // 绑定的 agent tool('claude' / 'codex');缺省消费侧按 'claude' 兜底。
21803
+ // 与 model 平行:persona 新建 session 的默认 tool,可平滑切换。
21804
+ tool: external_exports.string().optional(),
21805
+ createdAt: external_exports.number(),
21806
+ updatedAt: external_exports.number()
21807
+ }).strict();
21808
+ var PersonaSkillSummarySchema = external_exports.object({
21809
+ // 目录名作为 skill name(对齐 CC:frontmatter `name:` 仅作 displayName 用)
21810
+ name: external_exports.string().min(1),
21811
+ // SKILL.md frontmatter `description:`;缺省时省略字段
21812
+ description: external_exports.string().optional()
21979
21813
  });
21980
- var GitRootArgs = external_exports.object({ cwd: external_exports.string().min(1) });
21981
- var GitRootResponseSchema = external_exports.object({
21982
- isGitRoot: external_exports.boolean(),
21983
- gitRoot: external_exports.string().nullable()
21814
+ var PersonaPluginSummarySchema = external_exports.object({
21815
+ // settings.json enabledPlugins 的 key,例如 'superpowers@claude-plugins-official'
21816
+ id: external_exports.string().min(1)
21984
21817
  });
21985
- var GitBranchArgs = external_exports.object({ cwd: external_exports.string().min(1) });
21986
- var GitBranchResponseSchema = external_exports.object({
21987
- branch: external_exports.string().nullable()
21818
+ var PersonaSandboxSettingsSchema = external_exports.object({
21819
+ permissions: external_exports.object({
21820
+ defaultMode: external_exports.string().optional(),
21821
+ // CC 工具 allowlist('Bash'/'Read'/...)。per-persona profile 在最严格 base 上追加放开。
21822
+ allow: external_exports.array(external_exports.string()).optional(),
21823
+ // deny 优先级最高;强制底座(persona 私密区)由 daemon compose 强制 union,owner 删不掉。
21824
+ deny: external_exports.array(external_exports.string()).optional()
21825
+ }).optional(),
21826
+ sandbox: external_exports.object({
21827
+ enabled: external_exports.boolean().optional(),
21828
+ autoAllowBashIfSandboxed: external_exports.boolean().optional(),
21829
+ allowUnsandboxedCommands: external_exports.boolean().optional(),
21830
+ // 命令前缀白名单(CC `sandbox.excludedCommands`):匹配的命令在沙箱外运行,
21831
+ // 用于需逃出沙箱的工具(如 'docker *' / 'aliyun *' 要访问宿主 socket / 凭证)。
21832
+ excludedCommands: external_exports.array(external_exports.string()).optional(),
21833
+ filesystem: external_exports.object({
21834
+ denyRead: external_exports.array(external_exports.string()).optional(),
21835
+ allowRead: external_exports.array(external_exports.string()).optional(),
21836
+ denyWrite: external_exports.array(external_exports.string()).optional(),
21837
+ allowWrite: external_exports.array(external_exports.string()).optional()
21838
+ }).optional(),
21839
+ // 出站网络 + 本机端口。base 不放(空),profile 按需追加域名(app-builder = ['*'])。
21840
+ network: external_exports.object({
21841
+ allowedDomains: external_exports.array(external_exports.string()).optional(),
21842
+ allowLocalBinding: external_exports.boolean().optional()
21843
+ }).optional()
21844
+ }).optional()
21988
21845
  });
21989
- var GitBranchesArgs = external_exports.object({ cwd: external_exports.string().min(1) });
21990
- var GitBranchesResponseSchema = external_exports.object({
21991
- branches: external_exports.array(external_exports.string()),
21992
- head: external_exports.string().nullable()
21846
+ var PersonaInfoResponseSchema = PersonaFileSchema.extend({
21847
+ personality: external_exports.string().optional(),
21848
+ // 仅 'persona:get' 携带;null = 文件不存在 / parse 失败;undefined = 不在该响应类型上
21849
+ skills: external_exports.array(PersonaSkillSummarySchema).optional(),
21850
+ // 仅 'persona:get' 携带;空数组 = 没启用任何插件 / settings.json 不存在;undefined = 不在该响应类型上
21851
+ plugins: external_exports.array(PersonaPluginSummarySchema).optional(),
21852
+ sandboxSettings: PersonaSandboxSettingsSchema.nullable().optional()
21993
21853
  });
21994
- var HistoryRecentDirsArgs = external_exports.object({}).optional();
21995
- var RecentDirEntrySchema = external_exports.object({
21996
- cwd: external_exports.string().min(1),
21997
- updatedAt: external_exports.string().min(1)
21854
+ var PersonaCreateArgsSchema = external_exports.object({
21855
+ label: external_exports.string().min(1),
21856
+ personality: external_exports.string(),
21857
+ model: external_exports.string().optional(),
21858
+ tool: external_exports.string().optional(),
21859
+ public: external_exports.boolean().optional(),
21860
+ iconKey: external_exports.string().optional()
21861
+ }).strict();
21862
+ var PersonaIdArgsSchema = external_exports.object({
21863
+ personaId: external_exports.string().min(1)
21998
21864
  });
21999
- var HistoryRecentDirsResponseSchema = external_exports.object({
22000
- dirs: external_exports.array(RecentDirEntrySchema)
22001
- });
22002
- var SessionQuestionFrameSchema = external_exports.object({
22003
- type: external_exports.literal("session:question"),
22004
- sessionId: external_exports.string().min(1),
22005
- toolUseId: external_exports.string().min(1),
22006
- requestId: external_exports.string().min(1),
22007
- // UI 单卡承载多 question;空数组语义无效,schema 必拒
22008
- questions: external_exports.array(AskQuestionItemSchema).min(1)
21865
+ var PersonaUpdateArgsSchema = external_exports.object({
21866
+ personaId: external_exports.string().min(1),
21867
+ patch: external_exports.object({
21868
+ label: external_exports.string().min(1).optional(),
21869
+ model: external_exports.string().optional(),
21870
+ tool: external_exports.string().optional(),
21871
+ personality: external_exports.string().optional(),
21872
+ public: external_exports.boolean().optional(),
21873
+ // pass `null` to clear; daemon strips the field from PersonaFile on null
21874
+ iconKey: external_exports.string().nullable().optional()
21875
+ }).strict()
21876
+ }).strict();
21877
+ var CodexSandboxSettingsSchema = external_exports.object({
21878
+ // 额外可写的绝对路径或 ~ 路径(pnpm 工具链等);workspace(cwd) 和 userWorkDir 由 daemon 自动加,不用列。
21879
+ writableRoots: external_exports.array(external_exports.string()).optional(),
21880
+ // 禁读 glob(相对 workspace root 或绝对),如 ".secrets/**"、"**/*.env"。
21881
+ denyRead: external_exports.array(external_exports.string()).optional(),
21882
+ // true → 网络全放(*);缺省/false → 断网。
21883
+ network: external_exports.boolean().optional()
21884
+ }).strict();
21885
+
21886
+ // ../protocol/src/events.ts
21887
+ var SESSION_STATUS_VALUES = [
21888
+ "idle",
21889
+ "running",
21890
+ "running-idle",
21891
+ "stopped",
21892
+ "error",
21893
+ "observing"
21894
+ ];
21895
+ var HISTORY_USER_META_VALUES = [
21896
+ "task-notification",
21897
+ "slash-command",
21898
+ "local-command",
21899
+ "system-reminder",
21900
+ "skill-hint",
21901
+ "meta-text",
21902
+ "attachment-skills",
21903
+ "attachment-deferred-tools"
21904
+ ];
21905
+ var SKILL_SOURCE_VALUES = ["builtin", "global", "project", "plugin"];
21906
+ var AGENT_SOURCE_VALUES = [
21907
+ "builtin",
21908
+ "global",
21909
+ "project",
21910
+ "policy",
21911
+ "plugin"
21912
+ ];
21913
+
21914
+ // ../protocol/src/principal.ts
21915
+ var PrincipalKindSchema = external_exports.enum(["owner", "guest"]);
21916
+ var PrincipalSchema = external_exports.object({
21917
+ id: external_exports.string().min(1),
21918
+ kind: PrincipalKindSchema,
21919
+ displayName: external_exports.string(),
21920
+ /**
21921
+ * 飞书 union_id。owner: 本机 daemon 已飞书登录时透传自 owner-identity.json;未登录 undefined。
21922
+ * guest: v1 保持 undefined(connect token 当前不携带 unionId;未来若签名 payload 加字段可透传)。
21923
+ * 消费方(如 ticket MCP / 未来别的飞书身份挂钩场景)按 undefined 决定是否降级;本层不做 fallback。
21924
+ */
21925
+ feishuUnionId: external_exports.string().optional()
21926
+ }).strict();
21927
+ var SenderInfoSchema = external_exports.object({
21928
+ /** = principal.id = deviceId(决策 #16)。稳定路由 id */
21929
+ did: external_exports.string().min(1),
21930
+ displayName: external_exports.string(),
21931
+ /** owner 未登录 / guest 无飞书身份时缺省。消费方各自决定是否降级 */
21932
+ feishuUnionId: external_exports.string().optional(),
21933
+ principal: PrincipalKindSchema
21934
+ }).strict();
21935
+
21936
+ // ../protocol/src/schemas.ts
21937
+ var SessionStatusSchema = external_exports.enum(SESSION_STATUS_VALUES);
21938
+ var UsageSchema = external_exports.object({
21939
+ input_tokens: external_exports.number().int().nonnegative().optional(),
21940
+ cache_read_input_tokens: external_exports.number().int().nonnegative().optional(),
21941
+ cache_creation_input_tokens: external_exports.number().int().nonnegative().optional(),
21942
+ output_tokens: external_exports.number().int().nonnegative().optional()
22009
21943
  });
22010
- var SessionQuestionClearedFrameSchema = external_exports.object({
22011
- type: external_exports.literal("session:question:cleared"),
22012
- sessionId: external_exports.string().min(1),
22013
- toolUseId: external_exports.string().min(1),
22014
- // record<string,string>:与 AnswerQuestionArgs.answers 同形状(question text → label)
22015
- answers: external_exports.record(external_exports.string(), external_exports.string()).optional()
21944
+ var ContextUsageSchema = external_exports.object({
21945
+ inputTokens: external_exports.number().int().nonnegative(),
21946
+ outputTokens: external_exports.number().int().nonnegative(),
21947
+ cacheReadTokens: external_exports.number().int().nonnegative().optional(),
21948
+ cacheCreateTokens: external_exports.number().int().nonnegative().optional()
22016
21949
  });
22017
- var AnswerQuestionArgs = external_exports.object({
22018
- sessionId: external_exports.string().min(1),
22019
- toolUseId: external_exports.string().min(1),
22020
- answers: external_exports.record(external_exports.string(), external_exports.string())
21950
+ var sessionMetaShape = {
21951
+ gitBranch: external_exports.string().optional(),
21952
+ resolvedModel: external_exports.string().optional(),
21953
+ contextUsage: ContextUsageSchema.optional(),
21954
+ contextWindowSize: external_exports.number().int().positive().optional()
21955
+ };
21956
+ var SessionMetaSchema = external_exports.object(sessionMetaShape);
21957
+ var ModelInfoSchema = external_exports.object({
21958
+ id: external_exports.string().min(1),
21959
+ label: external_exports.string().min(1),
21960
+ description: external_exports.string().optional(),
21961
+ contextWindowSize: external_exports.number().int().positive(),
21962
+ default: external_exports.boolean().optional()
22021
21963
  });
22022
- var AnswerQuestionResponseSchema = external_exports.object({ ok: external_exports.literal(true) });
22023
- var CancelQuestionArgs = external_exports.object({
22024
- sessionId: external_exports.string().min(1),
22025
- toolUseId: external_exports.string().min(1)
21964
+ var ModeInfoSchema = external_exports.object({
21965
+ id: external_exports.string().min(1),
21966
+ label: external_exports.string().min(1),
21967
+ description: external_exports.string().optional()
22026
21968
  });
22027
- var CancelQuestionResponseSchema = external_exports.object({ ok: external_exports.literal(true) });
22028
- var AuthRequestFrameSchema = external_exports.object({
22029
- type: external_exports.literal("auth"),
22030
- token: external_exports.string().min(1),
22031
- scheme: external_exports.literal("bearer").optional(),
22032
- /**
22033
- * 决策 #16:自报身份字段(selfPrincipalId / selfDisplayName / selfDeviceId)全部删除——
22034
- * guest 的设备 id / 人 id / 来源全部由 connect token 的 subDevice/subOwner/provider 签名背书
22035
- * (server 签、目标设备本地验签,不可伪造),不再接受任何自报身份。
22036
- *
22037
- * selfUrl 已废弃(spec 2026-07-22 双向确认建联):可达地址自报移入 contact:handshake
22038
- * args——auth 层回归纯验票。旧客户端发来的 selfUrl 被 strip(zod 默认),无害;
22039
- * 旧客户端本身由 whoami 的 connect-token 拒绝路径拦截(CLIENT_OUTDATED)。
22040
- */
22041
- /**
22042
- * 客户端自报的 user-agent 性质标签(诊断/展示用)。
22043
- * 「自报事实」,非身份(决策 #16 边界):不参与鉴权、不参与路由、
22044
- * 任何 handler 不得据此做权限判断。name 约定命名('clawd-desktop' / 'clawd-web' /
22045
- * 'clawd-mobile-android' / ...),宽容未知值(将来加新客户端不动 schema)。
22046
- * instanceId:客户端首启生成 UUID 并本地持久化——区分同种类多实例(多手机/多 desktop 同连)。
22047
- */
22048
- clientInfo: external_exports.object({
22049
- name: external_exports.string().min(1),
22050
- version: external_exports.string().min(1),
22051
- instanceId: external_exports.string().min(1)
22052
- }).optional()
21969
+ var ConfigFieldSchemaSchema = external_exports.object({
21970
+ name: external_exports.string().min(1),
21971
+ type: external_exports.enum(["string", "select", "toggle"]),
21972
+ label: external_exports.string().min(1),
21973
+ description: external_exports.string().optional(),
21974
+ options: external_exports.array(
21975
+ external_exports.object({
21976
+ value: external_exports.string(),
21977
+ label: external_exports.string(),
21978
+ description: external_exports.string().optional()
21979
+ })
21980
+ ).optional(),
21981
+ default: external_exports.unknown().optional(),
21982
+ scope: external_exports.enum(["core", "tool-specific"])
22053
21983
  });
22054
- var AuthOkFrameSchema = external_exports.object({
22055
- type: external_exports.literal("auth:ok"),
22056
- version: external_exports.string().min(1).optional(),
22057
- protocolVersion: external_exports.number().int().nonnegative().optional()
21984
+ var CapabilitiesGetArgs = external_exports.object({
21985
+ tool: external_exports.string().min(1)
22058
21986
  });
22059
- var TunnelReadyEventSchema = external_exports.object({
22060
- type: external_exports.literal("tunnel:ready"),
22061
- url: external_exports.string().min(1),
22062
- subdomain: external_exports.string().min(1)
21987
+ var ToolFeaturesSchema = external_exports.object({
21988
+ rewind: external_exports.boolean(),
21989
+ subagents: external_exports.boolean(),
21990
+ tui: external_exports.boolean(),
21991
+ observe: external_exports.boolean(),
21992
+ fileSharing: external_exports.boolean(),
21993
+ // fork:session:fork 走 forkSession(claude jsonl 专用,派生新 jsonl)。codex 无 claude jsonl
21994
+ // → fork 不可用。UI 据此 gate assistant 消息上的 fork 按钮(codex 一轮多条消息会刷出一堆按钮且点了报错)。
21995
+ fork: external_exports.boolean()
22063
21996
  });
22064
- var TunnelExitedEventSchema = external_exports.object({
22065
- type: external_exports.literal("tunnel:exited"),
22066
- code: external_exports.number().int().nullable(),
22067
- subdomain: external_exports.string().nullable(),
22068
- url: external_exports.string().nullable()
21997
+ var CapabilitiesResponseSchema = external_exports.object({
21998
+ tool: external_exports.string().min(1),
21999
+ toolSessionIdLabel: external_exports.string().optional(),
22000
+ models: external_exports.array(ModelInfoSchema),
22001
+ permissionModes: external_exports.array(ModeInfoSchema),
22002
+ configSchema: external_exports.array(ConfigFieldSchemaSchema),
22003
+ features: ToolFeaturesSchema
22069
22004
  });
22070
- var TunnelUnavailableEventSchema = external_exports.object({
22071
- type: external_exports.literal("tunnel:unavailable"),
22072
- reason: external_exports.string().min(1),
22073
- failedAt: external_exports.string().min(1)
22005
+ var AllowRuleSchema = external_exports.object({
22006
+ tool: external_exports.string().min(1),
22007
+ pattern: external_exports.string().min(1),
22008
+ createdAt: external_exports.string().min(1).optional()
22074
22009
  });
22075
- var InfoRunningSessionSchema = external_exports.object({
22010
+ var SessionFileSchema = external_exports.object({
22076
22011
  sessionId: external_exports.string().min(1),
22077
- status: SessionStatusSchema,
22078
- freshSpawn: external_exports.boolean(),
22079
- pendingPermissionRequestIds: external_exports.array(external_exports.string().min(1)),
22080
- pendingQuestionToolUseIds: external_exports.array(external_exports.string().min(1))
22081
- });
22082
- var InfoResponseSchema = external_exports.object({
22083
- type: external_exports.literal("info"),
22084
- version: external_exports.string(),
22085
- protocolVersion: external_exports.number(),
22086
- hostname: external_exports.string(),
22087
- os: external_exports.string(),
22088
- tools: external_exports.array(external_exports.object({ id: external_exports.string(), available: external_exports.boolean() })),
22089
- runningSessions: external_exports.array(InfoRunningSessionSchema),
22090
- // ── file-sharing 会话身份回执(spec: superpowers/specs/2026-05-19-clawd-file-sharing-design.md §8) ──
22091
- // PR 1 阶段标 optional(daemon 还没下发,旧 daemon info 响应不带这五个字段);
22092
- // PR 2 daemon 实现 single HTTP server + auth-context 后,daemon 必返这五个字段,
22093
- // 届时可考虑改成 required。spec §11 第 3 条:"tokenRole 是协议字段,daemon 查 token
22094
- // 表后显式下发,UI 不自行推导"——所以 UI 一律读这里,禁止本地推导。
22095
- /** 'owner' = 拿到 owner-token 的连接(不限来源 IP)。来源 TOKEN_ROLES(spec §11 #1 中央真理源)。
22096
- * 历史 'personal' role(persona file-sharing token)在 2026-05-21 删除;tokenPersonaId 一同移除。 */
22097
- tokenRole: external_exports.enum(TOKEN_ROLES).optional(),
22098
- /** socket.remoteAddress 是否落在 127.0.0.1 / ::1;本期无 RPC 消费,保留协议槽位给未来 "Reveal in Finder" 等本机动作 */
22099
- isLoopback: external_exports.boolean().optional(),
22100
- /** UI file-sharing HTTP 路由的前缀(http(s)://host:port),不含尾斜杠;frpc 反代时返反代地址 */
22101
- httpBaseUrl: external_exports.string().optional(),
22102
- /** file-sharing HTTP 路由的 Authorization: Bearer token;与 WS token 解耦,HTTP 401 仅触发 ReAuth 不强踢 WS(spec §11 第 4 条) */
22103
- httpToken: external_exports.string().optional()
22104
- });
22105
- var PROJECT_PORT_MIN = 6173;
22106
- var PROJECT_PORT_MAX = 6272;
22107
- var projectNameRegex = /^[a-z][a-z0-9-]{0,39}$/;
22108
- var ProjectMetadataSchema = external_exports.object({
22109
- name: external_exports.string().regex(projectNameRegex, {
22110
- message: "kebab-case, \u5C0F\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u53EA\u5141\u8BB8\u5C0F\u5199\u5B57\u6BCD / \u6570\u5B57 / -\uFF0C\u6700\u957F 40 \u5B57\u7B26"
22111
- }),
22112
- port: external_exports.number().int().min(PROJECT_PORT_MIN).max(PROJECT_PORT_MAX),
22113
- createdAt: external_exports.string().datetime(),
22114
- /** dev server 启动命令(shell 字符串);占位符 $CLAWD_PREVIEW_PORT 替换 + env 注入 */
22115
- devCommand: external_exports.string().min(1),
22116
- /**
22117
- * 发布上线后的公网 URL(spec 2026-06-02-app-builder-single-pane-default-design §5.6.1)。
22118
- * assistant 跑完 publish.sh 后调 appBuilder:setProdUrl 写入;UI 读这个字段切预览栏到线上 URL,
22119
- * 取代旧 `<builder-preview url=... label="prod" />` marker 机制。
22120
- * 老 project 元数据无此字段(optional 兼容)。
22121
- */
22122
- prodUrl: external_exports.string().url().optional(),
22123
- /**
22124
- * dev server 就绪 stdout regex(spec 2026-06-02-app-builder-explicit-dev-server-control §2)。
22125
- * supervisor spawn 后会监听子进程 stdout,命中此 regex 视为 dev server 真 ready;
22126
- * 仅当 await ready 后才把 stage 切到 'running',避免 cold start race 导致 iframe 502。
22127
- * optional:缺省时 supervisor 用默认 /Local:\s+https?:\/\//(vite "Local: http://..." 输出)。
22128
- * 老板换非 vite 技术栈(Next.js "Ready in"、webpack "Compiled" 等)时自定义这个字段。
22129
- */
22130
- readyPattern: external_exports.string().optional(),
22012
+ cwd: external_exports.string().min(1),
22013
+ tool: external_exports.literal("claude").or(external_exports.string().min(1)).default("claude"),
22014
+ // 归一化 tool 侧 session id(CC = claude session uuid,Codex = codex 自己的 id)
22015
+ toolSessionId: external_exports.string().optional(),
22016
+ label: external_exports.string().optional(),
22017
+ model: external_exports.string().optional(),
22018
+ permissionMode: external_exports.string().optional(),
22019
+ effort: external_exports.string().optional(),
22020
+ // 归一化运行时观测字段(daemon 独立计算,session:update 不接受;meta_update 事件投递)
22021
+ ...sessionMetaShape,
22022
+ permissionRules: external_exports.array(AllowRuleSchema).optional(),
22023
+ // Sidebar 置顶时间戳;null/undefined 表示未置顶
22024
+ pinnedAt: external_exports.number().int().nonnegative().nullable().optional(),
22025
+ // pinned 行手动拖拽顺序;越小越靠前。session:reorderPins 整体重写所有 pinned 的此字段。
22026
+ // 缺失时 view-state 排序回退到 pinnedAt desc(旧数据兼容)
22027
+ pinSortOrder: external_exports.number().int().nullable().optional(),
22028
+ // daemon 权威的共享未读标记(spec 2026-07-20-shared-session-unread):
22029
+ // session wire status 从 running 跃迁为非 running 时 daemon 置为当时 ISO 时间戳;
22030
+ // session:markRead RPC 或新 turn 开始(→ running)时清为 null。
22031
+ // 所有客户端(desktop / mobile)共享同一份,任一端标读全端清。
22032
+ unreadAt: external_exports.string().min(1).nullable().optional(),
22033
+ // 用户在 NewSessionDialog Edit modal 选择的 icon 标识;UI 端做 enum 兜底
22034
+ iconKey: external_exports.string().optional(),
22035
+ // session:fork 派生的 session create 时记录源 session 的 sessionId(稳定 key,
22036
+ // 不受 parent clear / re-spawn 影响);sidebar 据此挂 fork 图标。非 fork session 该字段缺省。
22037
+ // 旧字段 forkedFromToolSessionId 已弃用,daemon 启动时一次性迁移老数据
22038
+ forkedFromSessionId: external_exports.string().min(1).optional(),
22039
+ // 快速问答临时会话标记(spec 2026-06-23-fork-quick-ask):true = 关闭抽屉即删、
22040
+ // 不进 sidebar 树、daemon 启动清扫孤儿。普通会话缺省。
22041
+ ephemeral: external_exports.boolean().optional(),
22042
+ // owner-mode persona session 身份标识;UI 用它在 SessionList 过滤 + jump,
22043
+ // daemon 用它做 idempotent dedupe + spawn 时派生 ctx.personaMode='owner'
22044
+ ownerPersonaId: external_exports.string().min(1).optional(),
22045
+ // app-builder Project 反向索引(spec: superpowers/specs/2026-06-01-app-builder-project-picker-design.md)。
22046
+ // 当此 session 绑定到某个 build 中的 project 时填写;name 与 projects/<name>/ 子目录同名,
22047
+ // 受 projectNameSchema regex 约束。daemon session:resume 时校验该目录存在,不存在则拒。
22048
+ appBuilderProject: external_exports.string().regex(/^[a-z][a-z0-9-]{0,39}$/).optional(),
22049
+ // listener-mode sub-session 的原始 chatId(owner-mode 不写;listener-scope 强制写入)。
22050
+ // 派生 sessionId 是单向 hash `${personaId}-${tokenHash12}-${chatHash8}`,必须保留原始 chatId
22051
+ // 才能让 alice 重连同一 sub-session(持久化在 alice localStorage 之外,由 daemon push 同步)。
22052
+ // optional 是因为 owner-mode session 不带;只要写入就是 listener-mode 必填三元组。
22053
+ chatId: external_exports.string().min(1).optional(),
22131
22054
  /**
22132
- * 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.4):
22133
- * in-flight 发布 job 的元数据。仅承载"in-flight"或"中断残骸"两种状态:
22134
- * - daemon spawn publish.sh + 收到第一个 ::stage::build marker 时写入
22135
- * - 每次 stage 切换更新 stage 字段
22136
- * - 成功 / 正常失败 / 用户 dismiss 时立即清掉
22137
- * - 只有 daemon 崩才会留残骸(子进程随 daemon 一起死)
22138
- * status 字段在 ProjectWithStatus 派生而不在这里 —— schema 是落盘形态,
22139
- * "in-flight vs interrupted" 区分由 daemon 响应时实时拼 registry 状态得出。
22055
+ * 创建该 session 的设备 id(决策 #16:从 ctx.principal.id 派生 = deviceId)。
22056
+ * UI self 判定收敛为单一比较 `!creatorPrincipalId || creatorPrincipalId === 本机 deviceId`
22057
+ * 「我自己创建」vs「别的设备接入创建」。MyPersonas 二级分组按 creatorPrincipalId(设备)
22058
+ * 分桶、按 contact(deviceId→ownerName) 反查显示名。
22059
+ *
22060
+ * 命名保留 creatorPrincipalId(命名债,语义已是 creatorDeviceId);值由 connect token
22061
+ * subDevice 背书(guest ctx)或本机 deviceId(owner ctx)。optional 兼容老 session。
22062
+ *
22063
+ * 决策 #16 删除了 creatorOwnerPrincipalId(personal token #735 遗留)——当年 guest 的
22064
+ * principal.id 都是同张 cap.id 区分不了人才加它;现在 principal.id = 设备 deviceId、
22065
+ * 归属人由 contact(deviceId→ownerId) 反查,该字段理由消失。
22140
22066
  */
22141
- publishJob: external_exports.object({
22142
- jobId: external_exports.string().min(1),
22143
- stage: external_exports.enum(["build", "deploy", "verify"]),
22144
- startedAt: external_exports.number().int().nonnegative()
22145
- }).optional()
22146
- });
22147
- var PROJECT_STAGE_VALUES = [
22148
- "install-pending",
22149
- // createProject 刚返回,scaffold 已完成(daemon 同步内联跑),等 assistant pnpm install
22150
- "installing",
22151
- // assistant pnpm install 中
22152
- "starting-dev-server",
22153
- // startDevServer 已调,supervisor spawn 子进程中(await ready 期间也在此 stage)
22154
- "running",
22155
- // dev server 跑起来了(supervisor stdout 命中 readyPattern + 端口已监听)
22156
- "stopped",
22157
- // 用户显式点"收起预览"停掉 / daemon 重启后默认;UI 渲染折叠条 + "展开预览"按钮
22158
- "failed"
22159
- // 某个阶段失败(stageReason 字段携带原因,含 dev server cold start timeout)
22160
- ];
22161
- var ProjectStageSchema = external_exports.enum(PROJECT_STAGE_VALUES);
22162
- var ProjectWithStatusSchema = ProjectMetadataSchema.extend({
22163
- isRunning: external_exports.boolean(),
22164
- boundSessionId: external_exports.string().nullable(),
22067
+ creatorPrincipalId: external_exports.string().min(1).optional(),
22165
22068
  /**
22166
- * 单栏 refactor stage fix (spec 2026-06-02 §5.6.2):daemon 内存维护的当前 stage。
22167
- * UI 据此切 PreviewPane spinner / iframe / error。
22168
- * optional 兼容启动后 daemon 还没有 stage 记录的 fresh project(按 isRunning 推断兜底)。
22069
+ * 创建该 session 的连接者飞书 displayName(一次性 stamp)。session:create handler
22070
+ * ctx.principal.displayName 传入;newRunner 时读这个字段派生 SubSessionMeta.callerDisplayName,
22071
+ * 注入到 cc system prompt 引导自我介绍(见 connection-prompt.ts)。
22072
+ * Optional 兼容老 SessionFile——newRunner 读不到时 fallback ContactStore 反查(guest)
22073
+ * 或 deps.ownerDisplayName(owner)。
22169
22074
  */
22170
- stage: ProjectStageSchema.optional(),
22171
- /** stage='failed' 时携带失败原因 */
22172
- stageReason: external_exports.string().optional(),
22075
+ creatorDisplayName: external_exports.string().min(1).optional(),
22173
22076
  /**
22174
- * 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.3):
22175
- * ProjectMetadata.publishJob status 派生版。daemon 响应时按以下规则实时拼装:
22176
- * - 落盘字段存在 + PublishJobRegistry 有匹配 jobId → 'in-flight'
22177
- * - 落盘字段存在 + Registry 无匹配(jobId 对不上或 entry 缺失)→ 'interrupted'(daemon 崩残骸)
22178
- * - 落盘字段不存在 undefined(字段省略)
22179
- * UI 用 status 决定 PreviewPane 渲染分支(in-flight 三段 checklist / interrupted 恢复条)。
22077
+ * 创建该 session 的连接者飞书 union_id(一次性 stamp,T-31 persona prompt injection)。
22078
+ * session:create / dispatch spawnB handler 从 ctx.principal.feishuUnionId(guest 场景来自
22079
+ * connect token subOwner)或 deps.ownerFeishuUnionId(owner 场景)传入;newRunner 时读这个
22080
+ * 字段派生 SubSessionMeta.callerFeishuUnionId 注入 cc system prompt「身份卡」的 union_id 行。
22081
+ * Optional:老 SessionFile / owner 未登飞书路径缺省,缺省时 prompt 不渲染该行(向后兼容)。
22180
22082
  */
22181
- publishJob: external_exports.object({
22182
- jobId: external_exports.string().min(1),
22183
- stage: external_exports.enum(["build", "deploy", "verify"]),
22184
- startedAt: external_exports.number().int().nonnegative(),
22185
- status: external_exports.enum(["in-flight", "interrupted"])
22083
+ creatorFeishuUnionId: external_exports.string().min(1).optional(),
22084
+ /**
22085
+ * Mirror peer sessions (2026-05-26): mirror 标识。**我在朋友 daemon 上创建的 session**,
22086
+ * 远端是 source of truth,本机是持久化副本,方便 sidebar 跨设备聚合。
22087
+ * 字段值 = 远端 daemon 的 deviceId(决策 #16:朋友设备标识,即我接入的那台机器)。
22088
+ *
22089
+ * 语义关键澄清:mirror **不是朋友创建给我的会话**——它是我自己的会话,只是在朋友
22090
+ * 的机器上跑。sidebar chip 显示 `@<朋友>` 暗示「位置」,不是「来源」。
22091
+ *
22092
+ * - undefined / 缺省 → 本机 native session(在我自己机器上跑)
22093
+ * - 非空 → 我的会话在该 deviceId 朋友的 daemon 上跑,本机为持久化副本
22094
+ *
22095
+ * 四类 session 取值矩阵(决策 #16 deviceId 版,creatorOwnerPrincipalId 列已删):
22096
+ * | 形态 | creatorPrincipalId(=设备) | originOwnerPrincipalId(=朋友设备) |
22097
+ * |-------------------------------------|--------------------------|----------------------------------|
22098
+ * | 本机 owner 自创 | 本机 deviceId | undefined |
22099
+ * | 本机被别的设备接入创建 | 接入者 deviceId(token 背书) | undefined |
22100
+ * | 我在朋友 daemon 上创建(mirror 回本机) | 我的 deviceId | 朋友 deviceId |
22101
+ *
22102
+ * UI 用法:
22103
+ * - sidebar Active/Pinned/Recents 过滤:`origin 非空 → 一律视作 self`(绕过 #739 隔离)
22104
+ * - 行内显示 `@<朋友>` chip 暗示位置
22105
+ * - 进 ChatPanel 时按 origin 路由到 `pool.ensureRemoteForOwner(origin)` 走远端(按 deviceId)
22106
+ *
22107
+ * daemon 用法:
22108
+ * - `peerSession:upsert` / `peerSession:remove` 一族 RPC 专管 mirror 写删;
22109
+ * daemon dumb write/delete,**不广播任何 push 帧**,UI 是写入唯一源
22110
+ * - native `session:*` handler 完全不感知 mirror(UI 操作 mirror 不走 native 路径)
22111
+ */
22112
+ originOwnerPrincipalId: external_exports.string().min(1).optional(),
22113
+ /**
22114
+ * Mirror 的 persona 身份(2026-07-17 android-dispatch-task spec §3.2):
22115
+ * 该 mirror 在朋友 daemon 上是用哪个 persona 创建的(朋友侧的 persona id)。
22116
+ * 与 originOwnerPrincipalId 平行的「位置」语义——**不参与**本机 persona 反查
22117
+ * (那是 ownerPersonaId 的职责,mirror 上按 #750 防线 strip)。
22118
+ * 消费方:mobile picker「借的」组按 (originOwnerPrincipalId, originOwnerPersonaId) 去重。
22119
+ * 写入方:ui toMirrorSessionFile / mobile buildMirrorUpsertArgs 在 strip ownerPersonaId 时 stamp。
22120
+ */
22121
+ originOwnerPersonaId: external_exports.string().min(1).optional(),
22122
+ /**
22123
+ * Dispatch 派生的 session 在 create 时记录源 session 的 sessionId(稳定 key);
22124
+ * sidebar 据此把 dispatch 出来的 sub-session 折叠在源 session 下。非 dispatch session 缺省。
22125
+ * mirror SessionFile 上必须 strip(朋友 daemon 上的 sessionId 在本机无意义,会让本机
22126
+ * 反查路径走错;按 #750 一族防线处理,跟 ownerPersonaId 同地点 strip)。
22127
+ */
22128
+ dispatchedFromSessionId: external_exports.string().min(1).optional(),
22129
+ /**
22130
+ * Shift fire 派生的 session 记录调 addShift 的 source cc session id(稳定 key);
22131
+ * sidebar 据此把 fire 出的 session 折叠在 source session 下,跟 dispatchedFromSessionId
22132
+ * 平行但渲染不同 icon(AlarmClock 区别于 dispatch 的 CornerDownRight),让 owner 一眼
22133
+ * 分清"派生于人为委派"还是"派生于定时唤起"。非 shift fire session 缺省。
22134
+ * 跟 dispatchedFromSessionId / forkedFromSessionId 三者互斥(同一 session 不会兼任)。
22135
+ * mirror SessionFile 同 dispatchedFromSessionId 处理(shift fire 本地概念,理论上不会
22136
+ * mirror,留 strip 防御)。
22137
+ */
22138
+ shiftFiredFromSessionId: external_exports.string().min(1).optional(),
22139
+ createdAt: external_exports.string().min(1),
22140
+ updatedAt: external_exports.string().min(1)
22141
+ });
22142
+ var ParsedEventBase = {
22143
+ seq: external_exports.number().int().nonnegative().optional(),
22144
+ ts: external_exports.string().optional(),
22145
+ // CC top-level uuid:同一逻辑帧从 stream-json stdout 和 JSONL 落地时携带相同值,
22146
+ // reducer 用它做跨路径去重(managed stdout 和 observer JSONL 双写)。对齐 cc-direct cc-event-store
22147
+ uuid: external_exports.string().optional()
22148
+ };
22149
+ var HistoryUserMetaSchema = external_exports.enum(HISTORY_USER_META_VALUES);
22150
+ var SubagentToolStatsSchema = external_exports.object({
22151
+ readCount: external_exports.number().int().nonnegative().optional(),
22152
+ searchCount: external_exports.number().int().nonnegative().optional(),
22153
+ bashCount: external_exports.number().int().nonnegative().optional(),
22154
+ editFileCount: external_exports.number().int().nonnegative().optional(),
22155
+ linesAdded: external_exports.number().int().nonnegative().optional(),
22156
+ linesRemoved: external_exports.number().int().nonnegative().optional(),
22157
+ otherToolCount: external_exports.number().int().nonnegative().optional()
22158
+ });
22159
+ var StructuredPatchHunkSchema = external_exports.object({
22160
+ oldStart: external_exports.number().int().nonnegative(),
22161
+ oldLines: external_exports.number().int().nonnegative(),
22162
+ newStart: external_exports.number().int().nonnegative(),
22163
+ newLines: external_exports.number().int().nonnegative(),
22164
+ // 每行以 '+' / '-' / ' ' 开头(diff npm 包的标准 hunk lines)
22165
+ lines: external_exports.array(external_exports.string())
22166
+ });
22167
+ var ToolResultExtraSchema = external_exports.object({
22168
+ agentId: external_exports.string().optional(),
22169
+ agentType: external_exports.string().optional(),
22170
+ status: external_exports.string().optional(),
22171
+ prompt: external_exports.string().optional(),
22172
+ // CC File*Tool 结果里的 filePath / structuredPatch:UI rewind 预览据此本地渲染 diff。
22173
+ // 两者同时存在才有意义;缺任一则 UI 降级为仅显示"受影响文件"摘要
22174
+ filePath: external_exports.string().optional(),
22175
+ structuredPatch: external_exports.array(StructuredPatchHunkSchema).optional(),
22176
+ stats: external_exports.object({
22177
+ durationMs: external_exports.number().int().nonnegative().optional(),
22178
+ tokens: external_exports.number().int().nonnegative().optional(),
22179
+ toolUseCount: external_exports.number().int().nonnegative().optional(),
22180
+ toolStats: SubagentToolStatsSchema.optional(),
22181
+ usage: UsageSchema.optional()
22186
22182
  }).optional()
22187
22183
  });
22188
- var ListProjectsArgsSchema = external_exports.object({}).strict();
22189
- var ListProjectsResultSchema = external_exports.object({
22190
- projects: external_exports.array(ProjectWithStatusSchema)
22191
- }).strict();
22192
- var GetProjectArgsSchema = external_exports.object({
22193
- sessionId: external_exports.string().min(1)
22194
- }).strict();
22195
- var GetProjectResultSchema = external_exports.object({
22196
- /** session 未绑 project / project 不存在时为 null(UI 走单栏 / 折叠) */
22197
- project: ProjectWithStatusSchema.nullable()
22198
- }).strict();
22199
- var CreateProjectArgsSchema = external_exports.object({
22200
- /** 必填:caller session,daemon 自动绑过去(spec 2026-06-02 §3 invariant 1 Session ↔ 1 Project) */
22201
- sessionId: external_exports.string().min(1),
22202
- name: external_exports.string()
22203
- }).strict();
22204
- var CreateProjectResultSchema = external_exports.object({
22205
- project: ProjectMetadataSchema
22206
- }).strict();
22207
- var DeleteProjectArgsSchema = external_exports.object({
22208
- name: external_exports.string()
22209
- }).strict();
22210
- var DeleteProjectResultSchema = external_exports.object({}).strict();
22211
- var UpdateProjectPortArgsSchema = external_exports.object({
22212
- name: external_exports.string(),
22213
- newPort: external_exports.number().int()
22214
- }).strict();
22215
- var UpdateProjectPortResultSchema = external_exports.object({
22216
- project: ProjectMetadataSchema
22217
- }).strict();
22218
- var SetProdUrlArgsSchema = external_exports.object({
22219
- name: external_exports.string().regex(projectNameRegex),
22220
- url: external_exports.string().url()
22221
- }).strict();
22222
- var SetProdUrlResultSchema = external_exports.object({
22223
- project: ProjectMetadataSchema
22224
- }).strict();
22225
- var StartDevServerArgsSchema = external_exports.object({
22226
- sessionId: external_exports.string().min(1),
22227
- force: external_exports.boolean().optional()
22228
- }).strict();
22229
- var StartDevServerResultSchema = external_exports.object({
22230
- project: ProjectMetadataSchema
22231
- }).strict();
22232
- var ASSISTANT_REPORTABLE_STAGES = [
22184
+ var MemoryEntrySchema = external_exports.object({
22185
+ path: external_exports.string(),
22186
+ content: external_exports.string(),
22187
+ mtimeMs: external_exports.number().optional()
22188
+ });
22189
+ var AskQuestionOptionSchema = external_exports.object({
22190
+ label: external_exports.string().min(1),
22191
+ description: external_exports.string().optional()
22192
+ });
22193
+ var AskQuestionItemSchema = external_exports.object({
22194
+ question: external_exports.string().min(1),
22195
+ // multiSelect 必填(boolean 不给默认值):daemon emit 时必须显式传,避免 UI 端漂移
22196
+ multiSelect: external_exports.boolean(),
22197
+ options: external_exports.array(AskQuestionOptionSchema).min(1)
22198
+ });
22199
+ var ParsedEventSchema = external_exports.discriminatedUnion("kind", [
22200
+ // session_init 仅携带 session 标识;resolvedModel 等元信息走 meta_update
22201
+ external_exports.object({
22202
+ ...ParsedEventBase,
22203
+ kind: external_exports.literal("session_init"),
22204
+ toolSessionId: external_exports.string().optional()
22205
+ }),
22206
+ external_exports.object({
22207
+ ...ParsedEventBase,
22208
+ kind: external_exports.literal("thinking"),
22209
+ text: external_exports.string(),
22210
+ // 同一思考块的多次 stream_event 增量带相同 partialId(= `${sessionId}-${blockIndex}`);
22211
+ // 不带表示是 assistant 帧的整段快照。UI 用 partialId 累积 / 用快照覆盖。
22212
+ partialId: external_exports.string().optional()
22213
+ }),
22214
+ external_exports.object({
22215
+ ...ParsedEventBase,
22216
+ kind: external_exports.literal("text"),
22217
+ text: external_exports.string(),
22218
+ // 同一文本块的多次 stream_event 增量带相同 partialId;语义同 thinking
22219
+ partialId: external_exports.string().optional()
22220
+ }),
22221
+ // 真实用户输入:daemon 通过 --replay-user-messages 拿到 stdin 回显,区分于 assistant text。
22222
+ // meta 非空表示是 CC 注入的系统消息(task-notification / slash-command / system-reminder 等),
22223
+ // UI 据此走低视觉权重渲染或子 agent 通知卡。
22224
+ //
22225
+ // sender(2026-07-08 spec §4.1):daemon 'send' 命令 synth 的 user_text 携带发起人 SenderInfo;
22226
+ // observer 回灌路径(cc jsonl)永远不带 —— cc 自己写盘不知道 daemon 层身份。
22227
+ // UI 端 sender 缺省 → 不渲染 displayName label;有 → 气泡下方渲染。
22228
+ external_exports.object({
22229
+ ...ParsedEventBase,
22230
+ kind: external_exports.literal("user_text"),
22231
+ text: external_exports.string(),
22232
+ meta: HistoryUserMetaSchema.optional(),
22233
+ taskId: external_exports.string().optional(),
22234
+ parentToolUseId: external_exports.string().optional(),
22235
+ sender: SenderInfoSchema.optional()
22236
+ }),
22237
+ external_exports.object({
22238
+ ...ParsedEventBase,
22239
+ kind: external_exports.literal("tool_call"),
22240
+ toolUseId: external_exports.string(),
22241
+ tool: external_exports.string(),
22242
+ // 等于 session.tool;UI 按 {toolKind, tool} 分派渲染。additive 可选,旧 adapter 不填也能解析
22243
+ toolKind: external_exports.string().optional(),
22244
+ input: external_exports.unknown()
22245
+ }),
22246
+ external_exports.object({
22247
+ ...ParsedEventBase,
22248
+ kind: external_exports.literal("tool_result"),
22249
+ toolUseId: external_exports.string(),
22250
+ output: external_exports.unknown().optional(),
22251
+ error: external_exports.string().optional(),
22252
+ // CC Agent / Task tool 完成后在 JSONL 顶层挂的 toolUseResult 元信息(非 content 字段)
22253
+ // 老 CC 走 <task-notification> user 消息携带统计,新 CC 直接挂在这里——兼容期两者可能并存
22254
+ toolResultExtra: ToolResultExtraSchema.optional(),
22255
+ // 精确指向发起 tool 的 assistant 消息顶层 uuid;toolUseId 已够 UI 聚合,这个仅作调试辅助
22256
+ sourceToolAssistantUUID: external_exports.string().optional(),
22257
+ // AskUserQuestion 实时回放(plan: clawd-ask-user-question 任务 B 修复):
22258
+ // CC 用户答完后把 answers 写在 user 帧顶层 toolUseResult.answers,daemon parser
22259
+ // 抽到这里。UI eventsToLines 用 toolUseId 配对到 question-card line,把卡片转为
22260
+ // 只读态显示用户的答案。仅 AskUserQuestion 配对的 tool_result 行携带;普通工具不带。
22261
+ // 等价于 HistoryMessage.askQuestionAnswers(历史回放路径),两端字段名对齐。
22262
+ askQuestionAnswers: external_exports.record(external_exports.string(), external_exports.string()).optional()
22263
+ }),
22264
+ // CC 命中项目记忆(`type:"attachment"`,`attachment.type:"memories"`)的独立事件;
22265
+ // 其它 attachment 子类型(skills / hook_context / deferred_tools / hook_success / unknown)
22266
+ // 视觉权重低,daemon 直接走 user_text + HistoryUserMeta 折叠,不另开 kind
22267
+ external_exports.object({
22268
+ ...ParsedEventBase,
22269
+ kind: external_exports.literal("attachment_memories"),
22270
+ memories: external_exports.array(MemoryEntrySchema)
22271
+ }),
22272
+ external_exports.object({
22273
+ ...ParsedEventBase,
22274
+ kind: external_exports.literal("permission_request"),
22275
+ requestId: external_exports.string(),
22276
+ tool: external_exports.string(),
22277
+ input: external_exports.unknown(),
22278
+ // CC `control_request.request.tool_use_id` 对应的 tool_use id;UI 用它把队列项与
22279
+ // 后续 tool_result.toolUseId 关联做跨客户端 dequeue(plan permission-multi-pending-queue.md
22280
+ // 选项 ii)。老 daemon / legacy CC 不发该字段时保持向后兼容(optional)。
22281
+ toolUseId: external_exports.string().optional()
22282
+ }),
22283
+ // AskUserQuestion 工具调用的内联锚点(plan: clawd-ask-user-question 问题 1 修复):
22284
+ // daemon parser 把 assistant tool_use AskUserQuestion 翻译成本 kind(不是 permission_request、
22285
+ // 也不是 tool_call),让 UI 在事件流自然位置渲染问答卡(紧跟 assistant 消息 / 在后续消息之前),
22286
+ // 而不是被强行挂在末尾。permission_request 帧仍正常下发驱动 pendingQuestions 状态机,
22287
+ // 但只走 wire 帧不入 ring buffer——状态由 daemon pendingQuestions 持有,
22288
+ // 渲染锚点由本 kind 的 ParsedEvent 提供。
22289
+ // 历史回放:history-to-lines.ts 在 jsonl tool_use AskUserQuestion 处插入对应 'question-card' line,
22290
+ // 配对的 tool_result 携带 toolUseResult.answers,已答完的展示只读态。
22291
+ external_exports.object({
22292
+ ...ParsedEventBase,
22293
+ kind: external_exports.literal("ask_user_question"),
22294
+ toolUseId: external_exports.string(),
22295
+ questions: external_exports.array(AskQuestionItemSchema)
22296
+ }),
22297
+ // turn_end —— 一轮 AI 响应结束。消费者:reducer pushEventToBuffer 翻 turnOpen=false;
22298
+ // UI useChatPanelState 收 "Claude is working" spinner(lastEventKind===turn_end)。
22299
+ // 三个产生来源:
22300
+ // ① SDK 模式 stream-json `result` 帧(claude.ts)—— stdout 最后一帧,可靠
22301
+ // ② TUI 模式 observer 读 JSONL `system/turn_duration` 行(claude-tui.ts parseLine)
22302
+ // ⚠️ CC 写此行早于该轮尾段正文落盘,可能被尾随 text 覆盖 lastEventKind(③ 存在的原因)
22303
+ // ③ TUI 模式屏幕静止 AND observer 静止(observeScreenIdle + manager.observerIdleWaitMs 复合闸 →
22304
+ // dispatchTurnIdle inject)—— 兜 ② 的覆盖;等尾随 text 全部 poll 落盘后补,排在 buffer 末条
22305
+ external_exports.object({
22306
+ ...ParsedEventBase,
22307
+ kind: external_exports.literal("turn_end")
22308
+ }),
22309
+ // SDK system 帧 task_started / task_progress / task_notification 的归一化产物:
22310
+ // 子 agent 执行过程中实时上报 agentId / lastToolName / stats,UI pending 期就能开抽屉、看进度。
22311
+ // toolUseId 对齐父 Agent 工具的 tool_use_id;status 由 SDK subtype 派生。
22312
+ external_exports.object({
22313
+ ...ParsedEventBase,
22314
+ kind: external_exports.literal("subagent_progress"),
22315
+ toolUseId: external_exports.string(),
22316
+ agentId: external_exports.string(),
22317
+ status: external_exports.enum(["started", "running", "completed", "failed"]),
22318
+ description: external_exports.string().optional(),
22319
+ lastToolName: external_exports.string().optional(),
22320
+ prompt: external_exports.string().optional(),
22321
+ stats: external_exports.object({
22322
+ durationMs: external_exports.number().int().nonnegative().optional(),
22323
+ tokens: external_exports.number().int().nonnegative().optional(),
22324
+ toolUseCount: external_exports.number().int().nonnegative().optional()
22325
+ }).optional()
22326
+ }),
22327
+ external_exports.object({
22328
+ ...ParsedEventBase,
22329
+ kind: external_exports.literal("error"),
22330
+ message: external_exports.string()
22331
+ }),
22332
+ // 元信息投递:daemon adapter 从任意来源(stream-json / JSONL)抽出的 SessionMeta 子集
22333
+ // reducer 做 patch merge + diff + persist + 广播 session:info;不入 ring buffer
22334
+ external_exports.object({
22335
+ ...ParsedEventBase,
22336
+ kind: external_exports.literal("meta_update"),
22337
+ patch: SessionMetaSchema
22338
+ }),
22339
+ // 系统消息(CC 自家系统提示 / 老板插话补充);persona 场景下区分两类:
22340
+ // metaSource='cc' → CC 注入的系统消息(默认低视觉权重渲染)
22341
+ // metaSource='owner' → 老板通过 persona:appendOwnerMessage 插入的话(蓝色气泡)
22342
+ // 缺省视为 'cc';现有非 persona 场景保持兼容(不需要 owner 时不下发该字段)
22343
+ external_exports.object({
22344
+ ...ParsedEventBase,
22345
+ kind: external_exports.literal("meta-text"),
22346
+ text: external_exports.string(),
22347
+ metaSource: external_exports.enum(["cc", "owner"]).optional()
22348
+ })
22349
+ ]);
22350
+ var SessionCreateArgs = external_exports.object({
22351
+ // 当 ownerPersonaId 存在时 cwd 由 daemon 派生,UI 可不传
22352
+ cwd: external_exports.string().min(1).optional(),
22353
+ tool: external_exports.string().optional(),
22354
+ label: external_exports.string().optional(),
22355
+ model: external_exports.string().optional(),
22356
+ permissionMode: external_exports.string().optional(),
22357
+ effort: external_exports.string().optional(),
22358
+ // 用户在 NewSessionDialog 选择的 icon 标识;UI 端做 enum 兜底
22359
+ iconKey: external_exports.string().optional(),
22360
+ // session:fork 派生 session 时由 UI 传入源 sessionId,daemon 写到 SessionFile.forkedFromSessionId
22361
+ forkedFromSessionId: external_exports.string().min(1).optional(),
22362
+ // 快速问答:创建时打 ephemeral 标记,daemon 写到 SessionFile.ephemeral
22363
+ ephemeral: external_exports.boolean().optional(),
22364
+ // owner-mode persona session:传此字段时 daemon 自行派生 cwd 和启动参数,
22365
+ // 且按 ownerPersonaId 做 idempotent dedupe(每 persona 永远只有一个 owner session)
22366
+ ownerPersonaId: external_exports.string().min(1).optional()
22367
+ // 单栏默认 refactor (spec 2026-06-02):appBuilderProject 字段已从 SessionCreateArgs 砍掉。
22368
+ // 绑定路径收敛到 appBuilder:createProject —— 先创建空 session(仅传 ownerPersonaId=persona-app-builder),
22369
+ // 后通过 createProject RPC 创建 project 并 daemon 内部 mutate 写入 appBuilderProject。
22370
+ // SessionFile schema 仍保留该字段供 daemon 内部 mutate(manager.update 内部调用通道)。
22371
+ }).refine((args) => args.cwd != null || args.ownerPersonaId != null, {
22372
+ message: "cwd \u4E0E ownerPersonaId \u81F3\u5C11\u4F20\u4E00\u4E2A"
22373
+ });
22374
+ var SessionListArgs = external_exports.object({
22375
+ /** true = 只返回 mirror(originOwnerPrincipalId 非空,即「我在朋友 daemon 上创建」的本机存证)。 */
22376
+ originOnly: external_exports.boolean().optional(),
22377
+ /**
22378
+ * 按 own persona 窄化(2026-07-21 self-persona-sessions 追加):只留
22379
+ * `s.ownerPersonaId === args.ownerPersonaId` 的 sessions。
22380
+ * - mirror 行(`ownerPersonaId` 恒 null)天然排除
22381
+ * - 与 `originOnly=true` 同传恒返 0
22382
+ * - 老 daemon 不识别时忽略字段返回全量,客户端消费侧本就自带过滤/截断,天然向后兼容
22383
+ */
22384
+ ownerPersonaId: external_exports.string().min(1).optional(),
22385
+ /** 按 updatedAt desc(list 的既有排序)截断前 N 条。 */
22386
+ limit: external_exports.number().int().positive().optional(),
22387
+ /**
22388
+ * 分页起点(2026-07-18 android-tasks-tab 迭代追加):originOnly / ownerPersonaId 过滤后、
22389
+ * limit 截断前跳过前 N 条。与 limit 组合 = updatedAt desc 序上的一页。响应带 total
22390
+ * (过滤后总数,见 handler)供客户端判 hasMore。老 daemon 不识别时忽略 → 回全量,
22391
+ * 客户端按全量兼容。
22392
+ */
22393
+ offset: external_exports.number().int().nonnegative().optional()
22394
+ });
22395
+ var SessionIdArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
22396
+ var SessionUpdateArgs = external_exports.object({
22397
+ sessionId: external_exports.string().min(1),
22398
+ patch: external_exports.object({
22399
+ label: external_exports.string().optional(),
22400
+ model: external_exports.string().optional(),
22401
+ permissionMode: external_exports.string().optional(),
22402
+ effort: external_exports.string().optional(),
22403
+ cwd: external_exports.string().optional(),
22404
+ // 用户在 Edit modal 选择的 icon 标识;UI 端做 enum 兜底
22405
+ iconKey: external_exports.string().optional()
22406
+ // 注意:appBuilderProject 字段已从 patch 中砍掉(spec 2026-06-02-app-builder-single-pane-default-design)。
22407
+ // 绑定单向不可变 —— 由 appBuilder:createProject 在 daemon 内部一次写入;UI / assistant 不再
22408
+ // 通过 sessionUpdate 修改这个字段。SessionFile 仍保留 appBuilderProject 字段供 daemon 内部 mutate。
22409
+ })
22410
+ });
22411
+ var SessionSendArgs = external_exports.object({
22412
+ sessionId: external_exports.string().min(1),
22413
+ text: external_exports.string()
22414
+ });
22415
+ var SessionInterruptArgs = SessionIdArgs;
22416
+ var SessionRewindArgs = external_exports.object({
22417
+ sessionId: external_exports.string().min(1),
22418
+ userMessageId: external_exports.string().min(1),
22419
+ dryRun: external_exports.boolean().optional()
22420
+ });
22421
+ var SessionRewindResponseSchema = external_exports.object({
22422
+ canRewind: external_exports.boolean(),
22423
+ error: external_exports.string().optional(),
22424
+ filesChanged: external_exports.array(external_exports.string()).optional(),
22425
+ insertions: external_exports.number().int().nonnegative().optional(),
22426
+ deletions: external_exports.number().int().nonnegative().optional()
22427
+ });
22428
+ var SessionRewindDiffArgs = external_exports.object({
22429
+ sessionId: external_exports.string().min(1),
22430
+ userMessageId: external_exports.string().min(1)
22431
+ });
22432
+ var RewindDiffHunkSchema = external_exports.object({
22433
+ oldStart: external_exports.number().int().nonnegative(),
22434
+ oldLines: external_exports.number().int().nonnegative(),
22435
+ newStart: external_exports.number().int().nonnegative(),
22436
+ newLines: external_exports.number().int().nonnegative(),
22437
+ lines: external_exports.array(external_exports.string())
22438
+ });
22439
+ var RewindDiffFileSchema = external_exports.object({
22440
+ filePath: external_exports.string().min(1),
22441
+ hunks: external_exports.array(RewindDiffHunkSchema),
22442
+ insertions: external_exports.number().int().nonnegative(),
22443
+ deletions: external_exports.number().int().nonnegative(),
22444
+ status: external_exports.enum(["modified", "added", "deleted"]).optional()
22445
+ });
22446
+ var SessionRewindDiffResponseSchema = external_exports.object({
22447
+ canRewind: external_exports.boolean(),
22448
+ error: external_exports.string().optional(),
22449
+ files: external_exports.array(RewindDiffFileSchema),
22450
+ totalInsertions: external_exports.number().int().nonnegative(),
22451
+ totalDeletions: external_exports.number().int().nonnegative()
22452
+ });
22453
+ var SessionRewindableMessageIdsArgs = SessionIdArgs;
22454
+ var SessionRewindableMessageIdsResponseSchema = external_exports.object({
22455
+ userMessageIds: external_exports.array(external_exports.string())
22456
+ });
22457
+ var SessionResumeArgs = external_exports.object({
22458
+ sessionId: external_exports.string().min(1),
22459
+ toolSessionId: external_exports.string().min(1)
22460
+ });
22461
+ var SessionForkArgs = external_exports.object({
22462
+ cwd: external_exports.string().min(1),
22463
+ toolSessionId: external_exports.string().min(1),
22464
+ messageUuid: external_exports.string().min(1)
22465
+ });
22466
+ var SessionForkResponseSchema = external_exports.object({
22467
+ forkedToolSessionId: external_exports.string().min(1),
22468
+ forkedFilePath: external_exports.string().min(1)
22469
+ });
22470
+ var SessionObserveArgs = external_exports.object({
22471
+ sessionId: external_exports.string().min(1),
22472
+ toolSessionId: external_exports.string().min(1),
22473
+ jsonlPath: external_exports.string().optional()
22474
+ });
22475
+ var SessionEventsArgs = external_exports.object({
22476
+ sessionId: external_exports.string().min(1),
22477
+ // -1 表示"从头拉全量"(尚未见过任何事件);seq 从 0 起,所以合法下界是 -1
22478
+ afterSeq: external_exports.number().int().min(-1)
22479
+ });
22480
+ var PermissionRespondArgs = external_exports.object({
22481
+ sessionId: external_exports.string().min(1),
22482
+ // 权限请求 id 用 `permissionRequestId`,**不能**叫 `requestId`:WS 传输层用帧顶层的
22483
+ // `requestId` 做 RPC 请求/响应关联(daemon-client 发帧时 `{...args, type, requestId}`,
22484
+ // 传输 id 在最后会覆盖 args 同名字段)。若沿用 `requestId`,权限 id 会被传输 id(如 "r61")
22485
+ // 覆盖,daemon 查 pendingPermissions 永远 miss → 点了允许一直卡住。
22486
+ permissionRequestId: external_exports.string().min(1),
22487
+ allow: external_exports.boolean(),
22488
+ permanent: external_exports.boolean().optional(),
22489
+ pattern: external_exports.string().optional()
22490
+ });
22491
+ var HistoryListArgs = external_exports.object({ projectPath: external_exports.string().min(1) });
22492
+ var HistoryReadArgs = external_exports.object({
22493
+ sessionId: external_exports.string().min(1),
22494
+ limit: external_exports.number().int().positive().max(5e3).optional(),
22495
+ /** 不传时走 tail 语义:daemon 返回最后 limit 条(offset = max(0, total - limit)) */
22496
+ offset: external_exports.number().int().nonnegative().optional(),
22497
+ /**
22498
+ * 瘦身投影(2026-07-18 android-tasks-tab 迭代,v2 语义):true = daemon 裁掉窄消费面客户端
22499
+ * (mobile)不渲染的大字段(input / output / raw / toolResultExtra / memories /
22500
+ * sourceToolAssistantUUID),meta 注入行 text 截 500 字符。**例外:出错的工具调用全量保留**——
22501
+ * 本页内 error 非空的 tool_result 保留 output,且其同 toolUseId 的 tool_call 保留 input
22502
+ * (用户要能看清「啥错了」;老板 2026-07-18 拍板:普通工具调用手机不渲染,错误全量展示)。
22503
+ * desktop 渲染 tool card 需全文,不用此参数。老 daemon 不识别 → 回全量,客户端向后兼容。
22504
+ */
22505
+ slim: external_exports.boolean().optional()
22506
+ });
22507
+ var HistorySubagentsArgs = external_exports.object({
22508
+ cwd: external_exports.string().min(1),
22509
+ toolSessionId: external_exports.string().min(1)
22510
+ });
22511
+ var HistorySubagentReadArgs = external_exports.object({
22512
+ cwd: external_exports.string().min(1),
22513
+ toolSessionId: external_exports.string().min(1),
22514
+ subagentId: external_exports.string().min(1)
22515
+ });
22516
+ var WorkspaceListArgs = external_exports.object({
22517
+ // cwd 缺省则 daemon 兜底 os.homedir();UI 的 DirBrowser 首次浏览就走这条路径
22518
+ cwd: external_exports.string().min(1).optional(),
22519
+ path: external_exports.string().optional(),
22520
+ showHidden: external_exports.boolean().optional()
22521
+ });
22522
+ var WorkspaceReadArgs = external_exports.object({
22523
+ cwd: external_exports.string().min(1),
22524
+ path: external_exports.string().min(1)
22525
+ });
22526
+ var SkillsListArgs = external_exports.object({ cwd: external_exports.string().min(1), tool: external_exports.string().optional() });
22527
+ var SkillEntrySchema = external_exports.object({
22528
+ name: external_exports.string().min(1),
22529
+ source: external_exports.enum(SKILL_SOURCE_VALUES),
22530
+ path: external_exports.string().optional(),
22531
+ description: external_exports.string().optional(),
22532
+ plugin: external_exports.string().optional()
22533
+ });
22534
+ var AgentEntrySchema = external_exports.object({
22535
+ name: external_exports.string().min(1),
22536
+ source: external_exports.enum(AGENT_SOURCE_VALUES),
22537
+ path: external_exports.string().optional(),
22538
+ description: external_exports.string().optional(),
22539
+ whenToUse: external_exports.string().optional(),
22540
+ plugin: external_exports.string().optional()
22541
+ });
22542
+ var AgentsListArgs = external_exports.object({ cwd: external_exports.string().min(1), tool: external_exports.string().optional() });
22543
+ var AgentsListResponseSchema = external_exports.object({
22544
+ agents: external_exports.array(AgentEntrySchema)
22545
+ });
22546
+ var SessionCurrentTurnSenderArgs = external_exports.object({
22547
+ // 刻意不加 .min(1):空串是被依赖的软路径(handler 见空即返 sender:null,
22548
+ // session-current-turn-sender.spec 有用例守着)。加了 min 会把它变成硬报错。
22549
+ sessionId: external_exports.string().optional()
22550
+ });
22551
+ var SessionSubscribeArgs = external_exports.object({ sessionId: external_exports.string().min(1).optional() });
22552
+ var SessionPinArgs = external_exports.object({
22553
+ sessionId: external_exports.string().min(1),
22554
+ pinned: external_exports.boolean()
22555
+ });
22556
+ var PeerSessionUpsertArgs = SessionFileSchema;
22557
+ var PeerSessionUpsertResponseSchema = external_exports.object({
22558
+ type: external_exports.literal("peerSession:upsert:ok")
22559
+ });
22560
+ var PeerSessionRemoveArgs = external_exports.object({ sessionId: external_exports.string().min(1) });
22561
+ var PeerSessionRemoveResponseSchema = external_exports.object({
22562
+ type: external_exports.literal("peerSession:remove:ok")
22563
+ });
22564
+ var SessionReorderPinsArgs = external_exports.object({
22565
+ orderedIds: external_exports.array(external_exports.string().min(1)).min(1)
22566
+ });
22567
+ var GitRootArgs = external_exports.object({ cwd: external_exports.string().min(1) });
22568
+ var GitRootResponseSchema = external_exports.object({
22569
+ isGitRoot: external_exports.boolean(),
22570
+ gitRoot: external_exports.string().nullable()
22571
+ });
22572
+ var GitBranchArgs = external_exports.object({ cwd: external_exports.string().min(1) });
22573
+ var GitBranchResponseSchema = external_exports.object({
22574
+ branch: external_exports.string().nullable()
22575
+ });
22576
+ var GitBranchesArgs = external_exports.object({ cwd: external_exports.string().min(1) });
22577
+ var GitBranchesResponseSchema = external_exports.object({
22578
+ branches: external_exports.array(external_exports.string()),
22579
+ head: external_exports.string().nullable()
22580
+ });
22581
+ var HistoryRecentDirsArgs = external_exports.object({}).optional();
22582
+ var RecentDirEntrySchema = external_exports.object({
22583
+ cwd: external_exports.string().min(1),
22584
+ updatedAt: external_exports.string().min(1)
22585
+ });
22586
+ var HistoryRecentDirsResponseSchema = external_exports.object({
22587
+ dirs: external_exports.array(RecentDirEntrySchema)
22588
+ });
22589
+ var SessionQuestionFrameSchema = external_exports.object({
22590
+ type: external_exports.literal("session:question"),
22591
+ sessionId: external_exports.string().min(1),
22592
+ toolUseId: external_exports.string().min(1),
22593
+ requestId: external_exports.string().min(1),
22594
+ // UI 单卡承载多 question;空数组语义无效,schema 必拒
22595
+ questions: external_exports.array(AskQuestionItemSchema).min(1)
22596
+ });
22597
+ var SessionQuestionClearedFrameSchema = external_exports.object({
22598
+ type: external_exports.literal("session:question:cleared"),
22599
+ sessionId: external_exports.string().min(1),
22600
+ toolUseId: external_exports.string().min(1),
22601
+ // record<string,string>:与 AnswerQuestionArgs.answers 同形状(question text → label)
22602
+ answers: external_exports.record(external_exports.string(), external_exports.string()).optional()
22603
+ });
22604
+ var AnswerQuestionArgs = external_exports.object({
22605
+ sessionId: external_exports.string().min(1),
22606
+ toolUseId: external_exports.string().min(1),
22607
+ answers: external_exports.record(external_exports.string(), external_exports.string())
22608
+ });
22609
+ var AnswerQuestionResponseSchema = external_exports.object({ ok: external_exports.literal(true) });
22610
+ var CancelQuestionArgs = external_exports.object({
22611
+ sessionId: external_exports.string().min(1),
22612
+ toolUseId: external_exports.string().min(1)
22613
+ });
22614
+ var CancelQuestionResponseSchema = external_exports.object({ ok: external_exports.literal(true) });
22615
+ var AuthRequestFrameSchema = external_exports.object({
22616
+ type: external_exports.literal("auth"),
22617
+ token: external_exports.string().min(1),
22618
+ scheme: external_exports.literal("bearer").optional(),
22619
+ /**
22620
+ * 决策 #16:自报身份字段(selfPrincipalId / selfDisplayName / selfDeviceId)全部删除——
22621
+ * guest 的设备 id / 人 id / 来源全部由 connect token 的 subDevice/subOwner/provider 签名背书
22622
+ * (server 签、目标设备本地验签,不可伪造),不再接受任何自报身份。
22623
+ *
22624
+ * selfUrl 已废弃(spec 2026-07-22 双向确认建联):可达地址自报移入 contact:handshake
22625
+ * args——auth 层回归纯验票。旧客户端发来的 selfUrl 被 strip(zod 默认),无害;
22626
+ * 旧客户端本身由 whoami 的 connect-token 拒绝路径拦截(CLIENT_OUTDATED)。
22627
+ */
22628
+ /**
22629
+ * 客户端自报的 user-agent 性质标签(诊断/展示用)。
22630
+ * 「自报事实」,非身份(决策 #16 边界):不参与鉴权、不参与路由、
22631
+ * 任何 handler 不得据此做权限判断。name 约定命名('clawd-desktop' / 'clawd-web' /
22632
+ * 'clawd-mobile-android' / ...),宽容未知值(将来加新客户端不动 schema)。
22633
+ * instanceId:客户端首启生成 UUID 并本地持久化——区分同种类多实例(多手机/多 desktop 同连)。
22634
+ */
22635
+ clientInfo: external_exports.object({
22636
+ name: external_exports.string().min(1),
22637
+ version: external_exports.string().min(1),
22638
+ instanceId: external_exports.string().min(1)
22639
+ }).optional()
22640
+ });
22641
+ var AuthOkFrameSchema = external_exports.object({
22642
+ type: external_exports.literal("auth:ok"),
22643
+ version: external_exports.string().min(1).optional(),
22644
+ protocolVersion: external_exports.number().int().nonnegative().optional()
22645
+ });
22646
+ var TunnelReadyEventSchema = external_exports.object({
22647
+ type: external_exports.literal("tunnel:ready"),
22648
+ url: external_exports.string().min(1),
22649
+ subdomain: external_exports.string().min(1)
22650
+ });
22651
+ var TunnelExitedEventSchema = external_exports.object({
22652
+ type: external_exports.literal("tunnel:exited"),
22653
+ code: external_exports.number().int().nullable(),
22654
+ subdomain: external_exports.string().nullable(),
22655
+ url: external_exports.string().nullable()
22656
+ });
22657
+ var TunnelUnavailableEventSchema = external_exports.object({
22658
+ type: external_exports.literal("tunnel:unavailable"),
22659
+ reason: external_exports.string().min(1),
22660
+ failedAt: external_exports.string().min(1)
22661
+ });
22662
+ var InfoRunningSessionSchema = external_exports.object({
22663
+ sessionId: external_exports.string().min(1),
22664
+ status: SessionStatusSchema,
22665
+ freshSpawn: external_exports.boolean(),
22666
+ pendingPermissionRequestIds: external_exports.array(external_exports.string().min(1)),
22667
+ pendingQuestionToolUseIds: external_exports.array(external_exports.string().min(1))
22668
+ });
22669
+ var InfoResponseSchema = external_exports.object({
22670
+ type: external_exports.literal("info"),
22671
+ version: external_exports.string(),
22672
+ protocolVersion: external_exports.number(),
22673
+ hostname: external_exports.string(),
22674
+ os: external_exports.string(),
22675
+ tools: external_exports.array(external_exports.object({ id: external_exports.string(), available: external_exports.boolean() })),
22676
+ runningSessions: external_exports.array(InfoRunningSessionSchema),
22677
+ // ── file-sharing 会话身份回执(spec: superpowers/specs/2026-05-19-clawd-file-sharing-design.md §8) ──
22678
+ // PR 1 阶段标 optional(daemon 还没下发,旧 daemon info 响应不带这五个字段);
22679
+ // PR 2 daemon 实现 single HTTP server + auth-context 后,daemon 必返这五个字段,
22680
+ // 届时可考虑改成 required。spec §11 第 3 条:"tokenRole 是协议字段,daemon 查 token
22681
+ // 表后显式下发,UI 不自行推导"——所以 UI 一律读这里,禁止本地推导。
22682
+ /** 'owner' = 拿到 owner-token 的连接(不限来源 IP)。来源 TOKEN_ROLES(spec §11 #1 中央真理源)。
22683
+ * 历史 'personal' role(persona file-sharing token)在 2026-05-21 删除;tokenPersonaId 一同移除。 */
22684
+ tokenRole: external_exports.enum(TOKEN_ROLES).optional(),
22685
+ /** socket.remoteAddress 是否落在 127.0.0.1 / ::1;本期无 RPC 消费,保留协议槽位给未来 "Reveal in Finder" 等本机动作 */
22686
+ isLoopback: external_exports.boolean().optional(),
22687
+ /** UI 拼 file-sharing HTTP 路由的前缀(http(s)://host:port),不含尾斜杠;frpc 反代时返反代地址 */
22688
+ httpBaseUrl: external_exports.string().optional(),
22689
+ /** file-sharing HTTP 路由的 Authorization: Bearer token;与 WS token 解耦,HTTP 401 仅触发 ReAuth 不强踢 WS(spec §11 第 4 条) */
22690
+ httpToken: external_exports.string().optional()
22691
+ });
22692
+ var PROJECT_PORT_MIN = 6173;
22693
+ var PROJECT_PORT_MAX = 6272;
22694
+ var projectNameRegex = /^[a-z][a-z0-9-]{0,39}$/;
22695
+ var ProjectMetadataSchema = external_exports.object({
22696
+ name: external_exports.string().regex(projectNameRegex, {
22697
+ message: "kebab-case, \u5C0F\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u53EA\u5141\u8BB8\u5C0F\u5199\u5B57\u6BCD / \u6570\u5B57 / -\uFF0C\u6700\u957F 40 \u5B57\u7B26"
22698
+ }),
22699
+ port: external_exports.number().int().min(PROJECT_PORT_MIN).max(PROJECT_PORT_MAX),
22700
+ createdAt: external_exports.string().datetime(),
22701
+ /** dev server 启动命令(shell 字符串);占位符 $CLAWD_PREVIEW_PORT 替换 + env 注入 */
22702
+ devCommand: external_exports.string().min(1),
22703
+ /**
22704
+ * 发布上线后的公网 URL(spec 2026-06-02-app-builder-single-pane-default-design §5.6.1)。
22705
+ * assistant 跑完 publish.sh 后调 appBuilder:setProdUrl 写入;UI 读这个字段切预览栏到线上 URL,
22706
+ * 取代旧 `<builder-preview url=... label="prod" />` marker 机制。
22707
+ * 老 project 元数据无此字段(optional 兼容)。
22708
+ */
22709
+ prodUrl: external_exports.string().url().optional(),
22710
+ /**
22711
+ * dev server 就绪 stdout regex(spec 2026-06-02-app-builder-explicit-dev-server-control §2)。
22712
+ * supervisor spawn 后会监听子进程 stdout,命中此 regex 视为 dev server 真 ready;
22713
+ * 仅当 await ready 后才把 stage 切到 'running',避免 cold start race 导致 iframe 502。
22714
+ * optional:缺省时 supervisor 用默认 /Local:\s+https?:\/\//(vite "Local: http://..." 输出)。
22715
+ * 老板换非 vite 技术栈(Next.js "Ready in"、webpack "Compiled" 等)时自定义这个字段。
22716
+ */
22717
+ readyPattern: external_exports.string().optional(),
22718
+ /**
22719
+ * 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.4):
22720
+ * in-flight 发布 job 的元数据。仅承载"in-flight"或"中断残骸"两种状态:
22721
+ * - daemon spawn publish.sh + 收到第一个 ::stage::build marker 时写入
22722
+ * - 每次 stage 切换更新 stage 字段
22723
+ * - 成功 / 正常失败 / 用户 dismiss 时立即清掉
22724
+ * - 只有 daemon 崩才会留残骸(子进程随 daemon 一起死)
22725
+ * status 字段在 ProjectWithStatus 派生而不在这里 —— 本 schema 是落盘形态,
22726
+ * "in-flight vs interrupted" 区分由 daemon 响应时实时拼 registry 状态得出。
22727
+ */
22728
+ publishJob: external_exports.object({
22729
+ jobId: external_exports.string().min(1),
22730
+ stage: external_exports.enum(["build", "deploy", "verify"]),
22731
+ startedAt: external_exports.number().int().nonnegative()
22732
+ }).optional()
22733
+ });
22734
+ var PROJECT_STAGE_VALUES = [
22735
+ "install-pending",
22736
+ // createProject 刚返回,scaffold 已完成(daemon 同步内联跑),等 assistant pnpm install
22233
22737
  "installing",
22738
+ // assistant pnpm install 中
22739
+ "starting-dev-server",
22740
+ // startDevServer 已调,supervisor spawn 子进程中(await ready 期间也在此 stage)
22741
+ "running",
22742
+ // dev server 跑起来了(supervisor stdout 命中 readyPattern + 端口已监听)
22743
+ "stopped",
22744
+ // 用户显式点"收起预览"停掉 / daemon 重启后默认;UI 渲染折叠条 + "展开预览"按钮
22234
22745
  "failed"
22746
+ // 某个阶段失败(stageReason 字段携带原因,含 dev server cold start timeout)
22235
22747
  ];
22236
- var ReportStageArgsSchema = external_exports.object({
22237
- sessionId: external_exports.string().min(1),
22238
- stage: external_exports.enum(ASSISTANT_REPORTABLE_STAGES),
22239
- /** stage='failed' 时必填的原因(一句话),其它 stage optional */
22240
- reason: external_exports.string().optional()
22241
- }).strict();
22242
- var ReportStageResultSchema = external_exports.object({
22243
- ok: external_exports.literal(true)
22244
- }).strict();
22245
- var StopDevServerArgsSchema = external_exports.object({
22246
- sessionId: external_exports.string().min(1)
22247
- }).strict();
22248
- var StopDevServerResultSchema = external_exports.object({
22249
- ok: external_exports.literal(true)
22250
- }).strict();
22251
- var AppBuilderProjectUpdatedEventSchema = external_exports.object({
22252
- type: external_exports.literal("appBuilder:project-updated"),
22253
- project: ProjectWithStatusSchema,
22254
- stage: ProjectStageSchema,
22255
- /** stage='failed' 时的失败原因 */
22256
- stageReason: external_exports.string().optional()
22257
- }).strict();
22258
- var PublishArgsSchema = external_exports.object({
22259
- name: external_exports.string().regex(projectNameRegex)
22260
- });
22261
- var PublishResultSchema = external_exports.object({
22262
- jobId: external_exports.string().min(1),
22263
- status: external_exports.enum(["started", "already-publishing"])
22264
- }).strict();
22265
- var DismissPublishJobArgsSchema = external_exports.object({
22266
- name: external_exports.string().regex(projectNameRegex)
22267
- });
22268
- var DismissPublishJobResultSchema = external_exports.object({
22269
- ok: external_exports.literal(true)
22270
- }).strict();
22271
- var AppBuilderPublishProgressEventSchema = external_exports.object({
22272
- type: external_exports.literal("appBuilder:publish-progress"),
22273
- name: external_exports.string().regex(projectNameRegex),
22274
- jobId: external_exports.string().min(1),
22275
- stage: external_exports.enum(["build", "deploy", "verify"]),
22276
- status: external_exports.enum(["started", "completed"])
22277
- }).strict();
22278
- var AppBuilderPublishFailedEventSchema = external_exports.object({
22279
- type: external_exports.literal("appBuilder:publish-failed"),
22280
- name: external_exports.string().regex(projectNameRegex),
22281
- jobId: external_exports.string().min(1),
22282
- stage: external_exports.enum(["build", "deploy", "verify", "unknown"]),
22283
- errorSummary: external_exports.string()
22284
- }).strict();
22285
-
22286
- // ../protocol/src/capability.ts
22287
- var ResourceSchema2 = external_exports.discriminatedUnion("type", [
22288
- external_exports.object({ type: external_exports.literal("persona"), id: external_exports.string().min(1) }).strict(),
22289
- external_exports.object({ type: external_exports.literal("chat"), id: external_exports.string().min(1) }).strict(),
22290
- external_exports.object({ type: external_exports.literal("*") }).strict()
22291
- ]);
22292
- var ActionSchema = external_exports.enum(["read", "send", "admin"]);
22293
- var GrantSchema = external_exports.object({
22294
- resource: ResourceSchema2,
22295
- actions: external_exports.array(ActionSchema).min(1)
22296
- }).strict();
22297
- var CapabilitySchema = external_exports.object({
22298
- id: external_exports.string().min(1),
22299
- // sha256(token) hex 64
22300
- secretHash: external_exports.string().regex(/^[a-f0-9]{64}$/),
22301
- displayName: external_exports.string(),
22302
- // 空数组合法 = 纯访客(只能 DM)
22303
- grants: external_exports.array(GrantSchema),
22304
- issuedAt: external_exports.number().int().nonnegative(),
22305
- expiresAt: external_exports.number().int().positive().optional(),
22306
- maxUses: external_exports.number().int().positive().optional(),
22307
- usedCount: external_exports.number().int().nonnegative(),
22748
+ var ProjectStageSchema = external_exports.enum(PROJECT_STAGE_VALUES);
22749
+ var ProjectWithStatusSchema = ProjectMetadataSchema.extend({
22750
+ isRunning: external_exports.boolean(),
22751
+ boundSessionId: external_exports.string().nullable(),
22308
22752
  /**
22309
- * guest auth 帧捎带 selfPrincipalId 时由 AuthGate.authenticate 回写;
22310
- * 未被消费的 cap 此字段缺失。
22753
+ * 单栏 refactor stage fix (spec 2026-06-02 §5.6.2):daemon 内存维护的当前 stage。
22754
+ * UI 据此切 PreviewPane spinner / iframe / error。
22755
+ * optional 兼容启动后 daemon 还没有 stage 记录的 fresh project(按 isRunning 推断兜底)。
22311
22756
  */
22312
- peerOwnerId: external_exports.string().min(1).optional(),
22313
- /** 首次 client hello 时间戳(与 peerOwnerId 同步写入) */
22314
- firstUsedByPeerAt: external_exports.number().int().positive().optional(),
22757
+ stage: ProjectStageSchema.optional(),
22758
+ /** stage='failed' 时携带失败原因 */
22759
+ stageReason: external_exports.string().optional(),
22315
22760
  /**
22316
- * 对方 daemon owner 的 displayName,guest auth 帧 selfDisplayName 触发
22317
- * recordPeerHello 时同步回写。视角 B (2026-05-23) UI 派生联系人列表用此字段
22318
- * 显示对方名字(避免 fallback 到我颁 cap 时填的 displayName)。
22761
+ * 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.3):
22762
+ * ProjectMetadata.publishJob status 派生版。daemon 响应时按以下规则实时拼装:
22763
+ * - 落盘字段存在 + PublishJobRegistry 有匹配 jobId → 'in-flight'
22764
+ * - 落盘字段存在 + Registry 无匹配(jobId 对不上或 entry 缺失)→ 'interrupted'(daemon 崩残骸)
22765
+ * - 落盘字段不存在 → undefined(字段省略)
22766
+ * UI 用 status 决定 PreviewPane 渲染分支(in-flight 三段 checklist / interrupted 恢复条)。
22319
22767
  */
22320
- peerDisplayName: external_exports.string().optional()
22768
+ publishJob: external_exports.object({
22769
+ jobId: external_exports.string().min(1),
22770
+ stage: external_exports.enum(["build", "deploy", "verify"]),
22771
+ startedAt: external_exports.number().int().nonnegative(),
22772
+ status: external_exports.enum(["in-flight", "interrupted"])
22773
+ }).optional()
22774
+ });
22775
+ var ListProjectsArgsSchema = external_exports.object({}).strict();
22776
+ var ListProjectsResultSchema = external_exports.object({
22777
+ projects: external_exports.array(ProjectWithStatusSchema)
22321
22778
  }).strict();
22322
- var CapabilityWireSchema = CapabilitySchema.omit({ secretHash: true });
22323
- var WhoamiResponseSchema = external_exports.object({
22324
- type: external_exports.literal("whoami:ok"),
22325
- owner: external_exports.object({
22326
- id: external_exports.string(),
22327
- kind: external_exports.enum(["owner", "guest"]),
22328
- displayName: external_exports.string(),
22329
- /** 归属人 id(决策 #16:TTC unique_id 等,落 contact.ownerId) */
22330
- ownerId: external_exports.string(),
22331
- /** 身份来源(决策 #16:'ttc'/'google',落 contact.provider) */
22332
- provider: external_exports.string()
22333
- }).strict(),
22334
- capability: CapabilityWireSchema,
22335
- grantedPersonas: external_exports.array(
22336
- external_exports.object({
22337
- id: external_exports.string().min(1),
22338
- displayName: external_exports.string()
22339
- }).strict()
22340
- )
22779
+ var GetProjectArgsSchema = external_exports.object({
22780
+ sessionId: external_exports.string().min(1)
22341
22781
  }).strict();
22342
- var PERSONAL_CAP_GRANTS = Object.freeze([
22343
- Object.freeze({
22344
- resource: Object.freeze({ type: "persona", id: "*" }),
22345
- actions: Object.freeze(["read", "send"])
22346
- })
22347
- ]);
22348
-
22349
- // ../protocol/src/inbox.ts
22350
- var InboxMessageSchema = external_exports.object({
22351
- id: external_exports.string().min(1),
22352
- peerDeviceId: external_exports.string().min(1),
22353
- senderDeviceId: external_exports.string().min(1),
22354
- text: external_exports.string().min(1),
22355
- createdAt: external_exports.number().int().nonnegative(),
22356
- readBy: external_exports.record(external_exports.string().min(1), external_exports.number().int().positive()).default({}),
22357
- // persona 代发署名(B 版设计):非空 = 该消息由某 persona 代发,非真人手打。
22358
- // 缺省 = 真人。routing 身份仍看 senderDeviceId;origin 只用于末端 UI 渲染来源。
22359
- origin: external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }).optional()
22782
+ var GetProjectResultSchema = external_exports.object({
22783
+ /** session 未绑 project / project 不存在时为 null(UI 走单栏 / 折叠) */
22784
+ project: ProjectWithStatusSchema.nullable()
22360
22785
  }).strict();
22361
- var InboxPostMessageArgsSchema = external_exports.object({
22362
- peerDeviceId: external_exports.string().min(1).optional(),
22363
- id: external_exports.string().min(1),
22364
- text: external_exports.string().min(1),
22365
- createdAt: external_exports.number().int().nonnegative(),
22366
- // persona 代发署名(跨 daemon forward 时随远程腿透传;真人发缺省)。
22367
- origin: external_exports.object({ kind: external_exports.literal("persona"), personaId: external_exports.string().min(1) }).optional()
22786
+ var CreateProjectArgsSchema = external_exports.object({
22787
+ /** 必填:caller session,daemon 自动绑过去(spec 2026-06-02 §3 invariant 1 Session ↔ 1 Project) */
22788
+ sessionId: external_exports.string().min(1),
22789
+ // .min(1):改造前手写校验是 `!f.name` 明确拒空串;空 name 会让 projectDir('')
22790
+ // 落到 projects 根目录,scaffold 往根上铺模板。
22791
+ name: external_exports.string().min(1)
22368
22792
  }).strict();
22369
- var InboxListArgsSchema = external_exports.object({
22370
- peerDeviceId: external_exports.string().min(1),
22371
- sinceCreatedAt: external_exports.number().int().nonnegative().optional()
22793
+ var CreateProjectResultSchema = external_exports.object({
22794
+ project: ProjectMetadataSchema
22372
22795
  }).strict();
22373
- var InboxMarkReadArgsSchema = external_exports.object({
22374
- peerDeviceId: external_exports.string().min(1),
22375
- upToCreatedAt: external_exports.number().int().nonnegative()
22796
+ var DeleteProjectArgsSchema = external_exports.object({
22797
+ name: external_exports.string()
22376
22798
  }).strict();
22377
- var InboxSendDmArgsSchema = external_exports.object({
22378
- peerDeviceId: external_exports.string().min(1).optional(),
22379
- text: external_exports.string().min(1)
22380
- });
22381
-
22382
- // ../protocol/src/contact.ts
22383
- var ContactSchema = external_exports.object({
22384
- /**
22385
- * 对方设备标识(主键):对方 daemon 自己生成并持久化的标识(auth.json deviceId,
22386
- * 如 dev-<uuid>),provider 无关。同 deviceId 重复 upsert 覆盖。
22387
- */
22388
- deviceId: external_exports.string().min(1),
22389
- /**
22390
- * 归属人 id(决策 #16):TTC unique_id 等,由 connect token subOwner 签名背书。
22391
- * 与 provider 一起唯一标识一个人。DM 不再按它路由(路由用 deviceId),仅显示/分组用。
22392
- */
22393
- ownerId: external_exports.string().min(1),
22394
- /** 身份来源(决策 #16):'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...,token 背书 */
22395
- provider: external_exports.string().min(1),
22396
- /** 联系人显示名 */
22397
- displayName: external_exports.string(),
22398
- /** 该设备可达的 ws/tunnel 地址 */
22399
- remoteUrl: external_exports.string().min(1),
22400
- // 自动反向建立联系人(spec 决策 #11):被连接方本地验票成功后自动落 A 为
22401
- // 联系人,但它不持有 A 颁发的 token(A 从未给它换票)→ connectToken 为空串。
22402
- // device:connect 出站路径仍存中心 server 签发的真实 connect token(断线重连复用)。
22403
- // 不用 .min(1):自动反向路径合法地存空串,禁止填假 token 占位(不造假数据)。
22404
- connectToken: external_exports.string(),
22405
- grants: external_exports.array(GrantSchema),
22406
- addedAt: external_exports.number().int().nonnegative(),
22407
- /**
22408
- * pin 时间戳(ms,Date.now() 语义);null = 未 pin。sidebar 顶部固定区渲染由此驱动。
22409
- * 老 contacts.json 缺此字段 → zod default 补 null(无破坏性升级;不 orphan)。
22410
- * 对齐 SessionFile.pinnedAt 语义(daemon 侧持久化,contact:pin RPC 更新 → contact:pinned push)。
22411
- */
22412
- pinnedAt: external_exports.number().int().nullable().default(null),
22413
- /**
22414
- * 远程访问授权(spec 2026-07-16)。owner 视角:允许该 contact 反向操作我的设备——
22415
- * 跨设备 exec 的总开关(peerExec:run handler 运行时判它)。default=false,owner 显式开。
22416
- * 授权粒度 per-people (per-contact):借用别人 persona 本来就带信任对方本人的前提。
22417
- */
22418
- remoteAccessAllowed: external_exports.boolean().default(false)
22799
+ var DeleteProjectResultSchema = external_exports.object({}).strict();
22800
+ var UpdateProjectPortArgsSchema = external_exports.object({
22801
+ name: external_exports.string(),
22802
+ newPort: external_exports.number().int()
22419
22803
  }).strict();
22420
- var ContactWireSchema = ContactSchema;
22421
- var ContactRemoveArgsSchema = external_exports.object({
22422
- deviceId: external_exports.string().min(1)
22804
+ var UpdateProjectPortResultSchema = external_exports.object({
22805
+ project: ProjectMetadataSchema
22423
22806
  }).strict();
22424
- var ContactRemoveOkSchema = external_exports.object({
22425
- type: external_exports.literal("contact:remove:ok"),
22426
- deviceId: external_exports.string().min(1)
22807
+ var SetProdUrlArgsSchema = external_exports.object({
22808
+ name: external_exports.string().regex(projectNameRegex),
22809
+ url: external_exports.string().url()
22427
22810
  }).strict();
22428
- var ContactListOkSchema = external_exports.object({
22429
- type: external_exports.literal("contact:list:ok"),
22430
- contacts: external_exports.array(ContactWireSchema)
22811
+ var SetProdUrlResultSchema = external_exports.object({
22812
+ project: ProjectMetadataSchema
22431
22813
  }).strict();
22432
- var ContactAddedFrameSchema = external_exports.object({
22433
- type: external_exports.literal("contact:added"),
22434
- contact: ContactWireSchema
22814
+ var StartDevServerArgsSchema = external_exports.object({
22815
+ sessionId: external_exports.string().min(1),
22816
+ force: external_exports.boolean().optional()
22435
22817
  }).strict();
22436
- var ContactRemovedFrameSchema = external_exports.object({
22437
- type: external_exports.literal("contact:removed"),
22438
- deviceId: external_exports.string().min(1)
22818
+ var StartDevServerResultSchema = external_exports.object({
22819
+ project: ProjectMetadataSchema
22820
+ }).strict();
22821
+ var ASSISTANT_REPORTABLE_STAGES = [
22822
+ "installing",
22823
+ "failed"
22824
+ ];
22825
+ var ReportStageArgsSchema = external_exports.object({
22826
+ sessionId: external_exports.string().min(1),
22827
+ stage: external_exports.enum(ASSISTANT_REPORTABLE_STAGES),
22828
+ /** stage='failed' 时必填的原因(一句话),其它 stage optional */
22829
+ reason: external_exports.string().optional()
22439
22830
  }).strict();
22440
- var ContactPinArgsSchema = external_exports.object({
22441
- deviceId: external_exports.string().min(1),
22442
- pinned: external_exports.boolean()
22831
+ var ReportStageResultSchema = external_exports.object({
22832
+ ok: external_exports.literal(true)
22443
22833
  }).strict();
22444
- var ContactPinOkSchema = external_exports.object({
22445
- type: external_exports.literal("contact:pin:ok"),
22446
- deviceId: external_exports.string().min(1),
22447
- pinnedAt: external_exports.number().int().nullable()
22834
+ var StopDevServerArgsSchema = external_exports.object({
22835
+ sessionId: external_exports.string().min(1)
22448
22836
  }).strict();
22449
- var ContactPinnedFrameSchema = external_exports.object({
22450
- type: external_exports.literal("contact:pinned"),
22451
- deviceId: external_exports.string().min(1),
22452
- pinnedAt: external_exports.number().int().nullable()
22837
+ var StopDevServerResultSchema = external_exports.object({
22838
+ ok: external_exports.literal(true)
22453
22839
  }).strict();
22454
-
22455
- // ../protocol/src/contact-handshake.ts
22456
- var ContactHandshakeArgsSchema = external_exports.object({
22457
- selfUrl: external_exports.string().min(1)
22458
- });
22459
- var ContactHandshakeOkSchema = external_exports.object({
22460
- type: external_exports.literal("contact:handshake:ok"),
22461
- owner: external_exports.object({
22462
- /** 被调方 deviceId(路由主键;调用方落 Contact 的主键用自己请求的 args.deviceId,此值供校验/展示) */
22463
- id: external_exports.string(),
22464
- /** 归属人(落 Contact.ownerId / provider,显示分组用) */
22465
- ownerId: external_exports.string(),
22466
- provider: external_exports.string(),
22467
- displayName: external_exports.string()
22468
- }),
22469
- /** 被调方授调用方的 grants(落 Contact.grants) */
22470
- grants: external_exports.array(GrantSchema)
22471
- });
22472
-
22473
- // ../protocol/src/contact-remote-access.ts
22474
- var ContactSetRemoteAccessArgsSchema = external_exports.object({
22475
- deviceId: external_exports.string().min(1),
22476
- remoteAccessAllowed: external_exports.boolean()
22840
+ var AppBuilderProjectUpdatedEventSchema = external_exports.object({
22841
+ type: external_exports.literal("appBuilder:project-updated"),
22842
+ project: ProjectWithStatusSchema,
22843
+ stage: ProjectStageSchema,
22844
+ /** stage='failed' 时的失败原因 */
22845
+ stageReason: external_exports.string().optional()
22477
22846
  }).strict();
22478
- var ContactSetRemoteAccessOkSchema = external_exports.object({
22479
- type: external_exports.literal("contact:setRemoteAccess:ok"),
22480
- deviceId: external_exports.string().min(1),
22481
- remoteAccessAllowed: external_exports.boolean()
22847
+ var PublishArgsSchema = external_exports.object({
22848
+ name: external_exports.string().regex(projectNameRegex)
22849
+ });
22850
+ var PublishResultSchema = external_exports.object({
22851
+ jobId: external_exports.string().min(1),
22852
+ status: external_exports.enum(["started", "already-publishing"])
22482
22853
  }).strict();
22483
- var ContactRemoteAccessUpdatedFrameSchema = external_exports.object({
22484
- type: external_exports.literal("contact:remote-access-updated"),
22485
- deviceId: external_exports.string().min(1),
22486
- remoteAccessAllowed: external_exports.boolean()
22854
+ var DismissPublishJobArgsSchema = external_exports.object({
22855
+ name: external_exports.string().regex(projectNameRegex)
22856
+ });
22857
+ var DismissPublishJobResultSchema = external_exports.object({
22858
+ ok: external_exports.literal(true)
22487
22859
  }).strict();
22488
-
22489
- // ../protocol/src/peer-exec.ts
22490
- var PeerExecRunArgsSchema = external_exports.object({
22491
- /** A 侧发起时带:目标设备 deviceId。peer-forward 转发前 strip 掉,B 侧本地执行时无此字段。 */
22492
- peerDeviceId: external_exports.string().min(1).optional(),
22493
- /** 交给对端 `bash -c` 的命令;cc 自拼完整路径(一发一收,无跨命令会话状态)。 */
22494
- command: external_exports.string().min(1),
22495
- /** 超时上限(ms);缺省用 handler 默认 30_000,clamp 300_000。 */
22496
- timeoutMs: external_exports.number().int().positive().optional()
22860
+ var AppBuilderPublishProgressEventSchema = external_exports.object({
22861
+ type: external_exports.literal("appBuilder:publish-progress"),
22862
+ name: external_exports.string().regex(projectNameRegex),
22863
+ jobId: external_exports.string().min(1),
22864
+ stage: external_exports.enum(["build", "deploy", "verify"]),
22865
+ status: external_exports.enum(["started", "completed"])
22497
22866
  }).strict();
22498
- var PeerExecRunOkSchema = external_exports.object({
22499
- type: external_exports.literal("peerExec:run:ok"),
22500
- stdout: external_exports.string(),
22501
- stderr: external_exports.string(),
22502
- /** 进程退出码;被超时 kill null。 */
22503
- exitCode: external_exports.number().int().nullable(),
22504
- timedOut: external_exports.boolean(),
22505
- stdoutTruncated: external_exports.boolean(),
22506
- stderrTruncated: external_exports.boolean()
22867
+ var AppBuilderPublishFailedEventSchema = external_exports.object({
22868
+ type: external_exports.literal("appBuilder:publish-failed"),
22869
+ name: external_exports.string().regex(projectNameRegex),
22870
+ jobId: external_exports.string().min(1),
22871
+ stage: external_exports.enum(["build", "deploy", "verify", "unknown"]),
22872
+ errorSummary: external_exports.string()
22507
22873
  }).strict();
22508
22874
 
22509
- // ../protocol/src/extension.ts
22510
- var EXT_ID_REGEX = /^[a-z0-9][a-z0-9-]*$/;
22511
- var ExtensionStateSchema = external_exports.enum([
22512
- "stopped",
22513
- "starting",
22514
- "running",
22515
- "crashed",
22516
- "invalid"
22517
- ]);
22518
- var LOCALHOST_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
22519
- function isAllowedHostedUrl(raw) {
22520
- let u;
22521
- try {
22522
- u = new URL(raw);
22523
- } catch {
22524
- return false;
22525
- }
22526
- if (u.protocol === "https:") return true;
22527
- if (u.protocol === "http:" && LOCALHOST_HOSTS.has(u.hostname)) return true;
22528
- return false;
22529
- }
22530
- var ExtensionManifestSchema = external_exports.object({
22531
- id: external_exports.string().regex(EXT_ID_REGEX),
22532
- name: external_exports.string().min(1),
22533
- version: external_exports.string().min(1),
22534
- apiVersion: external_exports.literal("1"),
22535
- runtime: external_exports.object({ startCommand: external_exports.string().min(1) }).passthrough().optional(),
22536
- entry: external_exports.object({
22537
- url: external_exports.string().url().refine(isAllowedHostedUrl, {
22538
- message: "INVALID_URL_SCHEME: only https or http://localhost is allowed"
22539
- })
22540
- }).strict().optional()
22541
- }).passthrough().superRefine((m, ctx) => {
22542
- const hasRuntime = !!m.runtime;
22543
- const hasUrl = !!m.entry?.url;
22544
- if (hasRuntime && hasUrl) {
22545
- ctx.addIssue({
22546
- code: external_exports.ZodIssueCode.custom,
22547
- message: "INVALID_MANIFEST: entry.url and runtime cannot coexist"
22548
- });
22549
- }
22550
- if (!hasRuntime && !hasUrl) {
22551
- ctx.addIssue({
22552
- code: external_exports.ZodIssueCode.custom,
22553
- message: "INVALID_MANIFEST: must have either entry.url or runtime"
22554
- });
22555
- }
22556
- });
22557
- var ExtensionTargetSchema = external_exports.discriminatedUnion("kind", [
22558
- external_exports.object({ kind: external_exports.literal("local"), port: external_exports.number().int().min(1).max(65535) }),
22559
- external_exports.object({ kind: external_exports.literal("hosted"), url: external_exports.string().url() })
22560
- ]);
22561
- var ExtensionRecordSchema = external_exports.discriminatedUnion("state", [
22562
- external_exports.object({
22563
- extId: external_exports.string(),
22564
- manifest: ExtensionManifestSchema,
22565
- state: external_exports.literal("stopped")
22566
- }),
22567
- external_exports.object({
22568
- extId: external_exports.string(),
22569
- manifest: ExtensionManifestSchema,
22570
- state: external_exports.literal("starting")
22571
- }),
22572
- external_exports.object({
22573
- extId: external_exports.string(),
22574
- manifest: ExtensionManifestSchema,
22575
- state: external_exports.literal("running"),
22576
- target: ExtensionTargetSchema
22577
- }),
22578
- external_exports.object({
22579
- extId: external_exports.string(),
22580
- manifest: ExtensionManifestSchema,
22581
- state: external_exports.literal("crashed")
22582
- }),
22583
- external_exports.object({
22584
- extId: external_exports.string(),
22585
- manifest: external_exports.unknown().nullable(),
22586
- state: external_exports.literal("invalid"),
22587
- invalidReason: external_exports.string().min(1)
22588
- })
22589
- ]);
22590
- var PublishedSnapshotSchema = external_exports.object({
22591
- snapshotHash: external_exports.string().min(1),
22592
- version: external_exports.string().min(1),
22593
- publishedAt: external_exports.number()
22594
- });
22595
- var ChannelRefSchema = external_exports.discriminatedUnion("kind", [
22596
- external_exports.object({
22597
- kind: external_exports.literal("p2p-tunnel"),
22598
- ownerPrincipalId: external_exports.string().min(1),
22599
- extId: external_exports.string().min(1)
22600
- })
22601
- ]);
22602
- var SourceRefSchema = external_exports.discriminatedUnion("kind", [
22603
- external_exports.object({
22604
- kind: external_exports.literal("p2p-tunnel"),
22605
- ownerPrincipalId: external_exports.string().min(1),
22606
- extId: external_exports.string().min(1),
22607
- snapshotHash: external_exports.string().min(1)
22608
- })
22609
- ]);
22610
- var PublishedExtensionRecordSchema = external_exports.object({
22611
- extId: external_exports.string().min(1),
22612
- name: external_exports.string().min(1),
22613
- version: external_exports.string().min(1),
22614
- contentHash: external_exports.string().min(1),
22615
- publishedAt: external_exports.number()
22616
- });
22617
- var PublishCheckSchema = external_exports.discriminatedUnion("kind", [
22618
- external_exports.object({ kind: external_exports.literal("clean") }),
22619
- external_exports.object({
22620
- kind: external_exports.literal("ready-new-version"),
22621
- fromVersion: external_exports.string().min(1),
22622
- toVersion: external_exports.string().min(1)
22623
- }),
22624
- external_exports.object({
22625
- kind: external_exports.literal("error-same-hash"),
22626
- version: external_exports.string().min(1)
22627
- }),
22628
- external_exports.object({
22629
- kind: external_exports.literal("error-version-not-bumped"),
22630
- localVersion: external_exports.string().min(1),
22631
- publishedVersion: external_exports.string().min(1)
22632
- }),
22633
- external_exports.object({
22634
- kind: external_exports.literal("error-version-regression"),
22635
- localVersion: external_exports.string().min(1),
22636
- publishedVersion: external_exports.string().min(1)
22637
- })
22638
- ]);
22639
- var PublishStatusResultSchema = external_exports.object({
22640
- localManifest: external_exports.object({
22641
- name: external_exports.string().min(1),
22642
- version: external_exports.string().min(1),
22643
- contentHash: external_exports.string().min(1)
22644
- }),
22645
- publishState: external_exports.discriminatedUnion("kind", [
22646
- external_exports.object({ kind: external_exports.literal("unpublished") }),
22647
- external_exports.object({
22648
- kind: external_exports.literal("published"),
22649
- version: external_exports.string().min(1),
22650
- contentHash: external_exports.string().min(1),
22651
- publishedAt: external_exports.number()
22652
- })
22653
- ]),
22654
- check: PublishCheckSchema
22655
- });
22656
-
22657
- // ../protocol/src/feishu-auth.ts
22658
- var DeviceEntrySchema = external_exports.object({
22659
- /**
22660
- * 设备标识(决策 #15:daemon 本地生成的 dev-<uuid>,与人的身份 unionId 无关)。
22661
- * 中心 server clawd_devices 注册表仅作服务发现(url 下发 + 目录),不在安全路径上。
22662
- */
22663
- deviceId: external_exports.string().min(1),
22664
- /** 显示名 */
22875
+ // ../protocol/src/methods.ts
22876
+ var NO_ARGS = external_exports.object({});
22877
+ var METHOD_DOCS = {
22878
+ "session:create": {
22879
+ 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",
22880
+ args: SessionCreateArgs
22881
+ },
22882
+ "session:list": {
22883
+ summary: "\u5217\u51FA\u5F53\u524D\u8EAB\u4EFD\u53EF\u89C1\u7684\u4F1A\u8BDD\uFF08owner \u5168\u91CF\uFF1Bguest \u9650\u88AB\u6388\u6743 persona\uFF09",
22884
+ args: SessionListArgs
22885
+ },
22886
+ "session:get": {
22887
+ summary: "\u53D6\u5355\u4E2A\u4F1A\u8BDD\u7684\u5B8C\u6574 SessionFile\uFF08\u5143\u6570\u636E + \u72B6\u6001\uFF09",
22888
+ args: SessionIdArgs
22889
+ },
22890
+ "session:update": {
22891
+ 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",
22892
+ args: SessionUpdateArgs
22893
+ },
22894
+ "session:delete": {
22895
+ summary: "\u5220\u4F1A\u8BDD\uFF1A\u505C\u8FDB\u7A0B + \u5220 SessionFile\uFF0C\u5E76\u8054\u52A8\u6E05\u7406\u7ED1\u5B9A\u7684 app-builder project",
22896
+ args: SessionIdArgs
22897
+ },
22898
+ "session:send": {
22899
+ summary: "\u5411\u4F1A\u8BDD\u53D1\u4E00\u6761\u7528\u6237\u6D88\u606F\uFF08\u89E6\u53D1\u65B0\u4E00\u8F6E turn\uFF09",
22900
+ args: SessionSendArgs
22901
+ },
22902
+ "session:currentTurnSender": {
22903
+ 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",
22904
+ args: SessionCurrentTurnSenderArgs
22905
+ },
22906
+ "session:stop": {
22907
+ summary: "\u505C\u6389\u4F1A\u8BDD\u7684 tool \u8FDB\u7A0B\uFF08\u6740\u8FDB\u7A0B\uFF0C\u4F1A\u8BDD\u672C\u8EAB\u4FDD\u7559\uFF09",
22908
+ args: SessionIdArgs
22909
+ },
22910
+ "session:interrupt": {
22911
+ summary: "\u6E29\u67D4\u4E2D\u65AD\u5F53\u524D\u8F6E\u6B21\uFF0C\u4E0D\u6740\u8FDB\u7A0B\uFF08\u8D70 CC IPC control_request.subtype=interrupt\uFF09",
22912
+ args: SessionInterruptArgs
22913
+ },
22914
+ "session:rewind": {
22915
+ summary: "\u56DE\u6EDA\u5230\u6307\u5B9A user message\uFF0C\u5E76\u64A4\u9500\u5176\u540E CC \u505A\u7684\u6587\u4EF6\u7F16\u8F91",
22916
+ args: SessionRewindArgs
22917
+ },
22918
+ "session:rewind-diff": {
22919
+ 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",
22920
+ args: SessionRewindDiffArgs
22921
+ },
22922
+ "session:rewindable-message-ids": {
22923
+ 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",
22924
+ args: SessionRewindableMessageIdsArgs
22925
+ },
22926
+ "session:fork": {
22927
+ 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",
22928
+ args: SessionForkArgs
22929
+ },
22930
+ "session:new": {
22931
+ 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",
22932
+ args: SessionIdArgs
22933
+ },
22934
+ "session:resume": {
22935
+ summary: "\u628A\u4F1A\u8BDD\u6062\u590D\u5230\u6307\u5B9A\u7684 tool \u4F1A\u8BDD\uFF08CC transcript\uFF09\u4E0A\u7EE7\u7EED",
22936
+ args: SessionResumeArgs
22937
+ },
22938
+ "session:observe": {
22939
+ 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",
22940
+ args: SessionObserveArgs
22941
+ },
22942
+ "session:events": {
22943
+ 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",
22944
+ args: SessionEventsArgs
22945
+ },
22946
+ "session:subscribe": {
22947
+ 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",
22948
+ args: SessionSubscribeArgs
22949
+ },
22950
+ "session:unsubscribe": {
22951
+ 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",
22952
+ args: SessionSubscribeArgs
22953
+ },
22954
+ "session:pin": {
22955
+ summary: "\u7F6E\u9876 / \u53D6\u6D88\u7F6E\u9876\u4F1A\u8BDD",
22956
+ args: SessionPinArgs
22957
+ },
22958
+ "session:markRead": {
22959
+ summary: "\u6E05\u6389\u4F1A\u8BDD\u7684\u5171\u4EAB\u672A\u8BFB\u6807\u8BB0\u5E76\u5E7F\u64AD session:info\uFF1B\u5E42\u7B49",
22960
+ args: SessionIdArgs
22961
+ },
22962
+ "session:reorderPins": {
22963
+ summary: "\u6574\u4F53\u91CD\u5199\u6240\u6709\u7F6E\u9876\u4F1A\u8BDD\u7684\u6392\u5E8F\uFF08sidebar \u62D6\u62FD\u5B8C\u6210\u65F6\u8C03\uFF09",
22964
+ args: SessionReorderPinsArgs
22965
+ },
22966
+ "peerSession:upsert": {
22967
+ 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",
22968
+ args: PeerSessionUpsertArgs
22969
+ },
22970
+ "peerSession:remove": {
22971
+ summary: "\u5220\u9664\u4E00\u6761 mirror SessionFile\uFF08\u540C\u6837\u4E0D\u5E7F\u64AD\uFF09",
22972
+ args: PeerSessionRemoveArgs
22973
+ },
22974
+ "permission:respond": {
22975
+ summary: "\u56DE\u5E94 CC \u7684\u6743\u9650\u8BF7\u6C42\uFF08\u5141\u8BB8 / \u62D2\u7EDD / \u8BB0\u4F4F\u89C4\u5219\uFF09",
22976
+ args: PermissionRespondArgs
22977
+ },
22978
+ "session:answerQuestion": {
22979
+ summary: "\u56DE\u586B AskUserQuestion \u8868\u5355\u7B54\u6848\uFF0Cdaemon \u5408\u5E76\u8FDB updated_input \u5199 control_response \u7ED9 CC",
22980
+ args: AnswerQuestionArgs
22981
+ },
22982
+ "session:cancelQuestion": {
22983
+ summary: "\u7528\u6237\u8DF3\u8FC7 AskUserQuestion\uFF1Adaemon \u56DE allow + \u7A7A\u7B54\u6848\u8BA9 tool \u8D70\u7A7A\u8DEF\u5F84\uFF0C\u5E76\u5E7F\u64AD cleared \u5E27",
22984
+ args: CancelQuestionArgs
22985
+ },
22986
+ "history:projects": {
22987
+ 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",
22988
+ args: NO_ARGS
22989
+ },
22990
+ "history:list": {
22991
+ summary: "\u5217\u51FA\u67D0\u4E2A\u9879\u76EE\u4E0B\u7684\u5386\u53F2\u4F1A\u8BDD",
22992
+ args: HistoryListArgs
22993
+ },
22994
+ "history:read": {
22995
+ summary: "\u8BFB\u4E00\u6761\u5386\u53F2\u4F1A\u8BDD\u7684\u5B8C\u6574\u6D88\u606F\uFF08\u89E3\u6790 CC jsonl\uFF09",
22996
+ args: HistoryReadArgs
22997
+ },
22998
+ "history:subagents": {
22999
+ summary: "\u5217\u51FA\u67D0\u6B21\u4F1A\u8BDD\u91CC\u7684 subagent \u8FD0\u884C\u8BB0\u5F55",
23000
+ args: HistorySubagentsArgs
23001
+ },
23002
+ "history:subagent-read": {
23003
+ summary: "\u8BFB\u4E00\u6761 subagent \u7684\u5B8C\u6574\u8BB0\u5F55",
23004
+ args: HistorySubagentReadArgs
23005
+ },
23006
+ "history:recentDirs": {
23007
+ 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",
23008
+ args: NO_ARGS
23009
+ },
23010
+ "workspace:list": {
23011
+ summary: "\u5217\u76EE\u5F55\u5185\u5BB9\uFF08\u6587\u4EF6\u6D4F\u89C8\uFF09\uFF1Bguest \u88AB\u9650\u5236\u5728\u88AB\u6388\u6743 persona \u5B50\u6811\u5185",
23012
+ args: WorkspaceListArgs
23013
+ },
23014
+ "workspace:read": {
23015
+ summary: "\u8BFB\u6587\u4EF6\u5185\u5BB9\uFF1Bguest \u8DEF\u5F84\u8FB9\u754C\u4E0E workspace:list \u540C",
23016
+ args: WorkspaceReadArgs
23017
+ },
23018
+ "shift:list": {
23019
+ summary: "\u5217\u51FA owner \u7684\u5168\u90E8 shift\uFF08\u6392\u73ED\uFF09\uFF0C\u7ED9 UI \u65E5\u5386\u6E32\u67D3\u7528\uFF1Bowner-only",
23020
+ args: NO_ARGS
23021
+ },
23022
+ "shift-internal:add": {
23023
+ 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",
23024
+ args: ShiftInternalAddArgs
23025
+ },
23026
+ "shift-internal:list": {
23027
+ summary: "\u5217 shift\u3002\u7701\u7565 onlyMine \u9ED8\u8BA4 true \u2014\u2014 \u53EA\u5217\u672C persona \u5EFA\u7684",
23028
+ args: ShiftInternalListArgs
23029
+ },
23030
+ "shift-internal:cancel": {
23031
+ summary: "\u53D6\u6D88 shift\uFF08\u4EC5\u521B\u5EFA\u5B83\u7684 persona \u53EF\u64CD\u4F5C\uFF09",
23032
+ args: ShiftInternalCancelArgs
23033
+ },
23034
+ "shift-internal:update": {
23035
+ 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",
23036
+ args: ShiftInternalUpdateArgs
23037
+ },
23038
+ "shift-internal:history": {
23039
+ summary: "\u67E5 shift \u7684\u6267\u884C\u5386\u53F2\uFF08\u4EC5\u521B\u5EFA\u8005\uFF09",
23040
+ args: ShiftInternalHistoryArgs
23041
+ },
23042
+ "skills:list": {
23043
+ summary: "\u626B\u63CF\u5E76\u5217\u51FA\u8BE5\u76EE\u5F55\u53EF\u7528\u7684 skill",
23044
+ args: SkillsListArgs
23045
+ },
23046
+ "agents:list": {
23047
+ summary: "\u626B\u63CF\u5E76\u5217\u51FA\u8BE5\u76EE\u5F55\u53EF\u7528\u7684 subagent \u5B9A\u4E49",
23048
+ args: AgentsListArgs
23049
+ },
23050
+ "git:root": {
23051
+ summary: "\u53D6\u8BE5\u8DEF\u5F84\u6240\u5C5E git \u4ED3\u5E93\u7684\u6839\u76EE\u5F55\uFF08\u4E0D\u5728\u4ED3\u5E93\u91CC\u8FD4 null\uFF09",
23052
+ args: GitRootArgs
23053
+ },
23054
+ "git:branch": {
23055
+ summary: "\u53D6\u5F53\u524D\u5206\u652F\u540D",
23056
+ args: GitBranchArgs
23057
+ },
23058
+ "git:branches": {
23059
+ summary: "\u5217\u51FA\u672C\u5730\u5206\u652F",
23060
+ args: GitBranchesArgs
23061
+ },
23062
+ "capabilities:get": {
23063
+ summary: "\u53D6\u67D0\u4E2A tool \u7684\u80FD\u529B\u96C6\uFF1A\u53EF\u7528\u6A21\u578B\u5217\u8868 / permissionModes / configSchema",
23064
+ args: CapabilitiesGetArgs
23065
+ },
23066
+ "persona:create": {
23067
+ summary: "\u65B0\u5EFA persona\uFF08\u5199 PersonaFile + CLAUDE.md \u9AA8\u67B6\uFF09\u3002owner-only",
23068
+ args: PersonaCreateArgsSchema
23069
+ },
23070
+ "persona:list": {
23071
+ 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",
23072
+ args: NO_ARGS
23073
+ },
23074
+ "persona:get": {
23075
+ 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",
23076
+ args: PersonaIdArgsSchema
23077
+ },
23078
+ "persona:update": {
23079
+ summary: "\u6539 persona\uFF08label / model / public / CLAUDE.md \u7B49\uFF09\u3002owner-only",
23080
+ args: PersonaUpdateArgsSchema
23081
+ },
23082
+ "persona:delete": {
23083
+ summary: "\u5220 persona\u3002owner-only",
23084
+ args: PersonaIdArgsSchema
23085
+ },
23086
+ "personaDispatch:run": {
23087
+ 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**",
23088
+ args: DispatchRunArgsSchema
23089
+ },
23090
+ "personaDispatch:complete": {
23091
+ 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',
23092
+ args: DispatchCompleteArgsSchema
23093
+ },
23094
+ "personaDispatch:list": {
23095
+ summary: "\u67E5 dispatch \u53F0\u8D26\uFF08\u72B6\u6001 / \u7ED3\u679C / \u65F6\u95F4\u6233\uFF09\u3002\u7701\u7565 sourceSessionId = \u8FD4\u5168\u91CF",
23096
+ args: DispatchListArgsSchema
23097
+ },
23098
+ "personaDispatch:get": {
23099
+ summary: "\u67E5\u5355\u6761 dispatch \u53F0\u8D26\u7EC8\u6001\uFF1B\u8DE8\u8BBE\u5907\u65F6 A \u7AEF\u51ED connect token \u8F6E\u8BE2 B \u7AEF\u7528",
23100
+ args: DispatchGetArgsSchema
23101
+ },
23102
+ "peerExec:run": {
23103
+ 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",
23104
+ args: PeerExecRunArgsSchema
23105
+ },
23106
+ "session:pty:input": {
23107
+ 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 }"
23108
+ },
23109
+ "session:pty:resize": {
23110
+ summary: "\u540C\u6B65\u7EC8\u7AEF\u5C3A\u5BF8\u7ED9 pty\uFF08\u4EC5 tui \u6A21\u5F0F\uFF09\u3002body: { sessionId, cols, rows }"
23111
+ },
23112
+ "session:pty:snapshot": {
23113
+ 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 }"
23114
+ },
23115
+ "attachment.signUrl": {
23116
+ summary: "\u7ED9\u5DF2\u5165\u7FA4\u7684\u6587\u4EF6\u7B7E\u53D1 HMAC \u4E0B\u8F7D URL\uFF08\u8DE8\u8BBE\u5907\u53EF\u76F4\u63A5\u6253\u5F00\uFF09",
23117
+ args: AttachmentSignUrlArgs
23118
+ },
23119
+ "attachment.groupAdd": {
23120
+ 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",
23121
+ args: AttachmentGroupAddArgs
23122
+ },
23123
+ "attachment.groupRemove": {
23124
+ summary: "\u628A\u6587\u4EF6\u79FB\u51FA\u5171\u4EAB\u6E05\u5355",
23125
+ args: AttachmentGroupRemoveArgs
23126
+ },
23127
+ "attachment.groupList": {
23128
+ summary: "\u5217\u51FA\u672C\u4F1A\u8BDD\u5171\u4EAB\u6E05\u5355\u91CC\u7684\u6587\u4EF6",
23129
+ args: AttachmentGroupListArgs
23130
+ },
23131
+ "inbox:list": {
23132
+ summary: "\u62C9\u67D0\u4E2A peer \u7684 DM / \u901A\u77E5\u961F\u5217",
23133
+ args: InboxListArgsSchema
23134
+ },
23135
+ "inbox:markRead": {
23136
+ summary: "\u628A\u67D0 peer \u961F\u5217\u6807\u8BB0\u4E3A\u5DF2\u8BFB\u5230\u67D0\u65F6\u95F4\u70B9",
23137
+ args: InboxMarkReadArgsSchema
23138
+ },
23139
+ "inbox:postMessage": {
23140
+ 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",
23141
+ args: InboxPostMessageArgsSchema
23142
+ },
23143
+ "inbox:sendDm": {
23144
+ 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",
23145
+ args: InboxSendDmArgsSchema
23146
+ },
23147
+ "contact:list": {
23148
+ summary: "\u5217\u51FA\u8054\u7CFB\u4EBA\uFF08\u5DF2\u5EFA\u8054\u7684\u8BBE\u5907\uFF09\u3002owner-only",
23149
+ args: NO_ARGS
23150
+ },
23151
+ "contact:pin": {
23152
+ summary: "\u7F6E\u9876 / \u53D6\u6D88\u7F6E\u9876\u8054\u7CFB\u4EBA",
23153
+ args: ContactPinArgsSchema
23154
+ },
23155
+ "contact:remove": {
23156
+ summary: "\u5220\u9664\u8054\u7CFB\u4EBA\u5E76\u6E05\u6389\u5BF9\u5E94\u7684 inbox \u961F\u5217",
23157
+ args: ContactRemoveArgsSchema
23158
+ },
23159
+ "contact:setRemoteAccess": {
23160
+ 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",
23161
+ args: ContactSetRemoteAccessArgsSchema
23162
+ },
23163
+ "contact:handshake": {
23164
+ 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",
23165
+ args: ContactHandshakeArgsSchema
23166
+ },
23167
+ "visitor:list": {
23168
+ summary: "\u5217\u51FA\u767B\u5F55\u8BBF\u95EE\u8FC7\u672C\u673A public persona \u7684 web \u8BBF\u5BA2\u3002owner-only",
23169
+ args: NO_ARGS
23170
+ },
23171
+ "whoami": {
23172
+ 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",
23173
+ args: NO_ARGS
23174
+ },
23175
+ "info": {
23176
+ 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",
23177
+ args: NO_ARGS
23178
+ },
23179
+ "ping": {
23180
+ summary: "\u5B58\u6D3B\u63A2\u6D4B\uFF0C\u56DE pong",
23181
+ args: NO_ARGS
23182
+ },
23183
+ "meta:methods": {
23184
+ 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",
23185
+ args: NO_ARGS
23186
+ },
23187
+ "extension.list": {
23188
+ summary: "\u5217\u51FA\u5DF2\u5B89\u88C5\u7684 extension",
23189
+ args: NO_ARGS
23190
+ },
23191
+ "extension.open": {
23192
+ summary: "\u62C9\u8D77\u67D0\u4E2A extension\uFF08local-spawn \u8D77\u8FDB\u7A0B\u5E76\u7B49 healthz\uFF09",
23193
+ args: ExtensionIdArgs
23194
+ },
23195
+ "extension.close": {
23196
+ summary: "\u5173\u6389\u67D0\u4E2A\u6B63\u5728\u8DD1\u7684 extension",
23197
+ args: ExtensionIdArgs
23198
+ },
23199
+ "extension.uninstall": {
23200
+ summary: "\u5378\u8F7D extension\uFF08\u5220\u5B89\u88C5\u76EE\u5F55\uFF09",
23201
+ args: ExtensionIdArgs
23202
+ },
23203
+ "extension.publish": {
23204
+ summary: "\u628A\u672C\u673A extension \u516C\u5F00\u5230\u5206\u4EAB\u9891\u9053\uFF0C\u4F9B\u8054\u7CFB\u4EBA\u62C9\u53D6\u3002owner-only",
23205
+ args: ExtensionPublishArgs
23206
+ },
23207
+ "extension.unpublish": {
23208
+ summary: "\u64A4\u56DE\u5DF2\u516C\u5F00\u7684 extension\u3002owner-only",
23209
+ args: ExtensionIdArgs
23210
+ },
23211
+ "extension.publish:status": {
23212
+ summary: "\u67E5\u67D0\u4E2A extension \u7684\u516C\u5F00\u72B6\u6001\u3002owner-only",
23213
+ args: ExtensionIdArgs
23214
+ },
23215
+ "extension.list-published": {
23216
+ summary: "\uFF08\u8DE8\u8BBE\u5907\uFF09\u4ECE\u5BF9\u7AEF owner \u62C9\u5B83\u516C\u5F00\u7684 extension \u6E05\u5355",
23217
+ args: NO_ARGS
23218
+ },
23219
+ "extension.fetchBundle": {
23220
+ 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",
23221
+ args: ExtensionFetchBundleArgs
23222
+ },
23223
+ "extension.install-from-channel": {
23224
+ summary: "\u5728\u81EA\u5DF1 daemon \u4E0A\u4ECE\u5206\u4EAB\u9891\u9053\u5B89\u88C5 extension",
23225
+ args: ExtensionFromChannelArgs
23226
+ },
23227
+ "extension.update-from-channel": {
23228
+ summary: "\u5728\u81EA\u5DF1 daemon \u4E0A\u628A\u5DF2\u88C5 extension \u66F4\u65B0\u5230\u9891\u9053\u6700\u65B0\u7248",
23229
+ args: ExtensionFromChannelArgs
23230
+ },
23231
+ "auth:login:start": {
23232
+ 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",
23233
+ args: NO_ARGS
23234
+ },
23235
+ "auth:getIdentity": {
23236
+ 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",
23237
+ args: NO_ARGS
23238
+ },
23239
+ "auth:logout": {
23240
+ summary: "\u767B\u51FA\u98DE\u4E66\u8EAB\u4EFD\uFF08\u6E05 owner-identity \u843D\u76D8\uFF09\u3002owner-only",
23241
+ args: NO_ARGS
23242
+ },
23243
+ "device:list": {
23244
+ 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",
23245
+ args: NO_ARGS
23246
+ },
23247
+ "device:connect": {
23248
+ summary: "\u8FDE\u63A5\u76EE\u6807\u8BBE\u5907\uFF1A\u6362 aud \u7ED1\u5B9A\u7684\u7B7E\u540D token \u5E76\u8D70 contact:handshake \u5EFA\u8054\u3002owner-only",
23249
+ args: DeviceConnectArgsSchema
23250
+ },
23251
+ "appBuilder:listProjects": {
23252
+ summary: "\u5217\u51FA app-builder project\uFF08\u542B dev server \u72B6\u6001\uFF09",
23253
+ args: ListProjectsArgsSchema
23254
+ },
23255
+ "appBuilder:getProject": {
23256
+ summary: "\u6309 sessionId \u53D6\u5355\u4E2A\u7ED1\u5B9A\u7684 project\uFF08\u542B status\uFF09",
23257
+ args: GetProjectArgsSchema
23258
+ },
23259
+ "appBuilder:createProject": {
23260
+ 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",
23261
+ args: CreateProjectArgsSchema
23262
+ },
23263
+ "appBuilder:deleteProject": {
23264
+ summary: "\u505C dev server + \u5220 project \u76EE\u5F55\uFF08\u7ED1\u5B9A\u7684\u4F1A\u8BDD\u4E0D\u5728\u8FD9\u91CC\u5220\uFF09",
23265
+ args: DeleteProjectArgsSchema
23266
+ },
23267
+ "appBuilder:updateProjectPort": {
23268
+ summary: "\u6539 dev server \u7AEF\u53E3\uFF08\u6821\u9A8C\u6BB5\u5185 + \u4E0D\u649E\u8F66\uFF09\u5E76\u91CD\u542F",
23269
+ args: UpdateProjectPortArgsSchema
23270
+ },
23271
+ "appBuilder:setProdUrl": {
23272
+ summary: "\u53D1\u5E03\u4E0A\u7EBF\u540E\u56DE\u586B\u7EBF\u4E0A\u5730\u5740\u5230 .clawd-project.json",
23273
+ args: SetProdUrlArgsSchema
23274
+ },
23275
+ "appBuilder:startDevServer": {
23276
+ summary: "scaffold + \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210\u540E\u663E\u5F0F\u62C9\u8D77 dev server\uFF08createProject \u4E0D\u518D\u81EA\u52A8\u8D77\uFF09",
23277
+ args: StartDevServerArgsSchema
23278
+ },
23279
+ "appBuilder:reportStage": {
23280
+ summary: "\u4E0A\u62A5\u811A\u624B\u67B6\u9636\u6BB5\uFF08scaffolding / installing / failed \u7B49\uFF09\uFF0Cdaemon \u5E7F\u64AD\u5E27\u8BA9 UI \u5207 PreviewPane",
23281
+ args: ReportStageArgsSchema
23282
+ },
23283
+ "appBuilder:stopDevServer": {
23284
+ summary: "\u6536\u8D77\u9884\u89C8\uFF1A\u505C\u6389 dev server\uFF08\u5BF9\u79F0 startDevServer\uFF09",
23285
+ args: StopDevServerArgsSchema
23286
+ },
23287
+ "appBuilder:publish": {
23288
+ 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",
23289
+ args: PublishArgsSchema
23290
+ },
23291
+ "appBuilder:dismissPublishJob": {
23292
+ 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",
23293
+ args: DismissPublishJobArgsSchema
23294
+ }
23295
+ };
23296
+ var METHOD_NAMES = Object.keys(METHOD_DOCS);
23297
+ var RPC_METHOD_STATUSES = ["allowed", "conditional", "denied"];
23298
+ var RpcMethodStatusSchema = external_exports.enum(RPC_METHOD_STATUSES);
23299
+ var RpcMethodInfoSchema = external_exports.object({
23300
+ /** canonical method 名,直接可作为 clawd-rpc call 的 method 参数 */
22665
23301
  name: external_exports.string().min(1),
22666
- /** ws/tunnel 地址 */
22667
- url: external_exports.string().min(1)
22668
- });
22669
- var DeviceListResponseSchema = external_exports.object({
22670
- type: external_exports.literal("device:list:ok"),
22671
- devices: external_exports.array(DeviceEntrySchema)
22672
- });
22673
- var DeviceConnectArgsSchema = external_exports.object({
22674
- /** 目标设备的 deviceId(对方 daemon 生成的 dev-<uuid>) */
22675
- deviceId: external_exports.string().min(1),
23302
+ status: RpcMethodStatusSchema,
23303
+ /** 该 method 干什么,取自 {@link METHOD_DOCS} 的 summary */
23304
+ description: external_exports.string().min(1),
22676
23305
  /**
22677
- * 目标设备的 ws/tunnel 地址(可选):
22678
- * - 公开目录点击:带 url(device:list 已下发,省一次 server 查询)
22679
- * - 凭 deviceId 连接:缺省 url → daemon exchange 时由中心 server 下发该设备上报的 url
22680
- * - 注册表不在安全路径上:知道对方 url 时显式传入即可连接(不依赖中心 server 服务发现)
23306
+ * 参数字段,从 {@link METHOD_DOCS} 的 args schema **反射**得来(不手写)。
23307
+ * `null` = method 还没有中央 zod schema(欠账,见 RpcMethodDoc),调用方需自行试探。
22681
23308
  */
22682
- url: external_exports.string().min(1).optional(),
22683
- /** 显示名(公共设备来自目录;缺省时连上后用 whoami 回填) */
22684
- name: external_exports.string().optional()
22685
- });
22686
- var DeviceConnectResponseSchema = external_exports.object({
22687
- type: external_exports.literal("device:connect:ok"),
22688
- /** 连接的目标设备标识(= 请求 args.deviceId) */
22689
- deviceId: external_exports.string(),
22690
- name: external_exports.string(),
22691
- url: external_exports.string()
22692
- });
22693
- var FeishuIdentitySchema = external_exports.object({
22694
- /** 归属人 id(决策 #16:TTC unique_id,取代飞书 union_id;跨登录方式稳定) */
22695
- ownerId: external_exports.string().min(1),
22696
- /** 身份来源:'ttc'(飞书/手机/邮箱登入 TTC)| 'google' | ...(决策 #16,拓展用) */
22697
- provider: external_exports.string().min(1),
22698
- /** 显示名。TTC user_info 接口 data.name */
22699
- displayName: external_exports.string().min(1),
22700
- /** TTC user_info 接口 data.avatar_url,可缺省 */
22701
- avatarUrl: external_exports.string().optional(),
22702
- /** TTC user_info 接口 data.union_id(飞书 union_id;dataclaw 可信入口 X-User-UnionId 用),可缺省 */
22703
- unionId: external_exports.string().optional()
22704
- });
22705
- var AuthLoginStartResponseSchema = external_exports.object({
22706
- type: external_exports.literal("auth:login:start:ok"),
22707
- /** 完整 TTC 授权页 URL(含 callback_url + state + auto=1),UI 直接 window.open */
22708
- authUrl: external_exports.string().min(1),
22709
- /** 防 CSRF 的一次性 nonce;回调时 daemon 校验 */
22710
- state: external_exports.string().min(1)
22711
- });
22712
- var AuthGetIdentityResponseSchema = external_exports.object({
22713
- type: external_exports.literal("auth:getIdentity:ok"),
22714
- /** null = 未登录 */
22715
- identity: FeishuIdentitySchema.nullable(),
23309
+ args: external_exports.array(external_exports.object({ name: external_exports.string(), required: external_exports.boolean() })).nullable(),
22716
23310
  /**
22717
- * 本机设备标识(决策 #15:daemon 生成并持久化在 auth.json,如 dev-<uuid>)。
22718
- * 设备属性,与登录态无关、登录登出不变。UI"我的设备标识"用它拼
22719
- * clawos://device/<deviceId>(替代旧的 unionId——不再向外暴露人的身份标识)。
23311
+ * `denied` 必带:daemon error code(`UNAUTHORIZED` / `FEISHU_LOGIN_REQUIRED` /
23312
+ * `METHOD_NOT_IMPLEMENTED`)。`conditional` 必带:谁来做二次校验。
23313
+ * `allowed` 恒无。
22720
23314
  */
22721
- deviceId: external_exports.string().min(1)
22722
- });
22723
- var AuthLogoutResponseSchema = external_exports.object({
22724
- type: external_exports.literal("auth:logout:ok")
22725
- });
22726
- var AuthLoginDoneEventSchema = external_exports.object({
22727
- type: external_exports.literal("auth:login:done"),
22728
- identity: FeishuIdentitySchema
22729
- });
22730
- var AuthLoginFailedEventSchema = external_exports.object({
22731
- type: external_exports.literal("auth:login:failed"),
22732
- reason: external_exports.string()
22733
- });
22734
-
22735
- // ../protocol/src/dispatch.ts
22736
- var DispatchOutcomeSchema = external_exports.discriminatedUnion("kind", [
22737
- external_exports.object({
22738
- kind: external_exports.literal("success"),
22739
- text: external_exports.string(),
22740
- filePaths: external_exports.array(external_exports.string()).optional()
22741
- }),
22742
- external_exports.object({
22743
- kind: external_exports.literal("failure"),
22744
- reason: external_exports.string()
22745
- })
22746
- ]);
22747
- var DispatchRunArgsSchema = external_exports.object({
22748
- // 新开必填;续派(dispatchId 非空)时可省略——targetPersonaId 从台账行取。
22749
- targetPersona: external_exports.string().min(1).optional(),
22750
- // 续派(spec 2026-07-21,单 dispatchId 语义:一件事一行一 id):非空 = 把 prompt
22751
- // 作为新 turn 打进该 dispatch 的原 worker session 接着干(台账行复位 running)。
22752
- // 省略 = 新开一件事,daemon 铸新 id。
22753
- dispatchId: external_exports.string().min(1).optional(),
22754
- prompt: external_exports.string(),
22755
- // 跨设备 dispatch:非空 = A 角色,转发到该 contact deviceId 的 peer daemon;
22756
- // 省略 = 本地 dispatch / B 角色本地执行。A 转发给 B 时 body 不带此字段。
22757
- targetDeviceId: external_exports.string().min(1).optional(),
22758
- // 可选:override B session 使用的 claude 模型。缺省 = 用 persona 默认。
22759
- // 合法值集与 claude adapter capabilities.models[].id 一致(见 daemon
22760
- // tools/claude.ts CLAUDE_MODEL_IDS);handler 层做二次校验,非法值 fail-fast。
22761
- // protocol 层保持 string 便于未来跨 tool 扩展(届时 union 收合法字面量)。
22762
- model: external_exports.string().min(1).optional(),
22763
- // 可选:给新 worker session 起 label(写入 SessionFile.label,sidebar 显示)。
22764
- // 仅在**新开 dispatch**(dispatchId 缺席)时生效;续派(dispatchId 非空)
22765
- // 时 daemon 层静默丢弃(避免半途改 label 造成 sidebar 抖动)。
22766
- // 上限 60 字符——sidebar 显示 tolerance,卡在 dispatch 入口即可。
22767
- // 协议层不硬拒 sessionLabel + dispatchId 同传,保留 forward-compat。
22768
- sessionLabel: external_exports.string().min(1).max(60).optional()
22769
- }).refine((v) => v.targetPersona !== void 0 || v.dispatchId !== void 0, {
22770
- message: "either targetPersona (new dispatch) or dispatchId (follow-up) is required"
22771
- }).refine((v) => !(v.dispatchId !== void 0 && v.targetDeviceId !== void 0), {
22772
- message: "cross-device dispatch cannot be continued (dispatchId + targetDeviceId are mutually exclusive)"
22773
- });
22774
- var DispatchCompleteArgsSchema = external_exports.object({
22775
- dispatchId: external_exports.string().min(1),
22776
- outcome: DispatchOutcomeSchema
22777
- });
22778
- var DISPATCH_STATUSES = ["running", "completed", "failed"];
22779
- var DispatchStatusSchema = external_exports.enum(DISPATCH_STATUSES);
22780
- var DispatchRecordSchema = external_exports.object({
22781
- dispatchId: external_exports.string().min(1),
22782
- sourceSessionId: external_exports.string().min(1),
22783
- sourcePersonaId: external_exports.string().min(1).optional(),
22784
- targetPersonaId: external_exports.string().min(1),
22785
- /** B 的 sessionId;registerBSession 后回填 */
22786
- workerSessionId: external_exports.string().min(1).optional(),
22787
- /** 任务摘要;截断(≤500 字符)在 daemon store.add 处保证 */
22788
- taskText: external_exports.string(),
22789
- status: DispatchStatusSchema,
22790
- outcome: DispatchOutcomeSchema.optional(),
22791
- /** 上层消费者语义(如司礼监的口谕/验收状态),daemon 不解释 */
22792
- meta: external_exports.record(external_exports.unknown()).optional(),
22793
- createdAt: external_exports.string().min(1),
22794
- completedAt: external_exports.string().min(1).optional(),
22795
- /** 结果注入 source session 成功时戳,兼当投递 dedup 标记 */
22796
- deliveredAt: external_exports.string().min(1).optional()
22797
- });
22798
- var DispatchListArgsSchema = external_exports.object({
22799
- sourceSessionId: external_exports.string().min(1).optional()
22800
- });
22801
- var DispatchListResultSchema = external_exports.object({
22802
- records: external_exports.array(DispatchRecordSchema)
22803
- });
22804
- var DispatchGetArgsSchema = external_exports.object({
22805
- dispatchId: external_exports.string().min(1)
23315
+ reason: external_exports.string().optional()
22806
23316
  });
22807
- var DispatchGetOkSchema = external_exports.object({
22808
- type: external_exports.literal("personaDispatch:get:ok"),
22809
- status: DispatchStatusSchema,
22810
- outcome: DispatchOutcomeSchema.optional()
23317
+ var MetaMethodsResultSchema = external_exports.object({
23318
+ type: external_exports.literal("meta:methods"),
23319
+ /** METHOD_NAMES 全集,顺序与之一致 */
23320
+ methods: external_exports.array(RpcMethodInfoSchema)
22811
23321
  });
22812
23322
 
22813
23323
  // ../protocol/src/log.ts