@clawos-dev/clawd 0.2.631 → 0.2.634

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 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: createHash6 } = require("crypto");
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 = createHash6("sha1").update(key + GUID).digest("base64");
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: createHash6 } = require("crypto");
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 = createHash6("sha1").update(key + GUID).digest("base64");
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 = this.parseThreadSegments(locate, args.toolSessionId);
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 = this.parseThreadSegments(locate, args.toolSessionId).find((segment) => segment.parsed.subagents.some((sub) => sub.agentId === args.subagentId));
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 = this.parseThreadSegments(locate, threadId);
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 import_node_crypto30 = require("crypto");
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
- ...isCloudTool(state.file.tool) && state.file.cloudGatewaySessionId && !next.file.cloudGatewaySessionId ? [{ kind: "persist-file", file: next.file }] : [],
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 ?? []) this.session?.startTurn(turn.text, turn.id, turn.prepared === true);
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 || prepared && pending.text !== text) return false;
48228
- if (!prepared) {
48229
- this.hooks.store.write(this.state.file.cloudPendingTurns?.some((turn) => turn.id === commandId) ? { ...this.state.file, cloudPendingTurns: this.state.file.cloudPendingTurns.map((turn) => turn.id === commandId ? { ...turn, text, prepared: true } : turn) } : { ...this.state.file, cloudPendingCommand: { id: commandId, text, prepared: true } });
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
- const runner = this.runners.get(args.sessionId) ?? null;
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 import_node_crypto14 = require("crypto");
56583
+ var import_node_crypto13 = require("crypto");
56542
56584
 
56543
56585
  // src/deploy/verified-release.ts
56544
- var import_node_crypto12 = require("crypto");
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
- const retryWait = () => new Promise((resolve9) => {
56757
- const timer = setTimeout(resolve9, 250);
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 (!closed) await retryWait();
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 !== void 0 && !/^[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");
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 = (baseImage ?? BASE_IMAGE).replace(`${ACR_VPC_REGISTRY}/`, `${ACR_REGISTRY}/`);
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
- let baseImage;
61527
- try {
61528
- baseImage = (await import_promises5.default.readFile(import_node_path38.default.join(dir, ".clawd", "base-image.txt"), "utf8")).trim();
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, import_node_crypto12.createHash)("sha256").update(JSON.stringify({
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
- if (bytes.length > 1024 * 1024) throw new Error("\u5236\u54C1\u5F52\u6863\u8D85\u8FC7\u5927\u5C0F\u9650\u5236");
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("persona-dialogue") || !run.jobs.some((j2) => j2.key === DEPLOY_VERIFY_STAGE && j2.status === "done")) {
61761
- throw new Error("\u8FD9\u6B21\u53D1\u5E03\u8FD8\u6CA1\u6709\u901A\u8FC7\u81EA\u52A8\u5BF9\u8BDD\u9A8C\u8BC1\uFF0C\u8BF7\u91CD\u65B0\u626B\u63CF\u5E76\u53D1\u5E03\u6D4B\u8BD5\u73AF\u5883");
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 import_node_crypto13 = require("crypto");
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, import_node_crypto13.createHash)("sha256");
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, import_node_crypto14.randomUUID)();
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, import_node_crypto14.randomUUID)(), releaseId, at: deps.now(), phase: "prepared", verified: record4.verified }, true);
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 import_node_crypto15 = require("crypto");
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, import_node_crypto15.verify)(null, data, publicKeyPem, Buffer.from(sigB64, "base64url"));
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 import_node_crypto16 = require("crypto");
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, import_node_crypto16.randomUUID)(), prepared = false) {
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 import_node_crypto17 = require("crypto");
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, import_node_crypto17.randomUUID)();
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 import_node_crypto18 = require("crypto");
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, import_node_crypto18.randomUUID)();
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 import_node_crypto19 = __toESM(require("crypto"), 1);
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 = import_node_crypto19.default.createHash("sha256");
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()}-${import_node_crypto19.default.randomBytes(4).toString("hex")}`
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 import_node_crypto20 = __toESM(require("crypto"), 1);
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-${import_node_crypto20.default.randomBytes(6).toString("base64url")}`,
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 import_node_crypto21 = __toESM(require("crypto"), 1);
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}-${import_node_crypto21.default.randomBytes(3).toString("hex")}`;
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 import_node_crypto22 = __toESM(require("crypto"), 1);
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 import_node_crypto22.default.createHmac("sha256", DERIVE_SALT).update(input).digest("hex").slice(0, 32);
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 import_node_crypto23 = __toESM(require("crypto"), 1);
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 import_node_crypto23.default.randomBytes(32).toString("base64url");
70253
+ return import_node_crypto22.default.randomBytes(32).toString("base64url");
70180
70254
  }
70181
70255
  function defaultGenerateOwnerPrincipalId() {
70182
- return `owner-${import_node_crypto23.default.randomUUID()}`;
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 import_node_crypto24 = __toESM(require("crypto"), 1);
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 = import_node_crypto24.default.randomBytes(16).toString("base64url");
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 import_node_crypto25 = require("crypto");
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, import_node_crypto25.randomUUID)();
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
- if (!rollout.turns.some((turn) => turn.turnId === input.turnId && turn.status === "completed")) {
70950
- throw new Error(`codex fork: completed turn not found: ${input.turnId}`);
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)(source.home, input.targetCwd);
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: input.sourceThreadId,
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(source.home, "sessions")], forkedToolSessionId);
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.631".length > 0 ? "0.2.631" : "dev";
73733
+ var version = "0.2.634".length > 0 ? "0.2.634" : "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 import_node_crypto26 = __toESM(require("crypto"), 1);
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 = import_node_crypto26.default.createHash("sha256").update(buffer).digest("hex");
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 import_node_crypto27 = __toESM(require("crypto"), 1);
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 = import_node_crypto27.default.createHash("sha256").update(bundleZip).digest("hex");
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 import_node_crypto28 = __toESM(require("crypto"), 1);
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 = import_node_crypto28.default.createHash("sha256").update(bundleZip).digest("hex");
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 import_node_crypto29 = require("crypto");
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, import_node_crypto29.randomUUID)(),
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, import_node_crypto30.randomUUID)().slice(0, 8)}`,
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, import_node_crypto30.randomUUID)().slice(0, 8)}`,
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, import_node_crypto30.randomUUID)(),
76391
+ genId: () => (0, import_node_crypto29.randomUUID)(),
76313
76392
  store: dispatchStore,
76314
76393
  now: () => Date.now(),
76315
76394
  onCompleted: (sid) => deliverPendingRef?.(sid),