@clawos-dev/clawd 0.2.700 → 0.2.702

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.
@@ -31133,6 +31133,11 @@ var CloudWorkspaceResultSchema = external_exports.object({
31133
31133
  notStored: external_exports.boolean().optional()
31134
31134
  }).optional()
31135
31135
  });
31136
+ var CloudForkResultSchema = external_exports.object({
31137
+ threadId: external_exports.string().min(1),
31138
+ conversationId: external_exports.string().min(1),
31139
+ workspace: WorkspaceBindingSchema.optional()
31140
+ });
31136
31141
 
31137
31142
  // ../protocol/src/subscription-channel.ts
31138
31143
  var SubscriptionChannelSchema = external_exports.object({
@@ -33349,6 +33354,11 @@ var SessionCreateArgs = external_exports.object({
33349
33354
  serviceTier: CodexServiceTierSchema.optional(),
33350
33355
  iconKey: external_exports.string().optional(),
33351
33356
  forkedFromSessionId: external_exports.string().min(1).optional(),
33357
+ /** Cloud fork point (with forkedFromSessionId of a cloud session): Claude cuts at a message, Codex at a completed turn. */
33358
+ forkAt: external_exports.union([
33359
+ external_exports.object({ messageUuid: external_exports.string().min(1) }).strict(),
33360
+ external_exports.object({ turnId: external_exports.string().min(1) }).strict()
33361
+ ]).optional(),
33352
33362
  ephemeral: external_exports.boolean().optional(),
33353
33363
  // Persona context derives cwd and spawn defaults; missing cwd is allowed when persona identity determines it.
33354
33364
  ownerPersonaId: external_exports.string().min(1).optional(),
package/dist/cli.cjs CHANGED
@@ -4150,7 +4150,7 @@ var init_zod = __esm({
4150
4150
  });
4151
4151
 
4152
4152
  // ../protocol/src/cloud-workspace-schemas.ts
4153
- var WORKSPACE_COMPARISON_VALUES, Id, RepoId, Part, WorkspaceBranchSchema, FilePath, WorkspaceBindingSchema, WorkspaceRepoSchema, WorkspaceStatusSchema, Session, CloudWorkspaceArgsSchema, CloudWorkspaceResultSchema;
4153
+ var WORKSPACE_COMPARISON_VALUES, Id, RepoId, Part, WorkspaceBranchSchema, FilePath, WorkspaceBindingSchema, WorkspaceRepoSchema, WorkspaceStatusSchema, Session, CloudWorkspaceArgsSchema, CloudWorkspaceResultSchema, CloudForkResultSchema;
4154
4154
  var init_cloud_workspace_schemas = __esm({
4155
4155
  "../protocol/src/cloud-workspace-schemas.ts"() {
4156
4156
  "use strict";
@@ -4251,6 +4251,11 @@ var init_cloud_workspace_schemas = __esm({
4251
4251
  notStored: external_exports.boolean().optional()
4252
4252
  }).optional()
4253
4253
  });
4254
+ CloudForkResultSchema = external_exports.object({
4255
+ threadId: external_exports.string().min(1),
4256
+ conversationId: external_exports.string().min(1),
4257
+ workspace: WorkspaceBindingSchema.optional()
4258
+ });
4254
4259
  }
4255
4260
  });
4256
4261
 
@@ -8558,6 +8563,11 @@ var init_schemas = __esm({
8558
8563
  serviceTier: CodexServiceTierSchema.optional(),
8559
8564
  iconKey: external_exports.string().optional(),
8560
8565
  forkedFromSessionId: external_exports.string().min(1).optional(),
8566
+ /** Cloud fork point (with forkedFromSessionId of a cloud session): Claude cuts at a message, Codex at a completed turn. */
8567
+ forkAt: external_exports.union([
8568
+ external_exports.object({ messageUuid: external_exports.string().min(1) }).strict(),
8569
+ external_exports.object({ turnId: external_exports.string().min(1) }).strict()
8570
+ ]).optional(),
8561
8571
  ephemeral: external_exports.boolean().optional(),
8562
8572
  // Persona context derives cwd and spawn defaults; missing cwd is allowed when persona identity determines it.
8563
8573
  ownerPersonaId: external_exports.string().min(1).optional(),
@@ -46811,7 +46821,7 @@ function requireEnvironmentIdentity(stores, environment) {
46811
46821
  var import_node_path90 = __toESM(require("path"), 1);
46812
46822
  var import_node_fs69 = __toESM(require("fs"), 1);
46813
46823
  var import_node_os33 = __toESM(require("os"), 1);
46814
- var import_node_crypto32 = require("crypto");
46824
+ var import_node_crypto33 = require("crypto");
46815
46825
  var import_node_url6 = require("url");
46816
46826
 
46817
46827
  // src/logger.ts
@@ -50287,10 +50297,14 @@ var SessionManager = class {
50287
50297
  const iso = nowIso2(this.deps);
50288
50298
  const toolSessionId = this.deps.mode === "tui" && tool === "claude" ? (0, import_node_crypto5.randomUUID)() : void 0;
50289
50299
  const file = {
50290
- sessionId: newSessionId(),
50300
+ sessionId: args.cloudFork?.sessionId ?? newSessionId(),
50291
50301
  cwd,
50292
50302
  tool,
50293
- toolSessionId,
50303
+ toolSessionId: args.cloudFork?.toolSessionId ?? toolSessionId,
50304
+ ...args.cloudFork ? {
50305
+ cloudConversationId: args.cloudFork.cloudConversationId,
50306
+ ...args.cloudFork.cloudWorkspace ? { cloudWorkspace: args.cloudFork.cloudWorkspace } : {}
50307
+ } : {},
50294
50308
  label: args.label,
50295
50309
  aiLabel: args.aiLabel,
50296
50310
  ...personaDefaultFields(engineOverridden ? void 0 : personaDefaults, {
@@ -58091,6 +58105,7 @@ async function readReleaseArchive(bytes) {
58091
58105
  init_protocol();
58092
58106
  init_protocol();
58093
58107
  var CLOUD_WORKSPACE_SLOT = "{{WORKSPACE}}";
58108
+ var CLOUD_ENGINE_HOME_SLOT = "{{ENGINE_HOME}}";
58094
58109
  var GATEWAY_ROUTES = {
58095
58110
  healthz: () => "/healthz",
58096
58111
  turn: (personaId2) => `/p/${encodeURIComponent(personaId2)}/v1/chat/completions`,
@@ -58098,6 +58113,7 @@ var GATEWAY_ROUTES = {
58098
58113
  conversationCancel: (personaId2, conversationId) => `/p/${encodeURIComponent(personaId2)}/conversations/${encodeURIComponent(conversationId)}:cancel`,
58099
58114
  volume: () => "/me/volume",
58100
58115
  workspace: (personaId2) => `/p/${encodeURIComponent(personaId2)}/workspace`,
58116
+ fork: (personaId2) => `/p/${encodeURIComponent(personaId2)}/fork`,
58101
58117
  metrics: (personaId2) => `/metrics/${encodeURIComponent(personaId2)}`
58102
58118
  };
58103
58119
  var METRICS_TIMEOUT_MS = 3e4;
@@ -58236,6 +58252,21 @@ var CloudGatewayClient = class {
58236
58252
  log("finished", { outcome, statusCode, durationMs: Math.round(performance.now() - started) });
58237
58253
  }
58238
58254
  }
58255
+ /** Copy a cloud conversation under the child's ids (design 2026-10-20-cloud-session-fork §4.2); nothing is written locally here. */
58256
+ async fork(personaId2, body) {
58257
+ const { apiKey, gatewayUrl } = await this.credentials();
58258
+ const res = await this.fetchImpl(gatewayUrl + GATEWAY_ROUTES.fork(personaId2), {
58259
+ method: "POST",
58260
+ headers: { authorization: "Bearer " + apiKey, "content-type": "application/json" },
58261
+ body: JSON.stringify(body),
58262
+ signal: AbortSignal.timeout(3e5)
58263
+ });
58264
+ const result = await res.json().catch(() => ({}));
58265
+ if (res.status === 404 && !result.error?.code) throw new Error("\u4E91\u7AEF\u6682\u4E0D\u652F\u6301 fork");
58266
+ if (res.status === 409 && result.error?.code === "FORK_POINT_NOT_SYNCED") throw new Error("\u8FD9\u6761\u6D88\u606F\u8FD8\u6CA1\u540C\u6B65\u5230\u4E91\u7AEF\uFF0C\u7A0D\u540E\u518D\u8BD5");
58267
+ if (!res.ok) throw new Error("\u5206\u53C9\u5931\u8D25\uFF1A" + (result.error?.message ?? `gateway \u56DE ${res.status}`));
58268
+ return CloudForkResultSchema.parse(result);
58269
+ }
58239
58270
  async openTurn(personaId2, opts) {
58240
58271
  const { apiKey, gatewayUrl } = await this.credentials();
58241
58272
  const health = await this.fetchImpl(gatewayUrl + GATEWAY_ROUTES.healthz());
@@ -67065,6 +67096,24 @@ async function forwardPeerExecToPeer(args) {
67065
67096
  // src/tools/codex-cloud.ts
67066
67097
  init_protocol();
67067
67098
 
67099
+ // src/tools/cloud-instructions.ts
67100
+ function skillSection(engine) {
67101
+ const wrongHome = engine === "claude" ? "`~/.claude/skills` or `$HOME/.claude/skills`" : "`~/.codex/skills` or `<cwd>/.agents/skills`";
67102
+ return [
67103
+ "## Creating skills",
67104
+ "",
67105
+ `When the user asks you to create a skill, write it to \`${CLOUD_ENGINE_HOME_SLOT}/skills/<name>/SKILL.md\` (the user-level skills directory; it is kept across the user's later sessions with this persona). Do not write skills to ${wrongHome}: those paths are not read here and are lost.`,
67106
+ "Skills under `<cwd>/.claude/skills/` belong to the persona itself and are discarded when this session ends; only write there if the user explicitly asks for a skill that is part of the persona."
67107
+ ].join("\n");
67108
+ }
67109
+ function cloudInstructions(ctx, engine) {
67110
+ return [
67111
+ ctx.extraSystemPrompt,
67112
+ workDirPrompt(CLOUD_WORKSPACE_SLOT, ctx.personaMode ?? "owner"),
67113
+ engine === "pi" ? void 0 : skillSection(engine)
67114
+ ].filter((x2) => Boolean(x2)).join("\n\n");
67115
+ }
67116
+
67068
67117
  // src/tools/codex-cloud-session.ts
67069
67118
  var import_node_fs42 = __toESM(require("fs"), 1);
67070
67119
 
@@ -67258,7 +67307,7 @@ function createCloudCodexSession(ctx, sink, deps) {
67258
67307
  client: deps.client,
67259
67308
  personaId: personaId2,
67260
67309
  engine: "codex",
67261
- instructions: ctx.titleOnly ? void 0 : ctx.extraSystemPrompt,
67310
+ instructions: ctx.titleOnly ? void 0 : cloudInstructions(ctx, "codex"),
67262
67311
  prepare: (text) => portableCloudInput(text, { resolveCodexImage: cloudImageInput(deps) })
67263
67312
  });
67264
67313
  }
@@ -67270,7 +67319,7 @@ var CLOUD_CODEX_CAPABILITIES = {
67270
67319
  toolSessionIdLabel: "Codex Thread ID",
67271
67320
  models: [],
67272
67321
  permissionModes: [CLOUD_APPROVAL],
67273
- features: { rewind: false, subagents: true, tui: false, observe: false, fileSharing: false, fork: false },
67322
+ features: { rewind: false, subagents: true, tui: false, observe: false, fileSharing: false, fork: true },
67274
67323
  configSchema: [
67275
67324
  {
67276
67325
  name: "permissionMode",
@@ -67982,9 +68031,6 @@ var PiAdapter = class {
67982
68031
  };
67983
68032
 
67984
68033
  // src/tools/pi-cloud-session.ts
67985
- function cloudPiInstructions(ctx) {
67986
- return [ctx.extraSystemPrompt, workDirPrompt(CLOUD_WORKSPACE_SLOT, ctx.personaMode ?? "owner")].filter((x2) => Boolean(x2)).join("\n\n");
67987
- }
67988
68034
  function createCloudPiSession(ctx, sink, deps) {
67989
68035
  const personaId2 = personaIdFromCloudCwd(ctx.cwd);
67990
68036
  if (!personaId2 || ctx.cloudGatewaySessionId || ctx.cloudLegacyPendingCommand) {
@@ -68005,7 +68051,7 @@ function createCloudPiSession(ctx, sink, deps) {
68005
68051
  personaId: personaId2,
68006
68052
  engine: "pi",
68007
68053
  engineSessionId: ctx.toolSessionId,
68008
- instructions: ctx.titleOnly ? void 0 : cloudPiInstructions(ctx),
68054
+ instructions: ctx.titleOnly ? void 0 : cloudInstructions(ctx, "pi"),
68009
68055
  prepare: (text) => portableCloudInput(text, { fetchPiImage: deps.fetchImage ?? makeImageFetcher() })
68010
68056
  });
68011
68057
  }
@@ -68099,7 +68145,7 @@ function createCloudClaudeSession(ctx, sink, deps) {
68099
68145
  personaId: personaId2,
68100
68146
  engine: "claude",
68101
68147
  engineSessionId: ctx.toolSessionId,
68102
- instructions: ctx.titleOnly ? void 0 : cloudPiInstructions(ctx),
68148
+ instructions: ctx.titleOnly ? void 0 : cloudInstructions(ctx, "claude"),
68103
68149
  prepare: (text) => portableCloudInput(text, { fetchPiImage: deps.fetchImage ?? makeImageFetcher() })
68104
68150
  });
68105
68151
  }
@@ -68111,7 +68157,7 @@ var CLOUD_CLAUDE_CAPABILITIES = {
68111
68157
  toolSessionIdLabel: "Claude Session ID",
68112
68158
  models: [],
68113
68159
  permissionModes: [CLOUD_APPROVAL3],
68114
- features: { rewind: false, subagents: false, tui: false, observe: false, fileSharing: false, fork: false },
68160
+ features: { rewind: false, subagents: false, tui: false, observe: false, fileSharing: false, fork: true },
68115
68161
  configSchema: [
68116
68162
  {
68117
68163
  name: "permissionMode",
@@ -72823,6 +72869,45 @@ var import_node_os26 = __toESM(require("os"), 1);
72823
72869
  var import_node_path70 = __toESM(require("path"), 1);
72824
72870
  var import_node_crypto26 = require("crypto");
72825
72871
  init_claude_history();
72872
+
72873
+ // src/session/fork-transcript.ts
72874
+ var ForkPointNotFoundError = class extends Error {
72875
+ code = "FORK_POINT_NOT_FOUND";
72876
+ };
72877
+ function forkTranscriptEntries(entries, opts) {
72878
+ const mainEntries = entries.filter((e) => e.isSidechain !== true);
72879
+ const targetIdx = mainEntries.findIndex((e) => e.uuid === opts.messageUuid);
72880
+ if (targetIdx === -1) {
72881
+ throw new ForkPointNotFoundError(`fork: messageUuid not found in transcript: ${opts.messageUuid}`);
72882
+ }
72883
+ const moveCwd = (cwd) => {
72884
+ const from = opts.cwd.from;
72885
+ if (cwd === from) return opts.cwd.to;
72886
+ return cwd.startsWith(`${from}/`) ? opts.cwd.to + cwd.slice(from.length) : cwd;
72887
+ };
72888
+ let parentUuid = null;
72889
+ const out = [];
72890
+ for (const entry of mainEntries.slice(0, targetIdx + 1)) {
72891
+ const originalUuid = entry.uuid;
72892
+ const forked = {
72893
+ ...entry,
72894
+ sessionId: opts.sessionId,
72895
+ parentUuid,
72896
+ isSidechain: false
72897
+ };
72898
+ if (opts.cwd && typeof entry.cwd === "string") forked.cwd = moveCwd(entry.cwd);
72899
+ if (originalUuid) {
72900
+ forked.forkedFrom = { sessionId: entry.sessionId ?? opts.sourceSessionId, messageUuid: originalUuid };
72901
+ }
72902
+ if (entry.type !== "progress" && originalUuid) {
72903
+ parentUuid = originalUuid;
72904
+ }
72905
+ out.push(forked);
72906
+ }
72907
+ return out;
72908
+ }
72909
+
72910
+ // src/session/fork.ts
72826
72911
  function readJsonlEntries(file) {
72827
72912
  const raw = import_node_fs62.default.readFileSync(file, "utf8");
72828
72913
  const out = [];
@@ -72851,33 +72936,12 @@ function forkSession(input) {
72851
72936
  sourceFile = found;
72852
72937
  projectDir = import_node_path70.default.dirname(found);
72853
72938
  }
72854
- const entries = readJsonlEntries(sourceFile);
72855
- const mainEntries = entries.filter((e) => e.isSidechain !== true);
72856
- const targetIdx = mainEntries.findIndex((e) => e.uuid === input.messageUuid);
72857
- if (targetIdx === -1) {
72858
- throw new Error(`fork: messageUuid not found in transcript: ${input.messageUuid}`);
72859
- }
72860
- const sliced = mainEntries.slice(0, targetIdx + 1);
72861
72939
  const forkedToolSessionId = (0, import_node_crypto26.randomUUID)();
72862
- let parentUuid = null;
72863
- const forkedLines = [];
72864
- for (const entry of sliced) {
72865
- const originalSessionId = entry.sessionId ?? input.toolSessionId;
72866
- const originalUuid = entry.uuid;
72867
- const forked = {
72868
- ...entry,
72869
- sessionId: forkedToolSessionId,
72870
- parentUuid,
72871
- isSidechain: false
72872
- };
72873
- if (originalUuid) {
72874
- forked.forkedFrom = { sessionId: originalSessionId, messageUuid: originalUuid };
72875
- }
72876
- if (entry.type !== "progress" && originalUuid) {
72877
- parentUuid = originalUuid;
72878
- }
72879
- forkedLines.push(JSON.stringify(forked));
72880
- }
72940
+ const forkedLines = forkTranscriptEntries(readJsonlEntries(sourceFile), {
72941
+ messageUuid: input.messageUuid,
72942
+ sessionId: forkedToolSessionId,
72943
+ sourceSessionId: input.toolSessionId
72944
+ }).map((entry) => JSON.stringify(entry));
72881
72945
  const outDir = input.targetCwd ? import_node_path70.default.join(baseDir, "projects", cwdToHashDir(input.targetCwd)) : projectDir;
72882
72946
  const forkedFilePath = import_node_path70.default.join(outDir, `${forkedToolSessionId}.jsonl`);
72883
72947
  import_node_fs62.default.mkdirSync(outDir, { recursive: true });
@@ -73227,6 +73291,7 @@ function appendImportLedger(dataDir, entry) {
73227
73291
 
73228
73292
  // src/handlers/session.ts
73229
73293
  init_protocol();
73294
+ var import_node_crypto27 = require("crypto");
73230
73295
  var import_node_path74 = __toESM(require("path"), 1);
73231
73296
  function canReadSearchHit(ctx, file) {
73232
73297
  if (!ctx || ctx.principal.kind === "owner") return true;
@@ -73277,6 +73342,45 @@ function buildSessionHandlers(deps) {
73277
73342
  `${MASTER_PERSONA_ID} \u7684\u4F1A\u8BDD\u7531\u8BDD\u9898\u521B\u5EFA\uFF0C\u4E0D\u80FD\u76F4\u63A5\u5EFA\uFF1A\u8BF7\u5728\u9891\u9053\u91CC\u65B0\u5EFA\u8BDD\u9898`
73278
73343
  );
73279
73344
  };
73345
+ const forkCloudSession = async (args, forkAt, tool, ctx) => {
73346
+ if (!args.forkedFromSessionId) throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "fork: forkAt requires forkedFromSessionId");
73347
+ const source = manager.get({ sessionId: args.forkedFromSessionId }).response;
73348
+ if (!canReadSearchHit(ctx, source)) {
73349
+ throw new ClawdError(ERROR_CODES.UNAUTHORIZED, `principal ${ctx?.principal.kind}:${ctx?.principal.id} cannot fork session ${source.sessionId}`);
73350
+ }
73351
+ const engine = source.tool === CLAUDE_CLOUD_TOOL_ID ? "claude" : source.tool === CODEX_CLOUD_TOOL_ID ? "codex" : null;
73352
+ if (!engine || !deps.cloudFork) throw new ClawdError(ERROR_CODES.TOOL_NOT_SUPPORTED, `tool ${source.tool} does not support cloud fork`);
73353
+ if (tool !== source.tool || args.ownerPersonaId !== source.ownerPersonaId) {
73354
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "fork: cloud fork must stay on the source persona and engine");
73355
+ }
73356
+ if (engine === "claude" ? !("messageUuid" in forkAt) : !("turnId" in forkAt)) {
73357
+ throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, `fork: ${source.tool} needs ${engine === "claude" ? "messageUuid" : "turnId"}`);
73358
+ }
73359
+ const sourceConversationId = source.cloudConversationId ?? source.cloudExecutionId;
73360
+ if (!source.toolSessionId || !sourceConversationId) throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "fork: \u6E90\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u4E91\u7AEF\u5386\u53F2");
73361
+ if (source.cloudPendingTurns?.length) throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "fork: \u8BF7\u7B49\u5F85\u6E90\u4F1A\u8BDD\u5F53\u524D\u4EFB\u52A1\u5B8C\u6210");
73362
+ const sessionId = newSessionId();
73363
+ const threadId = (0, import_node_crypto27.randomUUID)();
73364
+ const result = await deps.cloudFork(source, {
73365
+ engine,
73366
+ source: {
73367
+ conversationId: sourceConversationId,
73368
+ threadId: source.toolSessionId,
73369
+ ...source.cloudWorkspace ? { workspaceId: source.cloudWorkspace.workspaceId } : {}
73370
+ },
73371
+ at: forkAt,
73372
+ child: { conversationId: sessionId, threadId, ...source.cloudWorkspace ? { workspaceId: sessionId } : {} }
73373
+ });
73374
+ if (result.threadId !== threadId || result.conversationId !== sessionId || Boolean(result.workspace) !== Boolean(source.cloudWorkspace)) {
73375
+ throw new Error("\u5206\u53C9\u5931\u8D25\uFF1Agateway \u8FD4\u56DE\u7684\u5B50\u4F1A\u8BDD\u4E0E\u8BF7\u6C42\u4E0D\u4E00\u81F4");
73376
+ }
73377
+ return {
73378
+ sessionId,
73379
+ toolSessionId: threadId,
73380
+ cloudConversationId: sessionId,
73381
+ ...result.workspace ? { cloudWorkspace: result.workspace } : {}
73382
+ };
73383
+ };
73280
73384
  const create = async (frame, _client, ctx) => {
73281
73385
  const args = SessionCreateArgs.parse(frame);
73282
73386
  assertNotMasterPersona(args.ownerPersonaId, args.ephemeral);
@@ -73303,8 +73407,10 @@ function buildSessionHandlers(deps) {
73303
73407
  const creatorPrincipalId = ctx?.principal.id ?? ownerPrincipalId;
73304
73408
  const creatorDisplayName = ctx?.principal.displayName ?? "Owner";
73305
73409
  const creatorFeishuUnionId = ctx?.principal.feishuUnionId;
73410
+ const { forkAt, ...createArgs } = args;
73411
+ const cloudFork = forkAt ? await forkCloudSession(args, forkAt, tool, ctx) : void 0;
73306
73412
  const { response, broadcast } = manager.create(
73307
- { ...args, tool, model, effort },
73413
+ { ...createArgs, tool, model, effort, ...cloudFork ? { cloudFork } : {} },
73308
73414
  creatorPrincipalId,
73309
73415
  creatorDisplayName,
73310
73416
  creatorFeishuUnionId
@@ -75391,7 +75497,7 @@ function buildCloudConnectorsHandlers(deps) {
75391
75497
 
75392
75498
  // src/handlers/cloud-workspace.ts
75393
75499
  init_protocol();
75394
- var import_node_crypto27 = require("crypto");
75500
+ var import_node_crypto28 = require("crypto");
75395
75501
  function buildCloudWorkspaceHandlers(deps) {
75396
75502
  return {
75397
75503
  "cloud:workspace": async (frame, _client, ctx) => {
@@ -75419,7 +75525,7 @@ function buildCloudWorkspaceHandlers(deps) {
75419
75525
  ) || file.cloudPendingTurns?.length))
75420
75526
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u5B8C\u6210");
75421
75527
  const conversationId = file.cloudConversationId ?? file.cloudExecutionId ?? file.sessionId;
75422
- const traceId = typeof frame.requestId === "string" && /^[A-Za-z0-9:_-]{1,128}$/.test(frame.requestId) ? frame.requestId : (0, import_node_crypto27.randomUUID)();
75528
+ const traceId = typeof frame.requestId === "string" && /^[A-Za-z0-9:_-]{1,128}$/.test(frame.requestId) ? frame.requestId : (0, import_node_crypto28.randomUUID)();
75423
75529
  const started = performance.now();
75424
75530
  const meta = { traceId, sessionId: args.sessionId, action: args.action };
75425
75531
  const log = (event, detail) => {
@@ -75778,7 +75884,7 @@ function computeMethodAccess(args) {
75778
75884
  }
75779
75885
 
75780
75886
  // src/version.ts
75781
- var version = "0.2.700".length > 0 ? "0.2.700" : "dev";
75887
+ var version = "0.2.702".length > 0 ? "0.2.702" : "dev";
75782
75888
 
75783
75889
  // src/cli-probe/probe.ts
75784
75890
  var fs87 = __toESM(require("fs"), 1);
@@ -76176,7 +76282,7 @@ init_protocol();
76176
76282
  // src/extension/bundle-zip.ts
76177
76283
  var import_promises12 = __toESM(require("fs/promises"), 1);
76178
76284
  var import_node_path79 = __toESM(require("path"), 1);
76179
- var import_node_crypto28 = __toESM(require("crypto"), 1);
76285
+ var import_node_crypto29 = __toESM(require("crypto"), 1);
76180
76286
  var import_jszip3 = __toESM(require_lib3(), 1);
76181
76287
  async function bundleExtensionDir(dir) {
76182
76288
  const entries = await listFilesSorted(dir);
@@ -76191,7 +76297,7 @@ async function bundleExtensionDir(dir) {
76191
76297
  compression: "DEFLATE",
76192
76298
  compressionOptions: { level: 6 }
76193
76299
  });
76194
- const sha256 = import_node_crypto28.default.createHash("sha256").update(buffer).digest("hex");
76300
+ const sha256 = import_node_crypto29.default.createHash("sha256").update(buffer).digest("hex");
76195
76301
  return { buffer, sha256 };
76196
76302
  }
76197
76303
  var FIXED_DATE = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
@@ -76259,7 +76365,7 @@ function computePublishCheck(args) {
76259
76365
  var import_promises13 = __toESM(require("fs/promises"), 1);
76260
76366
  var import_node_path81 = __toESM(require("path"), 1);
76261
76367
  var import_node_os30 = __toESM(require("os"), 1);
76262
- var import_node_crypto29 = __toESM(require("crypto"), 1);
76368
+ var import_node_crypto30 = __toESM(require("crypto"), 1);
76263
76369
  var import_jszip4 = __toESM(require_lib3(), 1);
76264
76370
 
76265
76371
  // src/extension/paths.ts
@@ -76288,7 +76394,7 @@ var InstallError = class extends Error {
76288
76394
  };
76289
76395
  async function installFromChannel(args, deps) {
76290
76396
  const { channelRef, snapshotHash, bundleZip } = args;
76291
- const computed = import_node_crypto29.default.createHash("sha256").update(bundleZip).digest("hex");
76397
+ const computed = import_node_crypto30.default.createHash("sha256").update(bundleZip).digest("hex");
76292
76398
  if (computed !== snapshotHash) {
76293
76399
  throw new InstallError(
76294
76400
  "HASH_MISMATCH",
@@ -76380,7 +76486,7 @@ async function installFromChannel(args, deps) {
76380
76486
  var import_promises14 = __toESM(require("fs/promises"), 1);
76381
76487
  var import_node_path82 = __toESM(require("path"), 1);
76382
76488
  var import_node_os31 = __toESM(require("os"), 1);
76383
- var import_node_crypto30 = __toESM(require("crypto"), 1);
76489
+ var import_node_crypto31 = __toESM(require("crypto"), 1);
76384
76490
  var import_jszip5 = __toESM(require_lib3(), 1);
76385
76491
  var UpdateError = class extends Error {
76386
76492
  constructor(code, message) {
@@ -76418,7 +76524,7 @@ async function updateFromChannel(args, deps) {
76418
76524
  if (e instanceof UpdateError) throw e;
76419
76525
  throw e;
76420
76526
  }
76421
- const computed = import_node_crypto30.default.createHash("sha256").update(bundleZip).digest("hex");
76527
+ const computed = import_node_crypto31.default.createHash("sha256").update(bundleZip).digest("hex");
76422
76528
  if (computed !== snapshotHash) {
76423
76529
  throw new UpdateError(
76424
76530
  "HASH_MISMATCH",
@@ -77562,7 +77668,7 @@ async function uninstall(deps) {
77562
77668
  }
77563
77669
 
77564
77670
  // src/handlers/index.ts
77565
- var import_node_crypto31 = require("crypto");
77671
+ var import_node_crypto32 = require("crypto");
77566
77672
 
77567
77673
  // src/handlers/peer-exec.ts
77568
77674
  init_protocol();
@@ -77719,7 +77825,7 @@ function buildMethodHandlers(deps) {
77719
77825
  const c2 = deps.contactStore.get(deviceId);
77720
77826
  return c2 ? { deviceId: c2.deviceId, remoteUrl: c2.remoteUrl, connectToken: c2.connectToken } : null;
77721
77827
  },
77722
- genId: () => (0, import_node_crypto31.randomUUID)(),
77828
+ genId: () => (0, import_node_crypto32.randomUUID)(),
77723
77829
  now: () => Date.now(),
77724
77830
  forwardInboxPostToPeer,
77725
77831
  logger: deps.logger
@@ -78453,7 +78559,7 @@ async function startDaemon(config) {
78453
78559
  const channelStore = createChannelStore({
78454
78560
  filePath: import_node_path90.default.join(config.dataDir, "channels.json"),
78455
78561
  now: () => Date.now(),
78456
- genId: () => `ch-${(0, import_node_crypto32.randomUUID)().slice(0, 8)}`,
78562
+ genId: () => `ch-${(0, import_node_crypto33.randomUUID)().slice(0, 8)}`,
78457
78563
  onFlushError: (err) => logger.error("channel store flush failed", {
78458
78564
  reason: err instanceof Error ? err.message : String(err)
78459
78565
  })
@@ -78462,7 +78568,7 @@ async function startDaemon(config) {
78462
78568
  const topicStore = createTopicStore({
78463
78569
  filePath: import_node_path90.default.join(config.dataDir, "topics.json"),
78464
78570
  now: () => Date.now(),
78465
- genId: () => `tp-${(0, import_node_crypto32.randomUUID)().slice(0, 8)}`,
78571
+ genId: () => `tp-${(0, import_node_crypto33.randomUUID)().slice(0, 8)}`,
78466
78572
  onFlushError: (err) => logger.error("topic store flush failed", {
78467
78573
  reason: err instanceof Error ? err.message : String(err)
78468
78574
  })
@@ -78470,7 +78576,7 @@ async function startDaemon(config) {
78470
78576
  await topicStore.load();
78471
78577
  let deliverPendingRef;
78472
78578
  const personaDispatchManager = new PersonaDispatchManager({
78473
- genId: () => (0, import_node_crypto32.randomUUID)(),
78579
+ genId: () => (0, import_node_crypto33.randomUUID)(),
78474
78580
  store: dispatchStore,
78475
78581
  now: () => Date.now(),
78476
78582
  onCompleted: (sid) => deliverPendingRef?.(sid),
@@ -78494,7 +78600,7 @@ async function startDaemon(config) {
78494
78600
  const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
78495
78601
  const githubTokenFile = import_node_path90.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
78496
78602
  const managedGithubVar = "CLAWD_GITHUB_MANAGED_TOKEN_SHA256";
78497
- const githubFingerprint = (token) => (0, import_node_crypto32.createHash)("sha256").update(token).digest("hex");
78603
+ const githubFingerprint = (token) => (0, import_node_crypto33.createHash)("sha256").update(token).digest("hex");
78498
78604
  const githubIdentity = createGithubIdentity({
78499
78605
  isManaged: (token) => readEnvFileVar(githubTokenFile, managedGithubVar) === githubFingerprint(token),
78500
78606
  markManaged: (token) => {
@@ -79333,6 +79439,11 @@ async function startDaemon(config) {
79333
79439
  fill: (args) => centralConnectorFill({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, ...args })
79334
79440
  }
79335
79441
  },
79442
+ cloudFork: (file, body) => {
79443
+ const personaId2 = personaIdFromCloudCwd(file.cwd);
79444
+ if (!personaId2) throw new Error(`\u4E91\u4F1A\u8BDD ${file.sessionId} \u7F3A\u5C11 gateway persona ID`);
79445
+ return gatewayForEnvironment(file.cloudEnvironment).fork(personaId2, body);
79446
+ },
79336
79447
  cloudWorkspace: {
79337
79448
  logger,
79338
79449
  getFile: (id) => manager.get({ sessionId: id }).response,