@clawos-dev/clawd 0.2.178-beta.358.7f6c694 → 0.2.179-beta.359.7bf1eca
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 +114 -137
- package/dist/shift/mcp-server.cjs +3 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -4784,6 +4784,16 @@ var init_schemas = __esm({
|
|
|
4784
4784
|
* 反查路径走错;按 #750 一族防线处理,跟 ownerPersonaId 同地点 strip)。
|
|
4785
4785
|
*/
|
|
4786
4786
|
dispatchedFromSessionId: external_exports.string().min(1).optional(),
|
|
4787
|
+
/**
|
|
4788
|
+
* Shift fire 派生的 session 记录调 addShift 的 source cc session id(稳定 key);
|
|
4789
|
+
* sidebar 据此把 fire 出的 session 折叠在 source session 下,跟 dispatchedFromSessionId
|
|
4790
|
+
* 平行但渲染不同 icon(AlarmClock 区别于 dispatch 的 CornerDownRight),让 owner 一眼
|
|
4791
|
+
* 分清"派生于人为委派"还是"派生于定时唤起"。非 shift fire session 缺省。
|
|
4792
|
+
* 跟 dispatchedFromSessionId / forkedFromSessionId 三者互斥(同一 session 不会兼任)。
|
|
4793
|
+
* mirror SessionFile 同 dispatchedFromSessionId 处理(shift fire 本地概念,理论上不会
|
|
4794
|
+
* mirror,留 strip 防御)。
|
|
4795
|
+
*/
|
|
4796
|
+
shiftFiredFromSessionId: external_exports.string().min(1).optional(),
|
|
4787
4797
|
createdAt: external_exports.string().min(1),
|
|
4788
4798
|
updatedAt: external_exports.string().min(1)
|
|
4789
4799
|
});
|
|
@@ -41261,6 +41271,22 @@ function composeGuestSandbox(base, userWorkDir, spawnCwd) {
|
|
|
41261
41271
|
return s;
|
|
41262
41272
|
}
|
|
41263
41273
|
|
|
41274
|
+
// src/shift/wrap.ts
|
|
41275
|
+
function wrapShiftFirePrompt(args) {
|
|
41276
|
+
return [
|
|
41277
|
+
`<clawd-shift-fire target-persona="${escapeAttr(args.targetPersona)}">`,
|
|
41278
|
+
"This is a scheduled shift fire \u2014 not a live user message.",
|
|
41279
|
+
"Respond as an assistant turn (start your output directly).",
|
|
41280
|
+
"",
|
|
41281
|
+
"Instruction:",
|
|
41282
|
+
args.prompt,
|
|
41283
|
+
"</clawd-shift-fire>"
|
|
41284
|
+
].join("\n");
|
|
41285
|
+
}
|
|
41286
|
+
function escapeAttr(v2) {
|
|
41287
|
+
return v2.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
41288
|
+
}
|
|
41289
|
+
|
|
41264
41290
|
// src/session/reducer.ts
|
|
41265
41291
|
init_runtime();
|
|
41266
41292
|
|
|
@@ -41318,29 +41344,6 @@ function buildConnectionPrompt(args) {
|
|
|
41318
41344
|
return result;
|
|
41319
41345
|
}
|
|
41320
41346
|
|
|
41321
|
-
// src/persona/sharing-prompt.ts
|
|
41322
|
-
var ATTACHMENT_SHARING_HINT = `## \u628A\u4EA7\u51FA\u6587\u4EF6\u5206\u4EAB\u7ED9\u5BF9\u65B9\uFF08attachment\uFF09
|
|
41323
|
-
|
|
41324
|
-
\u5F53\u4F60\u4EA7\u51FA\u4E86\u6587\u4EF6\u3001\u9700\u8981\u8BA9\u5BF9\u65B9\u62FF\u5230\u65F6\uFF08\u5C24\u5176 Bash \u89E3\u538B/\u751F\u6210\u7684\u6587\u4EF6\uFF0C\u6216\u8DE8\u8BBE\u5907\u88AB\u59D4\u6D3E\u65F6\u5BF9\u65B9\u5728\u53E6\u4E00\u53F0\u673A\u5668\u3001\u770B\u4E0D\u5230\u4F60\u7684\u672C\u5730\u8DEF\u5F84\uFF09\uFF0C\u7528 daemon \u7684 HTTP RPC \u628A\u6587\u4EF6\u8F6C\u6210\u4E00\u4E2A\u5E26\u7B7E\u540D\u7684\u4E0B\u8F7D URL\uFF1A
|
|
41325
|
-
|
|
41326
|
-
1. \u5165\u7FA4\uFF08\u767B\u8BB0\u5230\u672C session \u7684\u5171\u4EAB\u6E05\u5355\uFF09\uFF1A
|
|
41327
|
-
\`\`\`bash
|
|
41328
|
-
curl -sS -X POST "$CLAWD_DAEMON_URL/api/rpc/attachment.groupAdd" \\
|
|
41329
|
-
-H "X-Clawd-Session-Id: $CLAWD_SESSION_ID" -H 'Content-Type: application/json' \\
|
|
41330
|
-
-d '{"relPath":"<\u6587\u4EF6\u7684\u7EDD\u5BF9\u8DEF\u5F84>"}'
|
|
41331
|
-
\`\`\`
|
|
41332
|
-
2. \u7B7E\u540D\u62FF URL\uFF1A
|
|
41333
|
-
\`\`\`bash
|
|
41334
|
-
curl -sS -X POST "$CLAWD_DAEMON_URL/api/rpc/attachment.signUrl" \\
|
|
41335
|
-
-H "X-Clawd-Session-Id: $CLAWD_SESSION_ID" -H 'Content-Type: application/json' \\
|
|
41336
|
-
-d '{"relPath":"<\u540C\u4E00\u4E2A\u7EDD\u5BF9\u8DEF\u5F84>"}'
|
|
41337
|
-
\`\`\`
|
|
41338
|
-
\u8FD4\u56DE\u7684 \`url\` \u5C31\u662F\u5BF9\u65B9\u53EF\u76F4\u63A5\u6253\u5F00/\u4E0B\u8F7D\u7684\u94FE\u63A5\u3002
|
|
41339
|
-
|
|
41340
|
-
- \`relPath\` \u5FC5\u987B\u4F20**\u7EDD\u5BF9\u8DEF\u5F84**\uFF08\u4F60\u4EA7\u51FA\u6587\u4EF6\u7684\u771F\u5B9E\u8DEF\u5F84\uFF09\uFF0C\u4E0D\u8981\u4F20\u76F8\u5BF9\u8DEF\u5F84\u3002
|
|
41341
|
-
- \u53EA\u80FD\u5206\u4EAB\u4F60\u81EA\u5DF1\u5DE5\u4F5C\u76EE\u5F55\u5185\u7684\u6587\u4EF6\uFF0C\u8D8A\u754C\u4F1A\u88AB\u62D2\u3002
|
|
41342
|
-
- \u88AB dispatch \u63A5\u5230\u4EFB\u52A1\u3001\u8981\u56DE\u4F20\u4EA7\u7269\u65F6\uFF1A\u628A\u7B7E\u540D URL \u5199\u8FDB \`personaDispatchComplete\` \u7684 \`text\` \u91CC\uFF08\`filePaths\` \u53EA\u662F\u4F60\u672C\u673A\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u8DE8\u8BBE\u5907\u5BF9\u65B9\u6253\u4E0D\u5F00\uFF0CURL \u624D\u80FD\u6253\u5F00\uFF09\u3002`;
|
|
41343
|
-
|
|
41344
41347
|
// src/dispatch/system-prompt.ts
|
|
41345
41348
|
var DISPATCH_SYSTEM_PROMPT_HINT = `## \u59D4\u6D3E\u7ED9\u53E6\u4E00\u4E2A persona\uFF08dispatch\uFF09
|
|
41346
41349
|
|
|
@@ -41506,9 +41509,6 @@ function buildSpawnContext(state, deps) {
|
|
|
41506
41509
|
if (dispatchMcpConfigPath2) {
|
|
41507
41510
|
ctx.extraSystemPrompt = (ctx.extraSystemPrompt ? ctx.extraSystemPrompt + "\n\n" : "") + DISPATCH_SYSTEM_PROMPT_HINT;
|
|
41508
41511
|
}
|
|
41509
|
-
if (daemonUrl) {
|
|
41510
|
-
ctx.extraSystemPrompt = (ctx.extraSystemPrompt ? ctx.extraSystemPrompt + "\n\n" : "") + ATTACHMENT_SHARING_HINT;
|
|
41511
|
-
}
|
|
41512
41512
|
if (meta?.extraSettings) {
|
|
41513
41513
|
ctx.extraSettings = meta.extraSettings;
|
|
41514
41514
|
}
|
|
@@ -43268,10 +43268,14 @@ var SessionManager = class {
|
|
|
43268
43268
|
// 强制走 deps.store(即 default scope),不走 scopeForFile:mirror 物理落 default 即可。
|
|
43269
43269
|
// 远端 creator / origin 字段原值保留(不被本机 ctx 派生覆写)。
|
|
43270
43270
|
//
|
|
43271
|
-
// strip 远端 personaId / dispatchedFromSessionId:mirror
|
|
43272
|
-
//
|
|
43273
|
-
//
|
|
43274
|
-
// dispatchedFromSessionId
|
|
43271
|
+
// strip 远端 personaId / dispatchedFromSessionId / shiftFiredFromSessionId:mirror
|
|
43272
|
+
// SessionFile 上这些字段都指向朋友 daemon 上的本地 id,本机不持有对应 persona /
|
|
43273
|
+
// 源 session。留着会让按这些字段反查的本机消费者(MyPersonasSection 按 ownerPersonaId
|
|
43274
|
+
// 反查 persona、sidebar 按 dispatchedFromSessionId / shiftFiredFromSessionId 折叠
|
|
43275
|
+
// sub-session)走错分支。写入前清掉。#750 一族防线。
|
|
43276
|
+
//
|
|
43277
|
+
// shift fire 是本地 daemon scheduler 行为,理论上不产生 mirror SessionFile,但留 strip
|
|
43278
|
+
// 防御(同 dispatchedFromSessionId 处理姿势对齐)。
|
|
43275
43279
|
//
|
|
43276
43280
|
// 与 manager.create / manager.update 区别:
|
|
43277
43281
|
// - 不走 newRunner / attachObserver / cwd 校验(mirror 是纯 metadata 层)
|
|
@@ -43280,6 +43284,7 @@ var SessionManager = class {
|
|
|
43280
43284
|
const {
|
|
43281
43285
|
ownerPersonaId: _strippedPid,
|
|
43282
43286
|
dispatchedFromSessionId: _strippedDsp,
|
|
43287
|
+
shiftFiredFromSessionId: _strippedSft,
|
|
43283
43288
|
...rest
|
|
43284
43289
|
} = file;
|
|
43285
43290
|
return this.deps.store.write(rest);
|
|
@@ -43982,6 +43987,7 @@ var SessionManager = class {
|
|
|
43982
43987
|
cwd,
|
|
43983
43988
|
tool: "claude",
|
|
43984
43989
|
ownerPersonaId: args.targetPersona,
|
|
43990
|
+
...args.sourceSessionId ? { shiftFiredFromSessionId: args.sourceSessionId } : {},
|
|
43985
43991
|
createdAt: now,
|
|
43986
43992
|
updatedAt: now
|
|
43987
43993
|
};
|
|
@@ -44017,7 +44023,16 @@ var SessionManager = class {
|
|
|
44017
44023
|
});
|
|
44018
44024
|
const runner = this.ensureRunnerForScope(file, scope);
|
|
44019
44025
|
this.deps.logger?.info("shift.createShiftSession.runner-ready", { sessionId });
|
|
44020
|
-
runner.input({
|
|
44026
|
+
runner.input({
|
|
44027
|
+
kind: "command",
|
|
44028
|
+
command: {
|
|
44029
|
+
kind: "send",
|
|
44030
|
+
text: wrapShiftFirePrompt({
|
|
44031
|
+
prompt: args.prompt,
|
|
44032
|
+
targetPersona: args.targetPersona
|
|
44033
|
+
})
|
|
44034
|
+
}
|
|
44035
|
+
});
|
|
44021
44036
|
const kill = () => {
|
|
44022
44037
|
const r = this.runners.get(sessionId);
|
|
44023
44038
|
if (!r) return;
|
|
@@ -47539,7 +47554,8 @@ function createShiftScheduler(deps) {
|
|
|
47539
47554
|
shiftId: shift.id,
|
|
47540
47555
|
targetPersona: shift.targetPersona,
|
|
47541
47556
|
prompt: shift.prompt,
|
|
47542
|
-
timeoutMs
|
|
47557
|
+
timeoutMs,
|
|
47558
|
+
...shift.createdBySessionId ? { sourceSessionId: shift.createdBySessionId } : {}
|
|
47543
47559
|
});
|
|
47544
47560
|
sessionId = spawned.sessionId;
|
|
47545
47561
|
const startRun = {
|
|
@@ -47593,8 +47609,12 @@ function createShiftScheduler(deps) {
|
|
|
47593
47609
|
|
|
47594
47610
|
// src/shift/spawn.ts
|
|
47595
47611
|
function createShiftSpawnFn(deps) {
|
|
47596
|
-
return async ({ targetPersona, prompt, timeoutMs }) => {
|
|
47597
|
-
const created = deps.sessionManager.createShiftSession({
|
|
47612
|
+
return async ({ targetPersona, prompt, timeoutMs, sourceSessionId }) => {
|
|
47613
|
+
const created = deps.sessionManager.createShiftSession({
|
|
47614
|
+
targetPersona,
|
|
47615
|
+
prompt,
|
|
47616
|
+
...sourceSessionId ? { sourceSessionId } : {}
|
|
47617
|
+
});
|
|
47598
47618
|
let resolveOuter = () => {
|
|
47599
47619
|
};
|
|
47600
47620
|
const ended = new Promise((r) => {
|
|
@@ -47648,12 +47668,14 @@ function validateSchedule(schedule) {
|
|
|
47648
47668
|
function buildShiftInternalHandlers(deps) {
|
|
47649
47669
|
const add = async (frame) => {
|
|
47650
47670
|
const persona = readPersonaId(frame);
|
|
47671
|
+
const callerSessionId = typeof frame.sessionId === "string" ? frame.sessionId : void 0;
|
|
47651
47672
|
const { type: _t, requestId: _r, personaId: _p, sessionId: _s, ...rest } = frame;
|
|
47652
47673
|
const args = rest;
|
|
47653
47674
|
validateSchedule(args.schedule);
|
|
47654
47675
|
const shift = deps.store.add({
|
|
47655
47676
|
ownerId: deps.ownerIdProvider(),
|
|
47656
47677
|
createdByPersona: persona,
|
|
47678
|
+
...callerSessionId ? { createdBySessionId: callerSessionId } : {},
|
|
47657
47679
|
name: args.name,
|
|
47658
47680
|
enabled: true,
|
|
47659
47681
|
schedule: args.schedule,
|
|
@@ -49221,67 +49243,6 @@ function removeSubscription(client, sessionId) {
|
|
|
49221
49243
|
else client.subscribedSessions.set(sessionId, next);
|
|
49222
49244
|
}
|
|
49223
49245
|
|
|
49224
|
-
// src/transport/rpc-adapter.ts
|
|
49225
|
-
var EXPOSED_RPC_METHODS = [
|
|
49226
|
-
"appBuilder.createProject",
|
|
49227
|
-
"appBuilder.listProjects",
|
|
49228
|
-
"appBuilder.updateProjectPort",
|
|
49229
|
-
"appBuilder.setProdUrl",
|
|
49230
|
-
// 单栏 refactor §5.6.2 stage fix:scaffold + install 完成调 startDevServer 起 dev server;
|
|
49231
|
-
// 中间用 reportStage 上报阶段(scaffolding / installing / failed),UI 据 stage 推帧切 PreviewPane。
|
|
49232
|
-
"appBuilder.startDevServer",
|
|
49233
|
-
"appBuilder.reportStage",
|
|
49234
|
-
// 单栏 §5.6.5 fix: UI 切 session 时调(assistant 不需要主动调,但暴露白名单避免误猜成 forbidden)
|
|
49235
|
-
"appBuilder.setActiveSession",
|
|
49236
|
-
// dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
|
|
49237
|
-
// 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
|
|
49238
|
-
"auth.getIdentity",
|
|
49239
|
-
// Persona dispatch (Task 4): A 端 dispatch MCP server 调 run(hold-and-wait 一次);
|
|
49240
|
-
// B 端 dispatch MCP server 调 complete(带 outcome 触发 run 端 resolve)。详见
|
|
49241
|
-
// protocol/src/dispatch.ts。
|
|
49242
|
-
"personaDispatch.run",
|
|
49243
|
-
"personaDispatch.complete",
|
|
49244
|
-
// clawd-shift v1 (spec 2026-06-24-clawd-shift):cc 子进程内的 shift MCP server 调
|
|
49245
|
-
// 这 5 个 method 管理 owner 的 shift(fire-and-forget 排班)。鉴权靠 body.personaId
|
|
49246
|
-
// (mcp-server 从 process.env.CLAWD_PERSONA_ID 读,源 = SessionFile.ownerPersonaId)。
|
|
49247
|
-
// handler 内 cancel/update/history 校验 createdByPersona === personaId 防越权。
|
|
49248
|
-
"shift-internal.add",
|
|
49249
|
-
"shift-internal.list",
|
|
49250
|
-
"shift-internal.cancel",
|
|
49251
|
-
"shift-internal.update",
|
|
49252
|
-
"shift-internal.history",
|
|
49253
|
-
// file-sharing:persona guest agent 把自己工作目录内的产物入群+签名分享。
|
|
49254
|
-
// 路径越界由 handlers/attachment.ts guardAttachmentPath(scope-based)拦截。
|
|
49255
|
-
"attachment.groupAdd",
|
|
49256
|
-
"attachment.signUrl"
|
|
49257
|
-
];
|
|
49258
|
-
async function handleRpcRequest(input) {
|
|
49259
|
-
const { method, body, sessionId, dispatcher } = input;
|
|
49260
|
-
if (!sessionId) {
|
|
49261
|
-
return { status: 400, body: { ok: false, error: "MISSING_SESSION_ID", message: "X-Clawd-Session-Id header required" } };
|
|
49262
|
-
}
|
|
49263
|
-
if (!EXPOSED_RPC_METHODS.includes(method)) {
|
|
49264
|
-
return { status: 403, body: { ok: false, error: "METHOD_NOT_EXPOSED", message: `method "${method}" not exposed via HTTP RPC` } };
|
|
49265
|
-
}
|
|
49266
|
-
const internalMethod = method.replace(".", ":");
|
|
49267
|
-
const augmentedBody = {
|
|
49268
|
-
...typeof body === "object" && body != null ? body : {},
|
|
49269
|
-
sessionId
|
|
49270
|
-
};
|
|
49271
|
-
try {
|
|
49272
|
-
const result = await dispatcher.dispatch(internalMethod, augmentedBody, { sessionId });
|
|
49273
|
-
return { status: 200, body: { ok: true, result } };
|
|
49274
|
-
} catch (err) {
|
|
49275
|
-
const e = err;
|
|
49276
|
-
const code = e?.code ?? "INTERNAL";
|
|
49277
|
-
const message = e?.message ?? String(err);
|
|
49278
|
-
return { status: 400, body: { ok: false, error: code, message } };
|
|
49279
|
-
}
|
|
49280
|
-
}
|
|
49281
|
-
function resolveExposedHandler(handlers, internalMethod) {
|
|
49282
|
-
return handlers[internalMethod] ?? handlers[internalMethod.replace(":", ".")];
|
|
49283
|
-
}
|
|
49284
|
-
|
|
49285
49246
|
// src/transport/auth.ts
|
|
49286
49247
|
init_protocol();
|
|
49287
49248
|
var AuthGate = class {
|
|
@@ -50524,6 +50485,60 @@ async function importZip(buf, root) {
|
|
|
50524
50485
|
}
|
|
50525
50486
|
}
|
|
50526
50487
|
|
|
50488
|
+
// src/transport/rpc-adapter.ts
|
|
50489
|
+
var EXPOSED_RPC_METHODS = [
|
|
50490
|
+
"appBuilder.createProject",
|
|
50491
|
+
"appBuilder.listProjects",
|
|
50492
|
+
"appBuilder.updateProjectPort",
|
|
50493
|
+
"appBuilder.setProdUrl",
|
|
50494
|
+
// 单栏 refactor §5.6.2 stage fix:scaffold + install 完成调 startDevServer 起 dev server;
|
|
50495
|
+
// 中间用 reportStage 上报阶段(scaffolding / installing / failed),UI 据 stage 推帧切 PreviewPane。
|
|
50496
|
+
"appBuilder.startDevServer",
|
|
50497
|
+
"appBuilder.reportStage",
|
|
50498
|
+
// 单栏 §5.6.5 fix: UI 切 session 时调(assistant 不需要主动调,但暴露白名单避免误猜成 forbidden)
|
|
50499
|
+
"appBuilder.setActiveSession",
|
|
50500
|
+
// dataclaw-builder:persona 建页时取建页人身份(含 union_id)写进生成 app 的配置。
|
|
50501
|
+
// 路由到 handlers['auth:getIdentity'],只返 identity、绝不带 ttcToken(见 handlers/feishu-auth.ts)。
|
|
50502
|
+
"auth.getIdentity",
|
|
50503
|
+
// Persona dispatch (Task 4): A 端 dispatch MCP server 调 run(hold-and-wait 一次);
|
|
50504
|
+
// B 端 dispatch MCP server 调 complete(带 outcome 触发 run 端 resolve)。详见
|
|
50505
|
+
// protocol/src/dispatch.ts。
|
|
50506
|
+
"personaDispatch.run",
|
|
50507
|
+
"personaDispatch.complete",
|
|
50508
|
+
// clawd-shift v1 (spec 2026-06-24-clawd-shift):cc 子进程内的 shift MCP server 调
|
|
50509
|
+
// 这 5 个 method 管理 owner 的 shift(fire-and-forget 排班)。鉴权靠 body.personaId
|
|
50510
|
+
// (mcp-server 从 process.env.CLAWD_PERSONA_ID 读,源 = SessionFile.ownerPersonaId)。
|
|
50511
|
+
// handler 内 cancel/update/history 校验 createdByPersona === personaId 防越权。
|
|
50512
|
+
"shift-internal.add",
|
|
50513
|
+
"shift-internal.list",
|
|
50514
|
+
"shift-internal.cancel",
|
|
50515
|
+
"shift-internal.update",
|
|
50516
|
+
"shift-internal.history"
|
|
50517
|
+
];
|
|
50518
|
+
async function handleRpcRequest(input) {
|
|
50519
|
+
const { method, body, sessionId, dispatcher } = input;
|
|
50520
|
+
if (!sessionId) {
|
|
50521
|
+
return { status: 400, body: { ok: false, error: "MISSING_SESSION_ID", message: "X-Clawd-Session-Id header required" } };
|
|
50522
|
+
}
|
|
50523
|
+
if (!EXPOSED_RPC_METHODS.includes(method)) {
|
|
50524
|
+
return { status: 403, body: { ok: false, error: "METHOD_NOT_EXPOSED", message: `method "${method}" not exposed via HTTP RPC` } };
|
|
50525
|
+
}
|
|
50526
|
+
const internalMethod = method.replace(".", ":");
|
|
50527
|
+
const augmentedBody = {
|
|
50528
|
+
...typeof body === "object" && body != null ? body : {},
|
|
50529
|
+
sessionId
|
|
50530
|
+
};
|
|
50531
|
+
try {
|
|
50532
|
+
const result = await dispatcher.dispatch(internalMethod, augmentedBody, { sessionId });
|
|
50533
|
+
return { status: 200, body: { ok: true, result } };
|
|
50534
|
+
} catch (err) {
|
|
50535
|
+
const e = err;
|
|
50536
|
+
const code = e?.code ?? "INTERNAL";
|
|
50537
|
+
const message = e?.message ?? String(err);
|
|
50538
|
+
return { status: 400, body: { ok: false, error: code, message } };
|
|
50539
|
+
}
|
|
50540
|
+
}
|
|
50541
|
+
|
|
50527
50542
|
// src/transport/http-router.ts
|
|
50528
50543
|
var RPC_ROUTE_PREFIX = "/api/rpc/";
|
|
50529
50544
|
var RPC_BODY_MAX_BYTES = 1 * 1024 * 1024;
|
|
@@ -52914,16 +52929,6 @@ function personaIdFromPath(absPath, personaRoot) {
|
|
|
52914
52929
|
const id = rel.split(path44.sep)[0];
|
|
52915
52930
|
return id || null;
|
|
52916
52931
|
}
|
|
52917
|
-
function isPathWithin(dir, absPath) {
|
|
52918
|
-
const d = path44.resolve(dir);
|
|
52919
|
-
const t = path44.resolve(absPath);
|
|
52920
|
-
const sep3 = d.endsWith(path44.sep) ? "" : path44.sep;
|
|
52921
|
-
return t === d || t.startsWith(d + sep3);
|
|
52922
|
-
}
|
|
52923
|
-
function isPathInGuestBoundary(personaRoot, personaId, userWorkDir, absPath) {
|
|
52924
|
-
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
52925
|
-
return personaIdFromPath(path44.resolve(absPath), personaRoot) === personaId;
|
|
52926
|
-
}
|
|
52927
52932
|
|
|
52928
52933
|
// src/handlers/history.ts
|
|
52929
52934
|
init_protocol();
|
|
@@ -53735,31 +53740,6 @@ function assertGuestAttachmentPath(ctx, absPath, personaRoot, method, usersRoot)
|
|
|
53735
53740
|
}
|
|
53736
53741
|
}
|
|
53737
53742
|
function buildAttachmentHandlers(deps) {
|
|
53738
|
-
function guardAttachmentPath(ctx, sessionId, candidateAbs, method, nonGuestPolicy) {
|
|
53739
|
-
if (ctx?.principal.kind === "owner") return;
|
|
53740
|
-
const scope = deps.getSessionScope?.(sessionId);
|
|
53741
|
-
if (!scope) return;
|
|
53742
|
-
if (scope.kind === "persona" && scope.mode === "guest") {
|
|
53743
|
-
if (!deps.personaRoot) return;
|
|
53744
|
-
const userWorkDir = deps.usersRoot ? deriveUserWorkDir(scope.capId, deps.usersRoot) : void 0;
|
|
53745
|
-
if (!isPathInGuestBoundary(deps.personaRoot, scope.personaId, userWorkDir, candidateAbs)) {
|
|
53746
|
-
throw new ClawdError(
|
|
53747
|
-
ERROR_CODES.UNAUTHORIZED,
|
|
53748
|
-
`${method}: path outside guest work dir: ${candidateAbs}`
|
|
53749
|
-
);
|
|
53750
|
-
}
|
|
53751
|
-
return;
|
|
53752
|
-
}
|
|
53753
|
-
if (nonGuestPolicy === "group-acl") return;
|
|
53754
|
-
const cwd = deps.sessionStore?.read(sessionId)?.cwd;
|
|
53755
|
-
if (!cwd) return;
|
|
53756
|
-
if (!isPathWithin(cwd, candidateAbs)) {
|
|
53757
|
-
throw new ClawdError(
|
|
53758
|
-
ERROR_CODES.UNAUTHORIZED,
|
|
53759
|
-
`${method}: path outside session work dir: ${candidateAbs}`
|
|
53760
|
-
);
|
|
53761
|
-
}
|
|
53762
|
-
}
|
|
53763
53743
|
const signUrl = async (frame, _client, ctx) => {
|
|
53764
53744
|
const parsed = AttachmentSignUrlArgs.safeParse(frame);
|
|
53765
53745
|
if (!parsed.success) {
|
|
@@ -53802,7 +53782,7 @@ function buildAttachmentHandlers(deps) {
|
|
|
53802
53782
|
}
|
|
53803
53783
|
const cwdAbs = import_node_path36.default.resolve(sessionFile.cwd);
|
|
53804
53784
|
const candidateAbs = import_node_path36.default.isAbsolute(args.relPath) ? import_node_path36.default.resolve(args.relPath) : import_node_path36.default.resolve(cwdAbs, args.relPath);
|
|
53805
|
-
|
|
53785
|
+
assertGuestAttachmentPath(ctx, candidateAbs, deps.personaRoot, "attachment.signUrl", deps.usersRoot);
|
|
53806
53786
|
const entries = deps.groupFileStore.list(scope, args.sessionId);
|
|
53807
53787
|
const entry = entries.find((e) => {
|
|
53808
53788
|
const storedAbs = import_node_path36.default.isAbsolute(e.relPath) ? import_node_path36.default.resolve(e.relPath) : import_node_path36.default.resolve(cwdAbs, e.relPath);
|
|
@@ -53841,18 +53821,15 @@ function buildAttachmentHandlers(deps) {
|
|
|
53841
53821
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, parsed.error.message);
|
|
53842
53822
|
}
|
|
53843
53823
|
const args = parsed.data;
|
|
53824
|
+
guardGuestBySessionCwd(ctx, args.sessionId, "attachment.groupAdd");
|
|
53844
53825
|
const scope = deps.getSessionScope(args.sessionId);
|
|
53845
53826
|
if (!scope) {
|
|
53846
53827
|
throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `session ${args.sessionId} not found`);
|
|
53847
53828
|
}
|
|
53848
|
-
const cwdAbs = import_node_path36.default.resolve(deps.sessionStore?.read(args.sessionId)?.cwd ?? ".");
|
|
53849
|
-
const candidateAbs = import_node_path36.default.isAbsolute(args.relPath) ? import_node_path36.default.resolve(args.relPath) : import_node_path36.default.resolve(cwdAbs, args.relPath);
|
|
53850
|
-
guardAttachmentPath(ctx, args.sessionId, candidateAbs, "attachment.groupAdd", "cwd-subtree");
|
|
53851
|
-
const from = ctx?.principal.kind === "owner" ? "owner" : "agent";
|
|
53852
53829
|
const size = 0;
|
|
53853
53830
|
const entry = deps.groupFileStore.upsert(scope, args.sessionId, {
|
|
53854
53831
|
relPath: args.relPath,
|
|
53855
|
-
from,
|
|
53832
|
+
from: "owner",
|
|
53856
53833
|
label: args.label,
|
|
53857
53834
|
size,
|
|
53858
53835
|
mime: lookupMime(args.relPath)
|
|
@@ -57470,7 +57447,7 @@ async function startDaemon(config) {
|
|
|
57470
57447
|
});
|
|
57471
57448
|
const rpcDispatcher = {
|
|
57472
57449
|
async dispatch(method, args, _ctx) {
|
|
57473
|
-
const handler =
|
|
57450
|
+
const handler = handlers[method];
|
|
57474
57451
|
if (!handler) {
|
|
57475
57452
|
throw Object.assign(new Error(`unknown RPC method "${method}"`), { code: "METHOD_NOT_IMPLEMENTED" });
|
|
57476
57453
|
}
|
|
@@ -21251,7 +21251,9 @@ async function main() {
|
|
|
21251
21251
|
inputSchema: {
|
|
21252
21252
|
name: external_exports.string().describe("short label shown in shift.json + future UI"),
|
|
21253
21253
|
schedule: ScheduleSchema,
|
|
21254
|
-
prompt: external_exports.string().describe(
|
|
21254
|
+
prompt: external_exports.string().describe(
|
|
21255
|
+
"instruction the spawned cc executes on startup (NOT a chat message from the owner). Write what you want the persona to DO or SAY at fire time, in instruction form \u2014 daemon wraps it in a `<clawd-shift-fire>` tag so the spawned cc treats it as a scheduled action and responds as an assistant turn (the wrap is stripped from the owner's UI bubble)."
|
|
21256
|
+
),
|
|
21255
21257
|
targetPersona: external_exports.string().optional().describe("which persona to spawn; defaults to the calling persona"),
|
|
21256
21258
|
timeoutMs: external_exports.number().optional().describe("hard timeout per fire; default 30 minutes")
|
|
21257
21259
|
}
|
package/package.json
CHANGED