@clawos-dev/clawd 0.2.29 → 0.2.31-beta.46.76a266e
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 +158 -112
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -8583,7 +8583,7 @@ var init_zod = __esm({
|
|
|
8583
8583
|
});
|
|
8584
8584
|
|
|
8585
8585
|
// ../protocol/src/persona-schemas.ts
|
|
8586
|
-
var PersonaTokenEntrySchema, PersonaFileSchema,
|
|
8586
|
+
var PersonaTokenEntrySchema, PersonaFileSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema, PersonaIssueTokenArgsSchema, PersonaRevokeTokenArgsSchema, PersonaAppendOwnerMessageArgsSchema;
|
|
8587
8587
|
var init_persona_schemas = __esm({
|
|
8588
8588
|
"../protocol/src/persona-schemas.ts"() {
|
|
8589
8589
|
"use strict";
|
|
@@ -8602,66 +8602,6 @@ var init_persona_schemas = __esm({
|
|
|
8602
8602
|
createdAt: external_exports.number(),
|
|
8603
8603
|
updatedAt: external_exports.number()
|
|
8604
8604
|
}).strict();
|
|
8605
|
-
PersonaHelloFrameSchema = external_exports.object({
|
|
8606
|
-
kind: external_exports.literal("persona-hello"),
|
|
8607
|
-
token: external_exports.string().min(1)
|
|
8608
|
-
});
|
|
8609
|
-
PersonaSendFrameSchema = external_exports.object({
|
|
8610
|
-
kind: external_exports.literal("send"),
|
|
8611
|
-
text: external_exports.string()
|
|
8612
|
-
});
|
|
8613
|
-
PersonaResetFrameSchema = external_exports.object({
|
|
8614
|
-
kind: external_exports.literal("reset")
|
|
8615
|
-
});
|
|
8616
|
-
PersonaPingFrameSchema = external_exports.object({
|
|
8617
|
-
kind: external_exports.literal("ping")
|
|
8618
|
-
});
|
|
8619
|
-
PersonaReadyFrameSchema = external_exports.object({
|
|
8620
|
-
kind: external_exports.literal("persona-ready"),
|
|
8621
|
-
subSessionId: external_exports.string(),
|
|
8622
|
-
personaLabel: external_exports.string(),
|
|
8623
|
-
cwd: external_exports.string(),
|
|
8624
|
-
model: external_exports.string().optional()
|
|
8625
|
-
});
|
|
8626
|
-
PersonaHistoryEventFrameSchema = external_exports.object({
|
|
8627
|
-
kind: external_exports.literal("history-event"),
|
|
8628
|
-
event: external_exports.unknown()
|
|
8629
|
-
});
|
|
8630
|
-
PersonaHistoryDoneFrameSchema = external_exports.object({
|
|
8631
|
-
kind: external_exports.literal("history-done")
|
|
8632
|
-
});
|
|
8633
|
-
PersonaEventFrameSchema = external_exports.object({
|
|
8634
|
-
kind: external_exports.literal("event"),
|
|
8635
|
-
event: external_exports.unknown()
|
|
8636
|
-
});
|
|
8637
|
-
PersonaErrorFrameSchema = external_exports.object({
|
|
8638
|
-
kind: external_exports.literal("error"),
|
|
8639
|
-
code: external_exports.enum([
|
|
8640
|
-
"TOKEN_INVALID",
|
|
8641
|
-
"TOKEN_REVOKED",
|
|
8642
|
-
"PERSONA_DELETED",
|
|
8643
|
-
"PERSONA_NOT_PUBLIC",
|
|
8644
|
-
"INTERNAL"
|
|
8645
|
-
]),
|
|
8646
|
-
message: external_exports.string()
|
|
8647
|
-
});
|
|
8648
|
-
PersonaPongFrameSchema = external_exports.object({
|
|
8649
|
-
kind: external_exports.literal("pong")
|
|
8650
|
-
});
|
|
8651
|
-
PersonaClientFrameSchema = external_exports.discriminatedUnion("kind", [
|
|
8652
|
-
PersonaHelloFrameSchema,
|
|
8653
|
-
PersonaSendFrameSchema,
|
|
8654
|
-
PersonaResetFrameSchema,
|
|
8655
|
-
PersonaPingFrameSchema
|
|
8656
|
-
]);
|
|
8657
|
-
PersonaServerFrameSchema = external_exports.discriminatedUnion("kind", [
|
|
8658
|
-
PersonaReadyFrameSchema,
|
|
8659
|
-
PersonaHistoryEventFrameSchema,
|
|
8660
|
-
PersonaHistoryDoneFrameSchema,
|
|
8661
|
-
PersonaEventFrameSchema,
|
|
8662
|
-
PersonaErrorFrameSchema,
|
|
8663
|
-
PersonaPongFrameSchema
|
|
8664
|
-
]);
|
|
8665
8605
|
PersonaCreateArgsSchema = external_exports.object({
|
|
8666
8606
|
label: external_exports.string().min(1),
|
|
8667
8607
|
personality: external_exports.string(),
|
|
@@ -16644,8 +16584,9 @@ var SessionManager = class {
|
|
|
16644
16584
|
// 不进 SessionFile schema(避免破坏现有 zod parse),仅运行时缓存
|
|
16645
16585
|
subSessionMetaBySid = /* @__PURE__ */ new Map();
|
|
16646
16586
|
// persona-bound transport 订阅器:sessionId → Set<listener>。
|
|
16647
|
-
//
|
|
16648
|
-
//
|
|
16587
|
+
// 透传 owner 路径白名单 EventFrame(routeFromRunner 决定哪些 type 进入),listener 端按
|
|
16588
|
+
// `frame.type` narrow 出 'session:event'(ParsedEvent)/ 'session:status'(procAlive 同步)等。
|
|
16589
|
+
// 这样 owner / listener 共用同一组事件字面量,新增跨端信号时只需在 fan-out 白名单里加 type。
|
|
16649
16590
|
eventSubscribers = /* @__PURE__ */ new Map();
|
|
16650
16591
|
// 按 agentId 拿对应的 SessionStore;persona-* agentId 使用 personaRoot 路径。
|
|
16651
16592
|
// 'default' 直接复用 deps.store;其它 agentId 第一次访问时按需创建并缓存。
|
|
@@ -16700,15 +16641,14 @@ var SessionManager = class {
|
|
|
16700
16641
|
routeFromRunner(frame, target) {
|
|
16701
16642
|
const compressed = compressFrameForWire(frame);
|
|
16702
16643
|
if (!compressed) return;
|
|
16703
|
-
if (compressed.type === "session:event") {
|
|
16644
|
+
if (compressed.type === "session:event" || compressed.type === "session:status") {
|
|
16704
16645
|
const sid = compressed.sessionId;
|
|
16705
|
-
|
|
16706
|
-
if (sid && ev) {
|
|
16646
|
+
if (sid) {
|
|
16707
16647
|
const subs = this.eventSubscribers.get(sid);
|
|
16708
16648
|
if (subs && subs.size > 0) {
|
|
16709
16649
|
for (const fn of subs) {
|
|
16710
16650
|
try {
|
|
16711
|
-
fn(
|
|
16651
|
+
fn(compressed);
|
|
16712
16652
|
} catch {
|
|
16713
16653
|
}
|
|
16714
16654
|
}
|
|
@@ -17153,6 +17093,20 @@ var SessionManager = class {
|
|
|
17153
17093
|
getActive(sessionId) {
|
|
17154
17094
|
return this.runners.get(sessionId);
|
|
17155
17095
|
}
|
|
17096
|
+
/**
|
|
17097
|
+
* 拿当前 sub-session 的 wire 形态 status(已 compress:内部 reducer 'spawning' / 'running-idle' /
|
|
17098
|
+
* 'stopping' 等都压平)。无 runner 返回 'idle'(没 spawn 过)。
|
|
17099
|
+
*
|
|
17100
|
+
* 用途:listener 端 subscribe 时补推一次当前 status —— sessionManager.subscribe 注册的
|
|
17101
|
+
* callback 只接未来 emit,不重放当前 status;不补推则 listener 进入时如果 sub-session
|
|
17102
|
+
* 已 running,永远拿不到 procAlive 信号。owner 路径在 LocalWsServer.onSubscribe hook
|
|
17103
|
+
* 重放 pendingQuestions(同一思路)。
|
|
17104
|
+
*/
|
|
17105
|
+
getCurrentStatus(sessionId) {
|
|
17106
|
+
const runner = this.runners.get(sessionId);
|
|
17107
|
+
if (!runner) return "idle";
|
|
17108
|
+
return compressStatus(runner.getState().status);
|
|
17109
|
+
}
|
|
17156
17110
|
// 给 observer 用:保证有 runner 但不 spawn(仅创建 state 容器)
|
|
17157
17111
|
ensureSession(file) {
|
|
17158
17112
|
let r = this.runners.get(file.sessionId);
|
|
@@ -17239,7 +17193,35 @@ var SessionManager = class {
|
|
|
17239
17193
|
return runner.getState().buffer.map((e) => e.event);
|
|
17240
17194
|
}
|
|
17241
17195
|
/**
|
|
17242
|
-
* persona-bound transport
|
|
17196
|
+
* persona-bound transport 用:基于 readHistoryEvents 的 buffer 切片视图,支持分页。
|
|
17197
|
+
*
|
|
17198
|
+
* Why a new method instead of reusing `history:read` RPC handler:
|
|
17199
|
+
* - `history:read` 走 HandlerDeps.history.read(),读 CC 写盘的 jsonl 文件
|
|
17200
|
+
* - 本方法走 reducer buffer(与实时 `subscribe` 同一数据源)
|
|
17201
|
+
* 两条路径数据形态、时序、字段不同,不能共享 helper。persona-bound 客户端必须
|
|
17202
|
+
* 走 buffer 路径,才能保证首屏回放和实时帧无 gap、无重复。
|
|
17203
|
+
*
|
|
17204
|
+
* Why not 改 readHistoryEvents 加 limit/offset:现有 readHistoryEvents 的语义是
|
|
17205
|
+
* "返回 buffer 全部",被其它路径(rewind uuid 转译等)依赖;保留它不动,新加分页方法。
|
|
17206
|
+
*
|
|
17207
|
+
* 切片语义:clip 安全边界,response.offset 保留请求值便于客户端识别越界请求。
|
|
17208
|
+
* - offset >= total → events: [], offset: 请求值, total: 当前 buffer 长度
|
|
17209
|
+
* - offset + limit > total → 返回 tail [offset, total),长度 = total - offset
|
|
17210
|
+
* - 正常 → 返回 [offset, offset + limit)
|
|
17211
|
+
*
|
|
17212
|
+
* SESSION_NOT_FOUND 行为继承 readHistoryEvents(store.read 返回 null 即抛)。
|
|
17213
|
+
*/
|
|
17214
|
+
readHistoryPage(sessionId, agentId, limit, offset) {
|
|
17215
|
+
const all = this.readHistoryEvents(sessionId, agentId);
|
|
17216
|
+
const total = all.length;
|
|
17217
|
+
const start = Math.min(offset, total);
|
|
17218
|
+
const end = Math.min(start + limit, total);
|
|
17219
|
+
return { events: all.slice(start, end), offset, total };
|
|
17220
|
+
}
|
|
17221
|
+
/**
|
|
17222
|
+
* persona-bound transport 用:订阅 sub-session 的 owner-side EventFrame(白名单透传)。
|
|
17223
|
+
* 与 owner 路径共享同一组字面量,listener callback 拿到的 frame.type 当前可能是
|
|
17224
|
+
* 'session:event'(ParsedEvent 流)或 'session:status'(procAlive)。
|
|
17243
17225
|
* 返回 unsubscribe;不破坏现有 wire 广播路径——routeFromRunner 同时 fan-out 到
|
|
17244
17226
|
* eventSubscribers 和 deps.broadcastFrame
|
|
17245
17227
|
*/
|
|
@@ -18410,6 +18392,11 @@ var PersonaBoundHandler = class {
|
|
|
18410
18392
|
this.deps.logger.warn(`persona ws send failed: ${err.message}`);
|
|
18411
18393
|
}
|
|
18412
18394
|
};
|
|
18395
|
+
const sendError = (requestId, code, message) => {
|
|
18396
|
+
const errFrame = { type: "error", code, message };
|
|
18397
|
+
if (requestId) errFrame.requestId = requestId;
|
|
18398
|
+
send(errFrame);
|
|
18399
|
+
};
|
|
18413
18400
|
ws.on("message", (raw) => {
|
|
18414
18401
|
let parsedRaw;
|
|
18415
18402
|
try {
|
|
@@ -18418,18 +18405,19 @@ var PersonaBoundHandler = class {
|
|
|
18418
18405
|
ws.close(4400, "PROTOCOL_VIOLATION");
|
|
18419
18406
|
return;
|
|
18420
18407
|
}
|
|
18421
|
-
|
|
18422
|
-
if (!parseResult.success) {
|
|
18408
|
+
if (typeof parsedRaw !== "object" || parsedRaw === null) {
|
|
18423
18409
|
ws.close(4400, "PROTOCOL_VIOLATION");
|
|
18424
18410
|
return;
|
|
18425
18411
|
}
|
|
18426
|
-
const frame =
|
|
18412
|
+
const frame = parsedRaw;
|
|
18427
18413
|
if (!scope) {
|
|
18428
|
-
|
|
18414
|
+
const authParse = AuthRequestFrameSchema.safeParse(frame);
|
|
18415
|
+
if (!authParse.success) {
|
|
18429
18416
|
ws.close(4400, "PROTOCOL_VIOLATION");
|
|
18430
18417
|
return;
|
|
18431
18418
|
}
|
|
18432
|
-
const
|
|
18419
|
+
const { token } = authParse.data;
|
|
18420
|
+
const verify = this.deps.registry.verifyToken(personaId, token);
|
|
18433
18421
|
if (!verify.ok) {
|
|
18434
18422
|
const code = verify.code === "PERSONA_DELETED" ? 4404 : verify.code === "PERSONA_NOT_PUBLIC" ? 4403 : 4401;
|
|
18435
18423
|
ws.close(code, verify.code);
|
|
@@ -18444,7 +18432,7 @@ var PersonaBoundHandler = class {
|
|
|
18444
18432
|
try {
|
|
18445
18433
|
const { sessionFile } = this.deps.personaManager.getOrCreateSubSession(
|
|
18446
18434
|
personaId,
|
|
18447
|
-
|
|
18435
|
+
token
|
|
18448
18436
|
);
|
|
18449
18437
|
subSessionFile = sessionFile;
|
|
18450
18438
|
} catch (err) {
|
|
@@ -18455,69 +18443,127 @@ var PersonaBoundHandler = class {
|
|
|
18455
18443
|
return;
|
|
18456
18444
|
}
|
|
18457
18445
|
scope = { personaId, subSessionId: subSessionFile.sessionId };
|
|
18446
|
+
send({ type: "auth:ok" });
|
|
18458
18447
|
send({
|
|
18459
|
-
|
|
18460
|
-
|
|
18461
|
-
|
|
18448
|
+
type: "session:info",
|
|
18449
|
+
sessionId: subSessionFile.sessionId,
|
|
18450
|
+
label: persona.label,
|
|
18462
18451
|
cwd: this.deps.personaStore.personaDirPath(personaId),
|
|
18463
|
-
model: persona.model
|
|
18452
|
+
...persona.model ? { model: persona.model } : {}
|
|
18464
18453
|
});
|
|
18465
|
-
unsubscribe = this.deps.sessionManager.subscribe(
|
|
18466
|
-
subSessionFile.sessionId,
|
|
18467
|
-
personaId,
|
|
18468
|
-
(event) => {
|
|
18469
|
-
send({ kind: "event", event });
|
|
18470
|
-
}
|
|
18471
|
-
);
|
|
18472
|
-
try {
|
|
18473
|
-
const history = this.deps.sessionManager.readHistoryEvents(
|
|
18474
|
-
subSessionFile.sessionId,
|
|
18475
|
-
personaId
|
|
18476
|
-
);
|
|
18477
|
-
for (const event of history) {
|
|
18478
|
-
send({ kind: "history-event", event });
|
|
18479
|
-
}
|
|
18480
|
-
} catch (err) {
|
|
18481
|
-
this.deps.logger.warn(
|
|
18482
|
-
`persona history read failed: ${err.message}`
|
|
18483
|
-
);
|
|
18484
|
-
}
|
|
18485
|
-
send({ kind: "history-done" });
|
|
18486
18454
|
return;
|
|
18487
18455
|
}
|
|
18488
|
-
|
|
18489
|
-
|
|
18490
|
-
|
|
18456
|
+
const type = frame.type;
|
|
18457
|
+
const requestId = typeof frame.requestId === "string" ? frame.requestId : void 0;
|
|
18458
|
+
if (type === "auth") {
|
|
18459
|
+
ws.close(4400, "PROTOCOL_VIOLATION");
|
|
18460
|
+
return;
|
|
18461
|
+
}
|
|
18462
|
+
if (type === "ping") {
|
|
18463
|
+
send({ type: "pong", at: Date.now() });
|
|
18464
|
+
return;
|
|
18465
|
+
}
|
|
18466
|
+
const requireScopedSession = () => {
|
|
18467
|
+
if (frame.sessionId !== scope.subSessionId) {
|
|
18468
|
+
sendError(requestId, "FORBIDDEN", "sessionId out of scope");
|
|
18469
|
+
return false;
|
|
18470
|
+
}
|
|
18471
|
+
return true;
|
|
18472
|
+
};
|
|
18473
|
+
switch (type) {
|
|
18474
|
+
case "session:subscribe": {
|
|
18475
|
+
if (!requireScopedSession()) return;
|
|
18476
|
+
if (unsubscribe) unsubscribe();
|
|
18477
|
+
unsubscribe = this.deps.sessionManager.subscribe(
|
|
18478
|
+
scope.subSessionId,
|
|
18479
|
+
scope.personaId,
|
|
18480
|
+
(eventFrame) => send(eventFrame)
|
|
18481
|
+
);
|
|
18482
|
+
if (requestId)
|
|
18483
|
+
send({ type: "subscribed", requestId, sessionId: scope.subSessionId });
|
|
18484
|
+
const currentStatus = this.deps.sessionManager.getCurrentStatus(scope.subSessionId);
|
|
18485
|
+
send({
|
|
18486
|
+
type: "session:status",
|
|
18487
|
+
sessionId: scope.subSessionId,
|
|
18488
|
+
status: currentStatus
|
|
18489
|
+
});
|
|
18491
18490
|
return;
|
|
18492
|
-
|
|
18491
|
+
}
|
|
18492
|
+
case "session:unsubscribe": {
|
|
18493
|
+
if (!requireScopedSession()) return;
|
|
18494
|
+
if (unsubscribe) {
|
|
18495
|
+
unsubscribe();
|
|
18496
|
+
unsubscribe = null;
|
|
18497
|
+
}
|
|
18498
|
+
if (requestId) send({ type: "unsubscribed", requestId, sessionId: scope.subSessionId });
|
|
18499
|
+
return;
|
|
18500
|
+
}
|
|
18501
|
+
case "session:send": {
|
|
18502
|
+
if (!requireScopedSession()) return;
|
|
18503
|
+
const text = frame.text;
|
|
18504
|
+
if (typeof text !== "string") {
|
|
18505
|
+
sendError(requestId, "VALIDATION_ERROR", "text must be string");
|
|
18506
|
+
return;
|
|
18507
|
+
}
|
|
18493
18508
|
try {
|
|
18494
18509
|
this.deps.sessionManager.sendForAgent({
|
|
18495
18510
|
sessionId: scope.subSessionId,
|
|
18496
18511
|
agentId: scope.personaId,
|
|
18497
|
-
text
|
|
18512
|
+
text
|
|
18498
18513
|
});
|
|
18514
|
+
if (requestId) send({ type: "session:send", ok: true, requestId });
|
|
18499
18515
|
} catch (err) {
|
|
18500
|
-
|
|
18501
|
-
|
|
18502
|
-
);
|
|
18516
|
+
const e = err;
|
|
18517
|
+
sendError(requestId, e.code ?? "INTERNAL", e.message ?? String(err));
|
|
18503
18518
|
}
|
|
18504
18519
|
return;
|
|
18505
18520
|
}
|
|
18506
|
-
case "
|
|
18521
|
+
case "session:new": {
|
|
18522
|
+
if (!requireScopedSession()) return;
|
|
18507
18523
|
try {
|
|
18508
18524
|
this.deps.sessionManager.resetForAgent({
|
|
18509
18525
|
sessionId: scope.subSessionId,
|
|
18510
18526
|
agentId: scope.personaId
|
|
18511
18527
|
});
|
|
18528
|
+
if (requestId) send({ type: "session:info", sessionId: scope.subSessionId, requestId });
|
|
18512
18529
|
} catch (err) {
|
|
18513
|
-
|
|
18514
|
-
|
|
18530
|
+
const e = err;
|
|
18531
|
+
sendError(requestId, e.code ?? "INTERNAL", e.message ?? String(err));
|
|
18532
|
+
}
|
|
18533
|
+
return;
|
|
18534
|
+
}
|
|
18535
|
+
case "history:read": {
|
|
18536
|
+
if (!requireScopedSession()) return;
|
|
18537
|
+
const limit = typeof frame.limit === "number" && frame.limit > 0 ? frame.limit : 50;
|
|
18538
|
+
const offset = typeof frame.offset === "number" && frame.offset >= 0 ? frame.offset : 0;
|
|
18539
|
+
try {
|
|
18540
|
+
const page = this.deps.sessionManager.readHistoryPage(
|
|
18541
|
+
scope.subSessionId,
|
|
18542
|
+
scope.personaId,
|
|
18543
|
+
limit,
|
|
18544
|
+
offset
|
|
18515
18545
|
);
|
|
18546
|
+
if (requestId) {
|
|
18547
|
+
send({
|
|
18548
|
+
type: "history:read",
|
|
18549
|
+
requestId,
|
|
18550
|
+
events: page.events,
|
|
18551
|
+
offset,
|
|
18552
|
+
total: page.total
|
|
18553
|
+
});
|
|
18554
|
+
}
|
|
18555
|
+
} catch (err) {
|
|
18556
|
+
const e = err;
|
|
18557
|
+
sendError(requestId, e.code ?? "INTERNAL", e.message ?? String(err));
|
|
18516
18558
|
}
|
|
18517
18559
|
return;
|
|
18518
18560
|
}
|
|
18519
|
-
|
|
18520
|
-
|
|
18561
|
+
default:
|
|
18562
|
+
sendError(
|
|
18563
|
+
requestId,
|
|
18564
|
+
"METHOD_NOT_ALLOWED",
|
|
18565
|
+
`${typeof type === "string" ? type : "unknown"} not allowed for listener`
|
|
18566
|
+
);
|
|
18521
18567
|
return;
|
|
18522
18568
|
}
|
|
18523
18569
|
});
|
package/package.json
CHANGED