@clawos-dev/clawd 0.2.631 → 0.2.635
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/app-builder-plugin/mcp-server.cjs +9788 -60
- package/dist/cli.cjs +302 -223
- package/dist/cloud-persona-conversations.html +20 -20
- package/dist/cloud-persona-metrics.html +1 -1
- package/dist/dispatch/mcp-server.cjs +5 -1
- package/dist/persona-defaults/persona-app-builder/mcp/clawd-app-builder/mcp-server.cjs +9788 -60
- package/dist/persona-defaults/persona-dataclaw-builder/mcp/clawd-app-builder/mcp-server.cjs +9788 -60
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/{guest-ChwUkuXp.js → guest-BEqYFrpA.js} +147 -142
- package/dist/share-ui/assets/guest-tpz-2SdL.css +32 -0
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-BgjpLYnI.css +0 -32
package/dist/cli.cjs
CHANGED
|
@@ -7690,14 +7690,16 @@ var init_dashboard_schemas = __esm({
|
|
|
7690
7690
|
});
|
|
7691
7691
|
|
|
7692
7692
|
// ../protocol/src/persona-schemas.ts
|
|
7693
|
-
var PERSONA_SIZES, PersonaSizeSchema, PersonaFileSchema, PersonaSkillSummarySchema, PersonaPluginSummarySchema, CodexSandboxSettingsSchema, PersonaSandboxSettingsSchema, PersonaInfoResponseSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema;
|
|
7693
|
+
var PERSONA_SIZES, PersonaSizeSchema, PERSONA_CPUS, PersonaCpuSchema, PersonaFileSchema, PersonaSkillSummarySchema, PersonaPluginSummarySchema, CodexSandboxSettingsSchema, PersonaSandboxSettingsSchema, PersonaInfoResponseSchema, PersonaCreateArgsSchema, PersonaIdArgsSchema, PersonaUpdateArgsSchema;
|
|
7694
7694
|
var init_persona_schemas = __esm({
|
|
7695
7695
|
"../protocol/src/persona-schemas.ts"() {
|
|
7696
7696
|
"use strict";
|
|
7697
7697
|
init_zod();
|
|
7698
7698
|
init_release_schemas();
|
|
7699
|
-
PERSONA_SIZES = ["tiny", "small", "medium", "large"];
|
|
7699
|
+
PERSONA_SIZES = ["tiny", "small", "medium", "large", "xlarge"];
|
|
7700
7700
|
PersonaSizeSchema = external_exports.enum(PERSONA_SIZES);
|
|
7701
|
+
PERSONA_CPUS = [0.5, 1, 2];
|
|
7702
|
+
PersonaCpuSchema = external_exports.number().refine((cpu) => PERSONA_CPUS.includes(cpu), "Unsupported CPU");
|
|
7701
7703
|
PersonaFileSchema = external_exports.object({
|
|
7702
7704
|
personaId: external_exports.string(),
|
|
7703
7705
|
label: external_exports.string(),
|
|
@@ -7714,6 +7716,7 @@ var init_persona_schemas = __esm({
|
|
|
7714
7716
|
tool: external_exports.string().optional(),
|
|
7715
7717
|
/** Cloud resource size is string-compatible in stored files and narrowed at update/deploy boundaries; local execution ignores it. */
|
|
7716
7718
|
size: external_exports.string().optional(),
|
|
7719
|
+
cpu: external_exports.number().finite().optional(),
|
|
7717
7720
|
/** Cloud task-Pod concurrency, validated at release. Local execution ignores it; changes apply on the next publication. */
|
|
7718
7721
|
taskConcurrency: external_exports.number().int().positive().optional(),
|
|
7719
7722
|
createdAt: external_exports.number(),
|
|
@@ -7811,6 +7814,7 @@ var init_persona_schemas = __esm({
|
|
|
7811
7814
|
effort: external_exports.string().optional(),
|
|
7812
7815
|
tool: external_exports.string().optional(),
|
|
7813
7816
|
size: PersonaSizeSchema.optional(),
|
|
7817
|
+
cpu: PersonaCpuSchema.optional(),
|
|
7814
7818
|
taskConcurrency: PersonaFileSchema.shape.taskConcurrency,
|
|
7815
7819
|
personality: external_exports.string().optional(),
|
|
7816
7820
|
// 人格补充层正文(见 PersonaInfoResponseSchema.personalityLocal)。与 personality 各写
|
|
@@ -42487,7 +42491,7 @@ var require_websocket = __commonJS({
|
|
|
42487
42491
|
var http2 = require("http");
|
|
42488
42492
|
var net2 = require("net");
|
|
42489
42493
|
var tls = require("tls");
|
|
42490
|
-
var { randomBytes: randomBytes2, createHash:
|
|
42494
|
+
var { randomBytes: randomBytes2, createHash: createHash5 } = require("crypto");
|
|
42491
42495
|
var { Duplex, Readable: Readable4 } = require("stream");
|
|
42492
42496
|
var { URL: URL2 } = require("url");
|
|
42493
42497
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -43147,7 +43151,7 @@ var require_websocket = __commonJS({
|
|
|
43147
43151
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
43148
43152
|
return;
|
|
43149
43153
|
}
|
|
43150
|
-
const digest =
|
|
43154
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
43151
43155
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
43152
43156
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
43153
43157
|
return;
|
|
@@ -43514,7 +43518,7 @@ var require_websocket_server = __commonJS({
|
|
|
43514
43518
|
var EventEmitter2 = require("events");
|
|
43515
43519
|
var http2 = require("http");
|
|
43516
43520
|
var { Duplex } = require("stream");
|
|
43517
|
-
var { createHash:
|
|
43521
|
+
var { createHash: createHash5 } = require("crypto");
|
|
43518
43522
|
var extension2 = require_extension();
|
|
43519
43523
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
43520
43524
|
var subprotocol2 = require_subprotocol();
|
|
@@ -43815,7 +43819,7 @@ var require_websocket_server = __commonJS({
|
|
|
43815
43819
|
);
|
|
43816
43820
|
}
|
|
43817
43821
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
43818
|
-
const digest =
|
|
43822
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
43819
43823
|
const headers = [
|
|
43820
43824
|
"HTTP/1.1 101 Switching Protocols",
|
|
43821
43825
|
"Upgrade: websocket",
|
|
@@ -45000,7 +45004,7 @@ var CodexHistoryReader = class {
|
|
|
45000
45004
|
}
|
|
45001
45005
|
async read(args) {
|
|
45002
45006
|
const locate = createCodexRolloutLocator(this.deps.roots);
|
|
45003
|
-
const segments =
|
|
45007
|
+
const segments = parseCodexThreadSegments(locate, args.toolSessionId);
|
|
45004
45008
|
const messages = [];
|
|
45005
45009
|
for (const segment of segments) {
|
|
45006
45010
|
messages.push(...await withSubagentResults(
|
|
@@ -45020,7 +45024,7 @@ var CodexHistoryReader = class {
|
|
|
45020
45024
|
}
|
|
45021
45025
|
async readSubagent(args) {
|
|
45022
45026
|
const locate = createCodexRolloutLocator(this.deps.roots);
|
|
45023
|
-
const owner2 =
|
|
45027
|
+
const owner2 = parseCodexThreadSegments(locate, args.toolSessionId).find((segment) => segment.parsed.subagents.some((sub) => sub.agentId === args.subagentId));
|
|
45024
45028
|
const child = this.parseThread(locate, args.subagentId);
|
|
45025
45029
|
if (!owner2 || child.meta?.threadId !== args.subagentId || child.meta.parentThreadId !== owner2.threadId) {
|
|
45026
45030
|
throw new Error(
|
|
@@ -45036,7 +45040,7 @@ var CodexHistoryReader = class {
|
|
|
45036
45040
|
return [];
|
|
45037
45041
|
}
|
|
45038
45042
|
parseThread(locate, threadId) {
|
|
45039
|
-
const segments =
|
|
45043
|
+
const segments = parseCodexThreadSegments(locate, threadId);
|
|
45040
45044
|
const current = segments[segments.length - 1].parsed;
|
|
45041
45045
|
return {
|
|
45042
45046
|
...current,
|
|
@@ -45045,30 +45049,30 @@ var CodexHistoryReader = class {
|
|
|
45045
45049
|
turns: segments.flatMap((s2) => s2.parsed.turns)
|
|
45046
45050
|
};
|
|
45047
45051
|
}
|
|
45048
|
-
parseThreadSegments(locate, threadId, endByteOffset, seen = /* @__PURE__ */ new Set()) {
|
|
45049
|
-
const key = threadId.toLowerCase();
|
|
45050
|
-
if (seen.has(key)) throw new Error(`Codex fork history cycle at thread ${threadId}`);
|
|
45051
|
-
seen.add(key);
|
|
45052
|
-
try {
|
|
45053
|
-
const file = locate(threadId);
|
|
45054
|
-
if (!file) throw new Error(`Codex rollout not found for thread ${threadId}`);
|
|
45055
|
-
const bytes = import_node_fs3.default.readFileSync(file);
|
|
45056
|
-
if (endByteOffset !== void 0 && endByteOffset > bytes.length) {
|
|
45057
|
-
throw new Error(`Codex fork history_base exceeds source rollout ${threadId}`);
|
|
45058
|
-
}
|
|
45059
|
-
const text = (endByteOffset === void 0 ? bytes : bytes.subarray(0, endByteOffset)).toString("utf8");
|
|
45060
|
-
const parsed = parseCodexRollout(text);
|
|
45061
|
-
if (parsed.meta?.threadId.toLowerCase() !== key) {
|
|
45062
|
-
throw new Error(`Codex rollout metadata does not match thread ${threadId}`);
|
|
45063
|
-
}
|
|
45064
|
-
const base = historyBase(text);
|
|
45065
|
-
const inherited = base ? this.parseThreadSegments(locate, base.threadId, base.endByteOffset, seen) : [];
|
|
45066
|
-
return [...inherited, { threadId, parsed }];
|
|
45067
|
-
} finally {
|
|
45068
|
-
seen.delete(key);
|
|
45069
|
-
}
|
|
45070
|
-
}
|
|
45071
45052
|
};
|
|
45053
|
+
function parseCodexThreadSegments(locate, threadId, endByteOffset, seen = /* @__PURE__ */ new Set()) {
|
|
45054
|
+
const key = threadId.toLowerCase();
|
|
45055
|
+
if (seen.has(key)) throw new Error(`Codex fork history cycle at thread ${threadId}`);
|
|
45056
|
+
seen.add(key);
|
|
45057
|
+
try {
|
|
45058
|
+
const file = locate(threadId);
|
|
45059
|
+
if (!file) throw new Error(`Codex rollout not found for thread ${threadId}`);
|
|
45060
|
+
const bytes = import_node_fs3.default.readFileSync(file);
|
|
45061
|
+
if (endByteOffset !== void 0 && endByteOffset > bytes.length) {
|
|
45062
|
+
throw new Error(`Codex fork history_base exceeds source rollout ${threadId}`);
|
|
45063
|
+
}
|
|
45064
|
+
const text = (endByteOffset === void 0 ? bytes : bytes.subarray(0, endByteOffset)).toString("utf8");
|
|
45065
|
+
const parsed = parseCodexRollout(text);
|
|
45066
|
+
if (parsed.meta?.threadId.toLowerCase() !== key) {
|
|
45067
|
+
throw new Error(`Codex rollout metadata does not match thread ${threadId}`);
|
|
45068
|
+
}
|
|
45069
|
+
const base = historyBase(text);
|
|
45070
|
+
const inherited = base ? parseCodexThreadSegments(locate, base.threadId, base.endByteOffset, seen) : [];
|
|
45071
|
+
return [...inherited, { threadId, parsed }];
|
|
45072
|
+
} finally {
|
|
45073
|
+
seen.delete(key);
|
|
45074
|
+
}
|
|
45075
|
+
}
|
|
45072
45076
|
|
|
45073
45077
|
// src/tools/cloud-history-pages.ts
|
|
45074
45078
|
var import_node_crypto = require("crypto");
|
|
@@ -45483,7 +45487,7 @@ function requireEnvironmentIdentity(stores, environment) {
|
|
|
45483
45487
|
var import_node_path85 = __toESM(require("path"), 1);
|
|
45484
45488
|
var import_node_fs66 = __toESM(require("fs"), 1);
|
|
45485
45489
|
var import_node_os31 = __toESM(require("os"), 1);
|
|
45486
|
-
var
|
|
45490
|
+
var import_node_crypto29 = require("crypto");
|
|
45487
45491
|
var import_node_url6 = require("url");
|
|
45488
45492
|
|
|
45489
45493
|
// src/logger.ts
|
|
@@ -45983,6 +45987,37 @@ var SessionStore = class {
|
|
|
45983
45987
|
filePath(sessionId) {
|
|
45984
45988
|
return import_node_path6.default.join(this.root, `${safeFileName(sessionId)}.json`);
|
|
45985
45989
|
}
|
|
45990
|
+
// Exact prepared cloud turn bodies (images inlined as base64) live beside the session file, never in it, so they are
|
|
45991
|
+
// not persisted with every write or broadcast; restart recovery replays them byte-for-byte (the gateway rejects a
|
|
45992
|
+
// changed body for the same turn ID). Each write prunes payloads of turns no longer in cloudPendingTurns.
|
|
45993
|
+
cloudPayloadDir(sessionId) {
|
|
45994
|
+
return import_node_path6.default.join(this.root, `${safeFileName(sessionId)}.cloud-payloads`);
|
|
45995
|
+
}
|
|
45996
|
+
writeCloudPayload(sessionId, turnId, text) {
|
|
45997
|
+
const dir = this.cloudPayloadDir(sessionId);
|
|
45998
|
+
import_node_fs7.default.mkdirSync(dir, { recursive: true });
|
|
45999
|
+
const target = import_node_path6.default.join(dir, safeFileName(turnId));
|
|
46000
|
+
const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
|
|
46001
|
+
import_node_fs7.default.writeFileSync(tmp, text, { encoding: "utf8", mode: 384 });
|
|
46002
|
+
import_node_fs7.default.renameSync(tmp, target);
|
|
46003
|
+
}
|
|
46004
|
+
readCloudPayload(sessionId, turnId) {
|
|
46005
|
+
try {
|
|
46006
|
+
return import_node_fs7.default.readFileSync(import_node_path6.default.join(this.cloudPayloadDir(sessionId), safeFileName(turnId)), "utf8");
|
|
46007
|
+
} catch {
|
|
46008
|
+
return null;
|
|
46009
|
+
}
|
|
46010
|
+
}
|
|
46011
|
+
pruneCloudPayloads(file) {
|
|
46012
|
+
const dir = this.cloudPayloadDir(file.sessionId);
|
|
46013
|
+
if (!import_node_fs7.default.existsSync(dir)) return;
|
|
46014
|
+
const keep = new Set((file.cloudPendingTurns ?? []).map((turn) => safeFileName(turn.id)));
|
|
46015
|
+
if (keep.size === 0) {
|
|
46016
|
+
import_node_fs7.default.rmSync(dir, { recursive: true, force: true });
|
|
46017
|
+
return;
|
|
46018
|
+
}
|
|
46019
|
+
for (const name of import_node_fs7.default.readdirSync(dir)) if (!keep.has(name)) import_node_fs7.default.rmSync(import_node_path6.default.join(dir, name), { force: true });
|
|
46020
|
+
}
|
|
45986
46021
|
ensureDir() {
|
|
45987
46022
|
import_node_fs7.default.mkdirSync(this.root, { recursive: true });
|
|
45988
46023
|
}
|
|
@@ -46004,9 +46039,14 @@ var SessionStore = class {
|
|
|
46004
46039
|
const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
|
|
46005
46040
|
import_node_fs7.default.writeFileSync(tmp, JSON.stringify(validated, null, 2), { encoding: "utf8", mode: 384 });
|
|
46006
46041
|
import_node_fs7.default.renameSync(tmp, target);
|
|
46042
|
+
try {
|
|
46043
|
+
this.pruneCloudPayloads(validated);
|
|
46044
|
+
} catch {
|
|
46045
|
+
}
|
|
46007
46046
|
return validated;
|
|
46008
46047
|
}
|
|
46009
46048
|
delete(sessionId) {
|
|
46049
|
+
import_node_fs7.default.rmSync(this.cloudPayloadDir(sessionId), { recursive: true, force: true });
|
|
46010
46050
|
try {
|
|
46011
46051
|
import_node_fs7.default.unlinkSync(this.filePath(sessionId));
|
|
46012
46052
|
return true;
|
|
@@ -47402,14 +47442,6 @@ function reduceSessionInner(state, input, deps) {
|
|
|
47402
47442
|
case "inject-events": {
|
|
47403
47443
|
return applyEventBatch(state, input.events, deps);
|
|
47404
47444
|
}
|
|
47405
|
-
case "cloud-command-prepared": {
|
|
47406
|
-
const pending = state.file.cloudPendingCommand;
|
|
47407
|
-
const turn = state.file.cloudPendingTurns?.find((item) => item.id === input.commandId);
|
|
47408
|
-
if ((!pending || pending.id !== input.commandId) && !turn) return { state, effects: [] };
|
|
47409
|
-
const next = cloneState(state);
|
|
47410
|
-
next.file = turn ? { ...next.file, cloudPendingTurns: next.file.cloudPendingTurns?.map((item) => item.id === input.commandId ? { ...item, text: input.text, prepared: true } : item) } : { ...next.file, cloudPendingCommand: { id: pending.id, text: input.text, prepared: true } };
|
|
47411
|
-
return { state: next, effects: [{ kind: "persist-file", file: next.file }] };
|
|
47412
|
-
}
|
|
47413
47445
|
case "cloud-turn-terminal": {
|
|
47414
47446
|
if (!state.file.cloudPendingTurns?.some((item) => item.id === input.turnId)) return { state, effects: [] };
|
|
47415
47447
|
const next = cloneState(state);
|
|
@@ -47419,9 +47451,13 @@ function reduceSessionInner(state, input, deps) {
|
|
|
47419
47451
|
case "proc-exit": {
|
|
47420
47452
|
const next = cloneState(state);
|
|
47421
47453
|
next.procAlive = false;
|
|
47454
|
+
if (isCloudTool(next.file.tool) && next.file.cloudPendingCommand && !next.file.cloudPendingTurns) {
|
|
47455
|
+
next.file = { ...next.file, cloudPendingCommand: void 0 };
|
|
47456
|
+
}
|
|
47422
47457
|
if (isCloudTool(next.file.tool) && !next.file.cloudPendingCommand && next.file.cloudGatewaySessionId) {
|
|
47423
47458
|
next.file = { ...next.file, cloudGatewaySessionId: void 0 };
|
|
47424
47459
|
}
|
|
47460
|
+
const cloudFileChanged = next.file !== state.file;
|
|
47425
47461
|
next.status = "stopped";
|
|
47426
47462
|
next.stdinClosed = false;
|
|
47427
47463
|
next.pendingBgTasks = [];
|
|
@@ -47444,7 +47480,7 @@ function reduceSessionInner(state, input, deps) {
|
|
|
47444
47480
|
return {
|
|
47445
47481
|
state: next,
|
|
47446
47482
|
effects: [
|
|
47447
|
-
...
|
|
47483
|
+
...cloudFileChanged ? [{ kind: "persist-file", file: next.file }] : [],
|
|
47448
47484
|
...interruptEffects,
|
|
47449
47485
|
{
|
|
47450
47486
|
kind: "emit-frame",
|
|
@@ -47901,7 +47937,10 @@ var SessionRunner = class {
|
|
|
47901
47937
|
this.input({ kind: "command", command: { kind: "spawn-if-needed" } });
|
|
47902
47938
|
const pending = this.state.file.cloudPendingCommand;
|
|
47903
47939
|
if (pending) this.session?.startTurn(pending.text, pending.id, pending.prepared === true);
|
|
47904
|
-
for (const turn of this.state.file.cloudPendingTurns ?? [])
|
|
47940
|
+
for (const turn of this.state.file.cloudPendingTurns ?? []) {
|
|
47941
|
+
const payload = turn.prepared ? null : this.hooks.store.readCloudPayload(this.state.file.sessionId, turn.id);
|
|
47942
|
+
this.session?.startTurn(payload ?? turn.text, turn.id, payload !== null || turn.prepared === true);
|
|
47943
|
+
}
|
|
47905
47944
|
} finally {
|
|
47906
47945
|
this.recoveringCloud = false;
|
|
47907
47946
|
}
|
|
@@ -48224,10 +48263,9 @@ var SessionRunner = class {
|
|
|
48224
48263
|
}, "broadcast"),
|
|
48225
48264
|
onCommandPrepared: (commandId, text, prepared) => {
|
|
48226
48265
|
const pending = this.state.file.cloudPendingTurns?.find((turn) => turn.id === commandId) ?? this.state.file.cloudPendingCommand;
|
|
48227
|
-
if (!pending || pending.id !== commandId
|
|
48228
|
-
if (!prepared) {
|
|
48229
|
-
this.hooks.store.
|
|
48230
|
-
this.input({ kind: "cloud-command-prepared", commandId, text });
|
|
48266
|
+
if (!pending || pending.id !== commandId) return false;
|
|
48267
|
+
if (!prepared && pending !== this.state.file.cloudPendingCommand) {
|
|
48268
|
+
this.hooks.store.writeCloudPayload(this.state.file.sessionId, commandId, text);
|
|
48231
48269
|
}
|
|
48232
48270
|
return true;
|
|
48233
48271
|
},
|
|
@@ -48420,6 +48458,24 @@ var SessionManager = class {
|
|
|
48420
48458
|
setCloudCanceller(cancel) {
|
|
48421
48459
|
this.cloudCancel = cancel;
|
|
48422
48460
|
}
|
|
48461
|
+
/**
|
|
48462
|
+
* Cancel only an in-flight cloud turn before a local stop / delete / reset. Idle conversations need no gateway
|
|
48463
|
+
* call, and a failed cancel must not block the local action (offline / logged out / gateway errors).
|
|
48464
|
+
*/
|
|
48465
|
+
async cancelCloudTurns(file, runner) {
|
|
48466
|
+
const inFlight = (file.cloudConversationId || file.cloudGatewaySessionId) && (file.cloudPendingCommand || file.cloudPendingTurns?.length);
|
|
48467
|
+
if (!inFlight) {
|
|
48468
|
+
runner?.confirmCloudCancelled();
|
|
48469
|
+
return;
|
|
48470
|
+
}
|
|
48471
|
+
if (!this.cloudCancel) throw new Error("cloud canceller is not configured");
|
|
48472
|
+
try {
|
|
48473
|
+
await this.cloudCancel(file, runner);
|
|
48474
|
+
} catch (err) {
|
|
48475
|
+
this.deps.logger?.warn("cloud cancel failed; continuing locally", { sessionId: file.sessionId, message: err.message });
|
|
48476
|
+
runner?.confirmCloudCancelled();
|
|
48477
|
+
}
|
|
48478
|
+
}
|
|
48423
48479
|
// sessionId → SessionRunner;在 send / ensureSession 时按需创建
|
|
48424
48480
|
runners = /* @__PURE__ */ new Map();
|
|
48425
48481
|
// 标题生成 in-flight 防重(进程内);跨重启防重靠 SessionFile.aiLabelGeneratedAt
|
|
@@ -49178,12 +49234,7 @@ var SessionManager = class {
|
|
|
49178
49234
|
const file = this.findOwnedSession(args.sessionId);
|
|
49179
49235
|
if (!file) throw new ClawdError(ERROR_CODES.SESSION_NOT_FOUND, args.sessionId);
|
|
49180
49236
|
const runner = this.runners.get(args.sessionId) ?? null;
|
|
49181
|
-
if (isCloudTool(file.tool))
|
|
49182
|
-
if (file.cloudConversationId || file.cloudGatewaySessionId) {
|
|
49183
|
-
if (!this.cloudCancel) throw new Error("cloud canceller is not configured");
|
|
49184
|
-
await this.cloudCancel(file, runner);
|
|
49185
|
-
} else runner?.confirmCloudCancelled();
|
|
49186
|
-
}
|
|
49237
|
+
if (isCloudTool(file.tool)) await this.cancelCloudTurns(file, runner);
|
|
49187
49238
|
return this.delete(args);
|
|
49188
49239
|
}
|
|
49189
49240
|
send(args, senderPrincipal) {
|
|
@@ -49327,12 +49378,7 @@ var SessionManager = class {
|
|
|
49327
49378
|
async stop(args) {
|
|
49328
49379
|
const file = this.findOwnedSession(args.sessionId);
|
|
49329
49380
|
const runner = this.runners.get(args.sessionId);
|
|
49330
|
-
if (file && isCloudTool(file.tool))
|
|
49331
|
-
if (file.cloudConversationId || file.cloudGatewaySessionId) {
|
|
49332
|
-
if (!this.cloudCancel) throw new Error("cloud canceller is not configured");
|
|
49333
|
-
await this.cloudCancel(file, runner ?? null);
|
|
49334
|
-
} else runner?.confirmCloudCancelled();
|
|
49335
|
-
}
|
|
49381
|
+
if (file && isCloudTool(file.tool)) await this.cancelCloudTurns(file, runner ?? null);
|
|
49336
49382
|
if (!runner) {
|
|
49337
49383
|
if (file && isCloudTool(file.tool) && (file.cloudPendingCommand || file.cloudPendingTurns?.length)) this.writeOwned({ ...file, cloudPendingCommand: void 0, cloudPendingTurns: void 0 });
|
|
49338
49384
|
return { response: { ok: true }, broadcast: [] };
|
|
@@ -49528,11 +49574,7 @@ var SessionManager = class {
|
|
|
49528
49574
|
async newSessionWithCloudCancel(args) {
|
|
49529
49575
|
const file = this.getFile(args.sessionId);
|
|
49530
49576
|
if (isCloudTool(file.tool)) {
|
|
49531
|
-
|
|
49532
|
-
if (file.cloudConversationId || file.cloudGatewaySessionId) {
|
|
49533
|
-
if (!this.cloudCancel) throw new Error("cloud canceller is not configured");
|
|
49534
|
-
await this.cloudCancel(file, runner);
|
|
49535
|
-
} else runner?.confirmCloudCancelled();
|
|
49577
|
+
await this.cancelCloudTurns(file, this.runners.get(args.sessionId) ?? null);
|
|
49536
49578
|
return this.newSession(args);
|
|
49537
49579
|
}
|
|
49538
49580
|
return this.newSession(args);
|
|
@@ -56538,11 +56580,72 @@ function buildShiftInternalHandlers(deps) {
|
|
|
56538
56580
|
}
|
|
56539
56581
|
|
|
56540
56582
|
// src/handlers/deploy.ts
|
|
56541
|
-
var
|
|
56583
|
+
var import_node_crypto13 = require("crypto");
|
|
56542
56584
|
|
|
56543
56585
|
// src/deploy/verified-release.ts
|
|
56544
|
-
var
|
|
56586
|
+
var import_node_crypto11 = require("crypto");
|
|
56587
|
+
|
|
56588
|
+
// src/deploy/release-archive.ts
|
|
56545
56589
|
var import_jszip = __toESM(require_lib3(), 1);
|
|
56590
|
+
function inspectArchive(bytes) {
|
|
56591
|
+
const data = Buffer.from(bytes);
|
|
56592
|
+
let end = -1;
|
|
56593
|
+
for (let at4 = data.length - 22; at4 >= Math.max(0, data.length - 65557); at4--) {
|
|
56594
|
+
if (data.readUInt32LE(at4) === 101010256 && at4 + 22 + data.readUInt16LE(at4 + 20) === data.length) {
|
|
56595
|
+
end = at4;
|
|
56596
|
+
break;
|
|
56597
|
+
}
|
|
56598
|
+
}
|
|
56599
|
+
if (end < 0 || data.readUInt16LE(end + 4) || data.readUInt16LE(end + 6)) throw new Error("\u5236\u54C1\u5F52\u6863\u683C\u5F0F\u4E0D\u652F\u6301");
|
|
56600
|
+
const count = data.readUInt16LE(end + 10);
|
|
56601
|
+
const length = data.readUInt32LE(end + 12);
|
|
56602
|
+
let at3 = data.readUInt32LE(end + 16), roots = 0;
|
|
56603
|
+
if (count === 65535 || at3 + length !== end) throw new Error("\u5236\u54C1\u5F52\u6863\u683C\u5F0F\u4E0D\u652F\u6301");
|
|
56604
|
+
for (let i2 = 0; i2 < count; i2++) {
|
|
56605
|
+
if (at3 + 46 > end || data.readUInt32LE(at3) !== 33639248) throw new Error("\u5236\u54C1\u5F52\u6863\u683C\u5F0F\u4E0D\u6B63\u786E");
|
|
56606
|
+
const nameLength = data.readUInt16LE(at3 + 28);
|
|
56607
|
+
const next = at3 + 46 + nameLength + data.readUInt16LE(at3 + 30) + data.readUInt16LE(at3 + 32);
|
|
56608
|
+
if (next > end) throw new Error("\u5236\u54C1\u5F52\u6863\u683C\u5F0F\u4E0D\u6B63\u786E");
|
|
56609
|
+
const name = data.subarray(at3 + 46, at3 + 46 + nameLength).toString("utf8");
|
|
56610
|
+
if (name === "candidate-release.json") {
|
|
56611
|
+
roots++;
|
|
56612
|
+
if (data.readUInt32LE(at3 + 24) > 64 * 1024) throw new Error("\u5236\u54C1 JSON \u8D85\u8FC7\u5927\u5C0F\u9650\u5236");
|
|
56613
|
+
if (data.readUInt16LE(at3 + 8) & 1) throw new Error("\u5236\u54C1\u5F52\u6863\u4E0D\u80FD\u52A0\u5BC6");
|
|
56614
|
+
}
|
|
56615
|
+
at3 = next;
|
|
56616
|
+
}
|
|
56617
|
+
if (at3 !== end) throw new Error("\u5236\u54C1\u5F52\u6863\u683C\u5F0F\u4E0D\u6B63\u786E");
|
|
56618
|
+
if (roots > 1) throw new Error("\u5236\u54C1\u5F52\u6863\u6709\u91CD\u590D\u7684\u6839 JSON");
|
|
56619
|
+
if (roots !== 1) throw new Error("\u5236\u54C1\u7F3A\u5C11\u6839\u76EE\u5F55\u7684 candidate-release.json");
|
|
56620
|
+
}
|
|
56621
|
+
async function readReleaseArchive(bytes) {
|
|
56622
|
+
if (bytes.length > 1024 * 1024) throw new Error("\u5236\u54C1\u5F52\u6863\u8D85\u8FC7\u5927\u5C0F\u9650\u5236");
|
|
56623
|
+
inspectArchive(bytes);
|
|
56624
|
+
const zip = await import_jszip.default.loadAsync(bytes);
|
|
56625
|
+
const entry = zip.file("candidate-release.json");
|
|
56626
|
+
if (!entry || entry.dir || entry.unsafeOriginalName && entry.unsafeOriginalName !== "candidate-release.json") throw new Error("\u5236\u54C1\u7F3A\u5C11\u6839\u76EE\u5F55\u7684 candidate-release.json");
|
|
56627
|
+
const chunks = [];
|
|
56628
|
+
let size = 0;
|
|
56629
|
+
await new Promise((resolve9, reject) => {
|
|
56630
|
+
const stream = entry.nodeStream("nodebuffer");
|
|
56631
|
+
stream.on("data", (data) => {
|
|
56632
|
+
size += data.length;
|
|
56633
|
+
if (size > 64 * 1024) {
|
|
56634
|
+
stream.pause();
|
|
56635
|
+
reject(new Error("\u5236\u54C1 JSON \u8D85\u8FC7\u5927\u5C0F\u9650\u5236"));
|
|
56636
|
+
return;
|
|
56637
|
+
}
|
|
56638
|
+
chunks.push(Buffer.from(data));
|
|
56639
|
+
}).on("error", reject).on("end", resolve9).resume();
|
|
56640
|
+
});
|
|
56641
|
+
let raw;
|
|
56642
|
+
try {
|
|
56643
|
+
raw = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
56644
|
+
} catch {
|
|
56645
|
+
throw new Error("\u5236\u54C1 JSON \u4E0D\u662F\u5408\u6CD5\u683C\u5F0F");
|
|
56646
|
+
}
|
|
56647
|
+
return raw;
|
|
56648
|
+
}
|
|
56546
56649
|
|
|
56547
56650
|
// src/cloud/gateway-client.ts
|
|
56548
56651
|
init_protocol();
|
|
@@ -56710,6 +56813,9 @@ var CloudGatewayClient = class {
|
|
|
56710
56813
|
return CloudVolumeUsageSchema.parse(body.volume);
|
|
56711
56814
|
}
|
|
56712
56815
|
};
|
|
56816
|
+
var TURN_RETRY_BASE_MS = 250;
|
|
56817
|
+
var TURN_RETRY_MAX_MS = 3e4;
|
|
56818
|
+
var TURN_RETRY_MAX_FAILURES = 12;
|
|
56713
56819
|
function openHttpTurn(opts) {
|
|
56714
56820
|
const { fetchImpl, gatewayUrl, apiKey, personaId: personaId2, conversationId, turnId, text, expectedEngine, engineSessionId, instructions, effort, personaMode, purpose, logger } = opts;
|
|
56715
56821
|
const body = JSON.stringify({
|
|
@@ -56753,8 +56859,9 @@ function openHttpTurn(opts) {
|
|
|
56753
56859
|
if (!gapCbs.length) earlyGap = true;
|
|
56754
56860
|
for (const cb of gapCbs) cb();
|
|
56755
56861
|
};
|
|
56756
|
-
|
|
56757
|
-
|
|
56862
|
+
let failures = 0;
|
|
56863
|
+
const retryWait = (ms) => new Promise((resolve9) => {
|
|
56864
|
+
const timer = setTimeout(resolve9, ms);
|
|
56758
56865
|
timer.unref?.();
|
|
56759
56866
|
abort.signal.addEventListener("abort", () => {
|
|
56760
56867
|
clearTimeout(timer);
|
|
@@ -56796,6 +56903,7 @@ function openHttpTurn(opts) {
|
|
|
56796
56903
|
for (; ; ) {
|
|
56797
56904
|
const { value, done } = await reader.read();
|
|
56798
56905
|
if (done || closed) break;
|
|
56906
|
+
if (value.byteLength) failures = 0;
|
|
56799
56907
|
pending += decoder.decode(value, { stream: true });
|
|
56800
56908
|
let delimiter2;
|
|
56801
56909
|
while ((delimiter2 = /\r?\n\r?\n/.exec(pending)) !== null) {
|
|
@@ -56832,7 +56940,12 @@ function openHttpTurn(opts) {
|
|
|
56832
56940
|
}
|
|
56833
56941
|
logger?.warn("cloud turn SSE disconnected; reconnecting", { message: error.message, turnId });
|
|
56834
56942
|
}
|
|
56835
|
-
if (
|
|
56943
|
+
if (closed) return;
|
|
56944
|
+
if (++failures > TURN_RETRY_MAX_FAILURES) {
|
|
56945
|
+
state({ conversationId, turnId, status: "failed", errorCode: "GATEWAY_UNREACHABLE" });
|
|
56946
|
+
return;
|
|
56947
|
+
}
|
|
56948
|
+
await retryWait(Math.min(TURN_RETRY_BASE_MS * 2 ** (failures - 1), TURN_RETRY_MAX_MS));
|
|
56836
56949
|
}
|
|
56837
56950
|
})();
|
|
56838
56951
|
return {
|
|
@@ -60940,6 +61053,63 @@ async function storeGithubAuth(args) {
|
|
|
60940
61053
|
return { token: args.token, source: "file" };
|
|
60941
61054
|
}
|
|
60942
61055
|
|
|
61056
|
+
// src/deploy/base-release.ts
|
|
61057
|
+
init_zod();
|
|
61058
|
+
var SLUG = "ottin4ttc/clawos";
|
|
61059
|
+
var WORKFLOW = ".github/workflows/base-image-acr.yml";
|
|
61060
|
+
var SHA = external_exports.string().regex(/^[a-f0-9]{40}$/);
|
|
61061
|
+
var SourceSchema = external_exports.object({ cloudHost: SHA, workflow: SHA });
|
|
61062
|
+
var BaseSchema = external_exports.object({
|
|
61063
|
+
version: external_exports.literal(1),
|
|
61064
|
+
component: external_exports.literal("base"),
|
|
61065
|
+
environment: external_exports.literal("integration"),
|
|
61066
|
+
commit: SHA,
|
|
61067
|
+
image: external_exports.string().regex(/^registry(?:-vpc)?\.cn-hangzhou\.aliyuncs\.com\/ttc-prod\/clawd-persona-base@sha256:[a-f0-9]{64}$/),
|
|
61068
|
+
source: SourceSchema,
|
|
61069
|
+
workflowCommit: SHA,
|
|
61070
|
+
buildId: external_exports.string().min(1)
|
|
61071
|
+
});
|
|
61072
|
+
async function currentSource(api) {
|
|
61073
|
+
const head = await api.getJsonStrict(`/repos/${SLUG}/commits/release`);
|
|
61074
|
+
if (!SHA.safeParse(head?.sha).success || !SHA.safeParse(head?.commit?.tree?.sha).success) throw new Error("\u8BFB\u4E0D\u5230\u53EF\u4FE1\u7684 release \u5E95\u5EA7\u6E90\u7801\u7248\u672C");
|
|
61075
|
+
const commit = SHA.parse(head?.sha), tree = SHA.parse(head?.commit?.tree?.sha);
|
|
61076
|
+
const [root, workflow] = await Promise.all([
|
|
61077
|
+
api.getJsonStrict(`/repos/${SLUG}/git/trees/${tree}`),
|
|
61078
|
+
api.getJsonStrict(`/repos/${SLUG}/contents/${WORKFLOW}?ref=${commit}`)
|
|
61079
|
+
]);
|
|
61080
|
+
if (root?.truncated || workflow?.type !== "file") throw new Error("\u8BFB\u4E0D\u5230\u5B8C\u6574\u5E95\u5EA7\u6E90\u7801\u7248\u672C");
|
|
61081
|
+
const source = SourceSchema.safeParse({ cloudHost: root?.tree?.find((e) => e.path === "cloud-host" && e.type === "tree")?.sha, workflow: workflow.sha });
|
|
61082
|
+
if (!source.success) throw new Error("\u5E95\u5EA7\u6E90\u7801\u7248\u672C\u8BB0\u5F55\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u5237\u65B0\u540E\u518D\u53D1\u5E03");
|
|
61083
|
+
return { commit, source: source.data };
|
|
61084
|
+
}
|
|
61085
|
+
async function readCurrentBase(api) {
|
|
61086
|
+
const current = await currentSource(api);
|
|
61087
|
+
const listed = await api.getJsonStrict(`/repos/${SLUG}/actions/workflows/base-image-acr.yml/runs?branch=release&per_page=1`);
|
|
61088
|
+
const run = listed?.workflow_runs?.[0];
|
|
61089
|
+
if (!run || !Number.isSafeInteger(run.id) || run.id <= 0 || !Number.isSafeInteger(run.run_attempt) || run.run_attempt <= 0 || run.head_branch !== "release" || run.path !== WORKFLOW || run.head_repository?.full_name !== SLUG || !["push", "workflow_dispatch"].includes(run.event)) throw new Error("\u6CA1\u6709\u53EF\u4FE1\u7684 release \u5E95\u5EA7\u6784\u5EFA\uFF0C\u8BF7\u8FD0\u884C\u5E95\u5EA7\u6D41\u6C34\u7EBF\u540E\u518D\u53D1\u5E03");
|
|
61090
|
+
if (run.status !== "completed" || run.conclusion !== "success") throw new Error("\u6700\u65B0\u5E95\u5EA7\u6784\u5EFA\u5C1A\u672A\u6210\u529F\uFF0C\u8BF7\u67E5\u770B clawos \u5E95\u5EA7 Actions \u540E\u518D\u53D1\u5E03");
|
|
61091
|
+
SHA.parse(run.head_sha);
|
|
61092
|
+
let artifact;
|
|
61093
|
+
for (let page = 1; page <= 30; page++) {
|
|
61094
|
+
const list = await api.getJsonStrict(`/repos/${SLUG}/actions/runs/${run.id}/artifacts?per_page=100&page=${page}`);
|
|
61095
|
+
if (!Array.isArray(list?.artifacts)) throw new Error("\u8BFB\u4E0D\u5230\u5E95\u5EA7\u6784\u5EFA\u5236\u54C1");
|
|
61096
|
+
const hits = list.artifacts.filter((a2) => a2.name === `base-candidate-${run.id}-${run.run_attempt}`);
|
|
61097
|
+
if (hits.length > 1 || artifact && hits.length) throw new Error("\u5E95\u5EA7\u6784\u5EFA\u6709\u591A\u4EFD\u5339\u914D\u5236\u54C1\uFF0C\u8BF7\u91CD\u65B0\u6784\u5EFA");
|
|
61098
|
+
artifact ??= hits[0];
|
|
61099
|
+
if (list.artifacts.length < 100 && (list.total_count === void 0 || page * 100 >= list.total_count)) break;
|
|
61100
|
+
if (page === 30) throw new Error("\u5E95\u5EA7\u5236\u54C1\u540D\u5355\u672A\u5B8C\u6574\u8BFB\u5230");
|
|
61101
|
+
}
|
|
61102
|
+
if (!artifact || artifact.expired || !Number.isSafeInteger(artifact.id) || artifact.id <= 0 || !artifact.workflow_run || artifact.workflow_run.id !== run.id || artifact.workflow_run.head_sha !== run.head_sha) throw new Error("\u5E95\u5EA7\u5236\u54C1\u4E0D\u5B58\u5728\u3001\u5DF2\u8FC7\u671F\u6216\u7248\u672C\u4E0D\u5339\u914D\uFF0C\u8BF7\u91CD\u65B0\u6784\u5EFA");
|
|
61103
|
+
const parsed = BaseSchema.safeParse(await readReleaseArchive(await api.downloadArtifact(SLUG, artifact.id)));
|
|
61104
|
+
if (!parsed.success) throw new Error("\u5E95\u5EA7\u5236\u54C1\u7248\u672C\u8BB0\u5F55\u65E0\u6548\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C\u5E95\u5EA7\u6784\u5EFA");
|
|
61105
|
+
const release2 = parsed.data;
|
|
61106
|
+
const matches = (source) => release2.source.cloudHost === source.cloudHost && release2.source.workflow === source.workflow;
|
|
61107
|
+
if (release2.workflowCommit !== run.head_sha || !matches(current.source)) throw new Error("\u5E95\u5EA7\u5C1A\u672A\u6784\u5EFA\u5F53\u524D release \u6E90\u7801\uFF0C\u8BF7\u7B49\u5F85\u6216\u91CD\u65B0\u8FD0\u884C\u5E95\u5EA7\u6D41\u6C34\u7EBF");
|
|
61108
|
+
const after = await currentSource(api);
|
|
61109
|
+
if (!matches(after.source)) throw new Error("\u5E95\u5EA7\u6E90\u7801\u5728\u53D1\u5E03\u51C6\u5907\u671F\u95F4\u53D8\u5316\uFF0C\u8BF7\u7B49\u65B0\u6784\u5EFA\u6210\u529F\u540E\u518D\u53D1\u5E03");
|
|
61110
|
+
return release2;
|
|
61111
|
+
}
|
|
61112
|
+
|
|
60943
61113
|
// src/deploy/release-workflow.ts
|
|
60944
61114
|
init_protocol();
|
|
60945
61115
|
function renderDeployWorkflow(config) {
|
|
@@ -61040,6 +61210,7 @@ function renderDeployWorkflow(config) {
|
|
|
61040
61210
|
" --model '${{ steps.plan.outputs.model }}' \\",
|
|
61041
61211
|
" --effort '${{ steps.plan.outputs.effort }}' \\",
|
|
61042
61212
|
" --size '${{ steps.plan.outputs.size }}' \\",
|
|
61213
|
+
" --cpu '${{ steps.plan.outputs.cpu }}' \\",
|
|
61043
61214
|
" --task-concurrency '${{ steps.plan.outputs.task_concurrency }}' \\",
|
|
61044
61215
|
" --engine '${{ steps.plan.outputs.engine }}' \\",
|
|
61045
61216
|
" --connectors '${{ steps.plan.outputs.connectors }}' \\",
|
|
@@ -61164,30 +61335,6 @@ function renderDeployWorkflow(config) {
|
|
|
61164
61335
|
].join("\n");
|
|
61165
61336
|
}
|
|
61166
61337
|
|
|
61167
|
-
// src/deploy/templates.ts
|
|
61168
|
-
var import_node_crypto11 = require("crypto");
|
|
61169
|
-
|
|
61170
|
-
// src/deploy/default-base-release.json
|
|
61171
|
-
var default_base_release_default = {
|
|
61172
|
-
version: 1,
|
|
61173
|
-
environment: "integration",
|
|
61174
|
-
component: "base",
|
|
61175
|
-
image: "registry-vpc.cn-hangzhou.aliyuncs.com/ttc-prod/clawd-persona-base@sha256:9a0952c6bc94a6595374da7db125b5089b476d0bd88f280bd981757d9f572c22",
|
|
61176
|
-
commit: "8dfab2c57781e9f9600e3f99a79adcfbef455f2e",
|
|
61177
|
-
verification: {
|
|
61178
|
-
status: "passed",
|
|
61179
|
-
fingerprint: "d7b03abb9d2bf3a4d7f6f88ac43a2d33d6ec7a7c94ae816f7dae11d67d338194",
|
|
61180
|
-
checks: [
|
|
61181
|
-
"base-smoke",
|
|
61182
|
-
"codex-smoke",
|
|
61183
|
-
"pi-smoke",
|
|
61184
|
-
"workspace-persistence"
|
|
61185
|
-
],
|
|
61186
|
-
endpoint: "https://persona-int.clawos.chat",
|
|
61187
|
-
verifiedAt: "2026-10-08T09:34:53.131Z"
|
|
61188
|
-
}
|
|
61189
|
-
};
|
|
61190
|
-
|
|
61191
61338
|
// src/deploy/templates.ts
|
|
61192
61339
|
init_protocol();
|
|
61193
61340
|
var CLAWOS_REPO = "ottin4ttc/clawos";
|
|
@@ -61201,17 +61348,6 @@ var DOCKERIGNORE_PATH = ".dockerignore";
|
|
|
61201
61348
|
var ACR_REGISTRY = "registry.cn-hangzhou.aliyuncs.com";
|
|
61202
61349
|
var ACR_VPC_REGISTRY = "registry-vpc.cn-hangzhou.aliyuncs.com";
|
|
61203
61350
|
var ACR_NAMESPACE = "ttc-prod";
|
|
61204
|
-
var acceptedBase = VerifiedBaseReleaseSchema.parse(default_base_release_default);
|
|
61205
|
-
var baseFingerprint = (0, import_node_crypto11.createHash)("sha256").update(JSON.stringify({
|
|
61206
|
-
component: acceptedBase.component,
|
|
61207
|
-
image: acceptedBase.image,
|
|
61208
|
-
commit: acceptedBase.commit,
|
|
61209
|
-
baseImage: null,
|
|
61210
|
-
pipelineCommit: null,
|
|
61211
|
-
repository: null
|
|
61212
|
-
})).digest("hex");
|
|
61213
|
-
if (baseFingerprint !== acceptedBase.verification.fingerprint) throw new Error("\u5E73\u53F0\u9ED8\u8BA4\u5E95\u5EA7\u4E0E\u5DF2\u9A8C\u6536\u5236\u54C1\u4E0D\u4E00\u81F4");
|
|
61214
|
-
var BASE_IMAGE = acceptedBase.image.replace(`${ACR_VPC_REGISTRY}/`, `${ACR_REGISTRY}/`);
|
|
61215
61351
|
var PERSONA_LAYER_SCRIPT = "/opt/persona-layer.mjs";
|
|
61216
61352
|
var CLOUD_PERSONAS_ROOT = "/clawd/personas";
|
|
61217
61353
|
var GITIGNORE_LINES = [
|
|
@@ -61236,9 +61372,9 @@ function personaIdOf(repoName) {
|
|
|
61236
61372
|
return String(repoName).toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
|
|
61237
61373
|
}
|
|
61238
61374
|
function renderDockerfile(personaId2, baseImage) {
|
|
61239
|
-
if (baseImage !==
|
|
61375
|
+
if (typeof baseImage !== "string" || !/^[a-z0-9.-]+(?::[0-9]+)?\/[a-z0-9._/-]+@sha256:[a-f0-9]{64}$/.test(baseImage)) throw new Error("base image must be a complete digest reference");
|
|
61240
61376
|
if (!/^[a-z0-9][a-z0-9-]{0,39}$/.test(personaId2)) throw new Error(`persona id \u4E0D\u5408\u5F62\u72B6\uFF08[a-z0-9-]\uFF0C\u226440\uFF09\uFF1A${JSON.stringify(personaId2)}`);
|
|
61241
|
-
const fromImage =
|
|
61377
|
+
const fromImage = baseImage.replace(`${ACR_VPC_REGISTRY}/`, `${ACR_REGISTRY}/`);
|
|
61242
61378
|
const dir = `${CLOUD_PERSONAS_ROOT}/${personaId2}`;
|
|
61243
61379
|
return [
|
|
61244
61380
|
"# \u7531 clawd \u751F\u6210\u3001\u7531 clawd \u7EF4\u62A4\uFF1A\u6BCF\u6B21\u300C\u53D1\u5E03\u300D\u90FD\u4F1A\u7528\u5F53\u524D\u6A21\u677F\u91CD\u5199\u8FD9\u4EFD\u6587\u4EF6\u518D\u63D0\u4EA4\uFF0C\u624B\u6539\u4F1A\u88AB\u76D6\u6389\u3002",
|
|
@@ -61522,19 +61658,11 @@ async function writeWorkflow(dir) {
|
|
|
61522
61658
|
await import_promises5.default.writeFile(wf, body);
|
|
61523
61659
|
}
|
|
61524
61660
|
}
|
|
61525
|
-
async function writeDockerfile(dir, personaId2) {
|
|
61526
|
-
|
|
61527
|
-
|
|
61528
|
-
|
|
61529
|
-
} catch (error) {
|
|
61530
|
-
if (error.code !== "ENOENT") throw error;
|
|
61531
|
-
}
|
|
61532
|
-
if (baseImage === void 0) {
|
|
61533
|
-
baseImage = BASE_IMAGE;
|
|
61534
|
-
await import_promises5.default.mkdir(import_node_path38.default.join(dir, ".clawd"), { recursive: true });
|
|
61535
|
-
await import_promises5.default.writeFile(import_node_path38.default.join(dir, ".clawd", "base-image.txt"), `${baseImage}
|
|
61661
|
+
async function writeDockerfile(dir, personaId2, image) {
|
|
61662
|
+
const baseImage = image.replace("registry-vpc.cn-hangzhou.aliyuncs.com/", "registry.cn-hangzhou.aliyuncs.com/");
|
|
61663
|
+
await import_promises5.default.mkdir(import_node_path38.default.join(dir, ".clawd"), { recursive: true });
|
|
61664
|
+
await import_promises5.default.writeFile(import_node_path38.default.join(dir, ".clawd", "base-image.txt"), `${baseImage}
|
|
61536
61665
|
`);
|
|
61537
|
-
}
|
|
61538
61666
|
await import_promises5.default.writeFile(import_node_path38.default.join(dir, DOCKERFILE_PATH), renderDockerfile(personaId2, baseImage));
|
|
61539
61667
|
await import_promises5.default.writeFile(import_node_path38.default.join(dir, DOCKERIGNORE_PATH), DOCKERIGNORE_TEMPLATE);
|
|
61540
61668
|
}
|
|
@@ -61638,6 +61766,7 @@ async function commitAll(exec, args) {
|
|
|
61638
61766
|
async function release(exec, api, args) {
|
|
61639
61767
|
const info = await repoInfo(exec, args.dir);
|
|
61640
61768
|
if (!info) throw new RepoError("\u8FD8\u6CA1\u6709\u4ED3\u5E93\uFF0C\u5148\u70B9\u4E00\u6B21\u300C\u53D1\u5E03\u5230\u4E91\u4E0A\u300D\u5EFA\u4ED3");
|
|
61769
|
+
const base = await readCurrentBase(api);
|
|
61641
61770
|
await prepareIntegration(exec, args.dir, args.auth);
|
|
61642
61771
|
const before = await readDeployFileRaw(args.dir);
|
|
61643
61772
|
let committed = false;
|
|
@@ -61646,7 +61775,7 @@ async function release(exec, api, args) {
|
|
|
61646
61775
|
await api.enableActions(repoSlug(info.url));
|
|
61647
61776
|
await writeGitignore(args.dir);
|
|
61648
61777
|
await writeWorkflow(args.dir);
|
|
61649
|
-
await writeDockerfile(args.dir, cloudPersonaIdOf(info.url));
|
|
61778
|
+
await writeDockerfile(args.dir, cloudPersonaIdOf(info.url), base.image);
|
|
61650
61779
|
const identity = await identityArgs(exec, args.dir);
|
|
61651
61780
|
await mustGit(exec, args.dir, ["add", "-A"], "\u6682\u5B58\u6587\u4EF6");
|
|
61652
61781
|
const stamp = new Date(args.now()).toISOString();
|
|
@@ -61668,7 +61797,7 @@ init_protocol();
|
|
|
61668
61797
|
function validatePersonaRelease(raw, expected) {
|
|
61669
61798
|
const record4 = VerifiedPersonaReleaseSchema.parse(raw);
|
|
61670
61799
|
if (record4.repository !== expected.repository || record4.commit !== expected.commit || new URL(record4.verification.endpoint).origin !== expected.endpoint) throw new Error("\u5236\u54C1\u4E0E\u672C\u6B21\u6D4B\u8BD5\u4ED3\u5E93\u3001\u63D0\u4EA4\u6216\u73AF\u5883\u4E0D\u4E00\u81F4");
|
|
61671
|
-
const fingerprint = (0,
|
|
61800
|
+
const fingerprint = (0, import_node_crypto11.createHash)("sha256").update(JSON.stringify({
|
|
61672
61801
|
component: record4.component,
|
|
61673
61802
|
image: record4.image,
|
|
61674
61803
|
commit: record4.commit,
|
|
@@ -61679,37 +61808,6 @@ function validatePersonaRelease(raw, expected) {
|
|
|
61679
61808
|
if (record4.verification.fingerprint !== fingerprint) throw new Error("\u5236\u54C1\u5DF2\u504F\u79BB\u6D4B\u8BD5\u65F6\u7684\u7248\u672C\uFF0C\u8BF7\u91CD\u65B0\u6D4B\u8BD5");
|
|
61680
61809
|
return record4;
|
|
61681
61810
|
}
|
|
61682
|
-
function inspectArchive(bytes) {
|
|
61683
|
-
const data = Buffer.from(bytes);
|
|
61684
|
-
let end = -1;
|
|
61685
|
-
for (let at4 = data.length - 22; at4 >= Math.max(0, data.length - 65557); at4--) {
|
|
61686
|
-
if (data.readUInt32LE(at4) === 101010256 && at4 + 22 + data.readUInt16LE(at4 + 20) === data.length) {
|
|
61687
|
-
end = at4;
|
|
61688
|
-
break;
|
|
61689
|
-
}
|
|
61690
|
-
}
|
|
61691
|
-
if (end < 0 || data.readUInt16LE(end + 4) || data.readUInt16LE(end + 6)) throw new Error("\u5236\u54C1\u5F52\u6863\u683C\u5F0F\u4E0D\u652F\u6301");
|
|
61692
|
-
const count = data.readUInt16LE(end + 10);
|
|
61693
|
-
const length = data.readUInt32LE(end + 12);
|
|
61694
|
-
let at3 = data.readUInt32LE(end + 16), roots = 0;
|
|
61695
|
-
if (count === 65535 || at3 + length !== end) throw new Error("\u5236\u54C1\u5F52\u6863\u683C\u5F0F\u4E0D\u652F\u6301");
|
|
61696
|
-
for (let i2 = 0; i2 < count; i2++) {
|
|
61697
|
-
if (at3 + 46 > end || data.readUInt32LE(at3) !== 33639248) throw new Error("\u5236\u54C1\u5F52\u6863\u683C\u5F0F\u4E0D\u6B63\u786E");
|
|
61698
|
-
const nameLength = data.readUInt16LE(at3 + 28);
|
|
61699
|
-
const next = at3 + 46 + nameLength + data.readUInt16LE(at3 + 30) + data.readUInt16LE(at3 + 32);
|
|
61700
|
-
if (next > end) throw new Error("\u5236\u54C1\u5F52\u6863\u683C\u5F0F\u4E0D\u6B63\u786E");
|
|
61701
|
-
const name = data.subarray(at3 + 46, at3 + 46 + nameLength).toString("utf8");
|
|
61702
|
-
if (name === "candidate-release.json") {
|
|
61703
|
-
roots++;
|
|
61704
|
-
if (data.readUInt32LE(at3 + 24) > 64 * 1024) throw new Error("\u5236\u54C1 JSON \u8D85\u8FC7\u5927\u5C0F\u9650\u5236");
|
|
61705
|
-
if (data.readUInt16LE(at3 + 8) & 1) throw new Error("\u5236\u54C1\u5F52\u6863\u4E0D\u80FD\u52A0\u5BC6");
|
|
61706
|
-
}
|
|
61707
|
-
at3 = next;
|
|
61708
|
-
}
|
|
61709
|
-
if (at3 !== end) throw new Error("\u5236\u54C1\u5F52\u6863\u683C\u5F0F\u4E0D\u6B63\u786E");
|
|
61710
|
-
if (roots > 1) throw new Error("\u5236\u54C1\u5F52\u6863\u6709\u91CD\u590D\u7684\u6839 JSON");
|
|
61711
|
-
if (roots !== 1) throw new Error("\u5236\u54C1\u7F3A\u5C11\u6839\u76EE\u5F55\u7684 candidate-release.json");
|
|
61712
|
-
}
|
|
61713
61811
|
async function readVerifiedRelease(api, slug, run) {
|
|
61714
61812
|
if (run.environment !== "integration" || run.status !== "completed" || run.conclusion !== "success" || !run.jobs.some((j2) => j2.key === "deploy" && j2.status === "done")) throw new Error("\u6D4B\u8BD5\u90E8\u7F72\u8FD8\u6CA1\u6709\u6210\u529F\uFF0C\u4E0D\u80FD\u8BFB\u53D6\u5DF2\u6D4B\u5236\u54C1");
|
|
61715
61813
|
let artifact;
|
|
@@ -61725,31 +61823,7 @@ async function readVerifiedRelease(api, slug, run) {
|
|
|
61725
61823
|
if (!artifact || artifact.expired || !Number.isSafeInteger(artifact.id) || artifact.id <= 0) throw new Error("\u5DF2\u6D4B\u5236\u54C1\u4E0D\u5B58\u5728\u6216\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u91CD\u65B0\u53D1\u5E03\u6D4B\u8BD5");
|
|
61726
61824
|
if (artifact.workflow_run && (artifact.workflow_run.id !== run.runId || artifact.workflow_run.head_sha !== run.headSha)) throw new Error("\u5236\u54C1\u4E0D\u5C5E\u4E8E\u672C\u6B21\u6D4B\u8BD5\u6D41\u6C34\u7EBF");
|
|
61727
61825
|
const bytes = await api.downloadArtifact(slug, artifact.id);
|
|
61728
|
-
|
|
61729
|
-
inspectArchive(bytes);
|
|
61730
|
-
const zip = await import_jszip.default.loadAsync(bytes);
|
|
61731
|
-
const entry = zip.file("candidate-release.json");
|
|
61732
|
-
if (!entry || entry.dir || entry.unsafeOriginalName && entry.unsafeOriginalName !== "candidate-release.json") throw new Error("\u5236\u54C1\u7F3A\u5C11\u6839\u76EE\u5F55\u7684 candidate-release.json");
|
|
61733
|
-
const chunks = [];
|
|
61734
|
-
let size = 0;
|
|
61735
|
-
await new Promise((resolve9, reject) => {
|
|
61736
|
-
const stream = entry.nodeStream("nodebuffer");
|
|
61737
|
-
stream.on("data", (data) => {
|
|
61738
|
-
size += data.length;
|
|
61739
|
-
if (size > 64 * 1024) {
|
|
61740
|
-
stream.pause();
|
|
61741
|
-
reject(new Error("\u5236\u54C1 JSON \u8D85\u8FC7\u5927\u5C0F\u9650\u5236"));
|
|
61742
|
-
return;
|
|
61743
|
-
}
|
|
61744
|
-
chunks.push(Buffer.from(data));
|
|
61745
|
-
}).on("error", reject).on("end", resolve9).resume();
|
|
61746
|
-
});
|
|
61747
|
-
let raw;
|
|
61748
|
-
try {
|
|
61749
|
-
raw = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
61750
|
-
} catch {
|
|
61751
|
-
throw new Error("\u5236\u54C1 JSON \u4E0D\u662F\u5408\u6CD5\u683C\u5F0F");
|
|
61752
|
-
}
|
|
61826
|
+
const raw = await readReleaseArchive(bytes);
|
|
61753
61827
|
return { artifactId: artifact.id, release: validatePersonaRelease(raw, {
|
|
61754
61828
|
repository: slug,
|
|
61755
61829
|
commit: run.headSha,
|
|
@@ -61757,8 +61831,8 @@ async function readVerifiedRelease(api, slug, run) {
|
|
|
61757
61831
|
}) };
|
|
61758
61832
|
}
|
|
61759
61833
|
function requireDialogueVerification(release2, run) {
|
|
61760
|
-
if (!release2.verification.checks.includes(
|
|
61761
|
-
throw new Error("\u8FD9\u6B21\u53D1\u5E03\u8FD8\u6CA1\u6709\u901A\u8FC7\u81EA\u52A8\
|
|
61834
|
+
if (!["persona-dialogue", "persona-task"].every((check) => release2.verification.checks.includes(check)) || !run.jobs.some((j2) => j2.key === DEPLOY_VERIFY_STAGE && j2.status === "done")) {
|
|
61835
|
+
throw new Error("\u8FD9\u6B21\u53D1\u5E03\u8FD8\u6CA1\u6709\u901A\u8FC7\u81EA\u52A8 Conversation / Task \u9A8C\u8BC1\uFF0C\u8BF7\u91CD\u65B0\u626B\u63CF\u5E76\u53D1\u5E03\u6D4B\u8BD5\u73AF\u5883");
|
|
61762
61836
|
}
|
|
61763
61837
|
}
|
|
61764
61838
|
function integrationPersonaForRelease(cloud, release2, releaseId) {
|
|
@@ -61844,7 +61918,7 @@ async function resumePromotion(deps, original, options = {}) {
|
|
|
61844
61918
|
init_protocol();
|
|
61845
61919
|
|
|
61846
61920
|
// src/deploy/artifact.ts
|
|
61847
|
-
var
|
|
61921
|
+
var import_node_crypto12 = require("crypto");
|
|
61848
61922
|
var import_node_fs34 = __toESM(require("fs"), 1);
|
|
61849
61923
|
var import_node_os11 = __toESM(require("os"), 1);
|
|
61850
61924
|
var import_node_path39 = __toESM(require("path"), 1);
|
|
@@ -61883,7 +61957,7 @@ function downloadArtifact(exec) {
|
|
|
61883
61957
|
if (declared > ARTIFACT_MAX_BYTES) throw new Error(`\u8D44\u4EA7 ${declared} \u5B57\u8282\uFF0C\u8D85\u8FC7\u4E0A\u9650 ${ARTIFACT_MAX_BYTES}\uFF1A${url}`);
|
|
61884
61958
|
const dir = await import_node_fs34.default.promises.mkdtemp(import_node_path39.default.join(import_node_os11.default.tmpdir(), "clawd-artifact-"));
|
|
61885
61959
|
const file = import_node_path39.default.join(dir, "pkg");
|
|
61886
|
-
const hash = (0,
|
|
61960
|
+
const hash = (0, import_node_crypto12.createHash)("sha256");
|
|
61887
61961
|
let size = 0;
|
|
61888
61962
|
const meter = new import_node_stream3.Transform({
|
|
61889
61963
|
transform(chunk, _enc, cb) {
|
|
@@ -62781,7 +62855,7 @@ function buildDeployHandlers(deps) {
|
|
|
62781
62855
|
if (blockers.length > 0) throw invalid(`\u8FD8\u5DEE\uFF1A${blockers.join("\uFF1B")}`);
|
|
62782
62856
|
await configureTestIdentity(api, repoSlug(repo2.url));
|
|
62783
62857
|
if (await deps.claimPublisher(cloudPersonaIdOf(repo2.url), "integration") === "taken") throw invalid("\u6D4B\u8BD5\u73AF\u5883\u91CC\u7684\u8FD9\u4E2A\u540D\u5B57\u5DF2\u7531\u522B\u4EBA\u53D1\u5E03");
|
|
62784
|
-
const releaseId = (0,
|
|
62858
|
+
const releaseId = (0, import_node_crypto13.randomUUID)();
|
|
62785
62859
|
try {
|
|
62786
62860
|
const result = await release(deps.exec, api, { dir, now: deps.now, auth, manifest: entry.manifest, onPrepared: async (head) => {
|
|
62787
62861
|
const latest2 = await readHistory(dir);
|
|
@@ -62934,7 +63008,7 @@ function buildDeployHandlers(deps) {
|
|
|
62934
63008
|
const latest = await readHistory(mustPersona(personaId2));
|
|
62935
63009
|
await writeScanFile(mustPersona(personaId2), { ...latest, promotions: latest.promotions.map((p3) => p3.id === old.id ? { ...p3, phase: "failed", error: "\u51C6\u5907\u9636\u6BB5\u6D4B\u8BD5\u7248\u672C\u5DF2\u53D8\u5316\uFF0C\u5DF2\u7531\u91CD\u65B0\u786E\u8BA4\u7684\u65B0\u4EFB\u52A1\u66FF\u4EE3" } : p3) });
|
|
62936
63010
|
}
|
|
62937
|
-
const promotion = await continuePromotion(personaId2, record4, reuse ? { ...old, verified: snapshot ?? record4.verified } : { id: (0,
|
|
63011
|
+
const promotion = await continuePromotion(personaId2, record4, reuse ? { ...old, verified: snapshot ?? record4.verified } : { id: (0, import_node_crypto13.randomUUID)(), releaseId, at: deps.now(), phase: "prepared", verified: record4.verified }, true);
|
|
62938
63012
|
return { response: { type: "deploy:promote", promotion } };
|
|
62939
63013
|
};
|
|
62940
63014
|
const openTest = async (frame, _client, ctx) => {
|
|
@@ -64720,7 +64794,7 @@ ${formatLarkSpeakerReminder(speaker)}`
|
|
|
64720
64794
|
}
|
|
64721
64795
|
|
|
64722
64796
|
// src/lark-bot-connector/envelope.ts
|
|
64723
|
-
var
|
|
64797
|
+
var import_node_crypto14 = require("crypto");
|
|
64724
64798
|
var LARK_ENVELOPE_PREFIX = "clawdlbe1";
|
|
64725
64799
|
function verifyLarkEventEnvelope(args) {
|
|
64726
64800
|
const { token, publicKeyPem } = args;
|
|
@@ -64739,7 +64813,7 @@ function verifyLarkEventEnvelope(args) {
|
|
|
64739
64813
|
const data = Buffer.from(`${prefix}.${payloadB64}`, "utf8");
|
|
64740
64814
|
let sigOk = false;
|
|
64741
64815
|
try {
|
|
64742
|
-
sigOk = (0,
|
|
64816
|
+
sigOk = (0, import_node_crypto14.verify)(null, data, publicKeyPem, Buffer.from(sigB64, "base64url"));
|
|
64743
64817
|
} catch {
|
|
64744
64818
|
sigOk = false;
|
|
64745
64819
|
}
|
|
@@ -65342,7 +65416,7 @@ async function portableCloudInput(text, resolvers) {
|
|
|
65342
65416
|
}
|
|
65343
65417
|
|
|
65344
65418
|
// src/tools/cloud-turn-session.ts
|
|
65345
|
-
var
|
|
65419
|
+
var import_node_crypto15 = require("crypto");
|
|
65346
65420
|
function createCloudTurnSession(args) {
|
|
65347
65421
|
const { ctx, sink, client, personaId: personaId2, engine, instructions, engineSessionId, prepare } = args;
|
|
65348
65422
|
let conversationId = ctx.cloudConversationId ?? ctx.cloudExecutionId;
|
|
@@ -65364,7 +65438,7 @@ function createCloudTurnSession(args) {
|
|
|
65364
65438
|
void client.commandTurn(personaId2, conversationId, turnId, command).catch((e) => sink.onError(`\u4E91\u4E0A\u547D\u4EE4\u5931\u8D25\uFF1A${e.message}`));
|
|
65365
65439
|
};
|
|
65366
65440
|
return {
|
|
65367
|
-
startTurn(text, commandId = (0,
|
|
65441
|
+
startTurn(text, commandId = (0, import_node_crypto15.randomUUID)(), prepared = false) {
|
|
65368
65442
|
if (closed || live.has(commandId)) return;
|
|
65369
65443
|
conversationId ??= commandId;
|
|
65370
65444
|
live.add(commandId);
|
|
@@ -65677,7 +65751,7 @@ var PiRpcClient = class {
|
|
|
65677
65751
|
|
|
65678
65752
|
// src/tools/pi-session.ts
|
|
65679
65753
|
var import_node_child_process11 = require("child_process");
|
|
65680
|
-
var
|
|
65754
|
+
var import_node_crypto16 = require("crypto");
|
|
65681
65755
|
var import_node_fs40 = __toESM(require("fs"), 1);
|
|
65682
65756
|
var import_node_path44 = __toESM(require("path"), 1);
|
|
65683
65757
|
|
|
@@ -65959,7 +66033,7 @@ ${dirs.map((d2) => `- ${d2}`).join("\n")}`;
|
|
|
65959
66033
|
}
|
|
65960
66034
|
function createPiSession(ctx, sink, deps = {}) {
|
|
65961
66035
|
const cmd = process.env.PI_BIN ?? "pi";
|
|
65962
|
-
const sessionId = ctx.toolSessionId ?? (0,
|
|
66036
|
+
const sessionId = ctx.toolSessionId ?? (0, import_node_crypto16.randomUUID)();
|
|
65963
66037
|
const skillsDir = import_node_path44.default.join(ctx.cwd, ".claude", "skills");
|
|
65964
66038
|
const exists = deps.skillsDirExists ?? ((d2) => import_node_fs40.default.existsSync(d2));
|
|
65965
66039
|
const args = buildPiArgs(ctx, {
|
|
@@ -67321,7 +67395,7 @@ var wrapper_default = import_websocket.default;
|
|
|
67321
67395
|
|
|
67322
67396
|
// src/transport/local-ws-server.ts
|
|
67323
67397
|
var import_node_http = __toESM(require("http"), 1);
|
|
67324
|
-
var
|
|
67398
|
+
var import_node_crypto17 = require("crypto");
|
|
67325
67399
|
var LocalWsServer = class {
|
|
67326
67400
|
constructor(opts) {
|
|
67327
67401
|
this.opts = opts;
|
|
@@ -67531,7 +67605,7 @@ var LocalWsServer = class {
|
|
|
67531
67605
|
}
|
|
67532
67606
|
}
|
|
67533
67607
|
onConnection(socket, remoteAddress) {
|
|
67534
|
-
const id = (0,
|
|
67608
|
+
const id = (0, import_node_crypto17.randomUUID)();
|
|
67535
67609
|
const subscribedSessions = /* @__PURE__ */ new Map();
|
|
67536
67610
|
const handle = {
|
|
67537
67611
|
id,
|
|
@@ -68447,7 +68521,7 @@ var import_node_path53 = __toESM(require("path"), 1);
|
|
|
68447
68521
|
// src/attachment/upload.ts
|
|
68448
68522
|
var import_node_fs47 = __toESM(require("fs"), 1);
|
|
68449
68523
|
var import_node_path51 = __toESM(require("path"), 1);
|
|
68450
|
-
var
|
|
68524
|
+
var import_node_crypto18 = __toESM(require("crypto"), 1);
|
|
68451
68525
|
var import_promises8 = require("stream/promises");
|
|
68452
68526
|
var UploadError = class extends Error {
|
|
68453
68527
|
constructor(code, message) {
|
|
@@ -68471,11 +68545,11 @@ async function writeUploadedAttachment(args) {
|
|
|
68471
68545
|
} catch (err) {
|
|
68472
68546
|
throw new UploadError("STORAGE_ERROR", `mkdir failed: ${err.message}`);
|
|
68473
68547
|
}
|
|
68474
|
-
const hasher =
|
|
68548
|
+
const hasher = import_node_crypto18.default.createHash("sha256");
|
|
68475
68549
|
let actualSize = 0;
|
|
68476
68550
|
const tmpPath = import_node_path51.default.join(
|
|
68477
68551
|
attachmentsRoot,
|
|
68478
|
-
`.upload-${process.pid}-${Date.now()}-${
|
|
68552
|
+
`.upload-${process.pid}-${Date.now()}-${import_node_crypto18.default.randomBytes(4).toString("hex")}`
|
|
68479
68553
|
);
|
|
68480
68554
|
try {
|
|
68481
68555
|
await (0, import_promises8.pipeline)(
|
|
@@ -69325,7 +69399,7 @@ function runAttachmentGc(args) {
|
|
|
69325
69399
|
// src/attachment/group.ts
|
|
69326
69400
|
var import_node_fs50 = __toESM(require("fs"), 1);
|
|
69327
69401
|
var import_node_path55 = __toESM(require("path"), 1);
|
|
69328
|
-
var
|
|
69402
|
+
var import_node_crypto19 = __toESM(require("crypto"), 1);
|
|
69329
69403
|
init_protocol();
|
|
69330
69404
|
var GroupFileStore = class {
|
|
69331
69405
|
dataDir;
|
|
@@ -69403,7 +69477,7 @@ var GroupFileStore = class {
|
|
|
69403
69477
|
entries[idx] = next;
|
|
69404
69478
|
} else {
|
|
69405
69479
|
next = {
|
|
69406
|
-
id: `gf-${
|
|
69480
|
+
id: `gf-${import_node_crypto19.default.randomBytes(6).toString("base64url")}`,
|
|
69407
69481
|
relPath: input.relPath,
|
|
69408
69482
|
from: input.from,
|
|
69409
69483
|
label: input.label,
|
|
@@ -69525,7 +69599,7 @@ function readSpawnedByDesktopFromEnv(env = process.env) {
|
|
|
69525
69599
|
// src/tunnel/tunnel-manager.ts
|
|
69526
69600
|
var import_node_fs55 = __toESM(require("fs"), 1);
|
|
69527
69601
|
var import_node_path60 = __toESM(require("path"), 1);
|
|
69528
|
-
var
|
|
69602
|
+
var import_node_crypto20 = __toESM(require("crypto"), 1);
|
|
69529
69603
|
var import_node_child_process16 = require("child_process");
|
|
69530
69604
|
|
|
69531
69605
|
// src/tunnel/tunnel-store.ts
|
|
@@ -70022,7 +70096,7 @@ var TunnelManager = class {
|
|
|
70022
70096
|
override: this.deps.frpcBinaryOverride ?? void 0
|
|
70023
70097
|
});
|
|
70024
70098
|
const tomlPath = import_node_path60.default.join(this.deps.dataDir, "frpc.toml");
|
|
70025
|
-
const proxyName = `clawd-${t2.subdomain}-${localPort}-${
|
|
70099
|
+
const proxyName = `clawd-${t2.subdomain}-${localPort}-${import_node_crypto20.default.randomBytes(3).toString("hex")}`;
|
|
70026
70100
|
const toml = buildFrpcToml({
|
|
70027
70101
|
serverAddr: t2.frpsHost,
|
|
70028
70102
|
serverPort: t2.frpsPort,
|
|
@@ -70123,7 +70197,7 @@ async function waitForFrpcReady(proc, timeoutMs) {
|
|
|
70123
70197
|
// src/tunnel/device-key.ts
|
|
70124
70198
|
var import_node_os22 = __toESM(require("os"), 1);
|
|
70125
70199
|
var import_node_path61 = __toESM(require("path"), 1);
|
|
70126
|
-
var
|
|
70200
|
+
var import_node_crypto21 = __toESM(require("crypto"), 1);
|
|
70127
70201
|
var DERIVE_SALT = "clawd-tunnel-device-v1";
|
|
70128
70202
|
function deriveStableDeviceKey(opts = {}) {
|
|
70129
70203
|
const hostname = opts.hostname ?? import_node_os22.default.hostname();
|
|
@@ -70133,13 +70207,13 @@ function deriveStableDeviceKey(opts = {}) {
|
|
|
70133
70207
|
const normalizedDataDir = opts.dataDir ? import_node_path61.default.resolve(opts.dataDir) : null;
|
|
70134
70208
|
const isDefaultDir = normalizedDataDir == null || normalizedDataDir === defaultDataDir;
|
|
70135
70209
|
const input = isDefaultDir ? `${hostname}::${uid}` : `${hostname}::${uid}::${normalizedDataDir}`;
|
|
70136
|
-
return
|
|
70210
|
+
return import_node_crypto21.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
|
|
70137
70211
|
}
|
|
70138
70212
|
|
|
70139
70213
|
// src/auth-store.ts
|
|
70140
70214
|
var import_node_fs56 = __toESM(require("fs"), 1);
|
|
70141
70215
|
var import_node_path62 = __toESM(require("path"), 1);
|
|
70142
|
-
var
|
|
70216
|
+
var import_node_crypto22 = __toESM(require("crypto"), 1);
|
|
70143
70217
|
var AUTH_FILE_NAME = "auth.json";
|
|
70144
70218
|
function authFilePath(dataDir) {
|
|
70145
70219
|
return import_node_path62.default.join(dataDir, AUTH_FILE_NAME);
|
|
@@ -70176,10 +70250,10 @@ function loadOrCreateTunnelDeviceKey(opts) {
|
|
|
70176
70250
|
return tunnelDeviceKey;
|
|
70177
70251
|
}
|
|
70178
70252
|
function defaultGenerateToken() {
|
|
70179
|
-
return
|
|
70253
|
+
return import_node_crypto22.default.randomBytes(32).toString("base64url");
|
|
70180
70254
|
}
|
|
70181
70255
|
function defaultGenerateOwnerPrincipalId() {
|
|
70182
|
-
return `owner-${
|
|
70256
|
+
return `owner-${import_node_crypto22.default.randomUUID()}`;
|
|
70183
70257
|
}
|
|
70184
70258
|
function readAuthFile(file) {
|
|
70185
70259
|
try {
|
|
@@ -70311,7 +70385,7 @@ var OwnerIdentityStore = class {
|
|
|
70311
70385
|
};
|
|
70312
70386
|
|
|
70313
70387
|
// src/feishu-auth/login-flow.ts
|
|
70314
|
-
var
|
|
70388
|
+
var import_node_crypto23 = __toESM(require("crypto"), 1);
|
|
70315
70389
|
var STATE_TTL_MS = 5 * 60 * 1e3;
|
|
70316
70390
|
var LoginFlow = class {
|
|
70317
70391
|
constructor(deps) {
|
|
@@ -70321,7 +70395,7 @@ var LoginFlow = class {
|
|
|
70321
70395
|
pendingStates = /* @__PURE__ */ new Map();
|
|
70322
70396
|
generation = 0;
|
|
70323
70397
|
start() {
|
|
70324
|
-
const state =
|
|
70398
|
+
const state = import_node_crypto23.default.randomBytes(16).toString("base64url");
|
|
70325
70399
|
const now = (this.deps.now ?? Date.now)();
|
|
70326
70400
|
this.pendingStates.set(state, { issuedAt: now, owner: this.deps.expectedUnionId?.() });
|
|
70327
70401
|
this.gcExpired(now);
|
|
@@ -70855,7 +70929,7 @@ init_protocol();
|
|
|
70855
70929
|
var import_node_fs59 = __toESM(require("fs"), 1);
|
|
70856
70930
|
var import_node_os24 = __toESM(require("os"), 1);
|
|
70857
70931
|
var import_node_path65 = __toESM(require("path"), 1);
|
|
70858
|
-
var
|
|
70932
|
+
var import_node_crypto24 = require("crypto");
|
|
70859
70933
|
init_claude_history();
|
|
70860
70934
|
function readJsonlEntries(file) {
|
|
70861
70935
|
const raw = import_node_fs59.default.readFileSync(file, "utf8");
|
|
@@ -70892,7 +70966,7 @@ function forkSession(input) {
|
|
|
70892
70966
|
throw new Error(`fork: messageUuid not found in transcript: ${input.messageUuid}`);
|
|
70893
70967
|
}
|
|
70894
70968
|
const sliced = mainEntries.slice(0, targetIdx + 1);
|
|
70895
|
-
const forkedToolSessionId = (0,
|
|
70969
|
+
const forkedToolSessionId = (0, import_node_crypto24.randomUUID)();
|
|
70896
70970
|
let parentUuid = null;
|
|
70897
70971
|
const forkedLines = [];
|
|
70898
70972
|
for (const entry of sliced) {
|
|
@@ -70946,10 +71020,15 @@ async function forkCodexThread(input, deps = {}) {
|
|
|
70946
71020
|
if (rollout.meta?.threadId.toLowerCase() !== input.sourceThreadId.toLowerCase()) {
|
|
70947
71021
|
throw new Error(`codex fork: source thread metadata does not match ${input.sourceThreadId}`);
|
|
70948
71022
|
}
|
|
70949
|
-
|
|
70950
|
-
|
|
71023
|
+
const completed = (turns) => turns.some((turn) => turn.turnId === input.turnId && turn.status === "completed");
|
|
71024
|
+
let owner2 = { threadId: input.sourceThreadId, home: source.home };
|
|
71025
|
+
if (!completed(rollout.turns)) {
|
|
71026
|
+
const segment = parseCodexThreadSegments(createCodexRolloutLocator(input.roots), input.sourceThreadId).find((item) => completed(item.parsed.turns));
|
|
71027
|
+
const home = segment && locateCodexThread(input.roots, segment.threadId)?.home;
|
|
71028
|
+
if (!segment || !home) throw new Error(`codex fork: completed turn not found: ${input.turnId}`);
|
|
71029
|
+
owner2 = { threadId: segment.threadId, home };
|
|
70951
71030
|
}
|
|
70952
|
-
const connection = (deps.open ?? openCodexAppServer)(
|
|
71031
|
+
const connection = (deps.open ?? openCodexAppServer)(owner2.home, input.targetCwd);
|
|
70953
71032
|
const timeoutMs = deps.timeoutMs ?? DEFAULT_CODEX_QUERY_TIMEOUT_MS;
|
|
70954
71033
|
let timer;
|
|
70955
71034
|
const timeout = new Promise((_3, reject) => {
|
|
@@ -70964,7 +71043,7 @@ async function forkCodexThread(input, deps = {}) {
|
|
|
70964
71043
|
});
|
|
70965
71044
|
client.notify("initialized", {});
|
|
70966
71045
|
const result = await client.request("thread/fork", {
|
|
70967
|
-
threadId:
|
|
71046
|
+
threadId: owner2.threadId,
|
|
70968
71047
|
lastTurnId: input.turnId,
|
|
70969
71048
|
cwd: input.targetCwd
|
|
70970
71049
|
});
|
|
@@ -70972,7 +71051,7 @@ async function forkCodexThread(input, deps = {}) {
|
|
|
70972
71051
|
if (typeof forkedToolSessionId !== "string" || !forkedToolSessionId) {
|
|
70973
71052
|
throw new Error("codex fork: app-server returned no thread id");
|
|
70974
71053
|
}
|
|
70975
|
-
const forked = locateCodexThread([import_node_path66.default.join(
|
|
71054
|
+
const forked = locateCodexThread([import_node_path66.default.join(owner2.home, "sessions")], forkedToolSessionId);
|
|
70976
71055
|
if (!forked) throw new Error(`codex fork: rollout not found for forked thread ${forkedToolSessionId}`);
|
|
70977
71056
|
return { forkedToolSessionId, forkedFilePath: forked.file };
|
|
70978
71057
|
})()]);
|
|
@@ -73651,7 +73730,7 @@ function computeMethodAccess(args) {
|
|
|
73651
73730
|
}
|
|
73652
73731
|
|
|
73653
73732
|
// src/version.ts
|
|
73654
|
-
var version = "0.2.
|
|
73733
|
+
var version = "0.2.635".length > 0 ? "0.2.635" : "dev";
|
|
73655
73734
|
|
|
73656
73735
|
// src/cli-probe/probe.ts
|
|
73657
73736
|
var fs84 = __toESM(require("fs"), 1);
|
|
@@ -74045,7 +74124,7 @@ init_protocol();
|
|
|
74045
74124
|
// src/extension/bundle-zip.ts
|
|
74046
74125
|
var import_promises12 = __toESM(require("fs/promises"), 1);
|
|
74047
74126
|
var import_node_path74 = __toESM(require("path"), 1);
|
|
74048
|
-
var
|
|
74127
|
+
var import_node_crypto25 = __toESM(require("crypto"), 1);
|
|
74049
74128
|
var import_jszip3 = __toESM(require_lib3(), 1);
|
|
74050
74129
|
async function bundleExtensionDir(dir) {
|
|
74051
74130
|
const entries = await listFilesSorted(dir);
|
|
@@ -74060,7 +74139,7 @@ async function bundleExtensionDir(dir) {
|
|
|
74060
74139
|
compression: "DEFLATE",
|
|
74061
74140
|
compressionOptions: { level: 6 }
|
|
74062
74141
|
});
|
|
74063
|
-
const sha256 =
|
|
74142
|
+
const sha256 = import_node_crypto25.default.createHash("sha256").update(buffer).digest("hex");
|
|
74064
74143
|
return { buffer, sha256 };
|
|
74065
74144
|
}
|
|
74066
74145
|
var FIXED_DATE = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
|
|
@@ -74128,7 +74207,7 @@ function computePublishCheck(args) {
|
|
|
74128
74207
|
var import_promises13 = __toESM(require("fs/promises"), 1);
|
|
74129
74208
|
var import_node_path76 = __toESM(require("path"), 1);
|
|
74130
74209
|
var import_node_os28 = __toESM(require("os"), 1);
|
|
74131
|
-
var
|
|
74210
|
+
var import_node_crypto26 = __toESM(require("crypto"), 1);
|
|
74132
74211
|
var import_jszip4 = __toESM(require_lib3(), 1);
|
|
74133
74212
|
|
|
74134
74213
|
// src/extension/paths.ts
|
|
@@ -74157,7 +74236,7 @@ var InstallError = class extends Error {
|
|
|
74157
74236
|
};
|
|
74158
74237
|
async function installFromChannel(args, deps) {
|
|
74159
74238
|
const { channelRef, snapshotHash, bundleZip } = args;
|
|
74160
|
-
const computed =
|
|
74239
|
+
const computed = import_node_crypto26.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
74161
74240
|
if (computed !== snapshotHash) {
|
|
74162
74241
|
throw new InstallError(
|
|
74163
74242
|
"HASH_MISMATCH",
|
|
@@ -74249,7 +74328,7 @@ async function installFromChannel(args, deps) {
|
|
|
74249
74328
|
var import_promises14 = __toESM(require("fs/promises"), 1);
|
|
74250
74329
|
var import_node_path77 = __toESM(require("path"), 1);
|
|
74251
74330
|
var import_node_os29 = __toESM(require("os"), 1);
|
|
74252
|
-
var
|
|
74331
|
+
var import_node_crypto27 = __toESM(require("crypto"), 1);
|
|
74253
74332
|
var import_jszip5 = __toESM(require_lib3(), 1);
|
|
74254
74333
|
var UpdateError = class extends Error {
|
|
74255
74334
|
constructor(code, message) {
|
|
@@ -74287,7 +74366,7 @@ async function updateFromChannel(args, deps) {
|
|
|
74287
74366
|
if (e instanceof UpdateError) throw e;
|
|
74288
74367
|
throw e;
|
|
74289
74368
|
}
|
|
74290
|
-
const computed =
|
|
74369
|
+
const computed = import_node_crypto27.default.createHash("sha256").update(bundleZip).digest("hex");
|
|
74291
74370
|
if (computed !== snapshotHash) {
|
|
74292
74371
|
throw new UpdateError(
|
|
74293
74372
|
"HASH_MISMATCH",
|
|
@@ -75415,7 +75494,7 @@ async function uninstall(deps) {
|
|
|
75415
75494
|
}
|
|
75416
75495
|
|
|
75417
75496
|
// src/handlers/index.ts
|
|
75418
|
-
var
|
|
75497
|
+
var import_node_crypto28 = require("crypto");
|
|
75419
75498
|
|
|
75420
75499
|
// src/handlers/peer-exec.ts
|
|
75421
75500
|
init_protocol();
|
|
@@ -75572,7 +75651,7 @@ function buildMethodHandlers(deps) {
|
|
|
75572
75651
|
const c2 = deps.contactStore.get(deviceId);
|
|
75573
75652
|
return c2 ? { deviceId: c2.deviceId, remoteUrl: c2.remoteUrl, connectToken: c2.connectToken } : null;
|
|
75574
75653
|
},
|
|
75575
|
-
genId: () => (0,
|
|
75654
|
+
genId: () => (0, import_node_crypto28.randomUUID)(),
|
|
75576
75655
|
now: () => Date.now(),
|
|
75577
75656
|
forwardInboxPostToPeer,
|
|
75578
75657
|
logger: deps.logger
|
|
@@ -76292,7 +76371,7 @@ async function startDaemon(config) {
|
|
|
76292
76371
|
const channelStore = createChannelStore({
|
|
76293
76372
|
filePath: import_node_path85.default.join(config.dataDir, "channels.json"),
|
|
76294
76373
|
now: () => Date.now(),
|
|
76295
|
-
genId: () => `ch-${(0,
|
|
76374
|
+
genId: () => `ch-${(0, import_node_crypto29.randomUUID)().slice(0, 8)}`,
|
|
76296
76375
|
onFlushError: (err) => logger.error("channel store flush failed", {
|
|
76297
76376
|
reason: err instanceof Error ? err.message : String(err)
|
|
76298
76377
|
})
|
|
@@ -76301,7 +76380,7 @@ async function startDaemon(config) {
|
|
|
76301
76380
|
const topicStore = createTopicStore({
|
|
76302
76381
|
filePath: import_node_path85.default.join(config.dataDir, "topics.json"),
|
|
76303
76382
|
now: () => Date.now(),
|
|
76304
|
-
genId: () => `tp-${(0,
|
|
76383
|
+
genId: () => `tp-${(0, import_node_crypto29.randomUUID)().slice(0, 8)}`,
|
|
76305
76384
|
onFlushError: (err) => logger.error("topic store flush failed", {
|
|
76306
76385
|
reason: err instanceof Error ? err.message : String(err)
|
|
76307
76386
|
})
|
|
@@ -76309,7 +76388,7 @@ async function startDaemon(config) {
|
|
|
76309
76388
|
await topicStore.load();
|
|
76310
76389
|
let deliverPendingRef;
|
|
76311
76390
|
const personaDispatchManager = new PersonaDispatchManager({
|
|
76312
|
-
genId: () => (0,
|
|
76391
|
+
genId: () => (0, import_node_crypto29.randomUUID)(),
|
|
76313
76392
|
store: dispatchStore,
|
|
76314
76393
|
now: () => Date.now(),
|
|
76315
76394
|
onCompleted: (sid) => deliverPendingRef?.(sid),
|