@clawos-dev/clawd 0.2.220-beta.431.c9364d8 → 0.2.221-beta.432.4424967
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs
CHANGED
|
@@ -45,6 +45,9 @@ var init_methods = __esm({
|
|
|
45
45
|
"session:update",
|
|
46
46
|
"session:delete",
|
|
47
47
|
"session:send",
|
|
48
|
+
// per-turn sender 2026-07-08 spec §4.6:MCP servers (ticket / inbox ...) 走 HTTP RPC
|
|
49
|
+
// /api/rpc/session.currentTurnSender 拉当前 turn caller;WS handler 同名(loopback path 复用)
|
|
50
|
+
"session:currentTurnSender",
|
|
48
51
|
"session:stop",
|
|
49
52
|
// 温柔中断当前轮次,不杀进程(走 CC IPC control_request.subtype=interrupt)
|
|
50
53
|
"session:interrupt",
|
|
@@ -4520,6 +4523,59 @@ var init_attachment_schemas = __esm({
|
|
|
4520
4523
|
}
|
|
4521
4524
|
});
|
|
4522
4525
|
|
|
4526
|
+
// ../protocol/src/principal.ts
|
|
4527
|
+
function makeOwnerPrincipal(id, displayName, feishuUnionId) {
|
|
4528
|
+
return PrincipalSchema.parse({
|
|
4529
|
+
id,
|
|
4530
|
+
kind: "owner",
|
|
4531
|
+
displayName,
|
|
4532
|
+
...feishuUnionId ? { feishuUnionId } : {}
|
|
4533
|
+
});
|
|
4534
|
+
}
|
|
4535
|
+
function principalToSender(p2) {
|
|
4536
|
+
return {
|
|
4537
|
+
did: p2.id,
|
|
4538
|
+
displayName: p2.displayName,
|
|
4539
|
+
principal: p2.kind,
|
|
4540
|
+
...p2.feishuUnionId ? { feishuUnionId: p2.feishuUnionId } : {}
|
|
4541
|
+
};
|
|
4542
|
+
}
|
|
4543
|
+
function makeGuestSender(did, displayName, feishuUnionId) {
|
|
4544
|
+
return SenderInfoSchema.parse({
|
|
4545
|
+
did,
|
|
4546
|
+
displayName,
|
|
4547
|
+
principal: "guest",
|
|
4548
|
+
...feishuUnionId ? { feishuUnionId } : {}
|
|
4549
|
+
});
|
|
4550
|
+
}
|
|
4551
|
+
var PrincipalKindSchema, PrincipalSchema, SenderInfoSchema;
|
|
4552
|
+
var init_principal = __esm({
|
|
4553
|
+
"../protocol/src/principal.ts"() {
|
|
4554
|
+
"use strict";
|
|
4555
|
+
init_zod();
|
|
4556
|
+
PrincipalKindSchema = external_exports.enum(["owner", "guest"]);
|
|
4557
|
+
PrincipalSchema = external_exports.object({
|
|
4558
|
+
id: external_exports.string().min(1),
|
|
4559
|
+
kind: PrincipalKindSchema,
|
|
4560
|
+
displayName: external_exports.string(),
|
|
4561
|
+
/**
|
|
4562
|
+
* 飞书 union_id。owner: 本机 daemon 已飞书登录时透传自 owner-identity.json;未登录 undefined。
|
|
4563
|
+
* guest: v1 保持 undefined(connect token 当前不携带 unionId;未来若签名 payload 加字段可透传)。
|
|
4564
|
+
* 消费方(如 ticket MCP / 未来别的飞书身份挂钩场景)按 undefined 决定是否降级;本层不做 fallback。
|
|
4565
|
+
*/
|
|
4566
|
+
feishuUnionId: external_exports.string().optional()
|
|
4567
|
+
}).strict();
|
|
4568
|
+
SenderInfoSchema = external_exports.object({
|
|
4569
|
+
/** = principal.id = deviceId(决策 #16)。稳定路由 id */
|
|
4570
|
+
did: external_exports.string().min(1),
|
|
4571
|
+
displayName: external_exports.string(),
|
|
4572
|
+
/** owner 未登录 / guest 无飞书身份时缺省。消费方各自决定是否降级 */
|
|
4573
|
+
feishuUnionId: external_exports.string().optional(),
|
|
4574
|
+
principal: PrincipalKindSchema
|
|
4575
|
+
}).strict();
|
|
4576
|
+
}
|
|
4577
|
+
});
|
|
4578
|
+
|
|
4523
4579
|
// ../protocol/src/persona-schemas.ts
|
|
4524
4580
|
var PersonaFileSchema, PersonaSkillSummarySchema, PersonaPluginSummarySchema, PersonaSandboxSettingsSchema, PersonaInfoResponseSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema, CodexSandboxSettingsSchema;
|
|
4525
4581
|
var init_persona_schemas = __esm({
|
|
@@ -4628,6 +4684,7 @@ var init_schemas = __esm({
|
|
|
4628
4684
|
init_zod();
|
|
4629
4685
|
init_events();
|
|
4630
4686
|
init_attachment_schemas();
|
|
4687
|
+
init_principal();
|
|
4631
4688
|
init_persona_schemas();
|
|
4632
4689
|
SessionStatusSchema = external_exports.enum(SESSION_STATUS_VALUES);
|
|
4633
4690
|
UsageSchema = external_exports.object({
|
|
@@ -4894,13 +4951,18 @@ var init_schemas = __esm({
|
|
|
4894
4951
|
// 真实用户输入:daemon 通过 --replay-user-messages 拿到 stdin 回显,区分于 assistant text。
|
|
4895
4952
|
// meta 非空表示是 CC 注入的系统消息(task-notification / slash-command / system-reminder 等),
|
|
4896
4953
|
// UI 据此走低视觉权重渲染或子 agent 通知卡。
|
|
4954
|
+
//
|
|
4955
|
+
// sender(2026-07-08 spec §4.1):daemon 'send' 命令 synth 的 user_text 携带发起人 SenderInfo;
|
|
4956
|
+
// observer 回灌路径(cc jsonl)永远不带 —— cc 自己写盘不知道 daemon 层身份。
|
|
4957
|
+
// UI 端 sender 缺省 → 不渲染 displayName label;有 → 气泡下方渲染。
|
|
4897
4958
|
external_exports.object({
|
|
4898
4959
|
...ParsedEventBase,
|
|
4899
4960
|
kind: external_exports.literal("user_text"),
|
|
4900
4961
|
text: external_exports.string(),
|
|
4901
4962
|
meta: HistoryUserMetaSchema.optional(),
|
|
4902
4963
|
taskId: external_exports.string().optional(),
|
|
4903
|
-
parentToolUseId: external_exports.string().optional()
|
|
4964
|
+
parentToolUseId: external_exports.string().optional(),
|
|
4965
|
+
sender: SenderInfoSchema.optional()
|
|
4904
4966
|
}),
|
|
4905
4967
|
external_exports.object({
|
|
4906
4968
|
...ParsedEventBase,
|
|
@@ -5509,24 +5571,6 @@ var init_persona_mode = __esm({
|
|
|
5509
5571
|
}
|
|
5510
5572
|
});
|
|
5511
5573
|
|
|
5512
|
-
// ../protocol/src/principal.ts
|
|
5513
|
-
function makeOwnerPrincipal(id, displayName) {
|
|
5514
|
-
return PrincipalSchema.parse({ id, kind: "owner", displayName });
|
|
5515
|
-
}
|
|
5516
|
-
var PrincipalKindSchema, PrincipalSchema;
|
|
5517
|
-
var init_principal = __esm({
|
|
5518
|
-
"../protocol/src/principal.ts"() {
|
|
5519
|
-
"use strict";
|
|
5520
|
-
init_zod();
|
|
5521
|
-
PrincipalKindSchema = external_exports.enum(["owner", "guest"]);
|
|
5522
|
-
PrincipalSchema = external_exports.object({
|
|
5523
|
-
id: external_exports.string().min(1),
|
|
5524
|
-
kind: PrincipalKindSchema,
|
|
5525
|
-
displayName: external_exports.string()
|
|
5526
|
-
}).strict();
|
|
5527
|
-
}
|
|
5528
|
-
});
|
|
5529
|
-
|
|
5530
5574
|
// ../protocol/src/capability.ts
|
|
5531
5575
|
function stripSecretHash(cap) {
|
|
5532
5576
|
const { secretHash: _hash, ...wire } = cap;
|
|
@@ -41858,7 +41902,9 @@ function cloneState(s) {
|
|
|
41858
41902
|
// ReadyGate v2:readyForSend 是基础类型直接复制;pendingSend 必须浅拷贝防止
|
|
41859
41903
|
// reduce 内 push/shift 在调用方原 state 上副作用(reducer 纯函数契约)
|
|
41860
41904
|
readyForSend: s.readyForSend,
|
|
41861
|
-
pendingSend: s.pendingSend.slice()
|
|
41905
|
+
pendingSend: s.pendingSend.slice(),
|
|
41906
|
+
// per-turn sender (spec §4.3):SenderInfo 只在 case 'send' 覆盖,其它 kind 直接复用引用
|
|
41907
|
+
currentTurnSender: s.currentTurnSender
|
|
41862
41908
|
};
|
|
41863
41909
|
}
|
|
41864
41910
|
var IDLE_KILL_DELAY_MS = 6e5;
|
|
@@ -42197,10 +42243,12 @@ function applyCommand(state, command, deps) {
|
|
|
42197
42243
|
}
|
|
42198
42244
|
});
|
|
42199
42245
|
}
|
|
42246
|
+
next.currentTurnSender = command.senderPrincipal;
|
|
42200
42247
|
const userEvent = {
|
|
42201
42248
|
kind: "user_text",
|
|
42202
42249
|
text: command.text,
|
|
42203
|
-
uuid: deps.genUuid?.()
|
|
42250
|
+
uuid: deps.genUuid?.(),
|
|
42251
|
+
sender: command.senderPrincipal
|
|
42204
42252
|
};
|
|
42205
42253
|
const pushed = pushEventToBuffer(next, userEvent, deps);
|
|
42206
42254
|
effects.push(...pushed.effects);
|
|
@@ -43267,7 +43315,9 @@ function makeInitialState(file, subSessionMeta) {
|
|
|
43267
43315
|
// ReadyGate v2:默认值兼容 SDK happy path(直写 stdin,不走队列)。
|
|
43268
43316
|
// TUI 模式由 reducer send 分支按 deps.mode='tui' 主动翻 readyForSend=false
|
|
43269
43317
|
readyForSend: true,
|
|
43270
|
-
pendingSend: []
|
|
43318
|
+
pendingSend: [],
|
|
43319
|
+
// per-turn sender 2026-07-08 spec §4.3:初始 null;case 'send' 首次覆盖
|
|
43320
|
+
currentTurnSender: null
|
|
43271
43321
|
};
|
|
43272
43322
|
}
|
|
43273
43323
|
var SessionManager = class {
|
|
@@ -43940,7 +43990,7 @@ var SessionManager = class {
|
|
|
43940
43990
|
]
|
|
43941
43991
|
};
|
|
43942
43992
|
}
|
|
43943
|
-
send(args) {
|
|
43993
|
+
send(args, senderPrincipal) {
|
|
43944
43994
|
const existing = this.getFile(args.sessionId);
|
|
43945
43995
|
let runner = this.runners.get(args.sessionId);
|
|
43946
43996
|
if (!runner) {
|
|
@@ -43948,10 +43998,22 @@ var SessionManager = class {
|
|
|
43948
43998
|
this.runners.set(args.sessionId, runner);
|
|
43949
43999
|
}
|
|
43950
44000
|
const { broadcast } = this.withCollector(() => {
|
|
43951
|
-
runner.input({
|
|
44001
|
+
runner.input({
|
|
44002
|
+
kind: "command",
|
|
44003
|
+
command: { kind: "send", text: args.text, senderPrincipal }
|
|
44004
|
+
});
|
|
43952
44005
|
});
|
|
43953
44006
|
return { response: { ok: true }, broadcast };
|
|
43954
44007
|
}
|
|
44008
|
+
/**
|
|
44009
|
+
* 只读拿 SessionState;session 不存在返 null(不 throw)。
|
|
44010
|
+
* handlers/session.ts:currentTurnSender 用(loopback HTTP RPC 绝对不能因不存在的 sid 崩)。
|
|
44011
|
+
* 2026-07-08 spec §4.6。
|
|
44012
|
+
*/
|
|
44013
|
+
tryGetState(sessionId) {
|
|
44014
|
+
const runner = this.runners.get(sessionId);
|
|
44015
|
+
return runner?.getState() ?? null;
|
|
44016
|
+
}
|
|
43955
44017
|
// 等子进程真退出再 ack。reducer 推 SIGKILL effect(见 reducer.ts),内核立即回收子进程,
|
|
43956
44018
|
// proc.on('exit') 几乎瞬时触发;waitUntilStopped 的 3s 超时只在子进程已是 zombie 或
|
|
43957
44019
|
// 极端 OS 异常时才会用上。这样修掉了"前端 sessionStop 还没等 CC 退就去删 worktree
|
|
@@ -44351,7 +44413,10 @@ var SessionManager = class {
|
|
|
44351
44413
|
}
|
|
44352
44414
|
const runner = this.ensureRunnerForScope(file, args.scope);
|
|
44353
44415
|
const { broadcast } = this.withCollector(() => {
|
|
44354
|
-
runner.input({
|
|
44416
|
+
runner.input({
|
|
44417
|
+
kind: "command",
|
|
44418
|
+
command: { kind: "send", text: args.text, senderPrincipal: args.senderPrincipal }
|
|
44419
|
+
});
|
|
44355
44420
|
});
|
|
44356
44421
|
return { response: { ok: true }, broadcast };
|
|
44357
44422
|
}
|
|
@@ -44495,7 +44560,27 @@ var SessionManager = class {
|
|
|
44495
44560
|
sourceJsonlPath: args.sourceJsonlPath,
|
|
44496
44561
|
dispatchId: args.dispatchId
|
|
44497
44562
|
});
|
|
44498
|
-
|
|
44563
|
+
let dispatchSender;
|
|
44564
|
+
if (args.guestPrincipalId) {
|
|
44565
|
+
dispatchSender = makeGuestSender(args.guestPrincipalId, args.guestDisplayName ?? args.guestPrincipalId);
|
|
44566
|
+
} else {
|
|
44567
|
+
if (!this.deps.ownerPrincipalId) {
|
|
44568
|
+
throw new Error(
|
|
44569
|
+
"createDispatchedSession requires ManagerDeps.ownerPrincipalId to build owner sender"
|
|
44570
|
+
);
|
|
44571
|
+
}
|
|
44572
|
+
dispatchSender = principalToSender(
|
|
44573
|
+
makeOwnerPrincipal(
|
|
44574
|
+
this.deps.ownerPrincipalId,
|
|
44575
|
+
this.deps.ownerDisplayName ?? "Owner",
|
|
44576
|
+
this.deps.ownerFeishuUnionId
|
|
44577
|
+
)
|
|
44578
|
+
);
|
|
44579
|
+
}
|
|
44580
|
+
runner.input({
|
|
44581
|
+
kind: "command",
|
|
44582
|
+
command: { kind: "send", text: taskPack, senderPrincipal: dispatchSender }
|
|
44583
|
+
});
|
|
44499
44584
|
this.deps.logger?.info("dispatch.createDispatchedSession.task-pack-sent", {
|
|
44500
44585
|
dispatchId: args.dispatchId,
|
|
44501
44586
|
bSessionId: sessionId
|
|
@@ -44570,6 +44655,18 @@ var SessionManager = class {
|
|
|
44570
44655
|
);
|
|
44571
44656
|
const runner = this.ensureRunnerForScope(file, scope);
|
|
44572
44657
|
this.deps.logger?.info("shift.createShiftSession.runner-ready", { sessionId });
|
|
44658
|
+
if (!this.deps.ownerPrincipalId) {
|
|
44659
|
+
throw new Error(
|
|
44660
|
+
"createShiftSession requires ManagerDeps.ownerPrincipalId to build owner sender"
|
|
44661
|
+
);
|
|
44662
|
+
}
|
|
44663
|
+
const shiftSender = principalToSender(
|
|
44664
|
+
makeOwnerPrincipal(
|
|
44665
|
+
this.deps.ownerPrincipalId,
|
|
44666
|
+
this.deps.ownerDisplayName ?? "Owner",
|
|
44667
|
+
this.deps.ownerFeishuUnionId
|
|
44668
|
+
)
|
|
44669
|
+
);
|
|
44573
44670
|
runner.input({
|
|
44574
44671
|
kind: "command",
|
|
44575
44672
|
command: {
|
|
@@ -44577,7 +44674,8 @@ var SessionManager = class {
|
|
|
44577
44674
|
text: wrapShiftFirePrompt({
|
|
44578
44675
|
prompt: args.prompt,
|
|
44579
44676
|
targetPersona: args.targetPersona
|
|
44580
|
-
})
|
|
44677
|
+
}),
|
|
44678
|
+
senderPrincipal: shiftSender
|
|
44581
44679
|
}
|
|
44582
44680
|
});
|
|
44583
44681
|
return { sessionId, ended, kill: killImpl };
|
|
@@ -48090,7 +48188,7 @@ function ticketMcpConfigPath(dataDir) {
|
|
|
48090
48188
|
function writeTicketMcpConfig(args) {
|
|
48091
48189
|
const cfgPath = ticketMcpConfigPath(args.dataDir);
|
|
48092
48190
|
const content = {
|
|
48093
|
-
_comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002ticket-mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\uFF0CHTTP client \u8C03 clawos api /api/tickets/*\u3002env \u542B api url\u3001\u5199\u6B7B API key\
|
|
48191
|
+
_comment: "daemon \u542F\u52A8\u65F6\u81EA\u52A8\u751F\u6210\uFF1Bcc spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002ticket-mcp-server.cjs \u662F daemon \u81EA\u5E26\u7684 stdio MCP server\uFF0CHTTP client \u8C03 clawos api /api/tickets/*\u3002env \u542B api url\u3001\u5199\u6B7B API key\u3001scene\uFF1Bdid/name \u6BCF\u6B21 tool call \u8D70 CLAWD_DAEMON_URL + CLAWD_SESSION_ID (cc \u5DF2\u6CE8) fetch /api/rpc/session.currentTurnSender \u62FF\u5F53\u524D turn caller (2026-07-08 spec \xA74.7)\u3002CLAWD_TICKET_LOG \u6307 server \u5199\u65E5\u5FD7\u7684 append \u6587\u4EF6\u8DEF\u5F84\u3002cc \u573A\u666F scene \u56FA\u5B9A persona\u3002",
|
|
48094
48192
|
mcpServers: {
|
|
48095
48193
|
"clawd-ticket": {
|
|
48096
48194
|
type: "stdio",
|
|
@@ -48099,8 +48197,6 @@ function writeTicketMcpConfig(args) {
|
|
|
48099
48197
|
env: {
|
|
48100
48198
|
CLAWD_TICKET_API_URL: args.apiBaseUrl,
|
|
48101
48199
|
CLAWD_TICKET_API_KEY: args.apiKey,
|
|
48102
|
-
CLAWD_TICKET_DID: args.did,
|
|
48103
|
-
CLAWD_TICKET_NAME: args.name,
|
|
48104
48200
|
CLAWD_TICKET_SCENE: "persona",
|
|
48105
48201
|
...args.logPath ? { CLAWD_TICKET_LOG: args.logPath } : {}
|
|
48106
48202
|
}
|
|
@@ -50211,7 +50307,12 @@ var EXPOSED_RPC_METHODS = [
|
|
|
50211
50307
|
"attachment.groupAdd",
|
|
50212
50308
|
"attachment.signUrl",
|
|
50213
50309
|
// persona 受控发 P2P IM DM(sender 由 session scope 推,driver 分级授权见 handlers/inbox.ts)
|
|
50214
|
-
"inbox.sendDm"
|
|
50310
|
+
"inbox.sendDm",
|
|
50311
|
+
// per-turn sender 2026-07-08 spec §4.1:MCP servers (ticket / inbox / ...) 每 tool call
|
|
50312
|
+
// 查当前 turn caller —— cc 长驻 + owner/guest 交替驱动同一 session 时不能靠启动时 env
|
|
50313
|
+
// 写死身份,必须运行时 fetch。header X-Clawd-Session-Id 作 session 定位,handler 内查
|
|
50314
|
+
// manager.tryGetState(sid).currentTurnSender 返 SenderInfo | null。
|
|
50315
|
+
"session.currentTurnSender"
|
|
50215
50316
|
];
|
|
50216
50317
|
async function handleRpcRequest(input) {
|
|
50217
50318
|
const { method, body, sessionId, dispatcher } = input;
|
|
@@ -50396,9 +50497,9 @@ function constantTimeEqual2(a, b2) {
|
|
|
50396
50497
|
}
|
|
50397
50498
|
|
|
50398
50499
|
// src/transport/connection-context.ts
|
|
50399
|
-
function ownerContext(ownerPrincipalId, displayName) {
|
|
50500
|
+
function ownerContext(ownerPrincipalId, displayName, feishuUnionId) {
|
|
50400
50501
|
return {
|
|
50401
|
-
principal: makeOwnerPrincipal(ownerPrincipalId, displayName),
|
|
50502
|
+
principal: makeOwnerPrincipal(ownerPrincipalId, displayName, feishuUnionId),
|
|
50402
50503
|
grants: [{ resource: { type: "*" }, actions: ["admin"] }]
|
|
50403
50504
|
};
|
|
50404
50505
|
}
|
|
@@ -50427,7 +50528,10 @@ function visitorGuestContext(p2) {
|
|
|
50427
50528
|
async function authenticate(token, deps) {
|
|
50428
50529
|
if (!token) return { ok: false, code: "NO_TOKEN" };
|
|
50429
50530
|
if (deps.isOwnerToken(token)) {
|
|
50430
|
-
return {
|
|
50531
|
+
return {
|
|
50532
|
+
ok: true,
|
|
50533
|
+
context: ownerContext(deps.ownerPrincipalId, deps.ownerDisplayName, deps.ownerFeishuUnionId)
|
|
50534
|
+
};
|
|
50431
50535
|
}
|
|
50432
50536
|
if (deps.verifyVisitorToken) {
|
|
50433
50537
|
const vr = deps.verifyVisitorToken(token);
|
|
@@ -54720,9 +54824,25 @@ function buildSessionHandlers(deps) {
|
|
|
54720
54824
|
const send = async (frame, _client, ctx) => {
|
|
54721
54825
|
const args = SessionSendArgs.parse(frame);
|
|
54722
54826
|
ensureSessionAccess(ctx, args.sessionId, "send");
|
|
54723
|
-
const
|
|
54827
|
+
const sender = ctx ? principalToSender(ctx.principal) : principalToSender(
|
|
54828
|
+
makeOwnerPrincipal(ownerPrincipalId, deps.ownerDisplayName, deps.ownerFeishuUnionId)
|
|
54829
|
+
);
|
|
54830
|
+
const { broadcast } = manager.send(args, sender);
|
|
54724
54831
|
return { response: { type: "session:send", ok: true }, broadcast };
|
|
54725
54832
|
};
|
|
54833
|
+
const currentTurnSender = async (frame, _client, ctx) => {
|
|
54834
|
+
const sid = typeof frame === "object" && frame != null && "sessionId" in frame ? String(frame.sessionId) : "";
|
|
54835
|
+
if (!sid) {
|
|
54836
|
+
return { response: { type: "session:currentTurnSender", sender: null } };
|
|
54837
|
+
}
|
|
54838
|
+
if (ctx && "principal" in ctx) {
|
|
54839
|
+
ensureSessionAccess(ctx, sid, "read");
|
|
54840
|
+
}
|
|
54841
|
+
const state = manager.tryGetState(sid);
|
|
54842
|
+
return {
|
|
54843
|
+
response: { type: "session:currentTurnSender", sender: state?.currentTurnSender ?? null }
|
|
54844
|
+
};
|
|
54845
|
+
};
|
|
54726
54846
|
const stop = async (frame, _client, ctx) => {
|
|
54727
54847
|
const args = SessionIdArgs.parse(frame);
|
|
54728
54848
|
ensureSessionAccess(ctx, args.sessionId, "send");
|
|
@@ -54925,6 +55045,7 @@ function buildSessionHandlers(deps) {
|
|
|
54925
55045
|
"session:update": update,
|
|
54926
55046
|
"session:delete": del,
|
|
54927
55047
|
"session:send": send,
|
|
55048
|
+
"session:currentTurnSender": currentTurnSender,
|
|
54928
55049
|
"session:stop": stop,
|
|
54929
55050
|
"session:interrupt": interrupt,
|
|
54930
55051
|
"session:rewind": rewind,
|
|
@@ -57993,7 +58114,14 @@ function buildAppBuilderHandlers(deps) {
|
|
|
57993
58114
|
broadcastProjectUpdated(f);
|
|
57994
58115
|
},
|
|
57995
58116
|
injectUserText: async (sessionId, text) => {
|
|
57996
|
-
const
|
|
58117
|
+
const ownerSender = principalToSender(
|
|
58118
|
+
makeOwnerPrincipal(
|
|
58119
|
+
deps.ownerPrincipalId,
|
|
58120
|
+
deps.ownerDisplayName ?? "Owner",
|
|
58121
|
+
deps.ownerFeishuUnionId
|
|
58122
|
+
)
|
|
58123
|
+
);
|
|
58124
|
+
const { broadcast } = sessionManager.send({ sessionId, text }, ownerSender);
|
|
57997
58125
|
for (const entry of broadcast) {
|
|
57998
58126
|
deps.broadcastSessionFrame(entry.frame, entry.target);
|
|
57999
58127
|
}
|
|
@@ -58292,6 +58420,9 @@ function buildMethodHandlers(deps) {
|
|
|
58292
58420
|
usersRoot: deps.usersRoot,
|
|
58293
58421
|
devServerLifecycle: deps.devServerLifecycle,
|
|
58294
58422
|
sessionManager: deps.manager,
|
|
58423
|
+
ownerPrincipalId: deps.ownerPrincipalId,
|
|
58424
|
+
ownerDisplayName: deps.ownerDisplayName,
|
|
58425
|
+
ownerFeishuUnionId: deps.ownerFeishuUnionId,
|
|
58295
58426
|
getTunnelUrl: deps.getTunnelUrl,
|
|
58296
58427
|
broadcastProjectUpdated: deps.broadcastProjectUpdated,
|
|
58297
58428
|
logger: deps.logger,
|
|
@@ -58620,6 +58751,10 @@ var METHOD_GRANT_MAP = {
|
|
|
58620
58751
|
"session:update": CAPABILITY_SCOPED,
|
|
58621
58752
|
"session:delete": CAPABILITY_SCOPED,
|
|
58622
58753
|
"session:send": CAPABILITY_SCOPED,
|
|
58754
|
+
// per-turn sender 2026-07-08 spec §4.6:dispatcher 层走 'public'(HTTP RPC path 需 dispatcher 放行);
|
|
58755
|
+
// WS path 的隐私边界(防 guest 猜 sid 枚举 owner feishuUnionId)由 handler 内 ensureSessionAccess
|
|
58756
|
+
// 显式兜底——见 handlers/session.ts:currentTurnSender。dispatcher 'public' ≠ handler 免检。
|
|
58757
|
+
"session:currentTurnSender": { kind: "public" },
|
|
58623
58758
|
"session:stop": CAPABILITY_SCOPED,
|
|
58624
58759
|
"session:interrupt": CAPABILITY_SCOPED,
|
|
58625
58760
|
"session:rewind": CAPABILITY_SCOPED,
|
|
@@ -59192,6 +59327,7 @@ async function startDaemon(config) {
|
|
|
59192
59327
|
let ownerId = feishuIdentity?.identity.ownerId ?? "";
|
|
59193
59328
|
let ownerProvider = feishuIdentity?.identity.provider ?? "";
|
|
59194
59329
|
let ownerDisplayName = feishuIdentity?.identity.displayName ?? loadOwnerDisplayName(config.dataDir);
|
|
59330
|
+
let ownerFeishuUnionId = feishuIdentity?.identity.unionId;
|
|
59195
59331
|
const authMode = resolvedAuthToken == null ? "none" : "first-message";
|
|
59196
59332
|
const inboxStore = new InboxStore(config.dataDir);
|
|
59197
59333
|
const inboxManager = new InboxManager(inboxStore, (_peerDeviceId, frame) => {
|
|
@@ -59204,6 +59340,7 @@ async function startDaemon(config) {
|
|
|
59204
59340
|
isOwnerToken: (x) => resolvedAuthToken != null && constantTimeEqual(x, resolvedAuthToken),
|
|
59205
59341
|
ownerPrincipalId,
|
|
59206
59342
|
ownerDisplayName,
|
|
59343
|
+
ownerFeishuUnionId,
|
|
59207
59344
|
// persona web 分享:访客 visitor token = daemon 自签 HMAC(无 aud),独立于飞书 connect token
|
|
59208
59345
|
// 基建——secret 恒存在(auth-store backfill),故无条件注入。验签 ok → guest ctx(persona wildcard)。
|
|
59209
59346
|
verifyVisitorToken: (t) => {
|
|
@@ -59287,7 +59424,7 @@ async function startDaemon(config) {
|
|
|
59287
59424
|
return result;
|
|
59288
59425
|
},
|
|
59289
59426
|
onAuthed: (h, ctx) => wsServer?.attachClientContext(h.id, ctx),
|
|
59290
|
-
buildOwnerContext: () => ownerContext(ownerPrincipalId, ownerDisplayName),
|
|
59427
|
+
buildOwnerContext: () => ownerContext(ownerPrincipalId, ownerDisplayName, ownerFeishuUnionId),
|
|
59291
59428
|
closeConnection: (h, code, reason) => wsServer?.closeClient(h.id, code, reason),
|
|
59292
59429
|
sendOk: (h, payload) => wsServer?.sendToClient(h.id, payload)
|
|
59293
59430
|
}) : null;
|
|
@@ -59359,8 +59496,6 @@ async function startDaemon(config) {
|
|
|
59359
59496
|
import_node_path64.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
59360
59497
|
];
|
|
59361
59498
|
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
|
|
59362
|
-
const ticketCallerDid = authFile.deviceId;
|
|
59363
|
-
const ticketCallerName = ownerDisplayName;
|
|
59364
59499
|
let ticketMcpConfigPath2;
|
|
59365
59500
|
if (ticketServerScriptPath) {
|
|
59366
59501
|
const ticketLogPath = import_node_path64.default.join(config.dataDir, "ticket-mcp-server.log");
|
|
@@ -59369,8 +59504,6 @@ async function startDaemon(config) {
|
|
|
59369
59504
|
serverScriptPath: ticketServerScriptPath,
|
|
59370
59505
|
apiBaseUrl: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
59371
59506
|
apiKey: resolveClawdTicketsApiKey(),
|
|
59372
|
-
did: ticketCallerDid,
|
|
59373
|
-
name: ticketCallerName,
|
|
59374
59507
|
logPath: ticketLogPath
|
|
59375
59508
|
});
|
|
59376
59509
|
logger.info("ticket.mcp.json written", {
|
|
@@ -59459,6 +59592,7 @@ async function startDaemon(config) {
|
|
|
59459
59592
|
personaStore,
|
|
59460
59593
|
ownerDisplayName,
|
|
59461
59594
|
ownerPrincipalId,
|
|
59595
|
+
ownerFeishuUnionId,
|
|
59462
59596
|
contactStore,
|
|
59463
59597
|
mode: config.mode,
|
|
59464
59598
|
// 单栏 refactor (spec 2026-06-02 §5.1):cc 子进程 env CLAWD_DAEMON_URL 闭包来源。
|
|
@@ -59721,6 +59855,8 @@ async function startDaemon(config) {
|
|
|
59721
59855
|
ownerDisplayName,
|
|
59722
59856
|
// 决策 #16: whoami owner.id = 本机 deviceId(路由主键)+ ownerId/provider 归属人
|
|
59723
59857
|
ownerPrincipalId,
|
|
59858
|
+
// per-turn sender §4.6:send handler 无 ctx 兜底 + AppBuilder publish injectUserText 需要
|
|
59859
|
+
ownerFeishuUnionId,
|
|
59724
59860
|
ownerId,
|
|
59725
59861
|
ownerProvider,
|
|
59726
59862
|
personaStore,
|
|
@@ -60004,6 +60140,7 @@ async function startDaemon(config) {
|
|
|
60004
60140
|
ownerId = result.identity.ownerId;
|
|
60005
60141
|
ownerProvider = result.identity.provider;
|
|
60006
60142
|
ownerDisplayName = result.identity.displayName;
|
|
60143
|
+
ownerFeishuUnionId = result.identity.unionId;
|
|
60007
60144
|
handlers = makeHandlers();
|
|
60008
60145
|
wsServer?.broadcastToOwners({ type: "auth:login:done", identity: result.identity });
|
|
60009
60146
|
setImmediate(() => wsServer?.closeAllClients());
|
|
@@ -60142,7 +60279,7 @@ async function startDaemon(config) {
|
|
|
60142
60279
|
wss.onFrame(async (client, frame) => {
|
|
60143
60280
|
const type = frame.type;
|
|
60144
60281
|
const requestId = typeof frame.requestId === "string" ? frame.requestId : void 0;
|
|
60145
|
-
const ctx = wsServer.getClientContext(client.id) ?? ownerContext(ownerPrincipalId, ownerDisplayName);
|
|
60282
|
+
const ctx = wsServer.getClientContext(client.id) ?? ownerContext(ownerPrincipalId, ownerDisplayName, ownerFeishuUnionId);
|
|
60146
60283
|
const result = await dispatchRpc(type, frame, client, ctx, {
|
|
60147
60284
|
handlers,
|
|
60148
60285
|
feishuActive: () => feishuActive
|