@clawos-dev/clawd 0.2.30 → 0.2.31
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 +125 -163
- 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,83 +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
|
-
offset: external_exports.number().int().nonnegative(),
|
|
8633
|
-
total: external_exports.number().int().nonnegative()
|
|
8634
|
-
});
|
|
8635
|
-
PersonaEventFrameSchema = external_exports.object({
|
|
8636
|
-
kind: external_exports.literal("event"),
|
|
8637
|
-
event: external_exports.unknown()
|
|
8638
|
-
});
|
|
8639
|
-
PersonaErrorFrameSchema = external_exports.object({
|
|
8640
|
-
kind: external_exports.literal("error"),
|
|
8641
|
-
code: external_exports.enum([
|
|
8642
|
-
"TOKEN_INVALID",
|
|
8643
|
-
"TOKEN_REVOKED",
|
|
8644
|
-
"PERSONA_DELETED",
|
|
8645
|
-
"PERSONA_NOT_PUBLIC",
|
|
8646
|
-
"INTERNAL"
|
|
8647
|
-
]),
|
|
8648
|
-
message: external_exports.string()
|
|
8649
|
-
});
|
|
8650
|
-
PersonaPongFrameSchema = external_exports.object({
|
|
8651
|
-
kind: external_exports.literal("pong")
|
|
8652
|
-
});
|
|
8653
|
-
PersonaHistoryPageRequestFrameSchema = external_exports.object({
|
|
8654
|
-
kind: external_exports.literal("history-page-request"),
|
|
8655
|
-
requestId: external_exports.string().min(1),
|
|
8656
|
-
limit: external_exports.number().int().positive(),
|
|
8657
|
-
offset: external_exports.number().int().nonnegative()
|
|
8658
|
-
});
|
|
8659
|
-
PersonaHistoryPageFrameSchema = external_exports.object({
|
|
8660
|
-
kind: external_exports.literal("history-page"),
|
|
8661
|
-
requestId: external_exports.string().min(1),
|
|
8662
|
-
events: external_exports.array(external_exports.unknown()),
|
|
8663
|
-
offset: external_exports.number().int().nonnegative(),
|
|
8664
|
-
total: external_exports.number().int().nonnegative()
|
|
8665
|
-
});
|
|
8666
|
-
PersonaClientFrameSchema = external_exports.discriminatedUnion("kind", [
|
|
8667
|
-
PersonaHelloFrameSchema,
|
|
8668
|
-
PersonaSendFrameSchema,
|
|
8669
|
-
PersonaResetFrameSchema,
|
|
8670
|
-
PersonaPingFrameSchema,
|
|
8671
|
-
PersonaHistoryPageRequestFrameSchema
|
|
8672
|
-
]);
|
|
8673
|
-
PersonaServerFrameSchema = external_exports.discriminatedUnion("kind", [
|
|
8674
|
-
PersonaReadyFrameSchema,
|
|
8675
|
-
PersonaHistoryEventFrameSchema,
|
|
8676
|
-
PersonaHistoryDoneFrameSchema,
|
|
8677
|
-
PersonaEventFrameSchema,
|
|
8678
|
-
PersonaErrorFrameSchema,
|
|
8679
|
-
PersonaPongFrameSchema,
|
|
8680
|
-
PersonaHistoryPageFrameSchema
|
|
8681
|
-
]);
|
|
8682
8605
|
PersonaCreateArgsSchema = external_exports.object({
|
|
8683
8606
|
label: external_exports.string().min(1),
|
|
8684
8607
|
personality: external_exports.string(),
|
|
@@ -16661,8 +16584,9 @@ var SessionManager = class {
|
|
|
16661
16584
|
// 不进 SessionFile schema(避免破坏现有 zod parse),仅运行时缓存
|
|
16662
16585
|
subSessionMetaBySid = /* @__PURE__ */ new Map();
|
|
16663
16586
|
// persona-bound transport 订阅器:sessionId → Set<listener>。
|
|
16664
|
-
//
|
|
16665
|
-
//
|
|
16587
|
+
// 透传 owner 路径白名单 EventFrame(routeFromRunner 决定哪些 type 进入),listener 端按
|
|
16588
|
+
// `frame.type` narrow 出 'session:event'(ParsedEvent)/ 'session:status'(procAlive 同步)等。
|
|
16589
|
+
// 这样 owner / listener 共用同一组事件字面量,新增跨端信号时只需在 fan-out 白名单里加 type。
|
|
16666
16590
|
eventSubscribers = /* @__PURE__ */ new Map();
|
|
16667
16591
|
// 按 agentId 拿对应的 SessionStore;persona-* agentId 使用 personaRoot 路径。
|
|
16668
16592
|
// 'default' 直接复用 deps.store;其它 agentId 第一次访问时按需创建并缓存。
|
|
@@ -16717,15 +16641,14 @@ var SessionManager = class {
|
|
|
16717
16641
|
routeFromRunner(frame, target) {
|
|
16718
16642
|
const compressed = compressFrameForWire(frame);
|
|
16719
16643
|
if (!compressed) return;
|
|
16720
|
-
if (compressed.type === "session:event") {
|
|
16644
|
+
if (compressed.type === "session:event" || compressed.type === "session:status") {
|
|
16721
16645
|
const sid = compressed.sessionId;
|
|
16722
|
-
|
|
16723
|
-
if (sid && ev) {
|
|
16646
|
+
if (sid) {
|
|
16724
16647
|
const subs = this.eventSubscribers.get(sid);
|
|
16725
16648
|
if (subs && subs.size > 0) {
|
|
16726
16649
|
for (const fn of subs) {
|
|
16727
16650
|
try {
|
|
16728
|
-
fn(
|
|
16651
|
+
fn(compressed);
|
|
16729
16652
|
} catch {
|
|
16730
16653
|
}
|
|
16731
16654
|
}
|
|
@@ -17170,6 +17093,20 @@ var SessionManager = class {
|
|
|
17170
17093
|
getActive(sessionId) {
|
|
17171
17094
|
return this.runners.get(sessionId);
|
|
17172
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
|
+
}
|
|
17173
17110
|
// 给 observer 用:保证有 runner 但不 spawn(仅创建 state 容器)
|
|
17174
17111
|
ensureSession(file) {
|
|
17175
17112
|
let r = this.runners.get(file.sessionId);
|
|
@@ -17282,7 +17219,9 @@ var SessionManager = class {
|
|
|
17282
17219
|
return { events: all.slice(start, end), offset, total };
|
|
17283
17220
|
}
|
|
17284
17221
|
/**
|
|
17285
|
-
* persona-bound transport 用:订阅 sub-session
|
|
17222
|
+
* persona-bound transport 用:订阅 sub-session 的 owner-side EventFrame(白名单透传)。
|
|
17223
|
+
* 与 owner 路径共享同一组字面量,listener callback 拿到的 frame.type 当前可能是
|
|
17224
|
+
* 'session:event'(ParsedEvent 流)或 'session:status'(procAlive)。
|
|
17286
17225
|
* 返回 unsubscribe;不破坏现有 wire 广播路径——routeFromRunner 同时 fan-out 到
|
|
17287
17226
|
* eventSubscribers 和 deps.broadcastFrame
|
|
17288
17227
|
*/
|
|
@@ -18453,6 +18392,11 @@ var PersonaBoundHandler = class {
|
|
|
18453
18392
|
this.deps.logger.warn(`persona ws send failed: ${err.message}`);
|
|
18454
18393
|
}
|
|
18455
18394
|
};
|
|
18395
|
+
const sendError = (requestId, code, message) => {
|
|
18396
|
+
const errFrame = { type: "error", code, message };
|
|
18397
|
+
if (requestId) errFrame.requestId = requestId;
|
|
18398
|
+
send(errFrame);
|
|
18399
|
+
};
|
|
18456
18400
|
ws.on("message", (raw) => {
|
|
18457
18401
|
let parsedRaw;
|
|
18458
18402
|
try {
|
|
@@ -18461,18 +18405,19 @@ var PersonaBoundHandler = class {
|
|
|
18461
18405
|
ws.close(4400, "PROTOCOL_VIOLATION");
|
|
18462
18406
|
return;
|
|
18463
18407
|
}
|
|
18464
|
-
|
|
18465
|
-
if (!parseResult.success) {
|
|
18408
|
+
if (typeof parsedRaw !== "object" || parsedRaw === null) {
|
|
18466
18409
|
ws.close(4400, "PROTOCOL_VIOLATION");
|
|
18467
18410
|
return;
|
|
18468
18411
|
}
|
|
18469
|
-
const frame =
|
|
18412
|
+
const frame = parsedRaw;
|
|
18470
18413
|
if (!scope) {
|
|
18471
|
-
|
|
18414
|
+
const authParse = AuthRequestFrameSchema.safeParse(frame);
|
|
18415
|
+
if (!authParse.success) {
|
|
18472
18416
|
ws.close(4400, "PROTOCOL_VIOLATION");
|
|
18473
18417
|
return;
|
|
18474
18418
|
}
|
|
18475
|
-
const
|
|
18419
|
+
const { token } = authParse.data;
|
|
18420
|
+
const verify = this.deps.registry.verifyToken(personaId, token);
|
|
18476
18421
|
if (!verify.ok) {
|
|
18477
18422
|
const code = verify.code === "PERSONA_DELETED" ? 4404 : verify.code === "PERSONA_NOT_PUBLIC" ? 4403 : 4401;
|
|
18478
18423
|
ws.close(code, verify.code);
|
|
@@ -18487,7 +18432,7 @@ var PersonaBoundHandler = class {
|
|
|
18487
18432
|
try {
|
|
18488
18433
|
const { sessionFile } = this.deps.personaManager.getOrCreateSubSession(
|
|
18489
18434
|
personaId,
|
|
18490
|
-
|
|
18435
|
+
token
|
|
18491
18436
|
);
|
|
18492
18437
|
subSessionFile = sessionFile;
|
|
18493
18438
|
} catch (err) {
|
|
@@ -18498,111 +18443,128 @@ var PersonaBoundHandler = class {
|
|
|
18498
18443
|
return;
|
|
18499
18444
|
}
|
|
18500
18445
|
scope = { personaId, subSessionId: subSessionFile.sessionId };
|
|
18446
|
+
send({ type: "auth:ok" });
|
|
18501
18447
|
send({
|
|
18502
|
-
|
|
18503
|
-
|
|
18504
|
-
|
|
18448
|
+
type: "session:info",
|
|
18449
|
+
sessionId: subSessionFile.sessionId,
|
|
18450
|
+
label: persona.label,
|
|
18505
18451
|
cwd: this.deps.personaStore.personaDirPath(personaId),
|
|
18506
|
-
model: persona.model
|
|
18507
|
-
});
|
|
18508
|
-
unsubscribe = this.deps.sessionManager.subscribe(
|
|
18509
|
-
subSessionFile.sessionId,
|
|
18510
|
-
personaId,
|
|
18511
|
-
(event) => {
|
|
18512
|
-
send({ kind: "event", event });
|
|
18513
|
-
}
|
|
18514
|
-
);
|
|
18515
|
-
const FIRST_PAGE_SIZE = 50;
|
|
18516
|
-
let firstPageOffset = 0;
|
|
18517
|
-
let firstPageTotal = 0;
|
|
18518
|
-
try {
|
|
18519
|
-
const page = this.deps.sessionManager.readHistoryPage(
|
|
18520
|
-
subSessionFile.sessionId,
|
|
18521
|
-
personaId,
|
|
18522
|
-
FIRST_PAGE_SIZE,
|
|
18523
|
-
0
|
|
18524
|
-
);
|
|
18525
|
-
for (const event of page.events) {
|
|
18526
|
-
send({ kind: "history-event", event });
|
|
18527
|
-
}
|
|
18528
|
-
firstPageOffset = page.events.length;
|
|
18529
|
-
firstPageTotal = page.total;
|
|
18530
|
-
} catch (err) {
|
|
18531
|
-
this.deps.logger.warn(
|
|
18532
|
-
`persona history read failed: ${err.message}`
|
|
18533
|
-
);
|
|
18534
|
-
}
|
|
18535
|
-
send({
|
|
18536
|
-
kind: "history-done",
|
|
18537
|
-
offset: firstPageOffset,
|
|
18538
|
-
total: firstPageTotal
|
|
18452
|
+
...persona.model ? { model: persona.model } : {}
|
|
18539
18453
|
});
|
|
18540
18454
|
return;
|
|
18541
18455
|
}
|
|
18542
|
-
|
|
18543
|
-
|
|
18544
|
-
|
|
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
|
+
});
|
|
18545
18490
|
return;
|
|
18546
|
-
|
|
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
|
+
}
|
|
18547
18508
|
try {
|
|
18548
18509
|
this.deps.sessionManager.sendForAgent({
|
|
18549
18510
|
sessionId: scope.subSessionId,
|
|
18550
18511
|
agentId: scope.personaId,
|
|
18551
|
-
text
|
|
18512
|
+
text
|
|
18552
18513
|
});
|
|
18514
|
+
if (requestId) send({ type: "session:send", ok: true, requestId });
|
|
18553
18515
|
} catch (err) {
|
|
18554
|
-
|
|
18555
|
-
|
|
18556
|
-
);
|
|
18516
|
+
const e = err;
|
|
18517
|
+
sendError(requestId, e.code ?? "INTERNAL", e.message ?? String(err));
|
|
18557
18518
|
}
|
|
18558
18519
|
return;
|
|
18559
18520
|
}
|
|
18560
|
-
case "
|
|
18521
|
+
case "session:new": {
|
|
18522
|
+
if (!requireScopedSession()) return;
|
|
18561
18523
|
try {
|
|
18562
18524
|
this.deps.sessionManager.resetForAgent({
|
|
18563
18525
|
sessionId: scope.subSessionId,
|
|
18564
18526
|
agentId: scope.personaId
|
|
18565
18527
|
});
|
|
18528
|
+
if (requestId) send({ type: "session:info", sessionId: scope.subSessionId, requestId });
|
|
18566
18529
|
} catch (err) {
|
|
18567
|
-
|
|
18568
|
-
|
|
18569
|
-
);
|
|
18530
|
+
const e = err;
|
|
18531
|
+
sendError(requestId, e.code ?? "INTERNAL", e.message ?? String(err));
|
|
18570
18532
|
}
|
|
18571
18533
|
return;
|
|
18572
18534
|
}
|
|
18573
|
-
case "
|
|
18574
|
-
|
|
18575
|
-
|
|
18576
|
-
|
|
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;
|
|
18577
18539
|
try {
|
|
18578
18540
|
const page = this.deps.sessionManager.readHistoryPage(
|
|
18579
18541
|
scope.subSessionId,
|
|
18580
18542
|
scope.personaId,
|
|
18581
|
-
|
|
18582
|
-
|
|
18543
|
+
limit,
|
|
18544
|
+
offset
|
|
18583
18545
|
);
|
|
18584
|
-
|
|
18585
|
-
|
|
18586
|
-
|
|
18587
|
-
|
|
18588
|
-
|
|
18589
|
-
|
|
18590
|
-
|
|
18591
|
-
|
|
18546
|
+
if (requestId) {
|
|
18547
|
+
send({
|
|
18548
|
+
type: "history:read",
|
|
18549
|
+
requestId,
|
|
18550
|
+
events: page.events,
|
|
18551
|
+
offset,
|
|
18552
|
+
total: page.total
|
|
18553
|
+
});
|
|
18554
|
+
}
|
|
18592
18555
|
} catch (err) {
|
|
18593
|
-
|
|
18594
|
-
|
|
18595
|
-
);
|
|
18596
|
-
send({
|
|
18597
|
-
kind: "history-page",
|
|
18598
|
-
requestId: frame.requestId,
|
|
18599
|
-
events: [],
|
|
18600
|
-
offset: frame.offset,
|
|
18601
|
-
total: 0
|
|
18602
|
-
});
|
|
18556
|
+
const e = err;
|
|
18557
|
+
sendError(requestId, e.code ?? "INTERNAL", e.message ?? String(err));
|
|
18603
18558
|
}
|
|
18604
18559
|
return;
|
|
18605
18560
|
}
|
|
18561
|
+
default:
|
|
18562
|
+
sendError(
|
|
18563
|
+
requestId,
|
|
18564
|
+
"METHOD_NOT_ALLOWED",
|
|
18565
|
+
`${typeof type === "string" ? type : "unknown"} not allowed for listener`
|
|
18566
|
+
);
|
|
18567
|
+
return;
|
|
18606
18568
|
}
|
|
18607
18569
|
});
|
|
18608
18570
|
ws.on("close", () => {
|