@cortexkit/opencode-magic-context 0.36.1 → 0.38.0

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.
Files changed (176) hide show
  1. package/README.md +2 -0
  2. package/dist/config/index.d.ts.map +1 -1
  3. package/dist/config/project-security.d.ts +2 -1
  4. package/dist/config/project-security.d.ts.map +1 -1
  5. package/dist/config/schema/magic-context.d.ts +10 -0
  6. package/dist/config/schema/magic-context.d.ts.map +1 -1
  7. package/dist/{conflict-warning-hook-mt0ttc4x.js → conflict-warning-hook-an4fxhwf.js} +3 -3
  8. package/dist/{derive-budgets-88mxk2w1.js → derive-budgets-da4yg3tz.js} +3 -2
  9. package/dist/features/magic-context/context-authority.d.ts.map +1 -1
  10. package/dist/features/magic-context/dreamer/classify-prompt.d.ts +5 -1
  11. package/dist/features/magic-context/dreamer/classify-prompt.d.ts.map +1 -1
  12. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  13. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  14. package/dist/features/magic-context/dreamer/manifest-parser.d.ts +8 -0
  15. package/dist/features/magic-context/dreamer/manifest-parser.d.ts.map +1 -1
  16. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts +7 -1
  17. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts.map +1 -1
  18. package/dist/features/magic-context/dreamer/map-memories.d.ts +18 -0
  19. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +5 -0
  21. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  23. package/dist/features/magic-context/dreamer/verify-prompt.d.ts +5 -1
  24. package/dist/features/magic-context/dreamer/verify-prompt.d.ts.map +1 -1
  25. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  26. package/dist/features/magic-context/fail-closed-block.d.ts +6 -1
  27. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  28. package/dist/features/magic-context/memory/embedding-openai.d.ts +3 -1
  29. package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
  30. package/dist/features/magic-context/memory/project-identity.d.ts +6 -0
  31. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  32. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  33. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  34. package/dist/features/magic-context/reclaim-protection.d.ts +13 -0
  35. package/dist/features/magic-context/reclaim-protection.d.ts.map +1 -0
  36. package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
  37. package/dist/features/magic-context/smart-notes/wake-plane.d.ts +21 -0
  38. package/dist/features/magic-context/smart-notes/wake-plane.d.ts.map +1 -0
  39. package/dist/features/magic-context/storage-db.d.ts +19 -3
  40. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  41. package/dist/features/magic-context/storage-meta-persisted.d.ts +23 -0
  42. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  43. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  44. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  45. package/dist/features/magic-context/storage-primers.d.ts +11 -0
  46. package/dist/features/magic-context/storage-primers.d.ts.map +1 -1
  47. package/dist/features/magic-context/storage-schema-helpers.d.ts.map +1 -1
  48. package/dist/features/magic-context/storage-tags.d.ts +13 -5
  49. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  50. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +7 -0
  51. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
  52. package/dist/features/magic-context/window-report-ledger.d.ts +70 -0
  53. package/dist/features/magic-context/window-report-ledger.d.ts.map +1 -0
  54. package/dist/hooks/auto-update-checker/checker.d.ts +8 -1
  55. package/dist/hooks/auto-update-checker/checker.d.ts.map +1 -1
  56. package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/channel2-cycle.d.ts +16 -0
  58. package/dist/hooks/magic-context/channel2-cycle.d.ts.map +1 -0
  59. package/dist/hooks/magic-context/channel2-delivery.d.ts +3 -9
  60. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  61. package/dist/hooks/magic-context/command-handler.d.ts +2 -0
  62. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  63. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +33 -103
  64. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  65. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  66. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  67. package/dist/hooks/magic-context/event-resolvers.d.ts +4 -0
  68. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  69. package/dist/hooks/magic-context/execute-status.d.ts +3 -1
  70. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  71. package/dist/hooks/magic-context/fold-execution-gate.d.ts +2 -0
  72. package/dist/hooks/magic-context/fold-execution-gate.d.ts.map +1 -0
  73. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  74. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  75. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  76. package/dist/hooks/magic-context/live-session-state.d.ts +3 -0
  77. package/dist/hooks/magic-context/live-session-state.d.ts.map +1 -1
  78. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  79. package/dist/hooks/magic-context/lkg-slot.d.ts +20 -0
  80. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  81. package/dist/hooks/magic-context/module-state-sync.d.ts +8 -0
  82. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  83. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  84. package/dist/hooks/magic-context/module-wire.d.ts +6 -1
  85. package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
  86. package/dist/hooks/magic-context/rust-mode-transform.d.ts +21 -2
  87. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  88. package/dist/hooks/magic-context/strip-content.d.ts +27 -0
  89. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  90. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  91. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  92. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +78 -0
  93. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -0
  94. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
  95. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +14 -3
  96. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  97. package/dist/hooks/magic-context/transform.d.ts +10 -0
  98. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  99. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  100. package/dist/{index-nsx2n9eg.js → index-4cz5nfxf.js} +3 -3
  101. package/dist/{index-f1tnb3vm.js → index-8pqfcghm.js} +21 -9
  102. package/dist/index-9zhhvr4w.js +733 -0
  103. package/dist/{index-zp6x6s6a.js → index-cae89eas.js} +25 -6
  104. package/dist/index-cgyfn1s2.js +53 -0
  105. package/dist/{index-3zqcdwqr.js → index-crke4z5j.js} +7 -4
  106. package/dist/{index-1skzp4dc.js → index-mmvhrqqb.js} +1991 -274
  107. package/dist/{index-tsgs7td8.js → index-pck9vadr.js} +1 -1
  108. package/dist/{index-3tnkymva.js → index-sw8gnq34.js} +1 -1
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +1714 -988
  111. package/dist/plugin/hooks/create-session-hooks.d.ts +3 -0
  112. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  113. package/dist/plugin/messages-transform.d.ts.map +1 -1
  114. package/dist/plugin/rpc-handlers.d.ts +2 -0
  115. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  116. package/dist/{recomp-orchestrator-a0g9b52q.js → recomp-orchestrator-jsde4ygw.js} +7 -6
  117. package/dist/{safe-notification-target-c11fdda2.js → safe-notification-target-b693f9x3.js} +2 -2
  118. package/dist/{send-session-notification-bgtf4853.js → send-session-notification-dxske5zm.js} +3 -3
  119. package/dist/shared/conflict-detector.d.ts +63 -0
  120. package/dist/shared/conflict-detector.d.ts.map +1 -1
  121. package/dist/shared/harness-provider-map.d.ts +8 -0
  122. package/dist/shared/harness-provider-map.d.ts.map +1 -1
  123. package/dist/shared/logger.d.ts +8 -0
  124. package/dist/shared/logger.d.ts.map +1 -1
  125. package/dist/shared/models-dev-cache.d.ts +7 -0
  126. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  127. package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
  128. package/dist/shared/prompt-surface.d.ts +2 -0
  129. package/dist/shared/prompt-surface.d.ts.map +1 -1
  130. package/dist/shared/rpc-client.d.ts.map +1 -1
  131. package/dist/shared/rpc-server.d.ts.map +1 -1
  132. package/dist/shared/rpc-types.d.ts +29 -0
  133. package/dist/shared/rpc-types.d.ts.map +1 -1
  134. package/dist/shared/rpc-utils.d.ts +28 -9
  135. package/dist/shared/rpc-utils.d.ts.map +1 -1
  136. package/dist/shared/tail-hygiene-status.d.ts +15 -0
  137. package/dist/shared/tail-hygiene-status.d.ts.map +1 -0
  138. package/dist/shared/window-geometry.d.ts +90 -0
  139. package/dist/shared/window-geometry.d.ts.map +1 -0
  140. package/dist/{storage-meta-session-df9tstzr.js → storage-meta-session-mk4gsnke.js} +4 -3
  141. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  142. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  143. package/dist/tui/data/context-db.d.ts.map +1 -1
  144. package/dist/tui-compiled/data/context-db.d.ts.map +1 -1
  145. package/package.json +3 -1
  146. package/src/config/index.ts +2 -0
  147. package/src/config/latch-permanence-guard.test.ts +218 -0
  148. package/src/config/project-security.ts +10 -1
  149. package/src/config/schema/magic-context.ts +12 -2
  150. package/src/shared/__fixtures__/window-overlay.v1.json +337 -0
  151. package/src/shared/conflict-detector.test.ts +176 -1
  152. package/src/shared/conflict-detector.ts +126 -3
  153. package/src/shared/harness-provider-map.test.ts +20 -0
  154. package/src/shared/harness-provider-map.ts +19 -0
  155. package/src/shared/logger.test.ts +119 -0
  156. package/src/shared/logger.ts +33 -15
  157. package/src/shared/models-dev-cache.test.ts +42 -0
  158. package/src/shared/models-dev-cache.ts +62 -9
  159. package/src/shared/prompt-surface-runtime.ts +5 -3
  160. package/src/shared/prompt-surface.test.ts +38 -0
  161. package/src/shared/prompt-surface.ts +15 -2
  162. package/src/shared/rpc-client.ts +4 -2
  163. package/src/shared/rpc-server.ts +1 -0
  164. package/src/shared/rpc-types.ts +30 -0
  165. package/src/shared/rpc-utils.test.ts +162 -13
  166. package/src/shared/rpc-utils.ts +224 -31
  167. package/src/shared/tail-hygiene-status.ts +57 -0
  168. package/src/shared/window-geometry.test.ts +342 -0
  169. package/src/shared/window-geometry.ts +626 -0
  170. package/src/tui/data/context-db.ts +5 -0
  171. package/src/tui/index.tsx +33 -1
  172. package/src/tui/slots/sidebar-content.tsx +17 -5
  173. package/src/tui-compiled/data/context-db.ts +5 -0
  174. package/src/tui-compiled/index.tsx +359 -273
  175. package/src/tui-compiled/slots/sidebar-content.tsx +316 -287
  176. package/dist/index-wgvxkqpx.js +0 -342
@@ -1,9 +1,8 @@
1
1
  import {
2
2
  deriveTriggerBudget,
3
3
  modelSupportsVision,
4
- piModelRefToCanonical,
5
4
  shouldEnforcePrivateStoragePermissions
6
- } from "./index-wgvxkqpx.js";
5
+ } from "./index-9zhhvr4w.js";
7
6
  import {
8
7
  parseProviderModel
9
8
  } from "./index-td9depx5.js";
@@ -11,10 +10,11 @@ import {
11
10
  describeError,
12
11
  getErrorMessage,
13
12
  sendIgnoredMessage
14
- } from "./index-nsx2n9eg.js";
13
+ } from "./index-4cz5nfxf.js";
15
14
  import {
16
15
  buildToolArcs,
17
16
  buildTrueRawTokenIndex,
17
+ byteSize,
18
18
  clearCachedM0M1,
19
19
  clearCompressionDepth,
20
20
  clearCompressionDepthRange,
@@ -35,13 +35,17 @@ import {
35
35
  readSessionChunk,
36
36
  stableStringify,
37
37
  updateSessionMeta
38
- } from "./index-3zqcdwqr.js";
38
+ } from "./index-crke4z5j.js";
39
+ import {
40
+ modelRefLookupOrder,
41
+ piModelRefToCanonical
42
+ } from "./index-cgyfn1s2.js";
39
43
  import {
40
44
  Database,
41
45
  closeQuietly,
42
46
  getMessageTimesFromOpenCodeDb,
43
47
  withPrivilegedWriter
44
- } from "./index-3tnkymva.js";
48
+ } from "./index-sw8gnq34.js";
45
49
  import {
46
50
  detectConfigFile
47
51
  } from "./index-8mtsfhyg.js";
@@ -51,7 +55,7 @@ import {
51
55
  import {
52
56
  log,
53
57
  sessionLog
54
- } from "./index-f1tnb3vm.js";
58
+ } from "./index-8pqfcghm.js";
55
59
  import {
56
60
  ensureCortexKitArtifactGitignore,
57
61
  getDataDir,
@@ -414,24 +418,44 @@ function isMagicContextHiddenAgentName(agent) {
414
418
  return false;
415
419
  }
416
420
  var MAX_FORMATTED_BLOCKING_PROCESSES = 8;
421
+ function normalizeFailClosedProcessKind(process2) {
422
+ switch (process2.kind) {
423
+ case "OpenCode server":
424
+ case "OpenCode instance (TUI/CLI)":
425
+ case "Pi":
426
+ case "process":
427
+ return process2.kind;
428
+ }
429
+ switch (process2.harness?.trim().toLowerCase()) {
430
+ case "opencode server":
431
+ return "OpenCode server";
432
+ case "opencode instance (tui/cli)":
433
+ case "opencode instance":
434
+ return "OpenCode instance (TUI/CLI)";
435
+ case "pi":
436
+ case "pi harness":
437
+ case "omp":
438
+ return "Pi";
439
+ default:
440
+ return "process";
441
+ }
442
+ }
417
443
  function formatFailClosedBlockingProcesses(processes) {
418
444
  const uniqueProcesses = new Map;
419
445
  for (const process2 of processes) {
420
- if (!process2.harness.trim() || !Number.isInteger(process2.pid) || process2.pid <= 0)
446
+ if (!Number.isInteger(process2.pid) || process2.pid <= 0)
421
447
  continue;
422
- uniqueProcesses.set(`${process2.harness}\x00${process2.pid}`, {
423
- harness: process2.harness.trim(),
424
- pid: process2.pid
425
- });
448
+ const kind = normalizeFailClosedProcessKind(process2);
449
+ uniqueProcesses.set(`${kind}\x00${process2.pid}`, { kind, pid: process2.pid });
426
450
  }
427
451
  const entries = [...uniqueProcesses.values()];
428
452
  const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
429
- const rendered = visible.map(({ harness, pid }) => `${harness} (PID ${pid})`);
453
+ const rendered = visible.map(({ kind, pid }) => `${kind} (PID ${pid})`);
430
454
  const omitted = entries.length - visible.length;
431
455
  if (omitted > 0)
432
456
  rendered.push(`${omitted} more blocking process(es)`);
433
457
  if (rendered.length === 0)
434
- return "a live harness process";
458
+ return "a live process";
435
459
  if (rendered.length === 1)
436
460
  return rendered[0];
437
461
  const last = rendered.pop();
@@ -441,9 +465,9 @@ function formatFailClosedBlockingMessage(reason) {
441
465
  if (reason.kind === "migration_guard") {
442
466
  if (reason.unreadableFile) {
443
467
  const arm = reason.unreadableArm ?? "io";
444
- const recovery = arm === "io" ? `If no OpenCode server is running, it is safe to delete ${reason.unreadableFile} and retry.` : `The file may be a recent incomplete write; retry after the file is older than the ten-minute grace window, or stop OpenCode before deleting it.`;
468
+ const recovery = arm === "io" ? `If none of these processes are running, it is safe to delete ${reason.unreadableFile} and retry.` : `The file may be a recent incomplete write; retry after the file is older than the ten-minute grace window, or stop the relevant process before deleting it.`;
445
469
  return [
446
- `Magic Context cannot migrate the shared database because RPC discovery file ${reason.unreadableFile} is uncertain (${arm} arm), so the absence of a live OpenCode server cannot be proven.`,
470
+ `Magic Context cannot migrate the shared database because RPC discovery file ${reason.unreadableFile} is uncertain (${arm} arm), so the absence of a live process cannot be proven.`,
447
471
  recovery,
448
472
  `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
449
473
  ].join(" ");
@@ -566,7 +590,7 @@ import {
566
590
  statSync as statSync2,
567
591
  unlinkSync
568
592
  } from "node:fs";
569
- import { basename, dirname, join as join3 } from "node:path";
593
+ import { basename, dirname, join as join3, resolve } from "node:path";
570
594
 
571
595
  // src/plugin/boot-quiet.ts
572
596
  var BOOT_QUIET_MS = 120000;
@@ -602,20 +626,24 @@ function rpcPortFilePath(storageDir, directory, pid = process.pid, instanceId) {
602
626
  }
603
627
  function isPidAlive(pid) {
604
628
  if (!Number.isInteger(pid) || pid <= 0)
605
- return false;
629
+ return "dead";
630
+ if (rpcIdentityPlatform === "win32")
631
+ return readWindowsProcess(pid).state;
606
632
  try {
607
- process.kill(pid, 0);
608
- return true;
609
- } catch (err) {
610
- return err.code === "EPERM";
633
+ rpcIdentityProcessKill(pid, 0);
634
+ return "alive";
635
+ } catch (error) {
636
+ return error.code === "ESRCH" ? "dead" : "inconclusive";
611
637
  }
612
638
  }
613
639
  var RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000;
614
640
  var LINUX_CLOCK_TICKS_PER_SECOND = 100;
615
641
  var PS_PROBE_TIMEOUT_MS = 1000;
616
642
  var OPEN_CODE_COMMAND_MARKERS = ["opencode", "node", "bun", "electron"];
643
+ var TASKLIST_NO_TASKS_PATTERN = /^INFO:\s+No tasks are running which match the specified criteria\.?$/im;
617
644
  var rpcIdentityReadFileSync = readFileSync;
618
645
  var rpcIdentityExecFileSync = execFileSync;
646
+ var rpcIdentityProcessKill = process.kill;
619
647
  var rpcProcessListExecFileSync = execFileSync;
620
648
  var rpcIdentityPlatform = process.platform;
621
649
  var rpcIdentityNowMs = () => Date.now();
@@ -645,7 +673,8 @@ function readPsProcessStartTime(pid) {
645
673
  try {
646
674
  const output = rpcIdentityExecFileSync("ps", ["-p", String(pid), "-o", "lstart="], {
647
675
  encoding: "utf8",
648
- timeout: PS_PROBE_TIMEOUT_MS
676
+ timeout: PS_PROBE_TIMEOUT_MS,
677
+ stdio: ["ignore", "pipe", "pipe"]
649
678
  });
650
679
  const processStartTime = Date.parse(String(output).trim());
651
680
  return Number.isFinite(processStartTime) ? processStartTime : null;
@@ -653,6 +682,70 @@ function readPsProcessStartTime(pid) {
653
682
  return null;
654
683
  }
655
684
  }
685
+ function parseCsvLine(line) {
686
+ const fields = [];
687
+ let field = "";
688
+ let quoted = false;
689
+ for (let index = 0;index < line.length; index += 1) {
690
+ const character = line[index];
691
+ if (character === '"') {
692
+ if (quoted && line[index + 1] === '"') {
693
+ field += '"';
694
+ index += 1;
695
+ } else {
696
+ quoted = !quoted;
697
+ }
698
+ } else if (character === "," && !quoted) {
699
+ fields.push(field);
700
+ field = "";
701
+ } else {
702
+ field += character;
703
+ }
704
+ }
705
+ if (quoted)
706
+ return null;
707
+ fields.push(field);
708
+ return fields;
709
+ }
710
+ function parseTasklistOutput(output) {
711
+ const entries = [];
712
+ let sawHeader = false;
713
+ for (const rawLine of output.split(/\r?\n/)) {
714
+ const line = rawLine.trim();
715
+ if (!line)
716
+ continue;
717
+ if (TASKLIST_NO_TASKS_PATTERN.test(line))
718
+ return [];
719
+ const fields = parseCsvLine(line);
720
+ if (!fields)
721
+ continue;
722
+ if (fields[1]?.trim().toLowerCase() === "pid") {
723
+ sawHeader = true;
724
+ continue;
725
+ }
726
+ const pid = Number(fields[1]);
727
+ if (!Number.isInteger(pid) || pid <= 0 || !fields[0])
728
+ continue;
729
+ entries.push({ pid, command: fields[0] });
730
+ }
731
+ return entries.length > 0 || sawHeader ? entries : null;
732
+ }
733
+ function readWindowsProcess(pid) {
734
+ try {
735
+ const output = rpcIdentityExecFileSync("tasklist", ["/FO", "CSV", "/FI", `PID eq ${pid}`], {
736
+ encoding: "utf8",
737
+ timeout: PS_PROBE_TIMEOUT_MS,
738
+ stdio: ["ignore", "pipe", "pipe"]
739
+ });
740
+ const entries = parseTasklistOutput(String(output));
741
+ if (entries === null)
742
+ return { state: "inconclusive" };
743
+ const process2 = entries.find((entry) => entry.pid === pid);
744
+ return process2 ? { state: "alive", command: process2.command } : { state: "dead" };
745
+ } catch {
746
+ return { state: "inconclusive" };
747
+ }
748
+ }
656
749
  function readLinuxProcessCommand(pid) {
657
750
  try {
658
751
  return String(rpcIdentityReadFileSync(`/proc/${pid}/cmdline`, "utf8"));
@@ -664,40 +757,86 @@ function readPsProcessCommand(pid) {
664
757
  try {
665
758
  const output = rpcIdentityExecFileSync("ps", ["-p", String(pid), "-o", "command="], {
666
759
  encoding: "utf8",
667
- timeout: PS_PROBE_TIMEOUT_MS
760
+ timeout: PS_PROBE_TIMEOUT_MS,
761
+ stdio: ["ignore", "pipe", "pipe"]
668
762
  });
669
763
  return String(output);
670
764
  } catch {
671
765
  return null;
672
766
  }
673
767
  }
768
+ function readProcessCommand(pid) {
769
+ if (!Number.isInteger(pid) || pid <= 0)
770
+ return null;
771
+ return rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(pid) : rpcIdentityPlatform === "win32" ? readWindowsProcess(pid).command ?? null : readPsProcessCommand(pid);
772
+ }
773
+ function executableName(token) {
774
+ return (token ?? "").replace(/^['"]|['"]$/g, "").split("/").at(-1) ?? "";
775
+ }
776
+ function commandTokens(command) {
777
+ return command.toLowerCase().replaceAll("\\", "/").replaceAll("\x00", " ").split(/\s+/).map((token) => token.replace(/^['"]|['"]$/g, "")).filter(Boolean);
778
+ }
779
+ function commandHasOpenCodeExecutable(tokens) {
780
+ return tokens.findIndex((token) => {
781
+ const executable = executableName(token).replace(/\.(?:exe|cmd)$/, "");
782
+ return executable === "opencode" || executable.endsWith("/opencode");
783
+ });
784
+ }
785
+ function commandHasPiExecutable(tokens) {
786
+ for (let index = 0;index < tokens.length; index += 1) {
787
+ const executable = executableName(tokens[index]).replace(/\.(?:exe|cmd)$/, "");
788
+ if (["pi", "omp", "oh-my-pi"].includes(executable))
789
+ return true;
790
+ if (["node", "bun", "deno"].includes(executable)) {
791
+ const script = executableName(tokens[index + 1]).replace(/\.(?:exe|cmd)$/, "");
792
+ if (["pi", "pi.js", "pi.mjs", "pi.cjs"].includes(script) || tokens[index + 1]?.includes("pi-coding-agent")) {
793
+ return true;
794
+ }
795
+ }
796
+ }
797
+ return false;
798
+ }
799
+ function classifyProcessKind(command) {
800
+ if (!command)
801
+ return "process";
802
+ const tokens = commandTokens(command);
803
+ const openCodeIndex = commandHasOpenCodeExecutable(tokens);
804
+ if (openCodeIndex >= 0) {
805
+ const args = tokens.slice(openCodeIndex + 1);
806
+ if (args.some((token) => token === "serve" || token === "--serve" || token.startsWith("--serve="))) {
807
+ return "OpenCode server";
808
+ }
809
+ return "OpenCode instance (TUI/CLI)";
810
+ }
811
+ return commandHasPiExecutable(tokens) ? "Pi" : "process";
812
+ }
674
813
  function commandLooksLikeOpenCode(command) {
675
814
  const normalized = command.toLowerCase();
676
815
  return OPEN_CODE_COMMAND_MARKERS.some((marker) => normalized.includes(marker));
677
816
  }
678
817
  function isPidIdentityPlausible(record) {
679
818
  if (!Number.isInteger(record.pid) || record.pid <= 0)
680
- return false;
819
+ return "implausible";
681
820
  if (Number.isFinite(record.started_at) && record.started_at > 0) {
682
- const processStartTime = rpcIdentityPlatform === "linux" ? readLinuxProcessStartTime(record.pid) : readPsProcessStartTime(record.pid);
821
+ const processStartTime = rpcIdentityPlatform === "linux" ? readLinuxProcessStartTime(record.pid) : rpcIdentityPlatform === "win32" ? null : readPsProcessStartTime(record.pid);
683
822
  if (processStartTime === null)
684
- return true;
685
- return processStartTime <= record.started_at + RPC_IDENTITY_SKEW_TOLERANCE_MS;
823
+ return "inconclusive";
824
+ return processStartTime <= record.started_at + RPC_IDENTITY_SKEW_TOLERANCE_MS ? "plausible" : "implausible";
686
825
  }
687
- const command = rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(record.pid) : readPsProcessCommand(record.pid);
826
+ const command = rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(record.pid) : rpcIdentityPlatform === "win32" ? readWindowsProcess(record.pid).command ?? null : readPsProcessCommand(record.pid);
688
827
  if (command === null)
689
- return true;
690
- return commandLooksLikeOpenCode(command);
828
+ return "inconclusive";
829
+ return commandLooksLikeOpenCode(command) ? "plausible" : "implausible";
691
830
  }
692
831
  function commandLooksLikePi(command) {
693
832
  const normalized = command.trim().toLowerCase().replaceAll("\\", "/");
694
833
  const tokens = normalized.split(/\s+/).filter(Boolean);
695
- const executableName = (token) => (token ?? "").split("/").at(-1) ?? "";
696
- const first = executableName(tokens[0]).replace(/\.exe$/, "");
834
+ const executableName2 = (token) => (token ?? "").split("/").at(-1) ?? "";
835
+ const first = executableName2(tokens[0]).replace(/\.exe$/, "");
697
836
  if (["pi", "pi.cmd", "omp", "oh-my-pi"].includes(first))
698
837
  return true;
699
838
  if (["node", "bun", "deno"].includes(first)) {
700
- const script = executableName(tokens[1]);
839
+ const script = executableName2(tokens[1]);
701
840
  return ["pi", "pi.js", "pi.mjs", "pi.cjs"].includes(script) || normalized.includes("pi-coding-agent");
702
841
  }
703
842
  return false;
@@ -705,20 +844,39 @@ function commandLooksLikePi(command) {
705
844
  function inspectLivePiProcesses() {
706
845
  if (false) {}
707
846
  try {
708
- const output = String(rpcProcessListExecFileSync("ps", ["-axo", "pid=,command="], {
847
+ const isWindows = rpcIdentityPlatform === "win32";
848
+ const output = String(rpcProcessListExecFileSync(isWindows ? "tasklist" : "ps", isWindows ? ["/FO", "CSV"] : ["-axo", "pid=,command="], {
709
849
  encoding: "utf8",
710
- timeout: PS_PROBE_TIMEOUT_MS
850
+ timeout: PS_PROBE_TIMEOUT_MS,
851
+ stdio: ["ignore", "pipe", "pipe"]
711
852
  }));
712
853
  const pids = new Set;
713
- for (const line of output.split(/\r?\n/)) {
714
- const match = /^\s*(\d+)\s+(.+)$/.exec(line);
715
- if (!match)
716
- continue;
717
- const pid = Number(match[1]);
718
- if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid)
719
- continue;
720
- if (commandLooksLikePi(match[2]))
721
- pids.add(pid);
854
+ if (isWindows) {
855
+ const entries = parseTasklistOutput(output);
856
+ if (entries === null) {
857
+ return {
858
+ state: "unreadable",
859
+ processIds: [],
860
+ error: "tasklist output unavailable"
861
+ };
862
+ }
863
+ for (const entry of entries) {
864
+ if (entry.pid === process.pid)
865
+ continue;
866
+ if (commandLooksLikePi(entry.command))
867
+ pids.add(entry.pid);
868
+ }
869
+ } else {
870
+ for (const line of output.split(/\r?\n/)) {
871
+ const match = /^\s*(\d+)\s+(.+)$/.exec(line);
872
+ if (!match)
873
+ continue;
874
+ const pid = Number(match[1]);
875
+ if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid)
876
+ continue;
877
+ if (commandLooksLikePi(match[2]))
878
+ pids.add(pid);
879
+ }
722
880
  }
723
881
  return { state: "known", processIds: [...pids].sort((left, right) => left - right) };
724
882
  } catch (error) {
@@ -729,9 +887,6 @@ function inspectLivePiProcesses() {
729
887
  };
730
888
  }
731
889
  }
732
- function discoverLivePiProcessIds() {
733
- return inspectLivePiProcesses().processIds;
734
- }
735
890
  function parseRpcPortFile(content, fallbackPid = 0) {
736
891
  const trimmed = content.trim();
737
892
  if (!trimmed)
@@ -748,6 +903,8 @@ function parseRpcPortFile(content, fallbackPid = 0) {
748
903
  port: port2,
749
904
  pid,
750
905
  started_at: Number.isFinite(startedAt) ? startedAt : 0,
906
+ kind: typeof parsed.kind === "string" ? parsed.kind : undefined,
907
+ harness: typeof parsed.harness === "string" ? parsed.harness : undefined,
751
908
  token: typeof parsed.token === "string" ? parsed.token : undefined,
752
909
  instance_id: typeof parsed.instance_id === "string" ? parsed.instance_id : undefined
753
910
  };
@@ -1415,6 +1572,7 @@ function prepareMirrorPageStatements(db) {
1415
1572
  return {
1416
1573
  identityByModule: db.prepare("SELECT context_row_id FROM mirror_identity WHERE domain = ? AND module_project = ? AND module_row_id = ?"),
1417
1574
  insertIdentity: db.prepare("INSERT OR IGNORE INTO mirror_identity(domain, module_project, module_row_id, context_row_id) VALUES (?, ?, ?, ?)"),
1575
+ deleteIdentityByContext: db.prepare("DELETE FROM mirror_identity WHERE domain = ? AND context_row_id = ?"),
1418
1576
  deleteLiveMemory: db.prepare("DELETE FROM mirror_live_memory_rows WHERE module_project = ? AND module_row_id = ?"),
1419
1577
  deletePendingReferencesForMemory: db.prepare("DELETE FROM mirror_pending_references WHERE domain = ? AND module_project = ? AND (module_row_id = ? OR target_module_row_id = ?)"),
1420
1578
  deleteIdentity: db.prepare("DELETE FROM mirror_identity WHERE domain = ? AND module_project = ? AND module_row_id = ?"),
@@ -1466,7 +1624,7 @@ function prepareMirrorPageStatements(db) {
1466
1624
  check_quarantined_until = ?, check_next_due_at = ?, check_compiled_at = ?, check_false_since_at = ?,
1467
1625
  check_last_liveness_at = ?, last_checked_at = ?, check_status = ?, check_version = ?,
1468
1626
  policy_version = ?, anchor_block_id = ?, anchor_ordinal = ?, created_at = ?, updated_at = ? WHERE id = ?`),
1469
- upsertNoteRevision: db.prepare("INSERT INTO mirror_note_revisions(module_project, module_row_id, context_row_id, status_version) VALUES (?, ?, ?, ?) ON CONFLICT(module_project, module_row_id) DO UPDATE SET context_row_id = excluded.context_row_id, status_version = excluded.status_version"),
1627
+ upsertNoteRevision: db.prepare("INSERT OR REPLACE INTO mirror_note_revisions(module_project, module_row_id, context_row_id, status_version) VALUES (?, ?, ?, ?)"),
1470
1628
  translateMemoryReferences: db.prepare(`UPDATE memories
1471
1629
  SET superseded_by_memory_id = (
1472
1630
  SELECT target.context_row_id
@@ -1551,6 +1709,9 @@ function rememberIdentity(db, domain, moduleProject, moduleRowId, contextRowId,
1551
1709
  const existing = mirrorIdentity(db, domain, moduleProject, moduleRowId, statements);
1552
1710
  if (existing)
1553
1711
  return;
1712
+ if (domain === "notes") {
1713
+ (statements?.deleteIdentityByContext ?? db.prepare("DELETE FROM mirror_identity WHERE domain = ? AND context_row_id = ?")).run(domain, contextRowId);
1714
+ }
1554
1715
  (statements?.insertIdentity ?? db.prepare("INSERT OR IGNORE INTO mirror_identity(domain, module_project, module_row_id, context_row_id) VALUES (?, ?, ?, ?)")).run(domain, moduleProject, moduleRowId, contextRowId);
1555
1716
  }
1556
1717
  function contextMemoryId(db, domain, moduleProject, row, moduleRowId, statements) {
@@ -2133,6 +2294,8 @@ function healAllNullColumns(db) {
2133
2294
  ["stripped_placeholder_ids", ""],
2134
2295
  ["stale_reduce_stripped_ids", ""],
2135
2296
  ["processed_image_stripped_ids", ""],
2297
+ ["merged_reasoning_stripped_ids", ""],
2298
+ ["trailing_blank_decisions", ""],
2136
2299
  ["memory_block_cache", ""],
2137
2300
  ["memory_block_ids", ""],
2138
2301
  ["compaction_marker_state", ""],
@@ -2244,6 +2407,7 @@ import path from "node:path";
2244
2407
  var GIT_TIMEOUT_MS = 5000;
2245
2408
  var TRANSIENT_FAILURE_COOLDOWN_MS = 5 * 60 * 1000;
2246
2409
  var identityCache = new Map;
2410
+ var linkedGitWorktreeCache = new Map;
2247
2411
  var lastKnownGitIdentityCache = new Map;
2248
2412
  var directoryFallbackCache = new Map;
2249
2413
  var transientFailureCooldown = new Map;
@@ -2458,7 +2622,12 @@ function takeDubiousOwnershipProjectIdentityWarning(directory) {
2458
2622
  return formatDubiousOwnershipWarning(canonical);
2459
2623
  }
2460
2624
  function canonicalUserHomeDirectory() {
2461
- return realpathSync.native(userHomeDirectoryForIdentity());
2625
+ const homeDirectory = userHomeDirectoryForIdentity();
2626
+ try {
2627
+ return realpathSync.native(homeDirectory);
2628
+ } catch {
2629
+ return homeDirectory;
2630
+ }
2462
2631
  }
2463
2632
  function isUserHomeDirectory(directory) {
2464
2633
  try {
@@ -2592,6 +2761,27 @@ function normalizeStoredProjectPath(rawOrStored) {
2592
2761
  function storedPathBelongsToIdentity(storedProjectPath, projectIdentity) {
2593
2762
  return storedProjectPath === projectIdentity || normalizeStoredProjectPath(storedProjectPath) === projectIdentity;
2594
2763
  }
2764
+ function isLinkedGitWorktree(directory) {
2765
+ const resolvedDirectory = path.resolve(directory);
2766
+ const cached = linkedGitWorktreeCache.get(resolvedDirectory);
2767
+ if (cached !== undefined)
2768
+ return cached;
2769
+ let linked = false;
2770
+ try {
2771
+ const output = execFileSyncForIdentity("git", ["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"], {
2772
+ cwd: resolvedDirectory,
2773
+ encoding: "utf8",
2774
+ timeout: GIT_TIMEOUT_MS,
2775
+ windowsHide: true
2776
+ });
2777
+ const [gitDir, commonDir] = String(output).split(/\r?\n/u).map((line) => line.trim()).filter(Boolean);
2778
+ linked = Boolean(gitDir && commonDir && path.resolve(gitDir) !== path.resolve(commonDir));
2779
+ } catch {
2780
+ linked = hasGitDir(resolvedDirectory);
2781
+ }
2782
+ linkedGitWorktreeCache.set(resolvedDirectory, linked);
2783
+ return linked;
2784
+ }
2595
2785
  // src/features/magic-context/workspaces.ts
2596
2786
  var VALID_SHARE_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
2597
2787
  var DEFAULT_WORKSPACE_SHARE_CATEGORIES = ["CONSTRAINTS"];
@@ -3083,6 +3273,7 @@ var MIGRATIONS = [
3083
3273
  status TEXT NOT NULL DEFAULT 'active',
3084
3274
  promoted_at INTEGER NOT NULL,
3085
3275
  source_candidate_ids TEXT DEFAULT '[]',
3276
+ source_candidate_provenance TEXT,
3086
3277
  created_at INTEGER NOT NULL,
3087
3278
  updated_at INTEGER NOT NULL
3088
3279
  );
@@ -4109,6 +4300,7 @@ var MIGRATIONS = [
4109
4300
  last_observed_at INTEGER,
4110
4301
  answer_refreshed_at INTEGER,
4111
4302
  source_candidate_ids TEXT NOT NULL DEFAULT '[]',
4303
+ source_candidate_provenance TEXT,
4112
4304
  created_at INTEGER NOT NULL,
4113
4305
  updated_at INTEGER NOT NULL
4114
4306
  );
@@ -4918,6 +5110,37 @@ var MIGRATIONS = [
4918
5110
  ensureColumn(db, "notes", "compiled_at", "INTEGER");
4919
5111
  ensureColumn(db, "notes", "compile_status", "TEXT CHECK(compile_status IN ('compiled', 'plain', 'refused'))");
4920
5112
  }
5113
+ },
5114
+ {
5115
+ version: 77,
5116
+ description: "persist scoped provenance for promoted user memories and primers",
5117
+ up(db) {
5118
+ if (tableExists2(db, "user_memories")) {
5119
+ ensureColumn(db, "user_memories", "source_candidate_provenance", "TEXT");
5120
+ }
5121
+ if (tableExists2(db, "primers")) {
5122
+ ensureColumn(db, "primers", "source_candidate_provenance", "TEXT");
5123
+ }
5124
+ }
5125
+ },
5126
+ {
5127
+ version: 78,
5128
+ description: "add migration_pending journal for crash-safe cross-harness session migration",
5129
+ up(db) {
5130
+ db.exec(`
5131
+ CREATE TABLE IF NOT EXISTS migration_pending (
5132
+ migration_key TEXT PRIMARY KEY,
5133
+ source_session_id TEXT NOT NULL,
5134
+ target_harness TEXT NOT NULL,
5135
+ pi_session_id TEXT NOT NULL,
5136
+ final_path TEXT NOT NULL,
5137
+ stage_path TEXT NOT NULL,
5138
+ content_sha256 TEXT NOT NULL,
5139
+ phase TEXT NOT NULL CHECK (phase IN ('staged', 'db_committed')),
5140
+ created_at INTEGER NOT NULL
5141
+ );
5142
+ `);
5143
+ }
4921
5144
  }
4922
5145
  ];
4923
5146
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -5385,7 +5608,7 @@ function getSchemaFenceRejection() {
5385
5608
  function getMigrationOnOpenRefusal() {
5386
5609
  return lastMigrationOnOpenRefusal;
5387
5610
  }
5388
- var LATEST_SUPPORTED_VERSION = 76;
5611
+ var LATEST_SUPPORTED_VERSION = 78;
5389
5612
  var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
5390
5613
  var defaultStoragePermissionFs = { chmodSync, mkdirSync };
5391
5614
  var storagePermissionFs = defaultStoragePermissionFs;
@@ -5532,6 +5755,28 @@ function invalidDiscoveryReason(raw) {
5532
5755
  }
5533
5756
  return "parse-invalid";
5534
5757
  }
5758
+ function classifyDiscoveryRecordKind(record) {
5759
+ for (const value of [record.kind, record.harness]) {
5760
+ const normalized = value?.trim().toLowerCase();
5761
+ if (!normalized)
5762
+ continue;
5763
+ if (normalized === "process")
5764
+ return "process";
5765
+ if (normalized === "opencode server" || normalized === "server") {
5766
+ return "OpenCode server";
5767
+ }
5768
+ if (normalized === "opencode instance" || normalized === "opencode instance (tui/cli)" || normalized === "opencode" || normalized === "tui" || normalized === "cli") {
5769
+ return "OpenCode instance (TUI/CLI)";
5770
+ }
5771
+ if (normalized === "pi" || normalized === "pi harness" || normalized === "omp" || normalized === "oh-my-pi") {
5772
+ return "Pi";
5773
+ }
5774
+ }
5775
+ return null;
5776
+ }
5777
+ function classifyRpcProcess(record) {
5778
+ return classifyDiscoveryRecordKind(record) ?? classifyProcessKind(readProcessCommand(record.pid));
5779
+ }
5535
5780
  function classifyJunkDiscovery(portFile, raw, staleFiles) {
5536
5781
  let mtimeMs;
5537
5782
  try {
@@ -5584,7 +5829,9 @@ function inspectRpcServerDiscovery(storageDir) {
5584
5829
  return { state: "absent", serverPids: [], staleFiles: [] };
5585
5830
  }
5586
5831
  const pids = new Set;
5832
+ const processByPid = new Map;
5587
5833
  const staleFiles = [];
5834
+ const inconclusivePids = new Set;
5588
5835
  for (const portFile of portFiles) {
5589
5836
  let raw;
5590
5837
  try {
@@ -5604,10 +5851,23 @@ function inspectRpcServerDiscovery(storageDir) {
5604
5851
  return junk;
5605
5852
  continue;
5606
5853
  }
5607
- if (isPidAlive(record.pid) && isPidIdentityPlausible(record))
5854
+ const liveness = isPidAlive(record.pid);
5855
+ const identity = liveness === "dead" ? "implausible" : isPidIdentityPlausible(record);
5856
+ if (liveness === "alive" && identity === "plausible") {
5608
5857
  pids.add(record.pid);
5609
- else
5858
+ const detected = {
5859
+ kind: classifyRpcProcess(record),
5860
+ pid: record.pid
5861
+ };
5862
+ const previous = processByPid.get(record.pid);
5863
+ if (!previous || previous.kind === "process" && detected.kind !== "process") {
5864
+ processByPid.set(record.pid, detected);
5865
+ }
5866
+ } else if (liveness === "dead" || identity === "implausible") {
5610
5867
  staleFiles.push(portFile);
5868
+ } else {
5869
+ inconclusivePids.add(record.pid);
5870
+ }
5611
5871
  }
5612
5872
  for (const staleFile of staleFiles) {
5613
5873
  try {
@@ -5618,10 +5878,55 @@ function inspectRpcServerDiscovery(storageDir) {
5618
5878
  }
5619
5879
  const serverPids = [...pids].sort((a, b) => a - b);
5620
5880
  if (serverPids.length > 0) {
5621
- return { state: "live", serverPids, staleFiles };
5881
+ return {
5882
+ state: "live",
5883
+ serverPids,
5884
+ serverProcesses: serverPids.map((pid) => processByPid.get(pid) ?? { kind: "process", pid }),
5885
+ staleFiles
5886
+ };
5887
+ }
5888
+ const uncertainPids = [...inconclusivePids].sort((a, b) => a - b);
5889
+ if (uncertainPids.length > 0) {
5890
+ return {
5891
+ state: "inconclusive",
5892
+ serverPids: [],
5893
+ staleFiles,
5894
+ inconclusivePids: uncertainPids
5895
+ };
5622
5896
  }
5623
5897
  return { state: "stale", serverPids: [], staleFiles };
5624
5898
  }
5899
+ function formatInconclusiveOpenCodeMigrationWarning(dbPath, pids) {
5900
+ return `[magic-context] storage warning: continuing migration for ${dbPath}; OpenCode server PID ${pids.join(", ")} was not confirmed because its liveness or identity check could not run. This commonly means an OS sandbox denied kill(0) or ps. No live OpenCode server was confirmed.`;
5901
+ }
5902
+ function logInconclusiveMigrationProbes(dbPath, discovery, piProbeState) {
5903
+ const uncertainPids = discovery.inconclusivePids ?? [];
5904
+ if (uncertainPids.length > 0) {
5905
+ log(formatInconclusiveOpenCodeMigrationWarning(dbPath, uncertainPids));
5906
+ }
5907
+ if (piProbeState === "unreadable") {
5908
+ log(`[magic-context] storage warning: continuing migration for ${dbPath}; the Pi/OMP process-list probe could not run, which commonly means an OS sandbox denied ps. No live Pi harness was confirmed.`);
5909
+ }
5910
+ }
5911
+ function isDefaultSharedDatabasePath(dbPath) {
5912
+ if (!process.env.XDG_DATA_HOME && (process.env.MAGIC_CONTEXT_TEST_DATA_DIR || false)) {
5913
+ return false;
5914
+ }
5915
+ return resolve(dbPath) === resolve(join3(getMagicContextStorageDir(), "context.db"));
5916
+ }
5917
+ function migrationBlockingPiPids(dbPath, discovery, discoveredPiPids) {
5918
+ if (isDefaultSharedDatabasePath(dbPath))
5919
+ return [...discoveredPiPids];
5920
+ const sameDataDirPids = new Set(discovery.serverPids);
5921
+ return discoveredPiPids.filter((pid) => sameDataDirPids.has(pid));
5922
+ }
5923
+ function formatLiveProcessMigrationRefusal(dbPath, persistedVersion, latestSupportedVersion, serverPids, piPids) {
5924
+ const blockers = [
5925
+ ...serverPids.map((pid) => `confirmed OpenCode server PID ${pid}`),
5926
+ ...piPids.map((pid) => `confirmed Pi harness PID ${pid}`)
5927
+ ];
5928
+ return `[magic-context] storage fatal: refusing to migrate ${dbPath} from upstream migration v${persistedVersion} to v${latestSupportedVersion} while ${blockers.join(", ")} still use the old plugin build. Restart the blocking harness, then retry this process.`;
5929
+ }
5625
5930
  function enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion) {
5626
5931
  const persistedVersion = getPersistedSchemaVersion(db);
5627
5932
  if (persistedVersion >= latestSupportedVersion) {
@@ -5629,9 +5934,16 @@ function enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)
5629
5934
  return true;
5630
5935
  }
5631
5936
  const discovery = inspectRpcServerDiscovery(dbDir);
5632
- const piPids = discoverLivePiProcessIds();
5633
- if ((discovery.state === "absent" || discovery.state === "stale") && piPids.length === 0) {
5937
+ const piDiscovery = inspectLivePiProcesses();
5938
+ const piPids = migrationBlockingPiPids(dbPath, discovery, piDiscovery.processIds);
5939
+ const serverProcesses = discovery.serverProcesses ?? (discovery.state === "live" ? discovery.serverPids.map((pid) => ({ kind: "process", pid })) : []);
5940
+ const blockingProcesses = [
5941
+ ...serverProcesses,
5942
+ ...piPids.map((pid) => ({ kind: "Pi", pid }))
5943
+ ];
5944
+ if ((discovery.state === "absent" || discovery.state === "stale" || discovery.state === "inconclusive") && piPids.length === 0) {
5634
5945
  lastMigrationOnOpenRefusal = null;
5946
+ logInconclusiveMigrationProbes(dbPath, discovery, piDiscovery.state);
5635
5947
  return true;
5636
5948
  }
5637
5949
  const blockingPids = [...new Set([...discovery.serverPids, ...piPids])].sort((left, right) => left - right);
@@ -5639,6 +5951,7 @@ function enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)
5639
5951
  persistedVersion,
5640
5952
  supportedVersion: latestSupportedVersion,
5641
5953
  serverPids: blockingPids,
5954
+ blockingProcesses,
5642
5955
  ...discovery.unreadableFile ? { unreadableFile: discovery.unreadableFile } : {},
5643
5956
  ...discovery.unreadableArm ? { unreadableArm: discovery.unreadableArm } : {}
5644
5957
  };
@@ -5648,11 +5961,7 @@ function enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)
5648
5961
  const recovery = arm === "io" ? `If no OpenCode server is running, it is safe to delete ${unreadableFile} and retry.` : `Retry after the file is older than the ten-minute grace window, or stop OpenCode before deleting it.`;
5649
5962
  log(`[magic-context] storage fatal: refusing to migrate ${dbPath} from upstream migration v${persistedVersion} to v${latestSupportedVersion} because RPC discovery file ${unreadableFile} is uncertain (${arm} arm), so the absence of a live OpenCode server cannot be proven. ${recovery}`);
5650
5963
  } else {
5651
- const blockers = [
5652
- ...discovery.serverPids.map((pid) => `OpenCode server PID ${pid}`),
5653
- ...piPids.map((pid) => `Pi harness PID ${pid}`)
5654
- ];
5655
- log(`[magic-context] storage fatal: refusing to migrate ${dbPath} from upstream migration v${persistedVersion} to v${latestSupportedVersion} while ${blockers.join(", ")} may still use the old plugin build. Restart the blocking harness, then retry this process.`);
5964
+ log(formatLiveProcessMigrationRefusal(dbPath, persistedVersion, latestSupportedVersion, discovery.serverPids, piPids));
5656
5965
  }
5657
5966
  return false;
5658
5967
  }
@@ -5876,6 +6185,7 @@ function initializeDatabase(db) {
5876
6185
  last_observed_at INTEGER,
5877
6186
  answer_refreshed_at INTEGER,
5878
6187
  source_candidate_ids TEXT NOT NULL DEFAULT '[]',
6188
+ source_candidate_provenance TEXT,
5879
6189
  created_at INTEGER NOT NULL,
5880
6190
  updated_at INTEGER NOT NULL
5881
6191
  );
@@ -6511,6 +6821,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6511
6821
  ensureColumn(db, "primer_candidates", "question_embedding", "BLOB");
6512
6822
  ensureColumn(db, "primer_candidates", "question_embedding_model_id", "TEXT");
6513
6823
  ensureColumn(db, "primers", "question_embedding_model_id", "TEXT");
6824
+ ensureColumn(db, "primers", "source_candidate_provenance", "TEXT");
6825
+ const hasUserMemoriesTable = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'user_memories'").get();
6826
+ if (hasUserMemoriesTable) {
6827
+ ensureColumn(db, "user_memories", "source_candidate_provenance", "TEXT");
6828
+ }
6514
6829
  db.exec(`
6515
6830
  CREATE UNIQUE INDEX IF NOT EXISTS idx_primer_candidates_occurrence
6516
6831
  ON primer_candidates(project_path, harness, session_id, source_start_message_id, source_end_message_id);
@@ -6584,6 +6899,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6584
6899
  ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
6585
6900
  ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
6586
6901
  ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
6902
+ ensureColumn(db, "session_meta", "merged_reasoning_stripped_ids", "TEXT DEFAULT ''");
6903
+ ensureColumn(db, "session_meta", "trailing_blank_decisions", "TEXT DEFAULT ''");
6587
6904
  ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
6588
6905
  ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
6589
6906
  ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
@@ -6802,11 +7119,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6802
7119
  ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
6803
7120
  ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
6804
7121
  }
6805
- var CHANNEL2_CLAIM_TTL_MS = 120000;
7122
+ var CHANNEL2_CLAIM_TTL_MS = 10 * 60000;
6806
7123
  function healWedgedChannel2Claims(db) {
6807
7124
  try {
6808
7125
  const staleBefore = Date.now() - CHANNEL2_CLAIM_TTL_MS;
6809
- db.prepare("UPDATE session_meta SET channel2_nudge_state = 'pending', channel2_nudge_claimed_at = 0, channel2_nudge_claim_token = '' WHERE channel2_nudge_state = 'claimed' AND (channel2_nudge_claimed_at IS NULL OR channel2_nudge_claimed_at = 0 OR channel2_nudge_claimed_at <= ?)").run(staleBefore);
7126
+ db.prepare("UPDATE session_meta SET channel2_nudge_state = '', channel2_nudge_claimed_at = 0, channel2_nudge_claim_token = '' WHERE channel2_nudge_state = 'claimed' AND (channel2_nudge_claimed_at IS NULL OR channel2_nudge_claimed_at = 0 OR channel2_nudge_claimed_at <= ?)").run(staleBefore);
6810
7127
  } catch {}
6811
7128
  }
6812
7129
  function openDatabase(dbPathOrOptions) {
@@ -8205,7 +8522,7 @@ function clearHistorianFailureState(db, sessionId) {
8205
8522
  })();
8206
8523
  }
8207
8524
  function normalizeDetectedLimitModelKey(modelKey) {
8208
- return typeof modelKey === "string" && modelKey.length > 0 ? modelKey : null;
8525
+ return typeof modelKey === "string" && modelKey.length > 0 ? piModelRefToCanonical(modelKey) : null;
8209
8526
  }
8210
8527
  function normalizeEmergencyRecoveryOrigin(value) {
8211
8528
  return value === "provider_overflow" || value === "proactive_model_shrink" ? value : null;
@@ -8356,6 +8673,96 @@ function removeStrippedPlaceholderId(db, sessionId, messageId) {
8356
8673
  applyStrippedPlaceholderDelta(db, sessionId, { remove: [messageId] });
8357
8674
  return true;
8358
8675
  }
8676
+ function getMergedReasoningStrippedIds(db, sessionId) {
8677
+ const row = db.prepare("SELECT merged_reasoning_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
8678
+ return new Set(parseStrippedBlob(row?.merged_reasoning_stripped_ids));
8679
+ }
8680
+ function addMergedReasoningStrippedIds(db, sessionId, ids) {
8681
+ const add = [...ids];
8682
+ if (add.length === 0)
8683
+ return true;
8684
+ ensureSessionMetaRow(db, sessionId);
8685
+ for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
8686
+ const row = db.prepare("SELECT merged_reasoning_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
8687
+ const rawStored = row ? row.merged_reasoning_stripped_ids ?? null : null;
8688
+ const current = new Set(parseStrippedBlob(rawStored));
8689
+ let changed = false;
8690
+ for (const id of add) {
8691
+ if (!current.has(id)) {
8692
+ current.add(id);
8693
+ changed = true;
8694
+ }
8695
+ }
8696
+ if (!changed)
8697
+ return true;
8698
+ const nextBlob = JSON.stringify([...current]);
8699
+ const result = db.prepare("UPDATE session_meta SET merged_reasoning_stripped_ids = ? WHERE session_id = ? AND merged_reasoning_stripped_ids IS ?").run(nextBlob, sessionId, rawStored);
8700
+ if (result.changes > 0)
8701
+ return true;
8702
+ }
8703
+ sessionLog(sessionId, `merged_reasoning_stripped_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
8704
+ return false;
8705
+ }
8706
+ function isPersistedTrailingBlankDecision(value) {
8707
+ if (value === "keep" || value === "strip")
8708
+ return true;
8709
+ if (typeof value !== "string" || !value.startsWith("keep:"))
8710
+ return false;
8711
+ const countText = value.slice("keep:".length);
8712
+ if (!/^[1-9]\d*$/.test(countText))
8713
+ return false;
8714
+ const count = Number(countText);
8715
+ return Number.isSafeInteger(count) && count > 1 && count <= 1e4;
8716
+ }
8717
+ function parseTrailingBlankDecisions(raw) {
8718
+ if (!raw)
8719
+ return new Map;
8720
+ try {
8721
+ const parsed = JSON.parse(raw);
8722
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
8723
+ return new Map;
8724
+ const decisions = new Map;
8725
+ for (const [id, decision] of Object.entries(parsed)) {
8726
+ if (id.length > 0 && isPersistedTrailingBlankDecision(decision)) {
8727
+ decisions.set(id, decision);
8728
+ }
8729
+ }
8730
+ return decisions;
8731
+ } catch {
8732
+ return new Map;
8733
+ }
8734
+ }
8735
+ function getTrailingBlankDecisions(db, sessionId) {
8736
+ const row = db.prepare("SELECT trailing_blank_decisions FROM session_meta WHERE session_id = ?").get(sessionId);
8737
+ return parseTrailingBlankDecisions(row?.trailing_blank_decisions);
8738
+ }
8739
+ function addTrailingBlankDecisions(db, sessionId, additions, options) {
8740
+ const add = [...additions];
8741
+ if (add.length === 0)
8742
+ return true;
8743
+ ensureSessionMetaRow(db, sessionId);
8744
+ for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
8745
+ const row = db.prepare("SELECT trailing_blank_decisions FROM session_meta WHERE session_id = ?").get(sessionId);
8746
+ const rawStored = row ? row.trailing_blank_decisions ?? null : null;
8747
+ const current = parseTrailingBlankDecisions(rawStored);
8748
+ let changed = false;
8749
+ for (const [id, decision] of add) {
8750
+ const currentDecision = current.get(id);
8751
+ if (currentDecision === undefined || id === options?.overwriteMessageId && currentDecision !== decision) {
8752
+ current.set(id, decision);
8753
+ changed = true;
8754
+ }
8755
+ }
8756
+ if (!changed)
8757
+ return true;
8758
+ const nextBlob = JSON.stringify(Object.fromEntries(current));
8759
+ const result = db.prepare("UPDATE session_meta SET trailing_blank_decisions = ? WHERE session_id = ? AND trailing_blank_decisions IS ?").run(nextBlob, sessionId, rawStored);
8760
+ if (result.changes > 0)
8761
+ return true;
8762
+ }
8763
+ sessionLog(sessionId, `trailing_blank_decisions CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
8764
+ return false;
8765
+ }
8359
8766
  function getStaleReduceStrippedIds(db, sessionId) {
8360
8767
  const row = db.prepare("SELECT stale_reduce_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
8361
8768
  return new Set(parseStrippedBlob(row?.stale_reduce_stripped_ids));
@@ -8803,6 +9210,76 @@ function parseCandidateIds(raw) {
8803
9210
  return [];
8804
9211
  }
8805
9212
  }
9213
+ function parsePrimerSourceProvenance(raw) {
9214
+ if (raw === null)
9215
+ return null;
9216
+ try {
9217
+ const parsed = JSON.parse(raw);
9218
+ if (!Array.isArray(parsed))
9219
+ return null;
9220
+ const provenance = [];
9221
+ for (const value of parsed) {
9222
+ if (!value || typeof value !== "object")
9223
+ return null;
9224
+ const source = value;
9225
+ if (typeof source.candidate_id !== "number" || !Number.isFinite(source.candidate_id) || typeof source.project_path !== "string" || typeof source.harness !== "string" || typeof source.session_id !== "string" || source.source_compartment_start !== null && typeof source.source_compartment_start !== "number" || source.source_compartment_end !== null && typeof source.source_compartment_end !== "number" || typeof source.source_start_message_id !== "string" || typeof source.source_end_message_id !== "string") {
9226
+ return null;
9227
+ }
9228
+ provenance.push({
9229
+ candidateId: source.candidate_id,
9230
+ projectPath: source.project_path,
9231
+ harness: source.harness,
9232
+ sessionId: source.session_id,
9233
+ sourceCompartmentStart: source.source_compartment_start,
9234
+ sourceCompartmentEnd: source.source_compartment_end,
9235
+ sourceStartMessageId: source.source_start_message_id,
9236
+ sourceEndMessageId: source.source_end_message_id
9237
+ });
9238
+ }
9239
+ return provenance;
9240
+ } catch {
9241
+ return null;
9242
+ }
9243
+ }
9244
+ function loadPrimerSourceProvenance(db, candidateIds) {
9245
+ const ids = [...new Set(candidateIds)].sort((a, b) => a - b);
9246
+ if (ids.length === 0)
9247
+ return [];
9248
+ const placeholders3 = ids.map(() => "?").join(",");
9249
+ const rows = db.prepare(`SELECT id, project_path, harness, session_id,
9250
+ source_compartment_start, source_compartment_end,
9251
+ source_start_message_id, source_end_message_id
9252
+ FROM primer_candidates
9253
+ WHERE id IN (${placeholders3})
9254
+ ORDER BY id ASC`).all(...ids);
9255
+ return rows.map((row) => ({
9256
+ candidateId: row.id,
9257
+ projectPath: row.project_path,
9258
+ harness: row.harness,
9259
+ sessionId: row.session_id,
9260
+ sourceCompartmentStart: row.source_compartment_start,
9261
+ sourceCompartmentEnd: row.source_compartment_end,
9262
+ sourceStartMessageId: row.source_start_message_id,
9263
+ sourceEndMessageId: row.source_end_message_id
9264
+ }));
9265
+ }
9266
+ function serializePrimerSourceProvenance(provenance, sourceCandidateIds) {
9267
+ if (provenance.length === 0 && sourceCandidateIds.length > 0)
9268
+ return null;
9269
+ return JSON.stringify(provenance.map((source) => ({
9270
+ candidate_id: source.candidateId,
9271
+ project_path: source.projectPath,
9272
+ harness: source.harness,
9273
+ session_id: source.sessionId,
9274
+ source_compartment_start: source.sourceCompartmentStart,
9275
+ source_compartment_end: source.sourceCompartmentEnd,
9276
+ source_start_message_id: source.sourceStartMessageId,
9277
+ source_end_message_id: source.sourceEndMessageId
9278
+ })));
9279
+ }
9280
+ function normalizedCandidateIds(candidateIds) {
9281
+ return [...new Set(candidateIds)].sort((a, b) => a - b);
9282
+ }
8806
9283
  function toCandidate(row) {
8807
9284
  return {
8808
9285
  id: row.id,
@@ -8835,6 +9312,7 @@ function toPrimer(row) {
8835
9312
  lastObservedAt: row.last_observed_at,
8836
9313
  answerRefreshedAt: row.answer_refreshed_at,
8837
9314
  sourceCandidateIds: parseCandidateIds(row.source_candidate_ids),
9315
+ sourceProvenance: parsePrimerSourceProvenance(row.source_candidate_provenance),
8838
9316
  createdAt: row.created_at,
8839
9317
  updatedAt: row.updated_at
8840
9318
  };
@@ -8906,23 +9384,43 @@ function getActivePrimers(db, projectPath) {
8906
9384
  return rows.map(toPrimer);
8907
9385
  }
8908
9386
  function createPrimer(db, input) {
8909
- const now = input.now ?? Date.now();
8910
- const info = db.prepare(`INSERT INTO primers (
8911
- project_path, question, question_embedding, question_embedding_model_id, answer,
8912
- status, total_support, last_observed_at, answer_refreshed_at,
8913
- source_candidate_ids, created_at, updated_at
8914
- ) VALUES (?, ?, ?, ?, ?, 'active', ?, ?, NULL, ?, ?, ?)`).run(input.projectPath, input.question, vectorBlob(input.questionEmbedding), input.questionEmbeddingModelId ?? null, input.answer ?? "", input.totalSupport, input.lastObservedAt, JSON.stringify([...new Set(input.sourceCandidateIds)].sort((a, b) => a - b)), now, now);
8915
- return Number(info.lastInsertRowid);
9387
+ return db.transaction(() => {
9388
+ const now = input.now ?? Date.now();
9389
+ const sourceCandidateIds = normalizedCandidateIds(input.sourceCandidateIds);
9390
+ const sourceProvenance = loadPrimerSourceProvenance(db, sourceCandidateIds);
9391
+ const info = db.prepare(`INSERT INTO primers (
9392
+ project_path, question, question_embedding, question_embedding_model_id, answer,
9393
+ status, total_support, last_observed_at, answer_refreshed_at,
9394
+ source_candidate_ids, source_candidate_provenance, created_at, updated_at
9395
+ ) VALUES (?, ?, ?, ?, ?, 'active', ?, ?, NULL, ?, ?, ?, ?)`).run(input.projectPath, input.question, vectorBlob(input.questionEmbedding), input.questionEmbeddingModelId ?? null, input.answer ?? "", input.totalSupport, input.lastObservedAt, JSON.stringify(sourceCandidateIds), serializePrimerSourceProvenance(sourceProvenance, sourceCandidateIds), now, now);
9396
+ return Number(info.lastInsertRowid);
9397
+ })();
8916
9398
  }
8917
9399
  function updatePrimerSupport(db, input) {
8918
- db.prepare(`UPDATE primers
8919
- SET question_embedding = COALESCE(?, question_embedding),
8920
- question_embedding_model_id = COALESCE(?, question_embedding_model_id),
8921
- total_support = ?,
8922
- last_observed_at = ?,
8923
- source_candidate_ids = ?,
8924
- updated_at = ?
8925
- WHERE id = ?`).run(vectorBlob(input.questionEmbedding), input.questionEmbeddingModelId ?? null, input.totalSupport, input.lastObservedAt, JSON.stringify([...new Set(input.sourceCandidateIds)].sort((a, b) => a - b)), input.now ?? Date.now(), input.primerId);
9400
+ db.transaction(() => {
9401
+ const sourceCandidateIds = normalizedCandidateIds(input.sourceCandidateIds);
9402
+ const allowedIds = new Set(sourceCandidateIds);
9403
+ const existingRow = db.prepare("SELECT source_candidate_provenance FROM primers WHERE id = ?").get(input.primerId);
9404
+ const provenanceByCandidateId = new Map;
9405
+ for (const source of parsePrimerSourceProvenance(existingRow?.source_candidate_provenance ?? null) ?? []) {
9406
+ if (allowedIds.has(source.candidateId)) {
9407
+ provenanceByCandidateId.set(source.candidateId, source);
9408
+ }
9409
+ }
9410
+ for (const source of loadPrimerSourceProvenance(db, sourceCandidateIds)) {
9411
+ provenanceByCandidateId.set(source.candidateId, source);
9412
+ }
9413
+ const sourceProvenance = [...provenanceByCandidateId.values()].sort((a, b) => a.candidateId - b.candidateId);
9414
+ db.prepare(`UPDATE primers
9415
+ SET question_embedding = COALESCE(?, question_embedding),
9416
+ question_embedding_model_id = COALESCE(?, question_embedding_model_id),
9417
+ total_support = ?,
9418
+ last_observed_at = ?,
9419
+ source_candidate_ids = ?,
9420
+ source_candidate_provenance = ?,
9421
+ updated_at = ?
9422
+ WHERE id = ?`).run(vectorBlob(input.questionEmbedding), input.questionEmbeddingModelId ?? null, input.totalSupport, input.lastObservedAt, JSON.stringify(sourceCandidateIds), serializePrimerSourceProvenance(sourceProvenance, sourceCandidateIds), input.now ?? Date.now(), input.primerId);
9423
+ })();
8926
9424
  }
8927
9425
  function updatePrimerAnswer(db, primerId, answer, refreshedAt = Date.now()) {
8928
9426
  db.prepare("UPDATE primers SET answer = ?, answer_refreshed_at = ?, updated_at = ? WHERE id = ?").run(answer, refreshedAt, refreshedAt, primerId);
@@ -9026,6 +9524,1097 @@ function getLatestHistorianInvocationId(db, sessionId) {
9026
9524
  return null;
9027
9525
  }
9028
9526
  }
9527
+ // src/features/magic-context/reclaim-protection.ts
9528
+ var CTX_REDUCE_KEEP = 3;
9529
+ function newestCtxReduceTagNumbers(tags) {
9530
+ return new Set(tags.filter((tag) => tag.toolName === "ctx_reduce").sort((left, right) => right.tagNumber - left.tagNumber).slice(0, CTX_REDUCE_KEEP).map((tag) => tag.tagNumber));
9531
+ }
9532
+
9533
+ // src/hooks/magic-context/image-token-estimate.ts
9534
+ var IMAGE_TOKEN_DIVISOR = 750;
9535
+ var IMAGE_FALLBACK_TOKENS = 1200;
9536
+ var IMAGE_TOKEN_CAP = 4500;
9537
+ function estimateImageTokensFromDataUrl(url) {
9538
+ const comma = url.indexOf(",");
9539
+ if (comma < 0)
9540
+ return IMAGE_FALLBACK_TOKENS;
9541
+ const header = url.slice(0, comma);
9542
+ const payload = url.slice(comma + 1);
9543
+ const sliceLen = Math.min(512, payload.length);
9544
+ const preview = payload.slice(0, sliceLen);
9545
+ let bytes;
9546
+ try {
9547
+ bytes = base64Decode(preview);
9548
+ } catch {
9549
+ return IMAGE_FALLBACK_TOKENS;
9550
+ }
9551
+ if (header.includes("image/png")) {
9552
+ const dims = parsePngDimensions(bytes);
9553
+ if (dims)
9554
+ return clampImageTokens(Math.ceil(dims.w * dims.h / IMAGE_TOKEN_DIVISOR));
9555
+ } else if (header.includes("image/jpeg") || header.includes("image/jpg")) {
9556
+ const dims = parseJpegDimensions(bytes);
9557
+ if (dims)
9558
+ return clampImageTokens(Math.ceil(dims.w * dims.h / IMAGE_TOKEN_DIVISOR));
9559
+ } else if (header.includes("image/webp")) {
9560
+ const dims = parseWebpDimensions(bytes);
9561
+ if (dims)
9562
+ return clampImageTokens(Math.ceil(dims.w * dims.h / IMAGE_TOKEN_DIVISOR));
9563
+ } else if (header.includes("image/gif")) {
9564
+ const dims = parseGifDimensions(bytes);
9565
+ if (dims)
9566
+ return clampImageTokens(Math.ceil(dims.w * dims.h / IMAGE_TOKEN_DIVISOR));
9567
+ }
9568
+ return IMAGE_FALLBACK_TOKENS;
9569
+ }
9570
+ function clampImageTokens(n) {
9571
+ if (n < 1)
9572
+ return 1;
9573
+ if (n > IMAGE_TOKEN_CAP)
9574
+ return IMAGE_TOKEN_CAP;
9575
+ return n;
9576
+ }
9577
+ function base64Decode(b64) {
9578
+ const pad = b64.length % 4;
9579
+ const padded = pad === 0 ? b64 : b64 + "=".repeat(4 - pad);
9580
+ const binary = atob(padded);
9581
+ const out = new Uint8Array(binary.length);
9582
+ for (let i = 0;i < binary.length; i++)
9583
+ out[i] = binary.charCodeAt(i);
9584
+ return out;
9585
+ }
9586
+ function parsePngDimensions(b) {
9587
+ if (b.length < 24)
9588
+ return null;
9589
+ if (b[0] !== 137 || b[1] !== 80 || b[2] !== 78 || b[3] !== 71 || b[4] !== 13 || b[5] !== 10 || b[6] !== 26 || b[7] !== 10)
9590
+ return null;
9591
+ const w = readUint32BE(b, 16);
9592
+ const h = readUint32BE(b, 20);
9593
+ if (!w || !h)
9594
+ return null;
9595
+ return { w, h };
9596
+ }
9597
+ function parseJpegDimensions(b) {
9598
+ if (b.length < 4 || b[0] !== 255 || b[1] !== 216)
9599
+ return null;
9600
+ let i = 2;
9601
+ while (i < b.length - 8) {
9602
+ if (b[i] !== 255) {
9603
+ i++;
9604
+ continue;
9605
+ }
9606
+ const marker = b[i + 1];
9607
+ if (marker === undefined)
9608
+ break;
9609
+ if (isSofMarker(marker)) {
9610
+ const h = b[i + 5] << 8 | b[i + 6];
9611
+ const w = b[i + 7] << 8 | b[i + 8];
9612
+ if (w && h)
9613
+ return { w, h };
9614
+ return null;
9615
+ }
9616
+ if (marker === 216 || marker === 217 || marker === 1) {
9617
+ i += 2;
9618
+ continue;
9619
+ }
9620
+ const segLen = b[i + 2] << 8 | b[i + 3];
9621
+ if (segLen < 2)
9622
+ return null;
9623
+ i += 2 + segLen;
9624
+ }
9625
+ return null;
9626
+ }
9627
+ function isSofMarker(m) {
9628
+ if (m >= 192 && m <= 195)
9629
+ return true;
9630
+ if (m >= 197 && m <= 199)
9631
+ return true;
9632
+ if (m >= 201 && m <= 203)
9633
+ return true;
9634
+ if (m >= 205 && m <= 207)
9635
+ return true;
9636
+ return false;
9637
+ }
9638
+ function parseWebpDimensions(b) {
9639
+ if (b.length < 30)
9640
+ return null;
9641
+ if (b[0] !== 82 || b[1] !== 73 || b[2] !== 70 || b[3] !== 70)
9642
+ return null;
9643
+ if (b[8] !== 87 || b[9] !== 69 || b[10] !== 66 || b[11] !== 80)
9644
+ return null;
9645
+ const variant = String.fromCharCode(b[12], b[13], b[14], b[15]);
9646
+ if (variant === "VP8 ") {
9647
+ const w = (b[26] | b[27] << 8) & 16383;
9648
+ const h = (b[28] | b[29] << 8) & 16383;
9649
+ if (w && h)
9650
+ return { w, h };
9651
+ } else if (variant === "VP8L") {
9652
+ const b0 = b[21];
9653
+ const b1 = b[22];
9654
+ const b2 = b[23];
9655
+ const b3 = b[24];
9656
+ const w = 1 + ((b0 | b1 << 8) & 16383);
9657
+ const h = 1 + ((b1 >> 6 | b2 << 2 | b3 << 10) & 16383);
9658
+ if (w && h)
9659
+ return { w, h };
9660
+ } else if (variant === "VP8X") {
9661
+ const w = 1 + (b[24] | b[25] << 8 | b[26] << 16);
9662
+ const h = 1 + (b[27] | b[28] << 8 | b[29] << 16);
9663
+ if (w && h)
9664
+ return { w, h };
9665
+ }
9666
+ return null;
9667
+ }
9668
+ function parseGifDimensions(b) {
9669
+ if (b.length < 10)
9670
+ return null;
9671
+ if (b[0] !== 71 || b[1] !== 73 || b[2] !== 70)
9672
+ return null;
9673
+ const w = b[6] | b[7] << 8;
9674
+ const h = b[8] | b[9] << 8;
9675
+ if (!w || !h)
9676
+ return null;
9677
+ return { w, h };
9678
+ }
9679
+ function readUint32BE(b, offset) {
9680
+ return (b[offset] << 24 | b[offset + 1] << 16 | b[offset + 2] << 8 | b[offset + 3]) >>> 0;
9681
+ }
9682
+
9683
+ // src/hooks/magic-context/todo-view.ts
9684
+ import { createHash as createHash8 } from "node:crypto";
9685
+ var TODO_STATUS_PENDING = "pending";
9686
+ var TODO_STATUS_IN_PROGRESS = "in_progress";
9687
+ var TODO_STATUS_COMPLETED = "completed";
9688
+ var TODO_STATUS_CANCELLED = "cancelled";
9689
+ var TODO_PRIORITY_HIGH = "high";
9690
+ var TODO_PRIORITY_MEDIUM = "medium";
9691
+ var TODO_PRIORITY_LOW = "low";
9692
+ var TODO_STATUSES = [
9693
+ TODO_STATUS_PENDING,
9694
+ TODO_STATUS_IN_PROGRESS,
9695
+ TODO_STATUS_COMPLETED,
9696
+ TODO_STATUS_CANCELLED
9697
+ ];
9698
+ var TODO_PRIORITIES = [
9699
+ TODO_PRIORITY_HIGH,
9700
+ TODO_PRIORITY_MEDIUM,
9701
+ TODO_PRIORITY_LOW
9702
+ ];
9703
+ var TODO_STATUS_SET = new Set(TODO_STATUSES);
9704
+ var TODO_PRIORITY_SET = new Set(TODO_PRIORITIES);
9705
+ var TERMINAL_STATUSES = new Set([
9706
+ TODO_STATUS_COMPLETED,
9707
+ TODO_STATUS_CANCELLED
9708
+ ]);
9709
+ var TITLE_DONE_STATUSES = new Set([TODO_STATUS_COMPLETED]);
9710
+ var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
9711
+ function normalizeTodoStateJson(todos) {
9712
+ if (!Array.isArray(todos))
9713
+ return null;
9714
+ const normalized = [];
9715
+ for (const todo of todos) {
9716
+ if (!isTodoItem(todo))
9717
+ return null;
9718
+ normalized.push({
9719
+ content: todo.content,
9720
+ status: todo.status,
9721
+ priority: todo.priority ?? TODO_PRIORITY_MEDIUM
9722
+ });
9723
+ }
9724
+ return JSON.stringify(normalized);
9725
+ }
9726
+ function buildSyntheticTodoPart(stateJson) {
9727
+ const todos = parseTodoState(stateJson);
9728
+ if (todos === null || todos.length === 0)
9729
+ return null;
9730
+ if (todos.every((t) => TERMINAL_STATUSES.has(t.status)))
9731
+ return null;
9732
+ const callID = computeSyntheticCallId(stateJson);
9733
+ const activeCount = todos.filter((t) => !TITLE_DONE_STATUSES.has(t.status)).length;
9734
+ const output = JSON.stringify(todos, null, 2);
9735
+ const ts = 0;
9736
+ return {
9737
+ type: "tool",
9738
+ callID,
9739
+ tool: "todowrite",
9740
+ state: {
9741
+ status: "completed",
9742
+ input: { todos },
9743
+ output,
9744
+ title: `${activeCount} todos`,
9745
+ metadata: { todos, truncated: false },
9746
+ time: { start: ts, end: ts }
9747
+ },
9748
+ syntheticTodoMarker: true
9749
+ };
9750
+ }
9751
+ function computeSyntheticCallId(stateJson) {
9752
+ const hash = createHash8("sha256").update(stateJson).digest("hex").slice(0, 16);
9753
+ return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
9754
+ }
9755
+ function isSyntheticTodoPart(part) {
9756
+ if (part === null || typeof part !== "object")
9757
+ return false;
9758
+ const p = part;
9759
+ if (p.syntheticTodoMarker === true)
9760
+ return true;
9761
+ return p.type === "tool" && p.tool === "todowrite" && typeof p.callID === "string" && p.callID.startsWith(SYNTHETIC_CALL_ID_PREFIX);
9762
+ }
9763
+ function parseTodoState(stateJson) {
9764
+ if (stateJson.length === 0)
9765
+ return null;
9766
+ try {
9767
+ const parsed = JSON.parse(stateJson);
9768
+ if (!Array.isArray(parsed))
9769
+ return null;
9770
+ const result = [];
9771
+ for (const item of parsed) {
9772
+ if (!isTodoItem(item))
9773
+ return null;
9774
+ result.push({
9775
+ content: item.content,
9776
+ status: item.status,
9777
+ priority: item.priority ?? TODO_PRIORITY_MEDIUM
9778
+ });
9779
+ }
9780
+ return result;
9781
+ } catch {
9782
+ return null;
9783
+ }
9784
+ }
9785
+ function isTodoStatus(value) {
9786
+ return typeof value === "string" && TODO_STATUS_SET.has(value);
9787
+ }
9788
+ function isTodoPriority(value) {
9789
+ return typeof value === "string" && TODO_PRIORITY_SET.has(value);
9790
+ }
9791
+ function isTodoItem(value) {
9792
+ if (value === null || typeof value !== "object")
9793
+ return false;
9794
+ const todo = value;
9795
+ return typeof todo.content === "string" && isTodoStatus(todo.status) && (todo.priority === undefined || isTodoPriority(todo.priority));
9796
+ }
9797
+
9798
+ // src/hooks/magic-context/tail-hygiene-walk.ts
9799
+ var MAX_CONTENT_MEMO_ENTRIES = 1e5;
9800
+ var MAX_CONTENT_MEMO_BYTES = 64 * 1024 * 1024;
9801
+ var contentMemo = new Map;
9802
+ var contentMemoBytes = 0;
9803
+ var FNV1A_32_OFFSET = 2166136261;
9804
+ var FNV1A_32_PRIME = 16777619;
9805
+ var TAG_PREFIX = /^§\d+§\s*/;
9806
+ var DROP_PREFIXES = ["[dropped", "[truncated"];
9807
+ var CHANNEL1_REMINDER_OPEN = `
9808
+
9809
+ <system-reminder>
9810
+ `;
9811
+ var CHANNEL1_REMINDER_CLOSE = `
9812
+ </system-reminder>`;
9813
+ var TODO_HEAD_ANCHOR_ID = "__magic_context_todo_head__";
9814
+ function fnv1a32(value) {
9815
+ let hash = FNV1A_32_OFFSET;
9816
+ for (let index = 0;index < value.length; index += 1) {
9817
+ hash ^= value.charCodeAt(index);
9818
+ hash = Math.imul(hash, FNV1A_32_PRIME) >>> 0;
9819
+ }
9820
+ return hash.toString(16).padStart(8, "0");
9821
+ }
9822
+ function memoizedContent(kind, content) {
9823
+ const key = `${kind}\x00${content}`;
9824
+ const cached = contentMemo.get(key);
9825
+ if (cached)
9826
+ return cached;
9827
+ const measured = {
9828
+ hash: fnv1a32(key),
9829
+ tokens: kind === "excluded" ? 0 : estimateTokens(content),
9830
+ keyBytes: key.length * 2 + 32
9831
+ };
9832
+ contentMemo.set(key, measured);
9833
+ contentMemoBytes += measured.keyBytes;
9834
+ while (contentMemo.size > MAX_CONTENT_MEMO_ENTRIES || contentMemoBytes > MAX_CONTENT_MEMO_BYTES) {
9835
+ const oldest = contentMemo.keys().next().value;
9836
+ if (typeof oldest !== "string")
9837
+ break;
9838
+ const removed = contentMemo.get(oldest);
9839
+ if (removed)
9840
+ contentMemoBytes -= removed.keyBytes;
9841
+ contentMemo.delete(oldest);
9842
+ }
9843
+ return measured;
9844
+ }
9845
+ function safeStableStringify(value) {
9846
+ if (value === undefined || value === null)
9847
+ return "";
9848
+ if (typeof value === "string")
9849
+ return value;
9850
+ try {
9851
+ return stableStringify(value);
9852
+ } catch {
9853
+ return String(value);
9854
+ }
9855
+ }
9856
+ function firstString(record, fields) {
9857
+ for (const field of fields) {
9858
+ const value = record[field];
9859
+ if (typeof value === "string")
9860
+ return value;
9861
+ }
9862
+ return "";
9863
+ }
9864
+ function callIdFromPart(part) {
9865
+ const direct = firstString(part, ["callID", "callId", "toolCallId", "tool_call_id", "id"]);
9866
+ if (direct)
9867
+ return direct;
9868
+ const state2 = isRecord(part.state) ? part.state : null;
9869
+ return state2 ? firstString(state2, ["callID", "callId", "toolCallId", "tool_call_id", "id"]) : "";
9870
+ }
9871
+ function toolResultCallId(part) {
9872
+ return firstString(part, ["tool_use_id", "toolUseId", "callID", "callId"]);
9873
+ }
9874
+ function messageIdentity(message, messageIndex) {
9875
+ return typeof message.info.id === "string" ? message.info.id : `ordinal:${messageIndex}:${message.info.role ?? "unknown"}`;
9876
+ }
9877
+ function collectToolPartIdentities(messages) {
9878
+ const identities = new Map;
9879
+ const pendingOwners = new Map;
9880
+ for (let messageIndex = 0;messageIndex < messages.length; messageIndex += 1) {
9881
+ const message = messages[messageIndex];
9882
+ const currentOwner = messageIdentity(message, messageIndex);
9883
+ for (const part of message.parts) {
9884
+ if (!isRecord(part))
9885
+ continue;
9886
+ if (part.type === "tool-invocation" || part.type === "tool_use") {
9887
+ const callId = callIdFromPart(part);
9888
+ if (!callId)
9889
+ continue;
9890
+ const owners = pendingOwners.get(callId) ?? [];
9891
+ owners.push(currentOwner);
9892
+ pendingOwners.set(callId, owners);
9893
+ identities.set(part, {
9894
+ callId,
9895
+ ownerMessageId: currentOwner,
9896
+ messageIndex,
9897
+ kind: "invocation"
9898
+ });
9899
+ continue;
9900
+ }
9901
+ if (part.type === "tool_result") {
9902
+ const callId = toolResultCallId(part);
9903
+ if (!callId)
9904
+ continue;
9905
+ const owners = pendingOwners.get(callId);
9906
+ const ownerMessageId = owners?.shift() ?? currentOwner;
9907
+ identities.set(part, {
9908
+ callId,
9909
+ ownerMessageId,
9910
+ messageIndex,
9911
+ kind: "result"
9912
+ });
9913
+ continue;
9914
+ }
9915
+ if (part.type === "tool") {
9916
+ const callId = callIdFromPart(part);
9917
+ if (!callId)
9918
+ continue;
9919
+ identities.set(part, {
9920
+ callId,
9921
+ ownerMessageId: currentOwner,
9922
+ messageIndex,
9923
+ kind: "native"
9924
+ });
9925
+ }
9926
+ }
9927
+ }
9928
+ return identities;
9929
+ }
9930
+ function isSyntheticMessage(message) {
9931
+ const structuralHead = message.info.id === undefined && message.info.role === "user" && message.parts.length > 0 && message.parts.every((part) => isRecord(part) && part.synthetic === true);
9932
+ return structuralHead || message.info.summary === true || message.info.id === TODO_HEAD_ANCHOR_ID;
9933
+ }
9934
+ function isSyntheticPart(part) {
9935
+ return isRecord(part) && part.synthetic === true || isSyntheticTodoPart(part);
9936
+ }
9937
+ function stripChannel1ReminderSpans(output) {
9938
+ let stripped = output;
9939
+ while (stripped.endsWith(CHANNEL1_REMINDER_CLOSE)) {
9940
+ const opener = stripped.lastIndexOf(CHANNEL1_REMINDER_OPEN);
9941
+ if (opener < 0)
9942
+ break;
9943
+ stripped = stripped.slice(0, opener);
9944
+ }
9945
+ return stripped;
9946
+ }
9947
+ function isDropSentinel(content) {
9948
+ const stripped = content.trimStart().replace(TAG_PREFIX, "").trimStart().toLowerCase();
9949
+ return DROP_PREFIXES.some((prefix) => stripped.startsWith(prefix));
9950
+ }
9951
+ function toolOutputText(part) {
9952
+ if (part.type === "tool") {
9953
+ const state2 = isRecord(part.state) ? part.state : null;
9954
+ if (!state2)
9955
+ return null;
9956
+ if (state2.output !== undefined)
9957
+ return safeStableStringify(state2.output);
9958
+ if (state2.error !== undefined)
9959
+ return safeStableStringify(state2.error);
9960
+ if (state2.result !== undefined)
9961
+ return safeStableStringify(state2.result);
9962
+ return null;
9963
+ }
9964
+ if (part.type === "tool_result") {
9965
+ const value = part.content ?? part.output ?? part.result;
9966
+ return value === undefined ? null : safeStableStringify(value);
9967
+ }
9968
+ return null;
9969
+ }
9970
+ function toolInputText(part) {
9971
+ if (part.type === "tool") {
9972
+ const state2 = isRecord(part.state) ? part.state : null;
9973
+ if (!state2 || state2.input === undefined)
9974
+ return null;
9975
+ return safeStableStringify(state2.input);
9976
+ }
9977
+ if (part.type === "tool-invocation") {
9978
+ const value = part.args ?? part.input;
9979
+ return value === undefined ? null : safeStableStringify(value);
9980
+ }
9981
+ if (part.type === "tool_use") {
9982
+ return part.input === undefined ? null : safeStableStringify(part.input);
9983
+ }
9984
+ return null;
9985
+ }
9986
+ function messageIdForTag(tag) {
9987
+ if (tag.type === "tool")
9988
+ return tag.toolOwnerMessageId;
9989
+ return tag.messageId.replace(/:(?:p|file)\d+$/, "");
9990
+ }
9991
+ function protectedTagNumbers(tags, protectedTags) {
9992
+ const active = Array.from(new Set(tags.filter((tag) => tag.status === "active").map((tag) => tag.tagNumber))).sort((left, right) => right - left).slice(0, Math.max(0, protectedTags));
9993
+ const protectedNumbers = new Set(active);
9994
+ const protectedCtxReduceTags = newestCtxReduceTagNumbers(tags.filter((tag) => tag.status === "active" && tag.type === "tool"));
9995
+ for (const tagNumber of protectedCtxReduceTags)
9996
+ protectedNumbers.add(tagNumber);
9997
+ return protectedNumbers;
9998
+ }
9999
+ function neighborhoodConsistent(args) {
10000
+ let previousMax = null;
10001
+ for (let index = 0;index <= args.messageIndex; index += 1) {
10002
+ const bound = args.boundsByMessageIndex.get(index);
10003
+ if (bound)
10004
+ previousMax = previousMax === null ? bound.max : Math.max(previousMax, bound.max);
10005
+ }
10006
+ let nextMin = null;
10007
+ for (let index = args.messageIndex + 1;index < args.messageCount; index += 1) {
10008
+ const bound = args.boundsByMessageIndex.get(index);
10009
+ if (bound)
10010
+ nextMin = nextMin === null ? bound.min : Math.min(nextMin, bound.min);
10011
+ }
10012
+ if (previousMax === null || nextMin === null)
10013
+ return false;
10014
+ return args.orphanTagNumber >= previousMax && args.orphanTagNumber <= nextMin;
10015
+ }
10016
+ function buildTagAttribution(args) {
10017
+ const protectedNumbers = protectedTagNumbers(args.tags, args.protectedTags);
10018
+ const messageTags = new Map;
10019
+ const exactToolTags = new Map;
10020
+ const orphanTagsByCall = new Map;
10021
+ const messageIndexById = new Map;
10022
+ for (let index = 0;index < args.messages.length; index += 1) {
10023
+ const id = args.messages[index].info.id;
10024
+ if (typeof id === "string")
10025
+ messageIndexById.set(id, index);
10026
+ }
10027
+ const boundsByMessageIndex = new Map;
10028
+ for (const tag of args.tags) {
10029
+ if (tag.type === "tool") {
10030
+ if (tag.toolOwnerMessageId === null) {
10031
+ const rows = orphanTagsByCall.get(tag.messageId) ?? [];
10032
+ rows.push(tag);
10033
+ orphanTagsByCall.set(tag.messageId, rows);
10034
+ } else {
10035
+ exactToolTags.set(`${tag.toolOwnerMessageId}\x00${tag.messageId}`, tag);
10036
+ }
10037
+ } else {
10038
+ messageTags.set(tag.messageId, tag);
10039
+ }
10040
+ const ownerId = messageIdForTag(tag);
10041
+ const index = ownerId === null ? undefined : messageIndexById.get(ownerId);
10042
+ if (index === undefined)
10043
+ continue;
10044
+ const existing = boundsByMessageIndex.get(index);
10045
+ boundsByMessageIndex.set(index, {
10046
+ min: existing ? Math.min(existing.min, tag.tagNumber) : tag.tagNumber,
10047
+ max: existing ? Math.max(existing.max, tag.tagNumber) : tag.tagNumber
10048
+ });
10049
+ }
10050
+ const toolTagsByPart = new Map;
10051
+ const orphanCandidateOwners = new Map;
10052
+ for (const [part, identity] of args.toolIdentities) {
10053
+ const exact = exactToolTags.get(`${identity.ownerMessageId}\x00${identity.callId}`);
10054
+ if (exact) {
10055
+ toolTagsByPart.set(part, exact);
10056
+ continue;
10057
+ }
10058
+ const orphans = orphanTagsByCall.get(identity.callId);
10059
+ if (orphans?.length !== 1)
10060
+ continue;
10061
+ if (!neighborhoodConsistent({
10062
+ orphanTagNumber: orphans[0].tagNumber,
10063
+ messageIndex: identity.messageIndex,
10064
+ boundsByMessageIndex,
10065
+ messageCount: args.messages.length
10066
+ })) {
10067
+ continue;
10068
+ }
10069
+ const byOwner = orphanCandidateOwners.get(identity.callId) ?? new Map;
10070
+ const ownerParts = byOwner.get(identity.ownerMessageId) ?? [];
10071
+ ownerParts.push(identity);
10072
+ byOwner.set(identity.ownerMessageId, ownerParts);
10073
+ orphanCandidateOwners.set(identity.callId, byOwner);
10074
+ }
10075
+ for (const [callId, byOwner] of orphanCandidateOwners) {
10076
+ if (byOwner.size !== 1)
10077
+ continue;
10078
+ const orphan = orphanTagsByCall.get(callId)?.[0];
10079
+ if (!orphan)
10080
+ continue;
10081
+ const ownerId = byOwner.keys().next().value;
10082
+ if (typeof ownerId !== "string")
10083
+ continue;
10084
+ for (const [part, identity] of args.toolIdentities) {
10085
+ if (identity.callId === callId && identity.ownerMessageId === ownerId) {
10086
+ toolTagsByPart.set(part, orphan);
10087
+ }
10088
+ }
10089
+ }
10090
+ return { protectedNumbers, messageTags, toolTagsByPart };
10091
+ }
10092
+ function snapshot(args) {
10093
+ const memo = memoizedContent(args.kind, args.content);
10094
+ const tag = args.tag;
10095
+ const isProtected = tag ? args.protectedNumbers.has(tag.tagNumber) : false;
10096
+ const uTokens = tag?.status === "active" && !isProtected && args.kind !== "excluded" ? args.tokens : 0;
10097
+ return {
10098
+ key: args.key,
10099
+ contentHash: memo.hash,
10100
+ kind: args.kind,
10101
+ tokens: args.tokens,
10102
+ uTokens,
10103
+ tagNumber: tag?.tagNumber ?? null,
10104
+ tagStatus: tag?.status ?? null,
10105
+ protected: isProtected
10106
+ };
10107
+ }
10108
+ function excludedSnapshot(key, part) {
10109
+ const content = safeStableStringify(part);
10110
+ return snapshot({
10111
+ key,
10112
+ kind: "excluded",
10113
+ content,
10114
+ tokens: 0,
10115
+ tag: undefined,
10116
+ protectedNumbers: new Set
10117
+ });
10118
+ }
10119
+ function fileContentAndTokens(part) {
10120
+ const mime = typeof part.mime === "string" ? part.mime : "";
10121
+ const type = typeof part.type === "string" ? part.type.toLowerCase() : "";
10122
+ const url = typeof part.url === "string" ? part.url : "";
10123
+ if (mime.startsWith("image/") || type.includes("image")) {
10124
+ return {
10125
+ content: url,
10126
+ tokens: url.startsWith("data:") ? estimateImageTokensFromDataUrl(url) : 1200
10127
+ };
10128
+ }
10129
+ const content = firstString(part, ["content", "text", "source", "url"]);
10130
+ const memo = memoizedContent("file", content);
10131
+ return { content, tokens: memo.tokens };
10132
+ }
10133
+ function contentSignature(parts) {
10134
+ return fnv1a32(parts.map((part) => `${part.key}:${part.contentHash}`).join("\x00"));
10135
+ }
10136
+ function tailHygieneStructuralSignature(messages) {
10137
+ const partCounts = [];
10138
+ let totalBytes = 0;
10139
+ for (const message of messages) {
10140
+ partCounts.push(message.parts.length);
10141
+ totalBytes += byteSize(JSON.stringify(message) ?? "");
10142
+ }
10143
+ return { messageCount: messages.length, partCounts, totalBytes };
10144
+ }
10145
+ function sameTailHygieneStructuralSignature(expected, actual) {
10146
+ if (expected.messageCount !== actual.messageCount || expected.totalBytes !== actual.totalBytes || expected.partCounts.length !== actual.partCounts.length) {
10147
+ return false;
10148
+ }
10149
+ return expected.partCounts.every((count, index) => count === actual.partCounts[index]);
10150
+ }
10151
+ function measureTailHygiene(input) {
10152
+ const toolIdentities = collectToolPartIdentities(input.messages);
10153
+ const attribution = buildTagAttribution({
10154
+ messages: input.messages,
10155
+ tags: input.tags,
10156
+ toolIdentities,
10157
+ protectedTags: input.protectedTags
10158
+ });
10159
+ const droppedToolOwners = new Set;
10160
+ for (const [part, identity] of toolIdentities) {
10161
+ if (!isRecord(part))
10162
+ continue;
10163
+ const output = toolOutputText(part);
10164
+ if (output !== null && isDropSentinel(output)) {
10165
+ droppedToolOwners.add(`${identity.ownerMessageId}\x00${identity.callId}`);
10166
+ }
10167
+ }
10168
+ const parts = [];
10169
+ let t = 0;
10170
+ let u = 0;
10171
+ for (let messageIndex = 0;messageIndex < input.messages.length; messageIndex += 1) {
10172
+ const message = input.messages[messageIndex];
10173
+ const messageKey = messageIdentity(message, messageIndex);
10174
+ const messageSynthetic = isSyntheticMessage(message);
10175
+ for (let partIndex = 0;partIndex < message.parts.length; partIndex += 1) {
10176
+ const part = message.parts[partIndex];
10177
+ const key = `${messageKey}\x00${partIndex}`;
10178
+ if (messageSynthetic || isSyntheticPart(part) || !isRecord(part)) {
10179
+ parts.push(excludedSnapshot(`${key}\x00excluded`, part));
10180
+ continue;
10181
+ }
10182
+ const type = typeof part.type === "string" ? part.type : "";
10183
+ if (type === "reasoning" || type === "thinking" || type === "redacted_thinking" || type === "signature") {
10184
+ parts.push(excludedSnapshot(`${key}\x00excluded`, part));
10185
+ continue;
10186
+ }
10187
+ if (type === "text") {
10188
+ const content = firstString(part, ["text", "content"]);
10189
+ if (!content || isDropSentinel(content)) {
10190
+ parts.push(excludedSnapshot(`${key}\x00excluded`, part));
10191
+ continue;
10192
+ }
10193
+ const memo = memoizedContent("text", content);
10194
+ const tag = attribution.messageTags.get(`${message.info.id}:p${partIndex}`);
10195
+ const measured = snapshot({
10196
+ key: `${key}\x00text`,
10197
+ kind: "text",
10198
+ content,
10199
+ tokens: memo.tokens,
10200
+ tag,
10201
+ protectedNumbers: attribution.protectedNumbers
10202
+ });
10203
+ parts.push(measured);
10204
+ t += measured.tokens;
10205
+ u += measured.uTokens;
10206
+ continue;
10207
+ }
10208
+ if (type === "file" || type.includes("image") || type === "source") {
10209
+ const file = fileContentAndTokens(part);
10210
+ if (!file.content || isDropSentinel(file.content)) {
10211
+ parts.push(excludedSnapshot(`${key}\x00excluded`, part));
10212
+ continue;
10213
+ }
10214
+ const tag = attribution.messageTags.get(`${message.info.id}:file${partIndex}`);
10215
+ const measured = snapshot({
10216
+ key: `${key}\x00file`,
10217
+ kind: "file",
10218
+ content: file.content,
10219
+ tokens: file.tokens,
10220
+ tag,
10221
+ protectedNumbers: attribution.protectedNumbers
10222
+ });
10223
+ parts.push(measured);
10224
+ t += measured.tokens;
10225
+ u += measured.uTokens;
10226
+ continue;
10227
+ }
10228
+ const toolIdentity = toolIdentities.get(part);
10229
+ if (toolIdentity) {
10230
+ const ownerKey = `${toolIdentity.ownerMessageId}\x00${toolIdentity.callId}`;
10231
+ if (droppedToolOwners.has(ownerKey)) {
10232
+ parts.push(excludedSnapshot(`${key}\x00excluded`, part));
10233
+ continue;
10234
+ }
10235
+ const tag = attribution.toolTagsByPart.get(part);
10236
+ const inputText = toolInputText(part);
10237
+ if (inputText !== null) {
10238
+ const memo = memoizedContent("toolInput", inputText);
10239
+ const measured = snapshot({
10240
+ key: `${key}\x00toolInput`,
10241
+ kind: "toolInput",
10242
+ content: inputText,
10243
+ tokens: memo.tokens,
10244
+ tag,
10245
+ protectedNumbers: attribution.protectedNumbers
10246
+ });
10247
+ parts.push(measured);
10248
+ t += measured.tokens;
10249
+ u += measured.uTokens;
10250
+ }
10251
+ const rawOutput = toolOutputText(part);
10252
+ if (rawOutput !== null) {
10253
+ const output = stripChannel1ReminderSpans(rawOutput);
10254
+ if (isDropSentinel(output)) {
10255
+ parts.push(excludedSnapshot(`${key}\x00excludedOutput`, output));
10256
+ } else {
10257
+ const memo = memoizedContent("toolOutput", output);
10258
+ const measured = snapshot({
10259
+ key: `${key}\x00toolOutput`,
10260
+ kind: "toolOutput",
10261
+ content: output,
10262
+ tokens: memo.tokens,
10263
+ tag,
10264
+ protectedNumbers: attribution.protectedNumbers
10265
+ });
10266
+ parts.push(measured);
10267
+ t += measured.tokens;
10268
+ u += measured.uTokens;
10269
+ }
10270
+ }
10271
+ if (inputText === null && rawOutput === null) {
10272
+ parts.push(excludedSnapshot(`${key}\x00excluded`, part));
10273
+ }
10274
+ continue;
10275
+ }
10276
+ parts.push(excludedSnapshot(`${key}\x00excluded`, part));
10277
+ }
10278
+ }
10279
+ return {
10280
+ u: Math.min(Math.max(0, u), Math.max(0, t)),
10281
+ t: Math.max(0, t),
10282
+ contentSignature: contentSignature(parts),
10283
+ parts
10284
+ };
10285
+ }
10286
+ function sameMeasuredPrefix(baseline, current) {
10287
+ if (current.length < baseline.length)
10288
+ return { valid: false, boundaryAdvanceU: 0 };
10289
+ let boundaryAdvanceU = 0;
10290
+ for (let index = 0;index < baseline.length; index += 1) {
10291
+ const before = baseline[index];
10292
+ const after = current[index];
10293
+ if (before.key !== after.key || before.contentHash !== after.contentHash || before.kind !== after.kind || before.tokens !== after.tokens || before.tagNumber !== after.tagNumber || before.tagStatus !== after.tagStatus) {
10294
+ return { valid: false, boundaryAdvanceU: 0 };
10295
+ }
10296
+ if (!before.protected && after.protected)
10297
+ return { valid: false, boundaryAdvanceU: 0 };
10298
+ if (before.protected && !after.protected) {
10299
+ if (after.tagStatus !== "active")
10300
+ return { valid: false, boundaryAdvanceU: 0 };
10301
+ boundaryAdvanceU += after.tokens;
10302
+ } else if (before.uTokens !== after.uTokens) {
10303
+ return { valid: false, boundaryAdvanceU: 0 };
10304
+ }
10305
+ }
10306
+ return { valid: true, boundaryAdvanceU };
10307
+ }
10308
+ function refreshTailHygieneBaseline(input) {
10309
+ const measured = measureTailHygiene(input);
10310
+ const now = input.now ?? Date.now();
10311
+ if (!input.cacheBusting && input.previous?.generationInvalidated) {
10312
+ return { ...input.previous, contentSignature: measured.contentSignature };
10313
+ }
10314
+ if (input.cacheBusting || !input.previous) {
10315
+ return {
10316
+ baselineU: measured.u,
10317
+ baselineT: measured.t,
10318
+ turnDeltaU: 0,
10319
+ turnDeltaT: 0,
10320
+ baselineGeneration: (input.previous?.baselineGeneration ?? 0) + 1,
10321
+ computedAt: now,
10322
+ evaluable: true,
10323
+ generationInvalidated: false,
10324
+ baselineParts: measured.parts,
10325
+ contentSignature: measured.contentSignature
10326
+ };
10327
+ }
10328
+ const prefix = sameMeasuredPrefix(input.previous.baselineParts, measured.parts);
10329
+ if (!prefix.valid) {
10330
+ return {
10331
+ ...input.previous,
10332
+ evaluable: false,
10333
+ generationInvalidated: true,
10334
+ contentSignature: measured.contentSignature
10335
+ };
10336
+ }
10337
+ let turnDeltaT = 0;
10338
+ let turnDeltaU = prefix.boundaryAdvanceU;
10339
+ for (let index = input.previous.baselineParts.length;index < measured.parts.length; index += 1) {
10340
+ const part = measured.parts[index];
10341
+ turnDeltaT += part.tokens;
10342
+ if (part.kind !== "toolOutput")
10343
+ turnDeltaU += part.uTokens;
10344
+ }
10345
+ return {
10346
+ ...input.previous,
10347
+ turnDeltaU,
10348
+ turnDeltaT,
10349
+ evaluable: true,
10350
+ generationInvalidated: false,
10351
+ contentSignature: measured.contentSignature
10352
+ };
10353
+ }
10354
+ function effectiveTailHygiene(baseline) {
10355
+ const t = Math.max(0, baseline.baselineT + baseline.turnDeltaT);
10356
+ const u = Math.min(t, Math.max(0, baseline.baselineU + baseline.turnDeltaU));
10357
+ return { u, t };
10358
+ }
10359
+ function assertTailHygieneContentUnchanged(input) {
10360
+ const actual = measureTailHygiene(input).contentSignature;
10361
+ if (actual !== input.expectedSignature) {
10362
+ throw new Error(`tail hygiene walk was not the last byte-affecting operation: expected ${input.expectedSignature}, got ${actual}`);
10363
+ }
10364
+ }
10365
+
10366
+ // src/hooks/magic-context/ctx-reduce-nudge.ts
10367
+ var CHANNEL1_SENTINEL = "<system-reminder>";
10368
+ var TOKENS_PER_BYTE = 0.25;
10369
+ var CHANNEL1_MIN_TOKENS = 60000;
10370
+ var CHANNEL1_FLOOR_TOKENS = 25000;
10371
+ var CHANNEL1_REFIRE_FLOOR_TOKENS = 25000;
10372
+ var S_GENTLE = 0.2;
10373
+ var S_FIRM = 0.4;
10374
+ var S_URGENT = 0.6;
10375
+ var LEVEL_RANK = { gentle: 1, firm: 2, urgent: 3 };
10376
+ function channel1RefireTokens(tailTokens) {
10377
+ const scaled = Math.round(0.08 * Math.max(0, tailTokens));
10378
+ return Math.max(CHANNEL1_REFIRE_FLOOR_TOKENS, scaled);
10379
+ }
10380
+ function toolOutputTokens(output) {
10381
+ return estimateTokens(stripChannel1ReminderSpans(output));
10382
+ }
10383
+ function decideChannel1(input) {
10384
+ const tailTokens = Math.max(0, input.baselineT + input.turnDeltaT);
10385
+ const undroppedTokens = Math.min(tailTokens, Math.max(0, input.baselineU + input.turnDeltaU));
10386
+ const severity = Math.min(1, Math.max(0, undroppedTokens / Math.max(tailTokens, 1)));
10387
+ const resetCycle = input.hasRecentReduce || undroppedTokens < input.lastNudgeUndropped;
10388
+ const lastNudge = resetCycle ? 0 : input.lastNudgeUndropped;
10389
+ const lastLevel = resetCycle ? "" : input.lastNudgeLevel;
10390
+ const quiet = () => ({
10391
+ fire: false,
10392
+ level: "gentle",
10393
+ undroppedTokens,
10394
+ tailTokens,
10395
+ severity,
10396
+ nextLastNudge: lastNudge,
10397
+ nextLastNudgeLevel: lastLevel
10398
+ });
10399
+ if (input.evaluable === false || input.generationInvalidated === true)
10400
+ return quiet();
10401
+ if (input.hasRecentReduce)
10402
+ return quiet();
10403
+ if (tailTokens < CHANNEL1_MIN_TOKENS)
10404
+ return quiet();
10405
+ if (undroppedTokens < CHANNEL1_FLOOR_TOKENS || undroppedTokens === 0)
10406
+ return quiet();
10407
+ if (severity < S_GENTLE)
10408
+ return quiet();
10409
+ let level;
10410
+ if (severity >= S_URGENT)
10411
+ level = "urgent";
10412
+ else if (severity >= S_FIRM)
10413
+ level = "firm";
10414
+ else
10415
+ level = "gentle";
10416
+ const escalated = lastLevel === "" || LEVEL_RANK[level] > LEVEL_RANK[lastLevel];
10417
+ const cadenceReached = lastLevel !== "" && undroppedTokens - lastNudge >= channel1RefireTokens(tailTokens);
10418
+ if (!escalated && !cadenceReached)
10419
+ return quiet();
10420
+ return {
10421
+ fire: true,
10422
+ level,
10423
+ undroppedTokens,
10424
+ tailTokens,
10425
+ severity,
10426
+ nextLastNudge: undroppedTokens,
10427
+ nextLastNudgeLevel: level
10428
+ };
10429
+ }
10430
+ var CHANNEL2_SEVERITY_THRESHOLD = 0.75;
10431
+ var CHANNEL2_FLOOR_TOKENS = 50000;
10432
+ function evaluateChannel2(input) {
10433
+ const values = input ? [input.baselineU, input.baselineT, input.turnDeltaU, input.turnDeltaT] : [];
10434
+ if (input?.evaluable !== true || input.generationInvalidated === true || values.some((value) => !Number.isFinite(value))) {
10435
+ return {
10436
+ evaluable: false,
10437
+ shouldTrigger: false,
10438
+ reclaimableTokens: 0,
10439
+ tailTokens: 0,
10440
+ severity: 0
10441
+ };
10442
+ }
10443
+ const tailTokens = Math.max(0, input.baselineT + input.turnDeltaT);
10444
+ const reclaimableTokens = Math.min(tailTokens, Math.max(0, input.baselineU + input.turnDeltaU));
10445
+ const severity = Math.min(1, Math.max(0, reclaimableTokens / Math.max(tailTokens, 1)));
10446
+ return {
10447
+ evaluable: true,
10448
+ shouldTrigger: tailTokens >= CHANNEL1_MIN_TOKENS && reclaimableTokens >= CHANNEL2_FLOOR_TOKENS && severity >= CHANNEL2_SEVERITY_THRESHOLD,
10449
+ reclaimableTokens,
10450
+ tailTokens,
10451
+ severity
10452
+ };
10453
+ }
10454
+ function approxThousands(tokens) {
10455
+ return `${Math.round(tokens / 1000)}k`;
10456
+ }
10457
+ function formatOldestReclaimableHint(hint) {
10458
+ if (!hint || hint.length === 0)
10459
+ return "";
10460
+ const rendered = hint.slice(0, 4).map((tag) => `§${tag.tagNumber}§ ${tag.toolName ?? "tool"}`).join(" · ");
10461
+ return rendered.length > 0 ? `
10462
+ oldest reclaimable: ${rendered}.` : "";
10463
+ }
10464
+ function buildChannel2Reminder(undroppedTokens, hint) {
10465
+ const amount = approxThousands(undroppedTokens);
10466
+ const hintText = formatOldestReclaimableHint(hint);
10467
+ return `<system-reminder>
10468
+ ` + `Routine context housekeeping is near: a large span of this session will be comparted soon, ` + `and ~${amount} tokens of tool output remain unreduced. Drop spent outputs with ctx_reduce ` + `first so the archived span is the part that matters.${hintText}
10469
+ ` + `</system-reminder>`;
10470
+ }
10471
+ function buildChannel1Reminder(level, undroppedTokens, hint) {
10472
+ const amount = approxThousands(undroppedTokens);
10473
+ const hintText = formatOldestReclaimableHint(hint);
10474
+ let body;
10475
+ switch (level) {
10476
+ case "gentle":
10477
+ body = `You have ~${amount} tokens of content you have not reduced. ` + `When you are done with earlier outputs, dropping them with ctx_reduce keeps context lean.`;
10478
+ break;
10479
+ case "firm":
10480
+ body = `~${amount} tokens of unreduced content has built up. ` + `At your next natural stopping point, consider dropping what you have already processed with ctx_reduce.`;
10481
+ break;
10482
+ case "urgent":
10483
+ body = `~${amount} tokens of unreduced content remain across most of the live tail. ` + `Consider dropping spent outputs with ctx_reduce so the archived span is the part that matters.`;
10484
+ break;
10485
+ }
10486
+ return `
10487
+
10488
+ <system-reminder>
10489
+ ${body}${hintText}
10490
+ </system-reminder>`;
10491
+ }
10492
+
10493
+ // src/hooks/magic-context/emergency-drop.ts
10494
+ var TARGET_FRACTION = 0.3;
10495
+ var TIER_RECENCY_RESERVE = 0.2;
10496
+ var EMERGENCY_REARM_MIN_TOKENS = 2000;
10497
+ var T1_TOOLS = new Set(["read", "todowrite", "task", "aft_outline", "aft_zoom"]);
10498
+ var T2_TOOLS = new Set(["edit", "write", "apply_patch", "grep", "glob", "aft_search"]);
10499
+ function normalizeToolName(toolName) {
10500
+ if (!toolName)
10501
+ return "";
10502
+ let name = toolName.toLowerCase();
10503
+ if (name.startsWith("mcp_"))
10504
+ name = name.slice(4);
10505
+ return name;
10506
+ }
10507
+ function resolveToolTier(toolName) {
10508
+ const name = normalizeToolName(toolName);
10509
+ if (T1_TOOLS.has(name))
10510
+ return 1;
10511
+ if (T2_TOOLS.has(name))
10512
+ return 2;
10513
+ return 3;
10514
+ }
10515
+ function tagReclaimBytes(tag) {
10516
+ return tag.byteSize + tag.inputByteSize + tag.reasoningByteSize;
10517
+ }
10518
+ function estimateEmergencyDropReclaimTokens(tag) {
10519
+ return Math.round(tagReclaimBytes(tag) * TOKENS_PER_BYTE);
10520
+ }
10521
+ function planEmergencyDrop(input) {
10522
+ const {
10523
+ tags,
10524
+ floorTags,
10525
+ maxTag,
10526
+ protectedTags,
10527
+ currentTotalInputTokens,
10528
+ ceilingTokens,
10529
+ priorInputSample,
10530
+ hasPriorDrop
10531
+ } = input;
10532
+ const noop = (reason) => ({
10533
+ shouldDrop: false,
10534
+ tagNumbers: [],
10535
+ reclaimTokens: 0,
10536
+ reason
10537
+ });
10538
+ if (!Number.isFinite(ceilingTokens) || ceilingTokens <= 0) {
10539
+ return noop("unknown-ceiling");
10540
+ }
10541
+ if (!Number.isFinite(currentTotalInputTokens) || currentTotalInputTokens <= 0) {
10542
+ return noop("unknown-usage");
10543
+ }
10544
+ if (hasPriorDrop && currentTotalInputTokens === priorInputSample) {
10545
+ return noop("same-input-sample (awaiting fresh usage after prior drop)");
10546
+ }
10547
+ let tailTokens = 0;
10548
+ for (const tag of floorTags) {
10549
+ if (tag.status !== "active")
10550
+ continue;
10551
+ tailTokens += estimateEmergencyDropReclaimTokens(tag);
10552
+ }
10553
+ const fixedFloor = Math.max(currentTotalInputTokens - tailTokens, 0);
10554
+ const workingSpan = Math.max(ceilingTokens - fixedFloor, 0);
10555
+ const target = fixedFloor + TARGET_FRACTION * workingSpan;
10556
+ const reclaimTokens = Math.round(currentTotalInputTokens - target);
10557
+ if (reclaimTokens <= EMERGENCY_REARM_MIN_TOKENS) {
10558
+ return noop(`reclaim<=min (${reclaimTokens} <= ${EMERGENCY_REARM_MIN_TOKENS})`);
10559
+ }
10560
+ const protectedCutoff = maxTag - protectedTags;
10561
+ const tierActive = { 1: [], 2: [] };
10562
+ for (const tag of tags) {
10563
+ if (tag.status !== "active" || tag.type !== "tool")
10564
+ continue;
10565
+ const tier = resolveToolTier(tag.toolName);
10566
+ if (tier === 1 || tier === 2)
10567
+ tierActive[tier].push(tag.tagNumber);
10568
+ }
10569
+ const reserved = new Set;
10570
+ for (const tier of [1, 2]) {
10571
+ const nums = tierActive[tier];
10572
+ if (nums.length === 0)
10573
+ continue;
10574
+ nums.sort((a, b) => b - a);
10575
+ const reserveCount = Math.ceil(TIER_RECENCY_RESERVE * nums.length);
10576
+ for (let i = 0;i < reserveCount && i < nums.length; i++) {
10577
+ reserved.add(nums[i]);
10578
+ }
10579
+ }
10580
+ const protectedCtxReduceTags = newestCtxReduceTagNumbers(floorTags.filter((tag) => tag.status === "active" && tag.type === "tool"));
10581
+ const byTier = { 1: [], 2: [], 3: [] };
10582
+ for (const tag of tags) {
10583
+ if (tag.status !== "active" || tag.type !== "tool")
10584
+ continue;
10585
+ if (tag.tagNumber > protectedCutoff)
10586
+ continue;
10587
+ if (protectedCtxReduceTags.has(tag.tagNumber))
10588
+ continue;
10589
+ const tier = resolveToolTier(tag.toolName);
10590
+ if ((tier === 1 || tier === 2) && reserved.has(tag.tagNumber))
10591
+ continue;
10592
+ byTier[tier].push(tag);
10593
+ }
10594
+ const selected = [];
10595
+ let reclaimed = 0;
10596
+ outer:
10597
+ for (const tier of [3, 2, 1]) {
10598
+ const group = byTier[tier];
10599
+ group.sort((a, b) => a.tagNumber - b.tagNumber);
10600
+ for (const tag of group) {
10601
+ selected.push(tag.tagNumber);
10602
+ reclaimed += estimateEmergencyDropReclaimTokens(tag);
10603
+ if (reclaimed >= reclaimTokens)
10604
+ break outer;
10605
+ }
10606
+ }
10607
+ if (selected.length === 0) {
10608
+ return noop("no-candidates");
10609
+ }
10610
+ return {
10611
+ shouldDrop: true,
10612
+ tagNumbers: selected,
10613
+ reclaimTokens,
10614
+ reason: `tiered drop: ${selected.length} tags, reclaim≈${reclaimed}/${reclaimTokens} tokens (floor≈${fixedFloor}, ceiling=${Math.round(ceilingTokens)})`
10615
+ };
10616
+ }
10617
+
9029
10618
  // src/features/magic-context/storage-tags.ts
9030
10619
  var insertTagStatements = new WeakMap;
9031
10620
  var updateTagStatusStatements = new WeakMap;
@@ -9069,32 +10658,23 @@ function ownerMessageIdForTagRow(row) {
9069
10658
  }
9070
10659
  return row.message_id.replace(CONTENT_ID_SUFFIX, "");
9071
10660
  }
9072
- function getActiveTagTokenAggregate(db, sessionId, protectedTags = 0) {
9073
- const toolOutputExpr = protectedTags > 0 ? `COALESCE(SUM(CASE WHEN type = 'tool' AND tag_number < (
9074
- SELECT tag_number FROM tags
9075
- WHERE session_id = ? AND status = 'active'
9076
- ORDER BY tag_number DESC LIMIT 1 OFFSET ?
9077
- ) THEN COALESCE(token_count, 0) ELSE 0 END), 0)` : `COALESCE(SUM(CASE WHEN type = 'tool' THEN COALESCE(token_count, 0) ELSE 0 END), 0)`;
9078
- const sql = `SELECT
9079
- COALESCE(SUM(CASE WHEN type != 'tool' THEN COALESCE(token_count, 0) ELSE 0 END), 0)
9080
- + COALESCE(SUM(COALESCE(reasoning_token_count, 0)), 0) AS conversation,
9081
- COALESCE(SUM(CASE WHEN type = 'tool' THEN COALESCE(token_count, 0) + COALESCE(input_token_count, 0) ELSE 0 END), 0) AS tool_call,
9082
- ${toolOutputExpr} AS tool_output,
9083
- COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
9084
- FROM tags
9085
- WHERE session_id = ? AND status = 'active'`;
9086
- const params = protectedTags > 0 ? [sessionId, protectedTags - 1, sessionId] : [sessionId];
9087
- const row = db.prepare(sql).get(...params);
9088
- return {
9089
- conversation: row?.conversation ?? 0,
9090
- toolCall: row?.tool_call ?? 0,
9091
- toolOutput: row?.tool_output ?? 0,
9092
- nullCount: row?.null_count ?? 0
9093
- };
9094
- }
9095
- var RECLAIM_HINT_EXCLUDED_TOOLS = ["todowrite"];
10661
+ var RECLAIM_HINT_EXCLUDED_TOOLS = new Set([
10662
+ "ask",
10663
+ "bash_kill",
10664
+ "bash_status",
10665
+ "board",
10666
+ "task",
10667
+ "todoread",
10668
+ "todowrite",
10669
+ "work"
10670
+ ]);
9096
10671
  var AGE_RECLAIM_MIN_TOKENS = 250;
9097
- var RECLAIM_HINT_EXCLUDED_LIST = RECLAIM_HINT_EXCLUDED_TOOLS.map((name) => `'${name.replace(/'/g, "''")}'`).join(", ");
10672
+ function isReclaimHintExcludedTool(toolName) {
10673
+ if (!toolName)
10674
+ return false;
10675
+ const normalized = toolName.toLowerCase().replace(/^mcp_/, "");
10676
+ return normalized.startsWith("ctx_") || RECLAIM_HINT_EXCLUDED_TOOLS.has(normalized);
10677
+ }
9098
10678
  function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, limit = 4) {
9099
10679
  if (limit <= 0)
9100
10680
  return [];
@@ -9104,24 +10684,21 @@ function getOldestActiveUnprotectedToolTags(db, sessionId, protectedTags = 0, li
9104
10684
  WHERE session_id = ? AND status = 'active'
9105
10685
  ORDER BY tag_number DESC LIMIT 1 OFFSET ?
9106
10686
  )` : "";
9107
- const excludeStateTools = RECLAIM_HINT_EXCLUDED_LIST ? `AND (tool_name IS NULL OR tool_name NOT IN (${RECLAIM_HINT_EXCLUDED_LIST}))` : "";
9108
10687
  const valueFloor = `AND (
9109
10688
  (token_count IS NULL AND input_token_count IS NULL)
9110
10689
  OR (COALESCE(token_count, 0) + COALESCE(input_token_count, 0)) >= ?
9111
10690
  )`;
9112
- const params = protectedTags > 0 ? [sessionId, AGE_RECLAIM_MIN_TOKENS, sessionId, protectedTags - 1, boundedLimit] : [sessionId, AGE_RECLAIM_MIN_TOKENS, boundedLimit];
10691
+ const params = protectedTags > 0 ? [sessionId, AGE_RECLAIM_MIN_TOKENS, sessionId, protectedTags - 1] : [sessionId, AGE_RECLAIM_MIN_TOKENS];
9113
10692
  const rows = db.prepare(`SELECT tag_number, tool_name
9114
10693
  FROM tags
9115
10694
  WHERE session_id = ? AND status = 'active' AND type = 'tool'
9116
- ${excludeStateTools}
9117
10695
  ${valueFloor}
9118
10696
  ${whereProtected}
9119
- ORDER BY tag_number ASC, id ASC
9120
- LIMIT ?`).all(...params);
10697
+ ORDER BY tag_number ASC, id ASC`).all(...params);
9121
10698
  return rows.filter((row) => typeof row.tag_number === "number").map((row) => ({
9122
10699
  tagNumber: row.tag_number,
9123
10700
  toolName: typeof row.tool_name === "string" ? row.tool_name : null
9124
- }));
10701
+ })).filter((tag) => !isReclaimHintExcludedTool(tag.toolName)).sort((left, right) => resolveToolTier(right.toolName) - resolveToolTier(left.toolName) || left.tagNumber - right.tagNumber).slice(0, boundedLimit);
9125
10702
  }
9126
10703
  var getActiveToolTagsForAgeReclaimStatements = new WeakMap;
9127
10704
  function getActiveToolTagsForAgeReclaim(db, sessionId) {
@@ -9134,7 +10711,7 @@ function getActiveToolTagsForAgeReclaim(db, sessionId) {
9134
10711
  getActiveToolTagsForAgeReclaimStatements.set(db, stmt);
9135
10712
  }
9136
10713
  const rows = stmt.all(sessionId);
9137
- return rows.filter((row) => typeof row.tag_number === "number").map((row) => {
10714
+ const tags = rows.filter((row) => typeof row.tag_number === "number").map((row) => {
9138
10715
  const outputTokens = typeof row.token_count === "number" ? row.token_count : null;
9139
10716
  const inputTokens = typeof row.input_token_count === "number" ? row.input_token_count : null;
9140
10717
  return {
@@ -9143,6 +10720,8 @@ function getActiveToolTagsForAgeReclaim(db, sessionId) {
9143
10720
  reclaimableTokens: outputTokens === null && inputTokens === null ? null : (outputTokens ?? 0) + (inputTokens ?? 0)
9144
10721
  };
9145
10722
  });
10723
+ const protectedCtxReduceTags = newestCtxReduceTagNumbers(tags);
10724
+ return tags.filter((tag) => !protectedCtxReduceTags.has(tag.tagNumber));
9146
10725
  }
9147
10726
  function getTriggerTagTokenUpperBound(db, sessionId, floor = 0) {
9148
10727
  const sql = floor > 0 ? `SELECT
@@ -9297,8 +10876,8 @@ function isMaxTagNumberRow(row) {
9297
10876
  function escapeLikePattern(value) {
9298
10877
  return value.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_");
9299
10878
  }
9300
- function insertTag(db, sessionId, messageId, type, byteSize, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0, toolOwnerMessageId = null, entryFingerprint = null, tokenCounts = null) {
9301
- getInsertTagStatement(db).run(sessionId, messageId, type, byteSize, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness(), toolOwnerMessageId, entryFingerprint, tokenCounts?.tokenCount ?? null, tokenCounts?.inputTokenCount ?? null, tokenCounts?.reasoningTokenCount ?? null);
10879
+ function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0, toolOwnerMessageId = null, entryFingerprint = null, tokenCounts = null) {
10880
+ getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness(), toolOwnerMessageId, entryFingerprint, tokenCounts?.tokenCount ?? null, tokenCounts?.inputTokenCount ?? null, tokenCounts?.reasoningTokenCount ?? null);
9302
10881
  return tagNumber;
9303
10882
  }
9304
10883
  function updateTagStatus(db, sessionId, tagId, status) {
@@ -9403,6 +10982,7 @@ function getTagsBySession(db, sessionId) {
9403
10982
  return rows.map(toTagEntry);
9404
10983
  }
9405
10984
  var getActiveTagsBySessionStatements = new WeakMap;
10985
+ var getNullOwnerToolTagsBySessionStatements = new WeakMap;
9406
10986
  var getDroppedTagsBySessionStatements = new WeakMap;
9407
10987
  var getMaxDroppedTagNumberStatements = new WeakMap;
9408
10988
  function getActiveTagsBySessionStatement(db) {
@@ -9433,6 +11013,24 @@ function getActiveTagsBySession(db, sessionId) {
9433
11013
  const rows = getActiveTagsBySessionStatement(db).all(sessionId).filter(isTagRow);
9434
11014
  return rows.map(toTagEntry);
9435
11015
  }
11016
+ function getTailHygieneTags(db, sessionId) {
11017
+ const active = getActiveTagsBySession(db, sessionId);
11018
+ let orphanStatement = getNullOwnerToolTagsBySessionStatements.get(db);
11019
+ if (!orphanStatement) {
11020
+ orphanStatement = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags
11021
+ WHERE session_id = ? AND type = 'tool' AND tool_owner_message_id IS NULL
11022
+ ORDER BY tag_number ASC, id ASC`);
11023
+ getNullOwnerToolTagsBySessionStatements.set(db, orphanStatement);
11024
+ }
11025
+ const seen = new Set(active.map((tag) => `${tag.tagNumber}\x00${tag.messageId}\x00${tag.type}`));
11026
+ for (const row of orphanStatement.all(sessionId).filter(isTagRow)) {
11027
+ const orphan = toTagEntry(row);
11028
+ const key = `${orphan.tagNumber}\x00${orphan.messageId}\x00${orphan.type}`;
11029
+ if (!seen.has(key))
11030
+ active.push(orphan);
11031
+ }
11032
+ return active;
11033
+ }
9436
11034
  function getDroppedTagsBySession(db, sessionId) {
9437
11035
  const rows = getDroppedTagsBySessionStatement(db).all(sessionId).filter(isTagRow);
9438
11036
  return rows.map(toTagEntry);
@@ -9651,7 +11249,7 @@ var LIMIT_EXTRACTION_PATTERNS = [
9651
11249
  pattern: /too large for model with (\d+) maximum context length/i,
9652
11250
  provenance: "combined"
9653
11251
  },
9654
- { pattern: /context size.*(\d+) tokens?/i, provenance: "combined" },
11252
+ { pattern: /context size[^0-9]{0,40}(\d{4,})\s*tokens?/i, provenance: "combined" },
9655
11253
  { pattern: /exceeds? the context length of (\d+)/i, provenance: "combined" },
9656
11254
  {
9657
11255
  pattern: />\s*(\d+)\s*(?:tokens?\s*)?(?:maximum|max|limit)\b/i,
@@ -9823,7 +11421,7 @@ async function abortChildRun(client, sessionId) {
9823
11421
  try {
9824
11422
  await Promise.race([
9825
11423
  client.session.abort({ path: { id: sessionId } }),
9826
- new Promise((resolve) => setTimeout(resolve, ABORT_CALL_TIMEOUT_MS))
11424
+ new Promise((resolve2) => setTimeout(resolve2, ABORT_CALL_TIMEOUT_MS))
9827
11425
  ]);
9828
11426
  } catch (error) {
9829
11427
  log(`[model-retry] child session abort failed for ${sessionId}: ${String(error)}`);
@@ -10052,16 +11650,25 @@ function modelKeyLookupOrder(modelKey) {
10052
11650
  return [];
10053
11651
  const provider = modelKey.slice(0, slash);
10054
11652
  let modelID = modelKey.slice(slash + 1);
11653
+ const providerRefs = modelRefLookupOrder(`${provider}/${modelID}`);
10055
11654
  const candidates = [];
10056
11655
  while (modelID.length > 0) {
10057
- candidates.push({ key: `${provider}/${modelID}`, source: "exact" });
11656
+ for (const providerRef of providerRefs) {
11657
+ const providerSlash = providerRef.indexOf("/");
11658
+ const providerPrefix = providerRef.slice(0, providerSlash);
11659
+ candidates.push({ key: `${providerPrefix}/${modelID}`, source: "exact" });
11660
+ }
10058
11661
  candidates.push({ key: modelID, source: "bare" });
10059
11662
  const lastDash = modelID.lastIndexOf("-");
10060
11663
  if (lastDash <= 0)
10061
11664
  break;
10062
11665
  modelID = modelID.slice(0, lastDash);
10063
11666
  }
10064
- candidates.push({ key: `${provider}/*`, source: "wildcard" });
11667
+ for (const providerRef of providerRefs) {
11668
+ const providerSlash = providerRef.indexOf("/");
11669
+ const providerPrefix = providerRef.slice(0, providerSlash);
11670
+ candidates.push({ key: `${providerPrefix}/*`, source: "wildcard" });
11671
+ }
10065
11672
  const seen = new Set;
10066
11673
  return candidates.filter((candidate) => {
10067
11674
  if (seen.has(candidate.key))
@@ -10094,7 +11701,7 @@ function resolveModelConfigOrDefault(values, modelKey, fallback) {
10094
11701
  }
10095
11702
  // src/shared/prompt-surface-runtime.ts
10096
11703
  import { existsSync as existsSync5, readFileSync as readFileSync5, statSync as statSync5 } from "node:fs";
10097
- import { dirname as dirname3, isAbsolute as isAbsolute2, resolve } from "node:path";
11704
+ import { dirname as dirname3, isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
10098
11705
 
10099
11706
  // src/config/migrate-config-location.ts
10100
11707
  import {
@@ -10505,7 +12112,7 @@ function promptSurfaceHashMaterial(systemContent, preset = "full") {
10505
12112
  var PROMPT_SURFACE_TOOL_ID_SET = new Set(ACTIVE_TOOL_IDS);
10506
12113
  function resolveUserConfigDirectory(options) {
10507
12114
  if (options.userConfigDirectory)
10508
- return resolve(options.userConfigDirectory);
12115
+ return resolve2(options.userConfigDirectory);
10509
12116
  const sharedBase = cortexKitUserConfigBasePath();
10510
12117
  const shared = detectConfigFile(sharedBase);
10511
12118
  if (shared.format !== "none")
@@ -10532,7 +12139,7 @@ function createPromptSurfaceRuntime(options) {
10532
12139
  const readGuidanceOverride = (configuredPath) => {
10533
12140
  if (!configuredPath)
10534
12141
  return;
10535
- const path3 = isAbsolute2(configuredPath) ? configuredPath : resolve(userConfigDirectory, configuredPath);
12142
+ const path3 = isAbsolute2(configuredPath) ? configuredPath : resolve2(userConfigDirectory, configuredPath);
10536
12143
  let content;
10537
12144
  try {
10538
12145
  if (!statSync5(path3).isFile()) {
@@ -10592,12 +12199,13 @@ function createPromptSurfaceGuidanceEpochCache(runtime) {
10592
12199
  const epochs = new Map;
10593
12200
  return {
10594
12201
  resolve(sessionId, config, modelKey) {
12202
+ const canonicalModelKey = modelKey ? piModelRefToCanonical(modelKey) : undefined;
10595
12203
  const cached = epochs.get(sessionId);
10596
- if (cached && cached.config === config && cached.modelKey === modelKey) {
12204
+ if (cached && cached.config === config && cached.modelKey === canonicalModelKey) {
10597
12205
  return cached.selection;
10598
12206
  }
10599
- const selection = runtime.resolveGuidance(config, modelKey);
10600
- epochs.set(sessionId, { config, modelKey, selection });
12207
+ const selection = runtime.resolveGuidance(config, canonicalModelKey);
12208
+ epochs.set(sessionId, { config, modelKey: canonicalModelKey, selection });
10601
12209
  return selection;
10602
12210
  },
10603
12211
  clear(sessionId) {
@@ -10703,13 +12311,44 @@ function pruneExpiredUserMemoryCandidates(db, ttlMs, now = Date.now()) {
10703
12311
  const result = db.prepare("DELETE FROM user_memory_candidates WHERE created_at < ?").run(cutoff);
10704
12312
  return Number(result.changes ?? 0);
10705
12313
  }
12314
+ function loadUserMemorySourceProvenance(db, candidateIds) {
12315
+ const ids = [...new Set(candidateIds)].sort((a, b) => a - b);
12316
+ if (ids.length === 0)
12317
+ return [];
12318
+ const placeholders3 = ids.map(() => "?").join(",");
12319
+ const rows = db.prepare(`SELECT id, session_id, source_compartment_start, source_compartment_end
12320
+ FROM user_memory_candidates
12321
+ WHERE id IN (${placeholders3})
12322
+ ORDER BY id ASC`).all(...ids);
12323
+ return rows.map((row) => ({
12324
+ candidateId: row.id,
12325
+ sessionId: row.session_id,
12326
+ sourceCompartmentStart: row.source_compartment_start,
12327
+ sourceCompartmentEnd: row.source_compartment_end
12328
+ }));
12329
+ }
12330
+ function serializeUserMemorySourceProvenance(provenance, sourceCandidateIds) {
12331
+ if (provenance.length === 0 && sourceCandidateIds.length > 0)
12332
+ return null;
12333
+ return JSON.stringify(provenance.map((source) => ({
12334
+ candidate_id: source.candidateId,
12335
+ session_id: source.sessionId,
12336
+ source_compartment_start: source.sourceCompartmentStart,
12337
+ source_compartment_end: source.sourceCompartmentEnd
12338
+ })));
12339
+ }
10706
12340
  function insertUserMemory(db, content, sourceCandidateIds) {
10707
- const now = Date.now();
10708
- const result = db.prepare("INSERT INTO user_memories (content, status, promoted_at, source_candidate_ids, created_at, updated_at) VALUES (?, 'active', ?, ?, ?, ?)").run(content, now, JSON.stringify(sourceCandidateIds), now, now);
10709
- return Number(result.lastInsertRowid);
12341
+ return db.transaction(() => {
12342
+ const now = Date.now();
12343
+ const sourceProvenance = loadUserMemorySourceProvenance(db, sourceCandidateIds);
12344
+ const result = db.prepare(`INSERT INTO user_memories
12345
+ (content, status, promoted_at, source_candidate_ids, source_candidate_provenance, created_at, updated_at)
12346
+ VALUES (?, 'active', ?, ?, ?, ?, ?)`).run(content, now, JSON.stringify(sourceCandidateIds), serializeUserMemorySourceProvenance(sourceProvenance, sourceCandidateIds), now, now);
12347
+ return Number(result.lastInsertRowid);
12348
+ })();
10710
12349
  }
10711
12350
  function getActiveUserMemories(db) {
10712
- const rows = db.prepare("SELECT id, content, status, promoted_at, source_candidate_ids, created_at, updated_at FROM user_memories WHERE status = 'active' ORDER BY promoted_at ASC, id ASC").all();
12351
+ const rows = db.prepare("SELECT id, content, status, promoted_at, source_candidate_ids, source_candidate_provenance, created_at, updated_at FROM user_memories WHERE status = 'active' ORDER BY promoted_at ASC, id ASC").all();
10713
12352
  return rows.map(parseUserMemoryRow);
10714
12353
  }
10715
12354
  function updateUserMemoryContent(db, id, content) {
@@ -10718,26 +12357,58 @@ function updateUserMemoryContent(db, id, content) {
10718
12357
  function dismissUserMemory(db, id) {
10719
12358
  db.prepare("UPDATE user_memories SET status = 'dismissed', updated_at = ? WHERE id = ?").run(Date.now(), id);
10720
12359
  }
10721
- function parseUserMemoryRow(row) {
10722
- let candidateIds = [];
12360
+ function parseCandidateIds2(raw) {
10723
12361
  try {
10724
- candidateIds = JSON.parse(row.source_candidate_ids);
10725
- } catch {}
12362
+ const parsed = JSON.parse(raw);
12363
+ return Array.isArray(parsed) ? parsed.filter((id) => typeof id === "number" && Number.isFinite(id)) : [];
12364
+ } catch {
12365
+ return [];
12366
+ }
12367
+ }
12368
+ function parseUserMemorySourceProvenance(raw) {
12369
+ if (raw === null)
12370
+ return null;
12371
+ try {
12372
+ const parsed = JSON.parse(raw);
12373
+ if (!Array.isArray(parsed))
12374
+ return null;
12375
+ const provenance = [];
12376
+ for (const value of parsed) {
12377
+ if (!value || typeof value !== "object")
12378
+ return null;
12379
+ const source = value;
12380
+ if (typeof source.candidate_id !== "number" || !Number.isFinite(source.candidate_id) || typeof source.session_id !== "string" || source.source_compartment_start !== null && typeof source.source_compartment_start !== "number" || source.source_compartment_end !== null && typeof source.source_compartment_end !== "number") {
12381
+ return null;
12382
+ }
12383
+ provenance.push({
12384
+ candidateId: source.candidate_id,
12385
+ sessionId: source.session_id,
12386
+ sourceCompartmentStart: source.source_compartment_start,
12387
+ sourceCompartmentEnd: source.source_compartment_end
12388
+ });
12389
+ }
12390
+ return provenance;
12391
+ } catch {
12392
+ return null;
12393
+ }
12394
+ }
12395
+ function parseUserMemoryRow(row) {
10726
12396
  return {
10727
12397
  id: row.id,
10728
12398
  content: row.content,
10729
12399
  status: row.status === "dismissed" ? "dismissed" : "active",
10730
12400
  promotedAt: row.promoted_at,
10731
- sourceCandidateIds: candidateIds,
12401
+ sourceCandidateIds: parseCandidateIds2(row.source_candidate_ids),
12402
+ sourceProvenance: parseUserMemorySourceProvenance(row.source_candidate_provenance),
10732
12403
  createdAt: row.created_at,
10733
12404
  updatedAt: row.updated_at
10734
12405
  };
10735
12406
  }
10736
12407
 
10737
12408
  // src/features/magic-context/mural/storage-mural-cues.ts
10738
- import { createHash as createHash8 } from "node:crypto";
12409
+ import { createHash as createHash9 } from "node:crypto";
10739
12410
  function computeCueContentHash(content) {
10740
- return createHash8("sha256").update(content).digest("hex");
12411
+ return createHash9("sha256").update(content).digest("hex");
10741
12412
  }
10742
12413
  var muralCueColumnCache = new WeakMap;
10743
12414
  var muralCueRejectionColumnCache = new WeakMap;
@@ -10935,13 +12606,13 @@ function invalidateMemory(projectPath, memoryId) {
10935
12606
  }
10936
12607
 
10937
12608
  // src/features/magic-context/memory/normalize-hash.ts
10938
- import { createHash as createHash9 } from "node:crypto";
12609
+ import { createHash as createHash10 } from "node:crypto";
10939
12610
  function normalizeMemoryContent(content) {
10940
12611
  return content.toLowerCase().replace(/\s+/g, " ").trim();
10941
12612
  }
10942
12613
  function computeNormalizedHash(content) {
10943
12614
  const normalized = normalizeMemoryContent(content);
10944
- return createHash9("md5").update(normalized).digest("hex");
12615
+ return createHash10("md5").update(normalized).digest("hex");
10945
12616
  }
10946
12617
 
10947
12618
  // src/features/magic-context/memory/visibility.ts
@@ -11910,7 +13581,7 @@ async function runMemoryMigration(deps) {
11910
13581
  }
11911
13582
 
11912
13583
  // src/features/magic-context/compartment-chunk-embedding.ts
11913
- import { createHash as createHash10 } from "node:crypto";
13584
+ import { createHash as createHash11 } from "node:crypto";
11914
13585
 
11915
13586
  // src/features/magic-context/recursive-text-splitter.ts
11916
13587
  var DEFAULT_SEPARATORS = [`
@@ -12195,7 +13866,7 @@ function parseCanonicalLineRange(line) {
12195
13866
  return { start, end };
12196
13867
  }
12197
13868
  function hashChunkText(text) {
12198
- return createHash10("sha256").update(text).digest("hex");
13869
+ return createHash11("sha256").update(text).digest("hex");
12199
13870
  }
12200
13871
  function vectorBlob2(vector) {
12201
13872
  return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
@@ -12586,7 +14257,7 @@ function countSessionCompartmentEmbedCoverage(db, projectPath, sessionId, modelI
12586
14257
  }
12587
14258
 
12588
14259
  // src/features/magic-context/project-embedding-registry.ts
12589
- import { createHash as createHash12, randomUUID as randomUUID2 } from "node:crypto";
14260
+ import { createHash as createHash13, randomUUID as randomUUID2 } from "node:crypto";
12590
14261
 
12591
14262
  // src/config/schema/magic-context.ts
12592
14263
  import { homedir as homedir3 } from "node:os";
@@ -27252,7 +28923,10 @@ var MagicContextConfigSchema = exports_external.object({
27252
28923
  output_reserve: exports_external.union([
27253
28924
  exports_external.number().min(0),
27254
28925
  exports_external.object({ default: exports_external.number().min(0) }).catchall(exports_external.number().min(0))
27255
- ]).optional().describe('User-only output-token reservation override. Number or per-model object ({ default: 16384, "provider/model": 8192 }); 0 disables reservation. When unset, Magic Context reserves the catalog output limit (capped at 25% of context) for shared-window providers and keeps proven separate-quota Google/Gemini windows unchanged.'),
28926
+ ]).optional().describe('User-only output-token reservation override. Number or per-model object ({ default: 16384, "provider/model": 8192 }); 0 disables reservation. Takes precedence over every derived source: an explicit value here always wins against catalog output limits, provider window-geometry facts, and the 25%-of-context fallback (usable window = context window minus this reserve). When unset, Magic Context reserves the catalog output limit (capped at 25% of context) for shared-window providers and keeps proven separate-quota Google/Gemini windows unchanged.'),
28927
+ models: exports_external.object({
28928
+ window_overlay_path: exports_external.string().trim().min(1).optional()
28929
+ }).optional().describe("User-only Fusiform window-overlay settings. The path defaults to <dataDir>/fusiform/window-overlay.json."),
27256
28930
  toast_duration_ms: exports_external.number().min(0).max(60000).default(5000).describe("TUI toast lifetime in milliseconds for Magic Context notifications. Set to 0 to disable Magic Context toasts entirely (min: 0, max: 60000, default: 5000)"),
27257
28931
  execute_threshold_percentage: exports_external.union([
27258
28932
  exports_external.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE),
@@ -27304,7 +28978,7 @@ var MagicContextConfigSchema = exports_external.object({
27304
28978
  overlay: exports_external.boolean().default(true).describe("Pi only: show the persistent todo overlay above the editor while tasks are active.")
27305
28979
  }).default({ enabled: true, overlay: true }).describe("Pi-only todowrite tool and overlay controls. Pi registers tools and widgets at extension boot, so changing this after /cd requires /reload or restart."),
27306
28980
  pi: PiConfigSchema.describe("Pi-only child-process extension controls. This setting is user-level only; project configuration cannot choose which extensions a user's subagent children load."),
27307
- smart_drops: exports_external.boolean().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 5), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
28981
+ smart_drops: exports_external.boolean().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 3), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
27308
28982
  caveman_text_compression: exports_external.object({
27309
28983
  enabled: exports_external.boolean().default(false).describe("Apply deterministic caveman-style text compression to old conversation text. Active for primary sessions when enabled; never for subagents. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%)."),
27310
28984
  min_chars: exports_external.number().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
@@ -27656,7 +29330,7 @@ function releaseGitSweepLease(db, projectPath, holderId) {
27656
29330
  }
27657
29331
 
27658
29332
  // src/features/magic-context/memory/embedding-synapse.ts
27659
- import { createHash as createHash11 } from "node:crypto";
29333
+ import { createHash as createHash12 } from "node:crypto";
27660
29334
 
27661
29335
  // ../../node_modules/.bun/@cortexkit+subc-client@0.4.1/node_modules/@cortexkit/subc-client/dist/client.js
27662
29336
  import { promises as fs2 } from "node:fs";
@@ -28030,7 +29704,7 @@ class SubcSocket {
28030
29704
  return this.sock.localPort ?? null;
28031
29705
  }
28032
29706
  static connect(host, port, deadlineMs) {
28033
- return new Promise((resolve2, reject) => {
29707
+ return new Promise((resolve3, reject) => {
28034
29708
  const sock = net.connect({ host, port });
28035
29709
  sock.setNoDelay(true);
28036
29710
  const timer = setTimeout(() => {
@@ -28039,7 +29713,7 @@ class SubcSocket {
28039
29713
  }, Math.max(0, deadlineMs - Date.now()));
28040
29714
  sock.once("connect", () => {
28041
29715
  clearTimeout(timer);
28042
- resolve2(new SubcSocket(sock));
29716
+ resolve3(new SubcSocket(sock));
28043
29717
  });
28044
29718
  sock.once("error", (err) => {
28045
29719
  clearTimeout(timer);
@@ -28071,7 +29745,7 @@ class SubcSocket {
28071
29745
  }
28072
29746
  if (n === 0)
28073
29747
  return Promise.resolve(new Uint8Array(0));
28074
- return new Promise((resolve2, reject) => {
29748
+ return new Promise((resolve3, reject) => {
28075
29749
  let timer = null;
28076
29750
  if (Number.isFinite(deadlineMs)) {
28077
29751
  const remaining = deadlineMs - Date.now();
@@ -28084,7 +29758,7 @@ class SubcSocket {
28084
29758
  reject(new SocketTimeoutError(`timed out waiting for ${n} bytes`));
28085
29759
  }, remaining);
28086
29760
  }
28087
- this.waiter = { need: n, resolve: resolve2, reject, timer };
29761
+ this.waiter = { need: n, resolve: resolve3, reject, timer };
28088
29762
  this.tryServe();
28089
29763
  });
28090
29764
  }
@@ -28108,7 +29782,7 @@ class SubcSocket {
28108
29782
  let queued = false;
28109
29783
  let settled = false;
28110
29784
  let timer = null;
28111
- const completed = new Promise((resolve2, reject) => {
29785
+ const completed = new Promise((resolve3, reject) => {
28112
29786
  const settle = (run) => {
28113
29787
  if (settled)
28114
29788
  return;
@@ -28132,7 +29806,7 @@ class SubcSocket {
28132
29806
  if (err) {
28133
29807
  reject(new SocketWriteQueuedError("subc socket reported a write error after bytes were handed to the socket", err instanceof Error ? err : new Error(String(err))));
28134
29808
  } else {
28135
- resolve2();
29809
+ resolve3();
28136
29810
  }
28137
29811
  });
28138
29812
  });
@@ -28348,14 +30022,14 @@ class SubcClient {
28348
30022
  const admission = opts.admissionClass ?? AdmissionClass.Normal;
28349
30023
  const corr = this.allocateCorr();
28350
30024
  const key = pendingKey(handle, corr);
28351
- const closed = new Promise((resolve2, reject) => {
30025
+ const closed = new Promise((resolve3, reject) => {
28352
30026
  if (this.closedErr) {
28353
30027
  reject(this.closedErr);
28354
30028
  return;
28355
30029
  }
28356
30030
  this.pending.set(key, {
28357
30031
  handle,
28358
- resolve: () => resolve2(),
30032
+ resolve: () => resolve3(),
28359
30033
  reject,
28360
30034
  onProgress: onEvent,
28361
30035
  timer: null,
@@ -28440,11 +30114,11 @@ class SubcClient {
28440
30114
  const waiters = [];
28441
30115
  for (const pending of this.pending.values()) {
28442
30116
  if (pending.handle === handle && !pending.subscription) {
28443
- waiters.push(new Promise((resolve2) => {
30117
+ waiters.push(new Promise((resolve3) => {
28444
30118
  const previous = pending.onSettle;
28445
30119
  pending.onSettle = () => {
28446
30120
  previous?.();
28447
- resolve2();
30121
+ resolve3();
28448
30122
  };
28449
30123
  }));
28450
30124
  }
@@ -28500,11 +30174,11 @@ class SubcClient {
28500
30174
  const channel = handle?.channel ?? 0;
28501
30175
  const epoch = handle?.epoch ?? 0;
28502
30176
  const frame = buildFrame(FrameType.Request, buildFlags(false, priority, false, admission), channel, epoch, corr, body);
28503
- return new Promise((resolve2, reject) => {
30177
+ return new Promise((resolve3, reject) => {
28504
30178
  const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
28505
30179
  const pending = {
28506
30180
  handle,
28507
- resolve: resolve2,
30181
+ resolve: resolve3,
28508
30182
  reject,
28509
30183
  onProgress,
28510
30184
  timer: null,
@@ -28578,11 +30252,11 @@ class SubcClient {
28578
30252
  }
28579
30253
  return this.outcomeUnknownCallError("connection dropped before the managed call returned a response", error51);
28580
30254
  };
28581
- return new Promise((resolve2, reject) => {
30255
+ return new Promise((resolve3, reject) => {
28582
30256
  const ms = timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
28583
30257
  const pending = {
28584
30258
  handle,
28585
- resolve: resolve2,
30259
+ resolve: resolve3,
28586
30260
  reject,
28587
30261
  onProgress,
28588
30262
  timer: null,
@@ -28970,7 +30644,7 @@ function normalizeConnectOptions(opts) {
28970
30644
  identity: opts.identity,
28971
30645
  targetKind: opts.targetKind ?? DEFAULT_MANAGED_TARGET_KIND,
28972
30646
  reconnectBackoff: opts.reconnectBackoff ?? DEFAULT_RECONNECT_BACKOFF,
28973
- sleep: opts.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms))),
30647
+ sleep: opts.sleep ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms))),
28974
30648
  timeoutArbitrationGraceMs: opts.timeoutArbitrationGraceMs ?? TIMEOUT_ARBITRATION_GRACE_MS
28975
30649
  };
28976
30650
  }
@@ -29027,8 +30701,8 @@ class AsyncPermitPool {
29027
30701
  this.available -= 1;
29028
30702
  return this.releaseOnce();
29029
30703
  }
29030
- await new Promise((resolve2) => {
29031
- this.waiters.push(resolve2);
30704
+ await new Promise((resolve3) => {
30705
+ this.waiters.push(resolve3);
29032
30706
  });
29033
30707
  return this.releaseOnce();
29034
30708
  }
@@ -29084,8 +30758,8 @@ class SubcProvider {
29084
30758
  this.currentConn = currentConn;
29085
30759
  this.opts = opts;
29086
30760
  this.storage = storage;
29087
- this.closed = new Promise((resolve2) => {
29088
- this.resolveClosed = resolve2;
30761
+ this.closed = new Promise((resolve3) => {
30762
+ this.resolveClosed = resolve3;
29089
30763
  });
29090
30764
  this.readLoop(sock, this.generation);
29091
30765
  this.enqueueConnectionState({ state: "connected", epoch: this.connectionEpoch });
@@ -29105,13 +30779,13 @@ class SubcProvider {
29105
30779
  const key = routeKey(handle, corr);
29106
30780
  const timeoutMs = opts.timeoutMs ?? WRITE_TIMEOUT_MS;
29107
30781
  const frame = buildFrame(FrameType.Request, buildFlags(false, opts.priority ?? Priority.Interactive, false, opts.admissionClass ?? AdmissionClass.Normal), handle.channel, handle.epoch, corr, body);
29108
- return await new Promise((resolve2, reject) => {
30782
+ return await new Promise((resolve3, reject) => {
29109
30783
  const timer = setTimeout(() => {
29110
30784
  if (this.pending.delete(key))
29111
30785
  reject(new SubcProviderError("reverse request timed out", "request_timeout"));
29112
30786
  }, timeoutMs);
29113
30787
  this.pending.set(key, {
29114
- resolve: (response) => resolve2(response.body),
30788
+ resolve: (response) => resolve3(response.body),
29115
30789
  reject,
29116
30790
  timer
29117
30791
  });
@@ -29583,7 +31257,7 @@ function normalizeProviderConnectOptions(opts) {
29583
31257
  onBound: opts.onBound,
29584
31258
  onRouteGone: opts.onRouteGone,
29585
31259
  reconnectBackoff: opts.reconnectBackoff ?? DEFAULT_RECONNECT_BACKOFF,
29586
- sleep: opts.sleep ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms))),
31260
+ sleep: opts.sleep ?? ((ms) => new Promise((resolve3) => setTimeout(resolve3, ms))),
29587
31261
  restoredDebounceMs: opts.restoredDebounceMs ?? DEFAULT_RESTORED_DEBOUNCE_MS,
29588
31262
  onConnectionState: opts.onConnectionState,
29589
31263
  launchNonce: opts.launchNonce
@@ -29628,7 +31302,7 @@ function errorCode2(err) {
29628
31302
  return;
29629
31303
  }
29630
31304
  async function pauseBeforeStateRetry() {
29631
- await new Promise((resolve2) => setTimeout(resolve2, 0));
31305
+ await new Promise((resolve3) => setTimeout(resolve3, 0));
29632
31306
  }
29633
31307
  function controlFlags() {
29634
31308
  return buildFlags(false, Priority.Passive, false);
@@ -29866,10 +31540,10 @@ function classifyError(value) {
29866
31540
  });
29867
31541
  }
29868
31542
  function wait(ms) {
29869
- return new Promise((resolve2) => setTimeout(resolve2, ms));
31543
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
29870
31544
  }
29871
31545
  function sha256(value) {
29872
- return createHash11("sha256").update(value).digest("hex");
31546
+ return createHash12("sha256").update(value).digest("hex");
29873
31547
  }
29874
31548
  function stableJson(value) {
29875
31549
  if (Array.isArray(value))
@@ -30375,7 +32049,7 @@ async function acquireModelLoadLock(lockPath) {
30375
32049
  if (Date.now() - waitStart > MAX_LOCK_WAIT_MS) {
30376
32050
  throw new Error(`[magic-context] embedding-load lock wait exceeded ${MAX_LOCK_WAIT_MS}ms; another process is still loading the model. Skipping this init attempt to avoid an unsynchronized native load.`);
30377
32051
  }
30378
- await new Promise((resolve2) => setTimeout(resolve2, LOCK_POLL_MS));
32052
+ await new Promise((resolve3) => setTimeout(resolve3, LOCK_POLL_MS));
30379
32053
  }
30380
32054
  }
30381
32055
  }
@@ -30580,7 +32254,7 @@ class LocalEmbeddingProvider {
30580
32254
  }
30581
32255
  const delayMs = 300 * attempt + Math.floor(Math.random() * 200);
30582
32256
  log(`[magic-context] embedding model load attempt ${attempt}/${MAX_ATTEMPTS} failed transiently, retrying in ${delayMs}ms`);
30583
- await new Promise((resolve2) => setTimeout(resolve2, delayMs));
32257
+ await new Promise((resolve3) => setTimeout(resolve3, delayMs));
30584
32258
  }
30585
32259
  }
30586
32260
  if (this.pipeline) {
@@ -30613,8 +32287,8 @@ class LocalEmbeddingProvider {
30613
32287
  if (this.inFlight === 0) {
30614
32288
  return Promise.resolve();
30615
32289
  }
30616
- return new Promise((resolve2) => {
30617
- this.inFlightWaiters.push(resolve2);
32290
+ return new Promise((resolve3) => {
32291
+ this.inFlightWaiters.push(resolve3);
30618
32292
  });
30619
32293
  }
30620
32294
  finishInFlight() {
@@ -30769,9 +32443,14 @@ function blockedEmbeddingEndpointReason(endpoint) {
30769
32443
  function normalizeEndpoint2(endpoint) {
30770
32444
  return endpoint?.trim().replace(/\/+$/, "") ?? "";
30771
32445
  }
30772
- function embeddingModelsMatch(served, requested) {
30773
- const a = served.trim().toLowerCase();
30774
- const b = requested.trim().toLowerCase();
32446
+ function parseEmbeddingModel(model) {
32447
+ const lastColon = model.lastIndexOf(":");
32448
+ if (lastColon > model.lastIndexOf("/")) {
32449
+ return { base: model.slice(0, lastColon), tag: model.slice(lastColon + 1) };
32450
+ }
32451
+ return { base: model };
32452
+ }
32453
+ function matchNormalizedEmbeddingModels(a, b) {
30775
32454
  if (a.length === 0 || b.length === 0)
30776
32455
  return true;
30777
32456
  if (a === b)
@@ -30785,6 +32464,16 @@ function embeddingModelsMatch(served, requested) {
30785
32464
  return true;
30786
32465
  return false;
30787
32466
  }
32467
+ function embeddingModelsMatch(served, requested) {
32468
+ const a = served.trim().toLowerCase();
32469
+ const b = requested.trim().toLowerCase();
32470
+ const servedModel = parseEmbeddingModel(a);
32471
+ const requestedModel = parseEmbeddingModel(b);
32472
+ if (servedModel.tag !== undefined && requestedModel.tag !== undefined && servedModel.tag !== requestedModel.tag) {
32473
+ return false;
32474
+ }
32475
+ return matchNormalizedEmbeddingModels(servedModel.base, requestedModel.base);
32476
+ }
30788
32477
  var FAILURE_THRESHOLD = 3;
30789
32478
  var FAILURE_WINDOW_MS = 60000;
30790
32479
  var OPEN_DURATION_MS = 5 * 60000;
@@ -30915,7 +32604,7 @@ class OpenAICompatibleEmbeddingProvider {
30915
32604
  const servedModel = typeof body.model === "string" ? body.model : "";
30916
32605
  if (this.model && servedModel && !embeddingModelsMatch(servedModel, this.model)) {
30917
32606
  if (!this.modelMismatchLogged) {
30918
- log(`[magic-context] embedding endpoint served a DIFFERENT model than requested — refusing the substituted vectors (they have the wrong dimensions/space). requested="${this.model}" served="${servedModel}". The endpoint likely substituted a loaded model; load/select "${this.model}" on the endpoint, or set embedding.model to the served model.`);
32607
+ log(`[magic-context] embedding endpoint served a DIFFERENT model than requested — refusing the substituted vectors (they have the wrong dimensions/space). requested="${this.model}" served="${servedModel}". Check that the endpoint serves the requested model; variant suffixes and vendor prefixes are matched automatically.`);
30919
32608
  this.modelMismatchLogged = true;
30920
32609
  }
30921
32610
  this.recordFailure(isProbe);
@@ -31302,10 +32991,10 @@ function stableStringify2(value) {
31302
32991
  return JSON.stringify(value);
31303
32992
  }
31304
32993
  function sha256Prefix(value, length = 16) {
31305
- return createHash12("sha256").update(value).digest("hex").slice(0, length);
32994
+ return createHash13("sha256").update(value).digest("hex").slice(0, length);
31306
32995
  }
31307
32996
  function contentSha256(value) {
31308
- return createHash12("sha256").update(value).digest("hex");
32997
+ return createHash13("sha256").update(value).digest("hex");
31309
32998
  }
31310
32999
  function getRuntimeFingerprint(config2) {
31311
33000
  if (config2.provider === "off") {
@@ -31505,14 +33194,14 @@ function hasStaleEmbeddingRows(db, scope, projectIdentity, modelId) {
31505
33194
  LIMIT 1`).get(projectIdentity, modelId));
31506
33195
  }
31507
33196
  function sweepStaleEmbeddingIdentitiesForProject(db, projectIdentity, now = Date.now()) {
31508
- const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
33197
+ const snapshot2 = getProjectEmbeddingSnapshot(projectIdentity);
31509
33198
  const result = {
31510
33199
  memoryRowsDeleted: 0,
31511
33200
  commitRowsDeleted: 0,
31512
33201
  chunkRowsDeleted: 0,
31513
33202
  trackingRowsDeleted: 0
31514
33203
  };
31515
- if (!snapshot)
33204
+ if (!snapshot2)
31516
33205
  return result;
31517
33206
  if (untrustedLoadProjects.has(projectIdentity))
31518
33207
  return result;
@@ -31520,25 +33209,25 @@ function sweepStaleEmbeddingIdentitiesForProject(db, projectIdentity, now = Date
31520
33209
  const deleteTracking = getDeleteActiveIdentityStatement(db);
31521
33210
  const shadow = shadowRegistrations.get(projectIdentity);
31522
33211
  const protectedModels = {
31523
- memory: new Set([snapshot.modelId, ...shadow ? [shadow.modelId] : []]),
31524
- commit: new Set([snapshot.modelId, ...shadow ? [shadow.modelId] : []]),
31525
- chunk: new Set([snapshot.chunkModelId, ...shadow ? [shadow.chunkModelId] : []])
33212
+ memory: new Set([snapshot2.modelId, ...shadow ? [shadow.modelId] : []]),
33213
+ commit: new Set([snapshot2.modelId, ...shadow ? [shadow.modelId] : []]),
33214
+ chunk: new Set([snapshot2.chunkModelId, ...shadow ? [shadow.chunkModelId] : []])
31526
33215
  };
31527
33216
  const scopes = [
31528
33217
  {
31529
33218
  scope: "memory",
31530
- enabled: snapshot.enabled && snapshot.modelId !== "off",
31531
- currentModelId: snapshot.modelId
33219
+ enabled: snapshot2.enabled && snapshot2.modelId !== "off",
33220
+ currentModelId: snapshot2.modelId
31532
33221
  },
31533
33222
  {
31534
33223
  scope: "commit",
31535
- enabled: snapshot.gitCommitEnabled && snapshot.modelId !== "off",
31536
- currentModelId: snapshot.modelId
33224
+ enabled: snapshot2.gitCommitEnabled && snapshot2.modelId !== "off",
33225
+ currentModelId: snapshot2.modelId
31537
33226
  },
31538
33227
  {
31539
33228
  scope: "chunk",
31540
- enabled: snapshot.enabled && snapshot.chunkModelId !== "off",
31541
- currentModelId: snapshot.chunkModelId
33229
+ enabled: snapshot2.enabled && snapshot2.chunkModelId !== "off",
33230
+ currentModelId: snapshot2.chunkModelId
31542
33231
  }
31543
33232
  ];
31544
33233
  let remainingBudget = STALE_EMBEDDING_GC_BATCH_SIZE;
@@ -31994,7 +33683,7 @@ async function runShadowWorker() {
31994
33683
  }
31995
33684
  processed += item.ids.length;
31996
33685
  processedBytes += itemBytes;
31997
- await new Promise((resolve2) => setTimeout(resolve2, 0));
33686
+ await new Promise((resolve3) => setTimeout(resolve3, 0));
31998
33687
  }
31999
33688
  }
32000
33689
  function registerProjectInObservationMode(db, projectIdentity, sourceDirectory, failedConfig, failureSummary) {
@@ -32177,11 +33866,11 @@ function getLoadUnembeddedMemoriesStatement(db) {
32177
33866
  return stmt;
32178
33867
  }
32179
33868
  async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize = 10) {
32180
- const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
32181
- if (!snapshot?.enabled)
33869
+ const snapshot2 = getProjectEmbeddingSnapshot(projectIdentity);
33870
+ if (!snapshot2?.enabled)
32182
33871
  return 0;
32183
33872
  const normalizedBatchSize = Math.max(1, Math.floor(batchSize));
32184
- const memories = getLoadUnembeddedMemoriesStatement(db).all(snapshot.modelId, projectIdentity, normalizedBatchSize).filter(isUnembeddedMemoryRow);
33873
+ const memories = getLoadUnembeddedMemoriesStatement(db).all(snapshot2.modelId, projectIdentity, normalizedBatchSize).filter(isUnembeddedMemoryRow);
32185
33874
  if (memories.length === 0)
32186
33875
  return 0;
32187
33876
  try {
@@ -32211,10 +33900,10 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
32211
33900
  }
32212
33901
  }
32213
33902
  async function embedCommitBatch(db, projectIdentity, batchSize) {
32214
- const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
32215
- if (!snapshot?.gitCommitEnabled)
33903
+ const snapshot2 = getProjectEmbeddingSnapshot(projectIdentity);
33904
+ if (!snapshot2?.gitCommitEnabled)
32216
33905
  return 0;
32217
- const commits = loadUnembeddedCommits(db, projectIdentity, snapshot.modelId, Math.max(1, Math.floor(batchSize)));
33906
+ const commits = loadUnembeddedCommits(db, projectIdentity, snapshot2.modelId, Math.max(1, Math.floor(batchSize)));
32218
33907
  if (commits.length === 0)
32219
33908
  return 0;
32220
33909
  const result = await embedItemsForProject(projectIdentity, commits.map((commit) => ({
@@ -32238,8 +33927,8 @@ async function embedCommitBatch(db, projectIdentity, batchSize) {
32238
33927
  return embeddedCount;
32239
33928
  }
32240
33929
  async function drainCommitBacklogForProject(db, projectIdentity, deadline) {
32241
- const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
32242
- if (!snapshot?.gitCommitEnabled)
33930
+ const snapshot2 = getProjectEmbeddingSnapshot(projectIdentity);
33931
+ if (!snapshot2?.gitCommitEnabled)
32243
33932
  return 0;
32244
33933
  const holderId = `embed-sweep-${randomUUID2()}`;
32245
33934
  const lease = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
@@ -32355,7 +34044,7 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
32355
34044
  if (Date.now() - attemptStart >= EMBED_SLOW_FAILURE_NO_RETRY_MS)
32356
34045
  break;
32357
34046
  if (attempt < EMBED_SLICE_RETRY_ATTEMPTS - 1) {
32358
- await new Promise((resolve2) => setTimeout(resolve2, EMBED_SLICE_RETRY_BASE_MS * 2 ** attempt));
34047
+ await new Promise((resolve3) => setTimeout(resolve3, EMBED_SLICE_RETRY_BASE_MS * 2 ** attempt));
32359
34048
  }
32360
34049
  }
32361
34050
  embedded += persistedIds.size;
@@ -32369,12 +34058,12 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
32369
34058
  return { embedded, noWork, failed };
32370
34059
  }
32371
34060
  async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, options) {
32372
- const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
32373
- if (!snapshot?.enabled || snapshot.chunkModelId === "off") {
34061
+ const snapshot2 = getProjectEmbeddingSnapshot(projectIdentity);
34062
+ if (!snapshot2?.enabled || snapshot2.chunkModelId === "off") {
32374
34063
  return { status: "disabled", embedded: 0, total: 0 };
32375
34064
  }
32376
34065
  recordSessionProjectIdentity(db, sessionId, projectIdentity);
32377
- const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId);
34066
+ const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot2.chunkModelId);
32378
34067
  if (total === 0)
32379
34068
  return { status: "nothing", embedded: 0, total: 0 };
32380
34069
  const holderId = `session-embed-${randomUUID2()}`;
@@ -32411,14 +34100,14 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
32411
34100
  aborted2 = true;
32412
34101
  break;
32413
34102
  }
32414
- const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, [...skipIds, ...failedIds]);
34103
+ const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot2.chunkModelId, batchSize, [...skipIds, ...failedIds]);
32415
34104
  if (candidates.length === 0)
32416
34105
  break;
32417
34106
  const {
32418
34107
  embedded: n,
32419
34108
  noWork,
32420
34109
  failed
32421
- } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, drainAbort.signal);
34110
+ } = await embedCandidateChunkBatch(db, projectIdentity, snapshot2.chunkModelId, candidates, drainAbort.signal);
32422
34111
  if (leaseLost || !renewGitSweepLease(db, projectIdentity, holderId)) {
32423
34112
  leaseLost = true;
32424
34113
  drainAbort.abort();
@@ -32440,7 +34129,7 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
32440
34129
  }
32441
34130
  embedded += n;
32442
34131
  options?.onProgress?.({ embedded: Math.min(embedded, total), total });
32443
- await new Promise((resolve2) => setTimeout(resolve2, 0));
34132
+ await new Promise((resolve3) => setTimeout(resolve3, 0));
32444
34133
  }
32445
34134
  } finally {
32446
34135
  clearInterval(renewal);
@@ -32454,7 +34143,7 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
32454
34143
  if (aborted2)
32455
34144
  return { status: "aborted", embedded, total, failed: failedIds.length };
32456
34145
  if (providerDown || failedIds.length > 0) {
32457
- const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId) - skipIds.length);
34146
+ const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot2.chunkModelId) - skipIds.length);
32458
34147
  if (remaining > 0) {
32459
34148
  return { status: "stalled", embedded, total, remaining, failed: failedIds.length };
32460
34149
  }
@@ -32462,29 +34151,29 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
32462
34151
  return { status: "done", embedded, total, failed: failedIds.length };
32463
34152
  }
32464
34153
  function getEmbeddingCoverageStatus(db, projectIdentity, sessionId) {
32465
- const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
32466
- if (!snapshot?.enabled || snapshot.chunkModelId === "off") {
34154
+ const snapshot2 = getProjectEmbeddingSnapshot(projectIdentity);
34155
+ if (!snapshot2?.enabled || snapshot2.chunkModelId === "off") {
32467
34156
  return {
32468
34157
  enabled: false,
32469
- model: snapshot?.model ?? "off",
32470
- provider: snapshot?.provider ?? "off",
34158
+ model: snapshot2?.model ?? "off",
34159
+ provider: snapshot2?.provider ?? "off",
32471
34160
  session: { embedded: 0, total: 0 },
32472
34161
  memories: { embedded: 0, total: 0 },
32473
34162
  commits: { embedded: 0, total: 0, gitEnabled: false }
32474
34163
  };
32475
34164
  }
32476
- const session = countSessionCompartmentEmbedCoverage(db, projectIdentity, sessionId, snapshot.chunkModelId);
32477
- const memories = getMemoryEmbedCoverage(db, projectIdentity, snapshot.modelId);
32478
- const gitEnabled = snapshot.gitCommitEnabled;
34165
+ const session = countSessionCompartmentEmbedCoverage(db, projectIdentity, sessionId, snapshot2.chunkModelId);
34166
+ const memories = getMemoryEmbedCoverage(db, projectIdentity, snapshot2.modelId);
34167
+ const gitEnabled = snapshot2.gitCommitEnabled;
32479
34168
  const commits = gitEnabled ? {
32480
- embedded: countEmbeddedCommits(db, projectIdentity, snapshot.modelId),
34169
+ embedded: countEmbeddedCommits(db, projectIdentity, snapshot2.modelId),
32481
34170
  total: getCommitCount(db, projectIdentity),
32482
34171
  gitEnabled: true
32483
34172
  } : { embedded: 0, total: 0, gitEnabled: false };
32484
34173
  return {
32485
34174
  enabled: true,
32486
- model: snapshot.model,
32487
- provider: snapshot.provider,
34175
+ model: snapshot2.model,
34176
+ provider: snapshot2.provider,
32488
34177
  session,
32489
34178
  memories,
32490
34179
  commits
@@ -32672,8 +34361,8 @@ async function embedText(text, signal) {
32672
34361
  }
32673
34362
  // src/features/magic-context/memory/embedding-backfill.ts
32674
34363
  async function ensureMemoryEmbeddings(args) {
32675
- const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
32676
- if (!snapshot?.enabled) {
34364
+ const snapshot2 = getProjectEmbeddingSnapshot(args.projectIdentity);
34365
+ if (!snapshot2?.enabled) {
32677
34366
  return args.existingEmbeddings;
32678
34367
  }
32679
34368
  const missingMemories = args.memories.filter((memory) => !args.existingEmbeddings.has(memory.id));
@@ -33145,7 +34834,7 @@ function tallyFactsByCategory(facts) {
33145
34834
  import { join as join7 } from "node:path";
33146
34835
 
33147
34836
  // src/features/magic-context/compaction-marker.ts
33148
- import { createHash as createHash13 } from "node:crypto";
34837
+ import { createHash as createHash14 } from "node:crypto";
33149
34838
  import { existsSync as existsSync7 } from "node:fs";
33150
34839
  import { join as join6 } from "node:path";
33151
34840
  var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -33153,7 +34842,7 @@ var ID_PREFIX_HEX_LENGTH = 12;
33153
34842
  var ID_SUFFIX_LENGTH = 14;
33154
34843
  var ID_PREFIX_MASK = (1n << BigInt(ID_PREFIX_HEX_LENGTH * 4)) - 1n;
33155
34844
  function deterministicBase62(seed, length) {
33156
- let value = BigInt(`0x${createHash13("sha256").update(seed).digest("hex")}`);
34845
+ let value = BigInt(`0x${createHash14("sha256").update(seed).digest("hex")}`);
33157
34846
  const chars = Array(length);
33158
34847
  for (let index = length - 1;index >= 0; index -= 1) {
33159
34848
  chars[index] = BASE62_CHARS[Number(value % 62n)];
@@ -35473,8 +37162,8 @@ function isTransientHistorianPromptError(message) {
35473
37162
  ].some((token) => normalized.includes(token));
35474
37163
  }
35475
37164
  function sleep(ms) {
35476
- return new Promise((resolve2) => {
35477
- setTimeout(resolve2, ms);
37165
+ return new Promise((resolve3) => {
37166
+ setTimeout(resolve3, ms);
35478
37167
  });
35479
37168
  }
35480
37169
  function cleanupHistorianDump(sessionId, dumpPath) {
@@ -35519,7 +37208,7 @@ function sanitizeDumpName(value) {
35519
37208
  import { Buffer as Buffer3 } from "node:buffer";
35520
37209
 
35521
37210
  // src/features/magic-context/mural/render-trigger.ts
35522
- import { createHash as createHash14 } from "node:crypto";
37211
+ import { createHash as createHash15 } from "node:crypto";
35523
37212
 
35524
37213
  // src/features/magic-context/mural/mural-selection.ts
35525
37214
  var DEFAULT_MURAL_MEMORY_BUDGET = 8000;
@@ -36145,7 +37834,7 @@ function ensureMuralRendered(db, projectIdentity, budgetTokens = DEFAULT_MURAL_M
36145
37834
  return { hasMural: false, rerendered: false };
36146
37835
  }
36147
37836
  const rendered = renderMural(entries);
36148
- const textHash = createHash14("sha256").update(rendered.sha256Input).digest("hex");
37837
+ const textHash = createHash15("sha256").update(rendered.sha256Input).digest("hex");
36149
37838
  const existing = getMural(db, projectIdentity);
36150
37839
  if (existing && existing.contentHash === textHash && existing.width === rendered.width && existing.height === rendered.height) {
36151
37840
  return {
@@ -36710,11 +38399,15 @@ function trimMemoriesToBudget(sessionId, memories, budgetTokens) {
36710
38399
  }
36711
38400
  function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectPath, injectionBudgetTokens, temporalAwareness) {
36712
38401
  const cached2 = injectionCache.get(sessionId);
36713
- if (!isCacheBusting && cached2) {
36714
- if (cached2.kind === "empty") {
38402
+ if (cached2 && cached2.db !== db) {
38403
+ clearInjectionCache(sessionId);
38404
+ }
38405
+ const usableCached = cached2?.db === db ? cached2 : undefined;
38406
+ if (!isCacheBusting && usableCached) {
38407
+ if (usableCached.kind === "empty") {
36715
38408
  return null;
36716
38409
  }
36717
- const prepared = cached2.injection;
38410
+ const prepared = usableCached.injection;
36718
38411
  if (prepared.compartmentEndMessageId === null) {
36719
38412
  sessionLog(sessionId, "compartment injection cache in degraded mode (null boundary), forcing rebuild");
36720
38413
  } else {
@@ -36761,6 +38454,7 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
36761
38454
  }
36762
38455
  if (compartments.length === 0 && facts.length === 0 && !memoryBlock) {
36763
38456
  injectionCache.set(sessionId, {
38457
+ db,
36764
38458
  kind: "empty",
36765
38459
  compartmentEndMessageId: "",
36766
38460
  renderedBytes: 0
@@ -36800,7 +38494,7 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
36800
38494
  memoryCount,
36801
38495
  rebuiltFromDb: true
36802
38496
  };
36803
- injectionCache.set(sessionId, { kind: "populated", injection: result2 });
38497
+ injectionCache.set(sessionId, { db, kind: "populated", injection: result2 });
36804
38498
  return result2;
36805
38499
  }
36806
38500
  const lastCompartment = compartments[compartments.length - 1];
@@ -36832,7 +38526,7 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
36832
38526
  memoryCount,
36833
38527
  rebuiltFromDb: true
36834
38528
  };
36835
- injectionCache.set(sessionId, { kind: "populated", injection: result2 });
38529
+ injectionCache.set(sessionId, { db, kind: "populated", injection: result2 });
36836
38530
  return result2;
36837
38531
  }
36838
38532
  let skippedVisibleMessages = 0;
@@ -36893,7 +38587,7 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
36893
38587
  if (needsFreshMaterialization) {
36894
38588
  result.needsFreshMaterialization = true;
36895
38589
  }
36896
- injectionCache.set(sessionId, { kind: "populated", injection: result });
38590
+ injectionCache.set(sessionId, { db, kind: "populated", injection: result });
36897
38591
  return result;
36898
38592
  }
36899
38593
  function readCachedBaselineState(db, sessionId) {
@@ -37255,7 +38949,7 @@ function readCurrentM0SnapshotMarkersUncached(args) {
37255
38949
  upgradeState: getUpgradeState(args.db, args.sessionId),
37256
38950
  compartmentRenderEpoch: COMPARTMENT_RENDER_EPOCH,
37257
38951
  systemHash: hard.systemHash,
37258
- modelKey: hard.modelKey,
38952
+ modelKey: piModelRefToCanonical(hard.modelKey),
37259
38953
  projectIdentity: args.projectPath ?? null,
37260
38954
  muralEnabled: args.muralEnabled === true,
37261
38955
  renderBudgetIdentity: renderBudgetIdentity(args.memoryInjectionBudgetTokens, args.historyBudgetTokens)
@@ -37358,7 +39052,9 @@ function mustMaterialize(args) {
37358
39052
  if (cachedUpgradeIdentity.muralEnabled !== null && cachedUpgradeIdentity.muralEnabled !== current.muralEnabled || cachedUpgradeIdentity.renderBudgetIdentity !== null && cachedUpgradeIdentity.renderBudgetIdentity !== current.renderBudgetIdentity) {
37359
39053
  return { value: true, reason: "render_config" };
37360
39054
  }
37361
- if (hard.modelKey !== "" && hard.modelKey !== (args.state.cachedM0ModelKey ?? "")) {
39055
+ const canonicalHardModelKey = piModelRefToCanonical(hard.modelKey);
39056
+ const canonicalCachedModelKey = piModelRefToCanonical(args.state.cachedM0ModelKey ?? "");
39057
+ if (canonicalHardModelKey !== "" && canonicalHardModelKey !== canonicalCachedModelKey) {
37362
39058
  return { value: true, reason: "model_change" };
37363
39059
  }
37364
39060
  if (hard.systemHash !== "" && hard.systemHash !== (args.state.cachedM0SystemHash ?? "")) {
@@ -38102,7 +39798,7 @@ function markersFromCachedRow(row) {
38102
39798
  };
38103
39799
  }
38104
39800
  function cachedRowMatchesState(row, state2) {
38105
- return bufferEqualsNullable(row.cached_m0_bytes, state2.cachedM0Bytes) && (row.cached_m0_mural_data_url ?? null) === (state2.cachedM0MuralDataUrl ?? null) && (row.cached_m0_mural_hash ?? null) === (state2.cachedM0MuralHash ?? null) && row.cached_m0_project_memory_epoch === state2.cachedM0ProjectMemoryEpoch && (row.cached_m0_workspace_fingerprint ?? null) === (state2.cachedM0WorkspaceFingerprint ?? null) && row.cached_m0_project_user_profile_version === state2.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state2.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state2.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state2.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state2.cachedM0MaxMemoryMutationId && row.cached_m0_materialized_at === state2.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state2.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state2.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state2.cachedM0SystemHash ?? "") && (row.cached_m0_model_key ?? "") === (state2.cachedM0ModelKey ?? "") && (row.cached_m0_project_identity ?? null) === (state2.cachedM0ProjectIdentity ?? null);
39801
+ return bufferEqualsNullable(row.cached_m0_bytes, state2.cachedM0Bytes) && (row.cached_m0_mural_data_url ?? null) === (state2.cachedM0MuralDataUrl ?? null) && (row.cached_m0_mural_hash ?? null) === (state2.cachedM0MuralHash ?? null) && row.cached_m0_project_memory_epoch === state2.cachedM0ProjectMemoryEpoch && (row.cached_m0_workspace_fingerprint ?? null) === (state2.cachedM0WorkspaceFingerprint ?? null) && row.cached_m0_project_user_profile_version === state2.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state2.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state2.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state2.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state2.cachedM0MaxMemoryMutationId && row.cached_m0_materialized_at === state2.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state2.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state2.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state2.cachedM0SystemHash ?? "") && piModelRefToCanonical(row.cached_m0_model_key ?? "") === piModelRefToCanonical(state2.cachedM0ModelKey ?? "") && (row.cached_m0_project_identity ?? null) === (state2.cachedM0ProjectIdentity ?? null);
38106
39802
  }
38107
39803
  function applyCachedRowToState(state2, row) {
38108
39804
  const markers = markersFromCachedRow(row);
@@ -38559,13 +40255,13 @@ function force80PerRunCap(usable, N) {
38559
40255
  function force95PerRunCap(usable, N) {
38560
40256
  return Math.min(FORCE95_MAX_CAP, Math.max(4 * N, Math.min(Math.round(0.5 * usable), 250000)));
38561
40257
  }
38562
- function selectPerRunCap(snapshot) {
38563
- const usable = Math.max(1, Math.round(snapshot.contextLimit * snapshot.executeThresholdPercentage / 100));
38564
- if (snapshot.usagePercentage >= 95)
38565
- return force95PerRunCap(usable, snapshot.N);
38566
- if (snapshot.usagePercentage >= 80)
38567
- return force80PerRunCap(usable, snapshot.N);
38568
- return nonEmergencyPerRunCap(usable, snapshot.N);
40258
+ function selectPerRunCap(snapshot2) {
40259
+ const usable = Math.max(1, Math.round(snapshot2.contextLimit * snapshot2.executeThresholdPercentage / 100));
40260
+ if (snapshot2.usagePercentage >= 95)
40261
+ return force95PerRunCap(usable, snapshot2.N);
40262
+ if (snapshot2.usagePercentage >= 80)
40263
+ return force80PerRunCap(usable, snapshot2.N);
40264
+ return nonEmergencyPerRunCap(usable, snapshot2.N);
38569
40265
  }
38570
40266
  function boundaryMessageId(index, ordinal) {
38571
40267
  if (ordinal < 1 || ordinal > index.rawMessageCount)
@@ -38977,7 +40673,7 @@ function resolveWrapupProtectedTailBoundary(args) {
38977
40673
  });
38978
40674
  const eligibleEndOrdinal = Math.min(head.eligibleEndOrdinal, targetProtectedTailStart);
38979
40675
  const rawRangeFingerprint = computeRawRangeFingerprint(messages, offset, eligibleEndOrdinal);
38980
- const snapshot = {
40676
+ const snapshot2 = {
38981
40677
  sessionId: ctx.sessionId,
38982
40678
  mode: "manual-wrapup",
38983
40679
  offset,
@@ -39007,7 +40703,7 @@ function resolveWrapupProtectedTailBoundary(args) {
39007
40703
  boundaryReason
39008
40704
  };
39009
40705
  return {
39010
- snapshot,
40706
+ snapshot: snapshot2,
39011
40707
  rawMessagesAboveLastCompartment,
39012
40708
  anchorRawMessageCount,
39013
40709
  targetProtectedTailStart,
@@ -39026,46 +40722,46 @@ function getRawHistoryEligibility(db, sessionId) {
39026
40722
  hasRawBeyondLastCompartment: rawMessageCount >= offset
39027
40723
  };
39028
40724
  }
39029
- function hasRunnableCompartmentWindow(snapshot) {
39030
- if (snapshot.offset >= snapshot.protectedTailStart)
40725
+ function hasRunnableCompartmentWindow(snapshot2) {
40726
+ if (snapshot2.offset >= snapshot2.protectedTailStart)
39031
40727
  return false;
39032
- const forceMaterializationPercentage = escalationBands(snapshot.executeThresholdPercentage).forceMaterializationPercentage;
39033
- if (snapshot.usagePercentage >= forceMaterializationPercentage || snapshot.emergencyTailScale) {
39034
- return snapshot.trueRawEligibleTokens >= deriveMinForceEligibleTokens(snapshot.N) || snapshot.eligibleEndOrdinal > snapshot.offset;
40728
+ const forceMaterializationPercentage = escalationBands(snapshot2.executeThresholdPercentage).forceMaterializationPercentage;
40729
+ if (snapshot2.usagePercentage >= forceMaterializationPercentage || snapshot2.emergencyTailScale) {
40730
+ return snapshot2.trueRawEligibleTokens >= deriveMinForceEligibleTokens(snapshot2.N) || snapshot2.eligibleEndOrdinal > snapshot2.offset;
39035
40731
  }
39036
- return snapshot.eligibleEndOrdinal > snapshot.offset;
40732
+ return snapshot2.eligibleEndOrdinal > snapshot2.offset;
39037
40733
  }
39038
40734
  function validateBoundarySnapshot(args) {
39039
- const { snapshot } = args;
39040
- if (args.currentContextLimit && args.currentContextLimit !== snapshot.contextLimit) {
40735
+ const { snapshot: snapshot2 } = args;
40736
+ if (args.currentContextLimit && args.currentContextLimit !== snapshot2.contextLimit) {
39041
40737
  return {
39042
40738
  ok: false,
39043
40739
  reason: "model_or_limit_changed",
39044
- detail: `context limit changed from ${snapshot.contextLimit} to ${args.currentContextLimit}`
40740
+ detail: `context limit changed from ${snapshot2.contextLimit} to ${args.currentContextLimit}`
39045
40741
  };
39046
40742
  }
39047
- const messages = readRawSessionMessages(snapshot.sessionId);
40743
+ const messages = readRawSessionMessages(snapshot2.sessionId);
39048
40744
  const currentRawMessageCount = messages.reduce((max, message) => Math.max(max, message.ordinal), messages.length);
39049
- if (snapshot.rawMessageCountAtTrigger > currentRawMessageCount) {
40745
+ if (snapshot2.rawMessageCountAtTrigger > currentRawMessageCount) {
39050
40746
  return { ok: false, reason: "stale_snapshot", detail: "raw message count shrank" };
39051
40747
  }
39052
40748
  const idsByOrdinal = new Map(messages.map((message) => [message.ordinal, message.id]));
39053
40749
  const idAt = (ordinal) => idsByOrdinal.get(ordinal) ?? null;
39054
40750
  const checks3 = [
39055
- [snapshot.offset, snapshot.offsetMessageId, "offset"],
39056
- [snapshot.rawMessageCountAtTrigger, snapshot.rawLastMessageIdAtTrigger, "last"]
40751
+ [snapshot2.offset, snapshot2.offsetMessageId, "offset"],
40752
+ [snapshot2.rawMessageCountAtTrigger, snapshot2.rawLastMessageIdAtTrigger, "last"]
39057
40753
  ];
39058
- if (snapshot.protectedTailStart <= snapshot.rawMessageCountAtTrigger) {
40754
+ if (snapshot2.protectedTailStart <= snapshot2.rawMessageCountAtTrigger) {
39059
40755
  checks3.push([
39060
- snapshot.protectedTailStart,
39061
- snapshot.protectedTailStartMessageId,
40756
+ snapshot2.protectedTailStart,
40757
+ snapshot2.protectedTailStartMessageId,
39062
40758
  "protectedTailStart"
39063
40759
  ]);
39064
40760
  }
39065
- if (snapshot.eligibleEndOrdinal > snapshot.offset) {
40761
+ if (snapshot2.eligibleEndOrdinal > snapshot2.offset) {
39066
40762
  checks3.push([
39067
- snapshot.eligibleEndOrdinal - 1,
39068
- snapshot.eligibleEndMessageId,
40763
+ snapshot2.eligibleEndOrdinal - 1,
40764
+ snapshot2.eligibleEndMessageId,
39069
40765
  "eligibleEnd"
39070
40766
  ]);
39071
40767
  }
@@ -39078,26 +40774,26 @@ function validateBoundarySnapshot(args) {
39078
40774
  };
39079
40775
  }
39080
40776
  }
39081
- const expectedOffset = Math.max(1, getLastCompartmentEndMessage(args.db, snapshot.sessionId) + 1);
39082
- if (expectedOffset !== snapshot.offset) {
40777
+ const expectedOffset = Math.max(1, getLastCompartmentEndMessage(args.db, snapshot2.sessionId) + 1);
40778
+ if (expectedOffset !== snapshot2.offset) {
39083
40779
  return {
39084
40780
  ok: false,
39085
40781
  reason: "stale_snapshot",
39086
- detail: `last compartment moved: offset ${snapshot.offset} -> ${expectedOffset}`
40782
+ detail: `last compartment moved: offset ${snapshot2.offset} -> ${expectedOffset}`
39087
40783
  };
39088
40784
  }
39089
- const fingerprint = computeRawRangeFingerprint(messages, snapshot.offset, snapshot.eligibleEndOrdinal);
39090
- if (fingerprint !== snapshot.rawRangeFingerprint) {
40785
+ const fingerprint = computeRawRangeFingerprint(messages, snapshot2.offset, snapshot2.eligibleEndOrdinal);
40786
+ if (fingerprint !== snapshot2.rawRangeFingerprint) {
39091
40787
  return { ok: false, reason: "stale_snapshot", detail: "raw range fingerprint changed" };
39092
40788
  }
39093
40789
  return { ok: true };
39094
40790
  }
39095
- function recordHighPressureNoEligibleHead(db, snapshot) {
39096
- const forceMaterializationPercentage = escalationBands(snapshot.executeThresholdPercentage).forceMaterializationPercentage;
39097
- if (snapshot.usagePercentage < forceMaterializationPercentage && !snapshot.emergencyTailScale) {
40791
+ function recordHighPressureNoEligibleHead(db, snapshot2) {
40792
+ const forceMaterializationPercentage = escalationBands(snapshot2.executeThresholdPercentage).forceMaterializationPercentage;
40793
+ if (snapshot2.usagePercentage < forceMaterializationPercentage && !snapshot2.emergencyTailScale) {
39098
40794
  return 0;
39099
40795
  }
39100
- return recordProtectedTailNoEligibleHead(db, snapshot.sessionId);
40796
+ return recordProtectedTailNoEligibleHead(db, snapshot2.sessionId);
39101
40797
  }
39102
40798
 
39103
40799
  // src/hooks/magic-context/reference-seeds.generated.ts
@@ -42257,7 +43953,7 @@ async function executeContextRecomp(deps, options = {}) {
42257
43953
  }
42258
43954
 
42259
43955
  // src/hooks/magic-context/lkg-slot.ts
42260
- import { createHash as createHash15 } from "node:crypto";
43956
+ import { createHash as createHash16 } from "node:crypto";
42261
43957
  var LKG_TOTAL_BYTES = 64 * 1024 * 1024;
42262
43958
  var LKG_SINGLE_SLOT_BYTES = 24 * 1024 * 1024;
42263
43959
  var LKG_METADATA_BYTES = 256;
@@ -42319,13 +44015,32 @@ function lkgContentFields(value) {
42319
44015
  }
42320
44016
  }
42321
44017
  function lkgContentDigestFromFields(fields) {
42322
- const hash2 = createHash15("sha256");
44018
+ const hash2 = createHash16("sha256");
42323
44019
  for (const field of fields) {
42324
44020
  const value = typeof field === "symbol" ? field.description ?? "" : String(field);
42325
44021
  hash2.update(`${typeof field}:${value.length}:`).update(value).update("\x00");
42326
44022
  }
42327
44023
  return hash2.digest("base64url");
42328
44024
  }
44025
+ function incrementalLkgContentDigests(entries, prior) {
44026
+ const aligned = prior !== undefined && prior.ids.length === prior.signatures.length && prior.signatures.length === prior.digests.length;
44027
+ let reusedPrefix = 0;
44028
+ if (aligned && prior) {
44029
+ while (reusedPrefix < entries.length && reusedPrefix < prior.ids.length && entries[reusedPrefix]?.id === prior.ids[reusedPrefix] && entries[reusedPrefix]?.signature === prior.signatures[reusedPrefix]) {
44030
+ reusedPrefix += 1;
44031
+ }
44032
+ }
44033
+ const digests = [];
44034
+ if (aligned && prior) {
44035
+ for (let index = 0;index < reusedPrefix; index += 1) {
44036
+ digests.push(prior.digests[index]);
44037
+ }
44038
+ }
44039
+ for (let index = reusedPrefix;index < entries.length; index += 1) {
44040
+ digests.push(lkgContentDigestFromFields(entries[index]?.fields ?? []));
44041
+ }
44042
+ return { digests, reusedPrefix };
44043
+ }
42329
44044
  function lkgContentDigest(message) {
42330
44045
  const fields = lkgContentFields(message);
42331
44046
  return fields ? lkgContentDigestFromFields(fields) : null;
@@ -42335,7 +44050,7 @@ function touch(sessionId, entry) {
42335
44050
  slots.set(sessionId, entry);
42336
44051
  }
42337
44052
  function captureSlot(sessionId, slot) {
42338
- if (slot.inputContentDigests.length !== slot.inputIdSeq.length || slot.inputContentDigests.some((digest) => digest.length === 0)) {
44053
+ if (slot.inputContentDigests.length !== slot.inputIdSeq.length || slot.inputContentDigests.some((digest) => digest.length === 0) || slot.inputContentSignatures !== undefined && (slot.inputContentSignatures.length !== slot.inputIdSeq.length || slot.inputContentSignatures.some((signature) => signature.length === 0))) {
42339
44054
  return false;
42340
44055
  }
42341
44056
  const bytes = slotBytes(slot);
@@ -42368,7 +44083,8 @@ function captureSlot(sessionId, slot) {
42368
44083
  slot: {
42369
44084
  ...slot,
42370
44085
  inputIdSeq: [...slot.inputIdSeq],
42371
- inputContentDigests: [...slot.inputContentDigests]
44086
+ inputContentDigests: [...slot.inputContentDigests],
44087
+ inputContentSignatures: slot.inputContentSignatures ? [...slot.inputContentSignatures] : undefined
42372
44088
  },
42373
44089
  bytes
42374
44090
  };
@@ -42384,7 +44100,8 @@ function getSlot(sessionId) {
42384
44100
  return {
42385
44101
  ...entry.slot,
42386
44102
  inputIdSeq: [...entry.slot.inputIdSeq],
42387
- inputContentDigests: [...entry.slot.inputContentDigests]
44103
+ inputContentDigests: [...entry.slot.inputContentDigests],
44104
+ inputContentSignatures: entry.slot.inputContentSignatures ? [...entry.slot.inputContentSignatures] : undefined
42388
44105
  };
42389
44106
  }
42390
44107
  function dropSlot(sessionId, _reason) {
@@ -42654,4 +44371,4 @@ async function runUpgradeMemoryMigration(ctx, sessionId, migrationDirectory) {
42654
44371
  }
42655
44372
  }
42656
44373
 
42657
- export { withContentLanguageDirective, buildPrimaryLanguageDirective, cortexKitUserConfigBasePath, cortexKitProjectConfigBasePath, resolveLegacyConfigSources, resolveLegacyConfigSourcesForHarness, migrateMagicContextConfigLocations, exports_external, DEFAULT_PROTECTED_TAGS, parseCron, nextOccurrence, nextDueAtMs, promptSurfaceConfigIdentity, resolvePromptSurface, resolveModelConfigOrDefault, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, DEFAULT_LOCAL_EMBEDDING_MODEL, MagicContextConfigSchema, getOpenCodeDbPath, removeMcOwnedCompactionMarkers, isFailClosedBlockingError, shouldBypassFailClosedBlock, resolveAgentNameFromMessages, createFailClosedController, recordHookInitFailure, clearHookInitFailure, getLastHookInitFailure, ProjectIdentityError, resolveProjectIdentityStrict, takeDubiousOwnershipProjectIdentityWarning, resolveProjectIdentity, resolveProjectIdentityForSession, normalizeStoredProjectPath, storedPathBelongsToIdentity, recordSessionProjectIdentity, beginBootQuietPeriod, bootQuietRemainingMs, scheduleAfterBootQuiet, rpcPortDir, rpcPortFilePath, isPidAlive, parseRpcPortFile, registerModuleNoteEvaluationBridge, getModuleNoteEvaluationBridge, getContextStoreUuid, ensureContextStoreUuid, getAuthorityManagedMarker, reconcileAuthorityProject, checksumAuthoritySeedRows, prepareAuthority, drainAuthority, getMirrorCursor, applyMirroredNoteCompileFields, applyMirrorPage, pullMemoryMirrorOnce, V2_MEMORY_CATEGORIES, CATEGORY_PRIORITY, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, resolveStoredPathWorkspaceIdentity, storedPathBelongsToWorkspace, sourceNameForMemory, computeWorkspaceEpochFingerprint, recordToolDefinition, getMeasuredToolDefinitionTokens, getSchemaFenceRejection, getMigrationOnOpenRefusal, LATEST_SUPPORTED_VERSION, getDatabasePath, getPersistedSchemaVersion, setSqlitePragmaConfig, runSqliteOptimize, openDatabase, openDatabaseAsync, isDatabasePersisted, getDatabasePersistenceError, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, clearRecompStaging, recordEmbeddingMeasurement, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationIdForProjects, MAX_EXECUTE_THRESHOLD, escalationBands, isEmergencyRecoveryArmed, isProviderOverflowReconfirmed, getEmergencyRecoveryArmedAt, loadPersistedUsage, loadProtectedTailMeta, resetProtectedTailNoEligibleHead, getWrapupInProgressState, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, resolveCompactionModeRecord, getCompactionModeRecord, setCompactionModeRecord, getPersistedReasoningWatermark, setPersistedReasoningWatermark, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getLastNudgeLevel, setLastNudgeLevel, resetLastNudgeCycle, resetLastNudgeCycleIfTailShrank, getChannel2NudgeState, getChannel2NudgeClaim, setChannel2NudgeState, casChannel2NudgeState, claimChannel2NudgeState, casChannel2NudgeClaim, getPersistedNoteNudge, getNoteNudgeAnchors, getAutoSearchHintDecisions, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, removeNoteNudgeAnchorByMessageId, removeAutoSearchHintDecisionByMessageId, getPersistedTodoPermissionDenied, setPersistedTodoPermissionDenied, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, setNoteLastReadAt, getHistorianFailureState, clearHistorianFailureState, getOverflowState, recordOverflowDetected, recordDetectedContextLimit, clearEmergencyRecovery, clearDetectedContextLimit, getPersistedCompactionMarkerState, setPersistedCompactionMarkerState, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, removeStrippedPlaceholderId, getStaleReduceStrippedIds, addStaleReduceStrippedIds, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, getSessionsWithPendingMarker, setSessionWorkMetrics, getNotes, addNote, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, updateNote, dismissNote, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, clearPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectMemoryEpoch, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, getActiveTagTokenAggregate, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, updateTagMessageId, deleteTagsByMessageId, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getDroppedTagsBySession, getTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, createChildSessionWithFence, detectOverflow, promptSyncWithValidatedOutputRetry, normalizeSDKResponse, promptSurfaceHashMaterial, createPromptSurfaceRuntime, createPromptSurfaceGuidanceEpochCache, extractLatestAssistantText, hasLengthCappedOutput, setKeepSubagents, shouldKeepSubagents, recordChildInvocation, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_EDITOR_SYSTEM_PROMPT, COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, Priority, AdmissionClass, StaleRouteHandleError, SocketClosedError, SocketTimeoutError, SubcClient, isConsumerReconnectTransient, getCompartmentEvents, loadCompartmentChunkEmbeddingsForSearch, cosineSimilarity, SYNAPSE_DEFAULT_MODEL, SynapseEmbeddingProvider, computeNormalizedHash, saveCommitEmbedding, loadProjectCommitEmbeddings, loadUnembeddedCommits, countEmbeddedCommits, upsertCommits, getLatestIndexedCommitTimeMs, enforceProjectCap, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, saveEmbeddingIfHashMatches, getProjectEmbeddings, peekProjectEmbeddings, invalidateProject, invalidateMemory, markProjectLoadUntrusted, contentSha256, sweepStaleEmbeddingIdentitiesForProject, registerProjectEmbedding, registerProjectShadowEmbedding, getShadowEmbeddingMeasurementCohort, getPrimaryEmbeddingMeasurementCohort, embedShadowTextForProject, enqueueShadowEmbeddingItems, registerProjectInObservationMode, getProjectEmbeddingSnapshot, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, isEmbeddingEnabled, embedText, ensureMemoryEmbeddings, computeCueContentHash, hasMuralCueColumns, getMuralCueState, memoryNeedsCue, setMuralCue, recordMuralCueRejection, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, ModuleMemoryAuthorityError, insertMemory, insertMemoryIdempotent, getMemoryByHash, getMemoriesByProject, buildWorkspaceMemorySqlFilter, getMemoriesByProjects, getMaxMemoryIdForProjects, readNewMemoriesForM1Union, getMemoryById, getMemoriesByIds, updateMemorySeenCount, updateMemoryRetrievalCount, setMemoryClassification, supersededMemory, mergeMemoryStats, archiveMemory, getMemoryCountsByStatus, sanitizeFtsQuery, searchMemoriesFTS, searchMemoriesFTSUnion, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, MARKER_SUMMARY_TEXT, applyDeferredCompactionMarker, removeCompactionMarkerForSession, checkCompactionMarkerConsistency, getMural, BoundedSessionMap, extractM0Block, formatDate, injectTemporalMarkers, clearInjectionCache, getVisibleMemoryIds, prepareCompartmentInjection, renderCompartmentInjection, mustMaterialize, trimMemoriesToBudgetV2, renderMemoryBlockV2, injectM0M1, onNoteTrigger, peekNoteNudgeText, markNoteNudgeDelivered, clearNoteNudgeTriggerAndCooldown, resetNoteNudgeCooldownOnly, clearNoteNudgeTriggerOnly, RECOVERY_NO_HEAD_LIMIT, resolveOpenCodeProtectedTailBoundary, resolveWrapupProtectedTailBoundary, getRawHistoryEligibility, hasRunnableCompartmentWindow, recordHighPressureNoEligibleHead, runCompartmentAgent, snapRangeToCompartments, LKG_SNAPSHOT_ARRAY, LKG_SNAPSHOT_OBJECT, LKG_SNAPSHOT_KEY, LKG_SNAPSHOT_STRING, LKG_SNAPSHOT_NUMBER, LKG_SNAPSHOT_BOOLEAN, LKG_SNAPSHOT_NULL, LKG_SNAPSHOT_UNDEFINED, lkgContentDigestFromFields, lkgContentDigest, captureSlot, getSlot, dropSlot, noteEntry, getActiveCompartmentRun, markActiveCompartmentRunPublished, registerActiveCompartmentRun, startCompartmentAgent, isRecompFailure, isRecompSkip, isRecompComplete, extractRecompReason, contextualizeUpgradeReason, setRecompStarting, setRecompNote, setRecompTerminal, runManagedRecomp, runManagedUpgrade };
44374
+ export { withContentLanguageDirective, buildPrimaryLanguageDirective, cortexKitUserConfigBasePath, cortexKitProjectConfigBasePath, resolveLegacyConfigSources, resolveLegacyConfigSourcesForHarness, migrateMagicContextConfigLocations, exports_external, DEFAULT_PROTECTED_TAGS, parseCron, nextOccurrence, nextDueAtMs, promptSurfaceConfigIdentity, resolvePromptSurface, resolveModelConfigOrDefault, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, DEFAULT_LOCAL_EMBEDDING_MODEL, MagicContextConfigSchema, getOpenCodeDbPath, removeMcOwnedCompactionMarkers, isFailClosedBlockingError, shouldBypassFailClosedBlock, resolveAgentNameFromMessages, createFailClosedController, recordHookInitFailure, clearHookInitFailure, getLastHookInitFailure, ProjectIdentityError, resolveProjectIdentityStrict, takeDubiousOwnershipProjectIdentityWarning, resolveProjectIdentity, resolveProjectIdentityForSession, normalizeStoredProjectPath, storedPathBelongsToIdentity, isLinkedGitWorktree, recordSessionProjectIdentity, beginBootQuietPeriod, bootQuietRemainingMs, scheduleAfterBootQuiet, rpcPortDir, rpcPortFilePath, isPidAlive, parseRpcPortFile, registerModuleNoteEvaluationBridge, getModuleNoteEvaluationBridge, getContextStoreUuid, ensureContextStoreUuid, getAuthorityManagedMarker, reconcileAuthorityProject, checksumAuthoritySeedRows, prepareAuthority, drainAuthority, getMirrorCursor, applyMirroredNoteCompileFields, applyMirrorPage, pullMemoryMirrorOnce, V2_MEMORY_CATEGORIES, CATEGORY_PRIORITY, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, resolveStoredPathWorkspaceIdentity, storedPathBelongsToWorkspace, sourceNameForMemory, computeWorkspaceEpochFingerprint, recordToolDefinition, getMeasuredToolDefinitionTokens, getSchemaFenceRejection, getMigrationOnOpenRefusal, LATEST_SUPPORTED_VERSION, getDatabasePath, getPersistedSchemaVersion, setSqlitePragmaConfig, runSqliteOptimize, openDatabase, openDatabaseAsync, isDatabasePersisted, getDatabasePersistenceError, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, clearRecompStaging, recordEmbeddingMeasurement, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationIdForProjects, MAX_EXECUTE_THRESHOLD, escalationBands, isEmergencyRecoveryArmed, isProviderOverflowReconfirmed, getEmergencyRecoveryArmedAt, loadPersistedUsage, loadProtectedTailMeta, resetProtectedTailNoEligibleHead, getWrapupInProgressState, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, resolveCompactionModeRecord, getCompactionModeRecord, setCompactionModeRecord, getPersistedReasoningWatermark, setPersistedReasoningWatermark, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getLastNudgeLevel, setLastNudgeLevel, resetLastNudgeCycle, resetLastNudgeCycleIfTailShrank, getChannel2NudgeState, getChannel2NudgeClaim, setChannel2NudgeState, casChannel2NudgeState, claimChannel2NudgeState, casChannel2NudgeClaim, getPersistedNoteNudge, getNoteNudgeAnchors, getAutoSearchHintDecisions, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, removeNoteNudgeAnchorByMessageId, removeAutoSearchHintDecisionByMessageId, getPersistedTodoPermissionDenied, setPersistedTodoPermissionDenied, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, setNoteLastReadAt, getHistorianFailureState, clearHistorianFailureState, getOverflowState, recordOverflowDetected, recordDetectedContextLimit, clearEmergencyRecovery, clearDetectedContextLimit, getPersistedCompactionMarkerState, setPersistedCompactionMarkerState, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, removeStrippedPlaceholderId, getMergedReasoningStrippedIds, addMergedReasoningStrippedIds, getTrailingBlankDecisions, addTrailingBlankDecisions, getStaleReduceStrippedIds, addStaleReduceStrippedIds, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, getSessionsWithPendingMarker, setSessionWorkMetrics, getNotes, addNote, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, updateNote, dismissNote, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, clearPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectMemoryEpoch, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, CTX_REDUCE_KEEP, estimateImageTokensFromDataUrl, normalizeTodoStateJson, buildSyntheticTodoPart, computeSyntheticCallId, isSyntheticTodoPart, tailHygieneStructuralSignature, sameTailHygieneStructuralSignature, refreshTailHygieneBaseline, effectiveTailHygiene, assertTailHygieneContentUnchanged, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, toolOutputTokens, decideChannel1, evaluateChannel2, buildChannel2Reminder, buildChannel1Reminder, estimateEmergencyDropReclaimTokens, planEmergencyDrop, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, updateTagMessageId, deleteTagsByMessageId, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getTailHygieneTags, getDroppedTagsBySession, getTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, createChildSessionWithFence, detectOverflow, promptSyncWithValidatedOutputRetry, normalizeSDKResponse, promptSurfaceHashMaterial, createPromptSurfaceRuntime, createPromptSurfaceGuidanceEpochCache, extractLatestAssistantText, hasLengthCappedOutput, setKeepSubagents, shouldKeepSubagents, recordChildInvocation, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_EDITOR_SYSTEM_PROMPT, COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, Priority, AdmissionClass, StaleRouteHandleError, SocketClosedError, SocketTimeoutError, SubcClient, isConsumerReconnectTransient, connectionFileExists, getCompartmentEvents, loadCompartmentChunkEmbeddingsForSearch, cosineSimilarity, SYNAPSE_DEFAULT_MODEL, SynapseEmbeddingProvider, computeNormalizedHash, saveCommitEmbedding, loadProjectCommitEmbeddings, loadUnembeddedCommits, countEmbeddedCommits, upsertCommits, getLatestIndexedCommitTimeMs, enforceProjectCap, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, saveEmbeddingIfHashMatches, getProjectEmbeddings, peekProjectEmbeddings, invalidateProject, invalidateMemory, markProjectLoadUntrusted, contentSha256, sweepStaleEmbeddingIdentitiesForProject, registerProjectEmbedding, registerProjectShadowEmbedding, getShadowEmbeddingMeasurementCohort, getPrimaryEmbeddingMeasurementCohort, embedShadowTextForProject, enqueueShadowEmbeddingItems, registerProjectInObservationMode, getProjectEmbeddingSnapshot, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, isEmbeddingEnabled, embedText, ensureMemoryEmbeddings, computeCueContentHash, hasMuralCueColumns, getMuralCueState, memoryNeedsCue, setMuralCue, recordMuralCueRejection, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, ModuleMemoryAuthorityError, insertMemory, insertMemoryIdempotent, getMemoryByHash, getMemoriesByProject, buildWorkspaceMemorySqlFilter, getMemoriesByProjects, getMaxMemoryIdForProjects, readNewMemoriesForM1Union, getMemoryById, getMemoriesByIds, updateMemorySeenCount, updateMemoryRetrievalCount, setMemoryClassification, supersededMemory, mergeMemoryStats, archiveMemory, getMemoryCountsByStatus, sanitizeFtsQuery, searchMemoriesFTS, searchMemoriesFTSUnion, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, MARKER_SUMMARY_TEXT, applyDeferredCompactionMarker, removeCompactionMarkerForSession, checkCompactionMarkerConsistency, getMural, resolveMuralWire, BoundedSessionMap, extractM0Block, formatDate, injectTemporalMarkers, clearInjectionCache, getVisibleMemoryIds, prepareCompartmentInjection, renderCompartmentInjection, mustMaterialize, trimMemoriesToBudgetV2, renderMemoryBlockV2, injectM0M1, onNoteTrigger, peekNoteNudgeText, markNoteNudgeDelivered, clearNoteNudgeTriggerAndCooldown, resetNoteNudgeCooldownOnly, clearNoteNudgeTriggerOnly, RECOVERY_NO_HEAD_LIMIT, resolveOpenCodeProtectedTailBoundary, resolveWrapupProtectedTailBoundary, getRawHistoryEligibility, hasRunnableCompartmentWindow, recordHighPressureNoEligibleHead, runCompartmentAgent, snapRangeToCompartments, LKG_SNAPSHOT_ARRAY, LKG_SNAPSHOT_OBJECT, LKG_SNAPSHOT_KEY, LKG_SNAPSHOT_STRING, LKG_SNAPSHOT_NUMBER, LKG_SNAPSHOT_BOOLEAN, LKG_SNAPSHOT_NULL, LKG_SNAPSHOT_UNDEFINED, incrementalLkgContentDigests, lkgContentDigest, captureSlot, getSlot, dropSlot, noteEntry, getActiveCompartmentRun, markActiveCompartmentRunPublished, registerActiveCompartmentRun, startCompartmentAgent, isRecompFailure, isRecompSkip, isRecompComplete, extractRecompReason, contextualizeUpgradeReason, setRecompStarting, setRecompNote, setRecompTerminal, runManagedRecomp, runManagedUpgrade };