@cortexkit/pi-magic-context 0.41.0 → 0.41.2

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.
@@ -6,7 +6,7 @@ import {
6
6
  log,
7
7
  sanitizeDiagnosticText,
8
8
  sessionLog
9
- } from "./index-3k71e196.js";
9
+ } from "./index-q2vgz0j1.js";
10
10
  import {
11
11
  __commonJS,
12
12
  __export,
@@ -8422,8 +8422,8 @@ function formatFailClosedBlockingMessage(reason) {
8422
8422
  ].join(" ");
8423
8423
  }
8424
8424
  return [
8425
- `Magic Context cannot migrate the shared database because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
8426
- "Restart the blocking process (it will pick up the new build and migrate on start), or shut it down and retry.",
8425
+ `Magic Context cannot migrate the shared database (one database serves every project on this machine) because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
8426
+ "Restart the blocking process — even one from a different project — and it will pick up the new build and migrate on start; or shut it down and retry.",
8427
8427
  `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
8428
8428
  ].join(" ");
8429
8429
  }
@@ -8830,6 +8830,9 @@ function gitRootDirectory(canonical) {
8830
8830
  return null;
8831
8831
  }
8832
8832
  }
8833
+ function directoryHasGitMetadata(directory) {
8834
+ return gitRootDirectory(path.resolve(directory)) !== null;
8835
+ }
8833
8836
  function resolveProjectIdentityForSession(directory, allowHomeProject = false) {
8834
8837
  const canonicalHome = canonicalUserHomeDirectory();
8835
8838
  const canonicalDirectory = (() => {
@@ -9353,8 +9356,19 @@ function isPidAlive(pid) {
9353
9356
  var RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000;
9354
9357
  var LINUX_CLOCK_TICKS_PER_SECOND = 100;
9355
9358
  var PS_PROBE_TIMEOUT_MS = 1000;
9359
+ var WINDOWS_CIM_PROBE_TIMEOUT_MS = 5000;
9360
+ var MAX_ANCESTOR_WALK_DEPTH = 16;
9356
9361
  var OPEN_CODE_COMMAND_MARKERS = ["opencode", "node", "bun", "electron"];
9357
9362
  var TASKLIST_NO_TASKS_PATTERN = /^INFO:\s+No tasks are running which match the specified criteria\.?$/im;
9363
+ var WINDOWS_CIM_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress";
9364
+ var PI_HARNESS_ARC_MARKERS = [
9365
+ "pi-coding-agent",
9366
+ "oh-my-pi",
9367
+ "@oh-my-pi",
9368
+ "cljs/dist",
9369
+ "dist/bundle/cli"
9370
+ ];
9371
+ var PI_IMAGE_NAMES = new Set(["pi", "pi.cmd", "omp", "oh-my-pi"]);
9358
9372
  var rpcIdentityReadFileSync = readFileSync3;
9359
9373
  var rpcIdentityExecFileSync = execFileSync2;
9360
9374
  var rpcIdentityProcessKill = process.kill;
@@ -9399,7 +9413,7 @@ function readPsProcessStartTime(pid) {
9399
9413
  function readProcessStartTime(pid) {
9400
9414
  if (!Number.isInteger(pid) || pid <= 0)
9401
9415
  return null;
9402
- return rpcIdentityPlatform === "linux" ? readLinuxProcessStartTime(pid) : rpcIdentityPlatform === "win32" ? null : readPsProcessStartTime(pid);
9416
+ return rpcIdentityPlatform === "linux" ? readLinuxProcessStartTime(pid) : rpcIdentityPlatform === "win32" ? readWindowsProcessStartTime(pid) : readPsProcessStartTime(pid);
9403
9417
  }
9404
9418
  function readProcessProbeEvidence(pid) {
9405
9419
  return {
@@ -9407,6 +9421,10 @@ function readProcessProbeEvidence(pid) {
9407
9421
  commandLine: readProcessCommand(pid)
9408
9422
  };
9409
9423
  }
9424
+ var windowsProcessFactsCache = null;
9425
+ function rememberWindowsProcessFacts(facts) {
9426
+ windowsProcessFactsCache = new Map(facts.map((fact) => [fact.pid, fact]));
9427
+ }
9410
9428
  function parseCsvLine(line) {
9411
9429
  const fields = [];
9412
9430
  let field = "";
@@ -9471,6 +9489,16 @@ function readWindowsProcess(pid) {
9471
9489
  return { state: "inconclusive" };
9472
9490
  }
9473
9491
  }
9492
+ function readWindowsProcessStartTime(pid) {
9493
+ const cached = windowsProcessFactsCache?.get(pid);
9494
+ if (cached)
9495
+ return cached.startTime;
9496
+ const snapshot = tryReadWindowsCimSnapshot(rpcIdentityExecFileSync);
9497
+ if (!snapshot)
9498
+ return null;
9499
+ rememberWindowsProcessFacts(snapshot.facts);
9500
+ return windowsProcessFactsCache?.get(pid)?.startTime ?? null;
9501
+ }
9474
9502
  function readLinuxProcessCommand(pid) {
9475
9503
  try {
9476
9504
  return String(rpcIdentityReadFileSync(`/proc/${pid}/cmdline`, "utf8"));
@@ -9493,7 +9521,15 @@ function readPsProcessCommand(pid) {
9493
9521
  function readProcessCommand(pid) {
9494
9522
  if (!Number.isInteger(pid) || pid <= 0)
9495
9523
  return null;
9496
- return rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(pid) : rpcIdentityPlatform === "win32" ? readWindowsProcess(pid).command ?? null : readPsProcessCommand(pid);
9524
+ if (rpcIdentityPlatform === "linux")
9525
+ return readLinuxProcessCommand(pid);
9526
+ if (rpcIdentityPlatform === "win32") {
9527
+ const cached = windowsProcessFactsCache?.get(pid);
9528
+ if (cached?.commandLine)
9529
+ return cached.commandLine;
9530
+ return readWindowsProcess(pid).command ?? null;
9531
+ }
9532
+ return readPsProcessCommand(pid);
9497
9533
  }
9498
9534
  function executableName(token) {
9499
9535
  return (token ?? "").replace(/^['"]|['"]$/g, "").split("/").at(-1) ?? "";
@@ -9553,57 +9589,262 @@ function isPidIdentityPlausible(record, evidence) {
9553
9589
  return "inconclusive";
9554
9590
  return commandLooksLikeOpenCode(command) ? "plausible" : "implausible";
9555
9591
  }
9556
- function commandLooksLikePi(command) {
9557
- const normalized = command.trim().toLowerCase().replaceAll("\\", "/");
9558
- const tokens = normalized.split(/\s+/).filter(Boolean);
9559
- const executableName2 = (token) => (token ?? "").split("/").at(-1) ?? "";
9560
- const first = executableName2(tokens[0]).replace(/\.exe$/, "");
9561
- if (["pi", "pi.cmd", "omp", "oh-my-pi"].includes(first))
9592
+ function commandLooksLikePiImage(command) {
9593
+ const tokens = commandTokens(command);
9594
+ const first = executableName(tokens[0]).replace(/\.(?:exe|cmd)$/, "");
9595
+ return PI_IMAGE_NAMES.has(first);
9596
+ }
9597
+ function commandHasPiHarnessArc(command) {
9598
+ const normalized = command.trim().toLowerCase().replaceAll("\\", "/").replaceAll("\x00", " ");
9599
+ if (!normalized)
9600
+ return false;
9601
+ const tokens = commandTokens(command);
9602
+ if (tokens.length === 0)
9603
+ return false;
9604
+ const hasArc = PI_HARNESS_ARC_MARKERS.some((marker) => normalized.includes(marker));
9605
+ const first = executableName(tokens[0]).replace(/\.(?:exe|cmd)$/, "");
9606
+ if (hasArc && ["pi", "omp", "oh-my-pi", "node", "bun", "deno", "cmd"].includes(first)) {
9607
+ return true;
9608
+ }
9609
+ if (hasArc && PI_HARNESS_ARC_MARKERS.some((marker) => tokens[0].includes(marker))) {
9562
9610
  return true;
9611
+ }
9563
9612
  if (["node", "bun", "deno"].includes(first)) {
9564
- const script = executableName2(tokens[1]);
9565
- return ["pi", "pi.js", "pi.mjs", "pi.cjs"].includes(script) || normalized.includes("pi-coding-agent");
9613
+ const script = executableName(tokens[1]).replace(/\.(?:exe|cmd)$/, "");
9614
+ if (["pi", "pi.js", "pi.mjs", "pi.cjs"].includes(script))
9615
+ return true;
9616
+ if (hasArc)
9617
+ return true;
9566
9618
  }
9567
9619
  return false;
9568
9620
  }
9621
+ function execProcessList(exec, file, args, timeout = PS_PROBE_TIMEOUT_MS) {
9622
+ return String(exec(file, [...args], {
9623
+ encoding: "utf8",
9624
+ timeout,
9625
+ stdio: ["ignore", "pipe", "pipe"]
9626
+ }));
9627
+ }
9628
+ function parseWindowsCreationDate(value) {
9629
+ if (typeof value === "number" && Number.isFinite(value)) {
9630
+ return value > 1000000000000 ? value : value * 1000;
9631
+ }
9632
+ if (typeof value !== "string")
9633
+ return null;
9634
+ const trimmed = value.trim();
9635
+ if (!trimmed)
9636
+ return null;
9637
+ const wmi = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\.(\d{6})([+-])(\d{3})$/.exec(trimmed);
9638
+ if (wmi) {
9639
+ const utcMs = Date.UTC(Number(wmi[1]), Number(wmi[2]) - 1, Number(wmi[3]), Number(wmi[4]), Number(wmi[5]), Number(wmi[6]), Number(wmi[7]) / 1000);
9640
+ if (!Number.isFinite(utcMs))
9641
+ return null;
9642
+ const offsetMinutes = Number(wmi[9]);
9643
+ const sign = wmi[8] === "+" ? 1 : -1;
9644
+ return utcMs - sign * offsetMinutes * 60000;
9645
+ }
9646
+ const dotNet = /^\/Date\((-?\d+)\)\/$/.exec(trimmed);
9647
+ if (dotNet) {
9648
+ const milliseconds = Number(dotNet[1]);
9649
+ return Number.isFinite(milliseconds) ? milliseconds : null;
9650
+ }
9651
+ const parsed = Date.parse(trimmed);
9652
+ return Number.isFinite(parsed) ? parsed : null;
9653
+ }
9654
+ function parseWindowsCimOutput(output) {
9655
+ const trimmed = output.trim();
9656
+ if (!trimmed)
9657
+ return null;
9658
+ const bracket = trimmed.indexOf("[");
9659
+ const brace = trimmed.indexOf("{");
9660
+ const start = Math.min(bracket === -1 ? Number.POSITIVE_INFINITY : bracket, brace === -1 ? Number.POSITIVE_INFINITY : brace);
9661
+ if (!Number.isFinite(start))
9662
+ return null;
9663
+ let parsed;
9664
+ try {
9665
+ parsed = JSON.parse(trimmed.slice(start));
9666
+ } catch {
9667
+ return null;
9668
+ }
9669
+ if (parsed == null)
9670
+ return null;
9671
+ const rows = Array.isArray(parsed) ? parsed : [parsed];
9672
+ const facts = [];
9673
+ for (const row of rows) {
9674
+ if (!row || typeof row !== "object")
9675
+ continue;
9676
+ const record = row;
9677
+ const pid = Number(record.ProcessId);
9678
+ if (!Number.isInteger(pid) || pid <= 0)
9679
+ continue;
9680
+ const parentRaw = record.ParentProcessId;
9681
+ const parentPid = parentRaw == null || parentRaw === "" ? Number.NaN : Number(parentRaw);
9682
+ const commandLine = typeof record.CommandLine === "string" ? record.CommandLine : null;
9683
+ facts.push({
9684
+ pid,
9685
+ parentPid: Number.isInteger(parentPid) && parentPid > 0 ? parentPid : null,
9686
+ commandLine,
9687
+ imageName: commandLine ? executableName(commandTokens(commandLine)[0]) : null,
9688
+ startTime: parseWindowsCreationDate(record.CreationDate)
9689
+ });
9690
+ }
9691
+ return facts.length > 0 ? facts : null;
9692
+ }
9693
+ function snapshotFromFacts(facts, source) {
9694
+ const parentByPid = new Map;
9695
+ for (const fact of facts) {
9696
+ if (fact.parentPid != null)
9697
+ parentByPid.set(fact.pid, fact.parentPid);
9698
+ }
9699
+ return { facts, parentByPid, source };
9700
+ }
9701
+ function tryReadWindowsCimSnapshot(exec) {
9702
+ try {
9703
+ const output = execProcessList(exec, "powershell", ["-NoProfile", "-Command", WINDOWS_CIM_COMMAND], WINDOWS_CIM_PROBE_TIMEOUT_MS);
9704
+ const facts = parseWindowsCimOutput(output);
9705
+ return facts ? snapshotFromFacts(facts, "cim") : null;
9706
+ } catch {
9707
+ return null;
9708
+ }
9709
+ }
9710
+ function tryReadWindowsTasklistSnapshot() {
9711
+ try {
9712
+ const output = execProcessList(rpcProcessListExecFileSync, "tasklist", ["/FO", "CSV"]);
9713
+ const entries = parseTasklistOutput(output);
9714
+ if (entries === null)
9715
+ return null;
9716
+ const facts = entries.map((entry) => ({
9717
+ pid: entry.pid,
9718
+ parentPid: null,
9719
+ commandLine: null,
9720
+ imageName: entry.command,
9721
+ startTime: null
9722
+ }));
9723
+ return snapshotFromFacts(facts, "tasklist");
9724
+ } catch {
9725
+ return null;
9726
+ }
9727
+ }
9728
+ function readPosixProcessSnapshot() {
9729
+ const output = execProcessList(rpcProcessListExecFileSync, "ps", ["-axo", "pid=,command="]);
9730
+ const facts = [];
9731
+ for (const line of output.split(/\r?\n/)) {
9732
+ const match = /^\s*(\d+)\s+(.+)$/.exec(line);
9733
+ if (!match)
9734
+ continue;
9735
+ const pid = Number(match[1]);
9736
+ if (!Number.isInteger(pid) || pid <= 0)
9737
+ continue;
9738
+ facts.push({
9739
+ pid,
9740
+ parentPid: null,
9741
+ commandLine: match[2],
9742
+ imageName: executableName(commandTokens(match[2])[0]),
9743
+ startTime: null
9744
+ });
9745
+ }
9746
+ return snapshotFromFacts(facts, "ps");
9747
+ }
9748
+ function readPosixParentPid(pid) {
9749
+ try {
9750
+ const output = execProcessList(rpcProcessListExecFileSync, "ps", [
9751
+ "-o",
9752
+ "ppid=",
9753
+ "-p",
9754
+ String(pid)
9755
+ ]);
9756
+ const match = /^\s*(\d+)\s*$/.exec(output);
9757
+ if (!match)
9758
+ return null;
9759
+ const ppid = Number(match[1]);
9760
+ return Number.isInteger(ppid) && ppid > 0 ? ppid : null;
9761
+ } catch {
9762
+ return null;
9763
+ }
9764
+ }
9765
+ function collectAncestorPids(selfPid, parentByPid) {
9766
+ const ancestors = new Set;
9767
+ let current = selfPid;
9768
+ for (let depth = 0;depth < MAX_ANCESTOR_WALK_DEPTH; depth += 1) {
9769
+ let ppid = null;
9770
+ if (parentByPid.has(current)) {
9771
+ ppid = parentByPid.get(current) ?? null;
9772
+ } else if (rpcIdentityPlatform !== "win32") {
9773
+ ppid = readPosixParentPid(current);
9774
+ if (ppid == null && current === process.pid && process.ppid > 0) {
9775
+ ppid = process.ppid;
9776
+ }
9777
+ } else if (current === process.pid && process.ppid > 0) {
9778
+ ppid = process.ppid;
9779
+ } else {
9780
+ break;
9781
+ }
9782
+ if (ppid == null || ppid <= 0 || ppid === current || ancestors.has(ppid))
9783
+ break;
9784
+ ancestors.add(ppid);
9785
+ current = ppid;
9786
+ }
9787
+ return ancestors;
9788
+ }
9789
+ function classifyLivePiSnapshot(snapshot) {
9790
+ const ancestors = collectAncestorPids(process.pid, snapshot.parentByPid);
9791
+ const processIds = new Set;
9792
+ const inconclusivePids = new Set;
9793
+ const skippedAncestorPids = [];
9794
+ for (const fact of snapshot.facts) {
9795
+ if (fact.pid === process.pid)
9796
+ continue;
9797
+ const command = fact.commandLine ?? fact.imageName ?? "";
9798
+ const looksLikeHarness = commandHasPiHarnessArc(command) || commandLooksLikePiImage(command);
9799
+ if (!looksLikeHarness)
9800
+ continue;
9801
+ if (ancestors.has(fact.pid)) {
9802
+ skippedAncestorPids.push(fact.pid);
9803
+ log(`[magic-context] Pi process scan: skipping ancestor PID ${fact.pid} (session launcher shim)`);
9804
+ continue;
9805
+ }
9806
+ if (commandHasPiHarnessArc(command)) {
9807
+ processIds.add(fact.pid);
9808
+ continue;
9809
+ }
9810
+ inconclusivePids.add(fact.pid);
9811
+ log(`[magic-context] Pi process scan: PID ${fact.pid} command line is ambiguous (image-name or missing Pi/OMP arc); treating as inconclusive`);
9812
+ }
9813
+ skippedAncestorPids.sort((left, right) => left - right);
9814
+ const verified = [...processIds].sort((left, right) => left - right);
9815
+ const inconclusive = [...inconclusivePids].sort((left, right) => left - right);
9816
+ if (verified.length === 0 && inconclusive.length > 0) {
9817
+ return {
9818
+ state: "inconclusive",
9819
+ processIds: [],
9820
+ inconclusivePids: inconclusive,
9821
+ ...skippedAncestorPids.length > 0 ? { skippedAncestorPids } : {}
9822
+ };
9823
+ }
9824
+ return {
9825
+ state: "known",
9826
+ processIds: verified,
9827
+ ...inconclusive.length > 0 ? { inconclusivePids: inconclusive } : {},
9828
+ ...skippedAncestorPids.length > 0 ? { skippedAncestorPids } : {}
9829
+ };
9830
+ }
9569
9831
  function inspectLivePiProcesses() {
9570
9832
  if (false) {}
9571
9833
  try {
9572
- const isWindows = rpcIdentityPlatform === "win32";
9573
- const output = String(rpcProcessListExecFileSync(isWindows ? "tasklist" : "ps", isWindows ? ["/FO", "CSV"] : ["-axo", "pid=,command="], {
9574
- encoding: "utf8",
9575
- timeout: PS_PROBE_TIMEOUT_MS,
9576
- stdio: ["ignore", "pipe", "pipe"]
9577
- }));
9578
- const pids = new Set;
9579
- if (isWindows) {
9580
- const entries = parseTasklistOutput(output);
9581
- if (entries === null) {
9834
+ if (rpcIdentityPlatform === "win32") {
9835
+ const cim = tryReadWindowsCimSnapshot(rpcProcessListExecFileSync);
9836
+ const snapshot = cim ?? tryReadWindowsTasklistSnapshot();
9837
+ if (!snapshot) {
9582
9838
  return {
9583
9839
  state: "unreadable",
9584
9840
  processIds: [],
9585
- error: "tasklist output unavailable"
9841
+ error: "process list unavailable"
9586
9842
  };
9587
9843
  }
9588
- for (const entry of entries) {
9589
- if (entry.pid === process.pid)
9590
- continue;
9591
- if (commandLooksLikePi(entry.command))
9592
- pids.add(entry.pid);
9593
- }
9594
- } else {
9595
- for (const line of output.split(/\r?\n/)) {
9596
- const match = /^\s*(\d+)\s+(.+)$/.exec(line);
9597
- if (!match)
9598
- continue;
9599
- const pid = Number(match[1]);
9600
- if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid)
9601
- continue;
9602
- if (commandLooksLikePi(match[2]))
9603
- pids.add(pid);
9604
- }
9844
+ rememberWindowsProcessFacts(snapshot.facts);
9845
+ return classifyLivePiSnapshot(snapshot);
9605
9846
  }
9606
- return { state: "known", processIds: [...pids].sort((left, right) => left - right) };
9847
+ return classifyLivePiSnapshot(readPosixProcessSnapshot());
9607
9848
  } catch (error) {
9608
9849
  return {
9609
9850
  state: "unreadable",
@@ -9839,6 +10080,135 @@ function ensureContextStoreUuid(db) {
9839
10080
  var MAX_AUTHORITY_SEED_FRAME_BYTES = 900 * 1024;
9840
10081
  var mirrorFlights = new WeakMap;
9841
10082
 
10083
+ // ../plugin/src/features/magic-context/message-fts-rowid-map.ts
10084
+ import { createHash as createHash3 } from "node:crypto";
10085
+ var MESSAGE_FTS_ROWID_MAP_BACKFILL_BATCH_SIZE = 500;
10086
+ var BACKFILL_STATE_ID = 1;
10087
+ var EMPTY_INDEX_CONTENT_HASH = createHash3("sha256").update("").digest("hex");
10088
+ var upsertMapStatements = new WeakMap;
10089
+ var rangeReadyStatements = new WeakMap;
10090
+ var activeBackfills = new WeakMap;
10091
+ function getUpsertMapStatement(db) {
10092
+ let statement = upsertMapStatements.get(db);
10093
+ if (!statement) {
10094
+ statement = db.prepare(`INSERT INTO message_fts_rowid_map (session_id, message_ordinal, fts_rowid)
10095
+ VALUES (?, ?, ?)
10096
+ ON CONFLICT(session_id, message_ordinal) DO UPDATE SET
10097
+ fts_rowid = excluded.fts_rowid`);
10098
+ upsertMapStatements.set(db, statement);
10099
+ }
10100
+ return statement;
10101
+ }
10102
+ function getBackfillState(db) {
10103
+ const row = db.prepare(`SELECT watermark_rowid AS watermarkRowid, completed
10104
+ FROM message_fts_rowid_map_backfill_state
10105
+ WHERE id = ?`).get(BACKFILL_STATE_ID);
10106
+ return {
10107
+ processed: 0,
10108
+ watermarkRowid: typeof row?.watermarkRowid === "number" && Number.isSafeInteger(row.watermarkRowid) ? row.watermarkRowid : 0,
10109
+ completed: row?.completed === 1
10110
+ };
10111
+ }
10112
+ function recordMessageFtsRowid(db, sessionId, messageOrdinal, ftsRowid) {
10113
+ const numericRowid = Number(ftsRowid);
10114
+ if (!Number.isSafeInteger(numericRowid) || numericRowid <= 0) {
10115
+ throw new Error(`invalid message FTS rowid: ${String(ftsRowid)}`);
10116
+ }
10117
+ getUpsertMapStatement(db).run(sessionId, messageOrdinal, numericRowid);
10118
+ }
10119
+ function backfillMessageFtsRowidMapBatch(db, batchSize = MESSAGE_FTS_ROWID_MAP_BACKFILL_BATCH_SIZE) {
10120
+ const boundedBatchSize = Math.max(1, Math.floor(batchSize));
10121
+ let progress = {
10122
+ processed: 0,
10123
+ watermarkRowid: 0,
10124
+ completed: false
10125
+ };
10126
+ db.transaction(() => {
10127
+ const state = getBackfillState(db);
10128
+ if (state.completed) {
10129
+ progress = state;
10130
+ return;
10131
+ }
10132
+ const rows = db.prepare(`SELECT rowid AS ftsRowid,
10133
+ session_id AS sessionId,
10134
+ message_ordinal AS messageOrdinal
10135
+ FROM message_history_fts
10136
+ WHERE rowid > ?
10137
+ ORDER BY rowid ASC
10138
+ LIMIT ?`).all(state.watermarkRowid, boundedBatchSize);
10139
+ let watermarkRowid = state.watermarkRowid;
10140
+ for (const row of rows) {
10141
+ const ftsRowid = Number(row.ftsRowid);
10142
+ const messageOrdinal = Number(row.messageOrdinal);
10143
+ if (Number.isSafeInteger(ftsRowid) && ftsRowid > watermarkRowid) {
10144
+ watermarkRowid = ftsRowid;
10145
+ }
10146
+ if (typeof row.sessionId === "string" && Number.isSafeInteger(messageOrdinal) && messageOrdinal >= 0 && Number.isSafeInteger(ftsRowid) && ftsRowid > 0) {
10147
+ recordMessageFtsRowid(db, row.sessionId, messageOrdinal, ftsRowid);
10148
+ }
10149
+ }
10150
+ const completed = rows.length < boundedBatchSize;
10151
+ db.prepare(`UPDATE message_fts_rowid_map_backfill_state
10152
+ SET watermark_rowid = ?, completed = ?, updated_at = ?
10153
+ WHERE id = ?`).run(watermarkRowid, completed ? 1 : 0, Date.now(), BACKFILL_STATE_ID);
10154
+ progress = {
10155
+ processed: rows.length,
10156
+ watermarkRowid,
10157
+ completed
10158
+ };
10159
+ })();
10160
+ return progress;
10161
+ }
10162
+ async function runMessageFtsRowidMapBackfill(db) {
10163
+ for (;; ) {
10164
+ const progress = backfillMessageFtsRowidMapBatch(db);
10165
+ if (progress.completed)
10166
+ return;
10167
+ await new Promise((resolve2) => setTimeout(resolve2, 0));
10168
+ }
10169
+ }
10170
+ function startMessageFtsRowidMapBackfill(db) {
10171
+ const active = activeBackfills.get(db);
10172
+ if (active)
10173
+ return active;
10174
+ const run = runMessageFtsRowidMapBackfill(db).finally(() => {
10175
+ activeBackfills.delete(db);
10176
+ });
10177
+ activeBackfills.set(db, run);
10178
+ return run;
10179
+ }
10180
+ function messageFtsOrdinalRangeIsMapped(db, sessionId, startOrdinal, endOrdinal) {
10181
+ if (endOrdinal < startOrdinal)
10182
+ return true;
10183
+ if (getBackfillState(db).completed)
10184
+ return true;
10185
+ let statement = rangeReadyStatements.get(db);
10186
+ if (!statement) {
10187
+ statement = db.prepare(`SELECT COUNT(DISTINCT source.message_ordinal) AS sourceOrdinalCount,
10188
+ COUNT(DISTINCT CASE
10189
+ WHEN source.role IN ('user', 'assistant')
10190
+ AND source.normalized_content_hash != ?
10191
+ THEN source.message_ordinal
10192
+ END) AS expectedMapCount,
10193
+ COUNT(DISTINCT CASE
10194
+ WHEN source.role IN ('user', 'assistant')
10195
+ AND source.normalized_content_hash != ?
10196
+ AND map.fts_rowid IS NOT NULL
10197
+ THEN source.message_ordinal
10198
+ END) AS mappedCount
10199
+ FROM message_history_source AS source
10200
+ LEFT JOIN message_fts_rowid_map AS map
10201
+ ON map.session_id = source.session_id
10202
+ AND map.message_ordinal = source.message_ordinal
10203
+ WHERE source.session_id = ?
10204
+ AND source.message_ordinal BETWEEN ? AND ?`);
10205
+ rangeReadyStatements.set(db, statement);
10206
+ }
10207
+ const row = statement.get(EMPTY_INDEX_CONTENT_HASH, EMPTY_INDEX_CONTENT_HASH, sessionId, startOrdinal, endOrdinal);
10208
+ const ordinalCount = endOrdinal - startOrdinal + 1;
10209
+ return row?.sourceOrdinalCount === ordinalCount && row.expectedMapCount === row.mappedCount;
10210
+ }
10211
+
9842
10212
  // ../plugin/src/hooks/magic-context/compartment-parser.ts
9843
10213
  var COMPARTMENT_REGEX = /<compartment\s+([^>]*?)\s*>(.*?)<\/compartment>/gs;
9844
10214
  var ATTR_START_REGEX = /\bstart="(\d+)"/;
@@ -10071,6 +10441,7 @@ function healAllNullColumns(db) {
10071
10441
  ["stale_reduce_stripped_ids", ""],
10072
10442
  ["processed_image_stripped_ids", ""],
10073
10443
  ["merged_reasoning_stripped_ids", ""],
10444
+ ["thinking_binding_recovery_target", ""],
10074
10445
  ["trailing_blank_decisions", ""],
10075
10446
  ["memory_block_cache", ""],
10076
10447
  ["memory_block_ids", ""],
@@ -10122,7 +10493,7 @@ function healMissingMemoryBlockIds(db, columns) {
10122
10493
  }
10123
10494
 
10124
10495
  // ../plugin/src/features/magic-context/workspaces.ts
10125
- import { createHash as createHash3 } from "node:crypto";
10496
+ import { createHash as createHash4 } from "node:crypto";
10126
10497
 
10127
10498
  // ../plugin/src/features/magic-context/memory/constants.ts
10128
10499
  var V2_MEMORY_CATEGORIES = [
@@ -10359,7 +10730,7 @@ function computeWorkspaceEpochFingerprint(db, identities) {
10359
10730
  const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
10360
10731
  const epochs = getEpochMap(db, canonical);
10361
10732
  const shareCategories = selectWorkspaceShareCategories(db, canonical);
10362
- const hash = createHash3("sha256");
10733
+ const hash = createHash4("sha256");
10363
10734
  hash.update("share_categories", "utf8");
10364
10735
  hash.update("\x00");
10365
10736
  hash.update(shareCategories === null ? "NO_WORKSPACE" : JSON.stringify(shareCategories), "utf8");
@@ -12584,6 +12955,30 @@ var MIGRATIONS = [
12584
12955
  return;
12585
12956
  ensureColumn(db, "memory_verifications", "mapping_origin", "TEXT NOT NULL DEFAULT 'mapper'");
12586
12957
  }
12958
+ },
12959
+ {
12960
+ version: 83,
12961
+ description: "add indexed rowid access for message FTS content",
12962
+ up(db) {
12963
+ db.exec(`
12964
+ CREATE TABLE IF NOT EXISTS message_fts_rowid_map (
12965
+ session_id TEXT NOT NULL,
12966
+ message_ordinal INTEGER NOT NULL,
12967
+ fts_rowid INTEGER NOT NULL,
12968
+ PRIMARY KEY(session_id, message_ordinal)
12969
+ );
12970
+
12971
+ CREATE TABLE IF NOT EXISTS message_fts_rowid_map_backfill_state (
12972
+ id INTEGER PRIMARY KEY CHECK(id = 1),
12973
+ watermark_rowid INTEGER NOT NULL DEFAULT 0,
12974
+ completed INTEGER NOT NULL DEFAULT 0 CHECK(completed IN (0, 1)),
12975
+ updated_at INTEGER NOT NULL DEFAULT 0
12976
+ );
12977
+ INSERT OR IGNORE INTO message_fts_rowid_map_backfill_state
12978
+ (id, watermark_rowid, completed, updated_at)
12979
+ VALUES (1, 0, 0, 0);
12980
+ `);
12981
+ }
12587
12982
  }
12588
12983
  ];
12589
12984
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -13022,7 +13417,7 @@ function getSchemaFenceRejection() {
13022
13417
  function getMigrationOnOpenRefusal() {
13023
13418
  return lastMigrationOnOpenRefusal;
13024
13419
  }
13025
- var LATEST_SUPPORTED_VERSION = 82;
13420
+ var LATEST_SUPPORTED_VERSION = 83;
13026
13421
  var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
13027
13422
  var defaultStoragePermissionFs = { chmodSync, mkdirSync: mkdirSync2 };
13028
13423
  var storagePermissionFs = defaultStoragePermissionFs;
@@ -13321,13 +13716,18 @@ function createPiBlockingProcess(pid) {
13321
13716
  function formatInconclusiveOpenCodeMigrationWarning(dbPath, pids) {
13322
13717
  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.`;
13323
13718
  }
13324
- function logInconclusiveMigrationProbes(dbPath, discovery, piProbeState) {
13719
+ function formatInconclusivePiMigrationWarning(dbPath, pids) {
13720
+ return `[magic-context] storage warning: continuing migration for ${dbPath}; Pi/OMP PID ${pids.join(", ")} was not confirmed as a live harness because the process image or command line was ambiguous. No live Pi harness was confirmed.`;
13721
+ }
13722
+ function logInconclusiveMigrationProbes(dbPath, discovery, piDiscovery) {
13325
13723
  const uncertainPids = discovery.inconclusivePids ?? [];
13326
13724
  if (uncertainPids.length > 0) {
13327
13725
  log(formatInconclusiveOpenCodeMigrationWarning(dbPath, uncertainPids));
13328
13726
  }
13329
- if (piProbeState === "unreadable") {
13727
+ if (piDiscovery.state === "unreadable") {
13330
13728
  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.`);
13729
+ } else if ((piDiscovery.inconclusivePids?.length ?? 0) > 0) {
13730
+ log(formatInconclusivePiMigrationWarning(dbPath, piDiscovery.inconclusivePids ?? []));
13331
13731
  }
13332
13732
  }
13333
13733
  function isDefaultSharedDatabasePath(dbPath) {
@@ -13362,7 +13762,7 @@ function enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)
13362
13762
  const blockingProcesses = [...serverProcesses, ...piPids.map(createPiBlockingProcess)];
13363
13763
  if ((discovery.state === "absent" || discovery.state === "stale" || discovery.state === "inconclusive") && piPids.length === 0) {
13364
13764
  lastMigrationOnOpenRefusal = null;
13365
- logInconclusiveMigrationProbes(dbPath, discovery, piDiscovery.state);
13765
+ logInconclusiveMigrationProbes(dbPath, discovery, piDiscovery);
13366
13766
  return true;
13367
13767
  }
13368
13768
  const blockingPids = [...new Set([...discovery.serverPids, ...piPids])].sort((left, right) => left - right);
@@ -13409,17 +13809,20 @@ function finishDatabaseOpen(db, dbPath, explicitDbPath, latestSupportedVersion)
13409
13809
  }
13410
13810
  healWedgedChannel2Claims(db);
13411
13811
  if (!explicitDbPath) {
13412
- const runBackfill = () => {
13812
+ const runBackfills = () => {
13413
13813
  try {
13414
13814
  runToolOwnerBackfill(db);
13415
13815
  } catch (error) {
13416
13816
  log(`[magic-context] tool-owner backfill failed (continuing with lazy adoption fallback): ${getErrorMessage(error)}`);
13417
13817
  }
13818
+ startMessageFtsRowidMapBackfill(db).catch((error) => {
13819
+ log(`[magic-context] message FTS rowid-map backfill failed (will resume next startup): ${getErrorMessage(error)}`);
13820
+ });
13418
13821
  };
13419
13822
  if (bootQuietRemainingMs() > 0)
13420
- scheduleAfterBootQuiet(runBackfill);
13823
+ scheduleAfterBootQuiet(runBackfills);
13421
13824
  else
13422
- runBackfill();
13825
+ runBackfills();
13423
13826
  }
13424
13827
  setDatabase(db);
13425
13828
  loadToolDefinitionMeasurements(db);
@@ -13959,6 +14362,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
13959
14362
  tokenize='porter unicode61'
13960
14363
  );
13961
14364
 
14365
+ CREATE TABLE IF NOT EXISTS message_fts_rowid_map (
14366
+ session_id TEXT NOT NULL,
14367
+ message_ordinal INTEGER NOT NULL,
14368
+ fts_rowid INTEGER NOT NULL,
14369
+ PRIMARY KEY(session_id, message_ordinal)
14370
+ );
14371
+
14372
+ CREATE TABLE IF NOT EXISTS message_fts_rowid_map_backfill_state (
14373
+ id INTEGER PRIMARY KEY CHECK(id = 1),
14374
+ watermark_rowid INTEGER NOT NULL DEFAULT 0,
14375
+ completed INTEGER NOT NULL DEFAULT 0 CHECK(completed IN (0, 1)),
14376
+ updated_at INTEGER NOT NULL DEFAULT 0
14377
+ );
14378
+ INSERT OR IGNORE INTO message_fts_rowid_map_backfill_state
14379
+ (id, watermark_rowid, completed, updated_at)
14380
+ VALUES (1, 0, 0, 0);
14381
+
13962
14382
  CREATE TABLE IF NOT EXISTS message_history_index (
13963
14383
  session_id TEXT PRIMARY KEY,
13964
14384
  last_indexed_ordinal INTEGER NOT NULL DEFAULT 0,
@@ -14102,8 +14522,9 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
14102
14522
  cached_m0_system_hash TEXT,
14103
14523
  cached_m0_tool_set_hash TEXT,
14104
14524
  cached_m0_model_key TEXT,
14105
- cached_m0_project_identity TEXT,
14106
- cached_m0_last_baseline_end_message_id TEXT,
14525
+ cached_m0_project_identity TEXT,
14526
+ cached_m0_last_baseline_end_message_id TEXT,
14527
+ thinking_binding_recovery_target TEXT NOT NULL DEFAULT '',
14107
14528
  upgrade_reminded_at INTEGER,
14108
14529
  pi_stable_id_scheme INTEGER
14109
14530
  );
@@ -14325,6 +14746,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
14325
14746
  ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
14326
14747
  ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
14327
14748
  ensureColumn(db, "session_meta", "merged_reasoning_stripped_ids", "TEXT DEFAULT ''");
14749
+ ensureColumn(db, "session_meta", "thinking_binding_recovery_target", "TEXT DEFAULT ''");
14328
14750
  ensureColumn(db, "session_meta", "trailing_blank_decisions", "TEXT DEFAULT ''");
14329
14751
  ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
14330
14752
  ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
@@ -16066,7 +16488,7 @@ function clearPendingCompactionMarkerStateIf(db, sessionId, expected) {
16066
16488
  return result.changes > 0;
16067
16489
  }
16068
16490
  function isPendingPiCompactionMarker(value) {
16069
- return typeof value === "object" && value !== null && typeof value.firstKeptEntryId === "string" && typeof value.endMessageId === "string" && typeof value.ordinal === "number" && typeof value.tokensBefore === "number" && typeof value.summary === "string" && typeof value.publishedAt === "number";
16491
+ return typeof value === "object" && value !== null && (value.firstKeptEntryId === null || typeof value.firstKeptEntryId === "string") && typeof value.endMessageId === "string" && typeof value.ordinal === "number" && typeof value.tokensBefore === "number" && typeof value.summary === "string" && typeof value.publishedAt === "number";
16070
16492
  }
16071
16493
  function getPendingPiCompactionMarkerState(db, sessionId) {
16072
16494
  const row = db.prepare("SELECT pending_pi_compaction_marker_state FROM session_meta WHERE session_id = ?").get(sessionId);
@@ -16281,15 +16703,38 @@ var SESSION_SCOPED_TABLES = [
16281
16703
  { table: "embedding_measurement_corpus" },
16282
16704
  { table: "pending_session_cleanup", harnessScoped: true },
16283
16705
  { table: "message_history_fts" },
16706
+ { table: "message_fts_rowid_map" },
16284
16707
  { table: "message_history_source", harnessScoped: true },
16285
16708
  { table: "message_history_index", harnessScoped: true },
16286
16709
  { table: "lkg_slots" }
16287
16710
  ];
16288
- function deleteSessionScopedRows(db, sessionIds, harness) {
16711
+ function deleteSessionScopedRows(db, sessionIds, harness, options = {}) {
16289
16712
  if (sessionIds.length === 0)
16290
- return;
16291
- const placeholders2 = sessionIds.map(() => "?").join(", ");
16713
+ return 0;
16714
+ let deletableSessionIds = [...sessionIds];
16715
+ if (options.rustModuleCleanupAcknowledged !== true) {
16716
+ const placeholders3 = sessionIds.map(() => "?").join(", ");
16717
+ const harnessPredicate = harness === undefined ? "" : " AND harness = ?";
16718
+ const protectedRows = db.prepare(`SELECT session_id
16719
+ FROM pending_session_cleanup
16720
+ WHERE session_id IN (${placeholders3})
16721
+ AND harness LIKE '%:rust'${harnessPredicate}`).all(...sessionIds, ...harness === undefined ? [] : [`${harness}:rust`]);
16722
+ const protectedSessionIds = new Set(protectedRows.map((row) => row.session_id));
16723
+ deletableSessionIds = sessionIds.filter((sessionId) => !protectedSessionIds.has(sessionId));
16724
+ }
16725
+ if (deletableSessionIds.length === 0)
16726
+ return 0;
16727
+ const placeholders2 = deletableSessionIds.map(() => "?").join(", ");
16292
16728
  for (const definition of SESSION_SCOPED_TABLES) {
16729
+ if (definition.table === "message_history_fts") {
16730
+ db.prepare(`DELETE FROM message_history_fts
16731
+ WHERE rowid IN (
16732
+ SELECT fts_rowid
16733
+ FROM message_fts_rowid_map
16734
+ WHERE session_id IN (${placeholders2})
16735
+ )`).run(...deletableSessionIds);
16736
+ continue;
16737
+ }
16293
16738
  const predicates = [`session_id IN (${placeholders2})`];
16294
16739
  if (definition.extraPredicate)
16295
16740
  predicates.push(definition.extraPredicate);
@@ -16298,10 +16743,11 @@ function deleteSessionScopedRows(db, sessionIds, harness) {
16298
16743
  predicates.push("harness = ?");
16299
16744
  const statement = db.prepare(`DELETE FROM ${definition.table} WHERE ${predicates.join(" AND ")}`);
16300
16745
  if (bindHarness)
16301
- statement.run(...sessionIds, harness);
16746
+ statement.run(...deletableSessionIds, harness);
16302
16747
  else
16303
- statement.run(...sessionIds);
16748
+ statement.run(...deletableSessionIds);
16304
16749
  }
16750
+ return deletableSessionIds.length;
16305
16751
  }
16306
16752
 
16307
16753
  // ../plugin/src/features/magic-context/storage-meta-session.ts
@@ -16402,8 +16848,15 @@ function advanceToolReclaimWatermark(db, sessionId, maxTagNumber) {
16402
16848
  db.prepare("UPDATE session_meta SET tool_reclaim_watermark = MAX(COALESCE(tool_reclaim_watermark, 0), ?) WHERE session_id = ?").run(maxTagNumber, sessionId);
16403
16849
  })();
16404
16850
  }
16851
+ function rustCleanupHarness() {
16852
+ return `${getHarness()}:rust`;
16853
+ }
16405
16854
  function retryPendingSessionCleanups(db, limit = 200) {
16406
- const rows = db.prepare("SELECT session_id FROM pending_session_cleanup ORDER BY requested_at ASC, session_id ASC LIMIT ?").all(Math.max(1, Math.floor(limit)));
16855
+ const rows = db.prepare(`SELECT session_id
16856
+ FROM pending_session_cleanup
16857
+ WHERE harness NOT LIKE '%:rust'
16858
+ ORDER BY requested_at ASC, session_id ASC
16859
+ LIMIT ?`).all(Math.max(1, Math.floor(limit)));
16407
16860
  const failedSessionIds = [];
16408
16861
  let cleared = 0;
16409
16862
  for (const row of rows) {
@@ -16417,15 +16870,42 @@ function retryPendingSessionCleanups(db, limit = 200) {
16417
16870
  }
16418
16871
  return { attempted: rows.length, cleared, failedSessionIds };
16419
16872
  }
16420
- function clearSession(db, sessionId) {
16873
+ async function retryPendingRustSessionCleanupsForProject(db, projectPath, deleteSession, limit = 200) {
16874
+ const harness = getHarness();
16875
+ const rows = db.prepare(`SELECT pending.session_id
16876
+ FROM pending_session_cleanup pending
16877
+ JOIN session_projects projects
16878
+ ON projects.session_id = pending.session_id
16879
+ AND projects.harness = ?
16880
+ WHERE pending.harness = ?
16881
+ AND projects.project_path = ?
16882
+ ORDER BY pending.requested_at ASC, pending.session_id ASC
16883
+ LIMIT ?`).all(harness, rustCleanupHarness(), projectPath, Math.max(1, Math.floor(limit)));
16884
+ const failedSessionIds = [];
16885
+ let cleared = 0;
16886
+ for (const row of rows) {
16887
+ try {
16888
+ db.prepare("UPDATE pending_session_cleanup SET last_attempt_at = ? WHERE session_id = ?").run(Date.now(), row.session_id);
16889
+ await deleteSession(row.session_id);
16890
+ clearSession(db, row.session_id, true);
16891
+ cleared += 1;
16892
+ } catch {
16893
+ failedSessionIds.push(row.session_id);
16894
+ }
16895
+ }
16896
+ return { attempted: rows.length, cleared, failedSessionIds };
16897
+ }
16898
+ function clearSession(db, sessionId, rustModuleCleanupAcknowledged = false) {
16421
16899
  const transactionStartedAt = performance.now();
16422
16900
  db.transaction(() => {
16423
- deleteSessionScopedRows(db, [sessionId]);
16901
+ deleteSessionScopedRows(db, [sessionId], undefined, {
16902
+ rustModuleCleanupAcknowledged
16903
+ });
16424
16904
  })();
16425
16905
  logSlowWriteTransaction("clear-session", transactionStartedAt);
16426
16906
  }
16427
16907
  // ../plugin/src/hooks/magic-context/todo-view.ts
16428
- import { createHash as createHash4 } from "node:crypto";
16908
+ import { createHash as createHash5 } from "node:crypto";
16429
16909
  var TODO_STATUS_PENDING = "pending";
16430
16910
  var TODO_STATUS_IN_PROGRESS = "in_progress";
16431
16911
  var TODO_STATUS_COMPLETED = "completed";
@@ -16493,7 +16973,7 @@ function buildSyntheticTodoPart(stateJson) {
16493
16973
  };
16494
16974
  }
16495
16975
  function computeSyntheticCallId(stateJson) {
16496
- const hash = createHash4("sha256").update(stateJson).digest("hex").slice(0, 16);
16976
+ const hash = createHash5("sha256").update(stateJson).digest("hex").slice(0, 16);
16497
16977
  return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
16498
16978
  }
16499
16979
  function parseTodoState(stateJson) {
@@ -16754,7 +17234,7 @@ function escapeXmlContent(s) {
16754
17234
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
16755
17235
  }
16756
17236
  // ../plugin/src/features/magic-context/message-index.ts
16757
- import { createHash as createHash5 } from "node:crypto";
17237
+ import { createHash as createHash6 } from "node:crypto";
16758
17238
 
16759
17239
  // ../plugin/src/hooks/magic-context/read-session-raw.ts
16760
17240
  function isRawMessageRow(row) {
@@ -17985,6 +18465,9 @@ var upsertMessageSourceStatements = new WeakMap;
17985
18465
  var deleteMessageSourceStatements = new WeakMap;
17986
18466
  var deleteMessageSourceRangeStatements = new WeakMap;
17987
18467
  var deleteMessageFtsStatements = new WeakMap;
18468
+ var deleteFtsMapStatements = new WeakMap;
18469
+ var deleteFtsMapRangeStatements = new WeakMap;
18470
+ var deleteMessageFtsMapStatements = new WeakMap;
17988
18471
  function normalizeIndexText(text) {
17989
18472
  return text.replace(/\s+/g, " ").trim();
17990
18473
  }
@@ -18023,7 +18506,12 @@ function getUpsertDirtyFloorStatement(db) {
18023
18506
  function getDeleteFtsRangeStatement(db) {
18024
18507
  let stmt = deleteFtsRangeStatements.get(db);
18025
18508
  if (!stmt) {
18026
- stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ? AND CAST(message_ordinal AS INTEGER) BETWEEN ? AND ?");
18509
+ stmt = db.prepare(`DELETE FROM message_history_fts
18510
+ WHERE rowid IN (
18511
+ SELECT fts_rowid
18512
+ FROM message_fts_rowid_map
18513
+ WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?
18514
+ )`);
18027
18515
  deleteFtsRangeStatements.set(db, stmt);
18028
18516
  }
18029
18517
  return stmt;
@@ -18031,7 +18519,12 @@ function getDeleteFtsRangeStatement(db) {
18031
18519
  function getCountIndexedMessageStatement(db) {
18032
18520
  let stmt = countIndexedMessageStatements.get(db);
18033
18521
  if (!stmt) {
18034
- stmt = db.prepare("SELECT COUNT(*) AS count FROM message_history_fts WHERE session_id = ? AND message_id = ?");
18522
+ stmt = db.prepare(`SELECT COUNT(*) AS count
18523
+ FROM message_history_source AS source
18524
+ JOIN message_fts_rowid_map AS map
18525
+ ON map.session_id = source.session_id
18526
+ AND map.message_ordinal = source.message_ordinal
18527
+ WHERE source.session_id = ? AND source.message_id = ?`);
18035
18528
  countIndexedMessageStatements.set(db, stmt);
18036
18529
  }
18037
18530
  return stmt;
@@ -18073,11 +18566,45 @@ function getDeleteMessageSourceRangeStatement(db) {
18073
18566
  function getDeleteMessageFtsStatement(db) {
18074
18567
  let stmt = deleteMessageFtsStatements.get(db);
18075
18568
  if (!stmt) {
18076
- stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ? AND message_id = ?");
18569
+ stmt = db.prepare(`DELETE FROM message_history_fts
18570
+ WHERE rowid IN (
18571
+ SELECT map.fts_rowid
18572
+ FROM message_history_source AS source
18573
+ JOIN message_fts_rowid_map AS map
18574
+ ON map.session_id = source.session_id
18575
+ AND map.message_ordinal = source.message_ordinal
18576
+ WHERE source.session_id = ? AND source.message_id = ?
18577
+ )`);
18077
18578
  deleteMessageFtsStatements.set(db, stmt);
18078
18579
  }
18079
18580
  return stmt;
18080
18581
  }
18582
+ function getDeleteFtsMapRangeStatement(db) {
18583
+ let stmt = deleteFtsMapRangeStatements.get(db);
18584
+ if (!stmt) {
18585
+ stmt = db.prepare("DELETE FROM message_fts_rowid_map WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?");
18586
+ deleteFtsMapRangeStatements.set(db, stmt);
18587
+ }
18588
+ return stmt;
18589
+ }
18590
+ function getDeleteMessageFtsMapStatement(db) {
18591
+ let stmt = deleteMessageFtsMapStatements.get(db);
18592
+ if (!stmt) {
18593
+ stmt = db.prepare(`DELETE FROM message_fts_rowid_map
18594
+ WHERE session_id = ?
18595
+ AND message_ordinal = (
18596
+ SELECT message_ordinal
18597
+ FROM message_history_source
18598
+ WHERE session_id = ? AND message_id = ?
18599
+ )`);
18600
+ deleteMessageFtsMapStatements.set(db, stmt);
18601
+ }
18602
+ return stmt;
18603
+ }
18604
+ function insertMessageFtsRow(db, sessionId, messageOrdinal, messageId, role, content) {
18605
+ const result = getInsertMessageStatement(db).run(sessionId, messageOrdinal, messageId, role, content);
18606
+ recordMessageFtsRowid(db, sessionId, messageOrdinal, result.lastInsertRowid);
18607
+ }
18081
18608
  function normalizeSourceVersion(version) {
18082
18609
  if (typeof version === "number")
18083
18610
  return `number:${version}`;
@@ -18090,7 +18617,7 @@ function getMessageSourceSnapshot(message) {
18090
18617
  return {
18091
18618
  ordinal: message.ordinal,
18092
18619
  sourceVersion: normalizeSourceVersion(message.version),
18093
- contentHash: createHash5("sha256").update(content).digest("hex"),
18620
+ contentHash: createHash6("sha256").update(content).digest("hex"),
18094
18621
  role: message.role,
18095
18622
  content
18096
18623
  };
@@ -18160,10 +18687,14 @@ function indexSingleMessageInTransaction(db, sessionId, message, now, dirtyFloor
18160
18687
  if (isMessageIndexSourceCurrent(db, sessionId, message)) {
18161
18688
  return false;
18162
18689
  }
18690
+ if (!messageFtsOrdinalRangeIsMapped(db, sessionId, message.ordinal, message.ordinal)) {
18691
+ return false;
18692
+ }
18163
18693
  getDeleteMessageFtsStatement(db).run(sessionId, message.id);
18694
+ getDeleteMessageFtsMapStatement(db).run(sessionId, sessionId, message.id);
18164
18695
  const content2 = setMessageSource(db, sessionId, message, now);
18165
18696
  if (content2.length > 0 && (message.role === "user" || message.role === "assistant")) {
18166
- getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content2);
18697
+ insertMessageFtsRow(db, sessionId, message.ordinal, message.id, message.role, content2);
18167
18698
  }
18168
18699
  setIndexProgress(db, sessionId, currentWatermark, dirtyFloorBeforeAttempt === message.ordinal ? null : dirtyFloorBeforeAttempt, now);
18169
18700
  return true;
@@ -18174,7 +18705,7 @@ function indexSingleMessageInTransaction(db, sessionId, message, now, dirtyFloor
18174
18705
  const content = setMessageSource(db, sessionId, message, now);
18175
18706
  let inserted = false;
18176
18707
  if (content.length > 0 && (message.role === "user" || message.role === "assistant") && !isMessageAlreadyIndexed(db, sessionId, message.id)) {
18177
- getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
18708
+ insertMessageFtsRow(db, sessionId, message.ordinal, message.id, message.role, content);
18178
18709
  inserted = true;
18179
18710
  }
18180
18711
  setIndexProgress(db, sessionId, message.ordinal, dirtyFloorBeforeAttempt === message.ordinal ? null : dirtyFloorBeforeAttempt, now);
@@ -18211,8 +18742,14 @@ function indexMessagesAfterOrdinal(db, sessionId, messages, _lastIndexedOrdinal,
18211
18742
  const currentWatermark = getLastIndexedOrdinal(db, sessionId);
18212
18743
  const dirtyFloor = getDirtyIndexFloor(db, sessionId);
18213
18744
  const effectiveWatermark = dirtyFloor === null ? currentWatermark : Math.min(currentWatermark, Math.max(0, dirtyFloor - 1));
18745
+ if (dirtyFloor !== null && dirtyFloor <= currentWatermark && !messageFtsOrdinalRangeIsMapped(db, sessionId, dirtyFloor, Math.min(currentWatermark, finalWatermark))) {
18746
+ db.exec("COMMIT");
18747
+ committed = true;
18748
+ return 0;
18749
+ }
18214
18750
  if (dirtyFloor !== null && dirtyFloor <= finalWatermark) {
18215
18751
  getDeleteFtsRangeStatement(db).run(sessionId, dirtyFloor, finalWatermark);
18752
+ getDeleteFtsMapRangeStatement(db).run(sessionId, dirtyFloor, finalWatermark);
18216
18753
  getDeleteMessageSourceRangeStatement(db).run(sessionId, dirtyFloor, finalWatermark);
18217
18754
  }
18218
18755
  const messagesByOrdinal = new Map;
@@ -18233,7 +18770,7 @@ function indexMessagesAfterOrdinal(db, sessionId, messages, _lastIndexedOrdinal,
18233
18770
  if (content.length === 0 || message.role !== "user" && message.role !== "assistant" || isMessageAlreadyIndexed(db, sessionId, message.id)) {
18234
18771
  continue;
18235
18772
  }
18236
- getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
18773
+ insertMessageFtsRow(db, sessionId, message.ordinal, message.id, message.role, content);
18237
18774
  inserted += 1;
18238
18775
  }
18239
18776
  const missingFloor = coveredWatermark < finalWatermark ? coveredWatermark + 1 : null;
@@ -18261,6 +18798,16 @@ function persistMessageHistoryOrphanSweepState(db, cursor, lastSweptAt) {
18261
18798
  cursor_session_id = excluded.cursor_session_id,
18262
18799
  last_swept_at = excluded.last_swept_at`).run(cursor, lastSweptAt);
18263
18800
  }
18801
+ function getOpenCodeSessionScopedCandidateSourceSql() {
18802
+ return SESSION_SCOPED_TABLES.filter((definition) => definition.harnessScoped === true).map((definition) => {
18803
+ const predicates = ["session_id IS NOT NULL", "harness = 'opencode'"];
18804
+ if (definition.extraPredicate)
18805
+ predicates.push(definition.extraPredicate);
18806
+ return `SELECT session_id FROM ${definition.table} WHERE ${predicates.join(" AND ")}`;
18807
+ }).join(`
18808
+ UNION
18809
+ `);
18810
+ }
18264
18811
  function sweepOrphanedOpenCodeMessageIndexes(db, openReadableOpenCodeDb, options = {}) {
18265
18812
  const now = options.now ?? Date.now();
18266
18813
  const batchSize = Math.max(1, Math.floor(options.batchSize ?? MESSAGE_HISTORY_ORPHAN_SWEEP_BATCH_SIZE));
@@ -18284,13 +18831,19 @@ function sweepOrphanedOpenCodeMessageIndexes(db, openReadableOpenCodeDb, options
18284
18831
  }
18285
18832
  try {
18286
18833
  const cutoff = now - safetyAgeMs;
18834
+ const candidateSourceSql = getOpenCodeSessionScopedCandidateSourceSql();
18287
18835
  const candidates = db.prepare(`SELECT session_id
18288
- FROM message_history_index
18289
- WHERE harness = 'opencode'
18290
- AND updated_at <= ?
18291
- AND session_id > ?
18836
+ FROM (${candidateSourceSql}) AS session_candidates
18837
+ WHERE session_id > ?
18838
+ AND NOT EXISTS (
18839
+ SELECT 1
18840
+ FROM message_history_index
18841
+ WHERE message_history_index.session_id = session_candidates.session_id
18842
+ AND message_history_index.harness = 'opencode'
18843
+ AND message_history_index.updated_at > ?
18844
+ )
18292
18845
  ORDER BY session_id ASC
18293
- LIMIT ?`).all(cutoff, cursor, batchSize);
18846
+ LIMIT ?`).all(cursor, cutoff, batchSize);
18294
18847
  const sessionExists = openCodeDb.prepare("SELECT 1 FROM session WHERE id = ? LIMIT 1");
18295
18848
  const missingSessionIds = candidates.filter((candidate) => !sessionExists.get(candidate.session_id)).map((candidate) => candidate.session_id);
18296
18849
  const nextCursor = candidates.length < batchSize ? "" : candidates[candidates.length - 1]?.session_id ?? cursor;
@@ -18299,10 +18852,19 @@ function sweepOrphanedOpenCodeMessageIndexes(db, openReadableOpenCodeDb, options
18299
18852
  let committed = false;
18300
18853
  let deleted = 0;
18301
18854
  try {
18302
- const stillEligible = db.prepare("SELECT 1 FROM message_history_index WHERE session_id = ? AND harness = 'opencode' AND updated_at <= ?");
18855
+ const stillEligible = db.prepare(`SELECT 1
18856
+ FROM (${candidateSourceSql}) AS session_candidates
18857
+ WHERE session_id = ?
18858
+ AND NOT EXISTS (
18859
+ SELECT 1
18860
+ FROM message_history_index
18861
+ WHERE message_history_index.session_id = session_candidates.session_id
18862
+ AND message_history_index.harness = 'opencode'
18863
+ AND message_history_index.updated_at > ?
18864
+ )
18865
+ LIMIT 1`);
18303
18866
  const eligibleSessionIds = missingSessionIds.filter((sessionId) => stillEligible.get(sessionId, cutoff));
18304
- deleteSessionScopedRows(db, eligibleSessionIds, "opencode");
18305
- deleted = eligibleSessionIds.length;
18867
+ deleted = deleteSessionScopedRows(db, eligibleSessionIds, "opencode");
18306
18868
  persistMessageHistoryOrphanSweepState(db, nextCursor, completedAt);
18307
18869
  db.exec("COMMIT");
18308
18870
  committed = true;
@@ -18324,7 +18886,7 @@ function sweepOrphanedOpenCodeMessageIndexes(db, openReadableOpenCodeDb, options
18324
18886
  }
18325
18887
  }
18326
18888
  // ../plugin/src/features/magic-context/project-docs-hash.ts
18327
- import { createHash as createHash6 } from "node:crypto";
18889
+ import { createHash as createHash7 } from "node:crypto";
18328
18890
  import { lstatSync, readFileSync as readFileSync5, statSync as statSync4 } from "node:fs";
18329
18891
  import path2 from "node:path";
18330
18892
  var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
@@ -18422,7 +18984,7 @@ function hashCanonicalPieces(hashPieces) {
18422
18984
  if (hashPieces.length === 0) {
18423
18985
  return "";
18424
18986
  }
18425
- return createHash6("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
18987
+ return createHash7("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
18426
18988
  }
18427
18989
  function readProjectDocsCanonical(projectDirectory) {
18428
18990
  const canonicalDirectory = path2.resolve(projectDirectory);
@@ -18693,10 +19255,10 @@ function copySessionStateForClone(db, sourceSessionId, destinationSessionId, fil
18693
19255
  });
18694
19256
  }
18695
19257
  // ../plugin/src/features/magic-context/storage-embedding-measurements.ts
18696
- import { createHash as createHash7 } from "node:crypto";
19258
+ import { createHash as createHash8 } from "node:crypto";
18697
19259
  function normalizedQueryHash(query) {
18698
19260
  const normalized = query.trim().replace(/\s+/g, " ").toLowerCase();
18699
- return createHash7("sha256").update(normalized).digest("hex");
19261
+ return createHash8("sha256").update(normalized).digest("hex");
18700
19262
  }
18701
19263
  var MEASUREMENT_CORPUS_SESSION_ROW_CAP = 2000;
18702
19264
  function recordEmbeddingMeasurement(db, input, cap = MEASUREMENT_CORPUS_SESSION_ROW_CAP) {
@@ -19165,6 +19727,7 @@ function markNoteChecked(db, noteId) {
19165
19727
  // ../plugin/src/features/magic-context/storage-ops.ts
19166
19728
  var queuePendingOpStatements = new WeakMap;
19167
19729
  var getPendingOpsStatements = new WeakMap;
19730
+ var getPendingOpsCountStatements = new WeakMap;
19168
19731
  var clearPendingOpsStatements = new WeakMap;
19169
19732
  var removePendingOpStatements = new WeakMap;
19170
19733
  function getQueuePendingOpStatement(db) {
@@ -19225,6 +19788,19 @@ function getPendingOps(db, sessionId) {
19225
19788
  const rows = getPendingOpsStatement(db).all(sessionId).filter(isPendingOpRow);
19226
19789
  return rows.map(toPendingOp).filter((op) => op !== null);
19227
19790
  }
19791
+ function getPendingOpsCount(db, sessionId) {
19792
+ try {
19793
+ let statement = getPendingOpsCountStatements.get(db);
19794
+ if (!statement) {
19795
+ statement = db.prepare("SELECT COUNT(*) AS count FROM pending_ops WHERE session_id = ?");
19796
+ getPendingOpsCountStatements.set(db, statement);
19797
+ }
19798
+ const row = statement.get(sessionId);
19799
+ return typeof row?.count === "number" && Number.isFinite(row.count) ? row.count : null;
19800
+ } catch {
19801
+ return null;
19802
+ }
19803
+ }
19228
19804
  function clearPendingOps(db, sessionId) {
19229
19805
  getClearPendingOpsStatement(db).run(sessionId);
19230
19806
  }
@@ -20053,7 +20629,10 @@ var getTagNumbersByMessageIdStatements = new WeakMap;
20053
20629
  var deleteTagsByMessageIdStatements = new WeakMap;
20054
20630
  var getMaxTagNumberBySessionStatements = new WeakMap;
20055
20631
  var getTagNumberByMessageIdStatements = new WeakMap;
20632
+ var getAssignableTagNumberByMessageIdStatements = new WeakMap;
20056
20633
  var hasPiFallbackMessageTagStatements = new WeakMap;
20634
+ var WHITESPACE_ASSISTANT_INERT_MESSAGE_PREFIX = "__mc_whitespace_assistant_inert__:";
20635
+ var WHITESPACE_ASSISTANT_INERT_FINGERPRINT_PREFIX = "mc:whitespace-assistant:";
20057
20636
  function getInsertTagStatement(db) {
20058
20637
  let stmt = insertTagStatements.get(db);
20059
20638
  if (!stmt) {
@@ -20279,6 +20858,25 @@ function getTagNumberByMessageIdStatement(db) {
20279
20858
  }
20280
20859
  return stmt;
20281
20860
  }
20861
+ function getAssignableTagNumberByMessageIdStatement(db) {
20862
+ let stmt = getAssignableTagNumberByMessageIdStatements.get(db);
20863
+ if (!stmt) {
20864
+ stmt = db.prepare(`SELECT tag_number FROM tags
20865
+ WHERE session_id = ?
20866
+ AND message_id = ?
20867
+ AND NOT (
20868
+ status = 'compacted'
20869
+ AND COALESCE(
20870
+ entry_fingerprint LIKE '${WHITESPACE_ASSISTANT_INERT_FINGERPRINT_PREFIX}%',
20871
+ 0
20872
+ ) = 1
20873
+ )
20874
+ ORDER BY tag_number ASC
20875
+ LIMIT 1`);
20876
+ getAssignableTagNumberByMessageIdStatements.set(db, stmt);
20877
+ }
20878
+ return stmt;
20879
+ }
20282
20880
  function isTagRow(row) {
20283
20881
  if (row === null || typeof row !== "object")
20284
20882
  return false;
@@ -20322,6 +20920,18 @@ function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoni
20322
20920
  function updateTagStatus(db, sessionId, tagId, status) {
20323
20921
  getUpdateTagStatusStatement(db).run(status, sessionId, tagId);
20324
20922
  }
20923
+ function getInertWhitespaceAssistantTags(db, sessionId) {
20924
+ const rows = db.prepare(`SELECT tag_number AS tagNumber, entry_fingerprint AS entryFingerprint
20925
+ FROM tags
20926
+ WHERE session_id = ?
20927
+ AND type = 'message'
20928
+ AND status = 'compacted'
20929
+ AND entry_fingerprint LIKE ?`).all(sessionId, `${WHITESPACE_ASSISTANT_INERT_FINGERPRINT_PREFIX}%`);
20930
+ return rows.flatMap((row) => {
20931
+ const contentId = row.entryFingerprint.slice(WHITESPACE_ASSISTANT_INERT_FINGERPRINT_PREFIX.length);
20932
+ return contentId.length > 0 ? [{ tagNumber: row.tagNumber, contentId }] : [];
20933
+ });
20934
+ }
20325
20935
  function updateTagDropMode(db, sessionId, tagNumber, dropMode) {
20326
20936
  getUpdateTagDropModeStatement(db).run(dropMode, sessionId, tagNumber);
20327
20937
  }
@@ -20531,6 +21141,9 @@ function adoptPiFallbackToolOwnerTag(db, sessionId, tagNumber, callId, oldOwnerM
20531
21141
  };
20532
21142
  }
20533
21143
  function adoptPiFallbackMessageTag(db, sessionId, tagNumber, oldFallbackMessageId, newRealMessageId) {
21144
+ if (oldFallbackMessageId.startsWith(WHITESPACE_ASSISTANT_INERT_MESSAGE_PREFIX)) {
21145
+ return { action: "skipped" };
21146
+ }
20534
21147
  const survivor = getPiFallbackFoldTagRowByNumber(db, sessionId, tagNumber);
20535
21148
  if (survivor === null || survivor.type !== "message" || survivor.messageId !== oldFallbackMessageId) {
20536
21149
  return { action: "skipped" };
@@ -20569,6 +21182,10 @@ function getTagNumberByMessageId(db, sessionId, messageId) {
20569
21182
  const row = getTagNumberByMessageIdStatement(db).get(sessionId, messageId);
20570
21183
  return isTagNumberRow(row) ? row.tag_number : null;
20571
21184
  }
21185
+ function getAssignableTagNumberByMessageId(db, sessionId, messageId) {
21186
+ const row = getAssignableTagNumberByMessageIdStatement(db).get(sessionId, messageId);
21187
+ return isTagNumberRow(row) ? row.tag_number : null;
21188
+ }
20572
21189
  var getMinMessageTagNumberForRawIdStatements = new WeakMap;
20573
21190
  function isMinTagNumberRow(row) {
20574
21191
  return row !== null && typeof row === "object" && "m" in row;
@@ -20763,144 +21380,528 @@ var ERROR_CLASSES = new Set([
20763
21380
  "permission_denied",
20764
21381
  "unknown"
20765
21382
  ]);
20766
- // ../plugin/src/shared/prompt-surface-runtime.ts
20767
- import { existsSync as existsSync8, readFileSync as readFileSync7, statSync as statSync5 } from "node:fs";
20768
- import { dirname as dirname4, isAbsolute as isAbsolute2, resolve as resolve3 } from "node:path";
20769
-
20770
- // ../plugin/src/tools/light-descriptions.ts
20771
- var CTX_REDUCE_LIGHT_DESCRIPTION = `For ctx_reduce users, mark spent §N§ outputs discardable; release is QUEUED, not immediate, so content stays visible until space is needed. Newest tags stay protected until they age out. Released content becomes a placeholder; recover it only by rerunning the source or recovery tool, so mark only genuinely finished material. Mark analyzed, redundant, persisted, or merely confirmatory outputs; keep user messages, unresolved errors, unextracted evidence, and exact wording. NEVER blanket-mark a large range: review every tag first.`;
20772
- var CTX_EXPAND_LIGHT_DESCRIPTION = `For ctx_expand users, recover compacted conversation by passing a session-history heading's inclusive start/end ordinals. Results are raw [N] U:/A: transcript capped near 15K tokens; oversized ranges return the head and a continuation. Use verbose=true to list each message ordinal, part previews, and tool-output sizes; use message=N for one complete stored message and its tool exchanges. NEVER expand ranges after the last compartment because that live tail is already visible.`;
20773
- var CTX_NOTE_LIGHT_DESCRIPTION = `For ctx_note users, write saves, read lists, update changes, and dismiss retires future session notes; surface_condition creates a smart note. For smart notes, NEVER use a condition tied to this conversation or an unobservable future action because the background checker can inspect only external GitHub, disk, git, or web signals.`;
20774
- var CTX_MEMORY_LIGHT_DESCRIPTION = `For ctx_memory users, write one standalone durable fact with category and content; update one ID, archive one or more IDs, merge two or more IDs, or get one to twenty numeric IDs. get reads memories in every status; list remains dreamer-only, so primary agents must NEVER assume bulk-list access.`;
20775
- var CTX_SEARCH_LIGHT_DESCRIPTION = `For ctx_search users, retrieve only hidden recall: memories not already in <project-memory>, compacted messages outside the live tail, commits, and notes. Omit sources for broad search; select memory, message, git_commit, or note to target a source, or pass memory IDs to bypass text search. Message hits continue through ctx_expand.`;
20776
-
20777
- // ../plugin/src/shared/jsonc-parser.ts
20778
- import { existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
20779
- function stripJsonComments(content) {
20780
- let result = "";
20781
- let inString = false;
20782
- let escaped = false;
20783
- let inLineComment = false;
20784
- let inBlockComment = false;
20785
- for (let index = 0;index < content.length; index += 1) {
20786
- const char = content[index];
20787
- const next = content[index + 1];
20788
- if (inLineComment) {
20789
- if (char === `
20790
- `) {
20791
- inLineComment = false;
20792
- result += char;
20793
- }
20794
- continue;
20795
- }
20796
- if (inBlockComment) {
20797
- if (char === "*" && next === "/") {
20798
- inBlockComment = false;
20799
- index += 1;
20800
- }
20801
- continue;
20802
- }
20803
- if (inString) {
20804
- result += char;
20805
- if (escaped) {
20806
- escaped = false;
20807
- } else if (char === "\\") {
20808
- escaped = true;
20809
- } else if (char === '"') {
20810
- inString = false;
20811
- }
20812
- continue;
20813
- }
20814
- if (char === '"') {
20815
- inString = true;
20816
- result += char;
20817
- continue;
20818
- }
20819
- if (char === "/" && next === "/") {
20820
- inLineComment = true;
20821
- index += 1;
20822
- continue;
20823
- }
20824
- if (char === "/" && next === "*") {
20825
- inBlockComment = true;
20826
- index += 1;
20827
- continue;
20828
- }
20829
- result += char;
21383
+ // ../plugin/src/shared/window-geometry.ts
21384
+ import { readFileSync as readFileSync6 } from "node:fs";
21385
+ import { join as join6 } from "node:path";
21386
+ var WINDOW_OVERLAY_SCHEMA = "fusiform-window-overlay/v1";
21387
+ var PROMPT_WALL_MARGIN = 4096;
21388
+ var PI_OUTPUT_FLOOR = 4096;
21389
+ var OPENCODE_OUTPUT_CAP = 32000;
21390
+ var MIN_PLAUSIBLE_CONTEXT_LIMIT = 1024;
21391
+ var OUTPUT_RESERVE_CAP_RATIO = 0.25;
21392
+ var PROVIDER_GEOMETRY = {
21393
+ anthropic: "shared_truncating",
21394
+ xai: "shared_truncating",
21395
+ google: "separate",
21396
+ "google-antigravity": "separate"
21397
+ };
21398
+ var GRADES = new Set([
21399
+ "provider_asserted_runtime",
21400
+ "measured",
21401
+ "provider_asserted_doc",
21402
+ "catalog",
21403
+ "unknown"
21404
+ ]);
21405
+ var UNITS = new Set(["provider", "estimate"]);
21406
+ var BOUNDARIES = new Set(["Observed", "Asserted", "Corrected"]);
21407
+ var UNKNOWN_REASONS = new Set([
21408
+ "placeholder_output_equals_context",
21409
+ "placeholder_zero",
21410
+ "never_measured",
21411
+ "not_single_valued_at_key",
21412
+ "retracted"
21413
+ ]);
21414
+ var NUMERIC_FACT_KEYS = new Set([
21415
+ "window.advertised",
21416
+ "window.enforced",
21417
+ "output.advertised",
21418
+ "output.enforced",
21419
+ "output.default"
21420
+ ]);
21421
+ var configuredOverlayPath;
21422
+ var loadedOverlayPath;
21423
+ var loadedOverlay;
21424
+ var geometryClampLogSeen = new Set;
21425
+ function isRecord2(value) {
21426
+ return typeof value === "object" && value !== null && !Array.isArray(value);
21427
+ }
21428
+ function isFinitePositive(value) {
21429
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
21430
+ }
21431
+ function scalarizeFact(value) {
21432
+ if (value.kind === "stated")
21433
+ return isFinitePositive(value.value) ? value.value : undefined;
21434
+ if (value.kind === "bracket") {
21435
+ return isFinitePositive(value.at_least) ? value.at_least : undefined;
20830
21436
  }
20831
- return result;
21437
+ return;
20832
21438
  }
20833
- function stripTrailingCommas(content) {
20834
- let result = "";
20835
- let inString = false;
20836
- let escaped = false;
20837
- for (let index = 0;index < content.length; index += 1) {
20838
- const char = content[index];
20839
- if (inString) {
20840
- result += char;
20841
- if (escaped) {
20842
- escaped = false;
20843
- } else if (char === "\\") {
20844
- escaped = true;
20845
- } else if (char === '"') {
20846
- inString = false;
20847
- }
20848
- continue;
20849
- }
20850
- if (char === '"') {
20851
- inString = true;
20852
- result += char;
20853
- continue;
21439
+ function parseFactValue(value) {
21440
+ if (!isRecord2(value) || typeof value.kind !== "string")
21441
+ return;
21442
+ if (value.kind === "stated") {
21443
+ if ((typeof value.value !== "number" || !Number.isFinite(value.value)) && typeof value.value !== "string") {
21444
+ return;
20854
21445
  }
20855
- if (char === ",") {
20856
- let lookahead = index + 1;
20857
- while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
20858
- lookahead += 1;
20859
- }
20860
- const next = content[lookahead];
20861
- if (next === "}" || next === "]") {
20862
- continue;
20863
- }
21446
+ return { kind: "stated", value: value.value };
21447
+ }
21448
+ if (value.kind === "bracket") {
21449
+ const atLeast = value.at_least;
21450
+ const below = value.below;
21451
+ if (atLeast === undefined && below === undefined)
21452
+ return { kind: "bracket" };
21453
+ if (atLeast !== undefined && !isFinitePositive(atLeast))
21454
+ return;
21455
+ if (below !== undefined && !isFinitePositive(below))
21456
+ return;
21457
+ if (isFinitePositive(atLeast) && isFinitePositive(below) && below <= atLeast) {
21458
+ return;
20864
21459
  }
20865
- result += char;
21460
+ return {
21461
+ kind: "bracket",
21462
+ ...isFinitePositive(atLeast) ? { at_least: atLeast } : {},
21463
+ ...isFinitePositive(below) ? { below } : {}
21464
+ };
20866
21465
  }
20867
- return result;
21466
+ if (value.kind === "unknown" && UNKNOWN_REASONS.has(value.why)) {
21467
+ return { kind: "unknown", why: value.why };
21468
+ }
21469
+ return;
20868
21470
  }
20869
- var PROTOTYPE_POLLUTION_KEYS = new Set(["__proto__", "constructor", "prototype"]);
20870
- function isPrototypePollutionKey(key) {
20871
- return PROTOTYPE_POLLUTION_KEYS.has(key);
21471
+ function parseFact(key, value) {
21472
+ if (!isRecord2(value))
21473
+ return;
21474
+ const parsedValue = parseFactValue(value.value);
21475
+ if (!parsedValue || !GRADES.has(value.grade) || !UNITS.has(value.units) || !BOUNDARIES.has(value.boundary) || typeof value.source_ref !== "string" || value.source_ref.length === 0 || typeof value.observed_at !== "string" || value.observed_at.length === 0) {
21476
+ return;
21477
+ }
21478
+ if (NUMERIC_FACT_KEYS.has(key) && parsedValue.kind === "stated" && !isFinitePositive(parsedValue.value)) {
21479
+ return;
21480
+ }
21481
+ if (key === "geometry" && parsedValue.kind === "stated" && !["shared_upfront", "shared_truncating", "separate"].includes(String(parsedValue.value))) {
21482
+ return;
21483
+ }
21484
+ return {
21485
+ ...value,
21486
+ value: parsedValue,
21487
+ grade: value.grade,
21488
+ units: value.units,
21489
+ boundary: value.boundary,
21490
+ source_ref: value.source_ref,
21491
+ observed_at: value.observed_at
21492
+ };
20872
21493
  }
20873
- function sanitizeParsedJson(value, options = {}, path3 = []) {
20874
- if (Array.isArray(value)) {
20875
- return value.map((entry, index) => sanitizeParsedJson(entry, options, [...path3, index]));
21494
+ function parseWindowOverlay(value) {
21495
+ if (!isRecord2(value)) {
21496
+ return { badCells: 0, refusal: "overlay root is not an object" };
20876
21497
  }
20877
- if (value === null || typeof value !== "object")
20878
- return value;
20879
- const source = value;
20880
- const sourcePrototype = Object.getPrototypeOf(source);
20881
- if (sourcePrototype !== null && sourcePrototype !== Object.prototype) {
20882
- options.onRejectedKey?.([...path3, "__proto__"]);
21498
+ if (value.schema !== WINDOW_OVERLAY_SCHEMA) {
21499
+ return {
21500
+ badCells: 0,
21501
+ refusal: `unrecognized schema ${JSON.stringify(value.schema)}`
21502
+ };
20883
21503
  }
20884
- const sanitized = {};
20885
- for (const key of Object.keys(source)) {
20886
- if (isPrototypePollutionKey(key)) {
20887
- options.onRejectedKey?.([...path3, key]);
21504
+ if (typeof value.generated_at !== "string" || !Array.isArray(value.minted_provider_ids) || !value.minted_provider_ids.every((id) => typeof id === "string" && id.length > 0) || !Array.isArray(value.cells)) {
21505
+ return { badCells: 0, refusal: "invalid v1 envelope" };
21506
+ }
21507
+ const cells = [];
21508
+ let badCells = 0;
21509
+ for (const rawCell of value.cells) {
21510
+ if (!isRecord2(rawCell) || typeof rawCell.provider_id !== "string" || rawCell.provider_id.length === 0 || typeof rawCell.model_id !== "string" || rawCell.model_id.length === 0 || !isRecord2(rawCell.facts)) {
21511
+ badCells++;
20888
21512
  continue;
20889
21513
  }
20890
- Object.defineProperty(sanitized, key, {
20891
- value: sanitizeParsedJson(source[key], options, [...path3, key]),
20892
- enumerable: true,
20893
- configurable: true,
20894
- writable: true
21514
+ const facts = {};
21515
+ let valid = true;
21516
+ for (const [key, rawFact] of Object.entries(rawCell.facts)) {
21517
+ const fact = parseFact(key, rawFact);
21518
+ if (!fact) {
21519
+ valid = false;
21520
+ break;
21521
+ }
21522
+ facts[key] = fact;
21523
+ }
21524
+ if (!valid) {
21525
+ badCells++;
21526
+ continue;
21527
+ }
21528
+ cells.push({
21529
+ provider_id: rawCell.provider_id,
21530
+ model_id: rawCell.model_id,
21531
+ facts
20895
21532
  });
20896
21533
  }
20897
- return sanitized;
21534
+ return {
21535
+ overlay: {
21536
+ schema: WINDOW_OVERLAY_SCHEMA,
21537
+ generated_at: value.generated_at,
21538
+ minted_provider_ids: [...value.minted_provider_ids],
21539
+ cells
21540
+ },
21541
+ badCells
21542
+ };
20898
21543
  }
20899
- function parseJsonc(content, options = {}) {
20900
- const normalized = stripTrailingCommas(stripJsonComments(content));
20901
- return sanitizeParsedJson(JSON.parse(normalized), options);
21544
+ function defaultWindowOverlayPath() {
21545
+ return join6(getDataDir(), "fusiform", "window-overlay.json");
20902
21546
  }
20903
- function detectConfigFile(basePath) {
21547
+ function readWindowOverlayFile(path3, log2 = (message) => sessionLog("global", message)) {
21548
+ let raw;
21549
+ try {
21550
+ raw = readFileSync6(path3, "utf8");
21551
+ } catch (error) {
21552
+ if (error.code === "ENOENT")
21553
+ return;
21554
+ log2(`window-overlay: unable to read ${path3}; overlay ignored`);
21555
+ return;
21556
+ }
21557
+ let decoded;
21558
+ try {
21559
+ decoded = JSON.parse(raw);
21560
+ } catch {
21561
+ log2(`window-overlay: invalid JSON in ${path3}; overlay ignored`);
21562
+ return;
21563
+ }
21564
+ const parsed = parseWindowOverlay(decoded);
21565
+ if (parsed.refusal) {
21566
+ log2(`window-overlay: ${parsed.refusal} in ${path3}; entire overlay ignored`);
21567
+ return;
21568
+ }
21569
+ if (parsed.badCells > 0) {
21570
+ log2(`window-overlay: skipped ${parsed.badCells} invalid cell(s) from ${path3}`);
21571
+ }
21572
+ return parsed.overlay;
21573
+ }
21574
+ function setWindowOverlayPath(path3) {
21575
+ if (configuredOverlayPath === path3)
21576
+ return;
21577
+ reloadWindowOverlay(path3);
21578
+ }
21579
+ function reloadWindowOverlay(path3) {
21580
+ configuredOverlayPath = path3;
21581
+ loadedOverlayPath = undefined;
21582
+ loadedOverlay = undefined;
21583
+ }
21584
+ function getWindowOverlay() {
21585
+ const path3 = configuredOverlayPath ?? defaultWindowOverlayPath();
21586
+ if (loadedOverlayPath === path3 && loadedOverlay !== undefined) {
21587
+ return loadedOverlay ?? undefined;
21588
+ }
21589
+ loadedOverlayPath = path3;
21590
+ loadedOverlay = readWindowOverlayFile(path3) ?? null;
21591
+ return loadedOverlay ?? undefined;
21592
+ }
21593
+ function resolveWindowOverlayFacts(providerID, modelID, overlay = getWindowOverlay()) {
21594
+ if (!overlay)
21595
+ return;
21596
+ const modelRefs = modelRefLookupOrder(`${providerID}/${modelID}`);
21597
+ const providerCandidates = new Set(modelRefs.map((ref) => ref.slice(0, ref.indexOf("/"))));
21598
+ const modelCandidates = new Set([
21599
+ modelID,
21600
+ ...modelRefs.map((ref) => ref.slice(ref.indexOf("/") + 1))
21601
+ ]);
21602
+ const colon = modelID.lastIndexOf(":");
21603
+ if (colon > 0)
21604
+ modelCandidates.add(modelID.slice(0, colon));
21605
+ const wildcardFacts = {};
21606
+ const specificFacts = {};
21607
+ for (const cell of overlay.cells) {
21608
+ if (!providerCandidates.has(cell.provider_id))
21609
+ continue;
21610
+ if (cell.model_id === "*")
21611
+ Object.assign(wildcardFacts, cell.facts);
21612
+ else if (modelCandidates.has(cell.model_id))
21613
+ Object.assign(specificFacts, cell.facts);
21614
+ }
21615
+ const facts = { ...wildcardFacts, ...specificFacts };
21616
+ return Object.keys(facts).length > 0 ? { facts } : undefined;
21617
+ }
21618
+ function numericOverlayFact(overlay, key) {
21619
+ const fact = overlay?.facts[key];
21620
+ return fact ? scalarizeFact(fact.value) : undefined;
21621
+ }
21622
+ function overlayGeometry(overlay) {
21623
+ const fact = overlay?.facts.geometry;
21624
+ if (fact === undefined)
21625
+ return;
21626
+ if (fact.value.kind === "unknown")
21627
+ return { kind: "unknown" };
21628
+ if (fact.value.kind !== "stated")
21629
+ return;
21630
+ const value = fact.value.value;
21631
+ return value === "shared_upfront" || value === "shared_truncating" || value === "separate" ? { kind: "stated", value } : undefined;
21632
+ }
21633
+ function placeholderFilteredOutput(output, context) {
21634
+ if (!isFinitePositive(output))
21635
+ return;
21636
+ if (isFinitePositive(context) && output >= context)
21637
+ return;
21638
+ return output;
21639
+ }
21640
+ function mergePositive(overlayValue, providerValue) {
21641
+ return isFinitePositive(providerValue) ? providerValue : overlayValue;
21642
+ }
21643
+ function logGeometryClampOnce(key, message, log2) {
21644
+ if (geometryClampLogSeen.has(key))
21645
+ return;
21646
+ geometryClampLogSeen.add(key);
21647
+ (log2 ?? ((entry) => sessionLog("global", `window-geometry: ${entry}`)))(message);
21648
+ }
21649
+ function deriveWindowGeometry(providerID, modelID, catalogLimit, options = {}) {
21650
+ if (!catalogLimit && !options.providerLimit)
21651
+ return;
21652
+ const providerLimit = options.providerLimit;
21653
+ const catalogContext = isFinitePositive(catalogLimit?.context) ? catalogLimit.context : undefined;
21654
+ const advertised = numericOverlayFact(options.overlay, "window.advertised");
21655
+ const enforced = numericOverlayFact(options.overlay, "window.enforced");
21656
+ let softContext = mergePositive(enforced ?? advertised ?? catalogContext, providerLimit?.context);
21657
+ let hardContext = mergePositive(enforced ?? softContext, providerLimit?.context);
21658
+ if (isFinitePositive(options.contextCap)) {
21659
+ softContext = isFinitePositive(softContext) ? Math.min(softContext, options.contextCap) : options.contextCap;
21660
+ hardContext = isFinitePositive(hardContext) ? Math.min(hardContext, options.contextCap) : options.contextCap;
21661
+ }
21662
+ const input = mergePositive(isFinitePositive(catalogLimit?.input) ? catalogLimit.input : undefined, providerLimit?.input);
21663
+ if (!isFinitePositive(softContext) && !isFinitePositive(input))
21664
+ return;
21665
+ const catalogOutput = options.overlay === undefined && options.providerLimit === undefined ? isFinitePositive(catalogLimit?.output) ? catalogLimit.output : undefined : placeholderFilteredOutput(catalogLimit?.output, softContext);
21666
+ const overlayOutput = placeholderFilteredOutput(numericOverlayFact(options.overlay, "output.enforced") ?? numericOverlayFact(options.overlay, "output.default") ?? numericOverlayFact(options.overlay, "output.advertised"), softContext);
21667
+ const providerOutput = placeholderFilteredOutput(providerLimit?.output, softContext);
21668
+ const output = providerOutput ?? overlayOutput ?? catalogOutput;
21669
+ const geometryFact = overlayGeometry(options.overlay);
21670
+ const geometry = geometryFact?.kind === "stated" ? geometryFact.value : geometryFact?.kind === "unknown" ? "shared_upfront" : PROVIDER_GEOMETRY[providerID] ?? "shared_upfront";
21671
+ const geometryOverride = geometryFact?.kind === "stated" ? geometryFact.value : undefined;
21672
+ const preCarvedInput = isFinitePositive(input) && (!isFinitePositive(softContext) || input < softContext);
21673
+ const outputReserveOverride = typeof options.outputReserveOverride === "number" && Number.isFinite(options.outputReserveOverride) && options.outputReserveOverride >= 0 ? options.outputReserveOverride : undefined;
21674
+ let derivationWindow = softContext ?? input;
21675
+ let usableSoft;
21676
+ let softReserve = 0;
21677
+ let reserveSource = "none";
21678
+ if (outputReserveOverride !== undefined) {
21679
+ const reserveWindow = preCarvedInput ? input : softContext ?? input;
21680
+ if (!isFinitePositive(reserveWindow))
21681
+ return;
21682
+ derivationWindow = reserveWindow;
21683
+ softReserve = outputReserveOverride;
21684
+ reserveSource = "output_config";
21685
+ const floor = Math.max(MIN_PLAUSIBLE_CONTEXT_LIMIT, reserveWindow * 0.5);
21686
+ const flooredReserve = Math.min(softReserve, Math.max(0, reserveWindow - floor));
21687
+ if (flooredReserve < softReserve) {
21688
+ logGeometryClampOnce(`soft-floor|${providerID}/${modelID}|${softReserve}|${flooredReserve}`, `output reserve clamped by the half-window floor for ${providerID}/${modelID}: reserve ${softReserve} → ${flooredReserve}`, options.log);
21689
+ }
21690
+ softReserve = flooredReserve;
21691
+ usableSoft = Math.floor(reserveWindow - softReserve);
21692
+ } else if (preCarvedInput) {
21693
+ usableSoft = input;
21694
+ if (isFinitePositive(softContext)) {
21695
+ softReserve = Math.max(0, softContext - input);
21696
+ reserveSource = "output_catalog";
21697
+ }
21698
+ } else if (isFinitePositive(softContext)) {
21699
+ if (geometry === "separate" && (options.overlay === undefined || options.harness === "pi" || geometryOverride !== undefined)) {
21700
+ softReserve = 0;
21701
+ reserveSource = "none";
21702
+ } else {
21703
+ softReserve = output ?? 0;
21704
+ reserveSource = output === undefined ? "none" : "output_catalog";
21705
+ const cap = softContext * OUTPUT_RESERVE_CAP_RATIO;
21706
+ softReserve = Math.min(softReserve, options.harness === "pi" || options.overlay === undefined ? cap : Math.min(cap, OPENCODE_OUTPUT_CAP));
21707
+ }
21708
+ const floor = Math.max(MIN_PLAUSIBLE_CONTEXT_LIMIT, softContext * 0.5);
21709
+ const flooredReserve = Math.min(softReserve, Math.max(0, softContext - floor));
21710
+ if (flooredReserve < softReserve) {
21711
+ logGeometryClampOnce(`soft-floor|${providerID}/${modelID}|${softReserve}|${flooredReserve}`, `output reserve clamped by the half-window floor for ${providerID}/${modelID}: reserve ${softReserve} → ${flooredReserve} (catalog context/output pair is contradictory)`, options.log);
21712
+ }
21713
+ softReserve = flooredReserve;
21714
+ usableSoft = Math.floor(softContext - softReserve);
21715
+ } else {
21716
+ usableSoft = input;
21717
+ }
21718
+ const hardWindow = hardContext ?? softContext ?? input;
21719
+ if (!isFinitePositive(hardWindow))
21720
+ return;
21721
+ let usableHard;
21722
+ if (geometry === "separate") {
21723
+ usableHard = hardWindow;
21724
+ } else if (geometry === "shared_truncating") {
21725
+ usableHard = hardWindow - PROMPT_WALL_MARGIN;
21726
+ } else if (options.harness === "pi" && providerID !== "openai-codex") {
21727
+ usableHard = hardWindow - PI_OUTPUT_FLOOR;
21728
+ } else if (options.harness === "pi") {
21729
+ usableHard = hardWindow - (output ?? OPENCODE_OUTPUT_CAP);
21730
+ } else {
21731
+ const requestedOutput = Math.min(output ?? OPENCODE_OUTPUT_CAP, OPENCODE_OUTPUT_CAP);
21732
+ usableHard = hardWindow - requestedOutput;
21733
+ }
21734
+ usableHard = Math.max(MIN_PLAUSIBLE_CONTEXT_LIMIT, Math.floor(usableHard));
21735
+ if (usableHard < usableSoft) {
21736
+ logGeometryClampOnce(`${providerID}/${modelID}|${usableSoft}|${usableHard}`, `usable hard limit clamped for ${providerID}/${modelID}: ${usableHard} → ${usableSoft} (overlay/provider inversion)`, options.log);
21737
+ usableHard = usableSoft;
21738
+ }
21739
+ const resolvedWindow = derivationWindow ?? usableSoft;
21740
+ return {
21741
+ usableSoft,
21742
+ usableHard,
21743
+ geometry,
21744
+ derivation: {
21745
+ window: Math.floor(resolvedWindow),
21746
+ reserve: Math.floor(Math.max(0, resolvedWindow - usableSoft)),
21747
+ reserveSource,
21748
+ geometry
21749
+ }
21750
+ };
21751
+ }
21752
+ function formatWindowDerivationLine(inputTokens, result) {
21753
+ const percentage = result.usableSoft > 0 ? inputTokens / result.usableSoft * 100 : 0;
21754
+ const reserveLabel = result.derivation.reserveSource === "wall_margin" ? "wall margin" : result.derivation.reserveSource === "none" ? "reserve" : "output reserve";
21755
+ return `Context: ${formatCompactTokens(inputTokens)} / ${formatCompactTokens(result.usableSoft)} usable (${percentage.toFixed(1)}%) — window ${formatCompactTokens(result.derivation.window)} − ${formatCompactTokens(result.derivation.reserve)} ${reserveLabel} [${result.geometry}]`;
21756
+ }
21757
+ function formatCompactTokens(value) {
21758
+ if (Math.abs(value) >= 1e6) {
21759
+ return `${(value / 1e6).toFixed(1).replace(/\.0$/, "")}m`;
21760
+ }
21761
+ if (Math.abs(value) >= 1000) {
21762
+ return `${(value / 1000).toFixed(1).replace(/\.0$/, "")}k`;
21763
+ }
21764
+ return Math.round(value).toLocaleString();
21765
+ }
21766
+
21767
+ // ../plugin/src/shared/prompt-surface-runtime.ts
21768
+ import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync5 } from "node:fs";
21769
+ import { dirname as dirname4, isAbsolute as isAbsolute2, resolve as resolve3 } from "node:path";
21770
+
21771
+ // ../plugin/src/tools/light-descriptions.ts
21772
+ var CTX_REDUCE_LIGHT_DESCRIPTION = `For ctx_reduce users, mark spent §N§ outputs discardable; release is QUEUED, not immediate, so content stays visible until space is needed. Newest tags stay protected until they age out. Released content becomes a placeholder; recover it only by rerunning the source or recovery tool, so mark only genuinely finished material. Mark analyzed, redundant, persisted, or merely confirmatory outputs; keep user messages, unresolved errors, unextracted evidence, and exact wording. NEVER blanket-mark a large range: review every tag first.`;
21773
+ var CTX_EXPAND_LIGHT_DESCRIPTION = `For ctx_expand users, recover compacted conversation by passing a session-history heading's inclusive start/end ordinals. Results are raw [N] U:/A: transcript capped near 15K tokens; oversized ranges return the head and a continuation. Use verbose=true to list each message ordinal, part previews, and tool-output sizes; use message=N for one complete stored message and its tool exchanges. NEVER expand ranges after the last compartment because that live tail is already visible.`;
21774
+ var CTX_NOTE_LIGHT_DESCRIPTION = `For ctx_note users, write saves, read lists, update changes, and dismiss retires future session notes; surface_condition creates a smart note. For smart notes, NEVER use a condition tied to this conversation or an unobservable future action because the background checker can inspect only external GitHub, disk, git, or web signals.`;
21775
+ var CTX_MEMORY_LIGHT_DESCRIPTION = `For ctx_memory users, write one standalone durable fact with category and content; update one ID, archive one or more IDs, merge two or more IDs, or get one to twenty numeric IDs. get reads memories in every status; list remains dreamer-only, so primary agents must NEVER assume bulk-list access.`;
21776
+ var CTX_SEARCH_LIGHT_DESCRIPTION = `For ctx_search users, retrieve only hidden recall: memories not already in <project-memory>, compacted messages outside the live tail, commits, and notes. Omit sources for broad search; select memory, message, git_commit, or note to target a source, or pass memory IDs to bypass text search. Message hits continue through ctx_expand.`;
21777
+
21778
+ // ../plugin/src/shared/jsonc-parser.ts
21779
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
21780
+ function stripJsonComments(content) {
21781
+ let result = "";
21782
+ let inString = false;
21783
+ let escaped = false;
21784
+ let inLineComment = false;
21785
+ let inBlockComment = false;
21786
+ for (let index = 0;index < content.length; index += 1) {
21787
+ const char = content[index];
21788
+ const next = content[index + 1];
21789
+ if (inLineComment) {
21790
+ if (char === `
21791
+ `) {
21792
+ inLineComment = false;
21793
+ result += char;
21794
+ }
21795
+ continue;
21796
+ }
21797
+ if (inBlockComment) {
21798
+ if (char === "*" && next === "/") {
21799
+ inBlockComment = false;
21800
+ index += 1;
21801
+ }
21802
+ continue;
21803
+ }
21804
+ if (inString) {
21805
+ result += char;
21806
+ if (escaped) {
21807
+ escaped = false;
21808
+ } else if (char === "\\") {
21809
+ escaped = true;
21810
+ } else if (char === '"') {
21811
+ inString = false;
21812
+ }
21813
+ continue;
21814
+ }
21815
+ if (char === '"') {
21816
+ inString = true;
21817
+ result += char;
21818
+ continue;
21819
+ }
21820
+ if (char === "/" && next === "/") {
21821
+ inLineComment = true;
21822
+ index += 1;
21823
+ continue;
21824
+ }
21825
+ if (char === "/" && next === "*") {
21826
+ inBlockComment = true;
21827
+ index += 1;
21828
+ continue;
21829
+ }
21830
+ result += char;
21831
+ }
21832
+ return result;
21833
+ }
21834
+ function stripTrailingCommas(content) {
21835
+ let result = "";
21836
+ let inString = false;
21837
+ let escaped = false;
21838
+ for (let index = 0;index < content.length; index += 1) {
21839
+ const char = content[index];
21840
+ if (inString) {
21841
+ result += char;
21842
+ if (escaped) {
21843
+ escaped = false;
21844
+ } else if (char === "\\") {
21845
+ escaped = true;
21846
+ } else if (char === '"') {
21847
+ inString = false;
21848
+ }
21849
+ continue;
21850
+ }
21851
+ if (char === '"') {
21852
+ inString = true;
21853
+ result += char;
21854
+ continue;
21855
+ }
21856
+ if (char === ",") {
21857
+ let lookahead = index + 1;
21858
+ while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
21859
+ lookahead += 1;
21860
+ }
21861
+ const next = content[lookahead];
21862
+ if (next === "}" || next === "]") {
21863
+ continue;
21864
+ }
21865
+ }
21866
+ result += char;
21867
+ }
21868
+ return result;
21869
+ }
21870
+ var PROTOTYPE_POLLUTION_KEYS = new Set(["__proto__", "constructor", "prototype"]);
21871
+ function isPrototypePollutionKey(key) {
21872
+ return PROTOTYPE_POLLUTION_KEYS.has(key);
21873
+ }
21874
+ function sanitizeParsedJson(value, options = {}, path3 = []) {
21875
+ if (Array.isArray(value)) {
21876
+ return value.map((entry, index) => sanitizeParsedJson(entry, options, [...path3, index]));
21877
+ }
21878
+ if (value === null || typeof value !== "object")
21879
+ return value;
21880
+ const source = value;
21881
+ const sourcePrototype = Object.getPrototypeOf(source);
21882
+ if (sourcePrototype !== null && sourcePrototype !== Object.prototype) {
21883
+ options.onRejectedKey?.([...path3, "__proto__"]);
21884
+ }
21885
+ const sanitized = {};
21886
+ for (const key of Object.keys(source)) {
21887
+ if (isPrototypePollutionKey(key)) {
21888
+ options.onRejectedKey?.([...path3, key]);
21889
+ continue;
21890
+ }
21891
+ Object.defineProperty(sanitized, key, {
21892
+ value: sanitizeParsedJson(source[key], options, [...path3, key]),
21893
+ enumerable: true,
21894
+ configurable: true,
21895
+ writable: true
21896
+ });
21897
+ }
21898
+ return sanitized;
21899
+ }
21900
+ function parseJsonc(content, options = {}) {
21901
+ const normalized = stripTrailingCommas(stripJsonComments(content));
21902
+ return sanitizeParsedJson(JSON.parse(normalized), options);
21903
+ }
21904
+ function detectConfigFile(basePath) {
20904
21905
  const jsoncPath = `${basePath}.jsonc`;
20905
21906
  const jsonPath = `${basePath}.json`;
20906
21907
  if (existsSync7(jsoncPath)) {
@@ -21046,7 +22047,7 @@ function createPromptSurfaceRuntime(options) {
21046
22047
  warnOnce(`guidance-not-file:${path3}`, `prompt_surface.guidance_override_path (${path3}) is not a file; using built-in guidance.`);
21047
22048
  return;
21048
22049
  }
21049
- content = readFileSync7(path3, "utf8");
22050
+ content = readFileSync8(path3, "utf8");
21050
22051
  } catch (error) {
21051
22052
  const reason = error instanceof Error ? error.message : String(error);
21052
22053
  warnOnce(`guidance-unreadable:${path3}:${reason}`, `prompt_surface.guidance_override_path (${path3}) could not be read (${reason}); using built-in guidance.`);
@@ -36568,6 +37569,7 @@ var BaseEmbeddingConfigSchema = exports_external.object({
36568
37569
  query_input_type: exports_external.string().optional().describe("Optional input_type for query (search) embeddings on asymmetric models (e.g. NVIDIA NIM 'query'). When unset, query embeddings use embedding.input_type. Passage/stored content always uses embedding.input_type."),
36569
37570
  truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset."),
36570
37571
  max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted."),
37572
+ local_runtime: exports_external.enum(["auto", "native", "wasm"]).default("auto").describe("Local provider only: ONNX runtime selection. 'auto' uses native under Node and uses WASM under Bun versions before 1.4.0, where Bun's NAPI teardown race can panic on quit; native is restored automatically on Bun 1.4.0+. Set 'native' only to prefer speed while accepting that pre-1.4.0 Bun crash risk, or 'wasm' to avoid loading the native addon."),
36571
37573
  local_dtype: exports_external.enum([
36572
37574
  "auto",
36573
37575
  "fp32",
@@ -36624,6 +37626,7 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
36624
37626
  return {
36625
37627
  provider: "local",
36626
37628
  model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
37629
+ local_runtime: data.local_runtime,
36627
37630
  ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {},
36628
37631
  ...data.local_dtype ? { local_dtype: data.local_dtype } : {}
36629
37632
  };
@@ -36704,7 +37707,8 @@ var MagicContextConfigSchema = exports_external.object({
36704
37707
  }).default({ enforce_private_permissions: true }).describe("Storage permission policy. The default keeps session content and memories owner-private. Disabling enforcement is for trusted shared-group storage managed externally; every group member able to read the storage can read all stored session content and memories."),
36705
37708
  embedding: EmbeddingConfigSchema.default({
36706
37709
  provider: "local",
36707
- model: DEFAULT_LOCAL_EMBEDDING_MODEL
37710
+ model: DEFAULT_LOCAL_EMBEDDING_MODEL,
37711
+ local_runtime: "auto"
36708
37712
  }).describe("Embedding provider configuration"),
36709
37713
  subc: exports_external.object({
36710
37714
  connection_file: exports_external.string().trim().min(1).transform(expandConfigPath).describe("Path to the owner-only subc connection file.")
@@ -37255,13 +38259,13 @@ import {
37255
38259
  existsSync as existsSync9,
37256
38260
  linkSync,
37257
38261
  openSync as openSync2,
37258
- readFileSync as readFileSync8,
38262
+ readFileSync as readFileSync9,
37259
38263
  renameSync as renameSync2,
37260
38264
  statSync as statSync6,
37261
38265
  unlinkSync as unlinkSync3,
37262
38266
  writeFileSync as writeFileSync2
37263
38267
  } from "node:fs";
37264
- import { basename as basename3, dirname as dirname5, join as join6 } from "node:path";
38268
+ import { basename as basename3, dirname as dirname5, join as join7 } from "node:path";
37265
38269
 
37266
38270
  // ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
37267
38271
  function createScanner(text, ignoreTrivia = false) {
@@ -38662,13 +39666,13 @@ var QUALIFIER_FIELDS = ["variant", "thinking_level"];
38662
39666
  var TASK_MODEL_FIELDS = [...MODEL_FIELDS, ...QUALIFIER_FIELDS, "timeout_minutes"];
38663
39667
  var PRE_PER_HARNESS_BACKUP_SUFFIX = ".pre-per-harness.bak";
38664
39668
  var temporaryFileSequence = 0;
38665
- function isRecord2(value) {
39669
+ function isRecord3(value) {
38666
39670
  return typeof value === "object" && value !== null && !Array.isArray(value);
38667
39671
  }
38668
39672
  function asDocument(text) {
38669
39673
  try {
38670
39674
  const document = parseJsonc(text.startsWith("\uFEFF") ? text.slice(1) : text);
38671
- return isRecord2(document) ? document : null;
39675
+ return isRecord3(document) ? document : null;
38672
39676
  } catch {
38673
39677
  return null;
38674
39678
  }
@@ -38676,7 +39680,7 @@ function asDocument(text) {
38676
39680
  function getAtPath(document, path3) {
38677
39681
  let current = document;
38678
39682
  for (const part of path3) {
38679
- if (!isRecord2(current) || !Object.hasOwn(current, part))
39683
+ if (!isRecord3(current) || !Object.hasOwn(current, part))
38680
39684
  return;
38681
39685
  current = current[part];
38682
39686
  }
@@ -38685,7 +39689,7 @@ function getAtPath(document, path3) {
38685
39689
  function stableJson(value) {
38686
39690
  if (Array.isArray(value))
38687
39691
  return `[${value.map(stableJson).join(",")}]`;
38688
- if (!isRecord2(value))
39692
+ if (!isRecord3(value))
38689
39693
  return JSON.stringify(value);
38690
39694
  return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`).join(",")}}`;
38691
39695
  }
@@ -38698,7 +39702,7 @@ function valueForDiagnostic(value) {
38698
39702
  function migrateEntryForHarness(value, harness) {
38699
39703
  if (Array.isArray(value))
38700
39704
  return value.map((entry2) => migrateEntryForHarness(entry2, harness));
38701
- if (!isRecord2(value) || !Object.hasOwn(value, "model"))
39705
+ if (!isRecord3(value) || !Object.hasOwn(value, "model"))
38702
39706
  return value;
38703
39707
  const entry = { model: value.model };
38704
39708
  if (harness === "opencode" && Object.hasOwn(value, "variant")) {
@@ -38719,11 +39723,11 @@ function canCreateAtPath(document, path3) {
38719
39723
  for (const part of path3) {
38720
39724
  if (current === undefined)
38721
39725
  return true;
38722
- if (!isRecord2(current))
39726
+ if (!isRecord3(current))
38723
39727
  return false;
38724
39728
  current = current[part];
38725
39729
  }
38726
- return current === undefined || isRecord2(current);
39730
+ return current === undefined || isRecord3(current);
38727
39731
  }
38728
39732
  function flatFieldPath(parts) {
38729
39733
  return parts.join(".");
@@ -38764,7 +39768,7 @@ function updateDocumentForFlatFields(text) {
38764
39768
  };
38765
39769
  const migrateAgentFields = (agentName) => {
38766
39770
  const agent = document[agentName];
38767
- if (!isRecord2(agent))
39771
+ if (!isRecord3(agent))
38768
39772
  return;
38769
39773
  for (const field of MODEL_FIELDS) {
38770
39774
  if (!Object.hasOwn(agent, field))
@@ -38795,11 +39799,11 @@ function updateDocumentForFlatFields(text) {
38795
39799
  migrateAgentFields("historian");
38796
39800
  migrateAgentFields("dreamer");
38797
39801
  const dreamer = document.dreamer;
38798
- const tasks = isRecord2(dreamer) ? dreamer.tasks : undefined;
38799
- if (isRecord2(tasks)) {
39802
+ const tasks = isRecord3(dreamer) ? dreamer.tasks : undefined;
39803
+ if (isRecord3(tasks)) {
38800
39804
  for (const taskName of Object.keys(tasks).sort()) {
38801
39805
  const task = tasks[taskName];
38802
- if (!isRecord2(task))
39806
+ if (!isRecord3(task))
38803
39807
  continue;
38804
39808
  for (const field of TASK_MODEL_FIELDS) {
38805
39809
  if (!Object.hasOwn(task, field))
@@ -38855,7 +39859,7 @@ function writeExclusiveBackup(backupPath, bytes, mode) {
38855
39859
  if (error51.code !== "EEXIST")
38856
39860
  throw error51;
38857
39861
  }
38858
- const existingBytes = readFileSync8(backupPath);
39862
+ const existingBytes = readFileSync9(backupPath);
38859
39863
  if (existingBytes.equals(bytes))
38860
39864
  return;
38861
39865
  if (bytes.subarray(0, existingBytes.length).equals(existingBytes)) {
@@ -38873,7 +39877,7 @@ function writeTemporaryCandidate(configPath, bytes, mode) {
38873
39877
  const stem = basename3(configPath);
38874
39878
  for (let attempt = 0;attempt < 32; attempt++) {
38875
39879
  temporaryFileSequence += 1;
38876
- const path3 = join6(directory, `.${stem}.per-harness-${process.pid}-${temporaryFileSequence}.tmp`);
39880
+ const path3 = join7(directory, `.${stem}.per-harness-${process.pid}-${temporaryFileSequence}.tmp`);
38877
39881
  let descriptor;
38878
39882
  try {
38879
39883
  descriptor = openSync2(path3, "wx", mode);
@@ -38903,7 +39907,7 @@ function loadRawConfigFile(options) {
38903
39907
  return null;
38904
39908
  let observedBytes;
38905
39909
  try {
38906
- observedBytes = readFileSync8(options.configPath);
39910
+ observedBytes = readFileSync9(options.configPath);
38907
39911
  } catch (error51) {
38908
39912
  throw new Error(`failed to read config: ${error51 instanceof Error ? error51.message : String(error51)}`);
38909
39913
  }
@@ -38947,7 +39951,7 @@ function loadRawConfigFile(options) {
38947
39951
  writeExclusiveBackup(backupPath, observedBytes, mode);
38948
39952
  temporaryPath = writeTemporaryCandidate(options.configPath, migration.bytes, mode);
38949
39953
  options.afterTemporaryWrite?.();
38950
- const currentBytes = readFileSync8(options.configPath);
39954
+ const currentBytes = readFileSync9(options.configPath);
38951
39955
  if (!hasFlatKeys(currentBytes)) {
38952
39956
  unlinkSync3(temporaryPath);
38953
39957
  return {
@@ -38995,7 +39999,7 @@ function loadRawConfigFile(options) {
38995
39999
  }
38996
40000
 
38997
40001
  // ../plugin/src/config/variable.ts
38998
- import { existsSync as existsSync10, readFileSync as readFileSync9 } from "node:fs";
40002
+ import { existsSync as existsSync10, readFileSync as readFileSync10 } from "node:fs";
38999
40003
  import { homedir as homedir5 } from "node:os";
39000
40004
  import { dirname as dirname6, isAbsolute as isAbsolute3, resolve as resolve4 } from "node:path";
39001
40005
  var ENV_PATTERN = /\{env:([^}]+)\}/g;
@@ -39078,7 +40082,7 @@ function substituteConfigVariables(input) {
39078
40082
  }
39079
40083
  let contents;
39080
40084
  try {
39081
- contents = readFileSync9(filePath, "utf-8").trim();
40085
+ contents = readFileSync10(filePath, "utf-8").trim();
39082
40086
  } catch (error51) {
39083
40087
  const message = error51 instanceof Error ? error51.message : String(error51);
39084
40088
  warnings.push(`Failed to read file for ${token} (${filePath}): ${message}; using empty string`);
@@ -39093,387 +40097,6 @@ function substituteConfigVariables(input) {
39093
40097
  // ../plugin/src/shared/models-dev-cache.ts
39094
40098
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync11, renameSync as renameSync3, writeFileSync as writeFileSync3 } from "node:fs";
39095
40099
  import { join as join8 } from "node:path";
39096
-
39097
- // ../plugin/src/shared/window-geometry.ts
39098
- import { readFileSync as readFileSync10 } from "node:fs";
39099
- import { join as join7 } from "node:path";
39100
- var WINDOW_OVERLAY_SCHEMA = "fusiform-window-overlay/v1";
39101
- var PROMPT_WALL_MARGIN = 4096;
39102
- var PI_OUTPUT_FLOOR = 4096;
39103
- var OPENCODE_OUTPUT_CAP = 32000;
39104
- var MIN_PLAUSIBLE_CONTEXT_LIMIT = 1024;
39105
- var OUTPUT_RESERVE_CAP_RATIO = 0.25;
39106
- var PROVIDER_GEOMETRY = {
39107
- anthropic: "shared_truncating",
39108
- xai: "shared_truncating",
39109
- google: "separate",
39110
- "google-antigravity": "separate"
39111
- };
39112
- var GRADES = new Set([
39113
- "provider_asserted_runtime",
39114
- "measured",
39115
- "provider_asserted_doc",
39116
- "catalog",
39117
- "unknown"
39118
- ]);
39119
- var UNITS = new Set(["provider", "estimate"]);
39120
- var BOUNDARIES = new Set(["Observed", "Asserted", "Corrected"]);
39121
- var UNKNOWN_REASONS = new Set([
39122
- "placeholder_output_equals_context",
39123
- "placeholder_zero",
39124
- "never_measured",
39125
- "not_single_valued_at_key",
39126
- "retracted"
39127
- ]);
39128
- var NUMERIC_FACT_KEYS = new Set([
39129
- "window.advertised",
39130
- "window.enforced",
39131
- "output.advertised",
39132
- "output.enforced",
39133
- "output.default"
39134
- ]);
39135
- var configuredOverlayPath;
39136
- var loadedOverlayPath;
39137
- var loadedOverlay;
39138
- var geometryClampLogSeen = new Set;
39139
- function isRecord3(value) {
39140
- return typeof value === "object" && value !== null && !Array.isArray(value);
39141
- }
39142
- function isFinitePositive(value) {
39143
- return typeof value === "number" && Number.isFinite(value) && value > 0;
39144
- }
39145
- function scalarizeFact(value) {
39146
- if (value.kind === "stated")
39147
- return isFinitePositive(value.value) ? value.value : undefined;
39148
- if (value.kind === "bracket") {
39149
- return isFinitePositive(value.at_least) ? value.at_least : undefined;
39150
- }
39151
- return;
39152
- }
39153
- function parseFactValue(value) {
39154
- if (!isRecord3(value) || typeof value.kind !== "string")
39155
- return;
39156
- if (value.kind === "stated") {
39157
- if ((typeof value.value !== "number" || !Number.isFinite(value.value)) && typeof value.value !== "string") {
39158
- return;
39159
- }
39160
- return { kind: "stated", value: value.value };
39161
- }
39162
- if (value.kind === "bracket") {
39163
- const atLeast = value.at_least;
39164
- const below = value.below;
39165
- if (atLeast === undefined && below === undefined)
39166
- return { kind: "bracket" };
39167
- if (atLeast !== undefined && !isFinitePositive(atLeast))
39168
- return;
39169
- if (below !== undefined && !isFinitePositive(below))
39170
- return;
39171
- if (isFinitePositive(atLeast) && isFinitePositive(below) && below <= atLeast) {
39172
- return;
39173
- }
39174
- return {
39175
- kind: "bracket",
39176
- ...isFinitePositive(atLeast) ? { at_least: atLeast } : {},
39177
- ...isFinitePositive(below) ? { below } : {}
39178
- };
39179
- }
39180
- if (value.kind === "unknown" && UNKNOWN_REASONS.has(value.why)) {
39181
- return { kind: "unknown", why: value.why };
39182
- }
39183
- return;
39184
- }
39185
- function parseFact(key, value) {
39186
- if (!isRecord3(value))
39187
- return;
39188
- const parsedValue = parseFactValue(value.value);
39189
- if (!parsedValue || !GRADES.has(value.grade) || !UNITS.has(value.units) || !BOUNDARIES.has(value.boundary) || typeof value.source_ref !== "string" || value.source_ref.length === 0 || typeof value.observed_at !== "string" || value.observed_at.length === 0) {
39190
- return;
39191
- }
39192
- if (NUMERIC_FACT_KEYS.has(key) && parsedValue.kind === "stated" && !isFinitePositive(parsedValue.value)) {
39193
- return;
39194
- }
39195
- if (key === "geometry" && parsedValue.kind === "stated" && !["shared_upfront", "shared_truncating", "separate"].includes(String(parsedValue.value))) {
39196
- return;
39197
- }
39198
- return {
39199
- ...value,
39200
- value: parsedValue,
39201
- grade: value.grade,
39202
- units: value.units,
39203
- boundary: value.boundary,
39204
- source_ref: value.source_ref,
39205
- observed_at: value.observed_at
39206
- };
39207
- }
39208
- function parseWindowOverlay(value) {
39209
- if (!isRecord3(value)) {
39210
- return { badCells: 0, refusal: "overlay root is not an object" };
39211
- }
39212
- if (value.schema !== WINDOW_OVERLAY_SCHEMA) {
39213
- return {
39214
- badCells: 0,
39215
- refusal: `unrecognized schema ${JSON.stringify(value.schema)}`
39216
- };
39217
- }
39218
- if (typeof value.generated_at !== "string" || !Array.isArray(value.minted_provider_ids) || !value.minted_provider_ids.every((id) => typeof id === "string" && id.length > 0) || !Array.isArray(value.cells)) {
39219
- return { badCells: 0, refusal: "invalid v1 envelope" };
39220
- }
39221
- const cells = [];
39222
- let badCells = 0;
39223
- for (const rawCell of value.cells) {
39224
- if (!isRecord3(rawCell) || typeof rawCell.provider_id !== "string" || rawCell.provider_id.length === 0 || typeof rawCell.model_id !== "string" || rawCell.model_id.length === 0 || !isRecord3(rawCell.facts)) {
39225
- badCells++;
39226
- continue;
39227
- }
39228
- const facts = {};
39229
- let valid = true;
39230
- for (const [key, rawFact] of Object.entries(rawCell.facts)) {
39231
- const fact = parseFact(key, rawFact);
39232
- if (!fact) {
39233
- valid = false;
39234
- break;
39235
- }
39236
- facts[key] = fact;
39237
- }
39238
- if (!valid) {
39239
- badCells++;
39240
- continue;
39241
- }
39242
- cells.push({
39243
- provider_id: rawCell.provider_id,
39244
- model_id: rawCell.model_id,
39245
- facts
39246
- });
39247
- }
39248
- return {
39249
- overlay: {
39250
- schema: WINDOW_OVERLAY_SCHEMA,
39251
- generated_at: value.generated_at,
39252
- minted_provider_ids: [...value.minted_provider_ids],
39253
- cells
39254
- },
39255
- badCells
39256
- };
39257
- }
39258
- function defaultWindowOverlayPath() {
39259
- return join7(getDataDir(), "fusiform", "window-overlay.json");
39260
- }
39261
- function readWindowOverlayFile(path3, log2 = (message) => sessionLog("global", message)) {
39262
- let raw;
39263
- try {
39264
- raw = readFileSync10(path3, "utf8");
39265
- } catch (error51) {
39266
- if (error51.code === "ENOENT")
39267
- return;
39268
- log2(`window-overlay: unable to read ${path3}; overlay ignored`);
39269
- return;
39270
- }
39271
- let decoded;
39272
- try {
39273
- decoded = JSON.parse(raw);
39274
- } catch {
39275
- log2(`window-overlay: invalid JSON in ${path3}; overlay ignored`);
39276
- return;
39277
- }
39278
- const parsed = parseWindowOverlay(decoded);
39279
- if (parsed.refusal) {
39280
- log2(`window-overlay: ${parsed.refusal} in ${path3}; entire overlay ignored`);
39281
- return;
39282
- }
39283
- if (parsed.badCells > 0) {
39284
- log2(`window-overlay: skipped ${parsed.badCells} invalid cell(s) from ${path3}`);
39285
- }
39286
- return parsed.overlay;
39287
- }
39288
- function setWindowOverlayPath(path3) {
39289
- configuredOverlayPath = path3;
39290
- loadedOverlayPath = undefined;
39291
- loadedOverlay = undefined;
39292
- }
39293
- function getWindowOverlay() {
39294
- const path3 = configuredOverlayPath ?? defaultWindowOverlayPath();
39295
- if (loadedOverlayPath === path3 && loadedOverlay !== undefined) {
39296
- return loadedOverlay ?? undefined;
39297
- }
39298
- loadedOverlayPath = path3;
39299
- loadedOverlay = readWindowOverlayFile(path3) ?? null;
39300
- return loadedOverlay ?? undefined;
39301
- }
39302
- function resolveWindowOverlayFacts(providerID, modelID, overlay = getWindowOverlay()) {
39303
- if (!overlay)
39304
- return;
39305
- const modelRefs = modelRefLookupOrder(`${providerID}/${modelID}`);
39306
- const providerCandidates = new Set(modelRefs.map((ref) => ref.slice(0, ref.indexOf("/"))));
39307
- const modelCandidates = new Set([
39308
- modelID,
39309
- ...modelRefs.map((ref) => ref.slice(ref.indexOf("/") + 1))
39310
- ]);
39311
- const colon = modelID.lastIndexOf(":");
39312
- if (colon > 0)
39313
- modelCandidates.add(modelID.slice(0, colon));
39314
- const wildcardFacts = {};
39315
- const specificFacts = {};
39316
- for (const cell of overlay.cells) {
39317
- if (!providerCandidates.has(cell.provider_id))
39318
- continue;
39319
- if (cell.model_id === "*")
39320
- Object.assign(wildcardFacts, cell.facts);
39321
- else if (modelCandidates.has(cell.model_id))
39322
- Object.assign(specificFacts, cell.facts);
39323
- }
39324
- const facts = { ...wildcardFacts, ...specificFacts };
39325
- return Object.keys(facts).length > 0 ? { facts } : undefined;
39326
- }
39327
- function numericOverlayFact(overlay, key) {
39328
- const fact = overlay?.facts[key];
39329
- return fact ? scalarizeFact(fact.value) : undefined;
39330
- }
39331
- function overlayGeometry(overlay) {
39332
- const fact = overlay?.facts.geometry;
39333
- if (fact === undefined)
39334
- return;
39335
- if (fact.value.kind === "unknown")
39336
- return { kind: "unknown" };
39337
- if (fact.value.kind !== "stated")
39338
- return;
39339
- const value = fact.value.value;
39340
- return value === "shared_upfront" || value === "shared_truncating" || value === "separate" ? { kind: "stated", value } : undefined;
39341
- }
39342
- function placeholderFilteredOutput(output, context) {
39343
- if (!isFinitePositive(output))
39344
- return;
39345
- if (isFinitePositive(context) && output >= context)
39346
- return;
39347
- return output;
39348
- }
39349
- function mergePositive(overlayValue, providerValue) {
39350
- return isFinitePositive(providerValue) ? providerValue : overlayValue;
39351
- }
39352
- function logGeometryClampOnce(key, message, log2) {
39353
- if (geometryClampLogSeen.has(key))
39354
- return;
39355
- geometryClampLogSeen.add(key);
39356
- (log2 ?? ((entry) => sessionLog("global", `window-geometry: ${entry}`)))(message);
39357
- }
39358
- function deriveWindowGeometry(providerID, modelID, catalogLimit, options = {}) {
39359
- if (!catalogLimit && !options.providerLimit)
39360
- return;
39361
- const providerLimit = options.providerLimit;
39362
- const catalogContext = isFinitePositive(catalogLimit?.context) ? catalogLimit.context : undefined;
39363
- const advertised = numericOverlayFact(options.overlay, "window.advertised");
39364
- const enforced = numericOverlayFact(options.overlay, "window.enforced");
39365
- let softContext = mergePositive(enforced ?? advertised ?? catalogContext, providerLimit?.context);
39366
- let hardContext = mergePositive(enforced ?? softContext, providerLimit?.context);
39367
- if (isFinitePositive(options.contextCap)) {
39368
- softContext = isFinitePositive(softContext) ? Math.min(softContext, options.contextCap) : options.contextCap;
39369
- hardContext = isFinitePositive(hardContext) ? Math.min(hardContext, options.contextCap) : options.contextCap;
39370
- }
39371
- const input = mergePositive(isFinitePositive(catalogLimit?.input) ? catalogLimit.input : undefined, providerLimit?.input);
39372
- if (!isFinitePositive(softContext) && !isFinitePositive(input))
39373
- return;
39374
- const catalogOutput = options.overlay === undefined && options.providerLimit === undefined ? isFinitePositive(catalogLimit?.output) ? catalogLimit.output : undefined : placeholderFilteredOutput(catalogLimit?.output, softContext);
39375
- const overlayOutput = placeholderFilteredOutput(numericOverlayFact(options.overlay, "output.enforced") ?? numericOverlayFact(options.overlay, "output.default") ?? numericOverlayFact(options.overlay, "output.advertised"), softContext);
39376
- const providerOutput = placeholderFilteredOutput(providerLimit?.output, softContext);
39377
- const output = providerOutput ?? overlayOutput ?? catalogOutput;
39378
- const geometryFact = overlayGeometry(options.overlay);
39379
- const geometry = geometryFact?.kind === "stated" ? geometryFact.value : geometryFact?.kind === "unknown" ? "shared_upfront" : PROVIDER_GEOMETRY[providerID] ?? "shared_upfront";
39380
- const geometryOverride = geometryFact?.kind === "stated" ? geometryFact.value : undefined;
39381
- const preCarvedInput = isFinitePositive(input) && (!isFinitePositive(softContext) || input < softContext);
39382
- const outputReserveOverride = typeof options.outputReserveOverride === "number" && Number.isFinite(options.outputReserveOverride) && options.outputReserveOverride >= 0 ? options.outputReserveOverride : undefined;
39383
- let derivationWindow = softContext ?? input;
39384
- let usableSoft;
39385
- let softReserve = 0;
39386
- let reserveSource = "none";
39387
- if (outputReserveOverride !== undefined) {
39388
- const reserveWindow = preCarvedInput ? input : softContext ?? input;
39389
- if (!isFinitePositive(reserveWindow))
39390
- return;
39391
- derivationWindow = reserveWindow;
39392
- softReserve = outputReserveOverride;
39393
- reserveSource = "output_config";
39394
- const floor = Math.max(MIN_PLAUSIBLE_CONTEXT_LIMIT, reserveWindow * 0.5);
39395
- const flooredReserve = Math.min(softReserve, Math.max(0, reserveWindow - floor));
39396
- if (flooredReserve < softReserve) {
39397
- logGeometryClampOnce(`soft-floor|${providerID}/${modelID}|${softReserve}|${flooredReserve}`, `output reserve clamped by the half-window floor for ${providerID}/${modelID}: reserve ${softReserve} → ${flooredReserve}`, options.log);
39398
- }
39399
- softReserve = flooredReserve;
39400
- usableSoft = Math.floor(reserveWindow - softReserve);
39401
- } else if (preCarvedInput) {
39402
- usableSoft = input;
39403
- if (isFinitePositive(softContext)) {
39404
- softReserve = Math.max(0, softContext - input);
39405
- reserveSource = "output_catalog";
39406
- }
39407
- } else if (isFinitePositive(softContext)) {
39408
- if (geometry === "separate" && (options.overlay === undefined || options.harness === "pi" || geometryOverride !== undefined)) {
39409
- softReserve = 0;
39410
- reserveSource = "none";
39411
- } else {
39412
- softReserve = output ?? 0;
39413
- reserveSource = output === undefined ? "none" : "output_catalog";
39414
- const cap = softContext * OUTPUT_RESERVE_CAP_RATIO;
39415
- softReserve = Math.min(softReserve, options.harness === "pi" || options.overlay === undefined ? cap : Math.min(cap, OPENCODE_OUTPUT_CAP));
39416
- }
39417
- const floor = Math.max(MIN_PLAUSIBLE_CONTEXT_LIMIT, softContext * 0.5);
39418
- const flooredReserve = Math.min(softReserve, Math.max(0, softContext - floor));
39419
- if (flooredReserve < softReserve) {
39420
- logGeometryClampOnce(`soft-floor|${providerID}/${modelID}|${softReserve}|${flooredReserve}`, `output reserve clamped by the half-window floor for ${providerID}/${modelID}: reserve ${softReserve} → ${flooredReserve} (catalog context/output pair is contradictory)`, options.log);
39421
- }
39422
- softReserve = flooredReserve;
39423
- usableSoft = Math.floor(softContext - softReserve);
39424
- } else {
39425
- usableSoft = input;
39426
- }
39427
- const hardWindow = hardContext ?? softContext ?? input;
39428
- if (!isFinitePositive(hardWindow))
39429
- return;
39430
- let usableHard;
39431
- if (geometry === "separate") {
39432
- usableHard = hardWindow;
39433
- } else if (geometry === "shared_truncating") {
39434
- usableHard = hardWindow - PROMPT_WALL_MARGIN;
39435
- } else if (options.harness === "pi" && providerID !== "openai-codex") {
39436
- usableHard = hardWindow - PI_OUTPUT_FLOOR;
39437
- } else if (options.harness === "pi") {
39438
- usableHard = hardWindow - (output ?? OPENCODE_OUTPUT_CAP);
39439
- } else {
39440
- const requestedOutput = Math.min(output ?? OPENCODE_OUTPUT_CAP, OPENCODE_OUTPUT_CAP);
39441
- usableHard = hardWindow - requestedOutput;
39442
- }
39443
- usableHard = Math.max(MIN_PLAUSIBLE_CONTEXT_LIMIT, Math.floor(usableHard));
39444
- if (usableHard < usableSoft) {
39445
- logGeometryClampOnce(`${providerID}/${modelID}|${usableSoft}|${usableHard}`, `usable hard limit clamped for ${providerID}/${modelID}: ${usableHard} → ${usableSoft} (overlay/provider inversion)`, options.log);
39446
- usableHard = usableSoft;
39447
- }
39448
- const resolvedWindow = derivationWindow ?? usableSoft;
39449
- return {
39450
- usableSoft,
39451
- usableHard,
39452
- geometry,
39453
- derivation: {
39454
- window: Math.floor(resolvedWindow),
39455
- reserve: Math.floor(Math.max(0, resolvedWindow - usableSoft)),
39456
- reserveSource,
39457
- geometry
39458
- }
39459
- };
39460
- }
39461
- function formatWindowDerivationLine(inputTokens, result) {
39462
- const percentage = result.usableSoft > 0 ? inputTokens / result.usableSoft * 100 : 0;
39463
- const reserveLabel = result.derivation.reserveSource === "wall_margin" ? "wall margin" : result.derivation.reserveSource === "none" ? "reserve" : "output reserve";
39464
- return `Context: ${formatCompactTokens(inputTokens)} / ${formatCompactTokens(result.usableSoft)} usable (${percentage.toFixed(1)}%) — window ${formatCompactTokens(result.derivation.window)} − ${formatCompactTokens(result.derivation.reserve)} ${reserveLabel} [${result.geometry}]`;
39465
- }
39466
- function formatCompactTokens(value) {
39467
- if (Math.abs(value) >= 1e6) {
39468
- return `${(value / 1e6).toFixed(1).replace(/\.0$/, "")}m`;
39469
- }
39470
- if (Math.abs(value) >= 1000) {
39471
- return `${(value / 1000).toFixed(1).replace(/\.0$/, "")}k`;
39472
- }
39473
- return Math.round(value).toLocaleString();
39474
- }
39475
-
39476
- // ../plugin/src/shared/models-dev-cache.ts
39477
40100
  var MIN_SANE_LIMIT = 20000;
39478
40101
  var MAX_SANE_LIMIT = 3000000;
39479
40102
  function isSaneLimit(limit) {
@@ -40056,7 +40679,7 @@ function loadPiConfigDetailed(opts = {}) {
40056
40679
  import { statSync as statSync7 } from "node:fs";
40057
40680
 
40058
40681
  // ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
40059
- import { createHash as createHash8 } from "node:crypto";
40682
+ import { createHash as createHash9 } from "node:crypto";
40060
40683
 
40061
40684
  // ../plugin/src/features/magic-context/recursive-text-splitter.ts
40062
40685
  var DEFAULT_SEPARATORS = [`
@@ -40146,6 +40769,14 @@ function recursiveCharacterSplit(text, options) {
40146
40769
  // ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
40147
40770
  var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512;
40148
40771
  var CHUNK_WINDOW_SAFETY_RATIO = 0.9;
40772
+ var MESSAGE_FTS_CHUNK_LOAD_SQL = `SELECT map.message_ordinal AS messageOrdinal, fts.role, fts.content
40773
+ FROM message_fts_rowid_map AS map
40774
+ CROSS JOIN message_history_fts AS fts
40775
+ ON fts.rowid = map.fts_rowid
40776
+ WHERE map.session_id = ?
40777
+ AND map.message_ordinal BETWEEN ? AND ?
40778
+ AND fts.role IN ('user', 'assistant')
40779
+ ORDER BY map.message_ordinal ASC`;
40149
40780
  var loadFtsRowsStatements = new WeakMap;
40150
40781
  var existingHashStatements = new WeakMap;
40151
40782
  var existingHashByProjectStatements = new WeakMap;
@@ -40162,13 +40793,7 @@ var decodedSearchPoolBytes = 0;
40162
40793
  function getLoadFtsRowsStatement(db) {
40163
40794
  let stmt = loadFtsRowsStatements.get(db);
40164
40795
  if (!stmt) {
40165
- stmt = db.prepare(`SELECT message_ordinal AS messageOrdinal, role, content
40166
- FROM message_history_fts
40167
- WHERE session_id = ?
40168
- AND message_ordinal >= ?
40169
- AND message_ordinal <= ?
40170
- AND role IN ('user', 'assistant')
40171
- ORDER BY message_ordinal ASC`);
40796
+ stmt = db.prepare(MESSAGE_FTS_CHUNK_LOAD_SQL);
40172
40797
  loadFtsRowsStatements.set(db, stmt);
40173
40798
  }
40174
40799
  return stmt;
@@ -40341,7 +40966,7 @@ function parseCanonicalLineRange(line) {
40341
40966
  return { start, end };
40342
40967
  }
40343
40968
  function hashChunkText(text) {
40344
- return createHash8("sha256").update(text).digest("hex");
40969
+ return createHash9("sha256").update(text).digest("hex");
40345
40970
  }
40346
40971
  function vectorBlob2(vector) {
40347
40972
  return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
@@ -40356,6 +40981,8 @@ function toFloat32Array(blob) {
40356
40981
  function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal) {
40357
40982
  if (endOrdinal < startOrdinal)
40358
40983
  return "";
40984
+ if (!messageFtsOrdinalRangeIsMapped(db, sessionId, startOrdinal, endOrdinal))
40985
+ return null;
40359
40986
  const rows = getLoadFtsRowsStatement(db).all(sessionId, startOrdinal, endOrdinal).map((row) => row);
40360
40987
  const lines = [];
40361
40988
  let current = null;
@@ -40630,39 +41257,79 @@ function mapBackfillCandidateRows(rows) {
40630
41257
  title: row.title
40631
41258
  }));
40632
41259
  }
40633
- var sessionBackfillCandidateStatements = new WeakMap;
40634
- function loadUnembeddedSessionChunkCandidates(db, projectPath, sessionId, modelId, limit, excludeIds) {
40635
- if (excludeIds && excludeIds.length > 0) {
40636
- const placeholders3 = excludeIds.map(() => "?").join(", ");
40637
- const stmt2 = db.prepare(`SELECT c.id AS id,
40638
- c.session_id AS sessionId,
40639
- c.start_message AS startMessage,
40640
- c.end_message AS endMessage,
40641
- c.title AS title
40642
- FROM compartments c
40643
- JOIN session_projects sp
40644
- ON sp.session_id = c.session_id
40645
- AND sp.harness = c.harness
40646
- AND sp.project_path = ?
40647
- WHERE c.session_id = ?
40648
- AND c.start_message IS NOT NULL
40649
- AND c.end_message IS NOT NULL
40650
- AND c.id NOT IN (${placeholders3})
40651
- AND NOT EXISTS (
40652
- SELECT 1
40653
- FROM compartment_chunk_embeddings current
40654
- WHERE current.compartment_id = c.id
40655
- AND current.project_path = ?
40656
- AND current.model_id = ?
40657
- )
40658
- ORDER BY c.start_message ASC, c.id ASC
40659
- LIMIT ?`);
40660
- const rows2 = stmt2.all(projectPath, sessionId, ...excludeIds, projectPath, modelId, Math.max(1, limit));
40661
- return mapBackfillCandidateRows(rows2);
41260
+ function classifyChunkCoverageDefect(db, projectPath, modelId, candidate, maxInputTokens) {
41261
+ const mappedText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
41262
+ if (mappedText === null)
41263
+ return "deferred";
41264
+ const canonicalText = mappedText || buildCompartmentSummaryFallbackText(db, candidate.id);
41265
+ const windows = chunkCanonicalText(canonicalText, candidate.startMessage, candidate.endMessage, maxInputTokens);
41266
+ const existing = getExistingChunkHashes(db, candidate.id, modelId, projectPath);
41267
+ if (windows.some((window) => !existing.has(window.windowIndex)))
41268
+ return "missing";
41269
+ if (existing.size !== windows.length || windows.some((window) => existing.get(window.windowIndex) !== window.chunkHash)) {
41270
+ return "stale";
40662
41271
  }
40663
- let stmt = sessionBackfillCandidateStatements.get(db);
40664
- if (!stmt) {
40665
- stmt = db.prepare(`SELECT c.id AS id,
41272
+ return null;
41273
+ }
41274
+ function selectHashIncompleteChunkCandidates(db, projectPath, modelId, candidates, limit, maxInputTokens) {
41275
+ const missing = [];
41276
+ const stale = [];
41277
+ for (const candidate of candidates) {
41278
+ const defect = classifyChunkCoverageDefect(db, projectPath, modelId, candidate, maxInputTokens);
41279
+ if (defect === "missing")
41280
+ missing.push(candidate);
41281
+ else if (defect === "stale")
41282
+ stale.push(candidate);
41283
+ }
41284
+ return [...missing, ...stale].slice(0, limit);
41285
+ }
41286
+ var sessionBackfillCandidateStatements = new WeakMap;
41287
+ function loadUnembeddedSessionChunkCandidates(db, projectPath, sessionId, modelId, limit, excludeIds, maxInputTokens = DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS) {
41288
+ const exclusions = excludeIds && excludeIds.length > 0 ? excludeIds : [];
41289
+ const exclusionSql = exclusions.length > 0 ? `AND c.id NOT IN (${exclusions.map(() => "?").join(", ")})` : "";
41290
+ const stmt = exclusions.length > 0 ? db.prepare(`SELECT c.id AS id,
41291
+ c.session_id AS sessionId,
41292
+ c.start_message AS startMessage,
41293
+ c.end_message AS endMessage,
41294
+ c.title AS title
41295
+ FROM compartments c
41296
+ JOIN session_projects sp
41297
+ ON sp.session_id = c.session_id
41298
+ AND sp.harness = c.harness
41299
+ AND sp.project_path = ?
41300
+ WHERE c.session_id = ?
41301
+ AND c.start_message IS NOT NULL
41302
+ AND c.end_message IS NOT NULL
41303
+ ${exclusionSql}
41304
+ ORDER BY c.start_message ASC, c.id ASC`) : (() => {
41305
+ let cached2 = sessionBackfillCandidateStatements.get(db);
41306
+ if (!cached2) {
41307
+ cached2 = db.prepare(`SELECT c.id AS id,
41308
+ c.session_id AS sessionId,
41309
+ c.start_message AS startMessage,
41310
+ c.end_message AS endMessage,
41311
+ c.title AS title
41312
+ FROM compartments c
41313
+ JOIN session_projects sp
41314
+ ON sp.session_id = c.session_id
41315
+ AND sp.harness = c.harness
41316
+ AND sp.project_path = ?
41317
+ WHERE c.session_id = ?
41318
+ AND c.start_message IS NOT NULL
41319
+ AND c.end_message IS NOT NULL
41320
+ ORDER BY c.start_message ASC, c.id ASC`);
41321
+ sessionBackfillCandidateStatements.set(db, cached2);
41322
+ }
41323
+ return cached2;
41324
+ })();
41325
+ const rows = stmt.all(projectPath, sessionId, ...exclusions);
41326
+ return selectHashIncompleteChunkCandidates(db, projectPath, modelId, mapBackfillCandidateRows(rows), Math.max(1, limit), maxInputTokens);
41327
+ }
41328
+ function countUnembeddedSessionCompartments(db, projectPath, sessionId, modelId, maxInputTokens = DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS) {
41329
+ return loadUnembeddedSessionChunkCandidates(db, projectPath, sessionId, modelId, Number.MAX_SAFE_INTEGER, undefined, maxInputTokens).length;
41330
+ }
41331
+ function countSessionCompartmentEmbedCoverage(db, projectPath, sessionId, modelId, maxInputTokens = DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS) {
41332
+ const rows = db.prepare(`SELECT c.id AS id,
40666
41333
  c.session_id AS sessionId,
40667
41334
  c.start_message AS startMessage,
40668
41335
  c.end_message AS endMessage,
@@ -40675,60 +41342,15 @@ function loadUnembeddedSessionChunkCandidates(db, projectPath, sessionId, modelI
40675
41342
  WHERE c.session_id = ?
40676
41343
  AND c.start_message IS NOT NULL
40677
41344
  AND c.end_message IS NOT NULL
40678
- AND NOT EXISTS (
40679
- SELECT 1
40680
- FROM compartment_chunk_embeddings current
40681
- WHERE current.compartment_id = c.id
40682
- AND current.project_path = ?
40683
- AND current.model_id = ?
40684
- )
40685
- ORDER BY c.start_message ASC, c.id ASC
40686
- LIMIT ?`);
40687
- sessionBackfillCandidateStatements.set(db, stmt);
41345
+ ORDER BY c.start_message ASC, c.id ASC`).all(projectPath, sessionId);
41346
+ const candidates = mapBackfillCandidateRows(rows);
41347
+ let embedded = 0;
41348
+ for (const candidate of candidates) {
41349
+ if (classifyChunkCoverageDefect(db, projectPath, modelId, candidate, maxInputTokens) === null) {
41350
+ embedded += 1;
41351
+ }
40688
41352
  }
40689
- const rows = stmt.all(projectPath, sessionId, projectPath, modelId, Math.max(1, limit));
40690
- return mapBackfillCandidateRows(rows);
40691
- }
40692
- function countUnembeddedSessionCompartments(db, projectPath, sessionId, modelId) {
40693
- const row = db.prepare(`SELECT COUNT(*) AS n
40694
- FROM compartments c
40695
- JOIN session_projects sp
40696
- ON sp.session_id = c.session_id
40697
- AND sp.harness = c.harness
40698
- AND sp.project_path = ?
40699
- WHERE c.session_id = ?
40700
- AND c.start_message IS NOT NULL
40701
- AND c.end_message IS NOT NULL
40702
- AND NOT EXISTS (
40703
- SELECT 1
40704
- FROM compartment_chunk_embeddings current
40705
- WHERE current.compartment_id = c.id
40706
- AND current.project_path = ?
40707
- AND current.model_id = ?
40708
- )`).get(projectPath, sessionId, projectPath, modelId);
40709
- return typeof row?.n === "number" ? row.n : 0;
40710
- }
40711
- function countSessionCompartmentEmbedCoverage(db, projectPath, sessionId, modelId) {
40712
- const row = db.prepare(`SELECT
40713
- COUNT(*) AS total,
40714
- SUM(CASE WHEN EXISTS (
40715
- SELECT 1 FROM compartment_chunk_embeddings e
40716
- WHERE e.compartment_id = c.id
40717
- AND e.project_path = ?
40718
- AND e.model_id = ?
40719
- ) THEN 1 ELSE 0 END) AS embedded
40720
- FROM compartments c
40721
- JOIN session_projects sp
40722
- ON sp.session_id = c.session_id
40723
- AND sp.harness = c.harness
40724
- AND sp.project_path = ?
40725
- WHERE c.session_id = ?
40726
- AND c.start_message IS NOT NULL
40727
- AND c.end_message IS NOT NULL`).get(projectPath, modelId, projectPath, sessionId);
40728
- return {
40729
- total: typeof row?.total === "number" ? row.total : 0,
40730
- embedded: typeof row?.embedded === "number" ? row.embedded : 0
40731
- };
41353
+ return { embedded, total: candidates.length };
40732
41354
  }
40733
41355
 
40734
41356
  // ../plugin/src/features/magic-context/memory/cosine-similarity.ts
@@ -40749,7 +41371,7 @@ function cosineSimilarity(a, b) {
40749
41371
  }
40750
41372
 
40751
41373
  // ../plugin/src/features/magic-context/memory/embedding-synapse.ts
40752
- import { createHash as createHash9 } from "node:crypto";
41374
+ import { createHash as createHash10 } from "node:crypto";
40753
41375
 
40754
41376
  // ../../node_modules/.bun/@cortexkit+subc-client@0.4.1/node_modules/@cortexkit/subc-client/dist/client.js
40755
41377
  import { promises as fs2 } from "node:fs";
@@ -42101,21 +42723,28 @@ var SYNAPSE_DEFAULT_MODEL = "gte-modernbert-base-f16";
42101
42723
  var SYNAPSE_MAX_INPUT_TOKENS = 8192;
42102
42724
  var SYNAPSE_DEFAULT_QUERY_TIMEOUT_MS = 3000;
42103
42725
  var SYNAPSE_DEFAULT_BATCH_TIMEOUT_MS = 120000;
42726
+ var SYNAPSE_CERTIFICATION_REFUSAL_REASONS = new Set([
42727
+ "not_certified",
42728
+ "probe_required",
42729
+ "migration_required"
42730
+ ]);
42104
42731
 
42105
42732
  class SynapseEmbeddingError extends Error {
42106
42733
  code;
42107
42734
  retryAfterMs;
42108
42735
  permanent;
42736
+ refusalReason;
42109
42737
  constructor(code, message, options) {
42110
42738
  super(message, options?.cause === undefined ? undefined : { cause: options.cause });
42111
42739
  this.name = "SynapseEmbeddingError";
42112
42740
  this.code = code;
42113
42741
  this.permanent = options?.permanent ?? isPermanentSynapseCode(code);
42114
42742
  this.retryAfterMs = options?.retryAfterMs ?? (this.permanent ? undefined : 100);
42743
+ this.refusalReason = options?.refusalReason;
42115
42744
  }
42116
42745
  }
42117
42746
  function isPermanentSynapseCode(code) {
42118
- return code === "artifact_invalid" || code === "substitution_rejected" || code === "not_certified" || code === "probe_required" || code === "idempotency_conflict" || code === "schema_violation";
42747
+ return code === "artifact_invalid" || code === "substitution_rejected" || code === "not_certified" || code === "probe_required" || code === "idempotency_conflict" || code === "schema_violation" || code === "certification_refused" || code === "needs_reauth";
42119
42748
  }
42120
42749
  function asRecord(value) {
42121
42750
  return value !== null && typeof value === "object" ? value : null;
@@ -42141,11 +42770,21 @@ function readErrorCode(value) {
42141
42770
  }
42142
42771
  return;
42143
42772
  }
42773
+ function readCertificationRefusalReason(value) {
42774
+ if (!(value instanceof SubcCallError))
42775
+ return;
42776
+ const detail = value.detail;
42777
+ if (typeof detail === "string")
42778
+ return detail;
42779
+ const record2 = asRecord(detail);
42780
+ return typeof record2?.reason === "string" ? record2.reason : undefined;
42781
+ }
42144
42782
  function classifyError(value) {
42145
42783
  if (value instanceof SynapseEmbeddingError)
42146
42784
  return value;
42147
42785
  const code = readErrorCode(value) ?? (value instanceof Error ? value.name : "transport");
42148
42786
  const normalized = code.toLowerCase();
42787
+ const refusalReason = readCertificationRefusalReason(value);
42149
42788
  let mapped = "transport";
42150
42789
  if (normalized.includes("queue_full"))
42151
42790
  mapped = "queue_full";
@@ -42157,12 +42796,16 @@ function classifyError(value) {
42157
42796
  mapped = "artifact_invalid";
42158
42797
  else if (normalized.includes("substitution"))
42159
42798
  mapped = "substitution_rejected";
42799
+ else if (normalized === "certification_refused")
42800
+ mapped = "certification_refused";
42160
42801
  else if (normalized.includes("not_certified"))
42161
42802
  mapped = "not_certified";
42162
42803
  else if (normalized.includes("probe_required"))
42163
42804
  mapped = "probe_required";
42164
42805
  else if (normalized.includes("idempotency_conflict"))
42165
42806
  mapped = "idempotency_conflict";
42807
+ else if (normalized.includes("needs_reauth"))
42808
+ mapped = "needs_reauth";
42166
42809
  else if (normalized.includes("schema"))
42167
42810
  mapped = "schema_violation";
42168
42811
  else if (normalized.includes("module_restarted") || normalized.includes("module restarted"))
@@ -42170,14 +42813,46 @@ function classifyError(value) {
42170
42813
  const message = value instanceof Error ? value.message : String(value);
42171
42814
  return new SynapseEmbeddingError(mapped, message, {
42172
42815
  retryAfterMs: readRetryAfter(value) ?? (isPermanentSynapseCode(mapped) ? undefined : 100),
42173
- cause: value
42816
+ cause: value,
42817
+ refusalReason
42174
42818
  });
42175
42819
  }
42820
+ function embeddingFailureFor(error51) {
42821
+ const typedReason = error51.refusalReason;
42822
+ if (typedReason !== undefined && SYNAPSE_CERTIFICATION_REFUSAL_REASONS.has(typedReason) || error51.code === "not_certified" || error51.code === "probe_required") {
42823
+ return {
42824
+ class: "certification_refusal",
42825
+ reason: `SYNAPSE certification refused embedding: ${typedReason ?? error51.code}`,
42826
+ retryable: false
42827
+ };
42828
+ }
42829
+ if (error51.code === "certification_refused") {
42830
+ return {
42831
+ class: "certification_refusal",
42832
+ reason: `SYNAPSE certification refused embedding: ${typedReason ?? "unknown reason"}`,
42833
+ retryable: false
42834
+ };
42835
+ }
42836
+ if (typedReason === "needs_reauth" || typedReason === "needs_reauth_expired") {
42837
+ return {
42838
+ class: "credential_required",
42839
+ reason: "SYNAPSE requires reauthentication",
42840
+ retryable: false
42841
+ };
42842
+ }
42843
+ if (error51.code === "substitution_rejected") {
42844
+ return { class: "substitution_rejected", reason: error51.message, retryable: false };
42845
+ }
42846
+ if (error51.code === "schema_violation" || error51.code === "artifact_invalid") {
42847
+ return { class: "invalid_envelope", reason: error51.message, retryable: false };
42848
+ }
42849
+ return { class: "transport_error", reason: error51.message, retryable: !error51.permanent };
42850
+ }
42176
42851
  function wait(ms) {
42177
42852
  return new Promise((resolve5) => setTimeout(resolve5, ms));
42178
42853
  }
42179
42854
  function sha256(value) {
42180
- return createHash9("sha256").update(value).digest("hex");
42855
+ return createHash10("sha256").update(value).digest("hex");
42181
42856
  }
42182
42857
  function stableJson2(value) {
42183
42858
  if (Array.isArray(value))
@@ -42292,6 +42967,7 @@ class SynapseEmbeddingProvider {
42292
42967
  initialized = false;
42293
42968
  initializing = null;
42294
42969
  permanentFailure = false;
42970
+ lastFailureReason = null;
42295
42971
  batchLimit = 16;
42296
42972
  tokenBudget = null;
42297
42973
  constructor(options) {
@@ -42366,9 +43042,11 @@ class SynapseEmbeddingProvider {
42366
43042
  this.tokenBudget = metadata.recommended_token_budget ?? this.tokenBudget;
42367
43043
  }
42368
43044
  this.initialized = true;
43045
+ this.recordSuccess();
42369
43046
  return true;
42370
43047
  } catch (error51) {
42371
43048
  const classified = classifyError(error51);
43049
+ this.recordFailure(classified);
42372
43050
  if (classified.permanent) {
42373
43051
  this.permanentFailure = true;
42374
43052
  log(`[magic-context] Synapse lane disabled: ${classified.code}: ${classified.message}`);
@@ -42395,6 +43073,7 @@ class SynapseEmbeddingProvider {
42395
43073
  if (!extracted)
42396
43074
  throw new SynapseEmbeddingError("schema_violation", "Synapse query returned no vector");
42397
43075
  this.validateResponse(extracted.metadata, extracted.vector.length);
43076
+ this.recordSuccess();
42398
43077
  return extracted.vector;
42399
43078
  } catch (error51) {
42400
43079
  this.logCallFailure(error51, "embed.query");
@@ -42458,6 +43137,7 @@ class SynapseEmbeddingProvider {
42458
43137
  const vectorArray = Float32Array.from(vector);
42459
43138
  this.validateResponse({ ...batchEnvelope, ...item }, vectorArray.length);
42460
43139
  output.set(id, vectorArray);
43140
+ this.recordSuccess();
42461
43141
  }
42462
43142
  } catch (error51) {
42463
43143
  const classified = classifyError(error51);
@@ -42480,6 +43160,9 @@ class SynapseEmbeddingProvider {
42480
43160
  isLoaded() {
42481
43161
  return this.initialized;
42482
43162
  }
43163
+ getLastFailureReason() {
43164
+ return this.lastFailureReason;
43165
+ }
42483
43166
  requestConstraints(extra) {
42484
43167
  const metadata = this.metadata;
42485
43168
  if (!metadata)
@@ -42597,21 +43280,28 @@ class SynapseEmbeddingProvider {
42597
43280
  }
42598
43281
  logCallFailure(error51, operation) {
42599
43282
  const classified = classifyError(error51);
43283
+ this.recordFailure(classified);
42600
43284
  if (classified.permanent)
42601
43285
  this.permanentFailure = true;
42602
43286
  const suffix = classified.retryAfterMs === undefined ? "" : ` retry_after_ms=${classified.retryAfterMs}`;
42603
43287
  log(`[magic-context] Synapse ${operation} failed: ${classified.code}${suffix}: ${classified.message}`);
42604
43288
  }
43289
+ recordFailure(error51) {
43290
+ this.lastFailureReason = embeddingFailureFor(error51);
43291
+ }
43292
+ recordSuccess() {
43293
+ this.lastFailureReason = null;
43294
+ }
42605
43295
  }
42606
43296
 
42607
43297
  // ../plugin/src/features/magic-context/memory/normalize-hash.ts
42608
- import { createHash as createHash10 } from "node:crypto";
43298
+ import { createHash as createHash11 } from "node:crypto";
42609
43299
  function normalizeMemoryContent(content) {
42610
43300
  return content.toLowerCase().replace(/\s+/g, " ").trim();
42611
43301
  }
42612
43302
  function computeNormalizedHash(content) {
42613
43303
  const normalized = normalizeMemoryContent(content);
42614
- return createHash10("md5").update(normalized).digest("hex");
43304
+ return createHash11("md5").update(normalized).digest("hex");
42615
43305
  }
42616
43306
 
42617
43307
  // ../plugin/src/features/magic-context/memory/embedding-identity.ts
@@ -42655,6 +43345,131 @@ import { chmodSync as chmodSync2, mkdirSync as mkdirSync4 } from "node:fs";
42655
43345
  import { open, stat, unlink, writeFile } from "node:fs/promises";
42656
43346
  import { dirname as dirname7, join as join9 } from "node:path";
42657
43347
  import { pathToFileURL as pathToFileURL2 } from "node:url";
43348
+
43349
+ // ../plugin/src/features/magic-context/memory/embedding-failure.ts
43350
+ function errorMessage(error51) {
43351
+ return error51 instanceof Error ? error51.message : String(error51 ?? "unknown error");
43352
+ }
43353
+ function nestedMessages(error51) {
43354
+ const messages = [errorMessage(error51)];
43355
+ if (error51 && typeof error51 === "object" && "cause" in error51) {
43356
+ const cause = error51.cause;
43357
+ if (cause !== undefined)
43358
+ messages.push(...nestedMessages(cause));
43359
+ }
43360
+ return messages;
43361
+ }
43362
+ function safeErrorDetail(message) {
43363
+ return message.replace(/https?:\/\/[^\s"']+/gi, "<remote URL>").replace(/\/(?:Users|home)\/[^/\s]+/g, "~").replace(/\s+/g, " ").trim().slice(0, 240);
43364
+ }
43365
+ function hasAny(messages, patterns) {
43366
+ return messages.some((message) => {
43367
+ const lower = message.toLowerCase();
43368
+ return patterns.some((pattern) => lower.includes(pattern));
43369
+ });
43370
+ }
43371
+ function classifyLocalEmbeddingFailure(error51, context = {}) {
43372
+ const primaryMessages = nestedMessages(error51);
43373
+ const nativeMessages = context.nativeError === undefined ? [] : nestedMessages(context.nativeError);
43374
+ if (hasAny(primaryMessages, [
43375
+ "mc_embedding_fs_unavailable",
43376
+ "file system cache is not available"
43377
+ ]) || context.usesWasm && hasAny(primaryMessages, ["unable to get model file path or buffer"])) {
43378
+ return {
43379
+ class: "local_fs_unavailable",
43380
+ reason: "the WASM model cache cannot access the Node filesystem",
43381
+ retryable: false
43382
+ };
43383
+ }
43384
+ if (hasAny(primaryMessages, [
43385
+ "failed to fetch",
43386
+ "fetch failed",
43387
+ "network error",
43388
+ "enotfound",
43389
+ "econnreset",
43390
+ "econnrefused",
43391
+ "certificate",
43392
+ "unable to load file",
43393
+ "unauthorized access to file",
43394
+ "forbidden access to file",
43395
+ "not found at"
43396
+ ]) || primaryMessages.some((message) => /\bHTTP\s+[45]\d\d\b/i.test(message))) {
43397
+ return {
43398
+ class: "local_download_failure",
43399
+ reason: `the embedding model download failed: ${safeErrorDetail(primaryMessages[0])}`,
43400
+ retryable: true
43401
+ };
43402
+ }
43403
+ const bindingMessages = [...primaryMessages, ...nativeMessages];
43404
+ if (hasAny(bindingMessages, [
43405
+ "onnxruntime_binding.node",
43406
+ "cannot find package 'onnxruntime-node'",
43407
+ 'cannot find package "onnxruntime-node"',
43408
+ "cannot find module 'onnxruntime-node'",
43409
+ 'cannot find module "onnxruntime-node"',
43410
+ "could not resolve: onnxruntime-node"
43411
+ ])) {
43412
+ const platform = context.platform ?? process.platform;
43413
+ const arch = context.arch ?? process.arch;
43414
+ return {
43415
+ class: "local_binding_missing",
43416
+ reason: platform === "darwin" && arch === "x64" ? "onnxruntime-node has no darwin/x64 native binding and the WASM fallback could not complete" : `onnxruntime-node has no usable native binding for ${platform}/${arch} and the WASM fallback could not complete`,
43417
+ retryable: false
43418
+ };
43419
+ }
43420
+ return {
43421
+ class: "local_runtime_error",
43422
+ reason: `the local embedding runtime failed: ${safeErrorDetail(primaryMessages[0])}`,
43423
+ retryable: false
43424
+ };
43425
+ }
43426
+ function dominantEmbeddingFailure(failures) {
43427
+ const counts = new Map;
43428
+ for (const failure of failures) {
43429
+ const key = `${failure.class}\x00${failure.reason}`;
43430
+ const current = counts.get(key);
43431
+ if (current)
43432
+ current.count += 1;
43433
+ else
43434
+ counts.set(key, { failure, count: 1 });
43435
+ }
43436
+ let dominant;
43437
+ for (const candidate of counts.values()) {
43438
+ if (!dominant || candidate.count > dominant.count)
43439
+ dominant = candidate;
43440
+ }
43441
+ return dominant?.failure;
43442
+ }
43443
+
43444
+ // ../plugin/src/features/magic-context/memory/embedding-local.ts
43445
+ var BUN_NAPI_TEARDOWN_FIX_VERSION = [1, 4, 0];
43446
+ function currentLocalEmbeddingHost() {
43447
+ const bun = globalThis.Bun;
43448
+ const hasProcess = typeof process !== "undefined";
43449
+ const bunVersion = hasProcess && typeof process.versions?.bun === "string" ? process.versions.bun : undefined;
43450
+ return {
43451
+ isElectron: hasProcess && Boolean(process.versions?.electron),
43452
+ isBun: Boolean(bun) || Boolean(bunVersion),
43453
+ bunVersion,
43454
+ hasNodeFilesystem: hasProcess && (typeof process.versions?.node === "string" || typeof bunVersion === "string")
43455
+ };
43456
+ }
43457
+ function bunHasNapiTeardownFix(version2) {
43458
+ const match = version2?.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
43459
+ if (!match || match[4])
43460
+ return false;
43461
+ const parsed = [Number(match[1]), Number(match[2]), Number(match[3])];
43462
+ return parsed.some((part) => !Number.isSafeInteger(part)) ? false : parsed[0] > BUN_NAPI_TEARDOWN_FIX_VERSION[0] || parsed[0] === BUN_NAPI_TEARDOWN_FIX_VERSION[0] && (parsed[1] > BUN_NAPI_TEARDOWN_FIX_VERSION[1] || parsed[1] === BUN_NAPI_TEARDOWN_FIX_VERSION[1] && parsed[2] >= BUN_NAPI_TEARDOWN_FIX_VERSION[2]);
43463
+ }
43464
+ function resolveLocalEmbeddingRuntime(preference = "auto", host = currentLocalEmbeddingHost()) {
43465
+ if (preference === "native" || preference === "wasm")
43466
+ return preference;
43467
+ if (host.isElectron)
43468
+ return "electron";
43469
+ if (host.isBun && !bunHasNapiTeardownFix(host.bunVersion))
43470
+ return "wasm";
43471
+ return "native";
43472
+ }
42658
43473
  var LOCK_POLL_MS = 150;
42659
43474
  var STALE_LOCK_MS = 3 * 60000;
42660
43475
  var MAX_LOCK_WAIT_MS = 5 * 60000;
@@ -42707,23 +43522,29 @@ function startLockHeartbeat(lockPath) {
42707
43522
  return () => clearInterval(timer);
42708
43523
  }
42709
43524
  var localEmbeddingRuntimeMode = "native";
43525
+ var localEmbeddingProcessFailure = null;
42710
43526
  var wasmRuntimeInjected = false;
42711
- var isElectronForRuntime = () => typeof process !== "undefined" && Boolean(process.versions?.electron);
43527
+ var localEmbeddingHostForRuntime = currentLocalEmbeddingHost;
42712
43528
  var importWasmOrtForRuntime = async () => {
42713
- const ortWebSpec = `onnxruntime-${"web"}`;
42714
- return await import(ortWebSpec);
43529
+ const { createRequire: createRequireFn } = await import("node:module");
43530
+ const requireFn = createRequireFn(import.meta.url);
43531
+ const ortEntry = requireFn.resolve("onnxruntime-web");
43532
+ return {
43533
+ module: await import("onnxruntime-web"),
43534
+ entryPath: ortEntry
43535
+ };
42715
43536
  };
42716
43537
  var importTransformersForRuntime = async () => {
42717
- const transformersSpec = "@huggingface/transformers";
42718
- return await import(transformersSpec);
43538
+ return await import("./transformers.node-b1wa0hgx.js");
42719
43539
  };
42720
43540
  var importTransformersWasmFallbackForRuntime = async () => {
42721
- const { createRequire: createRequireFn } = await import("node:module");
42722
- const requireFn = createRequireFn(import.meta.url);
42723
- const nodeEntry = requireFn.resolve("@huggingface/transformers");
42724
- const webEntry = pathToFileURL2(join9(dirname7(nodeEntry), "transformers.web.js")).href;
43541
+ const webEntry = new URL("./transformers-web.js", import.meta.url).href;
42725
43542
  return await import(webEntry);
42726
43543
  };
43544
+ var importTransformersNodeWasmFallbackForRuntime = async () => {
43545
+ const nodeWasmEntry = new URL("./transformers-node-wasm.js", import.meta.url).href;
43546
+ return await import(nodeWasmEntry);
43547
+ };
42727
43548
  var modelCacheDirForRuntime = () => join9(getMagicContextStorageDir(), "models");
42728
43549
  var logForRuntime = log;
42729
43550
  var injectWasmOrtForRuntime = injectWasmOrt;
@@ -42739,17 +43560,9 @@ async function injectWasmOrt() {
42739
43560
  if (wasmRuntimeInjected)
42740
43561
  return true;
42741
43562
  try {
42742
- const ortWeb = await importWasmOrtForRuntime();
42743
- try {
42744
- const { createRequire: createRequireFn } = await import("node:module");
42745
- const requireFn = createRequireFn(import.meta.url);
42746
- const mainEntry = requireFn.resolve("onnxruntime-web");
42747
- const distDir = dirname7(mainEntry);
42748
- if (ortWeb.env?.wasm) {
42749
- ortWeb.env.wasm.wasmPaths = `${pathToFileURL2(distDir).href}/`;
42750
- }
42751
- } catch (pathError) {
42752
- log("[magic-context] could not resolve local onnxruntime-web/dist, falling back to default WASM paths:", pathError instanceof Error ? pathError.message : String(pathError));
43563
+ const { module: ortWeb, entryPath } = await importWasmOrtForRuntime();
43564
+ if (ortWeb.env?.wasm) {
43565
+ ortWeb.env.wasm.wasmPaths = `${pathToFileURL2(dirname7(entryPath)).href}/`;
42753
43566
  }
42754
43567
  globalThis[Symbol.for("onnxruntime")] = ortWeb;
42755
43568
  wasmRuntimeInjected = true;
@@ -42772,27 +43585,61 @@ function likelyMuslHint() {
42772
43585
  function localEmbeddingRuntimeIsDisabled() {
42773
43586
  return localEmbeddingRuntimeMode === "disabled";
42774
43587
  }
43588
+
43589
+ class LocalEmbeddingFallbackError extends Error {
43590
+ nativeError;
43591
+ constructor(nativeError, wasmError) {
43592
+ super("the native local embedding runtime and its WASM fallback both failed", {
43593
+ cause: wasmError
43594
+ });
43595
+ this.name = "LocalEmbeddingFallbackError";
43596
+ this.nativeError = nativeError;
43597
+ }
43598
+ }
43599
+
43600
+ class LocalEmbeddingFsUnavailableError extends Error {
43601
+ code = "MC_EMBEDDING_FS_UNAVAILABLE";
43602
+ constructor() {
43603
+ super("MC_EMBEDDING_FS_UNAVAILABLE: Node WASM bundle has no filesystem cache");
43604
+ this.name = "LocalEmbeddingFsUnavailableError";
43605
+ }
43606
+ }
43607
+ async function importWasmTransformersForHost() {
43608
+ const host = localEmbeddingHostForRuntime();
43609
+ if (host.isElectron) {
43610
+ return importTransformersForRuntime();
43611
+ }
43612
+ return host.hasNodeFilesystem ? importTransformersNodeWasmFallbackForRuntime() : importTransformersWasmFallbackForRuntime();
43613
+ }
42775
43614
  function disableLocalEmbeddingsAfterRuntimeFailure(detail) {
42776
43615
  localEmbeddingRuntimeMode = "disabled";
42777
- logForRuntime(`[magic-context] local embeddings are disabled because both the onnxruntime-node native binding and the onnxruntime-web (WASM) fallback failed to load. Native failure: ${detail}. Run \`npx @cortexkit/magic-context@latest doctor\` for repair guidance (use \`doctor --force\` to reinstall cached plugin packages), or configure an \`openai-compatible\` embedding HTTP endpoint. Existing memories are unaffected.`);
43616
+ logForRuntime(`[magic-context] local embeddings are disabled because both the onnxruntime-node native binding and the onnxruntime-web (WASM) fallback failed to load. Native failure: ${detail}. Run \`npx @cortexkit/magic-context@latest doctor\` for diagnostics; reinstalling repairs missing package files but cannot add a native binding that upstream does not ship. Alternatively, configure an \`openai-compatible\` embedding HTTP endpoint. Existing memories are unaffected.`);
42778
43617
  }
42779
- async function loadTransformersForLocalEmbedding() {
43618
+ async function loadTransformersForLocalEmbedding(runtimePreference) {
42780
43619
  if (localEmbeddingRuntimeMode === "disabled") {
42781
43620
  throw new Error("local embedding runtime is disabled");
42782
43621
  }
43622
+ const resolvedRuntime = resolveLocalEmbeddingRuntime(runtimePreference, localEmbeddingHostForRuntime());
43623
+ if (resolvedRuntime === "wasm") {
43624
+ if (!await ensureWasmOrtInjected()) {
43625
+ disableLocalEmbeddingsAfterRuntimeFailure("the selected WASM runtime is unavailable");
43626
+ throw new Error("onnxruntime-web failed to load");
43627
+ }
43628
+ return { module: await importWasmTransformersForHost(), usesWasm: true };
43629
+ }
42783
43630
  if (localEmbeddingRuntimeMode === "wasm") {
42784
43631
  if (!await ensureWasmOrtInjected()) {
42785
43632
  disableLocalEmbeddingsAfterRuntimeFailure("the previously selected WASM runtime is unavailable");
42786
43633
  throw new Error("onnxruntime-web failed to load");
42787
43634
  }
42788
43635
  try {
42789
- return { module: await importTransformersWasmFallbackForRuntime(), usesWasm: true };
43636
+ return { module: await importWasmTransformersForHost(), usesWasm: true };
42790
43637
  } catch (wasmError) {
42791
43638
  disableLocalEmbeddingsAfterRuntimeFailure("the previously selected WASM runtime failed to load");
42792
43639
  throw wasmError;
42793
43640
  }
42794
43641
  }
42795
- const electron = isElectronForRuntime();
43642
+ const electron = resolvedRuntime === "electron";
42796
43643
  if (electron) {
42797
43644
  const wasInjected = wasmRuntimeInjected;
42798
43645
  if (await ensureWasmOrtInjected()) {
@@ -42814,12 +43661,12 @@ async function loadTransformersForLocalEmbedding() {
42814
43661
  }
42815
43662
  localEmbeddingRuntimeMode = "wasm";
42816
43663
  try {
42817
- const module = await importTransformersWasmFallbackForRuntime();
43664
+ const module = await importWasmTransformersForHost();
42818
43665
  logForRuntime("[magic-context] onnxruntime-node failed to load; using onnxruntime-web (WASM) for local embeddings. WASM inference is slower than native; a remote `openai-compatible` provider may be faster." + likelyMuslHint());
42819
43666
  return { module, usesWasm: true };
42820
43667
  } catch (wasmError) {
42821
43668
  disableLocalEmbeddingsAfterRuntimeFailure(nativeError instanceof Error ? nativeError.message : String(nativeError));
42822
- throw wasmError;
43669
+ throw new LocalEmbeddingFallbackError(nativeError, wasmError);
42823
43670
  }
42824
43671
  }
42825
43672
  }
@@ -42848,6 +43695,8 @@ function isNativeRuntimeMissingError(error51) {
42848
43695
  if (code === "ERR_DLOPEN_FAILED" && lower.includes("onnxruntime")) {
42849
43696
  return true;
42850
43697
  }
43698
+ if (lower.includes('could not load the "sharp" module'))
43699
+ return true;
42851
43700
  const mentionsNativeRuntime = lower.includes("onnxruntime-node") || lower.includes("onnxruntime_binding");
42852
43701
  if (!mentionsNativeRuntime)
42853
43702
  return false;
@@ -42900,19 +43749,24 @@ class LocalEmbeddingProvider {
42900
43749
  maxInputTokens;
42901
43750
  model;
42902
43751
  dtype;
43752
+ runtimePreference;
42903
43753
  pipeline = null;
42904
43754
  initPromise = null;
43755
+ lastFailureReason = null;
43756
+ usesWasm = false;
42905
43757
  inFlight = 0;
42906
43758
  disposing = false;
42907
43759
  disposePromise = null;
42908
43760
  inFlightWaiters = [];
42909
- constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512, dtype = DEFAULT_LOCAL_DTYPE) {
43761
+ constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512, dtype = DEFAULT_LOCAL_DTYPE, runtimePreference = "auto") {
42910
43762
  this.model = model;
42911
43763
  this.maxInputTokens = maxInputTokens;
42912
43764
  this.dtype = dtype || DEFAULT_LOCAL_DTYPE;
43765
+ this.runtimePreference = runtimePreference;
42913
43766
  this.modelId = getEmbeddingProviderIdentity({
42914
43767
  provider: "local",
42915
43768
  model,
43769
+ local_runtime: runtimePreference,
42916
43770
  ...dtype && dtype !== DEFAULT_LOCAL_DTYPE ? { local_dtype: dtype } : {}
42917
43771
  });
42918
43772
  }
@@ -42924,6 +43778,7 @@ class LocalEmbeddingProvider {
42924
43778
  return true;
42925
43779
  }
42926
43780
  if (localEmbeddingRuntimeMode === "disabled") {
43781
+ this.lastFailureReason = localEmbeddingProcessFailure ?? classifyLocalEmbeddingFailure(new Error("local embedding runtime is disabled"));
42927
43782
  return false;
42928
43783
  }
42929
43784
  if (this.initPromise) {
@@ -42935,12 +43790,17 @@ class LocalEmbeddingProvider {
42935
43790
  if (this.disposing) {
42936
43791
  return;
42937
43792
  }
42938
- const { module: transformersModule, usesWasm } = await loadTransformersForLocalEmbedding();
43793
+ const { module: transformersModule, usesWasm } = await loadTransformersForLocalEmbedding(this.runtimePreference);
43794
+ this.usesWasm = usesWasm;
42939
43795
  const env = transformersModule.env;
42940
43796
  const LogLevel = transformersModule.LogLevel;
42941
43797
  if (LogLevel && "ERROR" in LogLevel) {
42942
43798
  env.logLevel = LogLevel.ERROR;
42943
43799
  }
43800
+ const host = localEmbeddingHostForRuntime();
43801
+ if (usesWasm && host.hasNodeFilesystem && !host.isElectron && (env.useFS !== true || env.useFSCache !== true)) {
43802
+ throw new LocalEmbeddingFsUnavailableError;
43803
+ }
42944
43804
  const modelCacheDir = modelCacheDirForRuntime();
42945
43805
  try {
42946
43806
  if (shouldEnforcePrivateStoragePermissions()) {
@@ -42989,6 +43849,8 @@ class LocalEmbeddingProvider {
42989
43849
  }
42990
43850
  }
42991
43851
  if (this.pipeline) {
43852
+ this.lastFailureReason = null;
43853
+ localEmbeddingProcessFailure = null;
42992
43854
  log(`[magic-context] embedding model loaded: ${this.model}`);
42993
43855
  } else if (this.disposing) {
42994
43856
  return;
@@ -43000,11 +43862,19 @@ class LocalEmbeddingProvider {
43000
43862
  await releaseLock();
43001
43863
  }
43002
43864
  } catch (error51) {
43865
+ const nativeError = error51 instanceof LocalEmbeddingFallbackError ? error51.nativeError : undefined;
43866
+ const failure = classifyLocalEmbeddingFailure(error51, {
43867
+ platform: process.platform,
43868
+ arch: process.arch,
43869
+ usesWasm: this.usesWasm,
43870
+ nativeError
43871
+ });
43872
+ this.lastFailureReason = failure;
43873
+ localEmbeddingProcessFailure = failure;
43003
43874
  if (!localEmbeddingRuntimeIsDisabled() && isNativeRuntimeMissingError(error51)) {
43004
43875
  disableLocalEmbeddingsAfterRuntimeFailure(error51 instanceof Error ? error51.message : String(error51));
43005
- } else if (!localEmbeddingRuntimeIsDisabled()) {
43006
- log("[magic-context] embedding model failed to load:", error51);
43007
43876
  }
43877
+ logForRuntime(`[magic-context] embedding model failed to load (${failure.class}: ${failure.reason}):`, error51);
43008
43878
  this.pipeline = null;
43009
43879
  } finally {
43010
43880
  this.initPromise = null;
@@ -43048,9 +43918,17 @@ class LocalEmbeddingProvider {
43048
43918
  pooling: "mean",
43049
43919
  normalize: true
43050
43920
  }));
43051
- return extractBatchEmbeddings(result, 1)[0] ?? null;
43921
+ const embedding = extractBatchEmbeddings(result, 1)[0] ?? null;
43922
+ if (!embedding) {
43923
+ this.lastFailureReason = classifyLocalEmbeddingFailure(new Error("local embedding pipeline returned no vector"), { usesWasm: this.usesWasm });
43924
+ } else {
43925
+ this.lastFailureReason = null;
43926
+ }
43927
+ return embedding;
43052
43928
  } catch (error51) {
43053
- log("[magic-context] embedding failed:", error51);
43929
+ const failure = classifyLocalEmbeddingFailure(error51, { usesWasm: this.usesWasm });
43930
+ this.lastFailureReason = failure;
43931
+ logForRuntime(`[magic-context] embedding failed (${failure.class}: ${failure.reason}):`, error51);
43054
43932
  return null;
43055
43933
  } finally {
43056
43934
  this.finishInFlight();
@@ -43079,9 +43957,17 @@ class LocalEmbeddingProvider {
43079
43957
  pooling: "mean",
43080
43958
  normalize: true
43081
43959
  }));
43082
- return extractBatchEmbeddings(result, texts.length);
43960
+ const embeddings = extractBatchEmbeddings(result, texts.length);
43961
+ if (embeddings.every((embedding) => embedding === null)) {
43962
+ this.lastFailureReason = classifyLocalEmbeddingFailure(new Error("local embedding pipeline returned no vectors"), { usesWasm: this.usesWasm });
43963
+ } else {
43964
+ this.lastFailureReason = null;
43965
+ }
43966
+ return embeddings;
43083
43967
  } catch (error51) {
43084
- log("[magic-context] embedding batch failed:", error51);
43968
+ const failure = classifyLocalEmbeddingFailure(error51, { usesWasm: this.usesWasm });
43969
+ this.lastFailureReason = failure;
43970
+ logForRuntime(`[magic-context] embedding batch failed (${failure.class}: ${failure.reason}):`, error51);
43085
43971
  return Array.from({ length: texts.length }, () => null);
43086
43972
  } finally {
43087
43973
  this.finishInFlight();
@@ -43114,6 +44000,9 @@ class LocalEmbeddingProvider {
43114
44000
  isLoaded() {
43115
44001
  return this.pipeline !== null;
43116
44002
  }
44003
+ getLastFailureReason() {
44004
+ return this.lastFailureReason;
44005
+ }
43117
44006
  }
43118
44007
 
43119
44008
  // ../plugin/src/features/magic-context/memory/embedding-ssrf.ts
@@ -43482,7 +44371,7 @@ class OpenAICompatibleEmbeddingProvider {
43482
44371
  }
43483
44372
 
43484
44373
  // ../plugin/src/features/magic-context/project-embedding-registry.ts
43485
- import { createHash as createHash11, randomUUID as randomUUID2 } from "node:crypto";
44374
+ import { createHash as createHash12, randomUUID as randomUUID2 } from "node:crypto";
43486
44375
 
43487
44376
  // ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
43488
44377
  var saveStatements = new WeakMap;
@@ -43934,25 +44823,6 @@ function invalidateMemory(projectPath, memoryId) {
43934
44823
  }
43935
44824
  }
43936
44825
 
43937
- // ../plugin/src/features/magic-context/memory/embedding-failure.ts
43938
- function dominantEmbeddingFailure(failures) {
43939
- const counts = new Map;
43940
- for (const failure of failures) {
43941
- const key = `${failure.class}\x00${failure.reason}`;
43942
- const current = counts.get(key);
43943
- if (current)
43944
- current.count += 1;
43945
- else
43946
- counts.set(key, { failure, count: 1 });
43947
- }
43948
- let dominant;
43949
- for (const candidate of counts.values()) {
43950
- if (!dominant || candidate.count > dominant.count)
43951
- dominant = candidate;
43952
- }
43953
- return dominant?.failure;
43954
- }
43955
-
43956
44826
  // ../plugin/src/features/magic-context/session-project-storage.ts
43957
44827
  var SESSION_CHUNK_REPAIR_BATCH_SIZE = 100;
43958
44828
  var upsertSessionProjectStatements = new WeakMap;
@@ -44108,6 +44978,7 @@ function resolveEmbeddingConfig(config2) {
44108
44978
  return {
44109
44979
  provider: "local",
44110
44980
  model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
44981
+ local_runtime: config2?.local_runtime ?? "auto",
44111
44982
  ...config2?.max_input_tokens ? {
44112
44983
  max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
44113
44984
  } : {},
@@ -44173,7 +45044,7 @@ function createProvider(config2, context) {
44173
45044
  });
44174
45045
  }
44175
45046
  if (config2.provider === "local") {
44176
- return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens, config2.local_dtype);
45047
+ return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens, config2.local_dtype, config2.local_runtime);
44177
45048
  }
44178
45049
  if (config2.provider === "synapse") {
44179
45050
  const synapse = config2;
@@ -44202,10 +45073,10 @@ function stableStringify2(value) {
44202
45073
  return JSON.stringify(value);
44203
45074
  }
44204
45075
  function sha256Prefix(value, length = 16) {
44205
- return createHash11("sha256").update(value).digest("hex").slice(0, length);
45076
+ return createHash12("sha256").update(value).digest("hex").slice(0, length);
44206
45077
  }
44207
45078
  function contentSha256(value) {
44208
- return createHash11("sha256").update(value).digest("hex");
45079
+ return createHash12("sha256").update(value).digest("hex");
44209
45080
  }
44210
45081
  function getRuntimeFingerprint(config2) {
44211
45082
  if (config2.provider === "off") {
@@ -44584,15 +45455,25 @@ function shadowBackfillMissingBase(scope, primaryModelId, shadowModelId, project
44584
45455
  };
44585
45456
  }
44586
45457
  return {
44587
- sql: `SELECT DISTINCT cp.compartment_id AS id
45458
+ sql: `SELECT cp.compartment_id AS id,
45459
+ MIN(CASE WHEN NOT EXISTS (
45460
+ SELECT 1 FROM compartment_chunk_embeddings same_key
45461
+ WHERE same_key.compartment_id = cp.compartment_id
45462
+ AND same_key.window_index = cp.window_index
45463
+ AND same_key.model_id = ?
45464
+ ) THEN 0 ELSE 1 END) AS defect_order
44588
45465
  FROM compartment_chunk_embeddings cp
44589
45466
  WHERE cp.project_path = ? AND cp.model_id = ?
44590
45467
  AND NOT EXISTS (
44591
- SELECT 1 FROM compartment_chunk_embeddings cs
44592
- WHERE cs.compartment_id = cp.compartment_id AND cs.model_id = ?
44593
- )`,
44594
- params: [projectIdentity, primaryModelId, shadowModelId],
44595
- orderBy: " ORDER BY cp.compartment_id"
45468
+ SELECT 1 FROM compartment_chunk_embeddings current
45469
+ WHERE current.compartment_id = cp.compartment_id
45470
+ AND current.window_index = cp.window_index
45471
+ AND current.chunk_hash = cp.chunk_hash
45472
+ AND current.model_id = ?
45473
+ )
45474
+ GROUP BY cp.compartment_id`,
45475
+ params: [shadowModelId, projectIdentity, primaryModelId, shadowModelId],
45476
+ orderBy: " ORDER BY defect_order ASC, cp.compartment_id ASC"
44596
45477
  };
44597
45478
  }
44598
45479
  function shadowBackfillMissingIds(db, projectIdentity, scope, primaryModelId, shadowModelId, limit) {
@@ -44736,13 +45617,17 @@ async function processShadowQueueItem(item) {
44736
45617
  const placeholders3 = boundedIds.map(() => "?").join(",");
44737
45618
  const candidates = db.prepare(`SELECT id, session_id, start_message, end_message
44738
45619
  FROM compartments WHERE id IN (${placeholders3})`).all(...boundedIds.map((id) => Number(id)));
44739
- const prepared = candidates.flatMap((candidate) => {
44740
- const text = buildCanonicalChunkTextFromFts(db, candidate.session_id, candidate.start_message, candidate.end_message) || buildCompartmentSummaryFallbackText(db, candidate.id);
44741
- if (!text)
44742
- return [];
44743
- const windows = chunkCanonicalText(text, candidate.start_message, candidate.end_message, SYNAPSE_MAX_INPUT_TOKENS);
44744
- return windows.length > 0 ? [{ candidate, windows }] : [];
44745
- });
45620
+ const prepared = [];
45621
+ for (const candidate of candidates) {
45622
+ const mappedText = buildCanonicalChunkTextFromFts(db, candidate.session_id, candidate.start_message, candidate.end_message);
45623
+ if (mappedText !== null) {
45624
+ const text = mappedText || buildCompartmentSummaryFallbackText(db, candidate.id);
45625
+ const windows = chunkCanonicalText(text, candidate.start_message, candidate.end_message, SYNAPSE_MAX_INPUT_TOKENS);
45626
+ if (windows.length > 0)
45627
+ prepared.push({ candidate, windows });
45628
+ }
45629
+ await new Promise((resolve5) => setTimeout(resolve5, 0));
45630
+ }
44746
45631
  const items = prepared.flatMap((item2) => item2.windows.map((window) => ({
44747
45632
  id: `chunk:${item2.candidate.id}:${window.windowIndex}`,
44748
45633
  text: window.text,
@@ -45087,7 +45972,11 @@ async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates
45087
45972
  const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
45088
45973
  const prepared = [];
45089
45974
  for (const candidate of candidates) {
45090
- const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage) || buildCompartmentSummaryFallbackText(db, candidate.id);
45975
+ await new Promise((resolve5) => setTimeout(resolve5, 0));
45976
+ const mappedText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
45977
+ if (mappedText === null)
45978
+ continue;
45979
+ const canonicalText = mappedText || buildCompartmentSummaryFallbackText(db, candidate.id);
45091
45980
  if (canonicalText.length === 0) {
45092
45981
  noWork.push(candidate.id);
45093
45982
  continue;
@@ -45186,7 +46075,8 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
45186
46075
  return { status: "disabled", embedded: 0, total: 0 };
45187
46076
  }
45188
46077
  recordSessionProjectIdentity(db, sessionId, projectIdentity);
45189
- const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId);
46078
+ const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
46079
+ const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId, maxInputTokens);
45190
46080
  if (total === 0)
45191
46081
  return { status: "nothing", embedded: 0, total: 0 };
45192
46082
  const holderId = `session-embed-${randomUUID2()}`;
@@ -45224,7 +46114,7 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
45224
46114
  aborted2 = true;
45225
46115
  break;
45226
46116
  }
45227
- const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, [...skipIds, ...failedIds]);
46117
+ const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, [...skipIds, ...failedIds], maxInputTokens);
45228
46118
  if (candidates.length === 0)
45229
46119
  break;
45230
46120
  const {
@@ -45269,7 +46159,7 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
45269
46159
  if (aborted2)
45270
46160
  return { status: "aborted", embedded, total, failed: failedIds.length };
45271
46161
  if (providerDown || failedIds.length > 0) {
45272
- const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId) - skipIds.length);
46162
+ const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId, maxInputTokens) - skipIds.length);
45273
46163
  if (remaining > 0) {
45274
46164
  return {
45275
46165
  status: "stalled",
@@ -45295,7 +46185,7 @@ function getEmbeddingCoverageStatus(db, projectIdentity, sessionId) {
45295
46185
  commits: { embedded: 0, total: 0, gitEnabled: false }
45296
46186
  };
45297
46187
  }
45298
- const session = countSessionCompartmentEmbedCoverage(db, projectIdentity, sessionId, snapshot.chunkModelId);
46188
+ const session = countSessionCompartmentEmbedCoverage(db, projectIdentity, sessionId, snapshot.chunkModelId, getProjectEmbeddingMaxInputTokens(projectIdentity));
45299
46189
  const memories = getMemoryEmbedCoverage(db, projectIdentity, snapshot.modelId);
45300
46190
  const gitEnabled = snapshot.gitCommitEnabled;
45301
46191
  const commits = gitEnabled ? {
@@ -45316,7 +46206,8 @@ function getEmbeddingCoverageStatus(db, projectIdentity, sessionId) {
45316
46206
  // ../plugin/src/features/magic-context/memory/embedding.ts
45317
46207
  var DEFAULT_EMBEDDING_CONFIG = {
45318
46208
  provider: "local",
45319
- model: DEFAULT_LOCAL_EMBEDDING_MODEL
46209
+ model: DEFAULT_LOCAL_EMBEDDING_MODEL,
46210
+ local_runtime: "auto"
45320
46211
  };
45321
46212
  var embeddingConfig = DEFAULT_EMBEDDING_CONFIG;
45322
46213
  var provider = null;
@@ -45336,7 +46227,7 @@ function createProvider2(config2) {
45336
46227
  });
45337
46228
  }
45338
46229
  if (config2.provider === "local") {
45339
- return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens, config2.local_dtype);
46230
+ return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens, config2.local_dtype, config2.local_runtime);
45340
46231
  }
45341
46232
  if (config2.provider === "synapse") {
45342
46233
  const synapse = config2;
@@ -45376,7 +46267,7 @@ async function embedText(text, signal) {
45376
46267
  }
45377
46268
 
45378
46269
  // ../plugin/src/plugin/embedding-bootstrap-helpers.ts
45379
- import { createHash as createHash12 } from "node:crypto";
46270
+ import { createHash as createHash13 } from "node:crypto";
45380
46271
  var EMBEDDING_AFFECTING_KEYS = new Set([
45381
46272
  "embedding.api_key",
45382
46273
  "embedding.endpoint",
@@ -45422,7 +46313,7 @@ var EMBEDDING_WARNING_TERMS = [
45422
46313
  ];
45423
46314
  var loggedFailureSignatures = new Map;
45424
46315
  function sha256Prefix2(value, length = 16) {
45425
- return createHash12("sha256").update(value).digest("hex").slice(0, length);
46316
+ return createHash13("sha256").update(value).digest("hex").slice(0, length);
45426
46317
  }
45427
46318
  function warningLooksEmbeddingRelated(message) {
45428
46319
  const lower = message.toLowerCase();
@@ -45561,10 +46452,6 @@ var STATUS_COLOR = {
45561
46452
  completed: "success",
45562
46453
  cancelled: "error"
45563
46454
  };
45564
- var SPIN_FRAMES = ["◐", "◓", "◑", "◒"];
45565
- function spinGlyph() {
45566
- return SPIN_FRAMES[Math.floor(Date.now() / 160) % SPIN_FRAMES.length];
45567
- }
45568
46455
  var snapshotsBySession = new Map;
45569
46456
  var MAX_TODOWRITE_RENDER_CACHE_ENTRIES = 50;
45570
46457
  var cachedTodowriteTodosByToolCallId = new Map;
@@ -45705,7 +46592,7 @@ function formatCounts(counts) {
45705
46592
  return parts.join(" · ");
45706
46593
  }
45707
46594
  function formatTodoLine(todo, theme, options = {}) {
45708
- const glyph = theme.fg(STATUS_COLOR[todo.status], todo.status === "in_progress" ? spinGlyph() : STATUS_GLYPH[todo.status]);
46595
+ const glyph = theme.fg(STATUS_COLOR[todo.status], STATUS_GLYPH[todo.status]);
45709
46596
  const id = options.showId && todo.id ? `${theme.fg("accent", `#${todo.id}`)} ` : "";
45710
46597
  const color = todo.status === "pending" || todo.status === "in_progress" ? "text" : "dim";
45711
46598
  let content = theme.fg(color, todo.content);
@@ -45724,9 +46611,6 @@ function lineComponent(renderLines) {
45724
46611
  invalidate() {}
45725
46612
  };
45726
46613
  }
45727
- function hasAnimatedRow(rows) {
45728
- return capTodoRows(rows).visible.some(({ todo }) => todo.status === "in_progress");
45729
- }
45730
46614
  function capTodoRows(rows) {
45731
46615
  if (rows.length <= MAX_TODO_CONTENT_ROWS) {
45732
46616
  return { visible: [...rows], hiddenCount: 0 };
@@ -45815,20 +46699,6 @@ function isOverlayLive(todo) {
45815
46699
  }
45816
46700
 
45817
46701
  class TodoOverlay {
45818
- spinTimer;
45819
- syncSpinTimer(hasInProgress) {
45820
- if (hasInProgress && this.widgetRegistered) {
45821
- if (this.spinTimer)
45822
- return;
45823
- this.spinTimer = setInterval(() => {
45824
- this.tui?.requestRender();
45825
- }, 160);
45826
- this.spinTimer.unref?.();
45827
- } else if (this.spinTimer) {
45828
- clearInterval(this.spinTimer);
45829
- this.spinTimer = undefined;
45830
- }
45831
- }
45832
46702
  uiCtx;
45833
46703
  sessionId;
45834
46704
  widgetRegistered = false;
@@ -45856,10 +46726,6 @@ class TodoOverlay {
45856
46726
  this.uiCtx.setWidget(WIDGET_KEY, undefined);
45857
46727
  this.widgetRegistered = false;
45858
46728
  this.tui = undefined;
45859
- if (this.spinTimer) {
45860
- clearInterval(this.spinTimer);
45861
- this.spinTimer = undefined;
45862
- }
45863
46729
  }
45864
46730
  return;
45865
46731
  }
@@ -45871,17 +46737,11 @@ class TodoOverlay {
45871
46737
  invalidate: () => {
45872
46738
  this.widgetRegistered = false;
45873
46739
  this.tui = undefined;
45874
- if (this.spinTimer) {
45875
- clearInterval(this.spinTimer);
45876
- this.spinTimer = undefined;
45877
- }
45878
46740
  }
45879
46741
  };
45880
46742
  }, { placement: "aboveEditor" });
45881
46743
  this.widgetRegistered = true;
45882
- this.syncSpinTimer(hasAnimatedRow(visible));
45883
46744
  } else {
45884
- this.syncSpinTimer(hasAnimatedRow(visible));
45885
46745
  this.tui?.requestRender();
45886
46746
  }
45887
46747
  }
@@ -45905,10 +46765,6 @@ class TodoOverlay {
45905
46765
  this.dispose();
45906
46766
  }
45907
46767
  dispose() {
45908
- if (this.spinTimer) {
45909
- clearInterval(this.spinTimer);
45910
- this.spinTimer = undefined;
45911
- }
45912
46768
  if (this.uiCtx)
45913
46769
  this.uiCtx.setWidget(WIDGET_KEY, undefined);
45914
46770
  this.widgetRegistered = false;
@@ -50586,6 +51442,87 @@ function createCtxExpandTool(deps) {
50586
51442
  }
50587
51443
  };
50588
51444
  }
51445
+
51446
+ // ../plugin/src/features/magic-context/dreamer/memory-claim-safety.ts
51447
+ var POLICY_SENTENCE_START = /(?:^|[.!?]\s+|\n\s*)(?:[-*]\s+|\d+[.)]\s+)?(?:you\s+|we\s+)?(?:must(?:\s+not)?|never|always|do\s+not|don't|shall\s+not)\b/i;
51448
+ var ACTOR_POLICY = /\b(?:you|we|agents?|masons?|workers?|operators?|users?|maintainers?)\s+(?:must(?:\s+not)?|should(?:\s+not)?|need\s+to|shall(?:\s+not)?|cannot|can't|may\s+not)\b/i;
51449
+ var BEHAVIORAL_WHEN_CLAUSE = /\bwhen\s+(?:you(?:'re|\s+are)?|we(?:'re|\s+are)?|told|asked|requested|working|debugging|reviewing|checking|verifying|investigating|using|running|editing|changing)\b/i;
51450
+ var WORKFLOW_IMPERATIVE = /(?:^|[.!?]\s+|\n\s*)(?:[-*]\s+|\d+[.)]\s+)?(?:please\s+)?(?:run|use|check|ask|avoid|prefer|ensure|keep|follow|brief|report|inspect|search|open|read|review|validate|confirm|delegate|stop|start|remember)\b/i;
51451
+ var DECISION_AUTHORITY = /\b(?:the\s+)?(?:user|operator|maintainer|owner)\s+(?:decides|chooses|approves|has\s+(?:the\s+)?final\s+say)\b/i;
51452
+ function isDirectiveShapedProjectRule(category, content) {
51453
+ if (category !== "PROJECT_RULES")
51454
+ return false;
51455
+ const text = content.trim();
51456
+ if (!text)
51457
+ return false;
51458
+ return POLICY_SENTENCE_START.test(text) || ACTOR_POLICY.test(text) || BEHAVIORAL_WHEN_CLAUSE.test(text) || WORKFLOW_IMPERATIVE.test(text) || DECISION_AUTHORITY.test(text);
51459
+ }
51460
+
51461
+ // ../plugin/src/features/magic-context/dreamer/curate-memory-safety.ts
51462
+ var PROJECT_SCOPED_CATEGORIES = new Set([
51463
+ "PROJECT_RULES",
51464
+ "ARCHITECTURE",
51465
+ "CONSTRAINTS",
51466
+ "CONFIG_VALUES",
51467
+ "NAMING"
51468
+ ]);
51469
+ var USER_PROFILE_REFERENCE = /\buser(?:[\s_-]+)(?:profile|preferences?)\b|\bU\d+\b/i;
51470
+ var refusalCountsBySession = new Map;
51471
+ function isSurvivingConsolidationTarget(memory2, successor, projectIdentity) {
51472
+ return successor !== null && successor.id !== memory2.id && successor.status === "active" && successor.supersededByMemoryId === null && (successor.expiresAt === null || successor.expiresAt > Date.now()) && projectIdentity(successor) === projectIdentity(memory2) && successor.category === memory2.category;
51473
+ }
51474
+ function assessCurateMutationSafety(args) {
51475
+ const { memory: memory2, successor, verdict } = args;
51476
+ if (verdict === "archive") {
51477
+ if (!isSurvivingConsolidationTarget(memory2, successor, args.projectIdentity)) {
51478
+ return {
51479
+ memoryId: memory2.id,
51480
+ verdict,
51481
+ reason: "missing-active-same-category-successor"
51482
+ };
51483
+ }
51484
+ if (PROJECT_SCOPED_CATEGORIES.has(memory2.category) && USER_PROFILE_REFERENCE.test(args.reason ?? "")) {
51485
+ return {
51486
+ memoryId: memory2.id,
51487
+ verdict,
51488
+ reason: "user-profile-is-not-project-memory"
51489
+ };
51490
+ }
51491
+ }
51492
+ if (isDirectiveShapedProjectRule(memory2.category, memory2.content)) {
51493
+ return {
51494
+ memoryId: memory2.id,
51495
+ verdict,
51496
+ reason: "directive-shaped-project-rule"
51497
+ };
51498
+ }
51499
+ if (verdict === "update") {
51500
+ const originalChars = memory2.content.trim().length;
51501
+ const replacementChars = args.replacementContent?.trim().length ?? 0;
51502
+ if (replacementChars * 2 < originalChars && !isSurvivingConsolidationTarget(memory2, successor, args.projectIdentity)) {
51503
+ return {
51504
+ memoryId: memory2.id,
51505
+ verdict,
51506
+ reason: "content-loss",
51507
+ originalChars,
51508
+ replacementChars
51509
+ };
51510
+ }
51511
+ }
51512
+ return null;
51513
+ }
51514
+ function recordCurateSafetyRefusal(sessionId, refusal) {
51515
+ const count = (refusalCountsBySession.get(sessionId) ?? 0) + 1;
51516
+ refusalCountsBySession.set(sessionId, count);
51517
+ const lengths = refusal.originalChars === undefined ? "" : ` original_chars=${refusal.originalChars} replacement_chars=${refusal.replacementChars ?? 0}`;
51518
+ log(`[dreamer] curate safety refusal: session_id=${sessionId} memory_id=${refusal.memoryId} verdict=${refusal.verdict} reason=${refusal.reason}${lengths} refused=${count}`);
51519
+ return count;
51520
+ }
51521
+ function takeCurateSafetyRefusalCount(sessionId) {
51522
+ const count = refusalCountsBySession.get(sessionId) ?? 0;
51523
+ refusalCountsBySession.delete(sessionId);
51524
+ return count;
51525
+ }
50589
51526
  // ../plugin/src/features/magic-context/memory/embedding-backfill.ts
50590
51527
  async function ensureMemoryEmbeddings(args) {
50591
51528
  const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
@@ -50627,9 +51564,9 @@ async function ensureMemoryEmbeddings(args) {
50627
51564
  return args.existingEmbeddings;
50628
51565
  }
50629
51566
  // ../plugin/src/features/magic-context/mural/storage-mural-cues.ts
50630
- import { createHash as createHash13 } from "node:crypto";
51567
+ import { createHash as createHash14 } from "node:crypto";
50631
51568
  function computeCueContentHash(content) {
50632
- return createHash13("sha256").update(content).digest("hex");
51569
+ return createHash14("sha256").update(content).digest("hex");
50633
51570
  }
50634
51571
  var muralCueColumnCache = new WeakMap;
50635
51572
  var muralCueRejectionColumnCache = new WeakMap;
@@ -51898,7 +52835,7 @@ var ALL_ACTIONS = [
51898
52835
  ];
51899
52836
  var DREAMER_ONLY_ACTIONS = new Set(["list"]);
51900
52837
  var GET_MAX_IDS = 20;
51901
- var ParamsSchema2 = exports_typebox.Object({
52838
+ var ParamsShape = {
51902
52839
  action: exports_typebox.Optional(exports_typebox.Union(ALL_ACTIONS.map((a) => exports_typebox.Literal(a)), {
51903
52840
  description: "What to do: write, update, archive, merge, get, or list"
51904
52841
  })),
@@ -51917,6 +52854,15 @@ var ParamsSchema2 = exports_typebox.Object({
51917
52854
  reason: exports_typebox.Optional(exports_typebox.String({
51918
52855
  description: "Why the memory is being archived (optional, recommended)"
51919
52856
  }))
52857
+ };
52858
+ var PrimaryParamsSchema = exports_typebox.Object(ParamsShape, {
52859
+ additionalProperties: true
52860
+ });
52861
+ var DreamerParamsSchema = exports_typebox.Object({
52862
+ ...ParamsShape,
52863
+ superseded_by: exports_typebox.Optional(exports_typebox.Number({
52864
+ description: "Active same-project/category memory that survives a curate consolidation"
52865
+ }))
51920
52866
  }, { additionalProperties: true });
51921
52867
  function ok2(text) {
51922
52868
  return { content: [{ type: "text", text }], details: undefined };
@@ -52042,7 +52988,7 @@ function createCtxMemoryTool(deps) {
52042
52988
  name: "ctx_memory",
52043
52989
  label: "Magic Context: Memory",
52044
52990
  description,
52045
- parameters: ParamsSchema2,
52991
+ parameters: dreamerAllowed ? DreamerParamsSchema : PrimaryParamsSchema,
52046
52992
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
52047
52993
  params = unwrapImitatedReducedArgs(params, ["action"], {
52048
52994
  action: { type: "enum", values: ALL_ACTIONS },
@@ -52050,7 +52996,8 @@ function createCtxMemoryTool(deps) {
52050
52996
  category: { type: "enum", values: V2_MEMORY_CATEGORIES },
52051
52997
  ids: { type: "array", items: "number", maxItems: 100 },
52052
52998
  limit: "number",
52053
- reason: "string"
52999
+ reason: "string",
53000
+ superseded_by: "number"
52054
53001
  });
52055
53002
  if (params.action === undefined) {
52056
53003
  return err2("Error: Action 'undefined' is not allowed in this context.");
@@ -52086,6 +53033,44 @@ function createCtxMemoryTool(deps) {
52086
53033
  return err2("Cross-session memory is disabled for this project.");
52087
53034
  }
52088
53035
  const sessionId = ctx.sessionManager.getSessionId();
53036
+ let curateSuccessor = null;
53037
+ if (dreamerAllowed && (params.action === "archive" || params.action === "update")) {
53038
+ const verdict = params.action;
53039
+ const ids = params.ids;
53040
+ const content = params.content?.trim();
53041
+ const validShape = ids && ids.length > 0 && ids.every(Number.isInteger) && (verdict !== "update" || ids.length === 1 && Boolean(content));
53042
+ if (validShape) {
53043
+ const uniqueIds = [...new Set(ids)];
53044
+ const memories = uniqueIds.map((id) => getMemoryById(deps.db, id));
53045
+ if (memories.every((memory2) => memory2 && memoryVisibleToTool(memory2))) {
53046
+ curateSuccessor = Number.isInteger(params.superseded_by) ? getMemoryById(deps.db, params.superseded_by) : null;
53047
+ const refusals = memories.flatMap((memory2) => {
53048
+ if (!memory2)
53049
+ return [];
53050
+ const refusal = assessCurateMutationSafety({
53051
+ memory: memory2,
53052
+ verdict,
53053
+ reason: params.reason,
53054
+ replacementContent: content,
53055
+ successor: curateSuccessor,
53056
+ projectIdentity: (candidate) => targetIdentityForStoredPath(candidate.projectPath)
53057
+ });
53058
+ return refusal ? [refusal] : [];
53059
+ });
53060
+ if (refusals.length > 0) {
53061
+ let refused = 0;
53062
+ for (const refusal of refusals) {
53063
+ refused = recordCurateSafetyRefusal(sessionId, refusal);
53064
+ }
53065
+ const memoryIds = refusals.map((refusal) => refusal.memoryId).join(", ");
53066
+ const reasons = [
53067
+ ...new Set(refusals.map((refusal) => refusal.reason))
53068
+ ].join(",");
53069
+ return ok2(`Skipped ${verdict} for memory [ID: ${memoryIds}]: curate safety refusal (${reasons}); refused=${refused}.`);
53070
+ }
53071
+ }
53072
+ }
53073
+ }
52089
53074
  if (params.action === "write") {
52090
53075
  const content = params.content?.trim();
52091
53076
  if (!content)
@@ -52313,11 +53298,21 @@ function createCtxMemoryTool(deps) {
52313
53298
  runImmediateTransaction(deps.db, () => {
52314
53299
  for (const target2 of targets) {
52315
53300
  archiveMemory(deps.db, target2.memoryId, params.reason);
52316
- queueMemoryMutation(deps.db, {
52317
- projectPath: target2.projectIdentity,
52318
- mutationType: "archive",
52319
- targetMemoryId: target2.memoryId
52320
- });
53301
+ if (dreamerAllowed && curateSuccessor) {
53302
+ supersededMemory(deps.db, target2.memoryId, curateSuccessor.id);
53303
+ queueMemoryMutation(deps.db, {
53304
+ projectPath: target2.projectIdentity,
53305
+ mutationType: "superseded",
53306
+ targetMemoryId: target2.memoryId,
53307
+ supersededById: curateSuccessor.id
53308
+ });
53309
+ } else {
53310
+ queueMemoryMutation(deps.db, {
53311
+ projectPath: target2.projectIdentity,
53312
+ mutationType: "archive",
53313
+ targetMemoryId: target2.memoryId
53314
+ });
53315
+ }
52321
53316
  }
52322
53317
  });
52323
53318
  const reasonSuffix = params.reason ? ` (${params.reason})` : "";
@@ -52902,7 +53897,7 @@ var FILTER_VALUES = [
52902
53897
  "dismissed",
52903
53898
  "all"
52904
53899
  ];
52905
- var ParamsSchema3 = exports_typebox.Object({
53900
+ var ParamsSchema2 = exports_typebox.Object({
52906
53901
  action: exports_typebox.Optional(exports_typebox.Union([
52907
53902
  exports_typebox.Literal("write"),
52908
53903
  exports_typebox.Literal("read"),
@@ -52979,7 +53974,7 @@ function createCtxNoteTool(deps) {
52979
53974
  name: "ctx_note",
52980
53975
  label: "Magic Context: Notes",
52981
53976
  description: CTX_NOTE_DESCRIPTION,
52982
- parameters: ParamsSchema3,
53977
+ parameters: ParamsSchema2,
52983
53978
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
52984
53979
  params = unwrapImitatedReducedArgs(params, ["action", "content"], {
52985
53980
  action: {
@@ -53259,7 +54254,7 @@ Keep: user messages, unresolved errors, raw evidence you haven't extracted yet,
53259
54254
  Never blanket-mark large ranges (e.g. "1-50") — review what each tag holds first.`;
53260
54255
 
53261
54256
  // src/tools/ctx-reduce.ts
53262
- var ParamsSchema4 = exports_typebox.Object({
54257
+ var ParamsSchema3 = exports_typebox.Object({
53263
54258
  drop: exports_typebox.Optional(exports_typebox.String({
53264
54259
  description: "Tag IDs to drop entirely. Ranges: '3-5', '1,2,9'"
53265
54260
  }))
@@ -53282,7 +54277,7 @@ function createCtxReduceTool(deps) {
53282
54277
  name: "ctx_reduce",
53283
54278
  label: "Magic Context: Reduce",
53284
54279
  description: CTX_REDUCE_DESCRIPTION,
53285
- parameters: ParamsSchema4,
54280
+ parameters: ParamsSchema3,
53286
54281
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
53287
54282
  params = unwrapImitatedReducedArgs(params, ["drop"], { drop: "string" });
53288
54283
  const sessionId = ctx.sessionManager.getSessionId();
@@ -53307,11 +54302,16 @@ function createCtxReduceTool(deps) {
53307
54302
  const protectedTagIds = activeTags.map((tag) => tag.tagNumber).sort((left, right) => right - left).slice(0, protectedTags);
53308
54303
  const protectedSet = new Set(protectedTagIds);
53309
54304
  const tagStatusMap = new Map(allTags.map((tag) => [tag.tagNumber, tag.status]));
54305
+ const inertWhitespaceTagNumbers = new Set(getInertWhitespaceAssistantTags(deps.db, sessionId).map((tag) => tag.tagNumber));
54306
+ const inertDropIds = [
54307
+ ...new Set(dropIds.filter((id) => inertWhitespaceTagNumbers.has(id)))
54308
+ ];
54309
+ const inertNote = inertDropIds.length > 0 ? `Skipped: ${inertDropIds.map((id) => `§${id}§ is provider framing, nothing to reclaim`).join("; ")}.` : "";
53310
54310
  const pendingOps = getPendingOps(deps.db, sessionId);
53311
54311
  const pendingMap = new Map(pendingOps.map((op) => [op.tagId, op.operation]));
53312
54312
  const conflicts = [];
53313
54313
  for (const id of dropIds) {
53314
- if (tagStatusMap.get(id) === "compacted") {
54314
+ if (tagStatusMap.get(id) === "compacted" && !inertWhitespaceTagNumbers.has(id)) {
53315
54315
  conflicts.push(`§${id}§ is from before compaction`);
53316
54316
  }
53317
54317
  }
@@ -53319,10 +54319,13 @@ function createCtxReduceTool(deps) {
53319
54319
  return err4(`Error: Conflicting operations — ${conflicts.join("; ")}.`);
53320
54320
  }
53321
54321
  const preFilterDropCount = dropIds.length;
53322
- dropIds = dropIds.filter((id) => tagStatusMap.get(id) !== "dropped" && pendingMap.get(id) !== "drop");
54322
+ dropIds = dropIds.filter((id) => !inertWhitespaceTagNumbers.has(id) && tagStatusMap.get(id) !== "dropped" && pendingMap.get(id) !== "drop");
53323
54323
  const skippedCount = preFilterDropCount - dropIds.length;
53324
54324
  if (dropIds.length === 0) {
53325
- return ok4("All requested tags were already queued or processed. No new action is needed.");
54325
+ return ok4([
54326
+ inertNote,
54327
+ "All requested tags were already queued or processed. No new action is needed."
54328
+ ].filter(Boolean).join(" "));
53326
54329
  }
53327
54330
  try {
53328
54331
  deps.db.transaction(() => {
@@ -53348,7 +54351,7 @@ function createCtxReduceTool(deps) {
53348
54351
  parts.push(`drop ${formatIds(immediateDropIds)}`);
53349
54352
  if (deferredDropIds.length > 0)
53350
54353
  parts.push(`deferred drop ${formatIds(deferredDropIds)}`);
53351
- return ok4(`Queued: ${parts.join(", ")}.${skippedNote}`);
54354
+ return ok4(`Queued: ${parts.join(", ")}.${skippedNote}${inertNote ? ` ${inertNote}` : ""}`);
53352
54355
  }
53353
54356
  };
53354
54357
  }
@@ -53749,7 +54752,7 @@ function containsProbeVerbatim(text, probes) {
53749
54752
  }
53750
54753
 
53751
54754
  // ../plugin/src/features/magic-context/search-measurement.ts
53752
- import { createHash as createHash14 } from "node:crypto";
54755
+ import { createHash as createHash15 } from "node:crypto";
53753
54756
  function resultId(result) {
53754
54757
  switch (result.source) {
53755
54758
  case "memory":
@@ -53836,7 +54839,7 @@ async function recordShadowMeasurement(args) {
53836
54839
  }
53837
54840
  }
53838
54841
  function sha2562(value) {
53839
- return createHash14("sha256").update(value).digest("hex");
54842
+ return createHash15("sha256").update(value).digest("hex");
53840
54843
  }
53841
54844
 
53842
54845
  // ../plugin/src/features/magic-context/search.ts
@@ -53852,8 +54855,16 @@ var GIT_COMMIT_SOURCE_BOOST = 1.2;
53852
54855
  var PRIMER_SOURCE_BOOST = 1.25;
53853
54856
  var messageSearchStatements = new WeakMap;
53854
54857
  var messageSearchStatementsWithCutoff = new WeakMap;
54858
+ var messageSearchDiagnosticStatements = new WeakMap;
53855
54859
  var batchedMessageSearchStatements = new WeakMap;
53856
54860
  var batchedFtsCountStatements = new WeakMap;
54861
+ function createUnifiedSearchDiagnostics() {
54862
+ return {
54863
+ suppressedVisibleMemoryIds: [],
54864
+ suppressedLiveMessageMatches: 0,
54865
+ gitCommitUnavailable: null
54866
+ };
54867
+ }
53857
54868
  function normalizeLimit2(limit) {
53858
54869
  if (typeof limit !== "number" || !Number.isFinite(limit)) {
53859
54870
  return DEFAULT_UNIFIED_SEARCH_LIMIT;
@@ -53944,6 +54955,51 @@ function getMessageSearchStatementWithCutoff(db) {
53944
54955
  }
53945
54956
  return stmt;
53946
54957
  }
54958
+ function getMessageSearchDiagnosticStatement(db) {
54959
+ let stmt = messageSearchDiagnosticStatements.get(db);
54960
+ if (!stmt) {
54961
+ stmt = db.prepare(`
54962
+ WITH matches AS MATERIALIZED (
54963
+ SELECT
54964
+ message_ordinal AS messageOrdinal,
54965
+ message_id AS messageId,
54966
+ role,
54967
+ content,
54968
+ CAST(message_ordinal AS INTEGER) AS ordinalValue,
54969
+ bm25(message_history_fts) AS ftsRank
54970
+ FROM message_history_fts
54971
+ WHERE session_id = ? AND message_history_fts MATCH ?
54972
+ ),
54973
+ eligible AS (
54974
+ SELECT * FROM matches
54975
+ WHERE ordinalValue <= ?
54976
+ ORDER BY ftsRank, ordinalValue ASC
54977
+ LIMIT ?
54978
+ ),
54979
+ summary AS (
54980
+ SELECT COUNT(*) AS suppressedCount
54981
+ FROM matches
54982
+ WHERE ordinalValue > ?
54983
+ )
54984
+ SELECT
54985
+ eligible.messageOrdinal,
54986
+ eligible.messageId,
54987
+ eligible.role,
54988
+ eligible.content,
54989
+ eligible.ftsRank,
54990
+ summary.suppressedCount,
54991
+ 0 AS summaryOnly
54992
+ FROM eligible CROSS JOIN summary
54993
+ UNION ALL
54994
+ SELECT NULL, NULL, NULL, NULL, NULL, summary.suppressedCount, 1
54995
+ FROM summary
54996
+ WHERE NOT EXISTS (SELECT 1 FROM eligible)
54997
+ ORDER BY summaryOnly ASC, ftsRank ASC, messageOrdinal ASC
54998
+ `);
54999
+ messageSearchDiagnosticStatements.set(db, stmt);
55000
+ }
55001
+ return stmt;
55002
+ }
53947
55003
  function getBatchedFtsCountStatement(db, queryCount, cutoff) {
53948
55004
  let statements = batchedFtsCountStatements.get(db);
53949
55005
  if (!statements) {
@@ -54084,10 +55140,8 @@ function mergeMemoryResults(args) {
54084
55140
  const memoryById = new Map(args.memories.map((memory2) => [memory2.id, memory2]));
54085
55141
  const candidateIds = new Set([...args.semanticScores.keys(), ...args.ftsScores.keys()]);
54086
55142
  const results = [];
55143
+ const suppressedVisibleIds = [];
54087
55144
  for (const id of candidateIds) {
54088
- if (args.visibleMemoryIds?.has(id)) {
54089
- continue;
54090
- }
54091
55145
  const memory2 = memoryById.get(id);
54092
55146
  if (!memory2) {
54093
55147
  continue;
@@ -54109,6 +55163,10 @@ function mergeMemoryResults(args) {
54109
55163
  if (score <= 0) {
54110
55164
  continue;
54111
55165
  }
55166
+ if (args.visibleMemoryIds?.has(id)) {
55167
+ suppressedVisibleIds.push(id);
55168
+ continue;
55169
+ }
54112
55170
  results.push({
54113
55171
  source: "memory",
54114
55172
  content: previewText(memory2.content),
@@ -54119,20 +55177,23 @@ function mergeMemoryResults(args) {
54119
55177
  sourceName: args.sourceNameByMemoryId?.get(memory2.id)
54120
55178
  });
54121
55179
  }
54122
- return results.sort((left, right) => {
54123
- if (right.score !== left.score) {
54124
- return right.score - left.score;
54125
- }
54126
- return left.memoryId - right.memoryId;
54127
- }).slice(0, args.limit);
55180
+ return {
55181
+ results: results.sort((left, right) => {
55182
+ if (right.score !== left.score) {
55183
+ return right.score - left.score;
55184
+ }
55185
+ return left.memoryId - right.memoryId;
55186
+ }).slice(0, args.limit),
55187
+ suppressedVisibleIds: suppressedVisibleIds.sort((left, right) => left - right)
55188
+ };
54128
55189
  }
54129
55190
  async function searchMemories(args) {
54130
55191
  if (!args.memoryEnabled) {
54131
- return [];
55192
+ return { results: [], suppressedVisibleIds: [] };
54132
55193
  }
54133
55194
  const memories = args.workspace?.isWorkspaced ? getMemoriesByProjects(args.db, args.workspace.expandedIdentities, ["active", "permanent"], Date.now(), args.workspace.ownIdentities, args.workspace.shareCategories) : getMemoriesByProject(args.db, args.projectPath);
54134
55195
  if (memories.length === 0) {
54135
- return [];
55196
+ return { results: [], suppressedVisibleIds: [] };
54136
55197
  }
54137
55198
  const ftsMatches = getFtsMatches({
54138
55199
  db: args.db,
@@ -54209,6 +55270,21 @@ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
54209
55270
  }
54210
55271
  return result;
54211
55272
  }
55273
+ function runMessageFtsQueryWithDiagnostics(args) {
55274
+ if (args.ftsQuery.length === 0)
55275
+ return { rows: [], suppressedCount: 0 };
55276
+ const rawRows = getMessageSearchDiagnosticStatement(args.db).all(args.sessionId, args.ftsQuery, args.cutoff, args.fetchLimit, args.cutoff).map((row) => row);
55277
+ const suppressedCount = rawRows[0]?.suppressedCount ?? 0;
55278
+ const rows = [];
55279
+ for (const row of rawRows) {
55280
+ if (row.summaryOnly === 1)
55281
+ continue;
55282
+ const normalized = normalizeMessageSearchRow(row, args.cutoff);
55283
+ if (normalized)
55284
+ rows.push(normalized);
55285
+ }
55286
+ return { rows, suppressedCount };
55287
+ }
54212
55288
  function getBatchedMessageSearchStatement(db, queryCount, cutoff) {
54213
55289
  let statements = batchedMessageSearchStatements.get(db);
54214
55290
  if (!statements) {
@@ -54275,7 +55351,20 @@ function searchMessages(args) {
54275
55351
  const baseQuery = sanitizeFtsQuery(args.query.trim());
54276
55352
  const probes = args.probes ?? [];
54277
55353
  if (probes.length === 0) {
54278
- const filtered = runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff).slice(0, args.limit);
55354
+ const outcome = args.diagnostics && cutoff !== null ? runMessageFtsQueryWithDiagnostics({
55355
+ db: args.db,
55356
+ sessionId: args.sessionId,
55357
+ ftsQuery: baseQuery,
55358
+ fetchLimit,
55359
+ cutoff
55360
+ }) : {
55361
+ rows: runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff),
55362
+ suppressedCount: 0
55363
+ };
55364
+ if (args.diagnostics) {
55365
+ args.diagnostics.suppressedLiveMessageMatches = outcome.suppressedCount;
55366
+ }
55367
+ const filtered = outcome.rows.slice(0, args.limit);
54279
55368
  return filtered.map((row, rank) => ({
54280
55369
  source: "message",
54281
55370
  content: previewText(row.content),
@@ -54288,8 +55377,19 @@ function searchMessages(args) {
54288
55377
  const sanitizedProbes = probes.map((probe) => ({ probe, query: sanitizeFtsQuery(probe) })).filter((entry) => entry.query.length > 0);
54289
55378
  const corpusSize = getIndexedMessageCorpusSize(args.db, args.sessionId, cutoff);
54290
55379
  const probeCounts = countSessionFtsMatchesBatch(args.db, args.sessionId, sanitizedProbes.map((entry) => entry.query), cutoff);
55380
+ const collectBaseDiagnostics = args.diagnostics !== undefined && cutoff !== null;
55381
+ const baseOutcome = collectBaseDiagnostics && baseQuery.length > 0 ? runMessageFtsQueryWithDiagnostics({
55382
+ db: args.db,
55383
+ sessionId: args.sessionId,
55384
+ ftsQuery: baseQuery,
55385
+ fetchLimit,
55386
+ cutoff
55387
+ }) : null;
55388
+ if (args.diagnostics) {
55389
+ args.diagnostics.suppressedLiveMessageMatches = baseOutcome?.suppressedCount ?? 0;
55390
+ }
54291
55391
  const searchQueries = [
54292
- ...baseQuery.length > 0 ? [baseQuery] : [],
55392
+ ...!collectBaseDiagnostics && baseQuery.length > 0 ? [baseQuery] : [],
54293
55393
  ...sanitizedProbes.map((entry) => entry.query)
54294
55394
  ];
54295
55395
  const rowsByQuery = runMessageFtsQueriesBatch(args.db, args.sessionId, searchQueries, fetchLimit, cutoff);
@@ -54297,10 +55397,11 @@ function searchMessages(args) {
54297
55397
  let queryIndex = 0;
54298
55398
  if (baseQuery.length > 0) {
54299
55399
  queryLists.push({
54300
- rows: rowsByQuery[queryIndex] ?? [],
55400
+ rows: baseOutcome?.rows ?? rowsByQuery[queryIndex] ?? [],
54301
55401
  weight: 1
54302
55402
  });
54303
- queryIndex += 1;
55403
+ if (!collectBaseDiagnostics)
55404
+ queryIndex += 1;
54304
55405
  }
54305
55406
  const probeWeights = new Map;
54306
55407
  sanitizedProbes.forEach((entry, probeIndex) => {
@@ -54687,6 +55788,9 @@ function memoriesToIdLookupResults(args) {
54687
55788
  }));
54688
55789
  }
54689
55790
  function resolveMemoriesByIdsForSearch(args) {
55791
+ if (args.diagnostics) {
55792
+ args.diagnostics.suppressedVisibleMemoryIds = [];
55793
+ }
54690
55794
  if (args.ids.length === 0) {
54691
55795
  return null;
54692
55796
  }
@@ -54697,16 +55801,22 @@ function resolveMemoriesByIdsForSearch(args) {
54697
55801
  }
54698
55802
  const memoriesById = new Map(fetched.map((memory2) => [memory2.id, memory2]));
54699
55803
  const ordered = [];
55804
+ const suppressedVisibleIds = new Set;
54700
55805
  for (const id of args.ids) {
54701
55806
  const memory2 = memoriesById.get(id);
54702
55807
  if (!memory2)
54703
55808
  continue;
54704
- if (args.visibleMemoryIds?.has(id))
55809
+ if (args.visibleMemoryIds?.has(id)) {
55810
+ suppressedVisibleIds.add(id);
54705
55811
  continue;
55812
+ }
54706
55813
  ordered.push(memory2);
54707
55814
  if (ordered.length >= args.limit)
54708
55815
  break;
54709
55816
  }
55817
+ if (args.diagnostics) {
55818
+ args.diagnostics.suppressedVisibleMemoryIds = [...suppressedVisibleIds].sort((left, right) => left - right);
55819
+ }
54710
55820
  if (ordered.length === 0) {
54711
55821
  return null;
54712
55822
  }
@@ -54728,6 +55838,11 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
54728
55838
  }
54729
55839
  const limit = normalizeLimit2(options.limit);
54730
55840
  const tierLimit = Math.max(limit * 3, DEFAULT_UNIFIED_SEARCH_LIMIT);
55841
+ if (options.diagnostics) {
55842
+ options.diagnostics.suppressedVisibleMemoryIds = [];
55843
+ options.diagnostics.suppressedLiveMessageMatches = 0;
55844
+ options.diagnostics.gitCommitUnavailable = null;
55845
+ }
54731
55846
  const embeddingEnabled = options.embeddingEnabled ?? true;
54732
55847
  const embedQuery = options.embedQuery ?? embedText;
54733
55848
  const isEmbeddingRuntimeEnabled = options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled;
@@ -54737,6 +55852,9 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
54737
55852
  const runMemory = activeSources.has("memory") && memoryFeatureEnabled;
54738
55853
  const runMessages = activeSources.has("message");
54739
55854
  const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
55855
+ if (options.diagnostics && activeSources.has("git_commit") && options.gitRepositoryAvailable === false) {
55856
+ options.diagnostics.gitCommitUnavailable = "no_git_repository";
55857
+ }
54740
55858
  const runPrimers = activeSources.has("primer") && memoryFeatureEnabled;
54741
55859
  const runNotes = activeSources.has("note");
54742
55860
  const runCompartmentChunks = runMessages && memoryFeatureEnabled && embeddingEnabled;
@@ -54753,7 +55871,8 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
54753
55871
  query: trimmedQuery,
54754
55872
  limit: tierLimit,
54755
55873
  maxOrdinal: options.maxMessageOrdinal,
54756
- probes: messageProbes
55874
+ probes: messageProbes,
55875
+ diagnostics: options.diagnostics
54757
55876
  }) : [];
54758
55877
  const capturedQuery = await queryEmbeddingPromise;
54759
55878
  const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
@@ -54777,7 +55896,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
54777
55896
  compartments: compartmentResults,
54778
55897
  limit: tierLimit
54779
55898
  });
54780
- const [memoryResults, gitCommitResults, primerResults, noteResults] = await Promise.all([
55899
+ const [memoryOutcome, gitCommitResults, primerResults, noteResults] = await Promise.all([
54781
55900
  runMemory ? searchMemories({
54782
55901
  db,
54783
55902
  projectPath,
@@ -54788,7 +55907,10 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
54788
55907
  queryModelId: embeddingModelId && embeddingModelId !== "off" ? embeddingModelId : null,
54789
55908
  workspace,
54790
55909
  visibleMemoryIds: options.visibleMemoryIds
54791
- }) : Promise.resolve([]),
55910
+ }) : Promise.resolve({
55911
+ results: [],
55912
+ suppressedVisibleIds: []
55913
+ }),
54792
55914
  runGitCommits ? Promise.resolve(searchGitCommits({
54793
55915
  db,
54794
55916
  projectPath,
@@ -54814,8 +55936,11 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
54814
55936
  probes: messageProbes
54815
55937
  })) : Promise.resolve([])
54816
55938
  ]);
55939
+ if (options.diagnostics) {
55940
+ options.diagnostics.suppressedVisibleMemoryIds = memoryOutcome.suppressedVisibleIds;
55941
+ }
54817
55942
  const results = [
54818
- ...memoryResults,
55943
+ ...memoryOutcome.results,
54819
55944
  ...primerResults,
54820
55945
  ...messageLikeResults,
54821
55946
  ...gitCommitResults,
@@ -54853,9 +55978,126 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
54853
55978
  }
54854
55979
  return results;
54855
55980
  }
55981
+ var SEARCH_NOTE_EXPAND_HINT = "Use ctx_expand(start=N-10, end=N) around any note @msg anchor above to read the surrounding conversation context.";
55982
+ function formatSearchAge(timestampMs) {
55983
+ const ageMs = Date.now() - timestampMs;
55984
+ if (ageMs < 0)
55985
+ return "future";
55986
+ const days = Math.floor(ageMs / (24 * 60 * 60 * 1000));
55987
+ if (days <= 0)
55988
+ return "today";
55989
+ if (days === 1)
55990
+ return "1d ago";
55991
+ if (days < 30)
55992
+ return `${days}d ago`;
55993
+ const months = Math.floor(days / 30);
55994
+ if (months === 1)
55995
+ return "1mo ago";
55996
+ if (months < 12)
55997
+ return `${months}mo ago`;
55998
+ const years = Math.floor(days / 365);
55999
+ return years === 1 ? "1y ago" : `${years}y ago`;
56000
+ }
56001
+ function formatUnifiedSearchResult(result, index, currentSessionId) {
56002
+ if (result.source === "memory") {
56003
+ const source = result.sourceName ? ` source=${result.sourceName}` : "";
56004
+ return [
56005
+ `[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category}${source} match=${result.matchType}`,
56006
+ result.content
56007
+ ].join(`
56008
+ `);
56009
+ }
56010
+ if (result.source === "git_commit") {
56011
+ return [
56012
+ `[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatSearchAge(result.committedAtMs)} match=${result.matchType}`,
56013
+ result.content
56014
+ ].join(`
56015
+ `);
56016
+ }
56017
+ if (result.source === "primer") {
56018
+ return [
56019
+ `[${index}] [primer] score=${result.score.toFixed(2)} id=${result.primerId} support=${result.support} match=${result.matchType}`,
56020
+ result.content
56021
+ ].join(`
56022
+ `);
56023
+ }
56024
+ if (result.source === "note") {
56025
+ const anchor = result.anchorOrdinal !== null && result.sourceSessionId === currentSessionId ? ` @msg ${result.anchorOrdinal}` : "";
56026
+ return [
56027
+ `[${index}] [note] score=${result.score.toFixed(2)} id=#${result.noteId} status=${result.status} ${formatSearchAge(result.createdAt)}${anchor}`,
56028
+ result.content
56029
+ ].join(`
56030
+ `);
56031
+ }
56032
+ if (result.source === "compartment") {
56033
+ return [
56034
+ `[${index}] [message] score=${result.score.toFixed(2)} compartment_id=${result.compartmentId} range=${result.startOrdinal}-${result.endOrdinal} match=${result.matchType} title=${result.title}`,
56035
+ result.snippet ? `Snippet: ${result.snippet}` : result.content
56036
+ ].join(`
56037
+ `);
56038
+ }
56039
+ const expandStart = Math.max(1, result.messageOrdinal - 3);
56040
+ const expandEnd = result.messageOrdinal + 3;
56041
+ return [
56042
+ `[${index}] [message] score=${result.score.toFixed(2)} ordinal=${result.messageOrdinal} range=${expandStart}-${expandEnd} role=${result.role}`,
56043
+ result.content
56044
+ ].join(`
56045
+ `);
56046
+ }
56047
+ function formatSearchDiagnosticLines(results, diagnostics) {
56048
+ if (!diagnostics)
56049
+ return [];
56050
+ const lines = [];
56051
+ const visibleIds = [...diagnostics.suppressedVisibleMemoryIds].sort((left, right) => left - right);
56052
+ if (visibleIds.length > 0) {
56053
+ const count = visibleIds.length;
56054
+ const noun = count === 1 ? "match" : "matches";
56055
+ const ids = visibleIds.join(", ");
56056
+ if (results.some((result) => result.source === "memory")) {
56057
+ lines.push(`Memories: ${count} additional ${noun} suppressed because ${count === 1 ? "it is" : "they are"} already visible in your project-memory block (ids ${ids}).`);
56058
+ } else {
56059
+ lines.push(`Memories: ${count} ${noun} found, all already visible in your project-memory block (ids ${ids}).`);
56060
+ }
56061
+ }
56062
+ if (diagnostics.suppressedLiveMessageMatches > 0) {
56063
+ const count = diagnostics.suppressedLiveMessageMatches;
56064
+ lines.push(`Message history: ${count} raw-message ${count === 1 ? "match is" : "matches are"} newer than the last compartment boundary (already in your context).`);
56065
+ }
56066
+ if (diagnostics.gitCommitUnavailable === "no_git_repository") {
56067
+ lines.push("Git commits: no git repository — commit search unavailable for this project.");
56068
+ }
56069
+ return lines;
56070
+ }
56071
+ function formatSearchResults(query, results, currentSessionId, diagnostics) {
56072
+ const diagnosticLines = formatSearchDiagnosticLines(results, diagnostics);
56073
+ if (results.length === 0) {
56074
+ if (diagnosticLines.length > 0) {
56075
+ return `No hidden results found for "${query}".
56076
+
56077
+ ${diagnosticLines.join(`
56078
+ `)}`;
56079
+ }
56080
+ return `No results found for "${query}" across notes, memories, primers, git commits, or message history.`;
56081
+ }
56082
+ const bodyParts = results.map((result, index) => formatUnifiedSearchResult(result, index + 1, currentSessionId));
56083
+ if (diagnosticLines.length > 0)
56084
+ bodyParts.push(diagnosticLines.join(`
56085
+ `));
56086
+ if (results.some((result) => result.source === "message" || result.source === "compartment")) {
56087
+ bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
56088
+ }
56089
+ if (results.some((result) => result.source === "note" && result.anchorOrdinal !== null && result.sourceSessionId === currentSessionId)) {
56090
+ bodyParts.push(SEARCH_NOTE_EXPAND_HINT);
56091
+ }
56092
+ return `Found ${results.length} result${results.length === 1 ? "" : "s"} for "${query}":
56093
+
56094
+ ${bodyParts.join(`
56095
+
56096
+ `)}`;
56097
+ }
54856
56098
 
54857
56099
  // ../plugin/src/features/magic-context/mural/render-trigger.ts
54858
- import { createHash as createHash15 } from "node:crypto";
56100
+ import { createHash as createHash16 } from "node:crypto";
54859
56101
 
54860
56102
  // ../plugin/src/features/magic-context/mural/mural-selection.ts
54861
56103
  var DEFAULT_MURAL_MEMORY_BUDGET = 8000;
@@ -55481,7 +56723,7 @@ function ensureMuralRendered(db, projectIdentity, budgetTokens = DEFAULT_MURAL_M
55481
56723
  return { hasMural: false, rerendered: false };
55482
56724
  }
55483
56725
  const rendered = renderMural(entries);
55484
- const textHash = createHash15("sha256").update(rendered.sha256Input).digest("hex");
56726
+ const textHash = createHash16("sha256").update(rendered.sha256Input).digest("hex");
55485
56727
  const existing = getMural(db, projectIdentity);
55486
56728
  if (existing && existing.contentHash === textHash && existing.width === rendered.width && existing.height === rendered.height) {
55487
56729
  return {
@@ -55711,7 +56953,7 @@ class BoundedSessionMap {
55711
56953
  }
55712
56954
 
55713
56955
  // ../plugin/src/features/magic-context/compaction-marker.ts
55714
- import { createHash as createHash16 } from "node:crypto";
56956
+ import { createHash as createHash17 } from "node:crypto";
55715
56957
  import { existsSync as existsSync14 } from "node:fs";
55716
56958
  import { join as join12 } from "node:path";
55717
56959
  var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -55719,7 +56961,7 @@ var ID_PREFIX_HEX_LENGTH = 12;
55719
56961
  var ID_SUFFIX_LENGTH = 14;
55720
56962
  var ID_PREFIX_MASK = (1n << BigInt(ID_PREFIX_HEX_LENGTH * 4)) - 1n;
55721
56963
  function deterministicBase62(seed, length) {
55722
- let value = BigInt(`0x${createHash16("sha256").update(seed).digest("hex")}`);
56964
+ let value = BigInt(`0x${createHash17("sha256").update(seed).digest("hex")}`);
55723
56965
  const chars = Array(length);
55724
56966
  for (let index = length - 1;index >= 0; index -= 1) {
55725
56967
  chars[index] = BASE62_CHARS[Number(value % 62n)];
@@ -56617,8 +57859,7 @@ Picking sources:
56617
57859
 
56618
57860
  // src/tools/ctx-search.ts
56619
57861
  var DEFAULT_LIMIT = 10;
56620
- var NOTE_EXPAND_HINT = "Use ctx_expand(start=N-10, end=N) around any note @msg anchor above to read the surrounding conversation context.";
56621
- var ParamsSchema5 = exports_typebox.Object({
57862
+ var ParamsSchema4 = exports_typebox.Object({
56622
57863
  query: exports_typebox.Optional(exports_typebox.String({
56623
57864
  description: "Search query. Matches against memory content, Primers, git commit messages, and raw user/assistant message text."
56624
57865
  })),
@@ -56640,96 +57881,13 @@ function normalizeLimit3(limit) {
56640
57881
  return DEFAULT_LIMIT;
56641
57882
  return Math.max(1, Math.floor(limit));
56642
57883
  }
56643
- function formatAge(committedAtMs) {
56644
- const ageMs = Date.now() - committedAtMs;
56645
- if (ageMs < 0)
56646
- return "future";
56647
- const days = Math.floor(ageMs / (24 * 60 * 60 * 1000));
56648
- if (days <= 0)
56649
- return "today";
56650
- if (days === 1)
56651
- return "1d ago";
56652
- if (days < 30)
56653
- return `${days}d ago`;
56654
- const months = Math.floor(days / 30);
56655
- if (months === 1)
56656
- return "1mo ago";
56657
- if (months < 12)
56658
- return `${months}mo ago`;
56659
- const years = Math.floor(days / 365);
56660
- return years === 1 ? "1y ago" : `${years}y ago`;
56661
- }
56662
- function formatResult(result, index, currentSessionId) {
56663
- if (result.source === "memory") {
56664
- const source = result.sourceName ? ` source=${result.sourceName}` : "";
56665
- return [
56666
- `[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category}${source} match=${result.matchType}`,
56667
- result.content
56668
- ].join(`
56669
- `);
56670
- }
56671
- if (result.source === "git_commit") {
56672
- return [
56673
- `[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatAge(result.committedAtMs)} match=${result.matchType}`,
56674
- result.content
56675
- ].join(`
56676
- `);
56677
- }
56678
- if (result.source === "primer") {
56679
- return [
56680
- `[${index}] [primer] score=${result.score.toFixed(2)} id=${result.primerId} support=${result.support} match=${result.matchType}`,
56681
- result.content
56682
- ].join(`
56683
- `);
56684
- }
56685
- if (result.source === "note") {
56686
- const anchor = result.anchorOrdinal !== null && result.sourceSessionId === currentSessionId ? ` @msg ${result.anchorOrdinal}` : "";
56687
- return [
56688
- `[${index}] [note] score=${result.score.toFixed(2)} id=#${result.noteId} status=${result.status} ${formatAge(result.createdAt)}${anchor}`,
56689
- result.content
56690
- ].join(`
56691
- `);
56692
- }
56693
- if (result.source === "compartment") {
56694
- return [
56695
- `[${index}] [message] score=${result.score.toFixed(2)} compartment_id=${result.compartmentId} range=${result.startOrdinal}-${result.endOrdinal} match=${result.matchType} title=${result.title}`,
56696
- result.snippet ? `Snippet: ${result.snippet}` : result.content
56697
- ].join(`
56698
- `);
56699
- }
56700
- const expandStart = Math.max(1, result.messageOrdinal - 3);
56701
- const expandEnd = result.messageOrdinal + 3;
56702
- return [
56703
- `[${index}] [message] score=${result.score.toFixed(2)} ordinal=${result.messageOrdinal} range=${expandStart}-${expandEnd} role=${result.role}`,
56704
- result.content
56705
- ].join(`
56706
- `);
56707
- }
56708
- function formatSearchResults(query, results, currentSessionId) {
56709
- if (results.length === 0) {
56710
- return `No results found for "${query}" across notes, memories, primers, git commits, or message history.`;
56711
- }
56712
- const bodyParts = results.map((result, index) => formatResult(result, index + 1, currentSessionId));
56713
- if (results.some((result) => result.source === "message" || result.source === "compartment")) {
56714
- bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
56715
- }
56716
- if (results.some((result) => result.source === "note" && result.anchorOrdinal !== null && result.sourceSessionId === currentSessionId)) {
56717
- bodyParts.push(NOTE_EXPAND_HINT);
56718
- }
56719
- const body = bodyParts.join(`
56720
-
56721
- `);
56722
- return `Found ${results.length} result${results.length === 1 ? "" : "s"} for "${query}":
56723
-
56724
- ${body}`;
56725
- }
56726
57884
  function createCtxSearchTool(deps) {
56727
57885
  const resolveProject = deps.resolveProjectIdentity ?? resolveProjectIdentityForSession;
56728
57886
  return {
56729
57887
  name: "ctx_search",
56730
57888
  label: "Magic Context: Search",
56731
57889
  description: CTX_SEARCH_DESCRIPTION,
56732
- parameters: ParamsSchema5,
57890
+ parameters: ParamsSchema4,
56733
57891
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
56734
57892
  params = unwrapImitatedReducedArgs(params, ["query"], {
56735
57893
  query: "string",
@@ -56771,6 +57929,7 @@ function createCtxSearchTool(deps) {
56771
57929
  const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, sessionId);
56772
57930
  const messageOrdinalCutoff = lastCompartmentEnd >= 0 ? lastCompartmentEnd : 0;
56773
57931
  const visibleMemoryIds = getVisibleMemoryIds(deps.db, sessionId);
57932
+ const diagnostics = createUnifiedSearchDiagnostics();
56774
57933
  const idShape = parseIdShapedQuery(query);
56775
57934
  if (idShape && memoryEnabled) {
56776
57935
  const idResults = resolveMemoriesByIdsForSearch({
@@ -56778,14 +57937,15 @@ function createCtxSearchTool(deps) {
56778
57937
  projectPath: projectIdentity,
56779
57938
  ids: idShape,
56780
57939
  limit: Math.max(normalizeLimit3(params.limit), idShape.length),
56781
- visibleMemoryIds
57940
+ visibleMemoryIds,
57941
+ diagnostics
56782
57942
  });
56783
- if (idResults !== null) {
57943
+ if (idResults !== null || diagnostics.suppressedVisibleMemoryIds.length > 0) {
56784
57944
  return {
56785
57945
  content: [
56786
57946
  {
56787
57947
  type: "text",
56788
- text: formatSearchResults(query, idResults, sessionId)
57948
+ text: formatSearchResults(query, idResults ?? [], sessionId, diagnostics)
56789
57949
  }
56790
57950
  ],
56791
57951
  details: undefined
@@ -56805,13 +57965,15 @@ function createCtxSearchTool(deps) {
56805
57965
  gitCommitsEnabled,
56806
57966
  sources: params.sources,
56807
57967
  visibleMemoryIds,
57968
+ diagnostics,
57969
+ gitRepositoryAvailable: directoryHasGitMetadata(ctx.cwd),
56808
57970
  explicitSearch: true
56809
57971
  });
56810
57972
  return {
56811
57973
  content: [
56812
57974
  {
56813
57975
  type: "text",
56814
- text: formatSearchResults(query, results, sessionId)
57976
+ text: formatSearchResults(query, results, sessionId, diagnostics)
56815
57977
  }
56816
57978
  ],
56817
57979
  details: undefined
@@ -56874,6 +58036,14 @@ function createTodowriteTool() {
56874
58036
  }
56875
58037
 
56876
58038
  // src/tools/index.ts
58039
+ var CTX_MEMORY_TOOL_NAME = "ctx_memory";
58040
+ function syncCtxMemoryToolEnabled(pi, memoryEnabled) {
58041
+ const activeTools = pi.getActiveTools();
58042
+ const isActive = activeTools.includes(CTX_MEMORY_TOOL_NAME);
58043
+ if (memoryEnabled === isActive)
58044
+ return;
58045
+ pi.setActiveTools(memoryEnabled ? [...activeTools, CTX_MEMORY_TOOL_NAME] : activeTools.filter((toolName) => toolName !== CTX_MEMORY_TOOL_NAME));
58046
+ }
56877
58047
  function registerMagicContextTools(pi, opts) {
56878
58048
  const resolveProjectIdentity2 = opts.resolveProjectIdentity ? (directory) => opts.resolveProjectIdentity?.({ cwd: directory }) : undefined;
56879
58049
  const promptSurfaceRuntime = opts.promptSurfaceRuntime ?? createPromptSurfaceRuntime({
@@ -56927,4 +58097,4 @@ function registerMagicContextTools(pi, opts) {
56927
58097
  }
56928
58098
  }
56929
58099
 
56930
- export { COMPACTION_ENABLED_PATH, isDreamerRunnable, isCompactionEnabled, migrateMagicContextConfigLocations, FAIL_CLOSED_DOCTOR_COMMAND, formatFailClosedBlockingMessage, createFailClosedBlockingError, isFailClosedBlockingError, shouldBypassFailClosedBlock, createFailClosedController, ProjectIdentityError, resolveProjectIdentityStrict, resolveProjectIdentity, resolveProjectIdentityForSession, beginBootQuietPeriod, scheduleAfterBootQuiet, Database, closeQuietly, isMidTurn, textMentionsRecentCommit, hasMeaningfulUserText, extractTexts, extractToolCallSummaries, preloadTokenizer, estimateTokens, normalizeText, isRecord, completedToolArcCrossesBoundary, estimateTrueRawMessageTokens, buildToolArcs, fenceBoundaryForCompletedToolArcs, fenceBoundaryForToolArcs, buildTrueRawTokenIndex, computeRawRangeFingerprint, invalidateTrueRawTokenCache, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isEditTool, applyEditMarkerToInput, setRawMessageProvider, withRawMessageProvider, cleanUserText, withRawSessionMessageCache, readRawSessionMessages, primeTailRawMessageCache, getCachedAbsoluteMessageCount, primeInMemoryTailRawMessageCache, getRawSessionMessageCount, getRawSessionTagKeysThrough, getLegacyProtectedTailStartOrdinal, readSessionChunk, clearCompressionDepth, clearCompressionDepthRange, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes, recordSessionProjectIdentity, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, isCompartmentLeaseHeld, piModelRefToCanonical, resolveModelRefForPi, modelRefLookupOrder, ompModelRefToCanonical, resolveModelRefForOmp, persistCachedM0, clearCachedM0M1, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, getCompartmentsByEndMessageId, appendCompartments, saveRecompStagingPass, getRecompStaging, clearRecompStaging, getRecompPartialRange, setRecompPartialRange, escapeXmlAttr, escapeXmlContent, getModuleNoteEvaluationBridge, getContextStoreUuid, parseCompartmentOutput, logSlowWriteTransaction, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, sourceNameForMemory, computeWorkspaceEpochFingerprint, bumpEpochsForWorkspaceMembers, readProjectDocsCanonical, copySessionStateForClone, getErrorMessage, describeError, setStoragePrivatePermissionEnforcement, getSchemaFenceRejection, getMigrationOnOpenRefusal, LATEST_SUPPORTED_VERSION, getDatabasePath, getPersistedSchemaVersion, setSqlitePragmaConfig, applySqliteTuningPragmas, runSqliteOptimize, openDatabase, openDatabaseAsync, queueM0Mutation, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRender, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationId, getMaxMemoryMutationIdForProjects, MAX_EXECUTE_THRESHOLD, escalationBands, describeProtectedTailDrainBudgetSkip, loadProtectedTailMeta, markProtectedTailPolicyV3Seeded, recordProtectedTailPublicationFloor, recordProtectedTailNoEligibleHead, getWrapupInProgressState, isWrapupInProgress, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, resolveCompactionModeRecord, getCompactionModeRecord, setCompactionModeRecord, reserveProtectedTailDrainTokens, clearEmergencyDrainLatch, recordHistorianDrainFailure, clearHistorianDrainFailure, rollbackProtectedTailDrainReservation, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getChannel1NudgeState, setChannel1NudgeState, markChannel1PostReduceGracePending, captureChannel1PostReduceGraceBaseline, getChannel2NudgeState, getChannel2NudgeClaim, setChannel2NudgeState, casChannel2NudgeState, claimChannel2NudgeState, casChannel2NudgeClaim, getPersistedNoteNudge, setPersistedNoteNudgeTrigger, setPersistedNoteNudgeTriggerMessageId, getNoteNudgeAnchors, getAutoSearchHintDecisions, deliverNoteNudgeAtomic, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, getNoteLastReadAt, getHistorianFailureState, incrementHistorianFailure, clearHistorianFailureState, getOverflowState, recordOverflowDetected, clearEmergencyRecovery, clearDetectedContextLimit, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, getPendingPiCompactionMarkerState, setPendingPiCompactionMarkerState, clearPendingPiCompactionMarkerStateIf, getSessionsWithPendingPiMarker, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, setSessionWorkMetrics, getSessionWorkMetrics, getOrCreateSessionMeta, updateSessionMeta, advanceToolReclaimWatermark, retryPendingSessionCleanups, getNotes, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, clearPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, insertPrimerCandidates, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, recordSubagentInvocation, getLatestHistorianInvocationId, CTX_REDUCE_KEEP, estimateImageTokensFromDataUrl, normalizeTodoStateJson, buildSyntheticTodoPart, stripChannel1ReminderSpans, effectiveTailHygiene, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, decideChannel1, evaluateChannel2, reclaimableToolOutputCount, buildChannel2Reminder, buildChannel1Reminder, planEmergencyDrop, updateTagByteSize, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, updateTagInputByteSize, updateTagTokenCount, getPersistedToolTagAccounting, getAllStatusTagTokenTotalsFlat, updateTagInputTokenCount, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, hasPiFallbackMessageTags, findAdoptableFallbackTags, hasPiFallbackToolOwnerTags, findPiFallbackToolOwnerTags, adoptPiFallbackToolOwnerTag, adoptPiFallbackMessageTag, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getTagsForPendingOperations, getTagsByNumbers, getDroppedTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, BoundedSessionMap, getWindowOverlay, resolveWindowOverlayFacts, deriveWindowGeometry, formatWindowDerivationLine, isSaneLimit, resolveOutputReserve, getSdkContextLimit, resolveModelConfigOrDefault, promptSurfaceHashMaterial, createPromptSurfaceRuntime, createPromptSurfaceGuidanceEpochCache, SYNTH_USER_ID_PREFIX, resolvePiStableId, isMidTurnPi, readPiSessionSnapshot, readPiSessionMessages, findLastModelKeyFromBranch, convertEntriesToRawMessages, withContentLanguageDirective, withMigrationLanguageDirective, buildPrimaryLanguageDirective, computeCueContentHash, hasMuralCueColumns, getMuralCueState, memoryNeedsCue, setMuralCue, recordMuralCueRejection, invalidateMemory, computeNormalizedHash, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, insertMemory, getMemoryByHash, getMemoriesByProject, getMemoriesByProjects, getMaxMemoryIdForProjects, getAllActiveMemoriesForMigration, getMemoryById, setMemoryClassification, archiveMemory, deleteMemory, getMemoryCount, getMemoryCountsByStatus, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, getOpenCodeDbPath2 as getOpenCodeDbPath, parseCron, nextOccurrence, nextDueAtMs, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, buildCanonicalChunkTextFromFts, buildCompartmentSummaryFallbackText, canonicalizeInMemoryChunkTextForEmbedding, chunkCanonicalText, chunkEmbeddingWindowsAreCurrent, replaceCompartmentChunkEmbeddings, cosineSimilarity, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, contentSha256, sweepStaleEmbeddingIdentitiesForProject, enqueueShadowEmbeddingItems, getProjectEmbeddingSnapshot, getProjectChunkEmbeddingModelId, getProjectEmbeddingMaxInputTokens, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, promoteSessionFactsDurable, embedPromotedFacts, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, wakePlaneStatus, indexCommitsForProject, embedUnembeddedCommits, loadPiConfig, ensureProjectRegisteredFromPiDirectory, resolveMuralWire, updateCompactionMarkerAfterPublication, COMPARTMENT_RENDER_EPOCH, encodeCachedM0UpgradeIdentity, decodeCachedM0UpgradeIdentity, DEFAULT_HISTORY_BUDGET_TOKENS, renderCompartmentAtTier, renderDecayedCompartments, extractM0Block, TEMPORAL_MARKER_PATTERN, temporalMarkerPrefix, clearInjectionCache, getVisibleMemoryIds, renderMemoryBlock, DEFAULT_MEMORY_BUDGET_TOKENS, DEFAULT_USER_PROFILE_BUDGET_TOKENS, trimMemoriesToBudgetV2, trimWorkspaceMemoriesToBudgetV2, trimUserMemoriesToBudget, renderMemoryBlockV2, stripMemoryMuralBlock, unifiedSearch, rememberTodowriteToolCallTodos, parseTodos, setTodoSnapshot, registerTodoOverlay, registerTodoStateLifecycle, registerMagicContextTools };
58100
+ export { COMPACTION_ENABLED_PATH, isDreamerRunnable, isCompactionEnabled, migrateMagicContextConfigLocations, FAIL_CLOSED_DOCTOR_COMMAND, formatFailClosedBlockingMessage, createFailClosedBlockingError, isFailClosedBlockingError, shouldBypassFailClosedBlock, createFailClosedController, ProjectIdentityError, resolveProjectIdentityStrict, resolveProjectIdentity, resolveProjectIdentityForSession, beginBootQuietPeriod, scheduleAfterBootQuiet, Database, closeQuietly, isMidTurn, textMentionsRecentCommit, hasMeaningfulUserText, extractTexts, extractToolCallSummaries, preloadTokenizer, estimateTokens, normalizeText, isRecord, completedToolArcCrossesBoundary, estimateTrueRawMessageTokens, buildToolArcs, fenceBoundaryForCompletedToolArcs, fenceBoundaryForToolArcs, buildTrueRawTokenIndex, computeRawRangeFingerprint, invalidateTrueRawTokenCache, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isEditTool, applyEditMarkerToInput, setRawMessageProvider, withRawMessageProvider, cleanUserText, withRawSessionMessageCache, readRawSessionMessages, primeTailRawMessageCache, getCachedAbsoluteMessageCount, primeInMemoryTailRawMessageCache, getRawSessionMessageCount, getRawSessionTagKeysThrough, getLegacyProtectedTailStartOrdinal, readSessionChunk, clearCompressionDepth, clearCompressionDepthRange, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes, recordSessionProjectIdentity, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, isCompartmentLeaseHeld, piModelRefToCanonical, resolveModelRefForPi, modelRefLookupOrder, ompModelRefToCanonical, resolveModelRefForOmp, persistCachedM0, clearCachedM0M1, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, getCompartmentsByEndMessageId, appendCompartments, saveRecompStagingPass, getRecompStaging, clearRecompStaging, getRecompPartialRange, setRecompPartialRange, escapeXmlAttr, escapeXmlContent, getModuleNoteEvaluationBridge, getContextStoreUuid, parseCompartmentOutput, logSlowWriteTransaction, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, sourceNameForMemory, computeWorkspaceEpochFingerprint, bumpEpochsForWorkspaceMembers, readProjectDocsCanonical, copySessionStateForClone, getErrorMessage, describeError, setStoragePrivatePermissionEnforcement, getSchemaFenceRejection, getMigrationOnOpenRefusal, LATEST_SUPPORTED_VERSION, getDatabasePath, getPersistedSchemaVersion, setSqlitePragmaConfig, applySqliteTuningPragmas, runSqliteOptimize, openDatabase, openDatabaseAsync, queueM0Mutation, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRender, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationId, getMaxMemoryMutationIdForProjects, MAX_EXECUTE_THRESHOLD, escalationBands, describeProtectedTailDrainBudgetSkip, loadProtectedTailMeta, markProtectedTailPolicyV3Seeded, recordProtectedTailPublicationFloor, recordProtectedTailNoEligibleHead, getWrapupInProgressState, isWrapupInProgress, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, resolveCompactionModeRecord, getCompactionModeRecord, setCompactionModeRecord, reserveProtectedTailDrainTokens, clearEmergencyDrainLatch, recordHistorianDrainFailure, clearHistorianDrainFailure, rollbackProtectedTailDrainReservation, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getChannel1NudgeState, setChannel1NudgeState, markChannel1PostReduceGracePending, captureChannel1PostReduceGraceBaseline, getChannel2NudgeState, getChannel2NudgeClaim, setChannel2NudgeState, casChannel2NudgeState, claimChannel2NudgeState, casChannel2NudgeClaim, getPersistedNoteNudge, setPersistedNoteNudgeTrigger, setPersistedNoteNudgeTriggerMessageId, getNoteNudgeAnchors, getAutoSearchHintDecisions, deliverNoteNudgeAtomic, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, getNoteLastReadAt, getHistorianFailureState, incrementHistorianFailure, clearHistorianFailureState, getOverflowState, recordOverflowDetected, clearEmergencyRecovery, clearDetectedContextLimit, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, getPendingPiCompactionMarkerState, setPendingPiCompactionMarkerState, clearPendingPiCompactionMarkerStateIf, getSessionsWithPendingPiMarker, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, setSessionWorkMetrics, getSessionWorkMetrics, getOrCreateSessionMeta, updateSessionMeta, advanceToolReclaimWatermark, retryPendingSessionCleanups, retryPendingRustSessionCleanupsForProject, getNotes, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, getPendingOpsCount, clearPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, insertPrimerCandidates, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, recordSubagentInvocation, getLatestHistorianInvocationId, CTX_REDUCE_KEEP, estimateImageTokensFromDataUrl, normalizeTodoStateJson, buildSyntheticTodoPart, stripChannel1ReminderSpans, effectiveTailHygiene, CHANNEL1_SENTINEL, CHANNEL1_FLOOR_TOKENS, decideChannel1, evaluateChannel2, reclaimableToolOutputCount, buildChannel2Reminder, buildChannel1Reminder, planEmergencyDrop, updateTagByteSize, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, updateTagInputByteSize, updateTagTokenCount, getPersistedToolTagAccounting, getAllStatusTagTokenTotalsFlat, updateTagInputTokenCount, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, hasPiFallbackMessageTags, findAdoptableFallbackTags, hasPiFallbackToolOwnerTags, findPiFallbackToolOwnerTags, adoptPiFallbackToolOwnerTag, adoptPiFallbackMessageTag, getMaxTagNumberBySession, getAssignableTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getTagsForPendingOperations, getTagsByNumbers, getDroppedTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, BoundedSessionMap, reloadWindowOverlay, getWindowOverlay, resolveWindowOverlayFacts, deriveWindowGeometry, formatWindowDerivationLine, isSaneLimit, resolveOutputReserve, getSdkContextLimit, resolveModelConfigOrDefault, promptSurfaceHashMaterial, createPromptSurfaceRuntime, createPromptSurfaceGuidanceEpochCache, SYNTH_USER_ID_PREFIX, resolvePiStableId, isMidTurnPi, readPiSessionSnapshot, readPiSessionMessages, findLastModelKeyFromBranch, convertEntriesToRawMessages, withContentLanguageDirective, withMigrationLanguageDirective, buildPrimaryLanguageDirective, computeCueContentHash, hasMuralCueColumns, getMuralCueState, memoryNeedsCue, setMuralCue, recordMuralCueRejection, invalidateMemory, computeNormalizedHash, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, insertMemory, getMemoryByHash, getMemoriesByProject, getMemoriesByProjects, getMaxMemoryIdForProjects, getAllActiveMemoriesForMigration, getMemoryById, setMemoryClassification, archiveMemory, deleteMemory, getMemoryCount, getMemoryCountsByStatus, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, getOpenCodeDbPath2 as getOpenCodeDbPath, parseCron, nextOccurrence, nextDueAtMs, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, buildCanonicalChunkTextFromFts, buildCompartmentSummaryFallbackText, canonicalizeInMemoryChunkTextForEmbedding, chunkCanonicalText, chunkEmbeddingWindowsAreCurrent, replaceCompartmentChunkEmbeddings, cosineSimilarity, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, contentSha256, sweepStaleEmbeddingIdentitiesForProject, enqueueShadowEmbeddingItems, getProjectEmbeddingSnapshot, getProjectChunkEmbeddingModelId, getProjectEmbeddingMaxInputTokens, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, promoteSessionFactsDurable, embedPromotedFacts, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, isDirectiveShapedProjectRule, takeCurateSafetyRefusalCount, wakePlaneStatus, indexCommitsForProject, embedUnembeddedCommits, loadPiConfig, ensureProjectRegisteredFromPiDirectory, resolveMuralWire, updateCompactionMarkerAfterPublication, COMPARTMENT_RENDER_EPOCH, encodeCachedM0UpgradeIdentity, decodeCachedM0UpgradeIdentity, DEFAULT_HISTORY_BUDGET_TOKENS, renderCompartmentAtTier, renderDecayedCompartments, extractM0Block, TEMPORAL_MARKER_PATTERN, temporalMarkerPrefix, clearInjectionCache, getVisibleMemoryIds, renderMemoryBlock, DEFAULT_MEMORY_BUDGET_TOKENS, DEFAULT_USER_PROFILE_BUDGET_TOKENS, trimMemoriesToBudgetV2, trimWorkspaceMemoriesToBudgetV2, trimUserMemoriesToBudget, renderMemoryBlockV2, stripMemoryMuralBlock, unifiedSearch, rememberTodowriteToolCallTodos, parseTodos, setTodoSnapshot, registerTodoOverlay, registerTodoStateLifecycle, syncCtxMemoryToolEnabled, registerMagicContextTools };