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.
@@ -6988,6 +6988,7 @@ function createOfflineHostCore(deps4) {
6988
6988
  const MAX_ARGS_BYTES = 256 * 1024;
6989
6989
  const WRITE_BUDGET = 30;
6990
6990
  const WRITE_WINDOW_MS = 6e4;
6991
+ const LOCK_RETRY_MS = [100, 300, 900];
6991
6992
  const DEFAULT_REPLY_SECS = 3600;
6992
6993
  const IMPLICIT_REPLY_SECS = 6 * 3600;
6993
6994
  const DRAIN_BATCH = 200;
@@ -7134,7 +7135,7 @@ function createOfflineHostCore(deps4) {
7134
7135
  ...opts2.admit ? { admit: opts2.admit } : {}
7135
7136
  });
7136
7137
  if (!r8.ok) {
7137
- if (r8.code === "journal_unwritable") deps4.log("error", "offline host: journal write refused", { home, kind, code: r8.code, why: r8.why, error: r8.message });
7138
+ 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 });
7138
7139
  return r8;
7139
7140
  }
7140
7141
  if (!r8.duplicate) {
@@ -7149,6 +7150,19 @@ function createOfflineHostCore(deps4) {
7149
7150
  if (r8.ok) return null;
7150
7151
  return fail6(r8.code, r8.message, { ...r8.retryAfterMs !== void 0 ? { retryAfterMs: r8.retryAfterMs } : {}, ...r8.why ? { detail: { why: r8.why } } : {} });
7151
7152
  }
7153
+ const lockRefused = (r8) => !r8.ok && r8.error.code === "journal_unwritable" && r8.error.detail?.why === "locked";
7154
+ async function whenUnlocked(home, op2, run13) {
7155
+ const t0 = Date.now();
7156
+ let r8 = run13();
7157
+ for (const ms2 of LOCK_RETRY_MS) {
7158
+ if (!lockRefused(r8)) return r8;
7159
+ 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 });
7160
+ await new Promise((resolve2) => setTimeout(resolve2, ms2));
7161
+ r8 = run13();
7162
+ }
7163
+ if (lockRefused(r8)) deps4.log("error", "offline host: the journal stayed locked; write refused", { home, op: op2, waitedMs: Date.now() - t0 });
7164
+ return r8;
7165
+ }
7152
7166
  function configure(slice) {
7153
7167
  if (!slice || slice.v !== 1 || typeof slice.home !== "string" || !slice.home) throw new Error("host.slice: bad slice");
7154
7168
  const prev = slices.get(slice.home);
@@ -7882,10 +7896,8 @@ ${kit10.buildReplyTrailer(row)}`;
7882
7896
  if (no) return no;
7883
7897
  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 });
7884
7898
  } else {
7885
- const denied = admitWrite(callerSid5) ?? roomFor(home);
7886
- if (denied) return denied;
7887
7899
  const base = slices.get(home)?.tasks.find((t3) => t3.id === task.id)?.updated_at;
7888
- const no = refusal2(append(home, { kind: "op", op: name, args: { ...args, id: task.id }, callerSid: callerSid5, ...base ? { base } : {} }));
7900
+ const no = refusal2(append(home, { kind: "op", op: name, args: { ...args, id: task.id }, callerSid: callerSid5, ...base ? { base } : {} }, false, { admit: () => admitWrite(callerSid5) ?? roomFor(home) }));
7889
7901
  if (no) return no;
7890
7902
  deps4.log("info", "offline host: write queued", { home, op: name, taskId: task.id, callerSid: callerSid5 });
7891
7903
  }
@@ -8327,7 +8339,7 @@ ${kit10.buildReplyTrailer(row)}`;
8327
8339
  const fromCopy = deps4.replica ? deps4.replica.answer(home, name, args, offlineNote(home)) : null;
8328
8340
  if (fromCopy) return fromCopy;
8329
8341
  if (deps4.boards && deps4.boards.BOARD_OPS.indexOf(name) !== -1) return opBoard(home, callerSid5, name, args);
8330
- if (QUEUED_OPS.includes(name)) return opQueued(home, callerSid5, name, args);
8342
+ if (QUEUED_OPS.includes(name)) return whenUnlocked(home, name, () => opQueued(home, callerSid5, name, args));
8331
8343
  return needsServer(name ? `"${name}"` : "That call");
8332
8344
  }
8333
8345
  }
@@ -8840,6 +8852,10 @@ ${mid}` : "";
8840
8852
  handle: handle4,
8841
8853
  handleLocal,
8842
8854
  handleFollower,
8855
+ /** handleFollower, waiting out another process's journal lock (whenUnlocked): the twins' follower.op. */
8856
+ handleFollowerWaiting: (home, req) => whenUnlocked(home, String(req.op ?? ""), () => handleFollower(home, req)),
8857
+ /** noteSession, waiting out another process's journal lock (whenUnlocked): the twins' host ask. */
8858
+ noteSessionWaiting: (home, rec3, opId, by) => whenUnlocked(home, "session", () => noteSession(home, rec3, opId, by)),
8843
8859
  pendingFor,
8844
8860
  journalStats,
8845
8861
  onResult,
@@ -23962,7 +23978,7 @@ function dispatchCommand(ws, id, cmd) {
23962
23978
  case 'follower.sessions': return cmdFollowerSessions(ws, id);
23963
23979
  case 'follower.send': return daemonCommands.run(function () { return cmdFollowerSend(ws, id, cmd); });
23964
23980
  case 'follower.permission': return daemonCommands.run(function () { return cmdFollowerPermission(ws, id, cmd); });
23965
- case 'follower.op': return cmdFollowerOp(ws, id, cmd);
23981
+ case 'follower.op': return daemonCommands.run(function () { return cmdFollowerOp(ws, id, cmd); });
23966
23982
  case 'follower.pending': return cmdFollowerPending(ws, id, cmd);
23967
23983
  // A new ask while the Mac is away ('replica-start-v1', WP12). Twin of daemon-standalone.ts.
23968
23984
  case 'follower.start': return daemonCommands.run(function () { return cmdFollowerStart(ws, id, cmd); });
@@ -25376,14 +25392,15 @@ async function cmdFollowerPermission(ws, id, cmd) {
25376
25392
  // The replica's write while the Mac is away (replica-ops-v1, journal v2). Its own gate:
25377
25393
  // the follower's own Walnut, the quiet window unless the Mac is still taking the
25378
25394
  // journal, and the daemon dir's owner. Twin of daemon-standalone.ts cmdFollowerOp.
25379
- function cmdFollowerOp(ws, id, cmd) {
25395
+ async function cmdFollowerOp(ws, id, cmd) {
25380
25396
  var home = followerHomeOf(ws);
25381
25397
  if (!home) return sendError(ws, id, 'follower.op: send follower.hello first');
25382
25398
  if (!followerMayWrite(home)) return sendError(ws, id, 'follower.op: your Mac answers again; write through it', { errorKind: 'leader_answers' });
25383
25399
  if (!ownsDaemonDir()) {
25384
25400
  return sendError(ws, id, 'follower.op: this daemon no longer owns its directory', { errorKind: 'journal_unwritable', detail: { why: 'not_owner' } });
25385
25401
  }
25386
- var r = offlineHost.handleFollower(home, { op: cmd.op, args: cmd.args, actor: cmd.actor, opId: cmd.opId, base: cmd.base });
25402
+ // Waits out another process's journal lock (about 1.3 s) before it answers.
25403
+ var r = await offlineHost.handleFollowerWaiting(home, { op: cmd.op, args: cmd.args, actor: cmd.actor, opId: cmd.opId, base: cmd.base });
25387
25404
  if (r.ok) return sendOk(ws, id, r.result);
25388
25405
  sendError(ws, id, 'follower.op: ' + r.error.message, Object.assign({ errorKind: r.error.code },
25389
25406
  r.error.detail !== undefined ? { detail: r.error.detail } : {}, r.error.retryAfterMs !== undefined ? { retryAfterMs: r.error.retryAfterMs } : {}));
@@ -25533,7 +25550,7 @@ async function startHostAsk(home, p, cmd) {
25533
25550
  throw err;
25534
25551
  }
25535
25552
  if (DIE_AFTER_ASK_SPAWN) process.kill(process.pid, 'SIGKILL');
25536
- var saved = offlineHost.noteSession(home, p.record, opId, cmd.actor);
25553
+ var saved = await offlineHost.noteSessionWaiting(home, p.record, opId, cmd.actor);
25537
25554
  hostStart.releasePending(home, p.sid);
25538
25555
  if (!saved.ok) {
25539
25556
  // Nothing would tell the Mac about this CLI: it must not run unseen. Not stamped as an
@@ -143397,8 +143414,9 @@ async function buildCopyManifest(kind) {
143397
143414
  }
143398
143415
  return manifest;
143399
143416
  }
143400
- function keepsCopiesTarget(t3) {
143401
- return t3.kind === "host" && t3.program?.() === "replica";
143417
+ function keepsCopiesTarget(t3, kind) {
143418
+ if (t3.kind === "host") return t3.program?.() === "replica";
143419
+ return t3.kind === "companion" && (kind === void 0 || COMPANION_COPY_KINDS.has(kind));
143402
143420
  }
143403
143421
  function manifestDigest(manifest, ordered = false) {
143404
143422
  let d8 = manifestDigests.get(manifest);
@@ -143512,7 +143530,7 @@ async function choiceOf(target2) {
143512
143530
  }
143513
143531
  async function syncCopyKinds(kinds, deps4 = {}) {
143514
143532
  const now = deps4.now ?? Date.now;
143515
- const all = (deps4.targets ?? await defaultTargets())().filter(keepsCopiesTarget);
143533
+ const all = (deps4.targets ?? await defaultTargets())().filter((t3) => kinds.some((k8) => keepsCopiesTarget(t3, k8.kind)));
143516
143534
  const ready2 = [];
143517
143535
  for (const target2 of all) if (await target2.available()) ready2.push({ target: target2, choice: await choiceOf(target2) });
143518
143536
  const results = [];
@@ -143520,7 +143538,7 @@ async function syncCopyKinds(kinds, deps4 = {}) {
143520
143538
  const asOf2 = now();
143521
143539
  const manifests = /* @__PURE__ */ new Map();
143522
143540
  for (const kind of kinds) {
143523
- if (!ready2.some((r8) => r8.choice[kind.choice])) continue;
143541
+ if (!ready2.some((r8) => r8.choice[kind.choice] && keepsCopiesTarget(r8.target, kind.kind))) continue;
143524
143542
  try {
143525
143543
  manifests.set(kind.kind, await buildCopyManifest(kind));
143526
143544
  } catch (err2) {
@@ -143529,6 +143547,7 @@ async function syncCopyKinds(kinds, deps4 = {}) {
143529
143547
  }
143530
143548
  for (const { target: target2, choice } of ready2) {
143531
143549
  for (const kind of kinds) {
143550
+ if (!keepsCopiesTarget(target2, kind.kind)) continue;
143532
143551
  const manifest = manifests.get(kind.kind);
143533
143552
  const st2 = kindState(target2, kind.kind);
143534
143553
  if (!choice[kind.choice]) {
@@ -143574,7 +143593,7 @@ async function purgeKind(kind, target2, st2) {
143574
143593
  async function confirmCopyKindRemoval(targetId, kind, opts2 = {}) {
143575
143594
  const { replicaTargets: replicaTargets2 } = await Promise.resolve().then(() => (init_replica_targets(), replica_targets_exports));
143576
143595
  const target2 = replicaTargets2().find((t3) => t3.id === targetId);
143577
- if (!target2 || target2.kind !== "host" || !peekKindState(targetId, kind)) return false;
143596
+ if (!target2 || !keepsCopiesTarget(target2, kind) || !peekKindState(targetId, kind)) return false;
143578
143597
  if (!confirmKindRemoval(target2, kind, opts2)) return false;
143579
143598
  log.session.warn("copies: the user confirmed a removal of most rows", { target: targetId, kind, entries: peekKindState(targetId, kind)?.confirmFor?.entries });
143580
143599
  copySoon(kind);
@@ -143689,6 +143708,7 @@ var init_copy_kind = __esm({
143689
143708
  init_kind_leader();
143690
143709
  init_search_digest();
143691
143710
  init_replica_status();
143711
+ init_gate();
143692
143712
  COPY_DEBOUNCE_MS = 3e3;
143693
143713
  COPY_SWEEP_MS = 5 * 6e4;
143694
143714
  COPY_FIRST_ROUND_MS = 15e3;
@@ -149382,6 +149402,7 @@ var init_routines = __esm({
149382
149402
  var routines_follower_exports = {};
149383
149403
  __export(routines_follower_exports, {
149384
149404
  _resetRoutinesCopyForTesting: () => _resetRoutinesCopyForTesting,
149405
+ companionRoutinesCopy: () => companionRoutinesCopy,
149385
149406
  readRoutinesCopy: () => readRoutinesCopy,
149386
149407
  routinesFollower: () => routinesFollower
149387
149408
  });
@@ -149477,6 +149498,10 @@ async function readRoutinesCopy(opts2 = {}) {
149477
149498
  const shown = opts2.includeDisabled ? all : all.filter((j8) => j8.enabled);
149478
149499
  return shown.sort((a8, b8) => (a8.state.nextRunAtMs ?? 0) - (b8.state.nextRunAtMs ?? 0));
149479
149500
  }
149501
+ async function companionRoutinesCopy(opts2 = {}) {
149502
+ if (!await copyKindHeld("routines")) return null;
149503
+ return await readRoutinesCopy(opts2) ?? [];
149504
+ }
149480
149505
  function _resetRoutinesCopyForTesting() {
149481
149506
  io2 = copyStateIo("routines");
149482
149507
  serial3 = serialChain();
@@ -149492,8 +149517,8 @@ var init_routines_follower = __esm({
149492
149517
  init_gate();
149493
149518
  init_state_io();
149494
149519
  init_routines();
149495
- jobsFile = () => CRON_FILE;
149496
- statesFile = () => path118.join(path118.dirname(CRON_FILE), "cron-state.json");
149520
+ jobsFile = () => copyPath(CRON_FILE);
149521
+ statesFile = () => copyPath(path118.join(path118.dirname(CRON_FILE), "cron-state.json"));
149497
149522
  io2 = copyStateIo("routines");
149498
149523
  serial3 = serialChain();
149499
149524
  follower2 = null;
@@ -166069,8 +166094,8 @@ import path136 from "path";
166069
166094
  import { fileURLToPath as fileURLToPath9 } from "url";
166070
166095
  function getVersion() {
166071
166096
  if (cachedVersion) return cachedVersion;
166072
- if ("0.6.16") {
166073
- cachedVersion = "0.6.16";
166097
+ if ("0.6.17") {
166098
+ cachedVersion = "0.6.17";
166074
166099
  versionKnown = true;
166075
166100
  return cachedVersion;
166076
166101
  }
@@ -190275,6 +190300,132 @@ var init_agent_turn_queue = __esm({
190275
190300
  }
190276
190301
  });
190277
190302
 
190303
+ // src/core/replication/kinds/personas.ts
190304
+ var personas_exports = {};
190305
+ __export(personas_exports, {
190306
+ PERSONAS_KIND: () => PERSONAS_KIND,
190307
+ PERSONAS_REMOVAL_FLOOR: () => PERSONAS_REMOVAL_FLOOR,
190308
+ PERSONAS_SCHEMA_VERSION: () => PERSONAS_SCHEMA_VERSION,
190309
+ _resetPersonasCopyForTesting: () => _resetPersonasCopyForTesting,
190310
+ personasFollower: () => personasFollower,
190311
+ readPersonaCopy: () => readPersonaCopy
190312
+ });
190313
+ function tools(v3) {
190314
+ return Array.isArray(v3) && v3.length > 0 && v3.every((t3) => typeof t3 === "string" && TOOL_RE.test(t3)) ? [...v3] : void 0;
190315
+ }
190316
+ async function leaderRows() {
190317
+ const [{ getConsoleAgents: getConsoleAgents2 }, { buildLaneProfile: buildLaneProfile2 }, { getConfig: getConfig2 }, { getAskWalnutLaunchPrefs: getAskWalnutLaunchPrefs2 }] = await Promise.all([
190318
+ Promise.resolve().then(() => (init_agent_registry(), agent_registry_exports)),
190319
+ Promise.resolve().then(() => (init_personal_ai_lane(), personal_ai_lane_exports)),
190320
+ Promise.resolve().then(() => (init_config_manager(), config_manager_exports)),
190321
+ Promise.resolve().then(() => (init_ask_walnut_launch(), ask_walnut_launch_exports))
190322
+ ]);
190323
+ const config = await getConfig2();
190324
+ const launch = await getAskWalnutLaunchPrefs2().catch(() => ({}));
190325
+ const agents = [{ id: "general", name: "Walnut" }, ...(await getConsoleAgents2()).filter((a8) => a8.id !== "general").map((a8) => ({ id: a8.id, name: a8.name }))];
190326
+ const rows = [];
190327
+ for (const a8 of agents) {
190328
+ if (!ID_RE2.test(a8.id)) continue;
190329
+ try {
190330
+ const { profile, effort } = await buildLaneProfile2(config, a8.id);
190331
+ const prompt = profile.systemPrompt ?? "";
190332
+ if (!prompt || Buffer.byteLength(prompt, "utf8") > MAX_PROMPT_BYTES) continue;
190333
+ rows.push({
190334
+ key: a8.id,
190335
+ agentId: a8.id,
190336
+ name: String(a8.name ?? a8.id).slice(0, 120),
190337
+ systemPrompt: prompt,
190338
+ systemPromptMode: profile.systemPromptMode === "replace" ? "replace" : "append",
190339
+ ...tools(profile.allowedTools) ? { allowedTools: tools(profile.allowedTools) } : {},
190340
+ ...tools(profile.tools) ? { tools: tools(profile.tools) } : {},
190341
+ ...effort ? { effort } : {},
190342
+ ...launch.model ? { launchModel: launch.model } : {},
190343
+ ...launch.effort ? { launchEffort: launch.effort } : {}
190344
+ });
190345
+ } catch (err2) {
190346
+ log.session.warn("copies: an agent persona was not rendered for the host", { agentId: a8.id, error: err2 instanceof Error ? err2.message : String(err2) });
190347
+ }
190348
+ }
190349
+ return rows;
190350
+ }
190351
+ function hashOf4(row) {
190352
+ let h8 = hashes3.get(row);
190353
+ if (h8 === void 0) {
190354
+ h8 = sha12(JSON.stringify(row));
190355
+ hashes3.set(row, h8);
190356
+ }
190357
+ return h8;
190358
+ }
190359
+ function isRow3(v3) {
190360
+ const r8 = v3;
190361
+ if (!r8 || typeof r8 !== "object" || Array.isArray(r8)) return false;
190362
+ if (Object.keys(r8).some((k8) => !ROW_KEYS.has(k8))) return false;
190363
+ if (typeof r8.key !== "string" || r8.key !== r8.agentId || !ID_RE2.test(r8.key) || typeof r8.name !== "string") return false;
190364
+ if (typeof r8.systemPrompt !== "string" || !r8.systemPrompt || Buffer.byteLength(r8.systemPrompt, "utf8") > MAX_PROMPT_BYTES) return false;
190365
+ if (r8.systemPromptMode !== "append" && r8.systemPromptMode !== "replace") return false;
190366
+ for (const k8 of ["allowedTools", "tools"]) if (r8[k8] !== void 0 && !tools(r8[k8])) return false;
190367
+ 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;
190368
+ return true;
190369
+ }
190370
+ function admit(r8) {
190371
+ return secretShapedValue(r8.systemPrompt) === null && secretShapedValue(r8.name) === null;
190372
+ }
190373
+ async function readPersonaCopy(agentId) {
190374
+ const rows = await copy2.read();
190375
+ return rows?.[agentId] ?? null;
190376
+ }
190377
+ function _resetPersonasCopyForTesting() {
190378
+ copy2.reset();
190379
+ }
190380
+ var PERSONAS_SCHEMA_VERSION, PERSONAS_REMOVAL_FLOOR, MAX_PROMPT_BYTES, ID_RE2, TOOL_RE, hashes3, PERSONAS_KIND, ROW_KEYS, copy2, personasFollower;
190381
+ var init_personas = __esm({
190382
+ "src/core/replication/kinds/personas.ts"() {
190383
+ "use strict";
190384
+ init_logging();
190385
+ init_config_allowlist();
190386
+ init_kind();
190387
+ init_file_copy();
190388
+ PERSONAS_SCHEMA_VERSION = 1;
190389
+ PERSONAS_REMOVAL_FLOOR = 0;
190390
+ MAX_PROMPT_BYTES = 120 * 1024;
190391
+ ID_RE2 = /^[A-Za-z0-9_-]{1,80}$/;
190392
+ TOOL_RE = /^[A-Za-z0-9_.:*()/ -]{1,200}$/;
190393
+ hashes3 = /* @__PURE__ */ new WeakMap();
190394
+ PERSONAS_KIND = {
190395
+ kind: "personas",
190396
+ schemaVersion: PERSONAS_SCHEMA_VERSION,
190397
+ key: (r8) => r8.key,
190398
+ hash: hashOf4,
190399
+ ordered: false,
190400
+ digest: false,
190401
+ choice: "personas",
190402
+ rows: leaderRows,
190403
+ watch: (soon) => {
190404
+ let stop2 = null;
190405
+ let stopped2 = false;
190406
+ void Promise.resolve().then(() => (init_config_manager(), config_manager_exports)).then((cm) => {
190407
+ if (!stopped2) stop2 = cm.onConfigWritten(soon);
190408
+ });
190409
+ return () => {
190410
+ stopped2 = true;
190411
+ stop2?.();
190412
+ };
190413
+ }
190414
+ };
190415
+ ROW_KEYS = /* @__PURE__ */ new Set(["key", "agentId", "name", "systemPrompt", "systemPromptMode", "allowedTools", "tools", "effort", "launchModel", "launchEffort"]);
190416
+ copy2 = createFileCopy({
190417
+ kind: "personas",
190418
+ schemaVersion: PERSONAS_SCHEMA_VERSION,
190419
+ label: "personas copy",
190420
+ removalFloor: PERSONAS_REMOVAL_FLOOR,
190421
+ isRow: isRow3,
190422
+ key: (r8) => r8.key,
190423
+ admit
190424
+ });
190425
+ personasFollower = copy2.follower;
190426
+ }
190427
+ });
190428
+
190278
190429
  // src/core/sessions/cloud-chat-lane.ts
190279
190430
  var cloud_chat_lane_exports = {};
190280
190431
  __export(cloud_chat_lane_exports, {
@@ -190413,7 +190564,9 @@ async function resolveCloudChatLane(lane, agentId, conversationId, cwd, firstMes
190413
190564
  CATCH_UP_BANNER_CLOSE: CATCH_UP_BANNER_CLOSE2,
190414
190565
  buildConversationSeed: buildConversationSeed2
190415
190566
  } = await Promise.resolve().then(() => (init_chat_history(), chat_history_exports));
190416
- const { profile: base, effort, seed } = await buildLaneProfile2(config, agentId, { conversationId });
190567
+ const { readPersonaCopy: readPersonaCopy2 } = await Promise.resolve().then(() => (init_personas(), personas_exports));
190568
+ const persona = await readPersonaCopy2(agentId).catch(() => null);
190569
+ const { profile: base, effort, seed } = await buildLaneProfile2(config, agentId, { conversationId, ...persona ? { persona } : {} });
190417
190570
  const profile = toCloudChatProfile(base, CONVERSATION_SEED_HEADER2);
190418
190571
  const sessionId = crypto49.randomUUID();
190419
190572
  const seedInProfile = !!seed && (seed.text !== "" || seed.stats.turnsTotal === 0);
@@ -197382,9 +197535,9 @@ function sanitizeHealthSync(body7, now = Date.now()) {
197382
197535
  const tz = isValidTz(b8.tz) ? b8.tz : "";
197383
197536
  const spec = metricSpec(type);
197384
197537
  const generic = isGenericType(type);
197385
- const storeId = typeof b8.storeId === "string" && ID_RE2.test(b8.storeId) ? b8.storeId : void 0;
197538
+ const storeId = typeof b8.storeId === "string" && ID_RE3.test(b8.storeId) ? b8.storeId : void 0;
197386
197539
  const dev = b8.device && typeof b8.device === "object" ? b8.device : {};
197387
- const installId = typeof dev.installId === "string" && ID_RE2.test(dev.installId) ? dev.installId : void 0;
197540
+ const installId = typeof dev.installId === "string" && ID_RE3.test(dev.installId) ? dev.installId : void 0;
197388
197541
  const device = { installId, model: str11(dev.model, 64), os: str11(dev.os, 64) };
197389
197542
  const hasDevice = Object.values(device).some((v3) => v3 !== void 0);
197390
197543
  const deleted = [...new Set(deletedIn.filter((u3) => typeof u3 === "string" && UUID_RE3.test(u3)))];
@@ -197452,14 +197605,14 @@ function relayPayload(batch) {
197452
197605
  samples: batch.samples.map(({ tz, ...rest }) => tz === batch.tz ? rest : { ...rest, tz })
197453
197606
  };
197454
197607
  }
197455
- var UUID_RE3, ID_RE2, MIN_INSTANT, FUTURE_SLACK_MS2, MAX_SPAN_MS;
197608
+ var UUID_RE3, ID_RE3, MIN_INSTANT, FUTURE_SLACK_MS2, MAX_SPAN_MS;
197456
197609
  var init_sanitize = __esm({
197457
197610
  "src/core/health/sanitize.ts"() {
197458
197611
  "use strict";
197459
197612
  init_catalog();
197460
197613
  init_day_key();
197461
197614
  UUID_RE3 = /^[A-Za-z0-9][A-Za-z0-9-]{0,63}$/;
197462
- ID_RE2 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/;
197615
+ ID_RE3 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/;
197463
197616
  MIN_INSTANT = Date.UTC(2010, 0, 1);
197464
197617
  FUTURE_SLACK_MS2 = 36 * 36e5;
197465
197618
  MAX_SPAN_MS = 2 * 864e5;
@@ -215063,7 +215216,7 @@ function prefAdmissible(p6) {
215063
215216
  function strings(v3) {
215064
215217
  return Array.isArray(v3) ? v3.filter((x3) => typeof x3 === "string") : [];
215065
215218
  }
215066
- async function leaderRows() {
215219
+ async function leaderRows2() {
215067
215220
  const raw = await readJsonFile(UI_PREFS_FILE, {}, { readErrors: "throw" });
215068
215221
  const rows = [];
215069
215222
  for (const [k8, v3] of Object.entries(raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {})) {
@@ -215075,15 +215228,15 @@ async function leaderRows() {
215075
215228
  rows.push({ key: "favorites", favorites: { projects: strings(fav?.projects), notes: strings(fav?.notes) } });
215076
215229
  return rows;
215077
215230
  }
215078
- function hashOf4(row) {
215079
- let h8 = hashes3.get(row);
215231
+ function hashOf5(row) {
215232
+ let h8 = hashes4.get(row);
215080
215233
  if (h8 === void 0) {
215081
215234
  h8 = sha12(JSON.stringify(row));
215082
- hashes3.set(row, h8);
215235
+ hashes4.set(row, h8);
215083
215236
  }
215084
215237
  return h8;
215085
215238
  }
215086
- function isRow3(v3) {
215239
+ function isRow4(v3) {
215087
215240
  const r8 = v3;
215088
215241
  if (!r8 || typeof r8 !== "object" || typeof r8.key !== "string") return false;
215089
215242
  if (r8.key === "favorites") {
@@ -215093,27 +215246,27 @@ function isRow3(v3) {
215093
215246
  const p6 = prefOf(r8.pref);
215094
215247
  return Object.keys(r8).length === 2 && r8.key.startsWith(UI) && copyableUiPrefKey(r8.key.slice(UI.length)) && !!p6 && typeof r8.pref === "object";
215095
215248
  }
215096
- function admit(r8) {
215249
+ function admit2(r8) {
215097
215250
  if ("favorites" in r8) return [...r8.favorites.projects, ...r8.favorites.notes].every((s4) => typeof s4 === "string" && secretShapedValue(s4) === null);
215098
215251
  return prefAdmissible(r8.pref);
215099
215252
  }
215100
215253
  async function readUiPrefsCopy() {
215101
- const rows = await copy2.read();
215254
+ const rows = await copy3.read();
215102
215255
  if (!rows) return null;
215103
215256
  const out = {};
215104
215257
  for (const r8 of Object.values(rows)) if ("pref" in r8) out[r8.key.slice(UI.length)] = r8.pref;
215105
215258
  return out;
215106
215259
  }
215107
215260
  async function readFavoritesCopy() {
215108
- const rows = await copy2.read();
215261
+ const rows = await copy3.read();
215109
215262
  if (!rows) return null;
215110
215263
  const f8 = rows.favorites;
215111
215264
  return f8 && "favorites" in f8 ? f8.favorites : { projects: [], notes: [] };
215112
215265
  }
215113
215266
  function _resetPrefsCopyForTesting() {
215114
- copy2.reset();
215267
+ copy3.reset();
215115
215268
  }
215116
- var PREFS_SCHEMA_VERSION, PREFS_REMOVAL_FLOOR, UI, MAX_VALUE_LEN2, hashes3, PREFS_KIND, copy2, prefsFollower;
215269
+ var PREFS_SCHEMA_VERSION, PREFS_REMOVAL_FLOOR, UI, MAX_VALUE_LEN2, hashes4, PREFS_KIND, copy3, prefsFollower;
215117
215270
  var init_prefs = __esm({
215118
215271
  "src/core/replication/kinds/prefs.ts"() {
215119
215272
  "use strict";
@@ -215127,16 +215280,16 @@ var init_prefs = __esm({
215127
215280
  PREFS_REMOVAL_FLOOR = 0;
215128
215281
  UI = "ui:";
215129
215282
  MAX_VALUE_LEN2 = 8 * 1024;
215130
- hashes3 = /* @__PURE__ */ new WeakMap();
215283
+ hashes4 = /* @__PURE__ */ new WeakMap();
215131
215284
  PREFS_KIND = {
215132
215285
  kind: "prefs",
215133
215286
  schemaVersion: PREFS_SCHEMA_VERSION,
215134
215287
  key: (r8) => r8.key,
215135
- hash: hashOf4,
215288
+ hash: hashOf5,
215136
215289
  ordered: false,
215137
215290
  digest: false,
215138
215291
  choice: "prefs",
215139
- rows: leaderRows,
215292
+ rows: leaderRows2,
215140
215293
  watch: (soon) => {
215141
215294
  const stops = [];
215142
215295
  let stopped2 = false;
@@ -215149,16 +215302,16 @@ var init_prefs = __esm({
215149
215302
  };
215150
215303
  }
215151
215304
  };
215152
- copy2 = createFileCopy({
215305
+ copy3 = createFileCopy({
215153
215306
  kind: "prefs",
215154
215307
  schemaVersion: PREFS_SCHEMA_VERSION,
215155
215308
  label: "prefs copy",
215156
215309
  removalFloor: PREFS_REMOVAL_FLOOR,
215157
- isRow: isRow3,
215310
+ isRow: isRow4,
215158
215311
  key: (r8) => r8.key,
215159
- admit
215312
+ admit: admit2
215160
215313
  });
215161
- prefsFollower = copy2.follower;
215314
+ prefsFollower = copy3.follower;
215162
215315
  }
215163
215316
  });
215164
215317
 
@@ -215750,7 +215903,7 @@ async function adoptDeviceRecord(input, opts2 = {}) {
215750
215903
  const existing = devices.find((d8) => d8.tokenHash === tokenHash);
215751
215904
  if (existing) return { result: { name: existing.name, adopted: false } };
215752
215905
  const finalName = freeName(devices, name);
215753
- const wanted = typeof input.id === "string" && ID_RE3.test(input.id) ? input.id : void 0;
215906
+ const wanted = typeof input.id === "string" && ID_RE4.test(input.id) ? input.id : void 0;
215754
215907
  const idFree = wanted !== void 0 && !devices.some((d8) => d8.id === wanted || d8.ownerId === wanted);
215755
215908
  const record2 = {
215756
215909
  name: finalName,
@@ -215785,7 +215938,7 @@ async function revokeAdopted(tokenHash) {
215785
215938
  if (out.revoked) log.web.info("device-adoption: twin pairing revoked", { name: record2.name, adoptedFrom: record2.adoptedFrom ?? null });
215786
215939
  return out.revoked ? { name: record2.name, refused: false, push: out.push } : { name: null, refused: false, push: null };
215787
215940
  }
215788
- var AdoptionError, HASH_RE2, ID_RE3, INFO_FIELD_MAX2, NAME_MAX2;
215941
+ var AdoptionError, HASH_RE2, ID_RE4, INFO_FIELD_MAX2, NAME_MAX2;
215789
215942
  var init_device_adoption = __esm({
215790
215943
  "src/core/device-adoption.ts"() {
215791
215944
  "use strict";
@@ -215803,7 +215956,7 @@ var init_device_adoption = __esm({
215803
215956
  }
215804
215957
  };
215805
215958
  HASH_RE2 = /^[0-9a-f]{64}$/;
215806
- ID_RE3 = /^d[0-9a-f]{16}$/;
215959
+ ID_RE4 = /^d[0-9a-f]{16}$/;
215807
215960
  INFO_FIELD_MAX2 = 120;
215808
215961
  NAME_MAX2 = 64;
215809
215962
  }
@@ -245175,7 +245328,7 @@ async function saveRecordingAudio(audioBase64, format2) {
245175
245328
  return { id, audioPath };
245176
245329
  }
245177
245330
  async function writeRecordingResult(id, meta) {
245178
- if (!ID_RE4.test(id)) throw new Error(`Invalid recording id: ${id}`);
245331
+ if (!ID_RE5.test(id)) throw new Error(`Invalid recording id: ${id}`);
245179
245332
  await mkdir7(dir3(), { recursive: true });
245180
245333
  const stamped = { timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...meta };
245181
245334
  await writeFile6(join16(dir3(), `${id}.json`), JSON.stringify(stamped, null, 2));
@@ -245184,7 +245337,7 @@ async function writeRecordingResult(id, meta) {
245184
245337
  return stamped.timestamp;
245185
245338
  }
245186
245339
  async function writeRecordingSecondary(id, secondary, expectTimestamp) {
245187
- if (!ID_RE4.test(id)) throw new Error(`Invalid recording id: ${id}`);
245340
+ if (!ID_RE5.test(id)) throw new Error(`Invalid recording id: ${id}`);
245188
245341
  const path298 = join16(dir3(), `${id}.json`);
245189
245342
  let existing;
245190
245343
  try {
@@ -245206,7 +245359,7 @@ async function listRecordings(limit = 20) {
245206
245359
  const out = [];
245207
245360
  for (const jf of jsonFiles) {
245208
245361
  const id = jf.slice(0, -5);
245209
- if (!ID_RE4.test(id)) continue;
245362
+ if (!ID_RE5.test(id)) continue;
245210
245363
  try {
245211
245364
  const raw = JSON.parse(await readFile8(join16(dir3(), jf), "utf-8"));
245212
245365
  out.push({
@@ -245226,7 +245379,7 @@ async function listRecordings(limit = 20) {
245226
245379
  return out;
245227
245380
  }
245228
245381
  async function readRecordingAudio(id) {
245229
- if (!ID_RE4.test(id)) return null;
245382
+ if (!ID_RE5.test(id)) return null;
245230
245383
  let files;
245231
245384
  try {
245232
245385
  files = await readdir3(dir3());
@@ -245254,13 +245407,13 @@ async function pruneOldRecordings() {
245254
245407
  }
245255
245408
  }
245256
245409
  }
245257
- var MAX_RECORDINGS, ID_RE4, AUDIO_EXTS;
245410
+ var MAX_RECORDINGS, ID_RE5, AUDIO_EXTS;
245258
245411
  var init_recordings = __esm({
245259
245412
  "src/core/stt/recordings.ts"() {
245260
245413
  "use strict";
245261
245414
  init_constants();
245262
245415
  MAX_RECORDINGS = 100;
245263
- ID_RE4 = /^[0-9A-Za-z-]+$/;
245416
+ ID_RE5 = /^[0-9A-Za-z-]+$/;
245264
245417
  AUDIO_EXTS = ["webm", "mp4", "ogg", "wav", "mp3", "m4a", "flac"];
245265
245418
  }
245266
245419
  });
@@ -251908,6 +252061,147 @@ var init_task_v1 = __esm({
251908
252061
  }
251909
252062
  });
251910
252063
 
252064
+ // src/core/replication/kinds/requests.ts
252065
+ var requests_exports = {};
252066
+ __export(requests_exports, {
252067
+ REQUESTS_KIND: () => REQUESTS_KIND,
252068
+ REQUESTS_REMOVAL_FLOOR: () => REQUESTS_REMOVAL_FLOOR,
252069
+ REQUESTS_SCHEMA_VERSION: () => REQUESTS_SCHEMA_VERSION,
252070
+ _resetRequestsCopyForTesting: () => _resetRequestsCopyForTesting,
252071
+ forwardRequest: () => forwardRequest,
252072
+ readRequestCopy: () => readRequestCopy,
252073
+ requestsFollower: () => requestsFollower
252074
+ });
252075
+ import fsp124 from "fs/promises";
252076
+ import path235 from "path";
252077
+ function forwardRequest(local, incoming) {
252078
+ if (local && FINAL.has(local.status) && !FINAL.has(incoming.status)) return local;
252079
+ return incoming;
252080
+ }
252081
+ function hashOf6(row) {
252082
+ let h8 = hashes5.get(row);
252083
+ if (h8 === void 0) {
252084
+ h8 = sha12(JSON.stringify(row));
252085
+ hashes5.set(row, h8);
252086
+ }
252087
+ return h8;
252088
+ }
252089
+ async function load6() {
252090
+ if (state11) return state11;
252091
+ let s4 = { asOf: 0, at: 0, order: [], hashes: {} };
252092
+ try {
252093
+ const raw = JSON.parse(await fsp124.readFile(STATE_FILE(), "utf8"));
252094
+ 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 };
252095
+ } catch {
252096
+ }
252097
+ state11 = s4;
252098
+ return s4;
252099
+ }
252100
+ async function save() {
252101
+ if (state11) await writeCopyFile(STATE_FILE(), { v: 1, asOf: state11.asOf, at: state11.at, hashes: state11.hashes });
252102
+ }
252103
+ async function readStore8() {
252104
+ try {
252105
+ const raw = JSON.parse(await fsp124.readFile(STORE_FILE(), "utf8"));
252106
+ return Array.isArray(raw?.requests) ? raw.requests.filter(isRow5) : [];
252107
+ } catch {
252108
+ return [];
252109
+ }
252110
+ }
252111
+ function isRow5(v3) {
252112
+ const r8 = v3;
252113
+ return !!r8 && typeof r8 === "object" && typeof r8.id === "string" && !!r8.id && typeof r8.fromSessionId === "string" && typeof r8.status === "string" && typeof r8.createdAt === "string";
252114
+ }
252115
+ function requestsFollower() {
252116
+ follower3 ??= createRowSetFollower({
252117
+ kind: "requests",
252118
+ schemaVersion: REQUESTS_SCHEMA_VERSION,
252119
+ label: "requests copy",
252120
+ log: log.session,
252121
+ removalFloor: REQUESTS_REMOVAL_FLOOR,
252122
+ ordered: false,
252123
+ serial: (fn) => serial4(fn),
252124
+ refuse: copyRefusal,
252125
+ load: load6,
252126
+ save,
252127
+ isRow: isRow5,
252128
+ key: (r8) => r8.id,
252129
+ localKeys: async () => (await readStore8()).map((r8) => r8.id),
252130
+ apply: async ({ rows, removeIds }) => {
252131
+ const byId = new Map((await readStore8()).map((r8) => [r8.id, r8]));
252132
+ for (const id of removeIds ?? []) byId.delete(id);
252133
+ for (const r8 of rows ?? []) {
252134
+ const kept = forwardRequest(byId.get(r8.id), r8);
252135
+ 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 });
252136
+ byId.set(r8.id, kept);
252137
+ }
252138
+ await writeCopyFile(STORE_FILE(), { requests: [...byId.values()] });
252139
+ return { skipped: [] };
252140
+ },
252141
+ held: async () => (await Promise.resolve().then(() => (init_journal_overlay(), journal_overlay_exports))).journalHeld("requests"),
252142
+ changed: () => {
252143
+ },
252144
+ purge: async () => {
252145
+ const removed = (await readStore8()).length;
252146
+ await fsp124.rm(STORE_FILE(), { force: true });
252147
+ await markCopyOff("requests");
252148
+ state11 = null;
252149
+ return { removed };
252150
+ }
252151
+ });
252152
+ return follower3;
252153
+ }
252154
+ async function readRequestCopy(id) {
252155
+ if (!await copyKindHeld("requests")) return null;
252156
+ return (await readStore8()).find((r8) => r8.id === id) ?? null;
252157
+ }
252158
+ function _resetRequestsCopyForTesting() {
252159
+ state11 = null;
252160
+ follower3 = null;
252161
+ serial4 = serialChain();
252162
+ }
252163
+ var REQUESTS_SCHEMA_VERSION, REQUESTS_REMOVAL_FLOOR, FINAL, hashes5, REQUESTS_KIND, STATE_FILE, STORE_FILE, state11, serial4, follower3;
252164
+ var init_requests = __esm({
252165
+ "src/core/replication/kinds/requests.ts"() {
252166
+ "use strict";
252167
+ init_constants();
252168
+ init_logging();
252169
+ init_kind();
252170
+ init_kind_follower();
252171
+ init_gate();
252172
+ REQUESTS_SCHEMA_VERSION = 1;
252173
+ REQUESTS_REMOVAL_FLOOR = 50;
252174
+ FINAL = /* @__PURE__ */ new Set(["replied", "notified", "expired"]);
252175
+ hashes5 = /* @__PURE__ */ new WeakMap();
252176
+ REQUESTS_KIND = {
252177
+ kind: "requests",
252178
+ schemaVersion: REQUESTS_SCHEMA_VERSION,
252179
+ key: (r8) => r8.id,
252180
+ hash: hashOf6,
252181
+ ordered: false,
252182
+ digest: false,
252183
+ choice: "requests",
252184
+ rows: async () => (await Promise.resolve().then(() => (init_session_requests(), session_requests_exports))).listAllSessionRequests(),
252185
+ watch: (soon) => {
252186
+ let stop2 = null;
252187
+ let stopped2 = false;
252188
+ void Promise.resolve().then(() => (init_session_requests(), session_requests_exports)).then(({ onSessionRequestsWritten: onSessionRequestsWritten2 }) => {
252189
+ if (!stopped2) stop2 = onSessionRequestsWritten2(soon);
252190
+ });
252191
+ return () => {
252192
+ stopped2 = true;
252193
+ stop2?.();
252194
+ };
252195
+ }
252196
+ };
252197
+ STATE_FILE = () => path235.join(WALNUT_HOME, "cache", "replica", "requests.json");
252198
+ STORE_FILE = () => copyPath(path235.join(WALNUT_HOME, "session-requests.json"));
252199
+ state11 = null;
252200
+ serial4 = serialChain();
252201
+ follower3 = null;
252202
+ }
252203
+ });
252204
+
251911
252205
  // src/web/routes/messages-v1.ts
251912
252206
  import { Router as Router82 } from "express";
251913
252207
  function header(req, name) {
@@ -251968,7 +252262,15 @@ var init_messages_v1 = __esm({
251968
252262
  return;
251969
252263
  }
251970
252264
  const { getSessionRequest: getSessionRequest2 } = await Promise.resolve().then(() => (init_session_requests(), session_requests_exports));
251971
- const request3 = await getSessionRequest2(id);
252265
+ let request3 = await getSessionRequest2(id);
252266
+ if (!request3) {
252267
+ const [{ readRequestCopy: readRequestCopy2 }, { copyKindAsOf: copyKindAsOf2, COPY_AS_OF_HEADER: COPY_AS_OF_HEADER2 }] = await Promise.all([
252268
+ Promise.resolve().then(() => (init_requests(), requests_exports)),
252269
+ Promise.resolve().then(() => (init_gate(), gate_exports))
252270
+ ]);
252271
+ request3 = await readRequestCopy2(id) ?? void 0;
252272
+ if (request3) res.setHeader(COPY_AS_OF_HEADER2, String(await copyKindAsOf2("requests") ?? 0));
252273
+ }
251972
252274
  if (!request3) {
251973
252275
  sendV1Error(res, 404, "not_found", `No such request: ${id}`);
251974
252276
  return;
@@ -253643,6 +253945,17 @@ var init_search_memory_v1 = __esm({
253643
253945
  });
253644
253946
  searchMemoryV1Router.get("/favorites", async (_req, res, next) => {
253645
253947
  try {
253948
+ const [{ readFavoritesCopy: readFavoritesCopy2 }, { copyKindAsOf: copyKindAsOf2, COPY_AS_OF_HEADER: COPY_AS_OF_HEADER2 }] = await Promise.all([
253949
+ Promise.resolve().then(() => (init_prefs(), prefs_exports)),
253950
+ Promise.resolve().then(() => (init_gate(), gate_exports))
253951
+ ]);
253952
+ const asOf2 = await copyKindAsOf2("prefs");
253953
+ const fav = asOf2 === null ? null : await readFavoritesCopy2();
253954
+ if (fav) {
253955
+ res.setHeader(COPY_AS_OF_HEADER2, String(asOf2));
253956
+ res.json({ projects: fav.projects ?? [], notes: fav.notes ?? [] });
253957
+ return;
253958
+ }
253646
253959
  const { readFavorites: readFavorites2 } = await Promise.resolve().then(() => (init_favorites(), favorites_exports));
253647
253960
  res.json(await readFavorites2());
253648
253961
  } catch (err2) {
@@ -254675,9 +254988,9 @@ var init_stt_v1 = __esm({
254675
254988
 
254676
254989
  // src/web/routes/pastes.ts
254677
254990
  import { Router as Router89 } from "express";
254678
- import path235 from "path";
254991
+ import path236 from "path";
254679
254992
  import { createHash as createHash38 } from "crypto";
254680
- import fsp124 from "fs/promises";
254993
+ import fsp125 from "fs/promises";
254681
254994
  var pastesRouter, MAX_PASTE_CHARS;
254682
254995
  var init_pastes = __esm({
254683
254996
  "src/web/routes/pastes.ts"() {
@@ -254697,11 +255010,11 @@ var init_pastes = __esm({
254697
255010
  res.status(413).json({ error: `Paste too large (max ${MAX_PASTE_CHARS} chars)` });
254698
255011
  return;
254699
255012
  }
254700
- await fsp124.mkdir(PASTES_DIR, { recursive: true });
255013
+ await fsp125.mkdir(PASTES_DIR, { recursive: true });
254701
255014
  const hash3 = createHash38("sha256").update(text5).digest("hex").slice(0, 12);
254702
255015
  const filename = `${Date.now()}-${hash3}.txt`;
254703
- const filePath = path235.join(PASTES_DIR, filename);
254704
- await fsp124.writeFile(filePath, text5, "utf8");
255016
+ const filePath = path236.join(PASTES_DIR, filename);
255017
+ await fsp125.writeFile(filePath, text5, "utf8");
254705
255018
  log.web.info("paste spilled to disk", { filePath, chars: text5.length });
254706
255019
  res.json({ path: filePath, filename, chars: text5.length });
254707
255020
  } catch (err2) {
@@ -254717,8 +255030,8 @@ __export(file_content_replica_copy_exports, {
254717
255030
  primaryDataDirRelPath: () => primaryDataDirRelPath,
254718
255031
  resolveReplicaCopy: () => resolveReplicaCopy
254719
255032
  });
254720
- import path236 from "path";
254721
- import fsp125 from "fs/promises";
255033
+ import path237 from "path";
255034
+ import fsp126 from "fs/promises";
254722
255035
  function dataDirIndex(parts, tilde) {
254723
255036
  if (tilde) return parts[1] === DATA_DIR_NAME ? 1 : -1;
254724
255037
  if ((parts[0] === "Users" || parts[0] === "home") && parts[2] === DATA_DIR_NAME) return 2;
@@ -254748,12 +255061,12 @@ async function resolveReplicaCopy(requestPath) {
254748
255061
  const rel = primaryDataDirRelPath(requestPath);
254749
255062
  if (rel === null || deniedName(rel)) return null;
254750
255063
  try {
254751
- const root6 = await fsp125.realpath(WALNUT_HOME);
254752
- const real = await fsp125.realpath(path236.join(WALNUT_HOME, rel));
254753
- if (!real.startsWith(root6 + path236.sep)) return null;
254754
- const realRel = path236.relative(root6, real).split(path236.sep).join("/");
254755
- if (isSecretPath(path236.join(WALNUT_HOME, realRel)) || deniedName(realRel)) return null;
254756
- const st2 = await fsp125.stat(real);
255064
+ const root6 = await fsp126.realpath(WALNUT_HOME);
255065
+ const real = await fsp126.realpath(path237.join(WALNUT_HOME, rel));
255066
+ if (!real.startsWith(root6 + path237.sep)) return null;
255067
+ const realRel = path237.relative(root6, real).split(path237.sep).join("/");
255068
+ if (isSecretPath(path237.join(WALNUT_HOME, realRel)) || deniedName(realRel)) return null;
255069
+ const st2 = await fsp126.stat(real);
254757
255070
  if (!st2.isFile()) return null;
254758
255071
  if (!await isTracked(root6, realRel)) return null;
254759
255072
  return { localPath: real, size: st2.size };
@@ -254793,11 +255106,11 @@ var init_file_content_replica_copy = __esm({
254793
255106
  // src/web/routes/media-v1.ts
254794
255107
  import { Router as Router90 } from "express";
254795
255108
  import crypto67 from "crypto";
254796
- import path237 from "path";
254797
- import fsp126 from "fs/promises";
255109
+ import path238 from "path";
255110
+ import fsp127 from "fs/promises";
254798
255111
  function cachePathFor(host, filePath) {
254799
255112
  const hash3 = crypto67.createHash("sha256").update(filePath).digest("hex").slice(0, 16);
254800
- return path237.join(REMOTE_IMAGES_DIR, host, `${hash3}-${path237.basename(filePath)}`);
255113
+ return path238.join(REMOTE_IMAGES_DIR, host, `${hash3}-${path238.basename(filePath)}`);
254801
255114
  }
254802
255115
  async function hostForSession(sessionId) {
254803
255116
  if (CLOUD_MODE) {
@@ -254862,11 +255175,11 @@ var init_media_v1 = __esm({
254862
255175
  try {
254863
255176
  const filePath = req.query.path;
254864
255177
  const session2 = typeof req.query.session === "string" && SID_RE6.test(req.query.session) ? req.query.session : void 0;
254865
- if (!filePath || typeof filePath !== "string" || !path237.isAbsolute(filePath) || filePath.includes("..")) {
255178
+ if (!filePath || typeof filePath !== "string" || !path238.isAbsolute(filePath) || filePath.includes("..")) {
254866
255179
  res.status(400).json({ error: { code: "bad_request", message: "path must be an absolute file path" } });
254867
255180
  return;
254868
255181
  }
254869
- const ext2 = path237.extname(filePath).slice(1).toLowerCase();
255182
+ const ext2 = path238.extname(filePath).slice(1).toLowerCase();
254870
255183
  const mime = EXT_TO_MIME3[ext2];
254871
255184
  if (!mime) {
254872
255185
  res.status(400).json({ error: { code: "bad_request", message: "file type not allowed" } });
@@ -254874,8 +255187,8 @@ var init_media_v1 = __esm({
254874
255187
  }
254875
255188
  let buffer2 = null;
254876
255189
  try {
254877
- const st2 = await fsp126.stat(filePath);
254878
- if (st2.isFile() && st2.size <= MAX_FILE_SIZE3) buffer2 = await fsp126.readFile(filePath);
255190
+ const st2 = await fsp127.stat(filePath);
255191
+ if (st2.isFile() && st2.size <= MAX_FILE_SIZE3) buffer2 = await fsp127.readFile(filePath);
254879
255192
  } catch {
254880
255193
  }
254881
255194
  let waitedOnPending = false;
@@ -254896,8 +255209,8 @@ var init_media_v1 = __esm({
254896
255209
  if (buffer2) {
254897
255210
  try {
254898
255211
  const cachePath3 = cachePathFor(host, filePath);
254899
- await fsp126.mkdir(path237.dirname(cachePath3), { recursive: true });
254900
- await fsp126.writeFile(cachePath3, buffer2);
255212
+ await fsp127.mkdir(path238.dirname(cachePath3), { recursive: true });
255213
+ await fsp127.writeFile(cachePath3, buffer2);
254901
255214
  } catch {
254902
255215
  }
254903
255216
  break;
@@ -254907,9 +255220,9 @@ var init_media_v1 = __esm({
254907
255220
  for (const host of hosts2) {
254908
255221
  try {
254909
255222
  const cached8 = cachePathFor(host, filePath);
254910
- const st2 = await fsp126.stat(cached8);
255223
+ const st2 = await fsp127.stat(cached8);
254911
255224
  if (st2.isFile() && st2.size <= MAX_FILE_SIZE3) {
254912
- buffer2 = await fsp126.readFile(cached8);
255225
+ buffer2 = await fsp127.readFile(cached8);
254913
255226
  break;
254914
255227
  }
254915
255228
  } catch {
@@ -254919,7 +255232,7 @@ var init_media_v1 = __esm({
254919
255232
  if (!buffer2 && hosts2.length > 0 && hosts2.every((h8) => h8 === "__local__") && !(await Promise.resolve().then(() => (init_bridge_registry(), bridge_registry_exports))).bridgeForHost("__local__").connected) {
254920
255233
  const { resolveReplicaCopy: resolveReplicaCopy2 } = await Promise.resolve().then(() => (init_file_content_replica_copy(), file_content_replica_copy_exports));
254921
255234
  const copy5 = await resolveReplicaCopy2(filePath);
254922
- if (copy5 && copy5.size <= MAX_FILE_SIZE3) buffer2 = await fsp126.readFile(copy5.localPath);
255235
+ if (copy5 && copy5.size <= MAX_FILE_SIZE3) buffer2 = await fsp127.readFile(copy5.localPath);
254923
255236
  }
254924
255237
  }
254925
255238
  if (!buffer2) {
@@ -254944,6 +255257,19 @@ var init_media_v1 = __esm({
254944
255257
 
254945
255258
  // src/web/routes/routines-v1.ts
254946
255259
  import { Router as Router91 } from "express";
255260
+ async function answeredFromCopy(res, includeDisabled, answer5) {
255261
+ const [{ companionRoutinesCopy: companionRoutinesCopy2 }, { copyKindAsOf: copyKindAsOf2, COPY_AS_OF_HEADER: COPY_AS_OF_HEADER2 }] = await Promise.all([
255262
+ Promise.resolve().then(() => (init_routines_follower(), routines_follower_exports)),
255263
+ Promise.resolve().then(() => (init_gate(), gate_exports))
255264
+ ]);
255265
+ const jobs2 = await companionRoutinesCopy2({ includeDisabled });
255266
+ if (!jobs2) return false;
255267
+ res.setHeader(COPY_AS_OF_HEADER2, String(await copyKindAsOf2("routines") ?? 0));
255268
+ const body7 = answer5(jobs2);
255269
+ if (body7 === null) sendV1Error(res, 404, "not_found", "No such routine in the copy of your Mac's routines");
255270
+ else res.json(body7);
255271
+ return true;
255272
+ }
254947
255273
  function validRid(req, res) {
254948
255274
  const id = String(req.params.id ?? "");
254949
255275
  if (!RID_RE.test(id)) {
@@ -254990,6 +255316,7 @@ var init_routines_v1 = __esm({
254990
255316
  try {
254991
255317
  const includeDisabled = req.query.includeDisabled === "true";
254992
255318
  if (CLOUD_MODE) {
255319
+ if (await answeredFromCopy(res, includeDisabled, (jobs2) => ({ jobs: jobs2 }))) return;
254993
255320
  await relayControlAction(res, "server.routines", SERVER_RELAY_SID14, { includeDisabled }, 200);
254994
255321
  return;
254995
255322
  }
@@ -255014,6 +255341,7 @@ var init_routines_v1 = __esm({
255014
255341
  routinesV1Router.get("/routines/status", async (_req, res, next) => {
255015
255342
  try {
255016
255343
  if (CLOUD_MODE) {
255344
+ if (await answeredFromCopy(res, true, (jobs2) => ({ enabled: false, storePath: "", jobs: jobs2.length, nextWakeAtMs: null }))) return;
255017
255345
  await relayControlAction(res, "server.routines.status", SERVER_RELAY_SID14, void 0, 200);
255018
255346
  return;
255019
255347
  }
@@ -255085,6 +255413,10 @@ var init_routines_v1 = __esm({
255085
255413
  const id = validRid(req, res);
255086
255414
  if (!id) return;
255087
255415
  if (CLOUD_MODE) {
255416
+ if (await answeredFromCopy(res, true, (jobs2) => {
255417
+ const job2 = jobs2.find((j8) => j8.id === id);
255418
+ return job2 ? { job: job2 } : null;
255419
+ })) return;
255088
255420
  await relayControlAction(res, "server.routines.get", SERVER_RELAY_SID14, { id }, 200);
255089
255421
  return;
255090
255422
  }
@@ -256279,8 +256611,8 @@ __export(file_content_bridge_exports, {
256279
256611
  resolveBridgeHost: () => resolveBridgeHost,
256280
256612
  serveCloudFileContent: () => serveCloudFileContent
256281
256613
  });
256282
- import path238 from "path";
256283
- import fsp127 from "fs/promises";
256614
+ import path239 from "path";
256615
+ import fsp128 from "fs/promises";
256284
256616
  function resolveBridgeHost(host) {
256285
256617
  return typeof host === "string" && host.length > 0 ? host : PRIMARY_BRIDGE_ALIAS4;
256286
256618
  }
@@ -256351,7 +256683,7 @@ function precheckPath(res, rawPath) {
256351
256683
  sendV1Error(res, 400, "bad_request", "Invalid path");
256352
256684
  return null;
256353
256685
  }
256354
- if (rawPath !== "~" && !rawPath.startsWith("~/") && !path238.isAbsolute(rawPath)) {
256686
+ if (rawPath !== "~" && !rawPath.startsWith("~/") && !path239.isAbsolute(rawPath)) {
256355
256687
  sendV1Error(res, 400, "bad_request", "Path must be absolute");
256356
256688
  return null;
256357
256689
  }
@@ -256395,7 +256727,7 @@ async function serveCloudFileContent(req, res) {
256395
256727
  const hostAlias2 = resolveBridgeHost(req.query.host);
256396
256728
  const raw = req.query.raw === "1" || req.query.raw === "true";
256397
256729
  const download = req.query.download === "1" || req.query.download === "true";
256398
- const ext2 = path238.extname(filePath).slice(1).toLowerCase();
256730
+ const ext2 = path239.extname(filePath).slice(1).toLowerCase();
256399
256731
  const {
256400
256732
  assertPathAllowed: assertPathAllowed2,
256401
256733
  isSecretPath: isSecretPath2,
@@ -256405,7 +256737,7 @@ async function serveCloudFileContent(req, res) {
256405
256737
  FileContentError: FileContentError2
256406
256738
  } = await Promise.resolve().then(() => (init_file_content(), file_content_exports));
256407
256739
  const explicitHost = typeof req.query.host === "string" && req.query.host.length > 0;
256408
- const locallyPresent = await fsp127.stat(filePath).then((st2) => st2.isFile()).catch(() => false);
256740
+ const locallyPresent = await fsp128.stat(filePath).then((st2) => st2.isFile()).catch(() => false);
256409
256741
  if (!explicitHost && locallyPresent && cloudLocalReadAllowed2(filePath) && !isSecretPath2(filePath)) {
256410
256742
  try {
256411
256743
  if (raw) {
@@ -256503,10 +256835,10 @@ async function serveReplicaCopy(req, res, requestPath, copy5, opts2) {
256503
256835
  return;
256504
256836
  }
256505
256837
  if (copy5.size <= MAX_BRIDGE_FILE_BYTES) {
256506
- res.json(jsonPayloadFromBuffer(await fsp127.readFile(copy5.localPath), opts2.ext, false));
256838
+ res.json(jsonPayloadFromBuffer(await fsp128.readFile(copy5.localPath), opts2.ext, false));
256507
256839
  return;
256508
256840
  }
256509
- const fh = await fsp127.open(copy5.localPath, "r");
256841
+ const fh = await fsp128.open(copy5.localPath, "r");
256510
256842
  try {
256511
256843
  const head2 = Buffer.alloc(MAX_TEXT_PAYLOAD);
256512
256844
  const { bytesRead } = await fh.read(head2, 0, head2.length, 0);
@@ -257580,17 +257912,17 @@ __export(checklist_io_exports, {
257580
257912
  readHeartbeatChecklist: () => readHeartbeatChecklist,
257581
257913
  writeHeartbeatChecklist: () => writeHeartbeatChecklist
257582
257914
  });
257583
- import fsp128 from "fs/promises";
257915
+ import fsp129 from "fs/promises";
257584
257916
  async function readHeartbeatChecklist() {
257585
257917
  try {
257586
- return await fsp128.readFile(HEARTBEAT_FILE, "utf-8");
257918
+ return await fsp129.readFile(HEARTBEAT_FILE, "utf-8");
257587
257919
  } catch (err2) {
257588
257920
  if (err2.code === "ENOENT") return "";
257589
257921
  throw err2;
257590
257922
  }
257591
257923
  }
257592
257924
  async function writeHeartbeatChecklist(content) {
257593
- await fsp128.writeFile(HEARTBEAT_FILE, content, "utf-8");
257925
+ await fsp129.writeFile(HEARTBEAT_FILE, content, "utf-8");
257594
257926
  }
257595
257927
  var init_checklist_io = __esm({
257596
257928
  "src/heartbeat/checklist-io.ts"() {
@@ -259509,11 +259841,11 @@ __export(ephemeral_guard_exports, {
259509
259841
  });
259510
259842
  import fs127 from "fs";
259511
259843
  import os60 from "os";
259512
- import path239 from "path";
259844
+ import path240 from "path";
259513
259845
  function productionWalnutHomes() {
259514
259846
  const homes = /* @__PURE__ */ new Set();
259515
259847
  const add3 = (home) => {
259516
- if (home) homes.add(path239.join(home, ".open-walnut"));
259848
+ if (home) homes.add(path240.join(home, ".open-walnut"));
259517
259849
  };
259518
259850
  add3(os60.homedir());
259519
259851
  try {
@@ -259523,7 +259855,7 @@ function productionWalnutHomes() {
259523
259855
  return [...homes];
259524
259856
  }
259525
259857
  function canonical2(dir4) {
259526
- const resolved = path239.resolve(dir4);
259858
+ const resolved = path240.resolve(dir4);
259527
259859
  try {
259528
259860
  return fs127.realpathSync(resolved);
259529
259861
  } catch {
@@ -259559,28 +259891,28 @@ __export(boot_guard_exports, {
259559
259891
  });
259560
259892
  import fs128 from "fs";
259561
259893
  import os61 from "os";
259562
- import path240 from "path";
259894
+ import path241 from "path";
259563
259895
  function canonical3(dir4) {
259564
- let head2 = path240.resolve(dir4);
259896
+ let head2 = path241.resolve(dir4);
259565
259897
  const rest = [];
259566
259898
  for (; ; ) {
259567
259899
  try {
259568
- return path240.join(fs128.realpathSync(head2), ...rest);
259900
+ return path241.join(fs128.realpathSync(head2), ...rest);
259569
259901
  } catch {
259570
259902
  }
259571
- const up = path240.dirname(head2);
259572
- if (up === head2) return path240.resolve(dir4);
259573
- rest.unshift(path240.basename(head2));
259903
+ const up = path241.dirname(head2);
259904
+ if (up === head2) return path241.resolve(dir4);
259905
+ rest.unshift(path241.basename(head2));
259574
259906
  head2 = up;
259575
259907
  }
259576
259908
  }
259577
259909
  function spellings(dir4) {
259578
- const resolved = path240.resolve(dir4);
259910
+ const resolved = path241.resolve(dir4);
259579
259911
  return [.../* @__PURE__ */ new Set([resolved, canonical3(resolved), `/private${resolved}`])];
259580
259912
  }
259581
259913
  function within5(child2, parent) {
259582
- const rel = path240.relative(parent, child2);
259583
- return rel === "" || !rel.startsWith("..") && !path240.isAbsolute(rel);
259914
+ const rel = path241.relative(parent, child2);
259915
+ return rel === "" || !rel.startsWith("..") && !path241.isAbsolute(rel);
259584
259916
  }
259585
259917
  function overlaps(a8, b8) {
259586
259918
  return spellings(a8).some((x3) => spellings(b8).some((y3) => within5(x3, y3) || within5(y3, x3)));
@@ -259591,7 +259923,7 @@ function holdsOrIs(outer, inner2) {
259591
259923
  function accountHomes(env3) {
259592
259924
  const homes = /* @__PURE__ */ new Set();
259593
259925
  const add3 = (h8) => {
259594
- if (h8 && h8.trim()) homes.add(path240.resolve(h8.trim()));
259926
+ if (h8 && h8.trim()) homes.add(path241.resolve(h8.trim()));
259595
259927
  };
259596
259928
  add3(env3.HOME);
259597
259929
  add3(os61.homedir());
@@ -259649,7 +259981,7 @@ function assertReplicaBootSafe(input) {
259649
259981
  if (why2) throw new Error(`Host replica refused to start: ${why2}.`);
259650
259982
  }
259651
259983
  function claimReplicaDir(dir4) {
259652
- const marker = path240.join(dir4, REPLICA_DIR_MARKER);
259984
+ const marker = path241.join(dir4, REPLICA_DIR_MARKER);
259653
259985
  try {
259654
259986
  return fs128.lstatSync(marker).isFile();
259655
259987
  } catch {
@@ -259674,7 +260006,7 @@ function claimReplicaDir(dir4) {
259674
260006
  function tightenReplicaModes(dirs2, limit = 2e4) {
259675
260007
  const marked = dirs2.filter((d8) => {
259676
260008
  try {
259677
- return fs128.lstatSync(path240.join(d8, REPLICA_DIR_MARKER)).isFile();
260009
+ return fs128.lstatSync(path241.join(d8, REPLICA_DIR_MARKER)).isFile();
259678
260010
  } catch {
259679
260011
  return false;
259680
260012
  }
@@ -259704,7 +260036,7 @@ function tightenReplicaModes(dirs2, limit = 2e4) {
259704
260036
  } catch {
259705
260037
  return;
259706
260038
  }
259707
- for (const n6 of names2) visit(path240.join(p6, n6));
260039
+ for (const n6 of names2) visit(path241.join(p6, n6));
259708
260040
  } else if (st2.isFile() && (st2.mode & 63) !== 0) {
259709
260041
  try {
259710
260042
  fs128.chmodSync(p6, st2.mode & 448 | 384);
@@ -259891,29 +260223,29 @@ __export(search_replica_store_exports, {
259891
260223
  searchReplicaSync: () => searchReplicaSync,
259892
260224
  startSearchReplicaStore: () => startSearchReplicaStore
259893
260225
  });
259894
- import fsp129 from "fs/promises";
260226
+ import fsp130 from "fs/promises";
259895
260227
  import os62 from "os";
259896
- import path241 from "path";
260228
+ import path242 from "path";
259897
260229
  async function wiring() {
259898
260230
  return Promise.resolve().then(() => (init_wiring(), wiring_exports));
259899
260231
  }
259900
260232
  async function loadState() {
259901
- if (state11) return state11;
260233
+ if (state12) return state12;
259902
260234
  let s4 = { v: 1, mode: null, syncedAt: null };
259903
260235
  try {
259904
- const raw = JSON.parse(await fsp129.readFile(STATE_FILE(), "utf8"));
260236
+ const raw = JSON.parse(await fsp130.readFile(STATE_FILE2(), "utf8"));
259905
260237
  if (raw && raw.v === 1) {
259906
260238
  s4 = { v: 1, mode: raw.mode ? companionSearchMode(raw.mode) : null, syncedAt: typeof raw.syncedAt === "number" ? raw.syncedAt : null };
259907
260239
  }
259908
260240
  } catch {
259909
260241
  }
259910
- state11 = s4;
260242
+ state12 = s4;
259911
260243
  return s4;
259912
260244
  }
259913
260245
  async function saveState() {
259914
- if (state11) await writeJsonFile(STATE_FILE(), state11);
260246
+ if (state12) await writeJsonFile(STATE_FILE2(), state12);
259915
260247
  }
259916
- function serial4(fn) {
260248
+ function serial5(fn) {
259917
260249
  const run13 = chain4.then(fn, fn);
259918
260250
  chain4 = run13.catch(() => {
259919
260251
  });
@@ -259977,8 +260309,8 @@ async function closeIndex() {
259977
260309
  allDirty2 = true;
259978
260310
  }
259979
260311
  function publishReady() {
259980
- const ready2 = enabled && mapBuilt && map3.size > 0 && state11?.syncedAt != null;
259981
- setCompanionSearchReady(ready2, ready2 ? state11.syncedAt : null);
260312
+ const ready2 = enabled && mapBuilt && map3.size > 0 && state12?.syncedAt != null;
260313
+ setCompanionSearchReady(ready2, ready2 ? state12.syncedAt : null);
259982
260314
  }
259983
260315
  async function markInSync() {
259984
260316
  const s4 = await loadState();
@@ -260005,7 +260337,7 @@ async function warm(why2) {
260005
260337
  }
260006
260338
  }
260007
260339
  function searchReplicaStatus(body7) {
260008
- return serial4(async () => {
260340
+ return serial5(async () => {
260009
260341
  if (!isFollower()) return { ok: false, status: 400, error: "not_a_replica" };
260010
260342
  const s4 = await loadState();
260011
260343
  const mode = companionSearchMode(body7.mode);
@@ -260053,7 +260385,7 @@ function searchReplicaStatus(body7) {
260053
260385
  });
260054
260386
  }
260055
260387
  function searchReplicaSync(body7) {
260056
- return serial4(async () => {
260388
+ return serial5(async () => {
260057
260389
  if (!isFollower()) return { ok: false, status: 400, error: "not_a_replica" };
260058
260390
  if (!enabled) return { ok: false, status: 400, error: "search_copy_off" };
260059
260391
  if (!Array.isArray(body7.entries)) return { ok: false, status: 400, error: "bad_entries" };
@@ -260098,7 +260430,7 @@ async function forgetSearchMemo() {
260098
260430
  }
260099
260431
  }
260100
260432
  function searchReplicaPut(body7) {
260101
- return serial4(async () => {
260433
+ return serial5(async () => {
260102
260434
  if (!isFollower()) return { ok: false, status: 400, error: "not_a_replica" };
260103
260435
  if (!enabled) return { ok: false, status: 400, error: "search_copy_off" };
260104
260436
  if (!Array.isArray(body7.docs)) return { ok: false, status: 400, error: "bad_docs" };
@@ -260164,7 +260496,7 @@ function startSearchReplicaStore(options = {}) {
260164
260496
  if (!s4.mode || stopped2) return;
260165
260497
  const decision = companionSearchDecision(s4.mode, deps3.totalMb());
260166
260498
  if (!decision.enabled) return;
260167
- await serial4(async () => {
260499
+ await serial5(async () => {
260168
260500
  enabled = true;
260169
260501
  reason2 = decision.reason;
260170
260502
  await refreshMap2(await openIndex());
@@ -260197,12 +260529,12 @@ function startSearchReplicaStore(options = {}) {
260197
260529
  }));
260198
260530
  }).catch((err2) => log.memory.warn("search replica: local writes not wired", { error: err2 instanceof Error ? err2.message : String(err2) }));
260199
260531
  unsubs.push(onLeaderPresence((answers4) => {
260200
- if (stopped2 || answers4 || !enabled || state11?.syncedAt == null) return;
260532
+ if (stopped2 || answers4 || !enabled || state12?.syncedAt == null) return;
260201
260533
  void warm("leader away");
260202
260534
  }));
260203
260535
  const tick = setInterval(() => {
260204
260536
  void (async () => {
260205
- if (stopped2 || !enabled || state11?.syncedAt == null) return;
260537
+ if (stopped2 || !enabled || state12?.syncedAt == null) return;
260206
260538
  if (Date.now() - lastWarmAt < WARM_EVERY_MS) return;
260207
260539
  if (!await deps3.macAway()) return;
260208
260540
  await warm("mac away");
@@ -260221,7 +260553,7 @@ function startSearchReplicaStore(options = {}) {
260221
260553
  };
260222
260554
  }
260223
260555
  function _resetSearchReplicaStoreForTesting(overrides = {}) {
260224
- state11 = null;
260556
+ state12 = null;
260225
260557
  enabled = false;
260226
260558
  reason2 = "off";
260227
260559
  map3.clear();
@@ -260236,7 +260568,7 @@ function _resetSearchReplicaStoreForTesting(overrides = {}) {
260236
260568
  deps3 = { totalMb: () => Math.round(os62.totalmem() / (1024 * 1024)), macAway: defaultMacAway, ...overrides };
260237
260569
  setCompanionSearchReady(false, null);
260238
260570
  }
260239
- 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;
260571
+ 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;
260240
260572
  var init_search_replica_store = __esm({
260241
260573
  "src/core/replication/search-replica-store.ts"() {
260242
260574
  "use strict";
@@ -260248,7 +260580,7 @@ var init_search_replica_store = __esm({
260248
260580
  init_replica_refs();
260249
260581
  init_search_digest();
260250
260582
  init_search_replica_wire();
260251
- STATE_FILE = () => path241.join(WALNUT_HOME, "cache", "search-replica.json");
260583
+ STATE_FILE2 = () => path242.join(WALNUT_HOME, "cache", "search-replica.json");
260252
260584
  MASS_REMOVE_FLOOR = 200;
260253
260585
  SCAN_SLICE2 = 500;
260254
260586
  WARM_EVERY_MS = 4 * 6e4;
@@ -260258,7 +260590,7 @@ var init_search_replica_store = __esm({
260258
260590
  totalMb: () => Math.round(os62.totalmem() / (1024 * 1024)),
260259
260591
  macAway: defaultMacAway
260260
260592
  };
260261
- state11 = null;
260593
+ state12 = null;
260262
260594
  enabled = false;
260263
260595
  reason2 = "off";
260264
260596
  map3 = new DigestMap();
@@ -260274,10 +260606,10 @@ var init_search_replica_store = __esm({
260274
260606
  });
260275
260607
 
260276
260608
  // src/core/replication/kinds/boards.ts
260277
- import fsp130 from "fs/promises";
260278
- import path242 from "path";
260609
+ import fsp131 from "fs/promises";
260610
+ import path243 from "path";
260279
260611
  async function leaderBoards(dir4 = boardsDir2()) {
260280
- const names2 = await fsp130.readdir(dir4).catch(() => []);
260612
+ const names2 = await fsp131.readdir(dir4).catch(() => []);
260281
260613
  const out = [];
260282
260614
  const unreadable = [];
260283
260615
  const seen2 = /* @__PURE__ */ new Set();
@@ -260286,9 +260618,9 @@ async function leaderBoards(dir4 = boardsDir2()) {
260286
260618
  const id = name.slice(0, -".json".length);
260287
260619
  if (!TASK_ID_RE3.test(id)) continue;
260288
260620
  seen2.add(id);
260289
- const file = path242.join(dir4, name);
260621
+ const file = path243.join(dir4, name);
260290
260622
  try {
260291
- const st2 = await fsp130.stat(file);
260623
+ const st2 = await fsp131.stat(file);
260292
260624
  if (!st2.isFile()) continue;
260293
260625
  if (st2.size > BOARD_COPY_MAX_BYTES) {
260294
260626
  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 });
@@ -260297,14 +260629,14 @@ async function leaderBoards(dir4 = boardsDir2()) {
260297
260629
  }
260298
260630
  let c8 = cache16.get(id);
260299
260631
  if (!c8 || c8.size !== st2.size || c8.mtimeMs !== st2.mtimeMs) {
260300
- const row = JSON.parse(await fsp130.readFile(file, "utf8"));
260301
- if (!isRow4(row) || row.task_id !== id) {
260632
+ const row = JSON.parse(await fsp131.readFile(file, "utf8"));
260633
+ if (!isRow6(row) || row.task_id !== id) {
260302
260634
  unreadable.push(id);
260303
260635
  continue;
260304
260636
  }
260305
260637
  c8 = { size: st2.size, mtimeMs: st2.mtimeMs, row, hash: sha12(JSON.stringify(row)) };
260306
260638
  cache16.set(id, c8);
260307
- hashOf5.set(row, c8.hash);
260639
+ hashOf7.set(row, c8.hash);
260308
260640
  }
260309
260641
  out.push(c8.row);
260310
260642
  } catch (err2) {
@@ -260319,56 +260651,56 @@ async function leaderBoards(dir4 = boardsDir2()) {
260319
260651
  if (fresh.length > 0) log.session.warn("boards copy: a board could not be read, the host keeps its copy of it", { taskIds: fresh });
260320
260652
  return out;
260321
260653
  }
260322
- function isRow4(v3) {
260654
+ function isRow6(v3) {
260323
260655
  const b8 = v3;
260324
260656
  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";
260325
260657
  }
260326
- async function load6() {
260327
- if (state12) return state12;
260658
+ async function load7() {
260659
+ if (state13) return state13;
260328
260660
  let s4 = { asOf: 0, at: 0, order: [], hashes: {} };
260329
260661
  try {
260330
- const raw = JSON.parse(await fsp130.readFile(STATE_FILE2(), "utf8"));
260662
+ const raw = JSON.parse(await fsp131.readFile(STATE_FILE3(), "utf8"));
260331
260663
  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 };
260332
260664
  } catch {
260333
260665
  }
260334
- state12 = s4;
260666
+ state13 = s4;
260335
260667
  return s4;
260336
260668
  }
260337
- async function save() {
260338
- if (state12) await writeCopyFile(STATE_FILE2(), { v: 1, asOf: state12.asOf, at: state12.at, hashes: state12.hashes });
260669
+ async function save2() {
260670
+ if (state13) await writeCopyFile(STATE_FILE3(), { v: 1, asOf: state13.asOf, at: state13.at, hashes: state13.hashes });
260339
260671
  }
260340
260672
  async function localIds() {
260341
- const names2 = await fsp130.readdir(boardsDir2()).catch(() => []);
260673
+ const names2 = await fsp131.readdir(boardsDir2()).catch(() => []);
260342
260674
  return names2.filter((n6) => n6.endsWith(".json")).map((n6) => n6.slice(0, -".json".length)).filter((id) => TASK_ID_RE3.test(id));
260343
260675
  }
260344
260676
  function changed3() {
260345
260677
  }
260346
260678
  function boardsFollower() {
260347
- follower3 ??= createRowSetFollower({
260679
+ follower4 ??= createRowSetFollower({
260348
260680
  kind: "boards",
260349
260681
  schemaVersion: BOARDS_SCHEMA_VERSION,
260350
260682
  label: "boards copy",
260351
260683
  log: log.session,
260352
260684
  removalFloor: BOARDS_REMOVAL_FLOOR,
260353
260685
  ordered: false,
260354
- serial: (fn) => serial5(fn),
260686
+ serial: (fn) => serial6(fn),
260355
260687
  refuse: copyRefusal,
260356
- load: load6,
260357
- save,
260358
- isRow: isRow4,
260688
+ load: load7,
260689
+ save: save2,
260690
+ isRow: isRow6,
260359
260691
  key: (b8) => b8.task_id,
260360
260692
  localKeys: localIds,
260361
260693
  apply: async ({ rows, removeIds }) => {
260362
260694
  const skipped = [];
260363
260695
  for (const id of removeIds ?? []) {
260364
- if (TASK_ID_RE3.test(id)) await fsp130.rm(path242.join(boardsDir2(), `${id}.json`), { force: true });
260696
+ if (TASK_ID_RE3.test(id)) await fsp131.rm(path243.join(boardsDir2(), `${id}.json`), { force: true });
260365
260697
  }
260366
260698
  for (const b8 of rows ?? []) {
260367
260699
  if (Buffer.byteLength(JSON.stringify(b8)) > BOARD_COPY_MAX_BYTES) {
260368
260700
  skipped.push(b8.task_id);
260369
260701
  continue;
260370
260702
  }
260371
- await writeCopyFile(path242.join(boardsDir2(), `${b8.task_id}.json`), b8);
260703
+ await writeCopyFile(path243.join(boardsDir2(), `${b8.task_id}.json`), b8);
260372
260704
  }
260373
260705
  return { skipped };
260374
260706
  },
@@ -260376,15 +260708,15 @@ function boardsFollower() {
260376
260708
  changed: changed3,
260377
260709
  purge: async () => {
260378
260710
  const ids2 = await localIds();
260379
- for (const id of ids2) await fsp130.rm(path242.join(boardsDir2(), `${id}.json`), { force: true });
260711
+ for (const id of ids2) await fsp131.rm(path243.join(boardsDir2(), `${id}.json`), { force: true });
260380
260712
  await markCopyOff("boards");
260381
- state12 = null;
260713
+ state13 = null;
260382
260714
  return { removed: ids2.length };
260383
260715
  }
260384
260716
  });
260385
- return follower3;
260717
+ return follower4;
260386
260718
  }
260387
- var BOARDS_SCHEMA_VERSION, BOARDS_REMOVAL_FLOOR, BOARD_COPY_MAX_BYTES, TASK_ID_RE3, boardsDir2, cache16, hashOf5, warnedTooBig, unreadableOf2, warnedUnreadable, BOARDS_KIND, STATE_FILE2, state12, serial5, follower3;
260719
+ var BOARDS_SCHEMA_VERSION, BOARDS_REMOVAL_FLOOR, BOARD_COPY_MAX_BYTES, TASK_ID_RE3, boardsDir2, cache16, hashOf7, warnedTooBig, unreadableOf2, warnedUnreadable, BOARDS_KIND, STATE_FILE3, state13, serial6, follower4;
260388
260720
  var init_boards2 = __esm({
260389
260721
  "src/core/replication/kinds/boards.ts"() {
260390
260722
  "use strict";
@@ -260397,9 +260729,9 @@ var init_boards2 = __esm({
260397
260729
  BOARDS_REMOVAL_FLOOR = 20;
260398
260730
  BOARD_COPY_MAX_BYTES = 2 * 1024 * 1024;
260399
260731
  TASK_ID_RE3 = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
260400
- boardsDir2 = () => path242.join(WALNUT_HOME, "boards");
260732
+ boardsDir2 = () => path243.join(WALNUT_HOME, "boards");
260401
260733
  cache16 = /* @__PURE__ */ new Map();
260402
- hashOf5 = /* @__PURE__ */ new WeakMap();
260734
+ hashOf7 = /* @__PURE__ */ new WeakMap();
260403
260735
  warnedTooBig = /* @__PURE__ */ new Set();
260404
260736
  unreadableOf2 = /* @__PURE__ */ new WeakMap();
260405
260737
  warnedUnreadable = /* @__PURE__ */ new Set();
@@ -260407,7 +260739,7 @@ var init_boards2 = __esm({
260407
260739
  kind: "boards",
260408
260740
  schemaVersion: BOARDS_SCHEMA_VERSION,
260409
260741
  key: (b8) => b8.task_id,
260410
- hash: (b8) => hashOf5.get(b8) ?? sha12(JSON.stringify(b8)),
260742
+ hash: (b8) => hashOf7.get(b8) ?? sha12(JSON.stringify(b8)),
260411
260743
  ordered: false,
260412
260744
  digest: false,
260413
260745
  choice: "boards",
@@ -260427,16 +260759,16 @@ var init_boards2 = __esm({
260427
260759
  };
260428
260760
  }
260429
260761
  };
260430
- STATE_FILE2 = () => path242.join(WALNUT_HOME, "cache", "replica", "boards.json");
260431
- state12 = null;
260432
- serial5 = serialChain();
260433
- follower3 = null;
260762
+ STATE_FILE3 = () => path243.join(WALNUT_HOME, "cache", "replica", "boards.json");
260763
+ state13 = null;
260764
+ serial6 = serialChain();
260765
+ follower4 = null;
260434
260766
  }
260435
260767
  });
260436
260768
 
260437
260769
  // src/core/replication/kinds/inbox.ts
260438
- import fsp131 from "fs/promises";
260439
- import path243 from "path";
260770
+ import fsp132 from "fs/promises";
260771
+ import path244 from "path";
260440
260772
  function watchLetters(soon) {
260441
260773
  let stop2 = null;
260442
260774
  let stopped2 = false;
@@ -260449,18 +260781,18 @@ function watchLetters(soon) {
260449
260781
  };
260450
260782
  }
260451
260783
  async function leaderBodies(dir4 = bodiesDir()) {
260452
- const names2 = (await fsp131.readdir(dir4).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6)).sort();
260784
+ const names2 = (await fsp132.readdir(dir4).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6)).sort();
260453
260785
  const out = [];
260454
260786
  const unreadable = [];
260455
260787
  const seen2 = new Set(names2);
260456
260788
  for (const name of names2) {
260457
- const file = path243.join(dir4, name);
260789
+ const file = path244.join(dir4, name);
260458
260790
  try {
260459
- const st2 = await fsp131.stat(file);
260791
+ const st2 = await fsp132.stat(file);
260460
260792
  if (!st2.isFile() || st2.size > INBOX_BODY_COPY_MAX_BYTES) continue;
260461
260793
  let c8 = bodyCache.get(name);
260462
260794
  if (!c8 || c8.size !== st2.size || c8.mtimeMs !== st2.mtimeMs) {
260463
- c8 = { size: st2.size, mtimeMs: st2.mtimeMs, hash: sha12(await fsp131.readFile(file, "utf8")) };
260795
+ c8 = { size: st2.size, mtimeMs: st2.mtimeMs, hash: sha12(await fsp132.readFile(file, "utf8")) };
260464
260796
  bodyCache.set(name, c8);
260465
260797
  }
260466
260798
  const row = { name };
@@ -260479,21 +260811,21 @@ async function loadBody(b8) {
260479
260811
  const file = bodyFiles.get(b8);
260480
260812
  if (!file) return typeof b8.body === "string" ? b8 : void 0;
260481
260813
  try {
260482
- const body7 = await fsp131.readFile(file, "utf8");
260814
+ const body7 = await fsp132.readFile(file, "utf8");
260483
260815
  return Buffer.byteLength(body7) > INBOX_BODY_COPY_MAX_BYTES ? void 0 : { name: b8.name, body: body7 };
260484
260816
  } catch {
260485
260817
  return void 0;
260486
260818
  }
260487
260819
  }
260488
260820
  function stateIo(name) {
260489
- const file = () => path243.join(WALNUT_HOME, "cache", "replica", `${name}.json`);
260821
+ const file = () => path244.join(WALNUT_HOME, "cache", "replica", `${name}.json`);
260490
260822
  let state17 = null;
260491
260823
  return {
260492
260824
  load: async () => {
260493
260825
  if (state17) return state17;
260494
260826
  let s4 = { asOf: 0, at: 0, order: [], hashes: {} };
260495
260827
  try {
260496
- const raw = JSON.parse(await fsp131.readFile(file(), "utf8"));
260828
+ const raw = JSON.parse(await fsp132.readFile(file(), "utf8"));
260497
260829
  if (raw?.v === 1 && raw.hashes && typeof raw.hashes === "object") {
260498
260830
  s4 = { asOf: Number(raw.asOf) || 0, at: Number(raw.at) || 0, order: Array.isArray(raw.order) ? raw.order.map(String) : [], hashes: raw.hashes };
260499
260831
  }
@@ -260512,7 +260844,7 @@ function stateIo(name) {
260512
260844
  }
260513
260845
  async function readIndex3() {
260514
260846
  try {
260515
- const raw = JSON.parse(await fsp131.readFile(indexFile3(), "utf8"));
260847
+ const raw = JSON.parse(await fsp132.readFile(indexFile3(), "utf8"));
260516
260848
  return Array.isArray(raw?.letters) ? raw.letters.filter(isLetter) : [];
260517
260849
  } catch {
260518
260850
  return [];
@@ -260535,7 +260867,7 @@ function inboxFollower() {
260535
260867
  removalFloor: INBOX_REMOVAL_FLOOR,
260536
260868
  ordered: true,
260537
260869
  digest: true,
260538
- serial: (fn) => serial6(fn),
260870
+ serial: (fn) => serial7(fn),
260539
260871
  refuse: refuse14,
260540
260872
  load: () => indexIo.load(),
260541
260873
  save: () => indexIo.save(),
@@ -260565,7 +260897,7 @@ function inboxFollower() {
260565
260897
  },
260566
260898
  purge: async () => {
260567
260899
  const removed = (await readIndex3()).length;
260568
- await fsp131.rm(indexFile3(), { force: true });
260900
+ await fsp132.rm(indexFile3(), { force: true });
260569
260901
  await markCopyOff("inbox");
260570
260902
  indexIo.reset();
260571
260903
  return { removed };
@@ -260581,23 +260913,23 @@ function inboxBodiesFollower() {
260581
260913
  log: log.notif,
260582
260914
  removalFloor: INBOX_REMOVAL_FLOOR,
260583
260915
  ordered: false,
260584
- serial: (fn) => serial6(fn),
260916
+ serial: (fn) => serial7(fn),
260585
260917
  refuse: refuse14,
260586
260918
  load: () => bodiesIo.load(),
260587
260919
  save: () => bodiesIo.save(),
260588
260920
  isRow: isBody,
260589
260921
  key: (b8) => b8.name,
260590
260922
  hash: (b8) => sha12(b8.body),
260591
- localKeys: async () => (await fsp131.readdir(bodiesDir()).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6)),
260923
+ localKeys: async () => (await fsp132.readdir(bodiesDir()).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6)),
260592
260924
  apply: async ({ rows, removeIds }) => {
260593
- for (const name of removeIds ?? []) if (BODY_FILE_RE.test(name)) await fsp131.rm(path243.join(bodiesDir(), name), { force: true });
260925
+ for (const name of removeIds ?? []) if (BODY_FILE_RE.test(name)) await fsp132.rm(path244.join(bodiesDir(), name), { force: true });
260594
260926
  const skipped = [];
260595
260927
  for (const b8 of rows ?? []) {
260596
260928
  if (Buffer.byteLength(b8.body) > INBOX_BODY_COPY_MAX_BYTES) {
260597
260929
  skipped.push(b8.name);
260598
260930
  continue;
260599
260931
  }
260600
- await writeCopyText(path243.join(bodiesDir(), b8.name), b8.body);
260932
+ await writeCopyText(path244.join(bodiesDir(), b8.name), b8.body);
260601
260933
  }
260602
260934
  return { skipped };
260603
260935
  },
@@ -260605,8 +260937,8 @@ function inboxBodiesFollower() {
260605
260937
  changed: () => {
260606
260938
  },
260607
260939
  purge: async () => {
260608
- const names2 = (await fsp131.readdir(bodiesDir()).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6));
260609
- for (const name of names2) await fsp131.rm(path243.join(bodiesDir(), name), { force: true });
260940
+ const names2 = (await fsp132.readdir(bodiesDir()).catch(() => [])).filter((n6) => BODY_FILE_RE.test(n6));
260941
+ for (const name of names2) await fsp132.rm(path244.join(bodiesDir(), name), { force: true });
260610
260942
  await markCopyOff("inbox-bodies");
260611
260943
  bodiesIo.reset();
260612
260944
  return { removed: names2.length };
@@ -260614,7 +260946,7 @@ function inboxBodiesFollower() {
260614
260946
  });
260615
260947
  return bodiesF;
260616
260948
  }
260617
- 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, refuse14, indexIo, bodiesIo, serial6, inboxF, bodiesF;
260949
+ 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, refuse14, indexIo, bodiesIo, serial7, inboxF, bodiesF;
260618
260950
  var init_inbox = __esm({
260619
260951
  "src/core/replication/kinds/inbox.ts"() {
260620
260952
  "use strict";
@@ -260627,9 +260959,9 @@ var init_inbox = __esm({
260627
260959
  INBOX_SCHEMA_VERSION = 1;
260628
260960
  INBOX_REMOVAL_FLOOR = 50;
260629
260961
  INBOX_BODY_COPY_MAX_BYTES = 4 * 1024 * 1024;
260630
- inboxDir = () => path243.join(WALNUT_HOME, "human-inbox");
260631
- indexFile3 = () => path243.join(inboxDir(), "index.json");
260632
- bodiesDir = () => path243.join(inboxDir(), "bodies");
260962
+ inboxDir = () => path244.join(WALNUT_HOME, "human-inbox");
260963
+ indexFile3 = () => path244.join(inboxDir(), "index.json");
260964
+ bodiesDir = () => path244.join(inboxDir(), "bodies");
260633
260965
  letterHashes = /* @__PURE__ */ new WeakMap();
260634
260966
  INBOX_KIND = {
260635
260967
  kind: "inbox",
@@ -260671,134 +261003,12 @@ var init_inbox = __esm({
260671
261003
  refuse14 = copyRefusal;
260672
261004
  indexIo = stateIo("inbox");
260673
261005
  bodiesIo = stateIo("inbox-bodies");
260674
- serial6 = serialChain();
261006
+ serial7 = serialChain();
260675
261007
  inboxF = null;
260676
261008
  bodiesF = null;
260677
261009
  }
260678
261010
  });
260679
261011
 
260680
- // src/core/replication/kinds/requests.ts
260681
- import fsp132 from "fs/promises";
260682
- import path244 from "path";
260683
- function forwardRequest(local, incoming) {
260684
- if (local && FINAL.has(local.status) && !FINAL.has(incoming.status)) return local;
260685
- return incoming;
260686
- }
260687
- function hashOf6(row) {
260688
- let h8 = hashes4.get(row);
260689
- if (h8 === void 0) {
260690
- h8 = sha12(JSON.stringify(row));
260691
- hashes4.set(row, h8);
260692
- }
260693
- return h8;
260694
- }
260695
- async function load7() {
260696
- if (state13) return state13;
260697
- let s4 = { asOf: 0, at: 0, order: [], hashes: {} };
260698
- try {
260699
- const raw = JSON.parse(await fsp132.readFile(STATE_FILE3(), "utf8"));
260700
- 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 };
260701
- } catch {
260702
- }
260703
- state13 = s4;
260704
- return s4;
260705
- }
260706
- async function save2() {
260707
- if (state13) await writeCopyFile(STATE_FILE3(), { v: 1, asOf: state13.asOf, at: state13.at, hashes: state13.hashes });
260708
- }
260709
- async function readStore8() {
260710
- try {
260711
- const raw = JSON.parse(await fsp132.readFile(STORE_FILE(), "utf8"));
260712
- return Array.isArray(raw?.requests) ? raw.requests.filter(isRow5) : [];
260713
- } catch {
260714
- return [];
260715
- }
260716
- }
260717
- function isRow5(v3) {
260718
- const r8 = v3;
260719
- return !!r8 && typeof r8 === "object" && typeof r8.id === "string" && !!r8.id && typeof r8.fromSessionId === "string" && typeof r8.status === "string" && typeof r8.createdAt === "string";
260720
- }
260721
- function requestsFollower() {
260722
- follower4 ??= createRowSetFollower({
260723
- kind: "requests",
260724
- schemaVersion: REQUESTS_SCHEMA_VERSION,
260725
- label: "requests copy",
260726
- log: log.session,
260727
- removalFloor: REQUESTS_REMOVAL_FLOOR,
260728
- ordered: false,
260729
- serial: (fn) => serial7(fn),
260730
- refuse: copyRefusal,
260731
- load: load7,
260732
- save: save2,
260733
- isRow: isRow5,
260734
- key: (r8) => r8.id,
260735
- localKeys: async () => (await readStore8()).map((r8) => r8.id),
260736
- apply: async ({ rows, removeIds }) => {
260737
- const byId = new Map((await readStore8()).map((r8) => [r8.id, r8]));
260738
- for (const id of removeIds ?? []) byId.delete(id);
260739
- for (const r8 of rows ?? []) {
260740
- const kept = forwardRequest(byId.get(r8.id), r8);
260741
- 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 });
260742
- byId.set(r8.id, kept);
260743
- }
260744
- await writeCopyFile(STORE_FILE(), { requests: [...byId.values()] });
260745
- return { skipped: [] };
260746
- },
260747
- held: async () => (await Promise.resolve().then(() => (init_journal_overlay(), journal_overlay_exports))).journalHeld("requests"),
260748
- changed: () => {
260749
- },
260750
- purge: async () => {
260751
- const removed = (await readStore8()).length;
260752
- await fsp132.rm(STORE_FILE(), { force: true });
260753
- await markCopyOff("requests");
260754
- state13 = null;
260755
- return { removed };
260756
- }
260757
- });
260758
- return follower4;
260759
- }
260760
- var REQUESTS_SCHEMA_VERSION, REQUESTS_REMOVAL_FLOOR, FINAL, hashes4, REQUESTS_KIND, STATE_FILE3, STORE_FILE, state13, serial7, follower4;
260761
- var init_requests = __esm({
260762
- "src/core/replication/kinds/requests.ts"() {
260763
- "use strict";
260764
- init_constants();
260765
- init_logging();
260766
- init_kind();
260767
- init_kind_follower();
260768
- init_gate();
260769
- REQUESTS_SCHEMA_VERSION = 1;
260770
- REQUESTS_REMOVAL_FLOOR = 50;
260771
- FINAL = /* @__PURE__ */ new Set(["replied", "notified", "expired"]);
260772
- hashes4 = /* @__PURE__ */ new WeakMap();
260773
- REQUESTS_KIND = {
260774
- kind: "requests",
260775
- schemaVersion: REQUESTS_SCHEMA_VERSION,
260776
- key: (r8) => r8.id,
260777
- hash: hashOf6,
260778
- ordered: false,
260779
- digest: false,
260780
- choice: "requests",
260781
- rows: async () => (await Promise.resolve().then(() => (init_session_requests(), session_requests_exports))).listAllSessionRequests(),
260782
- watch: (soon) => {
260783
- let stop2 = null;
260784
- let stopped2 = false;
260785
- void Promise.resolve().then(() => (init_session_requests(), session_requests_exports)).then(({ onSessionRequestsWritten: onSessionRequestsWritten2 }) => {
260786
- if (!stopped2) stop2 = onSessionRequestsWritten2(soon);
260787
- });
260788
- return () => {
260789
- stopped2 = true;
260790
- stop2?.();
260791
- };
260792
- }
260793
- };
260794
- STATE_FILE3 = () => path244.join(WALNUT_HOME, "cache", "replica", "requests.json");
260795
- STORE_FILE = () => path244.join(WALNUT_HOME, "session-requests.json");
260796
- state13 = null;
260797
- serial7 = serialChain();
260798
- follower4 = null;
260799
- }
260800
- });
260801
-
260802
261012
  // src/core/replication/kinds/sessions.ts
260803
261013
  import fsp133 from "fs/promises";
260804
261014
  import path245 from "path";
@@ -260829,11 +261039,11 @@ function projectedOf(row) {
260829
261039
  }
260830
261040
  return p6;
260831
261041
  }
260832
- function hashOf7(row) {
260833
- let h8 = hashes5.get(row);
261042
+ function hashOf8(row) {
261043
+ let h8 = hashes6.get(row);
260834
261044
  if (h8 === void 0) {
260835
261045
  h8 = sessionCopyHash(row);
260836
- hashes5.set(row, h8);
261046
+ hashes6.set(row, h8);
260837
261047
  }
260838
261048
  return h8;
260839
261049
  }
@@ -260853,7 +261063,7 @@ async function load8() {
260853
261063
  async function save3() {
260854
261064
  if (state14) await writeCopyFile(STATE_FILE4(), { v: 1, asOf: state14.asOf, at: state14.at, hashes: state14.hashes });
260855
261065
  }
260856
- function isRow6(v3) {
261066
+ function isRow7(v3) {
260857
261067
  const r8 = v3;
260858
261068
  return !!r8 && typeof r8 === "object" && !Array.isArray(r8) && typeof r8.claudeSessionId === "string" && r8.claudeSessionId.length > 0 && r8.claudeSessionId.length <= 200;
260859
261069
  }
@@ -260873,7 +261083,7 @@ function sessionsFollower() {
260873
261083
  refuse: copyRefusal,
260874
261084
  load: load8,
260875
261085
  save: save3,
260876
- isRow: isRow6,
261086
+ isRow: isRow7,
260877
261087
  key: (r8) => r8.claudeSessionId,
260878
261088
  hash: sessionCopyHash,
260879
261089
  localKeys: async () => (await Promise.resolve().then(() => (init_session_db(), session_db_exports))).sessionIdsInStore(),
@@ -260895,7 +261105,7 @@ function sessionsFollower() {
260895
261105
  });
260896
261106
  return follower5;
260897
261107
  }
260898
- 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;
261108
+ 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;
260899
261109
  var init_sessions2 = __esm({
260900
261110
  "src/core/replication/kinds/sessions.ts"() {
260901
261111
  "use strict";
@@ -260932,12 +261142,12 @@ var init_sessions2 = __esm({
260932
261142
  VOLATILE_SESSION_FIELDS = ["lastActiveAt", "activity", "contextTokens"];
260933
261143
  VOLATILE_SET = new Set(VOLATILE_SESSION_FIELDS);
260934
261144
  projected = /* @__PURE__ */ new WeakMap();
260935
- hashes5 = /* @__PURE__ */ new WeakMap();
261145
+ hashes6 = /* @__PURE__ */ new WeakMap();
260936
261146
  SESSIONS_KIND = {
260937
261147
  kind: "sessions",
260938
261148
  schemaVersion: SESSIONS_SCHEMA_VERSION,
260939
261149
  key: (s4) => s4.claudeSessionId,
260940
- hash: hashOf7,
261150
+ hash: hashOf8,
260941
261151
  ordered: false,
260942
261152
  digest: true,
260943
261153
  choice: "sessions",
@@ -260969,137 +261179,11 @@ var init_sessions2 = __esm({
260969
261179
  }
260970
261180
  });
260971
261181
 
260972
- // src/core/replication/kinds/personas.ts
260973
- var personas_exports = {};
260974
- __export(personas_exports, {
260975
- PERSONAS_KIND: () => PERSONAS_KIND,
260976
- PERSONAS_REMOVAL_FLOOR: () => PERSONAS_REMOVAL_FLOOR,
260977
- PERSONAS_SCHEMA_VERSION: () => PERSONAS_SCHEMA_VERSION,
260978
- _resetPersonasCopyForTesting: () => _resetPersonasCopyForTesting,
260979
- personasFollower: () => personasFollower,
260980
- readPersonaCopy: () => readPersonaCopy
260981
- });
260982
- function tools(v3) {
260983
- return Array.isArray(v3) && v3.length > 0 && v3.every((t3) => typeof t3 === "string" && TOOL_RE.test(t3)) ? [...v3] : void 0;
260984
- }
260985
- async function leaderRows2() {
260986
- const [{ getConsoleAgents: getConsoleAgents2 }, { buildLaneProfile: buildLaneProfile2 }, { getConfig: getConfig2 }, { getAskWalnutLaunchPrefs: getAskWalnutLaunchPrefs2 }] = await Promise.all([
260987
- Promise.resolve().then(() => (init_agent_registry(), agent_registry_exports)),
260988
- Promise.resolve().then(() => (init_personal_ai_lane(), personal_ai_lane_exports)),
260989
- Promise.resolve().then(() => (init_config_manager(), config_manager_exports)),
260990
- Promise.resolve().then(() => (init_ask_walnut_launch(), ask_walnut_launch_exports))
260991
- ]);
260992
- const config = await getConfig2();
260993
- const launch = await getAskWalnutLaunchPrefs2().catch(() => ({}));
260994
- const agents = [{ id: "general", name: "Walnut" }, ...(await getConsoleAgents2()).filter((a8) => a8.id !== "general").map((a8) => ({ id: a8.id, name: a8.name }))];
260995
- const rows = [];
260996
- for (const a8 of agents) {
260997
- if (!ID_RE5.test(a8.id)) continue;
260998
- try {
260999
- const { profile, effort } = await buildLaneProfile2(config, a8.id);
261000
- const prompt = profile.systemPrompt ?? "";
261001
- if (!prompt || Buffer.byteLength(prompt, "utf8") > MAX_PROMPT_BYTES) continue;
261002
- rows.push({
261003
- key: a8.id,
261004
- agentId: a8.id,
261005
- name: String(a8.name ?? a8.id).slice(0, 120),
261006
- systemPrompt: prompt,
261007
- systemPromptMode: profile.systemPromptMode === "replace" ? "replace" : "append",
261008
- ...tools(profile.allowedTools) ? { allowedTools: tools(profile.allowedTools) } : {},
261009
- ...tools(profile.tools) ? { tools: tools(profile.tools) } : {},
261010
- ...effort ? { effort } : {},
261011
- ...launch.model ? { launchModel: launch.model } : {},
261012
- ...launch.effort ? { launchEffort: launch.effort } : {}
261013
- });
261014
- } catch (err2) {
261015
- log.session.warn("copies: an agent persona was not rendered for the host", { agentId: a8.id, error: err2 instanceof Error ? err2.message : String(err2) });
261016
- }
261017
- }
261018
- return rows;
261019
- }
261020
- function hashOf8(row) {
261021
- let h8 = hashes6.get(row);
261022
- if (h8 === void 0) {
261023
- h8 = sha12(JSON.stringify(row));
261024
- hashes6.set(row, h8);
261025
- }
261026
- return h8;
261027
- }
261028
- function isRow7(v3) {
261029
- const r8 = v3;
261030
- if (!r8 || typeof r8 !== "object" || Array.isArray(r8)) return false;
261031
- if (Object.keys(r8).some((k8) => !ROW_KEYS.has(k8))) return false;
261032
- if (typeof r8.key !== "string" || r8.key !== r8.agentId || !ID_RE5.test(r8.key) || typeof r8.name !== "string") return false;
261033
- if (typeof r8.systemPrompt !== "string" || !r8.systemPrompt || Buffer.byteLength(r8.systemPrompt, "utf8") > MAX_PROMPT_BYTES) return false;
261034
- if (r8.systemPromptMode !== "append" && r8.systemPromptMode !== "replace") return false;
261035
- for (const k8 of ["allowedTools", "tools"]) if (r8[k8] !== void 0 && !tools(r8[k8])) return false;
261036
- 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;
261037
- return true;
261038
- }
261039
- function admit2(r8) {
261040
- return secretShapedValue(r8.systemPrompt) === null && secretShapedValue(r8.name) === null;
261041
- }
261042
- async function readPersonaCopy(agentId) {
261043
- const rows = await copy3.read();
261044
- return rows?.[agentId] ?? null;
261045
- }
261046
- function _resetPersonasCopyForTesting() {
261047
- copy3.reset();
261048
- }
261049
- var PERSONAS_SCHEMA_VERSION, PERSONAS_REMOVAL_FLOOR, MAX_PROMPT_BYTES, ID_RE5, TOOL_RE, hashes6, PERSONAS_KIND, ROW_KEYS, copy3, personasFollower;
261050
- var init_personas = __esm({
261051
- "src/core/replication/kinds/personas.ts"() {
261052
- "use strict";
261053
- init_logging();
261054
- init_config_allowlist();
261055
- init_kind();
261056
- init_file_copy();
261057
- PERSONAS_SCHEMA_VERSION = 1;
261058
- PERSONAS_REMOVAL_FLOOR = 0;
261059
- MAX_PROMPT_BYTES = 120 * 1024;
261060
- ID_RE5 = /^[A-Za-z0-9_-]{1,80}$/;
261061
- TOOL_RE = /^[A-Za-z0-9_.:*()/ -]{1,200}$/;
261062
- hashes6 = /* @__PURE__ */ new WeakMap();
261063
- PERSONAS_KIND = {
261064
- kind: "personas",
261065
- schemaVersion: PERSONAS_SCHEMA_VERSION,
261066
- key: (r8) => r8.key,
261067
- hash: hashOf8,
261068
- ordered: false,
261069
- digest: false,
261070
- choice: "personas",
261071
- rows: leaderRows2,
261072
- watch: (soon) => {
261073
- let stop2 = null;
261074
- let stopped2 = false;
261075
- void Promise.resolve().then(() => (init_config_manager(), config_manager_exports)).then((cm) => {
261076
- if (!stopped2) stop2 = cm.onConfigWritten(soon);
261077
- });
261078
- return () => {
261079
- stopped2 = true;
261080
- stop2?.();
261081
- };
261082
- }
261083
- };
261084
- ROW_KEYS = /* @__PURE__ */ new Set(["key", "agentId", "name", "systemPrompt", "systemPromptMode", "allowedTools", "tools", "effort", "launchModel", "launchEffort"]);
261085
- copy3 = createFileCopy({
261086
- kind: "personas",
261087
- schemaVersion: PERSONAS_SCHEMA_VERSION,
261088
- label: "personas copy",
261089
- removalFloor: PERSONAS_REMOVAL_FLOOR,
261090
- isRow: isRow7,
261091
- key: (r8) => r8.key,
261092
- admit: admit2
261093
- });
261094
- personasFollower = copy3.follower;
261095
- }
261096
- });
261097
-
261098
261182
  // src/core/replication/kinds/index.ts
261099
261183
  var kinds_exports = {};
261100
261184
  __export(kinds_exports, {
261185
+ copyKeepersOnly: () => copyKeepersOnly,
261101
261186
  copyKinds: () => copyKinds,
261102
- hostReplicaOnly: () => hostReplicaOnly,
261103
261187
  registerCopyFollowerKinds: () => registerCopyFollowerKinds,
261104
261188
  startCopyKinds: () => startCopyKinds
261105
261189
  });
@@ -261117,14 +261201,14 @@ function copyKinds() {
261117
261201
  PERSONAS_KIND
261118
261202
  ];
261119
261203
  }
261120
- function hostReplicaOnly(h8) {
261204
+ function copyKeepersOnly(h8) {
261121
261205
  return {
261122
261206
  kind: h8.kind,
261123
- // followerStep checks the version before the step: never `schema_newer` off a host replica.
261207
+ // followerStep checks the version before the step: never `schema_newer` where the kind is not kept.
261124
261208
  get schemaVersion() {
261125
- return keepsCopies() ? h8.schemaVersion : Number.MAX_SAFE_INTEGER;
261209
+ return keepsCopies(h8.kind) ? h8.schemaVersion : Number.MAX_SAFE_INTEGER;
261126
261210
  },
261127
- step: (op2, body7) => keepsCopies() ? h8.step(op2, body7) : { ok: false, status: 404, error: "unknown_kind" }
261211
+ step: (op2, body7) => keepsCopies(h8.kind) ? h8.step(op2, body7) : { ok: false, status: 404, error: "unknown_kind" }
261128
261212
  };
261129
261213
  }
261130
261214
  function registerCopyFollowerKinds() {
@@ -261139,7 +261223,7 @@ function registerCopyFollowerKinds() {
261139
261223
  prefsFollower(),
261140
261224
  configFollower(),
261141
261225
  personasFollower()
261142
- ].map((h8) => registerFollowerKind(hostReplicaOnly(h8)));
261226
+ ].map((h8) => registerFollowerKind(copyKeepersOnly(h8)));
261143
261227
  return () => {
261144
261228
  for (const u3 of off) u3();
261145
261229
  };
@@ -293249,10 +293333,13 @@ async function cleanupLaneClaudeMd(homeDir2 = WALNUT_HOME) {
293249
293333
  }
293250
293334
  }
293251
293335
  async function buildLaneProfile(config, agentId, opts2) {
293252
- const skillsIndex = await buildSessionSkillsPrompt().catch(() => "");
293253
- const memoryContext = await buildLaneMemoryContext().catch(() => "");
293336
+ const persona = opts2?.persona;
293337
+ const skillsIndex = persona ? "" : await buildSessionSkillsPrompt().catch(() => "");
293338
+ const memoryContext = persona ? "" : await buildLaneMemoryContext().catch(() => "");
293254
293339
  let profile;
293255
- if (agentId === "general") {
293340
+ if (persona) {
293341
+ profile = mergeProfiles({ systemPrompt: persona.systemPrompt, systemPromptMode: persona.systemPromptMode }, walnutMcpProfile());
293342
+ } else if (agentId === "general") {
293256
293343
  profile = personalAiProfile(config.user?.name ?? "the user", skillsIndex, memoryContext);
293257
293344
  } else {
293258
293345
  const { getAgent: getAgent2 } = await Promise.resolve().then(() => (init_agent_registry(), agent_registry_exports));
@@ -293262,7 +293349,8 @@ async function buildLaneProfile(config, agentId, opts2) {
293262
293349
  const contextBlock = await loadContextSources2(agentDef, {}).catch(() => "");
293263
293350
  profile = consoleAgentProfile(agentDef, skillsIndex, contextBlock);
293264
293351
  }
293265
- const effort = config.agent?.session_effort ?? "medium";
293352
+ const personaEffort = persona?.effort && LANE_EFFORTS.has(persona.effort) ? persona.effort : void 0;
293353
+ const effort = personaEffort ?? config.agent?.session_effort ?? "medium";
293266
293354
  if (!opts2?.conversationId) return { profile, effort };
293267
293355
  const base = profile.systemPrompt ?? "";
293268
293356
  const headroom = MAX_LANE_PROMPT_BYTES - Buffer.byteLength(base, "utf-8") - LANE_SEED_RESERVE_BYTES;
@@ -293532,7 +293620,7 @@ async function resolveLane(lane, agentId, conversationId, firstMessage, engine)
293532
293620
  });
293533
293621
  return { sessionId, created: true, engine: "claude" };
293534
293622
  }
293535
- var inFlight20, 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;
293623
+ var LANE_EFFORTS, inFlight20, 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;
293536
293624
  var init_personal_ai_lane = __esm({
293537
293625
  "src/core/sessions/personal-ai-lane.ts"() {
293538
293626
  "use strict";
@@ -293547,6 +293635,7 @@ var init_personal_ai_lane = __esm({
293547
293635
  init_default_engine();
293548
293636
  init_ask_profile_prefix();
293549
293637
  init_logging();
293638
+ LANE_EFFORTS = /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh", "max"]);
293550
293639
  inFlight20 = /* @__PURE__ */ new Map();
293551
293640
  LANE_MEMORY_HEADER = "## Standing memory (injected by Walnut)";
293552
293641
  MANAGED_LANE_CONTEXT_MARKERS = [
@@ -321314,9 +321403,13 @@ var init_task_replica_store = __esm({
321314
321403
  // src/core/replication/kinds/gate.ts
321315
321404
  var gate_exports = {};
321316
321405
  __export(gate_exports, {
321406
+ COMPANION_COPY_KINDS: () => COMPANION_COPY_KINDS,
321407
+ COPY_AS_OF_HEADER: () => COPY_AS_OF_HEADER,
321317
321408
  KIND_NOT_COPIED: () => KIND_NOT_COPIED,
321409
+ copyKindAsOf: () => copyKindAsOf,
321318
321410
  copyKindHeld: () => copyKindHeld,
321319
321411
  copyKindOff: () => copyKindOff,
321412
+ copyPath: () => copyPath,
321320
321413
  copyRefusal: () => copyRefusal,
321321
321414
  copyStateFile: () => copyStateFile,
321322
321415
  keepsCopies: () => keepsCopies,
@@ -321324,8 +321417,16 @@ __export(gate_exports, {
321324
321417
  });
321325
321418
  import fsp152 from "fs/promises";
321326
321419
  import path296 from "path";
321327
- function keepsCopies() {
321328
- return isHostReplicaProgram();
321420
+ function keepsCopies(kind) {
321421
+ if (isHostReplicaProgram()) return true;
321422
+ if (followerKind() !== "companion") return false;
321423
+ return kind === void 0 || COMPANION_COPY_KINDS.has(kind);
321424
+ }
321425
+ function copyPath(live6) {
321426
+ if (followerKind() !== "companion") return live6;
321427
+ const rel = path296.relative(WALNUT_HOME, live6);
321428
+ if (!rel || rel.startsWith("..") || path296.isAbsolute(rel)) throw new Error(`copyPath: ${live6} is not under the data dir`);
321429
+ return path296.join(WALNUT_HOME, "cache", "replica", "home", rel);
321329
321430
  }
321330
321431
  async function copyRefusal() {
321331
321432
  if (!keepsCopies()) return { status: 404, error: "unknown_kind" };
@@ -321346,20 +321447,26 @@ async function copyKindOff(kind) {
321346
321447
  }
321347
321448
  }
321348
321449
  async function copyKindHeld(kind) {
321450
+ return await copyKindAsOf(kind) !== null;
321451
+ }
321452
+ async function copyKindAsOf(kind) {
321349
321453
  try {
321350
321454
  const raw = JSON.parse(await fsp152.readFile(copyStateFile(kind), "utf8"));
321351
- return raw?.v === 1 && raw.off !== true && !!raw.hashes && typeof raw.hashes === "object";
321455
+ if (!(raw?.v === 1 && raw.off !== true && !!raw.hashes && typeof raw.hashes === "object")) return null;
321456
+ return Number(raw.asOf) || 0;
321352
321457
  } catch {
321353
- return false;
321458
+ return null;
321354
321459
  }
321355
321460
  }
321356
- var KIND_NOT_COPIED;
321461
+ var COMPANION_COPY_KINDS, COPY_AS_OF_HEADER, KIND_NOT_COPIED;
321357
321462
  var init_gate = __esm({
321358
321463
  "src/core/replication/kinds/gate.ts"() {
321359
321464
  "use strict";
321360
321465
  init_constants();
321361
321466
  init_server_role();
321362
321467
  init_kind_follower();
321468
+ COMPANION_COPY_KINDS = /* @__PURE__ */ new Set(["requests", "routines", "prefs", "personas"]);
321469
+ COPY_AS_OF_HEADER = "x-walnut-copy-as-of";
321363
321470
  KIND_NOT_COPIED = "kind_not_copied";
321364
321471
  }
321365
321472
  });