@clawos-dev/clawd 0.2.601 → 0.2.603
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 +297 -125
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -64276,6 +64276,8 @@ var GATEWAY_ROUTES = {
|
|
|
64276
64276
|
session: (personaId2) => `/p/${encodeURIComponent(personaId2)}/session`,
|
|
64277
64277
|
sessionSend: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/${encodeURIComponent(sessionId)}`,
|
|
64278
64278
|
sessionMirror: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/${encodeURIComponent(sessionId)}/mirror`,
|
|
64279
|
+
eventSession: (personaId2) => `/p/${encodeURIComponent(personaId2)}/session/events`,
|
|
64280
|
+
eventSend: (personaId2, sessionId) => `/p/${encodeURIComponent(personaId2)}/session/events/${encodeURIComponent(sessionId)}`,
|
|
64279
64281
|
// 调用方自己那块盘的用量(design 2026-09-19-cloud-volume-usage §3.3):同样按人、不挂 persona
|
|
64280
64282
|
volume: () => "/me/volume",
|
|
64281
64283
|
// 云 persona 运行看板的数据(design 2026-09-23-cloud-persona-metrics §3.6):只给发布者与管理员(gateway 问中心,design 2026-09-24-cloud-persona-conversations §3.2)
|
|
@@ -64396,6 +64398,22 @@ var CloudGatewayClient = class {
|
|
|
64396
64398
|
logger: this.deps.logger
|
|
64397
64399
|
});
|
|
64398
64400
|
}
|
|
64401
|
+
async openEventSession(personaId2, opts) {
|
|
64402
|
+
const { apiKey, gatewayUrl } = await this.credentials();
|
|
64403
|
+
return openHttpEventSession({
|
|
64404
|
+
fetchImpl: this.fetchImpl,
|
|
64405
|
+
gatewayUrl,
|
|
64406
|
+
apiKey,
|
|
64407
|
+
personaId: personaId2,
|
|
64408
|
+
engineSessionId: opts.toolSessionId,
|
|
64409
|
+
instructions: opts.instructions,
|
|
64410
|
+
purpose: opts.purpose,
|
|
64411
|
+
expectedEngine: opts.expectedEngine,
|
|
64412
|
+
effort: opts.effort,
|
|
64413
|
+
personaMode: opts.personaMode,
|
|
64414
|
+
logger: this.deps.logger
|
|
64415
|
+
});
|
|
64416
|
+
}
|
|
64399
64417
|
/**
|
|
64400
64418
|
* 看板数据(design 2026-09-23-cloud-persona-metrics §3.8):GET /metrics/<persona>?window&entry,**原样回**状态码与 body——
|
|
64401
64419
|
* 形状真源在 gateway 的 cloud-persona-metrics,daemon 只是替浏览器拿本机 api key 转一跳。拿不到 key / 连不上 / 超时 → 抛(路由折成 502)。
|
|
@@ -64433,6 +64451,149 @@ var CloudGatewayClient = class {
|
|
|
64433
64451
|
return CloudVolumeUsageSchema.parse(body.volume);
|
|
64434
64452
|
}
|
|
64435
64453
|
};
|
|
64454
|
+
function openHttpEventSession(opts) {
|
|
64455
|
+
const { fetchImpl, gatewayUrl, apiKey, personaId: personaId2, engineSessionId, instructions, purpose, effort, personaMode, expectedEngine, logger } = opts;
|
|
64456
|
+
const headers = { authorization: `Bearer ${apiKey}`, "content-type": "application/json" };
|
|
64457
|
+
const abort = new AbortController();
|
|
64458
|
+
const eventCbs = [];
|
|
64459
|
+
const controlCbs = [];
|
|
64460
|
+
const closeCbs = [];
|
|
64461
|
+
const earlyEvents = [];
|
|
64462
|
+
const earlyControls = [];
|
|
64463
|
+
let closed = false;
|
|
64464
|
+
let readyControl = null;
|
|
64465
|
+
let errorControl = null;
|
|
64466
|
+
let sessionId = null;
|
|
64467
|
+
let resolveReady;
|
|
64468
|
+
let rejectReady;
|
|
64469
|
+
const ready = new Promise((resolve9, reject) => {
|
|
64470
|
+
resolveReady = resolve9;
|
|
64471
|
+
rejectReady = reject;
|
|
64472
|
+
});
|
|
64473
|
+
void ready.catch(() => {
|
|
64474
|
+
});
|
|
64475
|
+
let sendChain = Promise.resolve();
|
|
64476
|
+
const emitControl = (control) => {
|
|
64477
|
+
if (control.kind === "ready") readyControl = control;
|
|
64478
|
+
if (control.kind === "error") errorControl = control;
|
|
64479
|
+
if (!controlCbs.length) earlyControls.push(control);
|
|
64480
|
+
for (const cb of controlCbs) cb(control);
|
|
64481
|
+
};
|
|
64482
|
+
const finish = (message) => {
|
|
64483
|
+
if (closed) return;
|
|
64484
|
+
if (message) emitControl({ kind: "error", message });
|
|
64485
|
+
closed = true;
|
|
64486
|
+
rejectReady(new Error(message ?? "event session closed"));
|
|
64487
|
+
abort.abort();
|
|
64488
|
+
for (const cb of closeCbs) cb();
|
|
64489
|
+
};
|
|
64490
|
+
void (async () => {
|
|
64491
|
+
try {
|
|
64492
|
+
const res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventSession(personaId2), {
|
|
64493
|
+
method: "POST",
|
|
64494
|
+
headers,
|
|
64495
|
+
body: JSON.stringify({ expectedEngine, ...engineSessionId ? { engineSessionId } : {}, ...instructions ? { instructions } : {}, ...purpose ? { purpose } : {}, ...effort ? { effort } : {}, ...personaMode ? { personaMode } : {} }),
|
|
64496
|
+
signal: abort.signal
|
|
64497
|
+
});
|
|
64498
|
+
if (!res.ok || !res.body) {
|
|
64499
|
+
let message = `gateway \u56DE ${res.status}`;
|
|
64500
|
+
try {
|
|
64501
|
+
const body = await res.json();
|
|
64502
|
+
if (typeof body.message === "string") message = body.message;
|
|
64503
|
+
if (body.error === "SESSION_VERSION_EXPIRED" && !message.includes("SESSION_VERSION_EXPIRED")) message = `SESSION_VERSION_EXPIRED: ${message}`;
|
|
64504
|
+
} catch {
|
|
64505
|
+
}
|
|
64506
|
+
finish(message);
|
|
64507
|
+
return;
|
|
64508
|
+
}
|
|
64509
|
+
const reader = res.body.getReader();
|
|
64510
|
+
const decoder = new TextDecoder();
|
|
64511
|
+
let pending = "";
|
|
64512
|
+
for (; ; ) {
|
|
64513
|
+
const { value, done } = await reader.read();
|
|
64514
|
+
if (done) break;
|
|
64515
|
+
pending += decoder.decode(value, { stream: true });
|
|
64516
|
+
const lines = pending.split("\n");
|
|
64517
|
+
pending = lines.pop() ?? "";
|
|
64518
|
+
for (const line of lines) {
|
|
64519
|
+
if (!line.trim()) continue;
|
|
64520
|
+
const data = JSON.parse(line);
|
|
64521
|
+
if (data.clawd === "events") {
|
|
64522
|
+
const events = ParsedEventSchema.array().parse(data.events);
|
|
64523
|
+
if (!eventCbs.length) earlyEvents.push(events);
|
|
64524
|
+
for (const cb of eventCbs) cb(events);
|
|
64525
|
+
continue;
|
|
64526
|
+
}
|
|
64527
|
+
const control = parseControlLine(line);
|
|
64528
|
+
if (!control) throw new Error("gateway event stream contains an unknown line");
|
|
64529
|
+
if (control.kind === "ready") {
|
|
64530
|
+
if (!control.session) throw new Error("gateway ready line has no session id");
|
|
64531
|
+
if (control.engine !== expectedEngine) {
|
|
64532
|
+
finish(control.engine ? `SESSION_VERSION_EXPIRED: \u5F53\u524D Pod \u662F ${control.engine}\uFF0C\u8FD9\u6761\u4F1A\u8BDD\u9700\u8981 ${expectedEngine}` : "gateway \u7684 ready \u63A7\u5236\u884C\u6CA1\u5E26 engine\uFF0Cgateway \u592A\u8001\uFF0C\u5148\u5347 gateway");
|
|
64533
|
+
return;
|
|
64534
|
+
}
|
|
64535
|
+
sessionId = control.session;
|
|
64536
|
+
resolveReady();
|
|
64537
|
+
}
|
|
64538
|
+
emitControl(control);
|
|
64539
|
+
if (control.kind === "error") {
|
|
64540
|
+
finish();
|
|
64541
|
+
return;
|
|
64542
|
+
}
|
|
64543
|
+
}
|
|
64544
|
+
}
|
|
64545
|
+
finish();
|
|
64546
|
+
} catch (e) {
|
|
64547
|
+
if (!closed) {
|
|
64548
|
+
logger?.warn("cloud event stream failed", { message: e.message });
|
|
64549
|
+
finish(`\u4E91\u4E0A\u4E8B\u4EF6\u901A\u9053\u51FA\u9519\uFF1A${e.message}`);
|
|
64550
|
+
}
|
|
64551
|
+
}
|
|
64552
|
+
})();
|
|
64553
|
+
return {
|
|
64554
|
+
send(command) {
|
|
64555
|
+
const next = sendChain.then(async () => {
|
|
64556
|
+
await ready;
|
|
64557
|
+
if (closed || !sessionId) throw new Error("event session closed");
|
|
64558
|
+
const res = await fetchImpl(gatewayUrl + GATEWAY_ROUTES.eventSend(personaId2, sessionId), { method: "POST", headers, body: JSON.stringify(command) });
|
|
64559
|
+
if (!res.ok) {
|
|
64560
|
+
let message = `gateway \u56DE ${res.status}`;
|
|
64561
|
+
try {
|
|
64562
|
+
const body = await res.json();
|
|
64563
|
+
if (typeof body.message === "string") message = body.message;
|
|
64564
|
+
} catch {
|
|
64565
|
+
}
|
|
64566
|
+
finish(message);
|
|
64567
|
+
throw new Error(message);
|
|
64568
|
+
}
|
|
64569
|
+
});
|
|
64570
|
+
sendChain = next.catch(() => {
|
|
64571
|
+
});
|
|
64572
|
+
return next;
|
|
64573
|
+
},
|
|
64574
|
+
onEvents(cb) {
|
|
64575
|
+
const first = !eventCbs.length;
|
|
64576
|
+
eventCbs.push(cb);
|
|
64577
|
+
if (first) for (const events of earlyEvents.splice(0)) cb(events);
|
|
64578
|
+
},
|
|
64579
|
+
onControl(cb) {
|
|
64580
|
+
const first = !controlCbs.length;
|
|
64581
|
+
controlCbs.push(cb);
|
|
64582
|
+
if (first) for (const control of earlyControls.splice(0)) cb(control);
|
|
64583
|
+
else {
|
|
64584
|
+
if (readyControl) cb(readyControl);
|
|
64585
|
+
if (errorControl) cb(errorControl);
|
|
64586
|
+
}
|
|
64587
|
+
},
|
|
64588
|
+
onClose(cb) {
|
|
64589
|
+
closeCbs.push(cb);
|
|
64590
|
+
if (closed) cb();
|
|
64591
|
+
},
|
|
64592
|
+
close() {
|
|
64593
|
+
finish();
|
|
64594
|
+
}
|
|
64595
|
+
};
|
|
64596
|
+
}
|
|
64436
64597
|
function parseControlLine(line) {
|
|
64437
64598
|
let o2;
|
|
64438
64599
|
try {
|
|
@@ -64653,54 +64814,26 @@ init_protocol();
|
|
|
64653
64814
|
|
|
64654
64815
|
// src/tools/codex-cloud-session.ts
|
|
64655
64816
|
var import_node_fs38 = __toESM(require("fs"), 1);
|
|
64656
|
-
|
|
64657
|
-
|
|
64658
|
-
|
|
64659
|
-
|
|
64660
|
-
|
|
64661
|
-
|
|
64662
|
-
|
|
64663
|
-
|
|
64664
|
-
|
|
64665
|
-
|
|
64666
|
-
|
|
64667
|
-
|
|
64668
|
-
|
|
64669
|
-
|
|
64670
|
-
|
|
64671
|
-
}
|
|
64672
|
-
return
|
|
64673
|
-
attach(t2) {
|
|
64674
|
-
if (closed) {
|
|
64675
|
-
t2.close();
|
|
64676
|
-
return;
|
|
64677
|
-
}
|
|
64678
|
-
target = t2;
|
|
64679
|
-
t2.onLine((l2) => {
|
|
64680
|
-
for (const cb of lineCbs) cb(l2);
|
|
64681
|
-
});
|
|
64682
|
-
t2.onClose(finish);
|
|
64683
|
-
for (const line of pending.splice(0)) t2.write(line);
|
|
64684
|
-
},
|
|
64685
|
-
write(line) {
|
|
64686
|
-
if (closed) return;
|
|
64687
|
-
if (target) target.write(line);
|
|
64688
|
-
else pending.push(line);
|
|
64689
|
-
},
|
|
64690
|
-
onLine(cb) {
|
|
64691
|
-
lineCbs.push(cb);
|
|
64692
|
-
},
|
|
64693
|
-
onClose(cb) {
|
|
64694
|
-
closeCbs.push(cb);
|
|
64695
|
-
if (closed) cb();
|
|
64696
|
-
},
|
|
64697
|
-
close() {
|
|
64698
|
-
if (closed) return;
|
|
64699
|
-
target?.close();
|
|
64700
|
-
finish();
|
|
64701
|
-
}
|
|
64702
|
-
};
|
|
64817
|
+
|
|
64818
|
+
// src/tools/cloud-portable-input.ts
|
|
64819
|
+
async function portableCloudInput(text, resolvers) {
|
|
64820
|
+
const markers = [...text.matchAll(/\[attachment:image:(https?:\/\/[^\]]+)\]/g)];
|
|
64821
|
+
let result = text;
|
|
64822
|
+
for (const match of markers) {
|
|
64823
|
+
const url = match[1];
|
|
64824
|
+
let dataUrl;
|
|
64825
|
+
const codex = resolvers.resolveCodexImage?.(url);
|
|
64826
|
+
if (codex?.type === "image" && codex.url.startsWith("data:")) dataUrl = codex.url;
|
|
64827
|
+
if (!dataUrl && resolvers.fetchPiImage) {
|
|
64828
|
+
const pi = await resolvers.fetchPiImage(url).catch(() => null);
|
|
64829
|
+
if (pi) dataUrl = `data:${pi.mimeType};base64,${pi.data}`;
|
|
64830
|
+
}
|
|
64831
|
+
if (dataUrl) result = result.replace(match[0], `[attachment:image:${dataUrl}]`);
|
|
64832
|
+
}
|
|
64833
|
+
return result;
|
|
64703
64834
|
}
|
|
64835
|
+
|
|
64836
|
+
// src/tools/codex-cloud-session.ts
|
|
64704
64837
|
function cloudImageInput(deps) {
|
|
64705
64838
|
return (url) => {
|
|
64706
64839
|
const secret = deps.getSignSecret?.();
|
|
@@ -64719,73 +64852,84 @@ function cloudImageInput(deps) {
|
|
|
64719
64852
|
}
|
|
64720
64853
|
function createCloudCodexSession(ctx, sink, deps) {
|
|
64721
64854
|
const personaId2 = personaIdFromCloudCwd(ctx.cwd);
|
|
64722
|
-
const stream = deferredLineStream();
|
|
64723
|
-
let resolvePaths;
|
|
64724
|
-
let rejectPaths;
|
|
64725
|
-
const paths = new Promise((resolve9, reject) => {
|
|
64726
|
-
resolvePaths = resolve9;
|
|
64727
|
-
rejectPaths = reject;
|
|
64728
|
-
});
|
|
64729
|
-
paths.catch(() => {
|
|
64730
|
-
});
|
|
64731
|
-
stream.onClose(() => rejectPaths(new Error("\u4E91\u4E0A\u901A\u9053\u5728 ready \u4E4B\u524D\u5173\u4E86\uFF0C\u62FF\u4E0D\u5230 Pod \u8DEF\u5F84")));
|
|
64732
64855
|
let channel = null;
|
|
64733
|
-
|
|
64734
|
-
|
|
64735
|
-
|
|
64736
|
-
|
|
64737
|
-
|
|
64738
|
-
|
|
64739
|
-
|
|
64740
|
-
|
|
64741
|
-
if (!ctx.toolSessionId || p3.model) return params;
|
|
64742
|
-
const config = await client.request("config/read", {});
|
|
64743
|
-
if (config?.config?.model) return { ...params, model: config.config.model };
|
|
64744
|
-
const list = await client.request("model/list", {});
|
|
64745
|
-
const selected = list?.data?.find((m3) => m3.isDefault);
|
|
64746
|
-
const current = selected?.id || selected?.model;
|
|
64747
|
-
if (!current) throw new Error("\u65E0\u6CD5\u786E\u5B9A\u5F53\u524D Codex \u9ED8\u8BA4\u6A21\u578B\uFF0C\u62D2\u7EDD\u6CBF\u7528\u65E7\u4F1A\u8BDD\u6A21\u578B");
|
|
64748
|
-
return { ...params, model: current };
|
|
64749
|
-
},
|
|
64750
|
-
imageInput: cloudImageInput(deps),
|
|
64751
|
-
// skills 在 Pod 里由 persona 目录自带,本机路径对它没意义
|
|
64752
|
-
// 「让对端走人」= 断开下行流,gateway 收到就删 Job;信号对 Pod 没有意义
|
|
64753
|
-
kill: () => stream.close(),
|
|
64754
|
-
// 云 persona 运行看板(design 2026-09-23-cloud-persona-metrics §3.7):提问那一行带「一轮开始」头,轮末镜像顺带报这一轮的结果
|
|
64755
|
-
onTurnStarting: () => channel?.markNextLineTurnStart(),
|
|
64756
|
-
// 轮末镜像带上这一轮的结果与首字节(design 2026-09-23-cloud-persona-metrics §3.7)
|
|
64757
|
-
onTurnCompleted: (outcome, afterFirstByteMs) => {
|
|
64758
|
-
if (!ctx.titleOnly) void channel?.mirror({ outcome, ...afterFirstByteMs !== void 0 ? { afterFirstByteMs } : {} });
|
|
64759
|
-
},
|
|
64760
|
-
now: deps.now
|
|
64761
|
-
});
|
|
64856
|
+
let closed = false;
|
|
64857
|
+
let exited = false;
|
|
64858
|
+
const exit = () => {
|
|
64859
|
+
if (!exited) {
|
|
64860
|
+
exited = true;
|
|
64861
|
+
sink.onExit(null);
|
|
64862
|
+
}
|
|
64863
|
+
};
|
|
64762
64864
|
if (!personaId2) {
|
|
64763
64865
|
queueMicrotask(() => {
|
|
64764
64866
|
sink.onError(`cloud session has no persona id (cwd=${ctx.cwd})`);
|
|
64765
|
-
|
|
64867
|
+
exit();
|
|
64766
64868
|
});
|
|
64767
|
-
return
|
|
64768
|
-
|
|
64769
|
-
|
|
64770
|
-
(
|
|
64771
|
-
|
|
64869
|
+
return { startTurn() {
|
|
64870
|
+
}, respondPermission() {
|
|
64871
|
+
}, interrupt() {
|
|
64872
|
+
}, async stop() {
|
|
64873
|
+
} };
|
|
64874
|
+
}
|
|
64875
|
+
const opened = deps.client.openEventSession(personaId2, {
|
|
64876
|
+
expectedEngine: "codex",
|
|
64877
|
+
...ctx.toolSessionId ? { toolSessionId: ctx.toolSessionId } : {},
|
|
64878
|
+
...ctx.extraSystemPrompt ? { instructions: ctx.extraSystemPrompt } : {},
|
|
64879
|
+
...ctx.effort ? { effort: ctx.effort } : {},
|
|
64880
|
+
...ctx.personaMode ? { personaMode: ctx.personaMode } : {},
|
|
64881
|
+
...ctx.titleOnly ? { purpose: "title" } : {}
|
|
64882
|
+
}).then(
|
|
64883
|
+
(opened2) => {
|
|
64884
|
+
channel = opened2;
|
|
64885
|
+
channel.onEvents((events) => sink.pushEvents(events));
|
|
64772
64886
|
channel.onControl((c2) => {
|
|
64773
|
-
if (c2.kind === "
|
|
64774
|
-
resolvePaths({ personaDir: c2.personaDir, workDir: c2.workDir, model: c2.model });
|
|
64775
|
-
} else if (c2.kind === "queued") {
|
|
64887
|
+
if (c2.kind === "queued") {
|
|
64776
64888
|
sink.pushEvents([{ kind: "meta-text", text: `\u4E91\u4E0A\u673A\u5668\u6709 ${c2.running} \u4E2A\u4EFB\u52A1\u5728\u8DD1\uFF0C\u7B49\u4E00\u4E2A\u7ED3\u675F\u5C31\u8F6E\u5230\u4F60` }]);
|
|
64777
64889
|
} else if (c2.kind === "error") {
|
|
64778
64890
|
sink.onError(`\u4E91\u4E0A persona \u8D77\u4E0D\u6765\uFF1A${c2.message}`);
|
|
64779
64891
|
}
|
|
64780
64892
|
});
|
|
64781
|
-
|
|
64893
|
+
channel.onClose(exit);
|
|
64894
|
+
if (closed) channel.close();
|
|
64895
|
+
return channel;
|
|
64782
64896
|
},
|
|
64783
64897
|
(e) => {
|
|
64784
64898
|
sink.onError(e instanceof CloudApiKeyRequiredError ? e.message : `\u8FDE\u4E0D\u4E0A\u4E91 gateway\uFF1A${e.message}`);
|
|
64785
|
-
|
|
64899
|
+
exit();
|
|
64900
|
+
throw e;
|
|
64786
64901
|
}
|
|
64787
64902
|
);
|
|
64788
|
-
|
|
64903
|
+
void opened.catch(() => {
|
|
64904
|
+
});
|
|
64905
|
+
let sendChain = Promise.resolve();
|
|
64906
|
+
const send2 = (command) => {
|
|
64907
|
+
sendChain = sendChain.then(command).catch((e) => {
|
|
64908
|
+
if (!closed && !exited) sink.onError(`\u4E91\u4E0A\u4F1A\u8BDD\u4E0A\u884C\u5931\u8D25\uFF1A${e.message}`);
|
|
64909
|
+
});
|
|
64910
|
+
};
|
|
64911
|
+
return {
|
|
64912
|
+
startTurn(text) {
|
|
64913
|
+
send2(async () => {
|
|
64914
|
+
const ch = await opened;
|
|
64915
|
+
if (closed) return;
|
|
64916
|
+
const portable = await portableCloudInput(text, { resolveCodexImage: cloudImageInput(deps) });
|
|
64917
|
+
await ch.send({ command: "turn", text: portable });
|
|
64918
|
+
});
|
|
64919
|
+
},
|
|
64920
|
+
respondPermission(requestId, allow) {
|
|
64921
|
+
send2(async () => (await opened).send({ command: "permission", requestId, allow }));
|
|
64922
|
+
},
|
|
64923
|
+
interrupt() {
|
|
64924
|
+
send2(async () => (await opened).send({ command: "interrupt" }));
|
|
64925
|
+
},
|
|
64926
|
+
async stop() {
|
|
64927
|
+
closed = true;
|
|
64928
|
+
const ch = await opened.catch(() => null);
|
|
64929
|
+
ch?.close();
|
|
64930
|
+
exit();
|
|
64931
|
+
}
|
|
64932
|
+
};
|
|
64789
64933
|
}
|
|
64790
64934
|
|
|
64791
64935
|
// src/tools/codex-cloud.ts
|
|
@@ -65473,34 +65617,30 @@ function cloudPiInstructions(ctx) {
|
|
|
65473
65617
|
function createCloudPiSession(ctx, sink, deps) {
|
|
65474
65618
|
const personaId2 = personaIdFromCloudCwd(ctx.cwd);
|
|
65475
65619
|
const sessionId = ctx.toolSessionId ?? (0, import_node_crypto13.randomUUID)();
|
|
65476
|
-
const stream = deferredLineStream();
|
|
65477
65620
|
let channel = null;
|
|
65478
|
-
|
|
65479
|
-
|
|
65480
|
-
|
|
65481
|
-
|
|
65482
|
-
|
|
65483
|
-
|
|
65484
|
-
|
|
65485
|
-
|
|
65486
|
-
// 云 persona 运行看板(design 2026-09-23-cloud-persona-metrics §3.7):提问那一行带「一轮开始」头,轮末镜像顺带报这一轮的结果
|
|
65487
|
-
onTurnStarting: () => channel?.markNextLineTurnStart(),
|
|
65488
|
-
// 轮末镜像带上这一轮的结果与首字节(design 2026-09-23-cloud-persona-metrics §3.7)
|
|
65489
|
-
onTurnCompleted: (outcome, afterFirstByteMs) => {
|
|
65490
|
-
if (!ctx.titleOnly) void channel?.mirror({ outcome, ...afterFirstByteMs !== void 0 ? { afterFirstByteMs } : {} });
|
|
65491
|
-
},
|
|
65492
|
-
now: deps.now
|
|
65493
|
-
});
|
|
65621
|
+
let closed = false;
|
|
65622
|
+
let exited = false;
|
|
65623
|
+
const exit = () => {
|
|
65624
|
+
if (!exited) {
|
|
65625
|
+
exited = true;
|
|
65626
|
+
sink.onExit(null);
|
|
65627
|
+
}
|
|
65628
|
+
};
|
|
65494
65629
|
if (!personaId2) {
|
|
65495
65630
|
queueMicrotask(() => {
|
|
65496
65631
|
sink.onError(`cloud session has no persona id (cwd=${ctx.cwd})`);
|
|
65497
|
-
|
|
65632
|
+
exit();
|
|
65498
65633
|
});
|
|
65499
|
-
return
|
|
65500
|
-
|
|
65501
|
-
|
|
65502
|
-
(
|
|
65503
|
-
|
|
65634
|
+
return { startTurn() {
|
|
65635
|
+
}, respondPermission() {
|
|
65636
|
+
}, interrupt() {
|
|
65637
|
+
}, async stop() {
|
|
65638
|
+
} };
|
|
65639
|
+
}
|
|
65640
|
+
const opened = deps.client.openEventSession(personaId2, { expectedEngine: "pi", toolSessionId: sessionId, instructions: ctx.titleOnly ? "" : cloudPiInstructions(ctx), ...ctx.titleOnly ? { purpose: "title" } : {} }).then(
|
|
65641
|
+
(opened2) => {
|
|
65642
|
+
channel = opened2;
|
|
65643
|
+
channel.onEvents((events) => sink.pushEvents(events));
|
|
65504
65644
|
channel.onControl((c2) => {
|
|
65505
65645
|
if (c2.kind === "queued") {
|
|
65506
65646
|
sink.pushEvents([{ kind: "meta-text", text: `\u4E91\u4E0A\u673A\u5668\u6709 ${c2.running} \u4E2A\u4EFB\u52A1\u5728\u8DD1\uFF0C\u7B49\u4E00\u4E2A\u7ED3\u675F\u5C31\u8F6E\u5230\u4F60` }]);
|
|
@@ -65508,14 +65648,46 @@ function createCloudPiSession(ctx, sink, deps) {
|
|
|
65508
65648
|
sink.onError(`\u4E91\u4E0A persona \u8D77\u4E0D\u6765\uFF1A${c2.message}`);
|
|
65509
65649
|
}
|
|
65510
65650
|
});
|
|
65511
|
-
|
|
65651
|
+
channel.onClose(exit);
|
|
65652
|
+
if (closed) channel.close();
|
|
65653
|
+
return channel;
|
|
65512
65654
|
},
|
|
65513
65655
|
(e) => {
|
|
65514
65656
|
sink.onError(e instanceof CloudApiKeyRequiredError ? e.message : `\u8FDE\u4E0D\u4E0A\u4E91 gateway\uFF1A${e.message}`);
|
|
65515
|
-
|
|
65657
|
+
exit();
|
|
65658
|
+
throw e;
|
|
65516
65659
|
}
|
|
65517
65660
|
);
|
|
65518
|
-
|
|
65661
|
+
void opened.catch(() => {
|
|
65662
|
+
});
|
|
65663
|
+
let sendChain = Promise.resolve();
|
|
65664
|
+
const send2 = (command) => {
|
|
65665
|
+
sendChain = sendChain.then(command).catch((e) => {
|
|
65666
|
+
if (!closed && !exited) sink.onError(`\u4E91\u4E0A\u4F1A\u8BDD\u4E0A\u884C\u5931\u8D25\uFF1A${e.message}`);
|
|
65667
|
+
});
|
|
65668
|
+
};
|
|
65669
|
+
return {
|
|
65670
|
+
startTurn(text) {
|
|
65671
|
+
send2(async () => {
|
|
65672
|
+
const ch = await opened;
|
|
65673
|
+
if (closed) return;
|
|
65674
|
+
const portable = await portableCloudInput(text, { fetchPiImage: deps.fetchImage ?? makeImageFetcher() });
|
|
65675
|
+
await ch.send({ command: "turn", text: portable });
|
|
65676
|
+
});
|
|
65677
|
+
},
|
|
65678
|
+
respondPermission(requestId, allow) {
|
|
65679
|
+
send2(async () => (await opened).send({ command: "permission", requestId, allow }));
|
|
65680
|
+
},
|
|
65681
|
+
interrupt() {
|
|
65682
|
+
send2(async () => (await opened).send({ command: "interrupt" }));
|
|
65683
|
+
},
|
|
65684
|
+
async stop() {
|
|
65685
|
+
closed = true;
|
|
65686
|
+
const ch = await opened.catch(() => null);
|
|
65687
|
+
ch?.close();
|
|
65688
|
+
exit();
|
|
65689
|
+
}
|
|
65690
|
+
};
|
|
65519
65691
|
}
|
|
65520
65692
|
|
|
65521
65693
|
// src/tools/pi-cloud.ts
|
|
@@ -73092,7 +73264,7 @@ function computeMethodAccess(args) {
|
|
|
73092
73264
|
}
|
|
73093
73265
|
|
|
73094
73266
|
// src/version.ts
|
|
73095
|
-
var version = "0.2.
|
|
73267
|
+
var version = "0.2.603".length > 0 ? "0.2.603" : "dev";
|
|
73096
73268
|
|
|
73097
73269
|
// src/cli-probe/probe.ts
|
|
73098
73270
|
var fs83 = __toESM(require("fs"), 1);
|