open-walnut 0.6.16 → 0.6.17

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.js CHANGED
@@ -8397,6 +8397,7 @@ function createOfflineHostCore(deps4) {
8397
8397
  const MAX_ARGS_BYTES = 256 * 1024;
8398
8398
  const WRITE_BUDGET = 30;
8399
8399
  const WRITE_WINDOW_MS = 6e4;
8400
+ const LOCK_RETRY_MS = [100, 300, 900];
8400
8401
  const DEFAULT_REPLY_SECS = 3600;
8401
8402
  const IMPLICIT_REPLY_SECS = 6 * 3600;
8402
8403
  const DRAIN_BATCH = 200;
@@ -8543,7 +8544,7 @@ function createOfflineHostCore(deps4) {
8543
8544
  ...opts2.admit ? { admit: opts2.admit } : {}
8544
8545
  });
8545
8546
  if (!r8.ok) {
8546
- if (r8.code === "journal_unwritable") deps4.log("error", "offline host: journal write refused", { home, kind, code: r8.code, why: r8.why, error: r8.message });
8547
+ if (r8.code === "journal_unwritable" && r8.why !== "locked") deps4.log("error", "offline host: journal write refused", { home, kind, code: r8.code, why: r8.why, error: r8.message });
8547
8548
  return r8;
8548
8549
  }
8549
8550
  if (!r8.duplicate) {
@@ -8558,6 +8559,19 @@ function createOfflineHostCore(deps4) {
8558
8559
  if (r8.ok) return null;
8559
8560
  return fail7(r8.code, r8.message, { ...r8.retryAfterMs !== void 0 ? { retryAfterMs: r8.retryAfterMs } : {}, ...r8.why ? { detail: { why: r8.why } } : {} });
8560
8561
  }
8562
+ const lockRefused = (r8) => !r8.ok && r8.error.code === "journal_unwritable" && r8.error.detail?.why === "locked";
8563
+ async function whenUnlocked(home, op2, run12) {
8564
+ const t0 = Date.now();
8565
+ let r8 = run12();
8566
+ for (const ms2 of LOCK_RETRY_MS) {
8567
+ if (!lockRefused(r8)) return r8;
8568
+ deps4.log("warn", "offline host: the journal is locked by another process; trying the write again", { home, op: op2, waitedMs: Date.now() - t0, retryInMs: ms2 });
8569
+ await new Promise((resolve2) => setTimeout(resolve2, ms2));
8570
+ r8 = run12();
8571
+ }
8572
+ if (lockRefused(r8)) deps4.log("error", "offline host: the journal stayed locked; write refused", { home, op: op2, waitedMs: Date.now() - t0 });
8573
+ return r8;
8574
+ }
8561
8575
  function configure(slice) {
8562
8576
  if (!slice || slice.v !== 1 || typeof slice.home !== "string" || !slice.home) throw new Error("host.slice: bad slice");
8563
8577
  const prev = slices.get(slice.home);
@@ -9291,10 +9305,8 @@ ${kit10.buildReplyTrailer(row)}`;
9291
9305
  if (no) return no;
9292
9306
  deps4.log("info", "offline host: write queued", { home, op: name, taskId: task.id, callerSid: callerSid5, kind: "task-fields", seq: saved.ok ? saved.seq : void 0 });
9293
9307
  } else {
9294
- const denied = admitWrite(callerSid5) ?? roomFor(home);
9295
- if (denied) return denied;
9296
9308
  const base = slices.get(home)?.tasks.find((t3) => t3.id === task.id)?.updated_at;
9297
- const no = refusal2(append(home, { kind: "op", op: name, args: { ...args2, id: task.id }, callerSid: callerSid5, ...base ? { base } : {} }));
9309
+ const no = refusal2(append(home, { kind: "op", op: name, args: { ...args2, id: task.id }, callerSid: callerSid5, ...base ? { base } : {} }, false, { admit: () => admitWrite(callerSid5) ?? roomFor(home) }));
9298
9310
  if (no) return no;
9299
9311
  deps4.log("info", "offline host: write queued", { home, op: name, taskId: task.id, callerSid: callerSid5 });
9300
9312
  }
@@ -9736,7 +9748,7 @@ ${kit10.buildReplyTrailer(row)}`;
9736
9748
  const fromCopy = deps4.replica ? deps4.replica.answer(home, name, args2, offlineNote(home)) : null;
9737
9749
  if (fromCopy) return fromCopy;
9738
9750
  if (deps4.boards && deps4.boards.BOARD_OPS.indexOf(name) !== -1) return opBoard(home, callerSid5, name, args2);
9739
- if (QUEUED_OPS.includes(name)) return opQueued(home, callerSid5, name, args2);
9751
+ if (QUEUED_OPS.includes(name)) return whenUnlocked(home, name, () => opQueued(home, callerSid5, name, args2));
9740
9752
  return needsServer(name ? `"${name}"` : "That call");
9741
9753
  }
9742
9754
  }
@@ -10249,6 +10261,10 @@ ${mid}` : "";
10249
10261
  handle: handle4,
10250
10262
  handleLocal,
10251
10263
  handleFollower,
10264
+ /** handleFollower, waiting out another process's journal lock (whenUnlocked): the twins' follower.op. */
10265
+ handleFollowerWaiting: (home, req) => whenUnlocked(home, String(req.op ?? ""), () => handleFollower(home, req)),
10266
+ /** noteSession, waiting out another process's journal lock (whenUnlocked): the twins' host ask. */
10267
+ noteSessionWaiting: (home, rec3, opId, by) => whenUnlocked(home, "session", () => noteSession(home, rec3, opId, by)),
10252
10268
  pendingFor,
10253
10269
  journalStats,
10254
10270
  onResult,
@@ -78788,7 +78804,7 @@ function dispatchCommand(ws, id, cmd) {
78788
78804
  case 'follower.sessions': return cmdFollowerSessions(ws, id);
78789
78805
  case 'follower.send': return daemonCommands.run(function () { return cmdFollowerSend(ws, id, cmd); });
78790
78806
  case 'follower.permission': return daemonCommands.run(function () { return cmdFollowerPermission(ws, id, cmd); });
78791
- case 'follower.op': return cmdFollowerOp(ws, id, cmd);
78807
+ case 'follower.op': return daemonCommands.run(function () { return cmdFollowerOp(ws, id, cmd); });
78792
78808
  case 'follower.pending': return cmdFollowerPending(ws, id, cmd);
78793
78809
  // A new ask while the Mac is away ('replica-start-v1', WP12). Twin of daemon-standalone.ts.
78794
78810
  case 'follower.start': return daemonCommands.run(function () { return cmdFollowerStart(ws, id, cmd); });
@@ -80202,14 +80218,15 @@ async function cmdFollowerPermission(ws, id, cmd) {
80202
80218
  // The replica's write while the Mac is away (replica-ops-v1, journal v2). Its own gate:
80203
80219
  // the follower's own Walnut, the quiet window unless the Mac is still taking the
80204
80220
  // journal, and the daemon dir's owner. Twin of daemon-standalone.ts cmdFollowerOp.
80205
- function cmdFollowerOp(ws, id, cmd) {
80221
+ async function cmdFollowerOp(ws, id, cmd) {
80206
80222
  var home = followerHomeOf(ws);
80207
80223
  if (!home) return sendError(ws, id, 'follower.op: send follower.hello first');
80208
80224
  if (!followerMayWrite(home)) return sendError(ws, id, 'follower.op: your Mac answers again; write through it', { errorKind: 'leader_answers' });
80209
80225
  if (!ownsDaemonDir()) {
80210
80226
  return sendError(ws, id, 'follower.op: this daemon no longer owns its directory', { errorKind: 'journal_unwritable', detail: { why: 'not_owner' } });
80211
80227
  }
80212
- var r = offlineHost.handleFollower(home, { op: cmd.op, args: cmd.args, actor: cmd.actor, opId: cmd.opId, base: cmd.base });
80228
+ // Waits out another process's journal lock (about 1.3 s) before it answers.
80229
+ var r = await offlineHost.handleFollowerWaiting(home, { op: cmd.op, args: cmd.args, actor: cmd.actor, opId: cmd.opId, base: cmd.base });
80213
80230
  if (r.ok) return sendOk(ws, id, r.result);
80214
80231
  sendError(ws, id, 'follower.op: ' + r.error.message, Object.assign({ errorKind: r.error.code },
80215
80232
  r.error.detail !== undefined ? { detail: r.error.detail } : {}, r.error.retryAfterMs !== undefined ? { retryAfterMs: r.error.retryAfterMs } : {}));
@@ -80359,7 +80376,7 @@ async function startHostAsk(home, p, cmd) {
80359
80376
  throw err;
80360
80377
  }
80361
80378
  if (DIE_AFTER_ASK_SPAWN) process.kill(process.pid, 'SIGKILL');
80362
- var saved = offlineHost.noteSession(home, p.record, opId, cmd.actor);
80379
+ var saved = await offlineHost.noteSessionWaiting(home, p.record, opId, cmd.actor);
80363
80380
  hostStart.releasePending(home, p.sid);
80364
80381
  if (!saved.ok) {
80365
80382
  // Nothing would tell the Mac about this CLI: it must not run unseen. Not stamped as an
@@ -122881,10 +122898,13 @@ async function cleanupLaneClaudeMd(homeDir2 = WALNUT_HOME) {
122881
122898
  }
122882
122899
  }
122883
122900
  async function buildLaneProfile(config, agentId, opts2) {
122884
- const skillsIndex = await buildSessionSkillsPrompt().catch(() => "");
122885
- const memoryContext = await buildLaneMemoryContext().catch(() => "");
122901
+ const persona = opts2?.persona;
122902
+ const skillsIndex = persona ? "" : await buildSessionSkillsPrompt().catch(() => "");
122903
+ const memoryContext = persona ? "" : await buildLaneMemoryContext().catch(() => "");
122886
122904
  let profile;
122887
- if (agentId === "general") {
122905
+ if (persona) {
122906
+ profile = mergeProfiles({ systemPrompt: persona.systemPrompt, systemPromptMode: persona.systemPromptMode }, walnutMcpProfile());
122907
+ } else if (agentId === "general") {
122888
122908
  profile = personalAiProfile(config.user?.name ?? "the user", skillsIndex, memoryContext);
122889
122909
  } else {
122890
122910
  const { getAgent: getAgent2 } = await Promise.resolve().then(() => (init_agent_registry(), agent_registry_exports));
@@ -122894,7 +122914,8 @@ async function buildLaneProfile(config, agentId, opts2) {
122894
122914
  const contextBlock = await loadContextSources2(agentDef, {}).catch(() => "");
122895
122915
  profile = consoleAgentProfile(agentDef, skillsIndex, contextBlock);
122896
122916
  }
122897
- const effort = config.agent?.session_effort ?? "medium";
122917
+ const personaEffort = persona?.effort && LANE_EFFORTS.has(persona.effort) ? persona.effort : void 0;
122918
+ const effort = personaEffort ?? config.agent?.session_effort ?? "medium";
122898
122919
  if (!opts2?.conversationId) return { profile, effort };
122899
122920
  const base = profile.systemPrompt ?? "";
122900
122921
  const headroom = MAX_LANE_PROMPT_BYTES - Buffer.byteLength(base, "utf-8") - LANE_SEED_RESERVE_BYTES;
@@ -123164,7 +123185,7 @@ async function resolveLane(lane, agentId, conversationId, firstMessage, engine)
123164
123185
  });
123165
123186
  return { sessionId, created: true, engine: "claude" };
123166
123187
  }
123167
- var inFlight7, LANE_MEMORY_HEADER, MANAGED_LANE_CONTEXT_MARKERS, MAX_LANE_PROMPT_BYTES, LANE_SEED_RESERVE_BYTES, LANE_SEED_MIN_BYTES, walnutProfileRefreshAt, WALNUT_PROFILE_REFRESH_TTL_MS;
123188
+ var LANE_EFFORTS, inFlight7, LANE_MEMORY_HEADER, MANAGED_LANE_CONTEXT_MARKERS, MAX_LANE_PROMPT_BYTES, LANE_SEED_RESERVE_BYTES, LANE_SEED_MIN_BYTES, walnutProfileRefreshAt, WALNUT_PROFILE_REFRESH_TTL_MS;
123168
123189
  var init_personal_ai_lane = __esm({
123169
123190
  "src/core/sessions/personal-ai-lane.ts"() {
123170
123191
  "use strict";
@@ -123179,6 +123200,7 @@ var init_personal_ai_lane = __esm({
123179
123200
  init_default_engine();
123180
123201
  init_ask_profile_prefix();
123181
123202
  init_logging();
123203
+ LANE_EFFORTS = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh", "max"]);
123182
123204
  inFlight7 = /* @__PURE__ */ new Map();
123183
123205
  LANE_MEMORY_HEADER = "## Standing memory (injected by Walnut)";
123184
123206
  MANAGED_LANE_CONTEXT_MARKERS = [
@@ -139289,8 +139311,9 @@ async function buildCopyManifest(kind) {
139289
139311
  }
139290
139312
  return manifest;
139291
139313
  }
139292
- function keepsCopiesTarget(t3) {
139293
- return t3.kind === "host" && t3.program?.() === "replica";
139314
+ function keepsCopiesTarget(t3, kind) {
139315
+ if (t3.kind === "host") return t3.program?.() === "replica";
139316
+ return t3.kind === "companion" && (kind === void 0 || COMPANION_COPY_KINDS.has(kind));
139294
139317
  }
139295
139318
  function manifestDigest(manifest, ordered = false) {
139296
139319
  let d8 = manifestDigests.get(manifest);
@@ -139404,7 +139427,7 @@ async function choiceOf(target2) {
139404
139427
  }
139405
139428
  async function syncCopyKinds(kinds, deps4 = {}) {
139406
139429
  const now = deps4.now ?? Date.now;
139407
- const all = (deps4.targets ?? await defaultTargets())().filter(keepsCopiesTarget);
139430
+ const all = (deps4.targets ?? await defaultTargets())().filter((t3) => kinds.some((k8) => keepsCopiesTarget(t3, k8.kind)));
139408
139431
  const ready2 = [];
139409
139432
  for (const target2 of all) if (await target2.available()) ready2.push({ target: target2, choice: await choiceOf(target2) });
139410
139433
  const results = [];
@@ -139412,7 +139435,7 @@ async function syncCopyKinds(kinds, deps4 = {}) {
139412
139435
  const asOf2 = now();
139413
139436
  const manifests = /* @__PURE__ */ new Map();
139414
139437
  for (const kind of kinds) {
139415
- if (!ready2.some((r8) => r8.choice[kind.choice])) continue;
139438
+ if (!ready2.some((r8) => r8.choice[kind.choice] && keepsCopiesTarget(r8.target, kind.kind))) continue;
139416
139439
  try {
139417
139440
  manifests.set(kind.kind, await buildCopyManifest(kind));
139418
139441
  } catch (err2) {
@@ -139421,6 +139444,7 @@ async function syncCopyKinds(kinds, deps4 = {}) {
139421
139444
  }
139422
139445
  for (const { target: target2, choice } of ready2) {
139423
139446
  for (const kind of kinds) {
139447
+ if (!keepsCopiesTarget(target2, kind.kind)) continue;
139424
139448
  const manifest = manifests.get(kind.kind);
139425
139449
  const st2 = kindState(target2, kind.kind);
139426
139450
  if (!choice[kind.choice]) {
@@ -139466,7 +139490,7 @@ async function purgeKind(kind, target2, st2) {
139466
139490
  async function confirmCopyKindRemoval(targetId, kind, opts2 = {}) {
139467
139491
  const { replicaTargets: replicaTargets2 } = await Promise.resolve().then(() => (init_replica_targets(), replica_targets_exports));
139468
139492
  const target2 = replicaTargets2().find((t3) => t3.id === targetId);
139469
- if (!target2 || target2.kind !== "host" || !peekKindState(targetId, kind)) return false;
139493
+ if (!target2 || !keepsCopiesTarget(target2, kind) || !peekKindState(targetId, kind)) return false;
139470
139494
  if (!confirmKindRemoval(target2, kind, opts2)) return false;
139471
139495
  log.session.warn("copies: the user confirmed a removal of most rows", { target: targetId, kind, entries: peekKindState(targetId, kind)?.confirmFor?.entries });
139472
139496
  copySoon(kind);
@@ -139581,6 +139605,7 @@ var init_copy_kind = __esm({
139581
139605
  init_kind_leader();
139582
139606
  init_search_digest();
139583
139607
  init_replica_status();
139608
+ init_gate();
139584
139609
  COPY_DEBOUNCE_MS = 3e3;
139585
139610
  COPY_SWEEP_MS = 5 * 6e4;
139586
139611
  COPY_FIRST_ROUND_MS = 15e3;
@@ -162196,6 +162221,7 @@ var init_routines = __esm({
162196
162221
  var routines_follower_exports = {};
162197
162222
  __export(routines_follower_exports, {
162198
162223
  _resetRoutinesCopyForTesting: () => _resetRoutinesCopyForTesting,
162224
+ companionRoutinesCopy: () => companionRoutinesCopy,
162199
162225
  readRoutinesCopy: () => readRoutinesCopy,
162200
162226
  routinesFollower: () => routinesFollower
162201
162227
  });
@@ -162291,6 +162317,10 @@ async function readRoutinesCopy(opts2 = {}) {
162291
162317
  const shown = opts2.includeDisabled ? all : all.filter((j8) => j8.enabled);
162292
162318
  return shown.sort((a8, b8) => (a8.state.nextRunAtMs ?? 0) - (b8.state.nextRunAtMs ?? 0));
162293
162319
  }
162320
+ async function companionRoutinesCopy(opts2 = {}) {
162321
+ if (!await copyKindHeld("routines")) return null;
162322
+ return await readRoutinesCopy(opts2) ?? [];
162323
+ }
162294
162324
  function _resetRoutinesCopyForTesting() {
162295
162325
  io3 = copyStateIo("routines");
162296
162326
  serial3 = serialChain();
@@ -162306,8 +162336,8 @@ var init_routines_follower = __esm({
162306
162336
  init_gate();
162307
162337
  init_state_io();
162308
162338
  init_routines();
162309
- jobsFile = () => CRON_FILE;
162310
- statesFile = () => path120.join(path120.dirname(CRON_FILE), "cron-state.json");
162339
+ jobsFile = () => copyPath(CRON_FILE);
162340
+ statesFile = () => copyPath(path120.join(path120.dirname(CRON_FILE), "cron-state.json"));
162311
162341
  io3 = copyStateIo("routines");
162312
162342
  serial3 = serialChain();
162313
162343
  follower2 = null;
@@ -178645,8 +178675,8 @@ import path137 from "path";
178645
178675
  import { fileURLToPath as fileURLToPath10 } from "url";
178646
178676
  function getVersion() {
178647
178677
  if (cachedVersion) return cachedVersion;
178648
- if ("0.6.16") {
178649
- cachedVersion = "0.6.16";
178678
+ if ("0.6.17") {
178679
+ cachedVersion = "0.6.17";
178650
178680
  versionKnown = true;
178651
178681
  return cachedVersion;
178652
178682
  }
@@ -202063,6 +202093,132 @@ var init_agent_turn_queue = __esm({
202063
202093
  }
202064
202094
  });
202065
202095
 
202096
+ // src/core/replication/kinds/personas.ts
202097
+ var personas_exports = {};
202098
+ __export(personas_exports, {
202099
+ PERSONAS_KIND: () => PERSONAS_KIND,
202100
+ PERSONAS_REMOVAL_FLOOR: () => PERSONAS_REMOVAL_FLOOR,
202101
+ PERSONAS_SCHEMA_VERSION: () => PERSONAS_SCHEMA_VERSION,
202102
+ _resetPersonasCopyForTesting: () => _resetPersonasCopyForTesting,
202103
+ personasFollower: () => personasFollower,
202104
+ readPersonaCopy: () => readPersonaCopy
202105
+ });
202106
+ function tools(v3) {
202107
+ return Array.isArray(v3) && v3.length > 0 && v3.every((t3) => typeof t3 === "string" && TOOL_RE.test(t3)) ? [...v3] : void 0;
202108
+ }
202109
+ async function leaderRows() {
202110
+ const [{ getConsoleAgents: getConsoleAgents2 }, { buildLaneProfile: buildLaneProfile2 }, { getConfig: getConfig2 }, { getAskWalnutLaunchPrefs: getAskWalnutLaunchPrefs2 }] = await Promise.all([
202111
+ Promise.resolve().then(() => (init_agent_registry(), agent_registry_exports)),
202112
+ Promise.resolve().then(() => (init_personal_ai_lane(), personal_ai_lane_exports)),
202113
+ Promise.resolve().then(() => (init_config_manager(), config_manager_exports)),
202114
+ Promise.resolve().then(() => (init_ask_walnut_launch(), ask_walnut_launch_exports))
202115
+ ]);
202116
+ const config = await getConfig2();
202117
+ const launch = await getAskWalnutLaunchPrefs2().catch(() => ({}));
202118
+ const agents = [{ id: "general", name: "Walnut" }, ...(await getConsoleAgents2()).filter((a8) => a8.id !== "general").map((a8) => ({ id: a8.id, name: a8.name }))];
202119
+ const rows = [];
202120
+ for (const a8 of agents) {
202121
+ if (!ID_RE.test(a8.id)) continue;
202122
+ try {
202123
+ const { profile, effort } = await buildLaneProfile2(config, a8.id);
202124
+ const prompt = profile.systemPrompt ?? "";
202125
+ if (!prompt || Buffer.byteLength(prompt, "utf8") > MAX_PROMPT_BYTES) continue;
202126
+ rows.push({
202127
+ key: a8.id,
202128
+ agentId: a8.id,
202129
+ name: String(a8.name ?? a8.id).slice(0, 120),
202130
+ systemPrompt: prompt,
202131
+ systemPromptMode: profile.systemPromptMode === "replace" ? "replace" : "append",
202132
+ ...tools(profile.allowedTools) ? { allowedTools: tools(profile.allowedTools) } : {},
202133
+ ...tools(profile.tools) ? { tools: tools(profile.tools) } : {},
202134
+ ...effort ? { effort } : {},
202135
+ ...launch.model ? { launchModel: launch.model } : {},
202136
+ ...launch.effort ? { launchEffort: launch.effort } : {}
202137
+ });
202138
+ } catch (err2) {
202139
+ log.session.warn("copies: an agent persona was not rendered for the host", { agentId: a8.id, error: err2 instanceof Error ? err2.message : String(err2) });
202140
+ }
202141
+ }
202142
+ return rows;
202143
+ }
202144
+ function hashOf3(row) {
202145
+ let h8 = hashes3.get(row);
202146
+ if (h8 === void 0) {
202147
+ h8 = sha12(JSON.stringify(row));
202148
+ hashes3.set(row, h8);
202149
+ }
202150
+ return h8;
202151
+ }
202152
+ function isRow3(v3) {
202153
+ const r8 = v3;
202154
+ if (!r8 || typeof r8 !== "object" || Array.isArray(r8)) return false;
202155
+ if (Object.keys(r8).some((k8) => !ROW_KEYS.has(k8))) return false;
202156
+ if (typeof r8.key !== "string" || r8.key !== r8.agentId || !ID_RE.test(r8.key) || typeof r8.name !== "string") return false;
202157
+ if (typeof r8.systemPrompt !== "string" || !r8.systemPrompt || Buffer.byteLength(r8.systemPrompt, "utf8") > MAX_PROMPT_BYTES) return false;
202158
+ if (r8.systemPromptMode !== "append" && r8.systemPromptMode !== "replace") return false;
202159
+ for (const k8 of ["allowedTools", "tools"]) if (r8[k8] !== void 0 && !tools(r8[k8])) return false;
202160
+ for (const k8 of ["effort", "launchModel", "launchEffort"]) if (r8[k8] !== void 0 && (typeof r8[k8] !== "string" || !/^[A-Za-z0-9._:[\]/-]{1,128}$/.test(r8[k8]))) return false;
202161
+ return true;
202162
+ }
202163
+ function admit(r8) {
202164
+ return secretShapedValue(r8.systemPrompt) === null && secretShapedValue(r8.name) === null;
202165
+ }
202166
+ async function readPersonaCopy(agentId) {
202167
+ const rows = await copy.read();
202168
+ return rows?.[agentId] ?? null;
202169
+ }
202170
+ function _resetPersonasCopyForTesting() {
202171
+ copy.reset();
202172
+ }
202173
+ var PERSONAS_SCHEMA_VERSION, PERSONAS_REMOVAL_FLOOR, MAX_PROMPT_BYTES, ID_RE, TOOL_RE, hashes3, PERSONAS_KIND, ROW_KEYS, copy, personasFollower;
202174
+ var init_personas = __esm({
202175
+ "src/core/replication/kinds/personas.ts"() {
202176
+ "use strict";
202177
+ init_logging();
202178
+ init_config_allowlist();
202179
+ init_kind();
202180
+ init_file_copy();
202181
+ PERSONAS_SCHEMA_VERSION = 1;
202182
+ PERSONAS_REMOVAL_FLOOR = 0;
202183
+ MAX_PROMPT_BYTES = 120 * 1024;
202184
+ ID_RE = /^[A-Za-z0-9_-]{1,80}$/;
202185
+ TOOL_RE = /^[A-Za-z0-9_.:*()/ -]{1,200}$/;
202186
+ hashes3 = /* @__PURE__ */ new WeakMap();
202187
+ PERSONAS_KIND = {
202188
+ kind: "personas",
202189
+ schemaVersion: PERSONAS_SCHEMA_VERSION,
202190
+ key: (r8) => r8.key,
202191
+ hash: hashOf3,
202192
+ ordered: false,
202193
+ digest: false,
202194
+ choice: "personas",
202195
+ rows: leaderRows,
202196
+ watch: (soon) => {
202197
+ let stop2 = null;
202198
+ let stopped2 = false;
202199
+ void Promise.resolve().then(() => (init_config_manager(), config_manager_exports)).then((cm) => {
202200
+ if (!stopped2) stop2 = cm.onConfigWritten(soon);
202201
+ });
202202
+ return () => {
202203
+ stopped2 = true;
202204
+ stop2?.();
202205
+ };
202206
+ }
202207
+ };
202208
+ ROW_KEYS = /* @__PURE__ */ new Set(["key", "agentId", "name", "systemPrompt", "systemPromptMode", "allowedTools", "tools", "effort", "launchModel", "launchEffort"]);
202209
+ copy = createFileCopy({
202210
+ kind: "personas",
202211
+ schemaVersion: PERSONAS_SCHEMA_VERSION,
202212
+ label: "personas copy",
202213
+ removalFloor: PERSONAS_REMOVAL_FLOOR,
202214
+ isRow: isRow3,
202215
+ key: (r8) => r8.key,
202216
+ admit
202217
+ });
202218
+ personasFollower = copy.follower;
202219
+ }
202220
+ });
202221
+
202066
202222
  // src/core/sessions/cloud-chat-lane.ts
202067
202223
  var cloud_chat_lane_exports = {};
202068
202224
  __export(cloud_chat_lane_exports, {
@@ -202201,7 +202357,9 @@ async function resolveCloudChatLane(lane, agentId, conversationId, cwd, firstMes
202201
202357
  CATCH_UP_BANNER_CLOSE: CATCH_UP_BANNER_CLOSE2,
202202
202358
  buildConversationSeed: buildConversationSeed2
202203
202359
  } = await Promise.resolve().then(() => (init_chat_history(), chat_history_exports));
202204
- const { profile: base, effort, seed } = await buildLaneProfile2(config, agentId, { conversationId });
202360
+ const { readPersonaCopy: readPersonaCopy2 } = await Promise.resolve().then(() => (init_personas(), personas_exports));
202361
+ const persona = await readPersonaCopy2(agentId).catch(() => null);
202362
+ const { profile: base, effort, seed } = await buildLaneProfile2(config, agentId, { conversationId, ...persona ? { persona } : {} });
202205
202363
  const profile = toCloudChatProfile(base, CONVERSATION_SEED_HEADER2);
202206
202364
  const sessionId = crypto47.randomUUID();
202207
202365
  const seedInProfile = !!seed && (seed.text !== "" || seed.stats.turnsTotal === 0);
@@ -209746,9 +209904,9 @@ function sanitizeHealthSync(body7, now = Date.now()) {
209746
209904
  const tz = isValidTz(b8.tz) ? b8.tz : "";
209747
209905
  const spec = metricSpec(type);
209748
209906
  const generic = isGenericType(type);
209749
- const storeId = typeof b8.storeId === "string" && ID_RE.test(b8.storeId) ? b8.storeId : void 0;
209907
+ const storeId = typeof b8.storeId === "string" && ID_RE2.test(b8.storeId) ? b8.storeId : void 0;
209750
209908
  const dev = b8.device && typeof b8.device === "object" ? b8.device : {};
209751
- const installId = typeof dev.installId === "string" && ID_RE.test(dev.installId) ? dev.installId : void 0;
209909
+ const installId = typeof dev.installId === "string" && ID_RE2.test(dev.installId) ? dev.installId : void 0;
209752
209910
  const device = { installId, model: str10(dev.model, 64), os: str10(dev.os, 64) };
209753
209911
  const hasDevice = Object.values(device).some((v3) => v3 !== void 0);
209754
209912
  const deleted = [...new Set(deletedIn.filter((u3) => typeof u3 === "string" && UUID_RE3.test(u3)))];
@@ -209816,14 +209974,14 @@ function relayPayload(batch) {
209816
209974
  samples: batch.samples.map(({ tz, ...rest }) => tz === batch.tz ? rest : { ...rest, tz })
209817
209975
  };
209818
209976
  }
209819
- var UUID_RE3, ID_RE, MIN_INSTANT, FUTURE_SLACK_MS2, MAX_SPAN_MS;
209977
+ var UUID_RE3, ID_RE2, MIN_INSTANT, FUTURE_SLACK_MS2, MAX_SPAN_MS;
209820
209978
  var init_sanitize = __esm({
209821
209979
  "src/core/health/sanitize.ts"() {
209822
209980
  "use strict";
209823
209981
  init_catalog();
209824
209982
  init_day_key();
209825
209983
  UUID_RE3 = /^[A-Za-z0-9][A-Za-z0-9-]{0,63}$/;
209826
- ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/;
209984
+ ID_RE2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/;
209827
209985
  MIN_INSTANT = Date.UTC(2010, 0, 1);
209828
209986
  FUTURE_SLACK_MS2 = 36 * 36e5;
209829
209987
  MAX_SPAN_MS = 2 * 864e5;
@@ -225310,7 +225468,7 @@ function prefAdmissible(p6) {
225310
225468
  function strings(v3) {
225311
225469
  return Array.isArray(v3) ? v3.filter((x3) => typeof x3 === "string") : [];
225312
225470
  }
225313
- async function leaderRows() {
225471
+ async function leaderRows2() {
225314
225472
  const raw = await readJsonFile(UI_PREFS_FILE, {}, { readErrors: "throw" });
225315
225473
  const rows = [];
225316
225474
  for (const [k8, v3] of Object.entries(raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {})) {
@@ -225322,15 +225480,15 @@ async function leaderRows() {
225322
225480
  rows.push({ key: "favorites", favorites: { projects: strings(fav?.projects), notes: strings(fav?.notes) } });
225323
225481
  return rows;
225324
225482
  }
225325
- function hashOf3(row) {
225326
- let h8 = hashes3.get(row);
225483
+ function hashOf4(row) {
225484
+ let h8 = hashes4.get(row);
225327
225485
  if (h8 === void 0) {
225328
225486
  h8 = sha12(JSON.stringify(row));
225329
- hashes3.set(row, h8);
225487
+ hashes4.set(row, h8);
225330
225488
  }
225331
225489
  return h8;
225332
225490
  }
225333
- function isRow3(v3) {
225491
+ function isRow4(v3) {
225334
225492
  const r8 = v3;
225335
225493
  if (!r8 || typeof r8 !== "object" || typeof r8.key !== "string") return false;
225336
225494
  if (r8.key === "favorites") {
@@ -225340,27 +225498,27 @@ function isRow3(v3) {
225340
225498
  const p6 = prefOf(r8.pref);
225341
225499
  return Object.keys(r8).length === 2 && r8.key.startsWith(UI) && copyableUiPrefKey(r8.key.slice(UI.length)) && !!p6 && typeof r8.pref === "object";
225342
225500
  }
225343
- function admit(r8) {
225501
+ function admit2(r8) {
225344
225502
  if ("favorites" in r8) return [...r8.favorites.projects, ...r8.favorites.notes].every((s4) => typeof s4 === "string" && secretShapedValue(s4) === null);
225345
225503
  return prefAdmissible(r8.pref);
225346
225504
  }
225347
225505
  async function readUiPrefsCopy() {
225348
- const rows = await copy.read();
225506
+ const rows = await copy2.read();
225349
225507
  if (!rows) return null;
225350
225508
  const out = {};
225351
225509
  for (const r8 of Object.values(rows)) if ("pref" in r8) out[r8.key.slice(UI.length)] = r8.pref;
225352
225510
  return out;
225353
225511
  }
225354
225512
  async function readFavoritesCopy() {
225355
- const rows = await copy.read();
225513
+ const rows = await copy2.read();
225356
225514
  if (!rows) return null;
225357
225515
  const f8 = rows.favorites;
225358
225516
  return f8 && "favorites" in f8 ? f8.favorites : { projects: [], notes: [] };
225359
225517
  }
225360
225518
  function _resetPrefsCopyForTesting() {
225361
- copy.reset();
225519
+ copy2.reset();
225362
225520
  }
225363
- var PREFS_SCHEMA_VERSION, PREFS_REMOVAL_FLOOR, UI, MAX_VALUE_LEN2, hashes3, PREFS_KIND, copy, prefsFollower;
225521
+ var PREFS_SCHEMA_VERSION, PREFS_REMOVAL_FLOOR, UI, MAX_VALUE_LEN2, hashes4, PREFS_KIND, copy2, prefsFollower;
225364
225522
  var init_prefs = __esm({
225365
225523
  "src/core/replication/kinds/prefs.ts"() {
225366
225524
  "use strict";
@@ -225374,16 +225532,16 @@ var init_prefs = __esm({
225374
225532
  PREFS_REMOVAL_FLOOR = 0;
225375
225533
  UI = "ui:";
225376
225534
  MAX_VALUE_LEN2 = 8 * 1024;
225377
- hashes3 = /* @__PURE__ */ new WeakMap();
225535
+ hashes4 = /* @__PURE__ */ new WeakMap();
225378
225536
  PREFS_KIND = {
225379
225537
  kind: "prefs",
225380
225538
  schemaVersion: PREFS_SCHEMA_VERSION,
225381
225539
  key: (r8) => r8.key,
225382
- hash: hashOf3,
225540
+ hash: hashOf4,
225383
225541
  ordered: false,
225384
225542
  digest: false,
225385
225543
  choice: "prefs",
225386
- rows: leaderRows,
225544
+ rows: leaderRows2,
225387
225545
  watch: (soon) => {
225388
225546
  const stops = [];
225389
225547
  let stopped2 = false;
@@ -225396,16 +225554,16 @@ var init_prefs = __esm({
225396
225554
  };
225397
225555
  }
225398
225556
  };
225399
- copy = createFileCopy({
225557
+ copy2 = createFileCopy({
225400
225558
  kind: "prefs",
225401
225559
  schemaVersion: PREFS_SCHEMA_VERSION,
225402
225560
  label: "prefs copy",
225403
225561
  removalFloor: PREFS_REMOVAL_FLOOR,
225404
- isRow: isRow3,
225562
+ isRow: isRow4,
225405
225563
  key: (r8) => r8.key,
225406
- admit
225564
+ admit: admit2
225407
225565
  });
225408
- prefsFollower = copy.follower;
225566
+ prefsFollower = copy2.follower;
225409
225567
  }
225410
225568
  });
225411
225569
 
@@ -226140,7 +226298,7 @@ async function adoptDeviceRecord(input, opts2 = {}) {
226140
226298
  const existing = devices.find((d8) => d8.tokenHash === tokenHash);
226141
226299
  if (existing) return { result: { name: existing.name, adopted: false } };
226142
226300
  const finalName = freeName(devices, name);
226143
- const wanted = typeof input.id === "string" && ID_RE2.test(input.id) ? input.id : void 0;
226301
+ const wanted = typeof input.id === "string" && ID_RE3.test(input.id) ? input.id : void 0;
226144
226302
  const idFree = wanted !== void 0 && !devices.some((d8) => d8.id === wanted || d8.ownerId === wanted);
226145
226303
  const record2 = {
226146
226304
  name: finalName,
@@ -226175,7 +226333,7 @@ async function revokeAdopted(tokenHash) {
226175
226333
  if (out.revoked) log.web.info("device-adoption: twin pairing revoked", { name: record2.name, adoptedFrom: record2.adoptedFrom ?? null });
226176
226334
  return out.revoked ? { name: record2.name, refused: false, push: out.push } : { name: null, refused: false, push: null };
226177
226335
  }
226178
- var AdoptionError, HASH_RE, ID_RE2, INFO_FIELD_MAX2, NAME_MAX;
226336
+ var AdoptionError, HASH_RE, ID_RE3, INFO_FIELD_MAX2, NAME_MAX;
226179
226337
  var init_device_adoption = __esm({
226180
226338
  "src/core/device-adoption.ts"() {
226181
226339
  "use strict";
@@ -226193,7 +226351,7 @@ var init_device_adoption = __esm({
226193
226351
  }
226194
226352
  };
226195
226353
  HASH_RE = /^[0-9a-f]{64}$/;
226196
- ID_RE2 = /^d[0-9a-f]{16}$/;
226354
+ ID_RE3 = /^d[0-9a-f]{16}$/;
226197
226355
  INFO_FIELD_MAX2 = 120;
226198
226356
  NAME_MAX = 64;
226199
226357
  }
@@ -245454,7 +245612,7 @@ import crypto64 from "crypto";
245454
245612
  import fs121 from "fs";
245455
245613
  import path225 from "path";
245456
245614
  function isDeviceCopyId(id) {
245457
- return typeof id === "string" && ID_RE3.test(id);
245615
+ return typeof id === "string" && ID_RE4.test(id);
245458
245616
  }
245459
245617
  function sha256Hex2(text5) {
245460
245618
  return crypto64.createHash("sha256").update(text5, "utf-8").digest("hex");
@@ -245544,14 +245702,14 @@ function createDeviceCopy(file) {
245544
245702
  }
245545
245703
  };
245546
245704
  }
245547
- var HASH_RE2, NAME_MAX2, MAX_DEVICES, ID_RE3;
245705
+ var HASH_RE2, NAME_MAX2, MAX_DEVICES, ID_RE4;
245548
245706
  var init_device_copy = __esm({
245549
245707
  "src/host-server/device-copy.ts"() {
245550
245708
  "use strict";
245551
245709
  HASH_RE2 = /^[0-9a-f]{64}$/;
245552
245710
  NAME_MAX2 = 64;
245553
245711
  MAX_DEVICES = 500;
245554
- ID_RE3 = /^[A-Za-z0-9._:-]{1,80}$/;
245712
+ ID_RE4 = /^[A-Za-z0-9._:-]{1,80}$/;
245555
245713
  }
245556
245714
  });
245557
245715
 
@@ -245572,11 +245730,11 @@ function replicaDeviceCopyFile(home = WALNUT_HOME) {
245572
245730
  return path226.join(home, "replica", "devices.json");
245573
245731
  }
245574
245732
  function replicaDeviceCopy() {
245575
- copy2 ??= createDeviceCopy(replicaDeviceCopyFile());
245576
- return copy2;
245733
+ copy3 ??= createDeviceCopy(replicaDeviceCopyFile());
245734
+ return copy3;
245577
245735
  }
245578
245736
  function _resetReplicaAuthForTesting() {
245579
- copy2 = null;
245737
+ copy3 = null;
245580
245738
  }
245581
245739
  function verifyReplicaToken(token) {
245582
245740
  const name = replicaDeviceCopy().verify(token);
@@ -245619,14 +245777,14 @@ async function replicaAuthMiddleware(req, res, next) {
245619
245777
  req.deviceName = cred.name;
245620
245778
  next();
245621
245779
  }
245622
- var copy2, PUBLIC_GET_PATHS, REPLICA_FAILURE_KEY;
245780
+ var copy3, PUBLIC_GET_PATHS, REPLICA_FAILURE_KEY;
245623
245781
  var init_auth11 = __esm({
245624
245782
  "src/replica/auth.ts"() {
245625
245783
  "use strict";
245626
245784
  init_constants();
245627
245785
  init_device_copy();
245628
245786
  init_logging();
245629
- copy2 = null;
245787
+ copy3 = null;
245630
245788
  PUBLIC_GET_PATHS = /* @__PURE__ */ new Set(["/v1/instance"]);
245631
245789
  REPLICA_FAILURE_KEY = "host-replica";
245632
245790
  }
@@ -252671,7 +252829,7 @@ async function saveRecordingAudio(audioBase64, format2) {
252671
252829
  return { id, audioPath };
252672
252830
  }
252673
252831
  async function writeRecordingResult(id, meta) {
252674
- if (!ID_RE4.test(id)) throw new Error(`Invalid recording id: ${id}`);
252832
+ if (!ID_RE5.test(id)) throw new Error(`Invalid recording id: ${id}`);
252675
252833
  await mkdir7(dir3(), { recursive: true });
252676
252834
  const stamped = { timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...meta };
252677
252835
  await writeFile6(join16(dir3(), `${id}.json`), JSON.stringify(stamped, null, 2));
@@ -252680,7 +252838,7 @@ async function writeRecordingResult(id, meta) {
252680
252838
  return stamped.timestamp;
252681
252839
  }
252682
252840
  async function writeRecordingSecondary(id, secondary, expectTimestamp) {
252683
- if (!ID_RE4.test(id)) throw new Error(`Invalid recording id: ${id}`);
252841
+ if (!ID_RE5.test(id)) throw new Error(`Invalid recording id: ${id}`);
252684
252842
  const path305 = join16(dir3(), `${id}.json`);
252685
252843
  let existing;
252686
252844
  try {
@@ -252702,7 +252860,7 @@ async function listRecordings(limit = 20) {
252702
252860
  const out = [];
252703
252861
  for (const jf of jsonFiles) {
252704
252862
  const id = jf.slice(0, -5);
252705
- if (!ID_RE4.test(id)) continue;
252863
+ if (!ID_RE5.test(id)) continue;
252706
252864
  try {
252707
252865
  const raw = JSON.parse(await readFile8(join16(dir3(), jf), "utf-8"));
252708
252866
  out.push({
@@ -252722,7 +252880,7 @@ async function listRecordings(limit = 20) {
252722
252880
  return out;
252723
252881
  }
252724
252882
  async function readRecordingAudio(id) {
252725
- if (!ID_RE4.test(id)) return null;
252883
+ if (!ID_RE5.test(id)) return null;
252726
252884
  let files;
252727
252885
  try {
252728
252886
  files = await readdir3(dir3());
@@ -252750,13 +252908,13 @@ async function pruneOldRecordings() {
252750
252908
  }
252751
252909
  }
252752
252910
  }
252753
- var MAX_RECORDINGS, ID_RE4, AUDIO_EXTS;
252911
+ var MAX_RECORDINGS, ID_RE5, AUDIO_EXTS;
252754
252912
  var init_recordings = __esm({
252755
252913
  "src/core/stt/recordings.ts"() {
252756
252914
  "use strict";
252757
252915
  init_constants();
252758
252916
  MAX_RECORDINGS = 100;
252759
- ID_RE4 = /^[0-9A-Za-z-]+$/;
252917
+ ID_RE5 = /^[0-9A-Za-z-]+$/;
252760
252918
  AUDIO_EXTS = ["webm", "mp4", "ogg", "wav", "mp3", "m4a", "flac"];
252761
252919
  }
252762
252920
  });
@@ -258872,6 +259030,147 @@ var init_task_v1 = __esm({
258872
259030
  }
258873
259031
  });
258874
259032
 
259033
+ // src/core/replication/kinds/requests.ts
259034
+ var requests_exports = {};
259035
+ __export(requests_exports, {
259036
+ REQUESTS_KIND: () => REQUESTS_KIND,
259037
+ REQUESTS_REMOVAL_FLOOR: () => REQUESTS_REMOVAL_FLOOR,
259038
+ REQUESTS_SCHEMA_VERSION: () => REQUESTS_SCHEMA_VERSION,
259039
+ _resetRequestsCopyForTesting: () => _resetRequestsCopyForTesting,
259040
+ forwardRequest: () => forwardRequest,
259041
+ readRequestCopy: () => readRequestCopy,
259042
+ requestsFollower: () => requestsFollower
259043
+ });
259044
+ import fsp123 from "fs/promises";
259045
+ import path236 from "path";
259046
+ function forwardRequest(local, incoming) {
259047
+ if (local && FINAL.has(local.status) && !FINAL.has(incoming.status)) return local;
259048
+ return incoming;
259049
+ }
259050
+ function hashOf5(row) {
259051
+ let h8 = hashes5.get(row);
259052
+ if (h8 === void 0) {
259053
+ h8 = sha12(JSON.stringify(row));
259054
+ hashes5.set(row, h8);
259055
+ }
259056
+ return h8;
259057
+ }
259058
+ async function load6() {
259059
+ if (state11) return state11;
259060
+ let s4 = { asOf: 0, at: 0, order: [], hashes: {} };
259061
+ try {
259062
+ const raw = JSON.parse(await fsp123.readFile(STATE_FILE(), "utf8"));
259063
+ if (raw?.v === 1 && raw.hashes && typeof raw.hashes === "object") s4 = { asOf: Number(raw.asOf) || 0, at: Number(raw.at) || 0, order: [], hashes: raw.hashes };
259064
+ } catch {
259065
+ }
259066
+ state11 = s4;
259067
+ return s4;
259068
+ }
259069
+ async function save() {
259070
+ if (state11) await writeCopyFile(STATE_FILE(), { v: 1, asOf: state11.asOf, at: state11.at, hashes: state11.hashes });
259071
+ }
259072
+ async function readStore7() {
259073
+ try {
259074
+ const raw = JSON.parse(await fsp123.readFile(STORE_FILE(), "utf8"));
259075
+ return Array.isArray(raw?.requests) ? raw.requests.filter(isRow5) : [];
259076
+ } catch {
259077
+ return [];
259078
+ }
259079
+ }
259080
+ function isRow5(v3) {
259081
+ const r8 = v3;
259082
+ return !!r8 && typeof r8 === "object" && typeof r8.id === "string" && !!r8.id && typeof r8.fromSessionId === "string" && typeof r8.status === "string" && typeof r8.createdAt === "string";
259083
+ }
259084
+ function requestsFollower() {
259085
+ follower3 ??= createRowSetFollower({
259086
+ kind: "requests",
259087
+ schemaVersion: REQUESTS_SCHEMA_VERSION,
259088
+ label: "requests copy",
259089
+ log: log.session,
259090
+ removalFloor: REQUESTS_REMOVAL_FLOOR,
259091
+ ordered: false,
259092
+ serial: (fn) => serial4(fn),
259093
+ refuse: copyRefusal,
259094
+ load: load6,
259095
+ save,
259096
+ isRow: isRow5,
259097
+ key: (r8) => r8.id,
259098
+ localKeys: async () => (await readStore7()).map((r8) => r8.id),
259099
+ apply: async ({ rows, removeIds }) => {
259100
+ const byId = new Map((await readStore7()).map((r8) => [r8.id, r8]));
259101
+ for (const id of removeIds ?? []) byId.delete(id);
259102
+ for (const r8 of rows ?? []) {
259103
+ const kept = forwardRequest(byId.get(r8.id), r8);
259104
+ if (kept !== r8) log.session.info("requests copy: kept a settled request the leader has not settled yet", { requestId: r8.id, local: kept.status, leader: r8.status });
259105
+ byId.set(r8.id, kept);
259106
+ }
259107
+ await writeCopyFile(STORE_FILE(), { requests: [...byId.values()] });
259108
+ return { skipped: [] };
259109
+ },
259110
+ held: async () => (await Promise.resolve().then(() => (init_journal_overlay(), journal_overlay_exports))).journalHeld("requests"),
259111
+ changed: () => {
259112
+ },
259113
+ purge: async () => {
259114
+ const removed = (await readStore7()).length;
259115
+ await fsp123.rm(STORE_FILE(), { force: true });
259116
+ await markCopyOff("requests");
259117
+ state11 = null;
259118
+ return { removed };
259119
+ }
259120
+ });
259121
+ return follower3;
259122
+ }
259123
+ async function readRequestCopy(id) {
259124
+ if (!await copyKindHeld("requests")) return null;
259125
+ return (await readStore7()).find((r8) => r8.id === id) ?? null;
259126
+ }
259127
+ function _resetRequestsCopyForTesting() {
259128
+ state11 = null;
259129
+ follower3 = null;
259130
+ serial4 = serialChain();
259131
+ }
259132
+ var REQUESTS_SCHEMA_VERSION, REQUESTS_REMOVAL_FLOOR, FINAL, hashes5, REQUESTS_KIND, STATE_FILE, STORE_FILE, state11, serial4, follower3;
259133
+ var init_requests = __esm({
259134
+ "src/core/replication/kinds/requests.ts"() {
259135
+ "use strict";
259136
+ init_constants();
259137
+ init_logging();
259138
+ init_kind();
259139
+ init_kind_follower();
259140
+ init_gate();
259141
+ REQUESTS_SCHEMA_VERSION = 1;
259142
+ REQUESTS_REMOVAL_FLOOR = 50;
259143
+ FINAL = /* @__PURE__ */ new Set(["replied", "notified", "expired"]);
259144
+ hashes5 = /* @__PURE__ */ new WeakMap();
259145
+ REQUESTS_KIND = {
259146
+ kind: "requests",
259147
+ schemaVersion: REQUESTS_SCHEMA_VERSION,
259148
+ key: (r8) => r8.id,
259149
+ hash: hashOf5,
259150
+ ordered: false,
259151
+ digest: false,
259152
+ choice: "requests",
259153
+ rows: async () => (await Promise.resolve().then(() => (init_session_requests(), session_requests_exports))).listAllSessionRequests(),
259154
+ watch: (soon) => {
259155
+ let stop2 = null;
259156
+ let stopped2 = false;
259157
+ void Promise.resolve().then(() => (init_session_requests(), session_requests_exports)).then(({ onSessionRequestsWritten: onSessionRequestsWritten2 }) => {
259158
+ if (!stopped2) stop2 = onSessionRequestsWritten2(soon);
259159
+ });
259160
+ return () => {
259161
+ stopped2 = true;
259162
+ stop2?.();
259163
+ };
259164
+ }
259165
+ };
259166
+ STATE_FILE = () => path236.join(WALNUT_HOME, "cache", "replica", "requests.json");
259167
+ STORE_FILE = () => copyPath(path236.join(WALNUT_HOME, "session-requests.json"));
259168
+ state11 = null;
259169
+ serial4 = serialChain();
259170
+ follower3 = null;
259171
+ }
259172
+ });
259173
+
258875
259174
  // src/web/routes/messages-v1.ts
258876
259175
  import { Router as Router82 } from "express";
258877
259176
  function header(req, name) {
@@ -258932,7 +259231,15 @@ var init_messages_v1 = __esm({
258932
259231
  return;
258933
259232
  }
258934
259233
  const { getSessionRequest: getSessionRequest2 } = await Promise.resolve().then(() => (init_session_requests(), session_requests_exports));
258935
- const request4 = await getSessionRequest2(id);
259234
+ let request4 = await getSessionRequest2(id);
259235
+ if (!request4) {
259236
+ const [{ readRequestCopy: readRequestCopy2 }, { copyKindAsOf: copyKindAsOf2, COPY_AS_OF_HEADER: COPY_AS_OF_HEADER2 }] = await Promise.all([
259237
+ Promise.resolve().then(() => (init_requests(), requests_exports)),
259238
+ Promise.resolve().then(() => (init_gate(), gate_exports))
259239
+ ]);
259240
+ request4 = await readRequestCopy2(id) ?? void 0;
259241
+ if (request4) res.setHeader(COPY_AS_OF_HEADER2, String(await copyKindAsOf2("requests") ?? 0));
259242
+ }
258936
259243
  if (!request4) {
258937
259244
  sendV1Error(res, 404, "not_found", `No such request: ${id}`);
258938
259245
  return;
@@ -260607,6 +260914,17 @@ var init_search_memory_v1 = __esm({
260607
260914
  });
260608
260915
  searchMemoryV1Router.get("/favorites", async (_req, res, next) => {
260609
260916
  try {
260917
+ const [{ readFavoritesCopy: readFavoritesCopy2 }, { copyKindAsOf: copyKindAsOf2, COPY_AS_OF_HEADER: COPY_AS_OF_HEADER2 }] = await Promise.all([
260918
+ Promise.resolve().then(() => (init_prefs(), prefs_exports)),
260919
+ Promise.resolve().then(() => (init_gate(), gate_exports))
260920
+ ]);
260921
+ const asOf2 = await copyKindAsOf2("prefs");
260922
+ const fav = asOf2 === null ? null : await readFavoritesCopy2();
260923
+ if (fav) {
260924
+ res.setHeader(COPY_AS_OF_HEADER2, String(asOf2));
260925
+ res.json({ projects: fav.projects ?? [], notes: fav.notes ?? [] });
260926
+ return;
260927
+ }
260610
260928
  const { readFavorites: readFavorites2 } = await Promise.resolve().then(() => (init_favorites(), favorites_exports));
260611
260929
  res.json(await readFavorites2());
260612
260930
  } catch (err2) {
@@ -261639,9 +261957,9 @@ var init_stt_v1 = __esm({
261639
261957
 
261640
261958
  // src/web/routes/pastes.ts
261641
261959
  import { Router as Router89 } from "express";
261642
- import path236 from "path";
261960
+ import path237 from "path";
261643
261961
  import { createHash as createHash37 } from "crypto";
261644
- import fsp123 from "fs/promises";
261962
+ import fsp124 from "fs/promises";
261645
261963
  var pastesRouter, MAX_PASTE_CHARS;
261646
261964
  var init_pastes = __esm({
261647
261965
  "src/web/routes/pastes.ts"() {
@@ -261661,11 +261979,11 @@ var init_pastes = __esm({
261661
261979
  res.status(413).json({ error: `Paste too large (max ${MAX_PASTE_CHARS} chars)` });
261662
261980
  return;
261663
261981
  }
261664
- await fsp123.mkdir(PASTES_DIR, { recursive: true });
261982
+ await fsp124.mkdir(PASTES_DIR, { recursive: true });
261665
261983
  const hash3 = createHash37("sha256").update(text5).digest("hex").slice(0, 12);
261666
261984
  const filename = `${Date.now()}-${hash3}.txt`;
261667
- const filePath = path236.join(PASTES_DIR, filename);
261668
- await fsp123.writeFile(filePath, text5, "utf8");
261985
+ const filePath = path237.join(PASTES_DIR, filename);
261986
+ await fsp124.writeFile(filePath, text5, "utf8");
261669
261987
  log.web.info("paste spilled to disk", { filePath, chars: text5.length });
261670
261988
  res.json({ path: filePath, filename, chars: text5.length });
261671
261989
  } catch (err2) {
@@ -261681,8 +261999,8 @@ __export(file_content_replica_copy_exports, {
261681
261999
  primaryDataDirRelPath: () => primaryDataDirRelPath,
261682
262000
  resolveReplicaCopy: () => resolveReplicaCopy
261683
262001
  });
261684
- import path237 from "path";
261685
- import fsp124 from "fs/promises";
262002
+ import path238 from "path";
262003
+ import fsp125 from "fs/promises";
261686
262004
  function dataDirIndex(parts, tilde) {
261687
262005
  if (tilde) return parts[1] === DATA_DIR_NAME ? 1 : -1;
261688
262006
  if ((parts[0] === "Users" || parts[0] === "home") && parts[2] === DATA_DIR_NAME) return 2;
@@ -261712,12 +262030,12 @@ async function resolveReplicaCopy(requestPath) {
261712
262030
  const rel = primaryDataDirRelPath(requestPath);
261713
262031
  if (rel === null || deniedName(rel)) return null;
261714
262032
  try {
261715
- const root6 = await fsp124.realpath(WALNUT_HOME);
261716
- const real = await fsp124.realpath(path237.join(WALNUT_HOME, rel));
261717
- if (!real.startsWith(root6 + path237.sep)) return null;
261718
- const realRel = path237.relative(root6, real).split(path237.sep).join("/");
261719
- if (isSecretPath(path237.join(WALNUT_HOME, realRel)) || deniedName(realRel)) return null;
261720
- const st2 = await fsp124.stat(real);
262033
+ const root6 = await fsp125.realpath(WALNUT_HOME);
262034
+ const real = await fsp125.realpath(path238.join(WALNUT_HOME, rel));
262035
+ if (!real.startsWith(root6 + path238.sep)) return null;
262036
+ const realRel = path238.relative(root6, real).split(path238.sep).join("/");
262037
+ if (isSecretPath(path238.join(WALNUT_HOME, realRel)) || deniedName(realRel)) return null;
262038
+ const st2 = await fsp125.stat(real);
261721
262039
  if (!st2.isFile()) return null;
261722
262040
  if (!await isTracked(root6, realRel)) return null;
261723
262041
  return { localPath: real, size: st2.size };
@@ -261757,11 +262075,11 @@ var init_file_content_replica_copy = __esm({
261757
262075
  // src/web/routes/media-v1.ts
261758
262076
  import { Router as Router90 } from "express";
261759
262077
  import crypto69 from "crypto";
261760
- import path238 from "path";
261761
- import fsp125 from "fs/promises";
262078
+ import path239 from "path";
262079
+ import fsp126 from "fs/promises";
261762
262080
  function cachePathFor(host, filePath) {
261763
262081
  const hash3 = crypto69.createHash("sha256").update(filePath).digest("hex").slice(0, 16);
261764
- return path238.join(REMOTE_IMAGES_DIR, host, `${hash3}-${path238.basename(filePath)}`);
262082
+ return path239.join(REMOTE_IMAGES_DIR, host, `${hash3}-${path239.basename(filePath)}`);
261765
262083
  }
261766
262084
  async function hostForSession(sessionId) {
261767
262085
  if (CLOUD_MODE) {
@@ -261826,11 +262144,11 @@ var init_media_v1 = __esm({
261826
262144
  try {
261827
262145
  const filePath = req.query.path;
261828
262146
  const session2 = typeof req.query.session === "string" && SID_RE6.test(req.query.session) ? req.query.session : void 0;
261829
- if (!filePath || typeof filePath !== "string" || !path238.isAbsolute(filePath) || filePath.includes("..")) {
262147
+ if (!filePath || typeof filePath !== "string" || !path239.isAbsolute(filePath) || filePath.includes("..")) {
261830
262148
  res.status(400).json({ error: { code: "bad_request", message: "path must be an absolute file path" } });
261831
262149
  return;
261832
262150
  }
261833
- const ext2 = path238.extname(filePath).slice(1).toLowerCase();
262151
+ const ext2 = path239.extname(filePath).slice(1).toLowerCase();
261834
262152
  const mime = EXT_TO_MIME3[ext2];
261835
262153
  if (!mime) {
261836
262154
  res.status(400).json({ error: { code: "bad_request", message: "file type not allowed" } });
@@ -261838,8 +262156,8 @@ var init_media_v1 = __esm({
261838
262156
  }
261839
262157
  let buffer2 = null;
261840
262158
  try {
261841
- const st2 = await fsp125.stat(filePath);
261842
- if (st2.isFile() && st2.size <= MAX_FILE_SIZE3) buffer2 = await fsp125.readFile(filePath);
262159
+ const st2 = await fsp126.stat(filePath);
262160
+ if (st2.isFile() && st2.size <= MAX_FILE_SIZE3) buffer2 = await fsp126.readFile(filePath);
261843
262161
  } catch {
261844
262162
  }
261845
262163
  let waitedOnPending = false;
@@ -261860,8 +262178,8 @@ var init_media_v1 = __esm({
261860
262178
  if (buffer2) {
261861
262179
  try {
261862
262180
  const cachePath3 = cachePathFor(host, filePath);
261863
- await fsp125.mkdir(path238.dirname(cachePath3), { recursive: true });
261864
- await fsp125.writeFile(cachePath3, buffer2);
262181
+ await fsp126.mkdir(path239.dirname(cachePath3), { recursive: true });
262182
+ await fsp126.writeFile(cachePath3, buffer2);
261865
262183
  } catch {
261866
262184
  }
261867
262185
  break;
@@ -261871,9 +262189,9 @@ var init_media_v1 = __esm({
261871
262189
  for (const host of hosts2) {
261872
262190
  try {
261873
262191
  const cached8 = cachePathFor(host, filePath);
261874
- const st2 = await fsp125.stat(cached8);
262192
+ const st2 = await fsp126.stat(cached8);
261875
262193
  if (st2.isFile() && st2.size <= MAX_FILE_SIZE3) {
261876
- buffer2 = await fsp125.readFile(cached8);
262194
+ buffer2 = await fsp126.readFile(cached8);
261877
262195
  break;
261878
262196
  }
261879
262197
  } catch {
@@ -261883,7 +262201,7 @@ var init_media_v1 = __esm({
261883
262201
  if (!buffer2 && hosts2.length > 0 && hosts2.every((h8) => h8 === "__local__") && !(await Promise.resolve().then(() => (init_bridge_registry(), bridge_registry_exports))).bridgeForHost("__local__").connected) {
261884
262202
  const { resolveReplicaCopy: resolveReplicaCopy2 } = await Promise.resolve().then(() => (init_file_content_replica_copy(), file_content_replica_copy_exports));
261885
262203
  const copy5 = await resolveReplicaCopy2(filePath);
261886
- if (copy5 && copy5.size <= MAX_FILE_SIZE3) buffer2 = await fsp125.readFile(copy5.localPath);
262204
+ if (copy5 && copy5.size <= MAX_FILE_SIZE3) buffer2 = await fsp126.readFile(copy5.localPath);
261887
262205
  }
261888
262206
  }
261889
262207
  if (!buffer2) {
@@ -261908,6 +262226,19 @@ var init_media_v1 = __esm({
261908
262226
 
261909
262227
  // src/web/routes/routines-v1.ts
261910
262228
  import { Router as Router91 } from "express";
262229
+ async function answeredFromCopy(res, includeDisabled, answer5) {
262230
+ const [{ companionRoutinesCopy: companionRoutinesCopy2 }, { copyKindAsOf: copyKindAsOf2, COPY_AS_OF_HEADER: COPY_AS_OF_HEADER2 }] = await Promise.all([
262231
+ Promise.resolve().then(() => (init_routines_follower(), routines_follower_exports)),
262232
+ Promise.resolve().then(() => (init_gate(), gate_exports))
262233
+ ]);
262234
+ const jobs2 = await companionRoutinesCopy2({ includeDisabled });
262235
+ if (!jobs2) return false;
262236
+ res.setHeader(COPY_AS_OF_HEADER2, String(await copyKindAsOf2("routines") ?? 0));
262237
+ const body7 = answer5(jobs2);
262238
+ if (body7 === null) sendV1Error(res, 404, "not_found", "No such routine in the copy of your Mac's routines");
262239
+ else res.json(body7);
262240
+ return true;
262241
+ }
261911
262242
  function validRid(req, res) {
261912
262243
  const id = String(req.params.id ?? "");
261913
262244
  if (!RID_RE.test(id)) {
@@ -261954,6 +262285,7 @@ var init_routines_v1 = __esm({
261954
262285
  try {
261955
262286
  const includeDisabled = req.query.includeDisabled === "true";
261956
262287
  if (CLOUD_MODE) {
262288
+ if (await answeredFromCopy(res, includeDisabled, (jobs2) => ({ jobs: jobs2 }))) return;
261957
262289
  await relayControlAction(res, "server.routines", SERVER_RELAY_SID14, { includeDisabled }, 200);
261958
262290
  return;
261959
262291
  }
@@ -261978,6 +262310,7 @@ var init_routines_v1 = __esm({
261978
262310
  routinesV1Router.get("/routines/status", async (_req, res, next) => {
261979
262311
  try {
261980
262312
  if (CLOUD_MODE) {
262313
+ if (await answeredFromCopy(res, true, (jobs2) => ({ enabled: false, storePath: "", jobs: jobs2.length, nextWakeAtMs: null }))) return;
261981
262314
  await relayControlAction(res, "server.routines.status", SERVER_RELAY_SID14, void 0, 200);
261982
262315
  return;
261983
262316
  }
@@ -262049,6 +262382,10 @@ var init_routines_v1 = __esm({
262049
262382
  const id = validRid(req, res);
262050
262383
  if (!id) return;
262051
262384
  if (CLOUD_MODE) {
262385
+ if (await answeredFromCopy(res, true, (jobs2) => {
262386
+ const job2 = jobs2.find((j8) => j8.id === id);
262387
+ return job2 ? { job: job2 } : null;
262388
+ })) return;
262052
262389
  await relayControlAction(res, "server.routines.get", SERVER_RELAY_SID14, { id }, 200);
262053
262390
  return;
262054
262391
  }
@@ -263243,8 +263580,8 @@ __export(file_content_bridge_exports, {
263243
263580
  resolveBridgeHost: () => resolveBridgeHost,
263244
263581
  serveCloudFileContent: () => serveCloudFileContent
263245
263582
  });
263246
- import path239 from "path";
263247
- import fsp126 from "fs/promises";
263583
+ import path240 from "path";
263584
+ import fsp127 from "fs/promises";
263248
263585
  function resolveBridgeHost(host) {
263249
263586
  return typeof host === "string" && host.length > 0 ? host : PRIMARY_BRIDGE_ALIAS3;
263250
263587
  }
@@ -263315,7 +263652,7 @@ function precheckPath(res, rawPath) {
263315
263652
  sendV1Error(res, 400, "bad_request", "Invalid path");
263316
263653
  return null;
263317
263654
  }
263318
- if (rawPath !== "~" && !rawPath.startsWith("~/") && !path239.isAbsolute(rawPath)) {
263655
+ if (rawPath !== "~" && !rawPath.startsWith("~/") && !path240.isAbsolute(rawPath)) {
263319
263656
  sendV1Error(res, 400, "bad_request", "Path must be absolute");
263320
263657
  return null;
263321
263658
  }
@@ -263359,7 +263696,7 @@ async function serveCloudFileContent(req, res) {
263359
263696
  const hostAlias2 = resolveBridgeHost(req.query.host);
263360
263697
  const raw = req.query.raw === "1" || req.query.raw === "true";
263361
263698
  const download = req.query.download === "1" || req.query.download === "true";
263362
- const ext2 = path239.extname(filePath).slice(1).toLowerCase();
263699
+ const ext2 = path240.extname(filePath).slice(1).toLowerCase();
263363
263700
  const {
263364
263701
  assertPathAllowed: assertPathAllowed2,
263365
263702
  isSecretPath: isSecretPath2,
@@ -263369,7 +263706,7 @@ async function serveCloudFileContent(req, res) {
263369
263706
  FileContentError: FileContentError2
263370
263707
  } = await Promise.resolve().then(() => (init_file_content(), file_content_exports));
263371
263708
  const explicitHost = typeof req.query.host === "string" && req.query.host.length > 0;
263372
- const locallyPresent = await fsp126.stat(filePath).then((st2) => st2.isFile()).catch(() => false);
263709
+ const locallyPresent = await fsp127.stat(filePath).then((st2) => st2.isFile()).catch(() => false);
263373
263710
  if (!explicitHost && locallyPresent && cloudLocalReadAllowed2(filePath) && !isSecretPath2(filePath)) {
263374
263711
  try {
263375
263712
  if (raw) {
@@ -263467,10 +263804,10 @@ async function serveReplicaCopy(req, res, requestPath, copy5, opts2) {
263467
263804
  return;
263468
263805
  }
263469
263806
  if (copy5.size <= MAX_BRIDGE_FILE_BYTES) {
263470
- res.json(jsonPayloadFromBuffer(await fsp126.readFile(copy5.localPath), opts2.ext, false));
263807
+ res.json(jsonPayloadFromBuffer(await fsp127.readFile(copy5.localPath), opts2.ext, false));
263471
263808
  return;
263472
263809
  }
263473
- const fh = await fsp126.open(copy5.localPath, "r");
263810
+ const fh = await fsp127.open(copy5.localPath, "r");
263474
263811
  try {
263475
263812
  const head2 = Buffer.alloc(MAX_TEXT_PAYLOAD);
263476
263813
  const { bytesRead } = await fh.read(head2, 0, head2.length, 0);
@@ -264544,17 +264881,17 @@ __export(checklist_io_exports, {
264544
264881
  readHeartbeatChecklist: () => readHeartbeatChecklist,
264545
264882
  writeHeartbeatChecklist: () => writeHeartbeatChecklist
264546
264883
  });
264547
- import fsp127 from "fs/promises";
264884
+ import fsp128 from "fs/promises";
264548
264885
  async function readHeartbeatChecklist() {
264549
264886
  try {
264550
- return await fsp127.readFile(HEARTBEAT_FILE, "utf-8");
264887
+ return await fsp128.readFile(HEARTBEAT_FILE, "utf-8");
264551
264888
  } catch (err2) {
264552
264889
  if (err2.code === "ENOENT") return "";
264553
264890
  throw err2;
264554
264891
  }
264555
264892
  }
264556
264893
  async function writeHeartbeatChecklist(content) {
264557
- await fsp127.writeFile(HEARTBEAT_FILE, content, "utf-8");
264894
+ await fsp128.writeFile(HEARTBEAT_FILE, content, "utf-8");
264558
264895
  }
264559
264896
  var init_checklist_io = __esm({
264560
264897
  "src/heartbeat/checklist-io.ts"() {
@@ -266334,11 +266671,11 @@ __export(ephemeral_guard_exports, {
266334
266671
  });
266335
266672
  import fs129 from "fs";
266336
266673
  import os60 from "os";
266337
- import path240 from "path";
266674
+ import path241 from "path";
266338
266675
  function productionWalnutHomes() {
266339
266676
  const homes = /* @__PURE__ */ new Set();
266340
266677
  const add3 = (home) => {
266341
- if (home) homes.add(path240.join(home, ".open-walnut"));
266678
+ if (home) homes.add(path241.join(home, ".open-walnut"));
266342
266679
  };
266343
266680
  add3(os60.homedir());
266344
266681
  try {
@@ -266348,7 +266685,7 @@ function productionWalnutHomes() {
266348
266685
  return [...homes];
266349
266686
  }
266350
266687
  function canonical2(dir4) {
266351
- const resolved = path240.resolve(dir4);
266688
+ const resolved = path241.resolve(dir4);
266352
266689
  try {
266353
266690
  return fs129.realpathSync(resolved);
266354
266691
  } catch {
@@ -266384,28 +266721,28 @@ __export(boot_guard_exports, {
266384
266721
  });
266385
266722
  import fs130 from "fs";
266386
266723
  import os61 from "os";
266387
- import path241 from "path";
266724
+ import path242 from "path";
266388
266725
  function canonical3(dir4) {
266389
- let head2 = path241.resolve(dir4);
266726
+ let head2 = path242.resolve(dir4);
266390
266727
  const rest = [];
266391
266728
  for (; ; ) {
266392
266729
  try {
266393
- return path241.join(fs130.realpathSync(head2), ...rest);
266730
+ return path242.join(fs130.realpathSync(head2), ...rest);
266394
266731
  } catch {
266395
266732
  }
266396
- const up = path241.dirname(head2);
266397
- if (up === head2) return path241.resolve(dir4);
266398
- rest.unshift(path241.basename(head2));
266733
+ const up = path242.dirname(head2);
266734
+ if (up === head2) return path242.resolve(dir4);
266735
+ rest.unshift(path242.basename(head2));
266399
266736
  head2 = up;
266400
266737
  }
266401
266738
  }
266402
266739
  function spellings(dir4) {
266403
- const resolved = path241.resolve(dir4);
266740
+ const resolved = path242.resolve(dir4);
266404
266741
  return [.../* @__PURE__ */ new Set([resolved, canonical3(resolved), `/private${resolved}`])];
266405
266742
  }
266406
266743
  function within5(child2, parent) {
266407
- const rel = path241.relative(parent, child2);
266408
- return rel === "" || !rel.startsWith("..") && !path241.isAbsolute(rel);
266744
+ const rel = path242.relative(parent, child2);
266745
+ return rel === "" || !rel.startsWith("..") && !path242.isAbsolute(rel);
266409
266746
  }
266410
266747
  function overlaps(a8, b8) {
266411
266748
  return spellings(a8).some((x3) => spellings(b8).some((y3) => within5(x3, y3) || within5(y3, x3)));
@@ -266416,7 +266753,7 @@ function holdsOrIs(outer, inner2) {
266416
266753
  function accountHomes(env3) {
266417
266754
  const homes = /* @__PURE__ */ new Set();
266418
266755
  const add3 = (h8) => {
266419
- if (h8 && h8.trim()) homes.add(path241.resolve(h8.trim()));
266756
+ if (h8 && h8.trim()) homes.add(path242.resolve(h8.trim()));
266420
266757
  };
266421
266758
  add3(env3.HOME);
266422
266759
  add3(os61.homedir());
@@ -266474,7 +266811,7 @@ function assertReplicaBootSafe(input) {
266474
266811
  if (why2) throw new Error(`Host replica refused to start: ${why2}.`);
266475
266812
  }
266476
266813
  function claimReplicaDir(dir4) {
266477
- const marker = path241.join(dir4, REPLICA_DIR_MARKER);
266814
+ const marker = path242.join(dir4, REPLICA_DIR_MARKER);
266478
266815
  try {
266479
266816
  return fs130.lstatSync(marker).isFile();
266480
266817
  } catch {
@@ -266499,7 +266836,7 @@ function claimReplicaDir(dir4) {
266499
266836
  function tightenReplicaModes(dirs2, limit = 2e4) {
266500
266837
  const marked = dirs2.filter((d8) => {
266501
266838
  try {
266502
- return fs130.lstatSync(path241.join(d8, REPLICA_DIR_MARKER)).isFile();
266839
+ return fs130.lstatSync(path242.join(d8, REPLICA_DIR_MARKER)).isFile();
266503
266840
  } catch {
266504
266841
  return false;
266505
266842
  }
@@ -266529,7 +266866,7 @@ function tightenReplicaModes(dirs2, limit = 2e4) {
266529
266866
  } catch {
266530
266867
  return;
266531
266868
  }
266532
- for (const n6 of names2) visit(path241.join(p6, n6));
266869
+ for (const n6 of names2) visit(path242.join(p6, n6));
266533
266870
  } else if (st2.isFile() && (st2.mode & 63) !== 0) {
266534
266871
  try {
266535
266872
  fs130.chmodSync(p6, st2.mode & 448 | 384);
@@ -266716,29 +267053,29 @@ __export(search_replica_store_exports, {
266716
267053
  searchReplicaSync: () => searchReplicaSync,
266717
267054
  startSearchReplicaStore: () => startSearchReplicaStore
266718
267055
  });
266719
- import fsp128 from "fs/promises";
267056
+ import fsp129 from "fs/promises";
266720
267057
  import os62 from "os";
266721
- import path242 from "path";
267058
+ import path243 from "path";
266722
267059
  async function wiring() {
266723
267060
  return Promise.resolve().then(() => (init_wiring(), wiring_exports));
266724
267061
  }
266725
267062
  async function loadState() {
266726
- if (state11) return state11;
267063
+ if (state12) return state12;
266727
267064
  let s4 = { v: 1, mode: null, syncedAt: null };
266728
267065
  try {
266729
- const raw = JSON.parse(await fsp128.readFile(STATE_FILE(), "utf8"));
267066
+ const raw = JSON.parse(await fsp129.readFile(STATE_FILE2(), "utf8"));
266730
267067
  if (raw && raw.v === 1) {
266731
267068
  s4 = { v: 1, mode: raw.mode ? companionSearchMode(raw.mode) : null, syncedAt: typeof raw.syncedAt === "number" ? raw.syncedAt : null };
266732
267069
  }
266733
267070
  } catch {
266734
267071
  }
266735
- state11 = s4;
267072
+ state12 = s4;
266736
267073
  return s4;
266737
267074
  }
266738
267075
  async function saveState() {
266739
- if (state11) await writeJsonFile(STATE_FILE(), state11);
267076
+ if (state12) await writeJsonFile(STATE_FILE2(), state12);
266740
267077
  }
266741
- function serial4(fn) {
267078
+ function serial5(fn) {
266742
267079
  const run12 = chain4.then(fn, fn);
266743
267080
  chain4 = run12.catch(() => {
266744
267081
  });
@@ -266802,8 +267139,8 @@ async function closeIndex() {
266802
267139
  allDirty2 = true;
266803
267140
  }
266804
267141
  function publishReady() {
266805
- const ready2 = enabled && mapBuilt && map3.size > 0 && state11?.syncedAt != null;
266806
- setCompanionSearchReady(ready2, ready2 ? state11.syncedAt : null);
267142
+ const ready2 = enabled && mapBuilt && map3.size > 0 && state12?.syncedAt != null;
267143
+ setCompanionSearchReady(ready2, ready2 ? state12.syncedAt : null);
266807
267144
  }
266808
267145
  async function markInSync() {
266809
267146
  const s4 = await loadState();
@@ -266830,7 +267167,7 @@ async function warm(why2) {
266830
267167
  }
266831
267168
  }
266832
267169
  function searchReplicaStatus(body7) {
266833
- return serial4(async () => {
267170
+ return serial5(async () => {
266834
267171
  if (!isFollower()) return { ok: false, status: 400, error: "not_a_replica" };
266835
267172
  const s4 = await loadState();
266836
267173
  const mode = companionSearchMode(body7.mode);
@@ -266878,7 +267215,7 @@ function searchReplicaStatus(body7) {
266878
267215
  });
266879
267216
  }
266880
267217
  function searchReplicaSync(body7) {
266881
- return serial4(async () => {
267218
+ return serial5(async () => {
266882
267219
  if (!isFollower()) return { ok: false, status: 400, error: "not_a_replica" };
266883
267220
  if (!enabled) return { ok: false, status: 400, error: "search_copy_off" };
266884
267221
  if (!Array.isArray(body7.entries)) return { ok: false, status: 400, error: "bad_entries" };
@@ -266923,7 +267260,7 @@ async function forgetSearchMemo() {
266923
267260
  }
266924
267261
  }
266925
267262
  function searchReplicaPut(body7) {
266926
- return serial4(async () => {
267263
+ return serial5(async () => {
266927
267264
  if (!isFollower()) return { ok: false, status: 400, error: "not_a_replica" };
266928
267265
  if (!enabled) return { ok: false, status: 400, error: "search_copy_off" };
266929
267266
  if (!Array.isArray(body7.docs)) return { ok: false, status: 400, error: "bad_docs" };
@@ -266989,7 +267326,7 @@ function startSearchReplicaStore(options = {}) {
266989
267326
  if (!s4.mode || stopped2) return;
266990
267327
  const decision = companionSearchDecision(s4.mode, deps3.totalMb());
266991
267328
  if (!decision.enabled) return;
266992
- await serial4(async () => {
267329
+ await serial5(async () => {
266993
267330
  enabled = true;
266994
267331
  reason2 = decision.reason;
266995
267332
  await refreshMap2(await openIndex());
@@ -267022,12 +267359,12 @@ function startSearchReplicaStore(options = {}) {
267022
267359
  }));
267023
267360
  }).catch((err2) => log.memory.warn("search replica: local writes not wired", { error: err2 instanceof Error ? err2.message : String(err2) }));
267024
267361
  unsubs.push(onLeaderPresence((answers4) => {
267025
- if (stopped2 || answers4 || !enabled || state11?.syncedAt == null) return;
267362
+ if (stopped2 || answers4 || !enabled || state12?.syncedAt == null) return;
267026
267363
  void warm("leader away");
267027
267364
  }));
267028
267365
  const tick = setInterval(() => {
267029
267366
  void (async () => {
267030
- if (stopped2 || !enabled || state11?.syncedAt == null) return;
267367
+ if (stopped2 || !enabled || state12?.syncedAt == null) return;
267031
267368
  if (Date.now() - lastWarmAt < WARM_EVERY_MS) return;
267032
267369
  if (!await deps3.macAway()) return;
267033
267370
  await warm("mac away");
@@ -267046,7 +267383,7 @@ function startSearchReplicaStore(options = {}) {
267046
267383
  };
267047
267384
  }
267048
267385
  function _resetSearchReplicaStoreForTesting(overrides = {}) {
267049
- state11 = null;
267386
+ state12 = null;
267050
267387
  enabled = false;
267051
267388
  reason2 = "off";
267052
267389
  map3.clear();
@@ -267061,7 +267398,7 @@ function _resetSearchReplicaStoreForTesting(overrides = {}) {
267061
267398
  deps3 = { totalMb: () => Math.round(os62.totalmem() / (1024 * 1024)), macAway: defaultMacAway, ...overrides };
267062
267399
  setCompanionSearchReady(false, null);
267063
267400
  }
267064
- var STATE_FILE, MASS_REMOVE_FLOOR, SCAN_SLICE2, WARM_EVERY_MS, TICK_MS2, defaultMacAway, deps3, state11, enabled, reason2, map3, mapBuilt, allDirty2, dirty2, unlisten, lastWarmAt, warmedOnce, chain4, yieldLoop;
267401
+ var STATE_FILE2, MASS_REMOVE_FLOOR, SCAN_SLICE2, WARM_EVERY_MS, TICK_MS2, defaultMacAway, deps3, state12, enabled, reason2, map3, mapBuilt, allDirty2, dirty2, unlisten, lastWarmAt, warmedOnce, chain4, yieldLoop;
267065
267402
  var init_search_replica_store = __esm({
267066
267403
  "src/core/replication/search-replica-store.ts"() {
267067
267404
  "use strict";
@@ -267073,7 +267410,7 @@ var init_search_replica_store = __esm({
267073
267410
  init_replica_refs();
267074
267411
  init_search_digest();
267075
267412
  init_search_replica_wire();
267076
- STATE_FILE = () => path242.join(WALNUT_HOME, "cache", "search-replica.json");
267413
+ STATE_FILE2 = () => path243.join(WALNUT_HOME, "cache", "search-replica.json");
267077
267414
  MASS_REMOVE_FLOOR = 200;
267078
267415
  SCAN_SLICE2 = 500;
267079
267416
  WARM_EVERY_MS = 4 * 6e4;
@@ -267083,7 +267420,7 @@ var init_search_replica_store = __esm({
267083
267420
  totalMb: () => Math.round(os62.totalmem() / (1024 * 1024)),
267084
267421
  macAway: defaultMacAway
267085
267422
  };
267086
- state11 = null;
267423
+ state12 = null;
267087
267424
  enabled = false;
267088
267425
  reason2 = "off";
267089
267426
  map3 = new DigestMap();
@@ -267099,10 +267436,10 @@ var init_search_replica_store = __esm({
267099
267436
  });
267100
267437
 
267101
267438
  // src/core/replication/kinds/boards.ts
267102
- import fsp129 from "fs/promises";
267103
- import path243 from "path";
267439
+ import fsp130 from "fs/promises";
267440
+ import path244 from "path";
267104
267441
  async function leaderBoards(dir4 = boardsDir2()) {
267105
- const names2 = await fsp129.readdir(dir4).catch(() => []);
267442
+ const names2 = await fsp130.readdir(dir4).catch(() => []);
267106
267443
  const out = [];
267107
267444
  const unreadable = [];
267108
267445
  const seen2 = /* @__PURE__ */ new Set();
@@ -267111,9 +267448,9 @@ async function leaderBoards(dir4 = boardsDir2()) {
267111
267448
  const id = name.slice(0, -".json".length);
267112
267449
  if (!TASK_ID_RE3.test(id)) continue;
267113
267450
  seen2.add(id);
267114
- const file = path243.join(dir4, name);
267451
+ const file = path244.join(dir4, name);
267115
267452
  try {
267116
- const st2 = await fsp129.stat(file);
267453
+ const st2 = await fsp130.stat(file);
267117
267454
  if (!st2.isFile()) continue;
267118
267455
  if (st2.size > BOARD_COPY_MAX_BYTES) {
267119
267456
  if (!warnedTooBig.has(id)) log.session.warn("boards copy: a board is too large to copy, it is read from the Mac", { taskId: id, bytes: st2.size });
@@ -267122,14 +267459,14 @@ async function leaderBoards(dir4 = boardsDir2()) {
267122
267459
  }
267123
267460
  let c8 = cache16.get(id);
267124
267461
  if (!c8 || c8.size !== st2.size || c8.mtimeMs !== st2.mtimeMs) {
267125
- const row = JSON.parse(await fsp129.readFile(file, "utf8"));
267126
- if (!isRow4(row) || row.task_id !== id) {
267462
+ const row = JSON.parse(await fsp130.readFile(file, "utf8"));
267463
+ if (!isRow6(row) || row.task_id !== id) {
267127
267464
  unreadable.push(id);
267128
267465
  continue;
267129
267466
  }
267130
267467
  c8 = { size: st2.size, mtimeMs: st2.mtimeMs, row, hash: sha12(JSON.stringify(row)) };
267131
267468
  cache16.set(id, c8);
267132
- hashOf4.set(row, c8.hash);
267469
+ hashOf6.set(row, c8.hash);
267133
267470
  }
267134
267471
  out.push(c8.row);
267135
267472
  } catch (err2) {
@@ -267144,56 +267481,56 @@ async function leaderBoards(dir4 = boardsDir2()) {
267144
267481
  if (fresh.length > 0) log.session.warn("boards copy: a board could not be read, the host keeps its copy of it", { taskIds: fresh });
267145
267482
  return out;
267146
267483
  }
267147
- function isRow4(v3) {
267484
+ function isRow6(v3) {
267148
267485
  const b8 = v3;
267149
267486
  return !!b8 && typeof b8 === "object" && !Array.isArray(b8) && typeof b8.task_id === "string" && TASK_ID_RE3.test(b8.task_id) && typeof b8.html === "string" && typeof b8.version === "number";
267150
267487
  }
267151
- async function load6() {
267152
- if (state12) return state12;
267488
+ async function load7() {
267489
+ if (state13) return state13;
267153
267490
  let s4 = { asOf: 0, at: 0, order: [], hashes: {} };
267154
267491
  try {
267155
- const raw = JSON.parse(await fsp129.readFile(STATE_FILE2(), "utf8"));
267492
+ const raw = JSON.parse(await fsp130.readFile(STATE_FILE3(), "utf8"));
267156
267493
  if (raw?.v === 1 && raw.hashes && typeof raw.hashes === "object") s4 = { asOf: Number(raw.asOf) || 0, at: Number(raw.at) || 0, order: [], hashes: raw.hashes };
267157
267494
  } catch {
267158
267495
  }
267159
- state12 = s4;
267496
+ state13 = s4;
267160
267497
  return s4;
267161
267498
  }
267162
- async function save() {
267163
- if (state12) await writeCopyFile(STATE_FILE2(), { v: 1, asOf: state12.asOf, at: state12.at, hashes: state12.hashes });
267499
+ async function save2() {
267500
+ if (state13) await writeCopyFile(STATE_FILE3(), { v: 1, asOf: state13.asOf, at: state13.at, hashes: state13.hashes });
267164
267501
  }
267165
267502
  async function localIds() {
267166
- const names2 = await fsp129.readdir(boardsDir2()).catch(() => []);
267503
+ const names2 = await fsp130.readdir(boardsDir2()).catch(() => []);
267167
267504
  return names2.filter((n6) => n6.endsWith(".json")).map((n6) => n6.slice(0, -".json".length)).filter((id) => TASK_ID_RE3.test(id));
267168
267505
  }
267169
267506
  function changed2() {
267170
267507
  }
267171
267508
  function boardsFollower() {
267172
- follower3 ??= createRowSetFollower({
267509
+ follower4 ??= createRowSetFollower({
267173
267510
  kind: "boards",
267174
267511
  schemaVersion: BOARDS_SCHEMA_VERSION,
267175
267512
  label: "boards copy",
267176
267513
  log: log.session,
267177
267514
  removalFloor: BOARDS_REMOVAL_FLOOR,
267178
267515
  ordered: false,
267179
- serial: (fn) => serial5(fn),
267516
+ serial: (fn) => serial6(fn),
267180
267517
  refuse: copyRefusal,
267181
- load: load6,
267182
- save,
267183
- isRow: isRow4,
267518
+ load: load7,
267519
+ save: save2,
267520
+ isRow: isRow6,
267184
267521
  key: (b8) => b8.task_id,
267185
267522
  localKeys: localIds,
267186
267523
  apply: async ({ rows, removeIds }) => {
267187
267524
  const skipped = [];
267188
267525
  for (const id of removeIds ?? []) {
267189
- if (TASK_ID_RE3.test(id)) await fsp129.rm(path243.join(boardsDir2(), `${id}.json`), { force: true });
267526
+ if (TASK_ID_RE3.test(id)) await fsp130.rm(path244.join(boardsDir2(), `${id}.json`), { force: true });
267190
267527
  }
267191
267528
  for (const b8 of rows ?? []) {
267192
267529
  if (Buffer.byteLength(JSON.stringify(b8)) > BOARD_COPY_MAX_BYTES) {
267193
267530
  skipped.push(b8.task_id);
267194
267531
  continue;
267195
267532
  }
267196
- await writeCopyFile(path243.join(boardsDir2(), `${b8.task_id}.json`), b8);
267533
+ await writeCopyFile(path244.join(boardsDir2(), `${b8.task_id}.json`), b8);
267197
267534
  }
267198
267535
  return { skipped };
267199
267536
  },
@@ -267201,15 +267538,15 @@ function boardsFollower() {
267201
267538
  changed: changed2,
267202
267539
  purge: async () => {
267203
267540
  const ids2 = await localIds();
267204
- for (const id of ids2) await fsp129.rm(path243.join(boardsDir2(), `${id}.json`), { force: true });
267541
+ for (const id of ids2) await fsp130.rm(path244.join(boardsDir2(), `${id}.json`), { force: true });
267205
267542
  await markCopyOff("boards");
267206
- state12 = null;
267543
+ state13 = null;
267207
267544
  return { removed: ids2.length };
267208
267545
  }
267209
267546
  });
267210
- return follower3;
267547
+ return follower4;
267211
267548
  }
267212
- var BOARDS_SCHEMA_VERSION, BOARDS_REMOVAL_FLOOR, BOARD_COPY_MAX_BYTES, TASK_ID_RE3, boardsDir2, cache16, hashOf4, warnedTooBig, unreadableOf2, warnedUnreadable, BOARDS_KIND, STATE_FILE2, state12, serial5, follower3;
267549
+ var BOARDS_SCHEMA_VERSION, BOARDS_REMOVAL_FLOOR, BOARD_COPY_MAX_BYTES, TASK_ID_RE3, boardsDir2, cache16, hashOf6, warnedTooBig, unreadableOf2, warnedUnreadable, BOARDS_KIND, STATE_FILE3, state13, serial6, follower4;
267213
267550
  var init_boards = __esm({
267214
267551
  "src/core/replication/kinds/boards.ts"() {
267215
267552
  "use strict";
@@ -267222,9 +267559,9 @@ var init_boards = __esm({
267222
267559
  BOARDS_REMOVAL_FLOOR = 20;
267223
267560
  BOARD_COPY_MAX_BYTES = 2 * 1024 * 1024;
267224
267561
  TASK_ID_RE3 = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
267225
- boardsDir2 = () => path243.join(WALNUT_HOME, "boards");
267562
+ boardsDir2 = () => path244.join(WALNUT_HOME, "boards");
267226
267563
  cache16 = /* @__PURE__ */ new Map();
267227
- hashOf4 = /* @__PURE__ */ new WeakMap();
267564
+ hashOf6 = /* @__PURE__ */ new WeakMap();
267228
267565
  warnedTooBig = /* @__PURE__ */ new Set();
267229
267566
  unreadableOf2 = /* @__PURE__ */ new WeakMap();
267230
267567
  warnedUnreadable = /* @__PURE__ */ new Set();
@@ -267232,7 +267569,7 @@ var init_boards = __esm({
267232
267569
  kind: "boards",
267233
267570
  schemaVersion: BOARDS_SCHEMA_VERSION,
267234
267571
  key: (b8) => b8.task_id,
267235
- hash: (b8) => hashOf4.get(b8) ?? sha12(JSON.stringify(b8)),
267572
+ hash: (b8) => hashOf6.get(b8) ?? sha12(JSON.stringify(b8)),
267236
267573
  ordered: false,
267237
267574
  digest: false,
267238
267575
  choice: "boards",
@@ -267252,16 +267589,16 @@ var init_boards = __esm({
267252
267589
  };
267253
267590
  }
267254
267591
  };
267255
- STATE_FILE2 = () => path243.join(WALNUT_HOME, "cache", "replica", "boards.json");
267256
- state12 = null;
267257
- serial5 = serialChain();
267258
- follower3 = null;
267592
+ STATE_FILE3 = () => path244.join(WALNUT_HOME, "cache", "replica", "boards.json");
267593
+ state13 = null;
267594
+ serial6 = serialChain();
267595
+ follower4 = null;
267259
267596
  }
267260
267597
  });
267261
267598
 
267262
267599
  // src/core/replication/kinds/inbox.ts
267263
- import fsp130 from "fs/promises";
267264
- import path244 from "path";
267600
+ import fsp131 from "fs/promises";
267601
+ import path245 from "path";
267265
267602
  function watchLetters(soon) {
267266
267603
  let stop2 = null;
267267
267604
  let stopped2 = false;
@@ -267274,18 +267611,18 @@ function watchLetters(soon) {
267274
267611
  };
267275
267612
  }
267276
267613
  async function leaderBodies(dir4 = bodiesDir()) {
267277
- const names2 = (await fsp130.readdir(dir4).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6)).sort();
267614
+ const names2 = (await fsp131.readdir(dir4).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6)).sort();
267278
267615
  const out = [];
267279
267616
  const unreadable = [];
267280
267617
  const seen2 = new Set(names2);
267281
267618
  for (const name of names2) {
267282
- const file = path244.join(dir4, name);
267619
+ const file = path245.join(dir4, name);
267283
267620
  try {
267284
- const st2 = await fsp130.stat(file);
267621
+ const st2 = await fsp131.stat(file);
267285
267622
  if (!st2.isFile() || st2.size > INBOX_BODY_COPY_MAX_BYTES) continue;
267286
267623
  let c8 = bodyCache.get(name);
267287
267624
  if (!c8 || c8.size !== st2.size || c8.mtimeMs !== st2.mtimeMs) {
267288
- c8 = { size: st2.size, mtimeMs: st2.mtimeMs, hash: sha12(await fsp130.readFile(file, "utf8")) };
267625
+ c8 = { size: st2.size, mtimeMs: st2.mtimeMs, hash: sha12(await fsp131.readFile(file, "utf8")) };
267289
267626
  bodyCache.set(name, c8);
267290
267627
  }
267291
267628
  const row = { name };
@@ -267304,21 +267641,21 @@ async function loadBody(b8) {
267304
267641
  const file = bodyFiles.get(b8);
267305
267642
  if (!file) return typeof b8.body === "string" ? b8 : void 0;
267306
267643
  try {
267307
- const body7 = await fsp130.readFile(file, "utf8");
267644
+ const body7 = await fsp131.readFile(file, "utf8");
267308
267645
  return Buffer.byteLength(body7) > INBOX_BODY_COPY_MAX_BYTES ? void 0 : { name: b8.name, body: body7 };
267309
267646
  } catch {
267310
267647
  return void 0;
267311
267648
  }
267312
267649
  }
267313
267650
  function stateIo(name) {
267314
- const file = () => path244.join(WALNUT_HOME, "cache", "replica", `${name}.json`);
267651
+ const file = () => path245.join(WALNUT_HOME, "cache", "replica", `${name}.json`);
267315
267652
  let state17 = null;
267316
267653
  return {
267317
267654
  load: async () => {
267318
267655
  if (state17) return state17;
267319
267656
  let s4 = { asOf: 0, at: 0, order: [], hashes: {} };
267320
267657
  try {
267321
- const raw = JSON.parse(await fsp130.readFile(file(), "utf8"));
267658
+ const raw = JSON.parse(await fsp131.readFile(file(), "utf8"));
267322
267659
  if (raw?.v === 1 && raw.hashes && typeof raw.hashes === "object") {
267323
267660
  s4 = { asOf: Number(raw.asOf) || 0, at: Number(raw.at) || 0, order: Array.isArray(raw.order) ? raw.order.map(String) : [], hashes: raw.hashes };
267324
267661
  }
@@ -267337,7 +267674,7 @@ function stateIo(name) {
267337
267674
  }
267338
267675
  async function readIndex3() {
267339
267676
  try {
267340
- const raw = JSON.parse(await fsp130.readFile(indexFile3(), "utf8"));
267677
+ const raw = JSON.parse(await fsp131.readFile(indexFile3(), "utf8"));
267341
267678
  return Array.isArray(raw?.letters) ? raw.letters.filter(isLetter) : [];
267342
267679
  } catch {
267343
267680
  return [];
@@ -267360,7 +267697,7 @@ function inboxFollower() {
267360
267697
  removalFloor: INBOX_REMOVAL_FLOOR,
267361
267698
  ordered: true,
267362
267699
  digest: true,
267363
- serial: (fn) => serial6(fn),
267700
+ serial: (fn) => serial7(fn),
267364
267701
  refuse: refuse11,
267365
267702
  load: () => indexIo.load(),
267366
267703
  save: () => indexIo.save(),
@@ -267390,7 +267727,7 @@ function inboxFollower() {
267390
267727
  },
267391
267728
  purge: async () => {
267392
267729
  const removed = (await readIndex3()).length;
267393
- await fsp130.rm(indexFile3(), { force: true });
267730
+ await fsp131.rm(indexFile3(), { force: true });
267394
267731
  await markCopyOff("inbox");
267395
267732
  indexIo.reset();
267396
267733
  return { removed };
@@ -267406,23 +267743,23 @@ function inboxBodiesFollower() {
267406
267743
  log: log.notif,
267407
267744
  removalFloor: INBOX_REMOVAL_FLOOR,
267408
267745
  ordered: false,
267409
- serial: (fn) => serial6(fn),
267746
+ serial: (fn) => serial7(fn),
267410
267747
  refuse: refuse11,
267411
267748
  load: () => bodiesIo.load(),
267412
267749
  save: () => bodiesIo.save(),
267413
267750
  isRow: isBody,
267414
267751
  key: (b8) => b8.name,
267415
267752
  hash: (b8) => sha12(b8.body),
267416
- localKeys: async () => (await fsp130.readdir(bodiesDir()).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6)),
267753
+ localKeys: async () => (await fsp131.readdir(bodiesDir()).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6)),
267417
267754
  apply: async ({ rows, removeIds }) => {
267418
- for (const name of removeIds ?? []) if (BODY_FILE_RE.test(name)) await fsp130.rm(path244.join(bodiesDir(), name), { force: true });
267755
+ for (const name of removeIds ?? []) if (BODY_FILE_RE.test(name)) await fsp131.rm(path245.join(bodiesDir(), name), { force: true });
267419
267756
  const skipped = [];
267420
267757
  for (const b8 of rows ?? []) {
267421
267758
  if (Buffer.byteLength(b8.body) > INBOX_BODY_COPY_MAX_BYTES) {
267422
267759
  skipped.push(b8.name);
267423
267760
  continue;
267424
267761
  }
267425
- await writeCopyText(path244.join(bodiesDir(), b8.name), b8.body);
267762
+ await writeCopyText(path245.join(bodiesDir(), b8.name), b8.body);
267426
267763
  }
267427
267764
  return { skipped };
267428
267765
  },
@@ -267430,8 +267767,8 @@ function inboxBodiesFollower() {
267430
267767
  changed: () => {
267431
267768
  },
267432
267769
  purge: async () => {
267433
- const names2 = (await fsp130.readdir(bodiesDir()).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6));
267434
- for (const name of names2) await fsp130.rm(path244.join(bodiesDir(), name), { force: true });
267770
+ const names2 = (await fsp131.readdir(bodiesDir()).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6));
267771
+ for (const name of names2) await fsp131.rm(path245.join(bodiesDir(), name), { force: true });
267435
267772
  await markCopyOff("inbox-bodies");
267436
267773
  bodiesIo.reset();
267437
267774
  return { removed: names2.length };
@@ -267439,7 +267776,7 @@ function inboxBodiesFollower() {
267439
267776
  });
267440
267777
  return bodiesF;
267441
267778
  }
267442
- var INBOX_SCHEMA_VERSION, INBOX_REMOVAL_FLOOR, INBOX_BODY_COPY_MAX_BYTES, inboxDir, indexFile3, bodiesDir, letterHashes, INBOX_KIND, bodyCache, bodyHashes, bodyFiles, unreadableBodiesOf, INBOX_BODIES_KIND, refuse11, indexIo, bodiesIo, serial6, inboxF, bodiesF;
267779
+ var INBOX_SCHEMA_VERSION, INBOX_REMOVAL_FLOOR, INBOX_BODY_COPY_MAX_BYTES, inboxDir, indexFile3, bodiesDir, letterHashes, INBOX_KIND, bodyCache, bodyHashes, bodyFiles, unreadableBodiesOf, INBOX_BODIES_KIND, refuse11, indexIo, bodiesIo, serial7, inboxF, bodiesF;
267443
267780
  var init_inbox = __esm({
267444
267781
  "src/core/replication/kinds/inbox.ts"() {
267445
267782
  "use strict";
@@ -267452,9 +267789,9 @@ var init_inbox = __esm({
267452
267789
  INBOX_SCHEMA_VERSION = 1;
267453
267790
  INBOX_REMOVAL_FLOOR = 50;
267454
267791
  INBOX_BODY_COPY_MAX_BYTES = 4 * 1024 * 1024;
267455
- inboxDir = () => path244.join(WALNUT_HOME, "human-inbox");
267456
- indexFile3 = () => path244.join(inboxDir(), "index.json");
267457
- bodiesDir = () => path244.join(inboxDir(), "bodies");
267792
+ inboxDir = () => path245.join(WALNUT_HOME, "human-inbox");
267793
+ indexFile3 = () => path245.join(inboxDir(), "index.json");
267794
+ bodiesDir = () => path245.join(inboxDir(), "bodies");
267458
267795
  letterHashes = /* @__PURE__ */ new WeakMap();
267459
267796
  INBOX_KIND = {
267460
267797
  kind: "inbox",
@@ -267496,134 +267833,12 @@ var init_inbox = __esm({
267496
267833
  refuse11 = copyRefusal;
267497
267834
  indexIo = stateIo("inbox");
267498
267835
  bodiesIo = stateIo("inbox-bodies");
267499
- serial6 = serialChain();
267836
+ serial7 = serialChain();
267500
267837
  inboxF = null;
267501
267838
  bodiesF = null;
267502
267839
  }
267503
267840
  });
267504
267841
 
267505
- // src/core/replication/kinds/requests.ts
267506
- import fsp131 from "fs/promises";
267507
- import path245 from "path";
267508
- function forwardRequest(local, incoming) {
267509
- if (local && FINAL.has(local.status) && !FINAL.has(incoming.status)) return local;
267510
- return incoming;
267511
- }
267512
- function hashOf5(row) {
267513
- let h8 = hashes4.get(row);
267514
- if (h8 === void 0) {
267515
- h8 = sha12(JSON.stringify(row));
267516
- hashes4.set(row, h8);
267517
- }
267518
- return h8;
267519
- }
267520
- async function load7() {
267521
- if (state13) return state13;
267522
- let s4 = { asOf: 0, at: 0, order: [], hashes: {} };
267523
- try {
267524
- const raw = JSON.parse(await fsp131.readFile(STATE_FILE3(), "utf8"));
267525
- if (raw?.v === 1 && raw.hashes && typeof raw.hashes === "object") s4 = { asOf: Number(raw.asOf) || 0, at: Number(raw.at) || 0, order: [], hashes: raw.hashes };
267526
- } catch {
267527
- }
267528
- state13 = s4;
267529
- return s4;
267530
- }
267531
- async function save2() {
267532
- if (state13) await writeCopyFile(STATE_FILE3(), { v: 1, asOf: state13.asOf, at: state13.at, hashes: state13.hashes });
267533
- }
267534
- async function readStore7() {
267535
- try {
267536
- const raw = JSON.parse(await fsp131.readFile(STORE_FILE(), "utf8"));
267537
- return Array.isArray(raw?.requests) ? raw.requests.filter(isRow5) : [];
267538
- } catch {
267539
- return [];
267540
- }
267541
- }
267542
- function isRow5(v3) {
267543
- const r8 = v3;
267544
- return !!r8 && typeof r8 === "object" && typeof r8.id === "string" && !!r8.id && typeof r8.fromSessionId === "string" && typeof r8.status === "string" && typeof r8.createdAt === "string";
267545
- }
267546
- function requestsFollower() {
267547
- follower4 ??= createRowSetFollower({
267548
- kind: "requests",
267549
- schemaVersion: REQUESTS_SCHEMA_VERSION,
267550
- label: "requests copy",
267551
- log: log.session,
267552
- removalFloor: REQUESTS_REMOVAL_FLOOR,
267553
- ordered: false,
267554
- serial: (fn) => serial7(fn),
267555
- refuse: copyRefusal,
267556
- load: load7,
267557
- save: save2,
267558
- isRow: isRow5,
267559
- key: (r8) => r8.id,
267560
- localKeys: async () => (await readStore7()).map((r8) => r8.id),
267561
- apply: async ({ rows, removeIds }) => {
267562
- const byId = new Map((await readStore7()).map((r8) => [r8.id, r8]));
267563
- for (const id of removeIds ?? []) byId.delete(id);
267564
- for (const r8 of rows ?? []) {
267565
- const kept = forwardRequest(byId.get(r8.id), r8);
267566
- if (kept !== r8) log.session.info("requests copy: kept a settled request the leader has not settled yet", { requestId: r8.id, local: kept.status, leader: r8.status });
267567
- byId.set(r8.id, kept);
267568
- }
267569
- await writeCopyFile(STORE_FILE(), { requests: [...byId.values()] });
267570
- return { skipped: [] };
267571
- },
267572
- held: async () => (await Promise.resolve().then(() => (init_journal_overlay(), journal_overlay_exports))).journalHeld("requests"),
267573
- changed: () => {
267574
- },
267575
- purge: async () => {
267576
- const removed = (await readStore7()).length;
267577
- await fsp131.rm(STORE_FILE(), { force: true });
267578
- await markCopyOff("requests");
267579
- state13 = null;
267580
- return { removed };
267581
- }
267582
- });
267583
- return follower4;
267584
- }
267585
- var REQUESTS_SCHEMA_VERSION, REQUESTS_REMOVAL_FLOOR, FINAL, hashes4, REQUESTS_KIND, STATE_FILE3, STORE_FILE, state13, serial7, follower4;
267586
- var init_requests = __esm({
267587
- "src/core/replication/kinds/requests.ts"() {
267588
- "use strict";
267589
- init_constants();
267590
- init_logging();
267591
- init_kind();
267592
- init_kind_follower();
267593
- init_gate();
267594
- REQUESTS_SCHEMA_VERSION = 1;
267595
- REQUESTS_REMOVAL_FLOOR = 50;
267596
- FINAL = /* @__PURE__ */ new Set(["replied", "notified", "expired"]);
267597
- hashes4 = /* @__PURE__ */ new WeakMap();
267598
- REQUESTS_KIND = {
267599
- kind: "requests",
267600
- schemaVersion: REQUESTS_SCHEMA_VERSION,
267601
- key: (r8) => r8.id,
267602
- hash: hashOf5,
267603
- ordered: false,
267604
- digest: false,
267605
- choice: "requests",
267606
- rows: async () => (await Promise.resolve().then(() => (init_session_requests(), session_requests_exports))).listAllSessionRequests(),
267607
- watch: (soon) => {
267608
- let stop2 = null;
267609
- let stopped2 = false;
267610
- void Promise.resolve().then(() => (init_session_requests(), session_requests_exports)).then(({ onSessionRequestsWritten: onSessionRequestsWritten2 }) => {
267611
- if (!stopped2) stop2 = onSessionRequestsWritten2(soon);
267612
- });
267613
- return () => {
267614
- stopped2 = true;
267615
- stop2?.();
267616
- };
267617
- }
267618
- };
267619
- STATE_FILE3 = () => path245.join(WALNUT_HOME, "cache", "replica", "requests.json");
267620
- STORE_FILE = () => path245.join(WALNUT_HOME, "session-requests.json");
267621
- state13 = null;
267622
- serial7 = serialChain();
267623
- follower4 = null;
267624
- }
267625
- });
267626
-
267627
267842
  // src/core/replication/kinds/sessions.ts
267628
267843
  import fsp132 from "fs/promises";
267629
267844
  import path246 from "path";
@@ -267654,11 +267869,11 @@ function projectedOf(row) {
267654
267869
  }
267655
267870
  return p6;
267656
267871
  }
267657
- function hashOf6(row) {
267658
- let h8 = hashes5.get(row);
267872
+ function hashOf7(row) {
267873
+ let h8 = hashes6.get(row);
267659
267874
  if (h8 === void 0) {
267660
267875
  h8 = sessionCopyHash(row);
267661
- hashes5.set(row, h8);
267876
+ hashes6.set(row, h8);
267662
267877
  }
267663
267878
  return h8;
267664
267879
  }
@@ -267678,7 +267893,7 @@ async function load8() {
267678
267893
  async function save3() {
267679
267894
  if (state14) await writeCopyFile(STATE_FILE4(), { v: 1, asOf: state14.asOf, at: state14.at, hashes: state14.hashes });
267680
267895
  }
267681
- function isRow6(v3) {
267896
+ function isRow7(v3) {
267682
267897
  const r8 = v3;
267683
267898
  return !!r8 && typeof r8 === "object" && !Array.isArray(r8) && typeof r8.claudeSessionId === "string" && r8.claudeSessionId.length > 0 && r8.claudeSessionId.length <= 200;
267684
267899
  }
@@ -267698,7 +267913,7 @@ function sessionsFollower() {
267698
267913
  refuse: copyRefusal,
267699
267914
  load: load8,
267700
267915
  save: save3,
267701
- isRow: isRow6,
267916
+ isRow: isRow7,
267702
267917
  key: (r8) => r8.claudeSessionId,
267703
267918
  hash: sessionCopyHash,
267704
267919
  localKeys: async () => (await Promise.resolve().then(() => (init_session_db(), session_db_exports))).sessionIdsInStore(),
@@ -267720,7 +267935,7 @@ function sessionsFollower() {
267720
267935
  });
267721
267936
  return follower5;
267722
267937
  }
267723
- var SESSIONS_SCHEMA_VERSION, SESSIONS_REMOVAL_FLOOR, PROCESS_FIELDS, PROCESS_SET, VOLATILE_SESSION_FIELDS, VOLATILE_SET, projected, hashes5, SESSIONS_KIND, STATE_FILE4, state14, serial8, follower5;
267938
+ var SESSIONS_SCHEMA_VERSION, SESSIONS_REMOVAL_FLOOR, PROCESS_FIELDS, PROCESS_SET, VOLATILE_SESSION_FIELDS, VOLATILE_SET, projected, hashes6, SESSIONS_KIND, STATE_FILE4, state14, serial8, follower5;
267724
267939
  var init_sessions3 = __esm({
267725
267940
  "src/core/replication/kinds/sessions.ts"() {
267726
267941
  "use strict";
@@ -267757,12 +267972,12 @@ var init_sessions3 = __esm({
267757
267972
  VOLATILE_SESSION_FIELDS = ["lastActiveAt", "activity", "contextTokens"];
267758
267973
  VOLATILE_SET = new Set(VOLATILE_SESSION_FIELDS);
267759
267974
  projected = /* @__PURE__ */ new WeakMap();
267760
- hashes5 = /* @__PURE__ */ new WeakMap();
267975
+ hashes6 = /* @__PURE__ */ new WeakMap();
267761
267976
  SESSIONS_KIND = {
267762
267977
  kind: "sessions",
267763
267978
  schemaVersion: SESSIONS_SCHEMA_VERSION,
267764
267979
  key: (s4) => s4.claudeSessionId,
267765
- hash: hashOf6,
267980
+ hash: hashOf7,
267766
267981
  ordered: false,
267767
267982
  digest: true,
267768
267983
  choice: "sessions",
@@ -267794,137 +268009,11 @@ var init_sessions3 = __esm({
267794
268009
  }
267795
268010
  });
267796
268011
 
267797
- // src/core/replication/kinds/personas.ts
267798
- var personas_exports = {};
267799
- __export(personas_exports, {
267800
- PERSONAS_KIND: () => PERSONAS_KIND,
267801
- PERSONAS_REMOVAL_FLOOR: () => PERSONAS_REMOVAL_FLOOR,
267802
- PERSONAS_SCHEMA_VERSION: () => PERSONAS_SCHEMA_VERSION,
267803
- _resetPersonasCopyForTesting: () => _resetPersonasCopyForTesting,
267804
- personasFollower: () => personasFollower,
267805
- readPersonaCopy: () => readPersonaCopy
267806
- });
267807
- function tools(v3) {
267808
- return Array.isArray(v3) && v3.length > 0 && v3.every((t3) => typeof t3 === "string" && TOOL_RE.test(t3)) ? [...v3] : void 0;
267809
- }
267810
- async function leaderRows2() {
267811
- const [{ getConsoleAgents: getConsoleAgents2 }, { buildLaneProfile: buildLaneProfile2 }, { getConfig: getConfig2 }, { getAskWalnutLaunchPrefs: getAskWalnutLaunchPrefs2 }] = await Promise.all([
267812
- Promise.resolve().then(() => (init_agent_registry(), agent_registry_exports)),
267813
- Promise.resolve().then(() => (init_personal_ai_lane(), personal_ai_lane_exports)),
267814
- Promise.resolve().then(() => (init_config_manager(), config_manager_exports)),
267815
- Promise.resolve().then(() => (init_ask_walnut_launch(), ask_walnut_launch_exports))
267816
- ]);
267817
- const config = await getConfig2();
267818
- const launch = await getAskWalnutLaunchPrefs2().catch(() => ({}));
267819
- const agents = [{ id: "general", name: "Walnut" }, ...(await getConsoleAgents2()).filter((a8) => a8.id !== "general").map((a8) => ({ id: a8.id, name: a8.name }))];
267820
- const rows = [];
267821
- for (const a8 of agents) {
267822
- if (!ID_RE5.test(a8.id)) continue;
267823
- try {
267824
- const { profile, effort } = await buildLaneProfile2(config, a8.id);
267825
- const prompt = profile.systemPrompt ?? "";
267826
- if (!prompt || Buffer.byteLength(prompt, "utf8") > MAX_PROMPT_BYTES) continue;
267827
- rows.push({
267828
- key: a8.id,
267829
- agentId: a8.id,
267830
- name: String(a8.name ?? a8.id).slice(0, 120),
267831
- systemPrompt: prompt,
267832
- systemPromptMode: profile.systemPromptMode === "replace" ? "replace" : "append",
267833
- ...tools(profile.allowedTools) ? { allowedTools: tools(profile.allowedTools) } : {},
267834
- ...tools(profile.tools) ? { tools: tools(profile.tools) } : {},
267835
- ...effort ? { effort } : {},
267836
- ...launch.model ? { launchModel: launch.model } : {},
267837
- ...launch.effort ? { launchEffort: launch.effort } : {}
267838
- });
267839
- } catch (err2) {
267840
- log.session.warn("copies: an agent persona was not rendered for the host", { agentId: a8.id, error: err2 instanceof Error ? err2.message : String(err2) });
267841
- }
267842
- }
267843
- return rows;
267844
- }
267845
- function hashOf7(row) {
267846
- let h8 = hashes6.get(row);
267847
- if (h8 === void 0) {
267848
- h8 = sha12(JSON.stringify(row));
267849
- hashes6.set(row, h8);
267850
- }
267851
- return h8;
267852
- }
267853
- function isRow7(v3) {
267854
- const r8 = v3;
267855
- if (!r8 || typeof r8 !== "object" || Array.isArray(r8)) return false;
267856
- if (Object.keys(r8).some((k8) => !ROW_KEYS.has(k8))) return false;
267857
- if (typeof r8.key !== "string" || r8.key !== r8.agentId || !ID_RE5.test(r8.key) || typeof r8.name !== "string") return false;
267858
- if (typeof r8.systemPrompt !== "string" || !r8.systemPrompt || Buffer.byteLength(r8.systemPrompt, "utf8") > MAX_PROMPT_BYTES) return false;
267859
- if (r8.systemPromptMode !== "append" && r8.systemPromptMode !== "replace") return false;
267860
- for (const k8 of ["allowedTools", "tools"]) if (r8[k8] !== void 0 && !tools(r8[k8])) return false;
267861
- for (const k8 of ["effort", "launchModel", "launchEffort"]) if (r8[k8] !== void 0 && (typeof r8[k8] !== "string" || !/^[A-Za-z0-9._:[\]/-]{1,128}$/.test(r8[k8]))) return false;
267862
- return true;
267863
- }
267864
- function admit2(r8) {
267865
- return secretShapedValue(r8.systemPrompt) === null && secretShapedValue(r8.name) === null;
267866
- }
267867
- async function readPersonaCopy(agentId) {
267868
- const rows = await copy3.read();
267869
- return rows?.[agentId] ?? null;
267870
- }
267871
- function _resetPersonasCopyForTesting() {
267872
- copy3.reset();
267873
- }
267874
- var PERSONAS_SCHEMA_VERSION, PERSONAS_REMOVAL_FLOOR, MAX_PROMPT_BYTES, ID_RE5, TOOL_RE, hashes6, PERSONAS_KIND, ROW_KEYS, copy3, personasFollower;
267875
- var init_personas = __esm({
267876
- "src/core/replication/kinds/personas.ts"() {
267877
- "use strict";
267878
- init_logging();
267879
- init_config_allowlist();
267880
- init_kind();
267881
- init_file_copy();
267882
- PERSONAS_SCHEMA_VERSION = 1;
267883
- PERSONAS_REMOVAL_FLOOR = 0;
267884
- MAX_PROMPT_BYTES = 120 * 1024;
267885
- ID_RE5 = /^[A-Za-z0-9_-]{1,80}$/;
267886
- TOOL_RE = /^[A-Za-z0-9_.:*()/ -]{1,200}$/;
267887
- hashes6 = /* @__PURE__ */ new WeakMap();
267888
- PERSONAS_KIND = {
267889
- kind: "personas",
267890
- schemaVersion: PERSONAS_SCHEMA_VERSION,
267891
- key: (r8) => r8.key,
267892
- hash: hashOf7,
267893
- ordered: false,
267894
- digest: false,
267895
- choice: "personas",
267896
- rows: leaderRows2,
267897
- watch: (soon) => {
267898
- let stop2 = null;
267899
- let stopped2 = false;
267900
- void Promise.resolve().then(() => (init_config_manager(), config_manager_exports)).then((cm) => {
267901
- if (!stopped2) stop2 = cm.onConfigWritten(soon);
267902
- });
267903
- return () => {
267904
- stopped2 = true;
267905
- stop2?.();
267906
- };
267907
- }
267908
- };
267909
- ROW_KEYS = /* @__PURE__ */ new Set(["key", "agentId", "name", "systemPrompt", "systemPromptMode", "allowedTools", "tools", "effort", "launchModel", "launchEffort"]);
267910
- copy3 = createFileCopy({
267911
- kind: "personas",
267912
- schemaVersion: PERSONAS_SCHEMA_VERSION,
267913
- label: "personas copy",
267914
- removalFloor: PERSONAS_REMOVAL_FLOOR,
267915
- isRow: isRow7,
267916
- key: (r8) => r8.key,
267917
- admit: admit2
267918
- });
267919
- personasFollower = copy3.follower;
267920
- }
267921
- });
267922
-
267923
268012
  // src/core/replication/kinds/index.ts
267924
268013
  var kinds_exports = {};
267925
268014
  __export(kinds_exports, {
268015
+ copyKeepersOnly: () => copyKeepersOnly,
267926
268016
  copyKinds: () => copyKinds,
267927
- hostReplicaOnly: () => hostReplicaOnly,
267928
268017
  registerCopyFollowerKinds: () => registerCopyFollowerKinds,
267929
268018
  startCopyKinds: () => startCopyKinds
267930
268019
  });
@@ -267942,14 +268031,14 @@ function copyKinds() {
267942
268031
  PERSONAS_KIND
267943
268032
  ];
267944
268033
  }
267945
- function hostReplicaOnly(h8) {
268034
+ function copyKeepersOnly(h8) {
267946
268035
  return {
267947
268036
  kind: h8.kind,
267948
- // followerStep checks the version before the step: never `schema_newer` off a host replica.
268037
+ // followerStep checks the version before the step: never `schema_newer` where the kind is not kept.
267949
268038
  get schemaVersion() {
267950
- return keepsCopies() ? h8.schemaVersion : Number.MAX_SAFE_INTEGER;
268039
+ return keepsCopies(h8.kind) ? h8.schemaVersion : Number.MAX_SAFE_INTEGER;
267951
268040
  },
267952
- step: (op2, body7) => keepsCopies() ? h8.step(op2, body7) : { ok: false, status: 404, error: "unknown_kind" }
268041
+ step: (op2, body7) => keepsCopies(h8.kind) ? h8.step(op2, body7) : { ok: false, status: 404, error: "unknown_kind" }
267953
268042
  };
267954
268043
  }
267955
268044
  function registerCopyFollowerKinds() {
@@ -267964,7 +268053,7 @@ function registerCopyFollowerKinds() {
267964
268053
  prefsFollower(),
267965
268054
  configFollower(),
267966
268055
  personasFollower()
267967
- ].map((h8) => registerFollowerKind(hostReplicaOnly(h8)));
268056
+ ].map((h8) => registerFollowerKind(copyKeepersOnly(h8)));
267968
268057
  return () => {
267969
268058
  for (const u3 of off) u3();
267970
268059
  };
@@ -313047,9 +313136,13 @@ var init_task_replica_store = __esm({
313047
313136
  // src/core/replication/kinds/gate.ts
313048
313137
  var gate_exports = {};
313049
313138
  __export(gate_exports, {
313139
+ COMPANION_COPY_KINDS: () => COMPANION_COPY_KINDS,
313140
+ COPY_AS_OF_HEADER: () => COPY_AS_OF_HEADER,
313050
313141
  KIND_NOT_COPIED: () => KIND_NOT_COPIED,
313142
+ copyKindAsOf: () => copyKindAsOf,
313051
313143
  copyKindHeld: () => copyKindHeld,
313052
313144
  copyKindOff: () => copyKindOff,
313145
+ copyPath: () => copyPath,
313053
313146
  copyRefusal: () => copyRefusal,
313054
313147
  copyStateFile: () => copyStateFile,
313055
313148
  keepsCopies: () => keepsCopies,
@@ -313057,8 +313150,16 @@ __export(gate_exports, {
313057
313150
  });
313058
313151
  import fsp149 from "fs/promises";
313059
313152
  import path293 from "path";
313060
- function keepsCopies() {
313061
- return isHostReplicaProgram();
313153
+ function keepsCopies(kind) {
313154
+ if (isHostReplicaProgram()) return true;
313155
+ if (followerKind() !== "companion") return false;
313156
+ return kind === void 0 || COMPANION_COPY_KINDS.has(kind);
313157
+ }
313158
+ function copyPath(live6) {
313159
+ if (followerKind() !== "companion") return live6;
313160
+ const rel = path293.relative(WALNUT_HOME, live6);
313161
+ if (!rel || rel.startsWith("..") || path293.isAbsolute(rel)) throw new Error(`copyPath: ${live6} is not under the data dir`);
313162
+ return path293.join(WALNUT_HOME, "cache", "replica", "home", rel);
313062
313163
  }
313063
313164
  async function copyRefusal() {
313064
313165
  if (!keepsCopies()) return { status: 404, error: "unknown_kind" };
@@ -313079,20 +313180,26 @@ async function copyKindOff(kind) {
313079
313180
  }
313080
313181
  }
313081
313182
  async function copyKindHeld(kind) {
313183
+ return await copyKindAsOf(kind) !== null;
313184
+ }
313185
+ async function copyKindAsOf(kind) {
313082
313186
  try {
313083
313187
  const raw = JSON.parse(await fsp149.readFile(copyStateFile(kind), "utf8"));
313084
- return raw?.v === 1 && raw.off !== true && !!raw.hashes && typeof raw.hashes === "object";
313188
+ if (!(raw?.v === 1 && raw.off !== true && !!raw.hashes && typeof raw.hashes === "object")) return null;
313189
+ return Number(raw.asOf) || 0;
313085
313190
  } catch {
313086
- return false;
313191
+ return null;
313087
313192
  }
313088
313193
  }
313089
- var KIND_NOT_COPIED;
313194
+ var COMPANION_COPY_KINDS, COPY_AS_OF_HEADER, KIND_NOT_COPIED;
313090
313195
  var init_gate = __esm({
313091
313196
  "src/core/replication/kinds/gate.ts"() {
313092
313197
  "use strict";
313093
313198
  init_constants();
313094
313199
  init_server_role();
313095
313200
  init_kind_follower();
313201
+ COMPANION_COPY_KINDS = /* @__PURE__ */ new Set(["requests", "routines", "prefs", "personas"]);
313202
+ COPY_AS_OF_HEADER = "x-walnut-copy-as-of";
313096
313203
  KIND_NOT_COPIED = "kind_not_copied";
313097
313204
  }
313098
313205
  });