@cortexkit/pi-magic-context 0.16.2 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -15043,14 +15043,334 @@ var init_embedding = __esm(() => {
15043
15043
  SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
15044
15044
  });
15045
15045
 
15046
+ // ../../node_modules/.bun/nanotar@0.3.0/node_modules/nanotar/dist/index.mjs
15047
+ function parseTar(data, opts) {
15048
+ const buffer2 = data.buffer || data;
15049
+ const files = [];
15050
+ let offset = 0;
15051
+ let nextExtendedHeader;
15052
+ let globalExtendedHeader;
15053
+ while (offset < buffer2.byteLength - 512) {
15054
+ let name = _readString(buffer2, offset, 100);
15055
+ if (name.length === 0) {
15056
+ break;
15057
+ }
15058
+ if (nextExtendedHeader) {
15059
+ const longName = nextExtendedHeader.path || nextExtendedHeader.linkpath;
15060
+ if (longName) {
15061
+ name = longName;
15062
+ }
15063
+ }
15064
+ const mode = _readString(buffer2, offset + 100, 8).trim();
15065
+ const uid = Number.parseInt(_readString(buffer2, offset + 108, 8));
15066
+ const gid = Number.parseInt(_readString(buffer2, offset + 116, 8));
15067
+ const size = _readNumber(buffer2, offset + 124, 12);
15068
+ const seek = 512 + 512 * Math.trunc(size / 512) + (size % 512 ? 512 : 0);
15069
+ const mtime = _readNumber(buffer2, offset + 136, 12);
15070
+ const _type = _readString(buffer2, offset + 156, 1) || "0";
15071
+ const type = tarItemTypeMap[_type] || _type;
15072
+ switch (type) {
15073
+ case "extendedHeader":
15074
+ case "globalExtendedHeader": {
15075
+ const headers = _parseExtendedHeaders(new Uint8Array(buffer2, offset + 512, size));
15076
+ if (type === "extendedHeader") {
15077
+ nextExtendedHeader = headers;
15078
+ } else {
15079
+ nextExtendedHeader = undefined;
15080
+ globalExtendedHeader = {
15081
+ ...globalExtendedHeader,
15082
+ ...headers
15083
+ };
15084
+ }
15085
+ offset += seek;
15086
+ continue;
15087
+ }
15088
+ case "gnuLongFileName":
15089
+ case "gnuOldLongFileName":
15090
+ case "gnuLongLinkName": {
15091
+ nextExtendedHeader = { path: _readString(buffer2, offset + 512, size) };
15092
+ offset += seek;
15093
+ continue;
15094
+ }
15095
+ }
15096
+ const user = _readString(buffer2, offset + 265, 32);
15097
+ const group = _readString(buffer2, offset + 297, 32);
15098
+ name = _sanitizePath(name);
15099
+ const meta3 = {
15100
+ name,
15101
+ type,
15102
+ size,
15103
+ attrs: {
15104
+ ...globalExtendedHeader,
15105
+ ...nextExtendedHeader,
15106
+ mode,
15107
+ uid,
15108
+ gid,
15109
+ mtime,
15110
+ user,
15111
+ group
15112
+ }
15113
+ };
15114
+ nextExtendedHeader = undefined;
15115
+ if (opts?.filter && !opts.filter(meta3)) {
15116
+ offset += seek;
15117
+ continue;
15118
+ }
15119
+ if (opts?.metaOnly) {
15120
+ files.push(meta3);
15121
+ offset += seek;
15122
+ continue;
15123
+ }
15124
+ const data2 = size === 0 ? undefined : new Uint8Array(buffer2, offset + 512, size);
15125
+ files.push({
15126
+ ...meta3,
15127
+ data: data2,
15128
+ get text() {
15129
+ return new TextDecoder().decode(this.data);
15130
+ }
15131
+ });
15132
+ offset += seek;
15133
+ }
15134
+ return files;
15135
+ }
15136
+ async function parseTarGzip(data, opts = {}) {
15137
+ const stream = new ReadableStream({
15138
+ start(controller) {
15139
+ controller.enqueue(new Uint8Array(data));
15140
+ controller.close();
15141
+ }
15142
+ }).pipeThrough(new DecompressionStream(opts.compression ?? "gzip"));
15143
+ const decompressedData = await new Response(stream).arrayBuffer();
15144
+ return parseTar(decompressedData, opts);
15145
+ }
15146
+ function _sanitizePath(path4) {
15147
+ let normalized = path4.replace(/\\/g, "/");
15148
+ normalized = normalized.replace(/^[a-zA-Z]:\//, "");
15149
+ normalized = normalized.replace(/^\/+/, "");
15150
+ const hasLeadingDotSlash = normalized.startsWith("./");
15151
+ const parts = normalized.split("/");
15152
+ const resolved = [];
15153
+ for (const part of parts) {
15154
+ if (part === "..") {
15155
+ resolved.pop();
15156
+ } else if (part !== "." && part !== "") {
15157
+ resolved.push(part);
15158
+ }
15159
+ }
15160
+ let result = resolved.join("/");
15161
+ if (hasLeadingDotSlash && !result.startsWith("./")) {
15162
+ result = "./" + result;
15163
+ }
15164
+ if (path4.endsWith("/") && !result.endsWith("/")) {
15165
+ result += "/";
15166
+ }
15167
+ return result;
15168
+ }
15169
+ function _readString(buffer2, offset, size) {
15170
+ const view = new Uint8Array(buffer2, offset, size);
15171
+ const i = view.indexOf(0);
15172
+ const td = new TextDecoder;
15173
+ return td.decode(i === -1 ? view : view.slice(0, i));
15174
+ }
15175
+ function _readNumber(buffer2, offset, size) {
15176
+ const view = new Uint8Array(buffer2, offset, size);
15177
+ let str = "";
15178
+ for (let i = 0;i < size; i++) {
15179
+ str += String.fromCodePoint(view[i]);
15180
+ }
15181
+ return Number.parseInt(str, 8);
15182
+ }
15183
+ function _parseExtendedHeaders(data) {
15184
+ const dataStr = new TextDecoder().decode(data);
15185
+ const headers = {};
15186
+ for (const line of dataStr.split(`
15187
+ `)) {
15188
+ const s = line.split(" ")[1]?.split("=");
15189
+ if (s) {
15190
+ headers[s[0]] = s[1];
15191
+ }
15192
+ }
15193
+ return headers;
15194
+ }
15195
+ var tarItemTypeMap;
15196
+ var init_dist = __esm(() => {
15197
+ tarItemTypeMap = {
15198
+ "0": "file",
15199
+ "1": "hardLink",
15200
+ "2": "symbolicLink",
15201
+ "3": "characterDevice",
15202
+ "4": "blockDevice",
15203
+ "5": "directory",
15204
+ "6": "fifo",
15205
+ "7": "contiguousFile",
15206
+ g: "globalExtendedHeader",
15207
+ x: "extendedHeader",
15208
+ D: "gnuDirectory",
15209
+ I: "gnuInodeMetadata",
15210
+ K: "gnuLongLinkName",
15211
+ L: "gnuLongFileName",
15212
+ N: "gnuOldLongFileName",
15213
+ M: "gnuMultiVolume",
15214
+ S: "gnuSparseFile",
15215
+ E: "gnuExtendedSparse",
15216
+ A: "solarisAcl",
15217
+ V: "solarisVolumeLabel",
15218
+ X: "solarisOldExtendedHeader"
15219
+ };
15220
+ });
15221
+
15222
+ // ../plugin/src/shared/native-binding.ts
15223
+ var exports_native_binding = {};
15224
+ __export(exports_native_binding, {
15225
+ resolveBetterSqliteNativeBinding: () => resolveBetterSqliteNativeBinding
15226
+ });
15227
+ import { existsSync, mkdirSync as mkdirSync2, writeFileSync } from "node:fs";
15228
+ import { createRequire } from "node:module";
15229
+ import * as path4 from "node:path";
15230
+ function logInfo(message) {
15231
+ log(`${PREFIX} ${message}`);
15232
+ }
15233
+ function logWarn(message) {
15234
+ log(`${PREFIX} WARN ${message}`);
15235
+ }
15236
+ function probeAbi(binaryPath) {
15237
+ const expected = process.versions.modules;
15238
+ try {
15239
+ const sandbox = { exports: {} };
15240
+ process.dlopen(sandbox, binaryPath);
15241
+ return { ok: true };
15242
+ } catch (err) {
15243
+ const message = err instanceof Error ? err.message : String(err);
15244
+ const pair = message.match(/NODE_MODULE_VERSION (\d+).*NODE_MODULE_VERSION (\d+)/s);
15245
+ if (pair?.[1] && pair[2]) {
15246
+ return { ok: false, expected: pair[2], actual: pair[1] };
15247
+ }
15248
+ const single = message.match(/NODE_MODULE_VERSION[ =:]+(\d+)/);
15249
+ if (single?.[1]) {
15250
+ return { ok: false, expected, actual: single[1] };
15251
+ }
15252
+ logWarn(`could not parse ABI from dlopen error: ${message}`);
15253
+ return { ok: false, expected, actual: null };
15254
+ }
15255
+ }
15256
+ function resolveBetterSqlite3OnDisk(requireFn) {
15257
+ try {
15258
+ const pkgJsonPath = requireFn.resolve("better-sqlite3/package.json");
15259
+ const pkgDir = path4.dirname(pkgJsonPath);
15260
+ const pkgJson = requireFn(pkgJsonPath);
15261
+ const binaryPath = path4.join(pkgDir, "build", "Release", "better_sqlite3.node");
15262
+ return { binaryPath, pkgVersion: pkgJson.version };
15263
+ } catch (err) {
15264
+ logWarn(`could not resolve better-sqlite3 in node_modules: ${err instanceof Error ? err.message : String(err)}`);
15265
+ return null;
15266
+ }
15267
+ }
15268
+ function getCachedBinaryPath(pkgVersion, abi) {
15269
+ return path4.join(getCacheDir(), "cortexkit", "native-bindings", "better-sqlite3", `v${pkgVersion}`, `electron-v${abi}-${process.platform}-${process.arch}`, "better_sqlite3.node");
15270
+ }
15271
+ async function downloadElectronPrebuild(pkgVersion, abi) {
15272
+ const filename = `better-sqlite3-v${pkgVersion}-electron-v${abi}-${process.platform}-${process.arch}.tar.gz`;
15273
+ const url2 = `https://github.com/WiseLibs/better-sqlite3/releases/download/v${pkgVersion}/${filename}`;
15274
+ logInfo(`downloading ${url2}`);
15275
+ const response = await fetch(url2, {
15276
+ redirect: "follow",
15277
+ headers: { "User-Agent": "magic-context-plugin/native-binding" }
15278
+ });
15279
+ if (!response.ok) {
15280
+ throw new Error(`failed to download Electron prebuild (HTTP ${response.status} ${response.statusText}) from ${url2}`);
15281
+ }
15282
+ const tarballBytes = new Uint8Array(await response.arrayBuffer());
15283
+ logInfo(`downloaded ${(tarballBytes.length / 1024).toFixed(1)} KB; extracting`);
15284
+ const files = await parseTarGzip(tarballBytes);
15285
+ const nodeFile = files.find((f) => f.name.endsWith("better_sqlite3.node"));
15286
+ if (!nodeFile?.data) {
15287
+ const names = files.map((f) => f.name).join(", ");
15288
+ throw new Error(`Electron prebuild tarball did not contain better_sqlite3.node; got: [${names}]`);
15289
+ }
15290
+ return nodeFile.data instanceof Uint8Array ? nodeFile.data : new Uint8Array(nodeFile.data);
15291
+ }
15292
+ async function resolveBetterSqliteNativeBinding() {
15293
+ if (!process.versions.electron) {
15294
+ return null;
15295
+ }
15296
+ if (inFlight) {
15297
+ return inFlight;
15298
+ }
15299
+ const promise2 = (async () => {
15300
+ const expected = process.versions.modules;
15301
+ logInfo(`Electron detected (v${process.versions.electron}, NODE_MODULE_VERSION ${expected}); verifying better-sqlite3 binding`);
15302
+ const requireFn = createRequire(import.meta.url);
15303
+ const resolved = resolveBetterSqlite3OnDisk(requireFn);
15304
+ if (!resolved) {
15305
+ return null;
15306
+ }
15307
+ const { binaryPath: diskPath, pkgVersion } = resolved;
15308
+ if (existsSync(diskPath)) {
15309
+ const diskProbe = probeAbi(diskPath);
15310
+ if (diskProbe.ok) {
15311
+ logInfo(`on-disk binary already matches Electron ABI v${expected}; using default bindings() lookup`);
15312
+ return null;
15313
+ }
15314
+ logInfo(`on-disk binary ABI ${diskProbe.actual ?? "unknown"} != required ${expected}; will use Electron prebuild`);
15315
+ } else {
15316
+ logWarn(`expected better-sqlite3 binary not found at ${diskPath}; will fetch Electron prebuild anyway`);
15317
+ }
15318
+ const cachedPath = getCachedBinaryPath(pkgVersion, expected);
15319
+ if (existsSync(cachedPath)) {
15320
+ const cachedProbe = probeAbi(cachedPath);
15321
+ if (cachedProbe.ok) {
15322
+ logInfo(`using cached Electron prebuild at ${cachedPath}`);
15323
+ return cachedPath;
15324
+ }
15325
+ logWarn(`cached binary at ${cachedPath} has wrong ABI (${cachedProbe.actual ?? "unknown"} != ${expected}); refetching`);
15326
+ }
15327
+ mkdirSync2(path4.dirname(cachedPath), { recursive: true });
15328
+ const nodeFileBytes = await downloadElectronPrebuild(pkgVersion, expected);
15329
+ writeFileSync(cachedPath, nodeFileBytes);
15330
+ logInfo(`cached Electron prebuild at ${cachedPath} (${(nodeFileBytes.length / 1024).toFixed(1)} KB)`);
15331
+ const finalProbe = probeAbi(cachedPath);
15332
+ if (!finalProbe.ok) {
15333
+ throw new Error(`downloaded Electron prebuild has wrong ABI (${finalProbe.actual ?? "unknown"} != ${expected}); refusing to use`);
15334
+ }
15335
+ return cachedPath;
15336
+ })();
15337
+ inFlight = promise2;
15338
+ try {
15339
+ return await promise2;
15340
+ } finally {
15341
+ if (inFlight === promise2) {
15342
+ inFlight = null;
15343
+ }
15344
+ }
15345
+ }
15346
+ var PREFIX = "[native-binding]", inFlight = null;
15347
+ var init_native_binding = __esm(() => {
15348
+ init_dist();
15349
+ init_data_path();
15350
+ init_logger();
15351
+ });
15352
+
15046
15353
  // ../plugin/src/shared/sqlite.ts
15047
- var isBun, bunSpec, betterSpec, sqliteModule, DatabaseImpl, Database;
15354
+ var isBun, bunSpec, betterSpec, electronNativeBinding, sqliteModule, RawDatabaseImpl, DatabaseImpl, Database;
15048
15355
  var init_sqlite = __esm(async () => {
15049
15356
  isBun = typeof process !== "undefined" && typeof process.versions?.bun === "string";
15050
15357
  bunSpec = "bun:" + "sqlite";
15051
15358
  betterSpec = "better-" + "sqlite3";
15359
+ electronNativeBinding = isBun ? null : await (async () => {
15360
+ const mod = await Promise.resolve().then(() => (init_native_binding(), exports_native_binding));
15361
+ return mod.resolveBetterSqliteNativeBinding();
15362
+ })();
15052
15363
  sqliteModule = isBun ? await import(bunSpec) : await import(betterSpec);
15053
- DatabaseImpl = isBun ? sqliteModule.Database : sqliteModule.default;
15364
+ RawDatabaseImpl = isBun ? sqliteModule.Database : sqliteModule.default;
15365
+ DatabaseImpl = electronNativeBinding == null ? RawDatabaseImpl : class DatabaseWithElectronBinding extends RawDatabaseImpl {
15366
+ constructor(filename, options) {
15367
+ const fallback = electronNativeBinding;
15368
+ super(filename, {
15369
+ ...options,
15370
+ nativeBinding: options?.nativeBinding ?? fallback
15371
+ });
15372
+ }
15373
+ };
15054
15374
  Database = DatabaseImpl;
15055
15375
  });
15056
15376
 
@@ -15072,9 +15392,9 @@ __export(exports_read_session_db, {
15072
15392
  findLastAssistantModelFromOpenCodeDb: () => findLastAssistantModelFromOpenCodeDb,
15073
15393
  closeReadOnlySessionDb: () => closeReadOnlySessionDb
15074
15394
  });
15075
- import { join as join4 } from "node:path";
15395
+ import { join as join5 } from "node:path";
15076
15396
  function getOpenCodeDbPath() {
15077
- return join4(getDataDir(), "opencode", "opencode.db");
15397
+ return join5(getDataDir(), "opencode", "opencode.db");
15078
15398
  }
15079
15399
  function closeCachedReadOnlyDb() {
15080
15400
  if (!cachedReadOnlyDb) {
@@ -15133,7 +15453,8 @@ function findLastAssistantModelFromOpenCodeDb(sessionId) {
15133
15453
  try {
15134
15454
  return withReadOnlySessionDb((db) => {
15135
15455
  const row = db.prepare(`SELECT json_extract(data, '$.providerID') as providerID,
15136
- json_extract(data, '$.modelID') as modelID
15456
+ json_extract(data, '$.modelID') as modelID,
15457
+ json_extract(data, '$.agent') as agent
15137
15458
  FROM message
15138
15459
  WHERE session_id = ?
15139
15460
  AND json_extract(data, '$.role') = 'assistant'
@@ -15144,7 +15465,12 @@ function findLastAssistantModelFromOpenCodeDb(sessionId) {
15144
15465
  if (!row || typeof row.providerID !== "string" || typeof row.modelID !== "string") {
15145
15466
  return null;
15146
15467
  }
15147
- return { providerID: row.providerID, modelID: row.modelID };
15468
+ const agent = typeof row.agent === "string" && row.agent.length > 0 ? row.agent : undefined;
15469
+ return {
15470
+ providerID: row.providerID,
15471
+ modelID: row.modelID,
15472
+ ...agent ? { agent } : {}
15473
+ };
15148
15474
  });
15149
15475
  } catch (error48) {
15150
15476
  log("[magic-context] failed to recover live model from OpenCode DB:", error48);
@@ -22792,10 +23118,10 @@ var require_stringify = __commonJS((exports, module) => {
22792
23118
  replacer = null;
22793
23119
  indent = EMPTY;
22794
23120
  };
22795
- var join11 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one, gap)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two, gap)), gap) : EMPTY;
23121
+ var join13 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one, gap)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two, gap)), gap) : EMPTY;
22796
23122
  var join_content = (inside, value, gap) => {
22797
23123
  const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
22798
- return join11(comment, inside, gap);
23124
+ return join13(comment, inside, gap);
22799
23125
  };
22800
23126
  var stringify_string = (holder, key, value) => {
22801
23127
  const raw = get_raw_string_literal(holder, key);
@@ -22817,13 +23143,13 @@ var require_stringify = __commonJS((exports, module) => {
22817
23143
  if (i !== 0) {
22818
23144
  inside += COMMA;
22819
23145
  }
22820
- const before = join11(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
23146
+ const before = join13(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
22821
23147
  inside += before || LF + deeper_gap;
22822
23148
  inside += stringify(i, value, deeper_gap) || STR_NULL;
22823
23149
  inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
22824
23150
  after_comma = process_comments(value, AFTER(i), deeper_gap);
22825
23151
  }
22826
- inside += join11(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
23152
+ inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
22827
23153
  return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
22828
23154
  };
22829
23155
  var object_stringify = (value, gap) => {
@@ -22844,13 +23170,13 @@ var require_stringify = __commonJS((exports, module) => {
22844
23170
  inside += COMMA;
22845
23171
  }
22846
23172
  first = false;
22847
- const before = join11(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
23173
+ const before = join13(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
22848
23174
  inside += before || LF + deeper_gap;
22849
23175
  inside += quote(key) + process_comments(value, AFTER_PROP(key), deeper_gap) + COLON + process_comments(value, AFTER_COLON(key), deeper_gap) + SPACE + sv + process_comments(value, AFTER_VALUE(key), deeper_gap);
22850
23176
  after_comma = process_comments(value, AFTER(key), deeper_gap);
22851
23177
  };
22852
23178
  keys.forEach(iteratee);
22853
- inside += join11(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
23179
+ inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
22854
23180
  return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
22855
23181
  };
22856
23182
  function stringify(key, holder, gap) {
@@ -22944,8 +23270,8 @@ var require_src2 = __commonJS((exports, module) => {
22944
23270
 
22945
23271
  // src/index.ts
22946
23272
  init_embedding();
22947
- import { createRequire } from "node:module";
22948
- import { join as join13 } from "node:path";
23273
+ import { createRequire as createRequire2 } from "node:module";
23274
+ import { join as join15 } from "node:path";
22949
23275
 
22950
23276
  // ../plugin/src/features/magic-context/memory/project-identity.ts
22951
23277
  import { execSync } from "node:child_process";
@@ -22985,422 +23311,9 @@ function resolveProjectIdentity(directory) {
22985
23311
  return identity;
22986
23312
  }
22987
23313
 
22988
- // ../plugin/src/features/magic-context/overflow-detection.ts
22989
- var OVERFLOW_PATTERNS = [
22990
- /prompt is too long/i,
22991
- /input is too long for requested model/i,
22992
- /exceeds the context window/i,
22993
- /input token count.*exceeds the maximum/i,
22994
- /maximum prompt length is \d+/i,
22995
- /reduce the length of the messages/i,
22996
- /maximum context length is \d+ tokens/i,
22997
- /exceeds the limit of \d+/i,
22998
- /exceeds the available context size/i,
22999
- /greater than the context length/i,
23000
- /context window exceeds limit/i,
23001
- /exceeded model token limit/i,
23002
- /context[_ ]length[_ ]exceeded/i,
23003
- /request entity too large/i,
23004
- /context length is only \d+ tokens/i,
23005
- /input length.*exceeds.*context length/i,
23006
- /prompt too long; exceeded (?:max )?context length/i,
23007
- /too large for model with \d+ maximum context length/i,
23008
- /model_context_window_exceeded/i,
23009
- /context size has been exceeded/i
23010
- ];
23011
- var LIMIT_EXTRACTION_PATTERNS = [
23012
- /maximum prompt length is (\d+)/i,
23013
- /maximum context length is (\d+) tokens?/i,
23014
- /context length is only (\d+) tokens?/i,
23015
- /exceeds the limit of (\d+)/i,
23016
- /too large for model with (\d+) maximum context length/i,
23017
- /context size.*(\d+) tokens?/i,
23018
- /exceeds? the context length of (\d+)/i,
23019
- /max(?:imum)?.*context.*?(\d+)/i
23020
- ];
23021
- var MIN_PLAUSIBLE_LIMIT = 1024;
23022
- var MAX_PLAUSIBLE_LIMIT = 1e7;
23023
- function extractErrorMessage(error48) {
23024
- if (!error48)
23025
- return "";
23026
- if (typeof error48 === "string")
23027
- return error48;
23028
- if (typeof error48 === "object") {
23029
- const obj = error48;
23030
- const nested = obj.error;
23031
- if (nested && typeof nested.message === "string" && nested.message.length > 0) {
23032
- return nested.message;
23033
- }
23034
- }
23035
- if (error48 instanceof Error)
23036
- return error48.message;
23037
- if (typeof error48 === "object") {
23038
- const obj = error48;
23039
- if (typeof obj.message === "string")
23040
- return obj.message;
23041
- if (typeof obj.responseBody === "string")
23042
- return obj.responseBody;
23043
- try {
23044
- return JSON.stringify(error48);
23045
- } catch {
23046
- return String(error48);
23047
- }
23048
- }
23049
- return String(error48);
23050
- }
23051
- function detectOverflow(error48) {
23052
- const message = extractErrorMessage(error48);
23053
- if (!message) {
23054
- return { isOverflow: false };
23055
- }
23056
- const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
23057
- let matched;
23058
- for (const pattern of OVERFLOW_PATTERNS) {
23059
- if (pattern.test(message)) {
23060
- matched = pattern;
23061
- break;
23062
- }
23063
- }
23064
- if (!matched && !hasStatus413) {
23065
- return { isOverflow: false };
23066
- }
23067
- const reportedLimit = parseReportedLimit(message);
23068
- return {
23069
- isOverflow: true,
23070
- reportedLimit,
23071
- matchedPattern: matched?.source
23072
- };
23073
- }
23074
- function parseReportedLimit(message) {
23075
- if (!message)
23076
- return;
23077
- for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
23078
- const match = message.match(pattern);
23079
- if (!match)
23080
- continue;
23081
- const raw = match[1];
23082
- if (!raw)
23083
- continue;
23084
- const value = Number.parseInt(raw, 10);
23085
- if (!Number.isFinite(value))
23086
- continue;
23087
- if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
23088
- continue;
23089
- return value;
23090
- }
23091
- return;
23092
- }
23093
-
23094
- // ../plugin/src/shared/harness.ts
23095
- var currentHarness = "opencode";
23096
- var harnessLocked = false;
23097
- function setHarness(value) {
23098
- if (harnessLocked && currentHarness !== value) {
23099
- throw new Error(`Magic Context: harness already locked to "${currentHarness}"; cannot change to "${value}"`);
23100
- }
23101
- currentHarness = value;
23102
- harnessLocked = true;
23103
- }
23104
- function getHarness() {
23105
- return currentHarness;
23106
- }
23314
+ // ../plugin/src/features/magic-context/message-index-async.ts
23315
+ init_logger();
23107
23316
 
23108
- // ../plugin/src/features/magic-context/compartment-storage.ts
23109
- var insertCompartmentStatements = new WeakMap;
23110
- var insertFactStatements = new WeakMap;
23111
- function getInsertCompartmentStatement(db) {
23112
- let stmt = insertCompartmentStatements.get(db);
23113
- if (!stmt) {
23114
- stmt = db.prepare("INSERT INTO compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, created_at, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
23115
- insertCompartmentStatements.set(db, stmt);
23116
- }
23117
- return stmt;
23118
- }
23119
- function getInsertFactStatement(db) {
23120
- let stmt = insertFactStatements.get(db);
23121
- if (!stmt) {
23122
- stmt = db.prepare("INSERT INTO session_facts (session_id, category, content, created_at, updated_at, harness) VALUES (?, ?, ?, ?, ?, ?)");
23123
- insertFactStatements.set(db, stmt);
23124
- }
23125
- return stmt;
23126
- }
23127
- function isCompartmentRow(row) {
23128
- if (row === null || typeof row !== "object")
23129
- return false;
23130
- const candidate = row;
23131
- return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number";
23132
- }
23133
- function isSessionFactRow(row) {
23134
- if (row === null || typeof row !== "object")
23135
- return false;
23136
- const candidate = row;
23137
- return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.category === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number" && typeof candidate.updated_at === "number";
23138
- }
23139
- function insertCompartmentRows(db, sessionId, compartments, now) {
23140
- const stmt = getInsertCompartmentStatement(db);
23141
- for (const compartment of compartments) {
23142
- stmt.run(sessionId, compartment.sequence, compartment.startMessage, compartment.endMessage, compartment.startMessageId, compartment.endMessageId, compartment.title, compartment.content, now, getHarness());
23143
- }
23144
- }
23145
- function insertFactRows(db, sessionId, facts, now) {
23146
- const stmt = getInsertFactStatement(db);
23147
- for (const fact of facts) {
23148
- stmt.run(sessionId, fact.category, fact.content, now, now, getHarness());
23149
- }
23150
- }
23151
- function toCompartment(row) {
23152
- return {
23153
- id: row.id,
23154
- sessionId: row.session_id,
23155
- sequence: row.sequence,
23156
- startMessage: row.start_message,
23157
- endMessage: row.end_message,
23158
- startMessageId: row.start_message_id,
23159
- endMessageId: row.end_message_id,
23160
- title: row.title,
23161
- content: row.content,
23162
- createdAt: row.created_at
23163
- };
23164
- }
23165
- function toSessionFact(row) {
23166
- return {
23167
- id: row.id,
23168
- sessionId: row.session_id,
23169
- category: row.category,
23170
- content: row.content,
23171
- createdAt: row.created_at,
23172
- updatedAt: row.updated_at
23173
- };
23174
- }
23175
- function getCompartments(db, sessionId) {
23176
- const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isCompartmentRow);
23177
- return rows.map(toCompartment);
23178
- }
23179
- function getLastCompartmentEndMessage(db, sessionId) {
23180
- const row = db.prepare("SELECT MAX(end_message) as max_end FROM compartments WHERE session_id = ?").get(sessionId);
23181
- return row?.max_end ?? -1;
23182
- }
23183
- function appendCompartments(db, sessionId, compartments) {
23184
- if (compartments.length === 0)
23185
- return;
23186
- const now = Date.now();
23187
- db.transaction(() => {
23188
- insertCompartmentRows(db, sessionId, compartments, now);
23189
- })();
23190
- }
23191
- function replaceSessionFacts(db, sessionId, facts) {
23192
- const now = Date.now();
23193
- db.transaction(() => {
23194
- db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
23195
- insertFactRows(db, sessionId, facts, now);
23196
- db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
23197
- })();
23198
- }
23199
- function getSessionFacts(db, sessionId) {
23200
- const rows = db.prepare("SELECT * FROM session_facts WHERE session_id = ? ORDER BY category ASC, id ASC").all(sessionId).filter(isSessionFactRow);
23201
- return rows.map(toSessionFact);
23202
- }
23203
- function replaceAllCompartmentState(db, sessionId, compartments, facts) {
23204
- const now = Date.now();
23205
- db.transaction(() => {
23206
- db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
23207
- db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
23208
- insertCompartmentRows(db, sessionId, compartments, now);
23209
- insertFactRows(db, sessionId, facts, now);
23210
- db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
23211
- })();
23212
- }
23213
- function buildCompartmentBlock(compartments, facts, memoryBlock, dateRanges) {
23214
- const lines = [];
23215
- if (memoryBlock) {
23216
- lines.push(memoryBlock);
23217
- lines.push("");
23218
- }
23219
- for (const c of compartments) {
23220
- const dates = dateRanges?.byId.get(c.id);
23221
- const dateAttr = dates ? ` start-date="${dates.start}" end-date="${dates.end}"` : "";
23222
- lines.push(`<compartment start="${c.startMessage}" end="${c.endMessage}"${dateAttr} title="${escapeXmlAttr(c.title)}">`);
23223
- lines.push(escapeXmlContent(c.content));
23224
- lines.push("</compartment>");
23225
- lines.push("");
23226
- }
23227
- const factsByCategory = new Map;
23228
- for (const f of facts) {
23229
- const existing = factsByCategory.get(f.category) ?? [];
23230
- existing.push(f.content);
23231
- factsByCategory.set(f.category, existing);
23232
- }
23233
- for (const [category, items] of factsByCategory) {
23234
- lines.push(`${category}:`);
23235
- for (const item of items) {
23236
- lines.push(`* ${escapeXmlContent(item)}`);
23237
- }
23238
- lines.push("");
23239
- }
23240
- return lines.join(`
23241
- `).trimEnd();
23242
- }
23243
- function saveRecompStagingPass(db, sessionId, passNumber, compartments, facts) {
23244
- const now = Date.now();
23245
- db.transaction(() => {
23246
- db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
23247
- const compartmentStmt = db.prepare("INSERT OR REPLACE INTO recomp_compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, pass_number, created_at, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
23248
- for (const c of compartments) {
23249
- compartmentStmt.run(sessionId, c.sequence, c.startMessage, c.endMessage, c.startMessageId, c.endMessageId, c.title, c.content, passNumber, now, getHarness());
23250
- }
23251
- const factStmt = db.prepare("INSERT INTO recomp_facts (session_id, category, content, pass_number, created_at, harness) VALUES (?, ?, ?, ?, ?, ?)");
23252
- for (const f of facts) {
23253
- factStmt.run(sessionId, f.category, f.content, passNumber, now, getHarness());
23254
- }
23255
- })();
23256
- }
23257
- function getRecompStaging(db, sessionId) {
23258
- const compartmentRows = db.prepare("SELECT * FROM recomp_compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isRecompCompartmentRow);
23259
- if (compartmentRows.length === 0)
23260
- return null;
23261
- const compartments = compartmentRows.map((row) => ({
23262
- sequence: row.sequence,
23263
- startMessage: row.start_message,
23264
- endMessage: row.end_message,
23265
- startMessageId: row.start_message_id,
23266
- endMessageId: row.end_message_id,
23267
- title: row.title,
23268
- content: row.content
23269
- }));
23270
- const factRows = db.prepare("SELECT category, content FROM recomp_facts WHERE session_id = ?").all(sessionId).filter(isRecompFactRow);
23271
- const maxPass = compartmentRows.reduce((m, r) => Math.max(m, r.pass_number), 0);
23272
- const lastEnd = compartmentRows[compartmentRows.length - 1]?.end_message ?? 0;
23273
- return {
23274
- compartments,
23275
- facts: factRows,
23276
- passCount: maxPass,
23277
- lastEndMessage: lastEnd
23278
- };
23279
- }
23280
- function promoteRecompStaging(db, sessionId) {
23281
- const now = Date.now();
23282
- return db.transaction(() => {
23283
- const staging = getRecompStaging(db, sessionId);
23284
- if (!staging || staging.compartments.length === 0)
23285
- return null;
23286
- db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
23287
- db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
23288
- insertCompartmentRows(db, sessionId, staging.compartments, now);
23289
- insertFactRows(db, sessionId, staging.facts, now);
23290
- db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
23291
- db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
23292
- db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE session_id = ?").run(sessionId);
23293
- return { compartments: staging.compartments, facts: staging.facts };
23294
- })();
23295
- }
23296
- function invalidateAllMemoryBlockCaches(db) {
23297
- try {
23298
- db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE memory_block_cache != '' OR memory_block_ids != ''").run();
23299
- } catch {}
23300
- }
23301
- function clearRecompStaging(db, sessionId) {
23302
- db.transaction(() => {
23303
- db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
23304
- db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
23305
- try {
23306
- db.prepare("UPDATE session_meta SET recomp_partial_range_start = 0, recomp_partial_range_end = 0 WHERE session_id = ?").run(sessionId);
23307
- } catch {}
23308
- })();
23309
- }
23310
- function getRecompPartialRange(db, sessionId) {
23311
- try {
23312
- const row = db.prepare("SELECT recomp_partial_range_start AS start, recomp_partial_range_end AS end FROM session_meta WHERE session_id = ?").get(sessionId);
23313
- const start = typeof row?.start === "number" ? row.start : 0;
23314
- const end = typeof row?.end === "number" ? row.end : 0;
23315
- if (start <= 0 || end <= 0)
23316
- return null;
23317
- return { start, end };
23318
- } catch {
23319
- return null;
23320
- }
23321
- }
23322
- function setRecompPartialRange(db, sessionId, range) {
23323
- const start = range ? range.start : 0;
23324
- const end = range ? range.end : 0;
23325
- db.prepare("INSERT OR IGNORE INTO session_meta (session_id) VALUES (?)").run(sessionId);
23326
- db.prepare("UPDATE session_meta SET recomp_partial_range_start = ?, recomp_partial_range_end = ? WHERE session_id = ?").run(start, end, sessionId);
23327
- }
23328
- function isRecompCompartmentRow(row) {
23329
- if (row === null || typeof row !== "object")
23330
- return false;
23331
- const candidate = row;
23332
- return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && typeof candidate.pass_number === "number" && typeof candidate.created_at === "number";
23333
- }
23334
- function isRecompFactRow(row) {
23335
- if (row === null || typeof row !== "object")
23336
- return false;
23337
- const candidate = row;
23338
- return typeof candidate.category === "string" && typeof candidate.content === "string";
23339
- }
23340
- function escapeXmlAttr(s) {
23341
- return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&apos;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
23342
- }
23343
- function escapeXmlContent(s) {
23344
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
23345
- }
23346
- // ../plugin/src/features/magic-context/compression-depth-storage.ts
23347
- var incrementDepthStatements = new WeakMap;
23348
- var totalDepthStatements = new WeakMap;
23349
- var maxDepthStatements = new WeakMap;
23350
- var clearDepthStatements = new WeakMap;
23351
- function getIncrementDepthStatement(db) {
23352
- let stmt = incrementDepthStatements.get(db);
23353
- if (!stmt) {
23354
- stmt = db.prepare("INSERT INTO compression_depth (session_id, message_ordinal, depth, harness) VALUES (?, ?, 1, ?) ON CONFLICT(session_id, message_ordinal) DO UPDATE SET depth = depth + 1");
23355
- incrementDepthStatements.set(db, stmt);
23356
- }
23357
- return stmt;
23358
- }
23359
- function getTotalDepthStatement(db) {
23360
- let stmt = totalDepthStatements.get(db);
23361
- if (!stmt) {
23362
- stmt = db.prepare("SELECT COALESCE(SUM(depth), 0) AS total_depth FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?");
23363
- totalDepthStatements.set(db, stmt);
23364
- }
23365
- return stmt;
23366
- }
23367
- function getClearDepthStatement(db) {
23368
- let stmt = clearDepthStatements.get(db);
23369
- if (!stmt) {
23370
- stmt = db.prepare("DELETE FROM compression_depth WHERE session_id = ?");
23371
- clearDepthStatements.set(db, stmt);
23372
- }
23373
- return stmt;
23374
- }
23375
- function incrementCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
23376
- if (endOrdinal < startOrdinal) {
23377
- return;
23378
- }
23379
- db.transaction(() => {
23380
- const stmt = getIncrementDepthStatement(db);
23381
- for (let ordinal = startOrdinal;ordinal <= endOrdinal; ordinal += 1) {
23382
- stmt.run(sessionId, ordinal, getHarness());
23383
- }
23384
- })();
23385
- }
23386
- function getAverageCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
23387
- if (endOrdinal < startOrdinal) {
23388
- return 0;
23389
- }
23390
- const row = getTotalDepthStatement(db).get(sessionId, startOrdinal, endOrdinal);
23391
- const totalDepth = typeof row?.total_depth === "number" ? row.total_depth : 0;
23392
- const messageCount = endOrdinal - startOrdinal + 1;
23393
- return totalDepth / messageCount;
23394
- }
23395
- function clearCompressionDepth(db, sessionId) {
23396
- getClearDepthStatement(db).run(sessionId);
23397
- }
23398
- function clearCompressionDepthRange(db, sessionId, startOrdinal, endOrdinal) {
23399
- if (endOrdinal < startOrdinal) {
23400
- return;
23401
- }
23402
- db.prepare("DELETE FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?").run(sessionId, startOrdinal, endOrdinal);
23403
- }
23404
23317
  // ../plugin/src/shared/internal-initiator-marker.ts
23405
23318
  var OMO_INTERNAL_INITIATOR_MARKER = "<!-- OMO_INTERNAL_INITIATOR -->";
23406
23319
 
@@ -156078,21 +155991,85 @@ function isTextPart(part) {
156078
155991
  const p = part;
156079
155992
  return p.type === "text" && typeof p.text === "string";
156080
155993
  }
156081
- function isToolPartWithOutput(part) {
155994
+ function isFilePart(part) {
156082
155995
  if (part === null || typeof part !== "object")
156083
155996
  return false;
156084
155997
  const p = part;
156085
- if (p.type !== "tool" || typeof p.callID !== "string")
155998
+ return p.type === "file" && typeof p.url === "string";
155999
+ }
156000
+
156001
+ // ../plugin/src/shared/record-type-guard.ts
156002
+ function isRecord(value) {
156003
+ return typeof value === "object" && value !== null && !Array.isArray(value);
156004
+ }
156005
+
156006
+ // ../plugin/src/hooks/magic-context/tool-drop-target.ts
156007
+ var IGNORE_PART_TYPES = new Set([
156008
+ "thinking",
156009
+ "reasoning",
156010
+ "redacted_thinking",
156011
+ "meta",
156012
+ "step-start",
156013
+ "step-finish"
156014
+ ]);
156015
+ function isToolCallId(value) {
156016
+ return typeof value === "string" && value.length > 0;
156017
+ }
156018
+ function hasMeaningfulPart(part) {
156019
+ if (!isRecord(part))
156086
156020
  return false;
156087
- if (p.state === null || typeof p.state !== "object")
156021
+ const type = part.type;
156022
+ if (type === "text") {
156023
+ return typeof part.text === "string" && part.text.trim().length > 0;
156024
+ }
156025
+ if (typeof type !== "string")
156088
156026
  return false;
156089
- return typeof p.state.output === "string";
156090
- }
156091
- function isFilePart(part) {
156092
- if (part === null || typeof part !== "object")
156027
+ if (IGNORE_PART_TYPES.has(type))
156093
156028
  return false;
156094
- const p = part;
156095
- return p.type === "file" && typeof p.url === "string";
156029
+ return true;
156030
+ }
156031
+ function extractToolCallObservation(part) {
156032
+ if (!isRecord(part))
156033
+ return null;
156034
+ if (part.type === "tool" && isToolCallId(part.callID)) {
156035
+ return { callId: part.callID, kind: "result" };
156036
+ }
156037
+ if (part.type === "tool-invocation" && isToolCallId(part.callID)) {
156038
+ return { callId: part.callID, kind: "invocation" };
156039
+ }
156040
+ if (part.type === "tool_use" && isToolCallId(part.id)) {
156041
+ return { callId: part.id, kind: "invocation" };
156042
+ }
156043
+ if (part.type === "tool_result" && isToolCallId(part.tool_use_id)) {
156044
+ return { callId: part.tool_use_id, kind: "result" };
156045
+ }
156046
+ return null;
156047
+ }
156048
+ class ToolMutationBatch {
156049
+ partsToRemove = new Set;
156050
+ affectedMessages = new Set;
156051
+ messages;
156052
+ constructor(messages) {
156053
+ this.messages = messages;
156054
+ }
156055
+ markForRemoval(occurrence) {
156056
+ this.partsToRemove.add(occurrence.part);
156057
+ this.affectedMessages.add(occurrence.message);
156058
+ }
156059
+ finalize() {
156060
+ if (this.partsToRemove.size === 0)
156061
+ return;
156062
+ for (const message of this.affectedMessages) {
156063
+ message.parts = message.parts.filter((p) => !this.partsToRemove.has(p));
156064
+ }
156065
+ for (let i = this.messages.length - 1;i >= 0; i -= 1) {
156066
+ if (!this.messages[i].parts.some(hasMeaningfulPart)) {
156067
+ this.messages.splice(i, 1);
156068
+ }
156069
+ }
156070
+ this.partsToRemove.clear();
156071
+ this.affectedMessages.clear();
156072
+ }
156096
156073
  }
156097
156074
 
156098
156075
  // ../plugin/src/hooks/magic-context/read-session-chunk.ts
@@ -156159,23 +156136,47 @@ function getRawSessionMessageCount(sessionId) {
156159
156136
  }
156160
156137
  function getRawSessionTagKeysThrough(sessionId, upToMessageIndex) {
156161
156138
  const messages = readRawSessionMessages(sessionId);
156162
- const keys = [];
156139
+ const messageFileKeys = new Set;
156140
+ const toolObservations = new Map;
156141
+ const unpairedInvocations = new Map;
156163
156142
  for (const message of messages) {
156164
156143
  if (message.ordinal > upToMessageIndex)
156165
156144
  break;
156166
156145
  for (const [partIndex, part] of message.parts.entries()) {
156167
156146
  if (isTextPart(part)) {
156168
- keys.push(`${message.id}:p${partIndex}`);
156147
+ messageFileKeys.add(`${message.id}:p${partIndex}`);
156148
+ continue;
156169
156149
  }
156170
156150
  if (isFilePart(part)) {
156171
- keys.push(`${message.id}:file${partIndex}`);
156151
+ messageFileKeys.add(`${message.id}:file${partIndex}`);
156152
+ continue;
156172
156153
  }
156173
- if (isToolPartWithOutput(part)) {
156174
- keys.push(part.callID);
156154
+ const obs = extractToolCallObservation(part);
156155
+ if (!obs)
156156
+ continue;
156157
+ let ownerMsgId;
156158
+ if (obs.kind === "invocation") {
156159
+ ownerMsgId = message.id;
156160
+ const queue = unpairedInvocations.get(obs.callId) ?? [];
156161
+ queue.push(message.id);
156162
+ unpairedInvocations.set(obs.callId, queue);
156163
+ } else {
156164
+ const queue = unpairedInvocations.get(obs.callId);
156165
+ if (queue && queue.length > 0) {
156166
+ const popped = queue.shift();
156167
+ if (queue.length === 0)
156168
+ unpairedInvocations.delete(obs.callId);
156169
+ ownerMsgId = popped ?? message.id;
156170
+ } else {
156171
+ ownerMsgId = message.id;
156172
+ }
156175
156173
  }
156174
+ const owners = toolObservations.get(obs.callId) ?? new Set;
156175
+ owners.add(ownerMsgId);
156176
+ toolObservations.set(obs.callId, owners);
156176
156177
  }
156177
156178
  }
156178
- return keys;
156179
+ return { messageFileKeys, toolObservations };
156179
156180
  }
156180
156181
  var PROTECTED_TAIL_USER_TURNS = 5;
156181
156182
  function getProtectedTailStartOrdinal(sessionId) {
@@ -156324,6 +156325,79 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
156324
156325
  };
156325
156326
  }
156326
156327
 
156328
+ // ../plugin/src/shared/harness.ts
156329
+ var currentHarness = "opencode";
156330
+ var harnessLocked = false;
156331
+ function setHarness(value) {
156332
+ if (harnessLocked && currentHarness !== value) {
156333
+ throw new Error(`Magic Context: harness already locked to "${currentHarness}"; cannot change to "${value}"`);
156334
+ }
156335
+ currentHarness = value;
156336
+ harnessLocked = true;
156337
+ }
156338
+ function getHarness() {
156339
+ return currentHarness;
156340
+ }
156341
+
156342
+ // ../plugin/src/features/magic-context/compression-depth-storage.ts
156343
+ var incrementDepthStatements = new WeakMap;
156344
+ var totalDepthStatements = new WeakMap;
156345
+ var maxDepthStatements = new WeakMap;
156346
+ var clearDepthStatements = new WeakMap;
156347
+ function getIncrementDepthStatement(db) {
156348
+ let stmt = incrementDepthStatements.get(db);
156349
+ if (!stmt) {
156350
+ stmt = db.prepare("INSERT INTO compression_depth (session_id, message_ordinal, depth, harness) VALUES (?, ?, 1, ?) ON CONFLICT(session_id, message_ordinal) DO UPDATE SET depth = depth + 1");
156351
+ incrementDepthStatements.set(db, stmt);
156352
+ }
156353
+ return stmt;
156354
+ }
156355
+ function getTotalDepthStatement(db) {
156356
+ let stmt = totalDepthStatements.get(db);
156357
+ if (!stmt) {
156358
+ stmt = db.prepare("SELECT COALESCE(SUM(depth), 0) AS total_depth FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?");
156359
+ totalDepthStatements.set(db, stmt);
156360
+ }
156361
+ return stmt;
156362
+ }
156363
+ function getClearDepthStatement(db) {
156364
+ let stmt = clearDepthStatements.get(db);
156365
+ if (!stmt) {
156366
+ stmt = db.prepare("DELETE FROM compression_depth WHERE session_id = ?");
156367
+ clearDepthStatements.set(db, stmt);
156368
+ }
156369
+ return stmt;
156370
+ }
156371
+ function incrementCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
156372
+ if (endOrdinal < startOrdinal) {
156373
+ return;
156374
+ }
156375
+ db.transaction(() => {
156376
+ const stmt = getIncrementDepthStatement(db);
156377
+ for (let ordinal = startOrdinal;ordinal <= endOrdinal; ordinal += 1) {
156378
+ stmt.run(sessionId, ordinal, getHarness());
156379
+ }
156380
+ })();
156381
+ }
156382
+ function getAverageCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
156383
+ if (endOrdinal < startOrdinal) {
156384
+ return 0;
156385
+ }
156386
+ const row = getTotalDepthStatement(db).get(sessionId, startOrdinal, endOrdinal);
156387
+ const totalDepth = typeof row?.total_depth === "number" ? row.total_depth : 0;
156388
+ const messageCount = endOrdinal - startOrdinal + 1;
156389
+ return totalDepth / messageCount;
156390
+ }
156391
+ function clearCompressionDepth(db, sessionId) {
156392
+ getClearDepthStatement(db).run(sessionId);
156393
+ }
156394
+ function clearCompressionDepthRange(db, sessionId, startOrdinal, endOrdinal) {
156395
+ if (endOrdinal < startOrdinal) {
156396
+ return;
156397
+ }
156398
+ db.prepare("DELETE FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?").run(sessionId, startOrdinal, endOrdinal);
156399
+ }
156400
+
156327
156401
  // ../plugin/src/features/magic-context/message-index.ts
156328
156402
  var lastIndexedStatements = new WeakMap;
156329
156403
  var insertMessageStatements = new WeakMap;
@@ -156331,6 +156405,7 @@ var upsertIndexStatements = new WeakMap;
156331
156405
  var deleteFtsStatements = new WeakMap;
156332
156406
  var deleteIndexStatements = new WeakMap;
156333
156407
  var countIndexedMessageStatements = new WeakMap;
156408
+ var indexedMessageIdStatements = new WeakMap;
156334
156409
  function normalizeIndexText(text) {
156335
156410
  return text.replace(/\s+/g, " ").trim();
156336
156411
  }
@@ -156374,10 +156449,34 @@ function getDeleteIndexStatement(db) {
156374
156449
  }
156375
156450
  return stmt;
156376
156451
  }
156452
+ function getCountIndexedMessageStatement(db) {
156453
+ let stmt = countIndexedMessageStatements.get(db);
156454
+ if (!stmt) {
156455
+ stmt = db.prepare("SELECT COUNT(*) AS count FROM message_history_fts WHERE session_id = ? AND message_id = ?");
156456
+ countIndexedMessageStatements.set(db, stmt);
156457
+ }
156458
+ return stmt;
156459
+ }
156460
+ function getIndexedMessageIdStatement(db) {
156461
+ let stmt = indexedMessageIdStatements.get(db);
156462
+ if (!stmt) {
156463
+ stmt = db.prepare("SELECT message_id AS messageId FROM message_history_fts WHERE session_id = ?");
156464
+ indexedMessageIdStatements.set(db, stmt);
156465
+ }
156466
+ return stmt;
156467
+ }
156377
156468
  function getLastIndexedOrdinal(db, sessionId) {
156378
156469
  const row = getLastIndexedStatement(db).get(sessionId);
156379
156470
  return typeof row?.last_indexed_ordinal === "number" ? row.last_indexed_ordinal : 0;
156380
156471
  }
156472
+ function isMessageAlreadyIndexed(db, sessionId, messageId) {
156473
+ const row = getCountIndexedMessageStatement(db).get(sessionId, messageId);
156474
+ return (typeof row?.count === "number" ? row.count : 0) > 0;
156475
+ }
156476
+ function advanceIndexWatermark(db, sessionId, ordinal, now) {
156477
+ const current = getLastIndexedOrdinal(db, sessionId);
156478
+ getUpsertIndexStatement(db).run(sessionId, Math.max(current, ordinal), now, getHarness());
156479
+ }
156381
156480
  function clearIndexedMessages(db, sessionId) {
156382
156481
  db.transaction(() => {
156383
156482
  getDeleteFtsStatement(db).run(sessionId);
@@ -156397,39 +156496,510 @@ function getIndexableContent(role, parts) {
156397
156496
  }
156398
156497
  return "";
156399
156498
  }
156400
- function ensureMessagesIndexed(db, sessionId, readMessages) {
156401
- const messages = readMessages(sessionId);
156402
- if (messages.length === 0) {
156403
- db.transaction(() => clearIndexedMessages(db, sessionId))();
156499
+ function indexSingleMessageInTransaction(db, sessionId, message, now) {
156500
+ if (message.role !== "user" && message.role !== "assistant") {
156501
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
156502
+ return false;
156503
+ }
156504
+ const content = getIndexableContent(message.role, message.parts);
156505
+ if (content.length === 0) {
156506
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
156507
+ return false;
156508
+ }
156509
+ if (isMessageAlreadyIndexed(db, sessionId, message.id)) {
156510
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
156511
+ return false;
156512
+ }
156513
+ getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
156514
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
156515
+ return true;
156516
+ }
156517
+ function indexSingleMessage(db, sessionId, message) {
156518
+ return db.transaction(() => indexSingleMessageInTransaction(db, sessionId, message, Date.now()))();
156519
+ }
156520
+ function indexMessagesAfterOrdinal(db, sessionId, messages, lastIndexedOrdinal, finalWatermark = messages.length) {
156521
+ const now = Date.now();
156522
+ let inserted = 0;
156523
+ db.transaction(() => {
156524
+ const existingMessageIds = new Set(getIndexedMessageIdStatement(db).all(sessionId).map((row) => row.messageId).filter((messageId) => typeof messageId === "string"));
156525
+ const insertMessage = getInsertMessageStatement(db);
156526
+ for (const message of messages) {
156527
+ if (message.ordinal <= lastIndexedOrdinal) {
156528
+ continue;
156529
+ }
156530
+ if (message.role !== "user" && message.role !== "assistant") {
156531
+ continue;
156532
+ }
156533
+ const content = getIndexableContent(message.role, message.parts);
156534
+ if (content.length === 0 || existingMessageIds.has(message.id)) {
156535
+ continue;
156536
+ }
156537
+ insertMessage.run(sessionId, message.ordinal, message.id, message.role, content);
156538
+ existingMessageIds.add(message.id);
156539
+ inserted++;
156540
+ }
156541
+ getUpsertIndexStatement(db).run(sessionId, finalWatermark, now, getHarness());
156542
+ })();
156543
+ return inserted;
156544
+ }
156545
+
156546
+ // ../plugin/src/features/magic-context/message-index-async.ts
156547
+ var INCREMENTAL_DEBOUNCE_MS = 100;
156548
+ var reconciledSessions = new Set;
156549
+ var reconciliationScheduledSessions = new Set;
156550
+ var sessionLocks = new Map;
156551
+ var incrementalTimers = new Map;
156552
+ var pendingIncrementalKeys = new Set;
156553
+ function defer(fn) {
156554
+ const immediate = globalThis.setImmediate;
156555
+ if (typeof immediate === "function") {
156556
+ immediate(fn);
156404
156557
  return;
156405
156558
  }
156406
- let lastIndexedOrdinal = getLastIndexedOrdinal(db, sessionId);
156407
- if (lastIndexedOrdinal > messages.length) {
156408
- db.transaction(() => clearIndexedMessages(db, sessionId))();
156409
- lastIndexedOrdinal = 0;
156559
+ setTimeout(fn, 0);
156560
+ }
156561
+ function runWithSessionLock(sessionId, operation) {
156562
+ const previous = sessionLocks.get(sessionId) ?? Promise.resolve();
156563
+ const run = previous.catch(() => {
156564
+ return;
156565
+ }).then(async () => {
156566
+ await operation();
156567
+ });
156568
+ sessionLocks.set(sessionId, run);
156569
+ run.finally(() => {
156570
+ if (sessionLocks.get(sessionId) === run) {
156571
+ sessionLocks.delete(sessionId);
156572
+ }
156573
+ }).catch(() => {
156574
+ return;
156575
+ });
156576
+ return run;
156577
+ }
156578
+ function logIndexingError(sessionId, action, error48) {
156579
+ sessionLog(sessionId, `message FTS async ${action} failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
156580
+ log(`[message-index-async] ${action} failed for ${sessionId}:`, error48);
156581
+ }
156582
+ async function reconcileSessionIndex(db, sessionId, readMessages) {
156583
+ await runWithSessionLock(sessionId, () => {
156584
+ if (reconciledSessions.has(sessionId)) {
156585
+ return;
156586
+ }
156587
+ const messages = readMessages(sessionId);
156588
+ if (messages.length === 0) {
156589
+ clearIndexedMessages(db, sessionId);
156590
+ reconciledSessions.add(sessionId);
156591
+ return;
156592
+ }
156593
+ let lastIndexedOrdinal = getLastIndexedOrdinal(db, sessionId);
156594
+ if (lastIndexedOrdinal > messages.length) {
156595
+ clearIndexedMessages(db, sessionId);
156596
+ lastIndexedOrdinal = 0;
156597
+ }
156598
+ const watermark = Math.min(lastIndexedOrdinal, messages.length);
156599
+ indexMessagesAfterOrdinal(db, sessionId, messages, watermark, messages.length);
156600
+ reconciledSessions.add(sessionId);
156601
+ });
156602
+ }
156603
+ function scheduleReconciliation(db, sessionId, readMessages) {
156604
+ if (reconciledSessions.has(sessionId) || reconciliationScheduledSessions.has(sessionId)) {
156605
+ return;
156410
156606
  }
156411
- if (lastIndexedOrdinal >= messages.length) {
156607
+ reconciliationScheduledSessions.add(sessionId);
156608
+ defer(() => {
156609
+ reconcileSessionIndex(db, sessionId, readMessages).catch((error48) => {
156610
+ reconciliationScheduledSessions.delete(sessionId);
156611
+ logIndexingError(sessionId, "reconciliation", error48);
156612
+ });
156613
+ });
156614
+ }
156615
+ function scheduleIncrementalIndex(db, sessionId, messageId, readSingleMessage) {
156616
+ const key = `${sessionId}\x00${messageId}`;
156617
+ if (incrementalTimers.has(key) || pendingIncrementalKeys.has(key)) {
156412
156618
  return;
156413
156619
  }
156414
- const messagesToInsert = messages.filter((message) => message.ordinal > lastIndexedOrdinal).filter((message) => message.role === "user" || message.role === "assistant").map((message) => ({
156415
- ordinal: message.ordinal,
156416
- id: message.id,
156417
- role: message.role,
156418
- content: getIndexableContent(message.role, message.parts)
156419
- })).filter((message) => message.content.length > 0);
156620
+ const timer = setTimeout(() => {
156621
+ incrementalTimers.delete(key);
156622
+ pendingIncrementalKeys.add(key);
156623
+ runWithSessionLock(sessionId, () => {
156624
+ const message = readSingleMessage(sessionId, messageId);
156625
+ if (!message) {
156626
+ return;
156627
+ }
156628
+ indexSingleMessage(db, sessionId, message);
156629
+ }).catch((error48) => {
156630
+ logIndexingError(sessionId, `incremental index for ${messageId}`, error48);
156631
+ }).finally(() => {
156632
+ pendingIncrementalKeys.delete(key);
156633
+ });
156634
+ }, INCREMENTAL_DEBOUNCE_MS);
156635
+ incrementalTimers.set(key, timer);
156636
+ }
156637
+ function clearSessionTracking(sessionId) {
156638
+ reconciledSessions.delete(sessionId);
156639
+ reconciliationScheduledSessions.delete(sessionId);
156640
+ sessionLocks.delete(sessionId);
156641
+ const prefix = `${sessionId}\x00`;
156642
+ for (const [key, timer] of incrementalTimers) {
156643
+ if (key.startsWith(prefix)) {
156644
+ clearTimeout(timer);
156645
+ incrementalTimers.delete(key);
156646
+ }
156647
+ }
156648
+ for (const key of pendingIncrementalKeys) {
156649
+ if (key.startsWith(prefix)) {
156650
+ pendingIncrementalKeys.delete(key);
156651
+ }
156652
+ }
156653
+ }
156654
+
156655
+ // ../plugin/src/features/magic-context/overflow-detection.ts
156656
+ var OVERFLOW_PATTERNS = [
156657
+ /prompt is too long/i,
156658
+ /input is too long for requested model/i,
156659
+ /exceeds the context window/i,
156660
+ /input token count.*exceeds the maximum/i,
156661
+ /maximum prompt length is \d+/i,
156662
+ /reduce the length of the messages/i,
156663
+ /maximum context length is \d+ tokens/i,
156664
+ /exceeds the limit of \d+/i,
156665
+ /exceeds the available context size/i,
156666
+ /greater than the context length/i,
156667
+ /context window exceeds limit/i,
156668
+ /exceeded model token limit/i,
156669
+ /context[_ ]length[_ ]exceeded/i,
156670
+ /request entity too large/i,
156671
+ /context length is only \d+ tokens/i,
156672
+ /input length.*exceeds.*context length/i,
156673
+ /prompt too long; exceeded (?:max )?context length/i,
156674
+ /too large for model with \d+ maximum context length/i,
156675
+ /model_context_window_exceeded/i,
156676
+ /context size has been exceeded/i
156677
+ ];
156678
+ var LIMIT_EXTRACTION_PATTERNS = [
156679
+ /maximum prompt length is (\d+)/i,
156680
+ /maximum context length is (\d+) tokens?/i,
156681
+ /context length is only (\d+) tokens?/i,
156682
+ /exceeds the limit of (\d+)/i,
156683
+ /too large for model with (\d+) maximum context length/i,
156684
+ /context size.*(\d+) tokens?/i,
156685
+ /exceeds? the context length of (\d+)/i,
156686
+ /max(?:imum)?.*context.*?(\d+)/i
156687
+ ];
156688
+ var MIN_PLAUSIBLE_LIMIT = 1024;
156689
+ var MAX_PLAUSIBLE_LIMIT = 1e7;
156690
+ function extractErrorMessage(error48) {
156691
+ if (!error48)
156692
+ return "";
156693
+ if (typeof error48 === "string")
156694
+ return error48;
156695
+ if (typeof error48 === "object") {
156696
+ const obj = error48;
156697
+ const nested = obj.error;
156698
+ if (nested && typeof nested.message === "string" && nested.message.length > 0) {
156699
+ return nested.message;
156700
+ }
156701
+ }
156702
+ if (error48 instanceof Error)
156703
+ return error48.message;
156704
+ if (typeof error48 === "object") {
156705
+ const obj = error48;
156706
+ if (typeof obj.message === "string")
156707
+ return obj.message;
156708
+ if (typeof obj.responseBody === "string")
156709
+ return obj.responseBody;
156710
+ try {
156711
+ return JSON.stringify(error48);
156712
+ } catch {
156713
+ return String(error48);
156714
+ }
156715
+ }
156716
+ return String(error48);
156717
+ }
156718
+ function detectOverflow(error48) {
156719
+ const message = extractErrorMessage(error48);
156720
+ if (!message) {
156721
+ return { isOverflow: false };
156722
+ }
156723
+ const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
156724
+ let matched;
156725
+ for (const pattern of OVERFLOW_PATTERNS) {
156726
+ if (pattern.test(message)) {
156727
+ matched = pattern;
156728
+ break;
156729
+ }
156730
+ }
156731
+ if (!matched && !hasStatus413) {
156732
+ return { isOverflow: false };
156733
+ }
156734
+ const reportedLimit = parseReportedLimit(message);
156735
+ return {
156736
+ isOverflow: true,
156737
+ reportedLimit,
156738
+ matchedPattern: matched?.source
156739
+ };
156740
+ }
156741
+ function parseReportedLimit(message) {
156742
+ if (!message)
156743
+ return;
156744
+ for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
156745
+ const match = message.match(pattern);
156746
+ if (!match)
156747
+ continue;
156748
+ const raw = match[1];
156749
+ if (!raw)
156750
+ continue;
156751
+ const value = Number.parseInt(raw, 10);
156752
+ if (!Number.isFinite(value))
156753
+ continue;
156754
+ if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
156755
+ continue;
156756
+ return value;
156757
+ }
156758
+ return;
156759
+ }
156760
+
156761
+ // ../plugin/src/features/magic-context/compartment-storage.ts
156762
+ var insertCompartmentStatements = new WeakMap;
156763
+ var insertFactStatements = new WeakMap;
156764
+ function getInsertCompartmentStatement(db) {
156765
+ let stmt = insertCompartmentStatements.get(db);
156766
+ if (!stmt) {
156767
+ stmt = db.prepare("INSERT INTO compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, created_at, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
156768
+ insertCompartmentStatements.set(db, stmt);
156769
+ }
156770
+ return stmt;
156771
+ }
156772
+ function getInsertFactStatement(db) {
156773
+ let stmt = insertFactStatements.get(db);
156774
+ if (!stmt) {
156775
+ stmt = db.prepare("INSERT INTO session_facts (session_id, category, content, created_at, updated_at, harness) VALUES (?, ?, ?, ?, ?, ?)");
156776
+ insertFactStatements.set(db, stmt);
156777
+ }
156778
+ return stmt;
156779
+ }
156780
+ function isCompartmentRow(row) {
156781
+ if (row === null || typeof row !== "object")
156782
+ return false;
156783
+ const candidate = row;
156784
+ return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number";
156785
+ }
156786
+ function isSessionFactRow(row) {
156787
+ if (row === null || typeof row !== "object")
156788
+ return false;
156789
+ const candidate = row;
156790
+ return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.category === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number" && typeof candidate.updated_at === "number";
156791
+ }
156792
+ function insertCompartmentRows(db, sessionId, compartments, now) {
156793
+ const stmt = getInsertCompartmentStatement(db);
156794
+ for (const compartment of compartments) {
156795
+ stmt.run(sessionId, compartment.sequence, compartment.startMessage, compartment.endMessage, compartment.startMessageId, compartment.endMessageId, compartment.title, compartment.content, now, getHarness());
156796
+ }
156797
+ }
156798
+ function insertFactRows(db, sessionId, facts, now) {
156799
+ const stmt = getInsertFactStatement(db);
156800
+ for (const fact of facts) {
156801
+ stmt.run(sessionId, fact.category, fact.content, now, now, getHarness());
156802
+ }
156803
+ }
156804
+ function toCompartment(row) {
156805
+ return {
156806
+ id: row.id,
156807
+ sessionId: row.session_id,
156808
+ sequence: row.sequence,
156809
+ startMessage: row.start_message,
156810
+ endMessage: row.end_message,
156811
+ startMessageId: row.start_message_id,
156812
+ endMessageId: row.end_message_id,
156813
+ title: row.title,
156814
+ content: row.content,
156815
+ createdAt: row.created_at
156816
+ };
156817
+ }
156818
+ function toSessionFact(row) {
156819
+ return {
156820
+ id: row.id,
156821
+ sessionId: row.session_id,
156822
+ category: row.category,
156823
+ content: row.content,
156824
+ createdAt: row.created_at,
156825
+ updatedAt: row.updated_at
156826
+ };
156827
+ }
156828
+ function getCompartments(db, sessionId) {
156829
+ const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isCompartmentRow);
156830
+ return rows.map(toCompartment);
156831
+ }
156832
+ function getLastCompartmentEndMessage(db, sessionId) {
156833
+ const row = db.prepare("SELECT MAX(end_message) as max_end FROM compartments WHERE session_id = ?").get(sessionId);
156834
+ return row?.max_end ?? -1;
156835
+ }
156836
+ function appendCompartments(db, sessionId, compartments) {
156837
+ if (compartments.length === 0)
156838
+ return;
156420
156839
  const now = Date.now();
156421
156840
  db.transaction(() => {
156422
- const insertMessage = getInsertMessageStatement(db);
156423
- for (const message of messagesToInsert) {
156424
- insertMessage.run(sessionId, message.ordinal, message.id, message.role, message.content);
156841
+ insertCompartmentRows(db, sessionId, compartments, now);
156842
+ })();
156843
+ }
156844
+ function replaceSessionFacts(db, sessionId, facts) {
156845
+ const now = Date.now();
156846
+ db.transaction(() => {
156847
+ db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
156848
+ insertFactRows(db, sessionId, facts, now);
156849
+ db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
156850
+ })();
156851
+ }
156852
+ function getSessionFacts(db, sessionId) {
156853
+ const rows = db.prepare("SELECT * FROM session_facts WHERE session_id = ? ORDER BY category ASC, id ASC").all(sessionId).filter(isSessionFactRow);
156854
+ return rows.map(toSessionFact);
156855
+ }
156856
+ function replaceAllCompartmentState(db, sessionId, compartments, facts) {
156857
+ const now = Date.now();
156858
+ db.transaction(() => {
156859
+ db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
156860
+ db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
156861
+ insertCompartmentRows(db, sessionId, compartments, now);
156862
+ insertFactRows(db, sessionId, facts, now);
156863
+ db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
156864
+ })();
156865
+ }
156866
+ function buildCompartmentBlock(compartments, facts, memoryBlock, dateRanges) {
156867
+ const lines = [];
156868
+ if (memoryBlock) {
156869
+ lines.push(memoryBlock);
156870
+ lines.push("");
156871
+ }
156872
+ for (const c of compartments) {
156873
+ const dates = dateRanges?.byId.get(c.id);
156874
+ const dateAttr = dates ? ` start-date="${dates.start}" end-date="${dates.end}"` : "";
156875
+ lines.push(`<compartment start="${c.startMessage}" end="${c.endMessage}"${dateAttr} title="${escapeXmlAttr(c.title)}">`);
156876
+ lines.push(escapeXmlContent(c.content));
156877
+ lines.push("</compartment>");
156878
+ lines.push("");
156879
+ }
156880
+ const factsByCategory = new Map;
156881
+ for (const f of facts) {
156882
+ const existing = factsByCategory.get(f.category) ?? [];
156883
+ existing.push(f.content);
156884
+ factsByCategory.set(f.category, existing);
156885
+ }
156886
+ for (const [category, items] of factsByCategory) {
156887
+ lines.push(`${category}:`);
156888
+ for (const item of items) {
156889
+ lines.push(`* ${escapeXmlContent(item)}`);
156890
+ }
156891
+ lines.push("");
156892
+ }
156893
+ return lines.join(`
156894
+ `).trimEnd();
156895
+ }
156896
+ function saveRecompStagingPass(db, sessionId, passNumber, compartments, facts) {
156897
+ const now = Date.now();
156898
+ db.transaction(() => {
156899
+ db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
156900
+ const compartmentStmt = db.prepare("INSERT OR REPLACE INTO recomp_compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, pass_number, created_at, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
156901
+ for (const c of compartments) {
156902
+ compartmentStmt.run(sessionId, c.sequence, c.startMessage, c.endMessage, c.startMessageId, c.endMessageId, c.title, c.content, passNumber, now, getHarness());
156903
+ }
156904
+ const factStmt = db.prepare("INSERT INTO recomp_facts (session_id, category, content, pass_number, created_at, harness) VALUES (?, ?, ?, ?, ?, ?)");
156905
+ for (const f of facts) {
156906
+ factStmt.run(sessionId, f.category, f.content, passNumber, now, getHarness());
156425
156907
  }
156426
- getUpsertIndexStatement(db).run(sessionId, messages.length, now, getHarness());
156427
156908
  })();
156428
156909
  }
156910
+ function getRecompStaging(db, sessionId) {
156911
+ const compartmentRows = db.prepare("SELECT * FROM recomp_compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isRecompCompartmentRow);
156912
+ if (compartmentRows.length === 0)
156913
+ return null;
156914
+ const compartments = compartmentRows.map((row) => ({
156915
+ sequence: row.sequence,
156916
+ startMessage: row.start_message,
156917
+ endMessage: row.end_message,
156918
+ startMessageId: row.start_message_id,
156919
+ endMessageId: row.end_message_id,
156920
+ title: row.title,
156921
+ content: row.content
156922
+ }));
156923
+ const factRows = db.prepare("SELECT category, content FROM recomp_facts WHERE session_id = ?").all(sessionId).filter(isRecompFactRow);
156924
+ const maxPass = compartmentRows.reduce((m, r) => Math.max(m, r.pass_number), 0);
156925
+ const lastEnd = compartmentRows[compartmentRows.length - 1]?.end_message ?? 0;
156926
+ return {
156927
+ compartments,
156928
+ facts: factRows,
156929
+ passCount: maxPass,
156930
+ lastEndMessage: lastEnd
156931
+ };
156932
+ }
156933
+ function promoteRecompStaging(db, sessionId) {
156934
+ const now = Date.now();
156935
+ return db.transaction(() => {
156936
+ const staging = getRecompStaging(db, sessionId);
156937
+ if (!staging || staging.compartments.length === 0)
156938
+ return null;
156939
+ db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
156940
+ db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
156941
+ insertCompartmentRows(db, sessionId, staging.compartments, now);
156942
+ insertFactRows(db, sessionId, staging.facts, now);
156943
+ db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
156944
+ db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
156945
+ db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE session_id = ?").run(sessionId);
156946
+ return { compartments: staging.compartments, facts: staging.facts };
156947
+ })();
156948
+ }
156949
+ function invalidateAllMemoryBlockCaches(db) {
156950
+ try {
156951
+ db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE memory_block_cache != '' OR memory_block_ids != ''").run();
156952
+ } catch {}
156953
+ }
156954
+ function clearRecompStaging(db, sessionId) {
156955
+ db.transaction(() => {
156956
+ db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
156957
+ db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
156958
+ try {
156959
+ db.prepare("UPDATE session_meta SET recomp_partial_range_start = 0, recomp_partial_range_end = 0 WHERE session_id = ?").run(sessionId);
156960
+ } catch {}
156961
+ })();
156962
+ }
156963
+ function getRecompPartialRange(db, sessionId) {
156964
+ try {
156965
+ const row = db.prepare("SELECT recomp_partial_range_start AS start, recomp_partial_range_end AS end FROM session_meta WHERE session_id = ?").get(sessionId);
156966
+ const start = typeof row?.start === "number" ? row.start : 0;
156967
+ const end = typeof row?.end === "number" ? row.end : 0;
156968
+ if (start <= 0 || end <= 0)
156969
+ return null;
156970
+ return { start, end };
156971
+ } catch {
156972
+ return null;
156973
+ }
156974
+ }
156975
+ function setRecompPartialRange(db, sessionId, range) {
156976
+ const start = range ? range.start : 0;
156977
+ const end = range ? range.end : 0;
156978
+ db.prepare("INSERT OR IGNORE INTO session_meta (session_id) VALUES (?)").run(sessionId);
156979
+ db.prepare("UPDATE session_meta SET recomp_partial_range_start = ?, recomp_partial_range_end = ? WHERE session_id = ?").run(start, end, sessionId);
156980
+ }
156981
+ function isRecompCompartmentRow(row) {
156982
+ if (row === null || typeof row !== "object")
156983
+ return false;
156984
+ const candidate = row;
156985
+ return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && typeof candidate.pass_number === "number" && typeof candidate.created_at === "number";
156986
+ }
156987
+ function isRecompFactRow(row) {
156988
+ if (row === null || typeof row !== "object")
156989
+ return false;
156990
+ const candidate = row;
156991
+ return typeof candidate.category === "string" && typeof candidate.content === "string";
156992
+ }
156993
+ function escapeXmlAttr(s) {
156994
+ return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&apos;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
156995
+ }
156996
+ function escapeXmlContent(s) {
156997
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
156998
+ }
156429
156999
  // ../plugin/src/features/magic-context/storage-db.ts
156430
157000
  init_data_path();
156431
- import { copyFileSync, cpSync, existsSync, mkdirSync as mkdirSync2 } from "node:fs";
156432
- import { join as join5 } from "node:path";
157001
+ import { copyFileSync, cpSync, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "node:fs";
157002
+ import { join as join7 } from "node:path";
156433
157003
 
156434
157004
  // ../plugin/src/shared/error-message.ts
156435
157005
  function getErrorMessage(error48) {
@@ -156714,6 +157284,58 @@ var MIGRATIONS = [
156714
157284
  db.exec("ALTER TABLE notes ADD COLUMN harness TEXT NOT NULL DEFAULT 'opencode'");
156715
157285
  }
156716
157286
  }
157287
+ },
157288
+ {
157289
+ version: 8,
157290
+ description: "Add partial indexes on tags(session_id, tag_number) for active and dropped",
157291
+ up: (db) => {
157292
+ db.exec(`
157293
+ CREATE INDEX IF NOT EXISTS idx_tags_active_session_tag_number
157294
+ ON tags(session_id, tag_number)
157295
+ WHERE status = 'active';
157296
+
157297
+ CREATE INDEX IF NOT EXISTS idx_tags_dropped_session_tag_number
157298
+ ON tags(session_id, tag_number)
157299
+ WHERE status = 'dropped';
157300
+ `);
157301
+ db.exec("ANALYZE tags;");
157302
+ }
157303
+ },
157304
+ {
157305
+ version: 9,
157306
+ description: "Persist tool_definition_measurements across plugin restarts",
157307
+ up: (db) => {
157308
+ db.exec(`
157309
+ CREATE TABLE IF NOT EXISTS tool_definition_measurements (
157310
+ provider_id TEXT NOT NULL,
157311
+ model_id TEXT NOT NULL,
157312
+ agent_name TEXT NOT NULL,
157313
+ tool_id TEXT NOT NULL,
157314
+ token_count INTEGER NOT NULL,
157315
+ recorded_at INTEGER NOT NULL,
157316
+ PRIMARY KEY (provider_id, model_id, agent_name, tool_id)
157317
+ );
157318
+ `);
157319
+ }
157320
+ },
157321
+ {
157322
+ version: 10,
157323
+ description: "Add tool_owner_message_id column to tags + composite identity indexes",
157324
+ up: (db) => {
157325
+ const cols = db.prepare("PRAGMA table_info(tags)").all();
157326
+ if (!cols.some((c) => c.name === "tool_owner_message_id")) {
157327
+ db.exec("ALTER TABLE tags ADD COLUMN tool_owner_message_id TEXT DEFAULT NULL");
157328
+ }
157329
+ db.exec(`
157330
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_tags_tool_composite
157331
+ ON tags(session_id, message_id, tool_owner_message_id)
157332
+ WHERE type = 'tool' AND tool_owner_message_id IS NOT NULL;
157333
+
157334
+ CREATE INDEX IF NOT EXISTS idx_tags_tool_null_owner
157335
+ ON tags(session_id, message_id)
157336
+ WHERE type = 'tool' AND tool_owner_message_id IS NULL;
157337
+ `);
157338
+ }
156717
157339
  }
156718
157340
  ];
156719
157341
  function ensureMigrationsTable(db) {
@@ -156729,22 +157351,51 @@ function getCurrentVersion(db) {
156729
157351
  const row = db.prepare("SELECT MAX(version) as version FROM schema_migrations").get();
156730
157352
  return row?.version ?? 0;
156731
157353
  }
157354
+ function isSiblingMigrationConflict(error48, version2) {
157355
+ if (!(error48 instanceof Error))
157356
+ return false;
157357
+ const code = error48.code;
157358
+ if (code !== "SQLITE_CONSTRAINT_PRIMARYKEY" && code !== "SQLITE_CONSTRAINT_UNIQUE") {
157359
+ return false;
157360
+ }
157361
+ const msg = error48.message;
157362
+ if (!msg.includes("schema_migrations"))
157363
+ return false;
157364
+ if (!msg.toLowerCase().includes("version"))
157365
+ return false;
157366
+ return true;
157367
+ }
156732
157368
  function runMigrations(db) {
156733
157369
  ensureMigrationsTable(db);
156734
- const currentVersion = getCurrentVersion(db);
156735
- const pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
157370
+ let currentVersion = getCurrentVersion(db);
157371
+ let pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
156736
157372
  if (pendingMigrations.length === 0) {
156737
157373
  return;
156738
157374
  }
156739
157375
  log(`[migrations] current schema version: ${currentVersion}, applying ${pendingMigrations.length} migration(s)`);
156740
- for (const migration of pendingMigrations) {
157376
+ let migrationIndex = 0;
157377
+ while (migrationIndex < pendingMigrations.length) {
157378
+ const migration = pendingMigrations[migrationIndex];
156741
157379
  try {
156742
157380
  db.transaction(() => {
156743
157381
  migration.up(db);
156744
157382
  db.prepare("INSERT INTO schema_migrations (version, description, applied_at) VALUES (?, ?, ?)").run(migration.version, migration.description, Date.now());
156745
157383
  })();
156746
157384
  log(`[migrations] applied v${migration.version}: ${migration.description}`);
157385
+ migrationIndex += 1;
156747
157386
  } catch (error48) {
157387
+ if (isSiblingMigrationConflict(error48, migration.version)) {
157388
+ log(`[migrations] v${migration.version} already applied by sibling instance — resuming with re-read version`);
157389
+ const reReadVersion = getCurrentVersion(db);
157390
+ if (reReadVersion <= currentVersion) {
157391
+ log(`[migrations] FAILED v${migration.version}: sibling-conflict shape but version not advanced (${reReadVersion} <= ${currentVersion}) — failing closed`);
157392
+ throw new Error(`Migration v${migration.version} failed: sibling conflict reported but version did not advance. Database may need manual repair.`);
157393
+ }
157394
+ currentVersion = reReadVersion;
157395
+ pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
157396
+ migrationIndex = 0;
157397
+ continue;
157398
+ }
156748
157399
  log(`[migrations] FAILED v${migration.version}: ${migration.description} — ${error48 instanceof Error ? error48.message : String(error48)}`);
156749
157400
  throw new Error(`Migration v${migration.version} failed: ${error48 instanceof Error ? error48.message : String(error48)}. Database may need manual repair.`);
156750
157401
  }
@@ -156752,27 +157403,300 @@ function runMigrations(db) {
156752
157403
  log(`[migrations] schema version now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
156753
157404
  }
156754
157405
 
157406
+ // ../plugin/src/features/magic-context/tool-definition-tokens.ts
157407
+ var measurements = new Map;
157408
+ var persistenceDb = null;
157409
+ function keyFor(providerID, modelID, agentName) {
157410
+ const agent = agentName && agentName.length > 0 ? agentName : "default";
157411
+ return `${providerID}/${modelID}/${agent}`;
157412
+ }
157413
+ function setDatabase(db) {
157414
+ persistenceDb = db;
157415
+ }
157416
+ function loadToolDefinitionMeasurements(db) {
157417
+ let rows = [];
157418
+ try {
157419
+ rows = db.prepare("SELECT provider_id, model_id, agent_name, tool_id, token_count FROM tool_definition_measurements").all();
157420
+ } catch {
157421
+ return;
157422
+ }
157423
+ for (const row of rows) {
157424
+ const key = keyFor(row.provider_id, row.model_id, row.agent_name);
157425
+ let inner = measurements.get(key);
157426
+ if (!inner) {
157427
+ inner = new Map;
157428
+ measurements.set(key, inner);
157429
+ }
157430
+ inner.set(row.tool_id, row.token_count);
157431
+ }
157432
+ }
157433
+
157434
+ // ../plugin/src/features/magic-context/tool-owner-backfill.ts
157435
+ init_data_path();
157436
+ init_logger();
157437
+ import { existsSync as existsSync2 } from "node:fs";
157438
+ import { join as join6 } from "node:path";
157439
+ var LEASE_DURATION_MS = 5 * 60 * 1000;
157440
+ var LEASE_RENEWAL_MS = 60 * 1000;
157441
+ function resolveOpencodeDbPath() {
157442
+ return join6(getDataDir(), "opencode", "opencode.db");
157443
+ }
157444
+ function ensureBackfillStateTable(db) {
157445
+ db.exec(`
157446
+ CREATE TABLE IF NOT EXISTS tool_owner_backfill_state (
157447
+ session_id TEXT PRIMARY KEY,
157448
+ status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'skipped')),
157449
+ started_at INTEGER,
157450
+ lease_expires_at INTEGER,
157451
+ completed_at INTEGER,
157452
+ last_error TEXT
157453
+ );
157454
+ CREATE INDEX IF NOT EXISTS idx_tool_owner_backfill_state_status
157455
+ ON tool_owner_backfill_state(status);
157456
+ `);
157457
+ }
157458
+ function runToolOwnerBackfill(db) {
157459
+ const startedAt = performance.now();
157460
+ ensureBackfillStateTable(db);
157461
+ const result = {
157462
+ sessionsProcessed: 0,
157463
+ sessionsSkippedNoOcDb: 0,
157464
+ sessionsSkippedNoMatches: 0,
157465
+ sessionsCompleted: 0,
157466
+ sessionsBlockedByLease: 0,
157467
+ sessionsErrored: 0,
157468
+ rowsUpdated: 0,
157469
+ rowsLeftNull: 0,
157470
+ durationMs: 0
157471
+ };
157472
+ if (!isToolOwnerBackfillNeeded(db)) {
157473
+ result.durationMs = performance.now() - startedAt;
157474
+ return result;
157475
+ }
157476
+ const opencodeDbPath = resolveOpencodeDbPath();
157477
+ if (!existsSync2(opencodeDbPath)) {
157478
+ log(`[backfill] OpenCode DB not found at ${opencodeDbPath} — marking all unbackfilled sessions as skipped. Lazy adoption (defense-in-depth) handles legacy rows at runtime.`);
157479
+ markAllUnbackfilledSessionsSkipped(db);
157480
+ result.sessionsSkippedNoOcDb = countSessionsByStatus(db, "skipped");
157481
+ result.durationMs = performance.now() - startedAt;
157482
+ return result;
157483
+ }
157484
+ db.exec(`ATTACH '${opencodeDbPath}' AS oc_backfill`);
157485
+ try {
157486
+ backfillToolOwnersInChunks(db, result);
157487
+ } finally {
157488
+ try {
157489
+ db.exec("DETACH DATABASE oc_backfill");
157490
+ } catch (error48) {
157491
+ log(`[backfill] failed to detach oc_backfill database: ${error48 instanceof Error ? error48.message : String(error48)}`);
157492
+ }
157493
+ }
157494
+ result.durationMs = performance.now() - startedAt;
157495
+ log(`[backfill] sessions=${result.sessionsProcessed} completed=${result.sessionsCompleted} skipped_no_oc=${result.sessionsSkippedNoOcDb} skipped_no_matches=${result.sessionsSkippedNoMatches} blocked_by_lease=${result.sessionsBlockedByLease} errored=${result.sessionsErrored} rows_updated=${result.rowsUpdated} rows_left_null=${result.rowsLeftNull} duration_ms=${Math.round(result.durationMs)}`);
157496
+ return result;
157497
+ }
157498
+ function isToolOwnerBackfillNeeded(db) {
157499
+ ensureBackfillStateTable(db);
157500
+ const row = db.prepare(`SELECT 1 AS hit
157501
+ FROM tags
157502
+ WHERE type = 'tool' AND tool_owner_message_id IS NULL
157503
+ AND NOT EXISTS (
157504
+ SELECT 1 FROM tool_owner_backfill_state s
157505
+ WHERE s.session_id = tags.session_id
157506
+ AND s.status IN ('completed', 'skipped')
157507
+ )
157508
+ LIMIT 1`).get();
157509
+ return row !== null && row !== undefined;
157510
+ }
157511
+ function markAllUnbackfilledSessionsSkipped(db) {
157512
+ const now = Date.now();
157513
+ db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, started_at, completed_at, last_error)
157514
+ SELECT DISTINCT session_id, 'skipped', NULL, ?, NULL
157515
+ FROM tags
157516
+ WHERE type = 'tool' AND tool_owner_message_id IS NULL
157517
+ ON CONFLICT(session_id) DO UPDATE SET
157518
+ status = 'skipped',
157519
+ completed_at = excluded.completed_at,
157520
+ last_error = NULL
157521
+ WHERE tool_owner_backfill_state.status NOT IN ('completed', 'running')`).run(now);
157522
+ }
157523
+ function countSessionsByStatus(db, status) {
157524
+ const row = db.prepare("SELECT COUNT(*) AS c FROM tool_owner_backfill_state WHERE status = ?").get(status);
157525
+ return row.c;
157526
+ }
157527
+ function acquireSessionLease(db, sessionId, now) {
157528
+ const expiresAt = now + LEASE_DURATION_MS;
157529
+ const result = db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, started_at, lease_expires_at)
157530
+ VALUES (?, 'running', ?, ?)
157531
+ ON CONFLICT(session_id) DO UPDATE SET
157532
+ status = 'running',
157533
+ started_at = excluded.started_at,
157534
+ lease_expires_at = excluded.lease_expires_at,
157535
+ last_error = NULL
157536
+ WHERE tool_owner_backfill_state.status IN ('pending', 'skipped')
157537
+ OR (tool_owner_backfill_state.status = 'running'
157538
+ AND tool_owner_backfill_state.lease_expires_at < ?)`).run(sessionId, now, expiresAt, now);
157539
+ return (result.changes ?? 0) === 1;
157540
+ }
157541
+ function renewSessionLease(db, sessionId, now) {
157542
+ const expiresAt = now + LEASE_DURATION_MS;
157543
+ db.prepare(`UPDATE tool_owner_backfill_state
157544
+ SET lease_expires_at = ?
157545
+ WHERE session_id = ? AND status = 'running'`).run(expiresAt, sessionId);
157546
+ }
157547
+ function markSessionCompleted(db, sessionId, now) {
157548
+ db.prepare(`UPDATE tool_owner_backfill_state
157549
+ SET status = 'completed', completed_at = ?, lease_expires_at = NULL, last_error = NULL
157550
+ WHERE session_id = ?`).run(now, sessionId);
157551
+ }
157552
+ function markSessionSkipped(db, sessionId, now, reason) {
157553
+ db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, completed_at, last_error)
157554
+ VALUES (?, 'skipped', ?, ?)
157555
+ ON CONFLICT(session_id) DO UPDATE SET
157556
+ status = 'skipped',
157557
+ completed_at = excluded.completed_at,
157558
+ last_error = excluded.last_error,
157559
+ lease_expires_at = NULL`).run(sessionId, now, reason);
157560
+ }
157561
+ function markSessionErrored(db, sessionId, error48) {
157562
+ const message = error48 instanceof Error ? error48.message : String(error48);
157563
+ db.prepare(`UPDATE tool_owner_backfill_state
157564
+ SET last_error = ?, lease_expires_at = NULL
157565
+ WHERE session_id = ?`).run(message, sessionId);
157566
+ }
157567
+ function getSessionsNeedingBackfill(db) {
157568
+ const rows = db.prepare(`SELECT DISTINCT t.session_id
157569
+ FROM tags t
157570
+ LEFT JOIN tool_owner_backfill_state s ON s.session_id = t.session_id
157571
+ WHERE t.type = 'tool' AND t.tool_owner_message_id IS NULL
157572
+ AND (s.status IS NULL OR s.status NOT IN ('completed', 'skipped'))
157573
+ ORDER BY t.session_id ASC`).all();
157574
+ return rows.map((r) => r.session_id);
157575
+ }
157576
+ function buildSessionOwnerMap(db, sessionId) {
157577
+ const rows = db.prepare(`SELECT
157578
+ COALESCE(
157579
+ CASE WHEN json_extract(p.data, '$.type') = 'tool_use'
157580
+ THEN json_extract(p.data, '$.id')
157581
+ END,
157582
+ json_extract(p.data, '$.callID')
157583
+ ) AS callid,
157584
+ m.id AS owner_id,
157585
+ m.time_created AS owner_t_created,
157586
+ p.id AS part_id,
157587
+ p.time_created AS part_t_created
157588
+ FROM oc_backfill.message m
157589
+ INNER JOIN oc_backfill.part p ON p.message_id = m.id
157590
+ WHERE m.session_id = ?
157591
+ AND json_extract(m.data, '$.role') = 'assistant'
157592
+ AND (
157593
+ (json_extract(p.data, '$.type') IN ('tool', 'tool-invocation')
157594
+ AND json_extract(p.data, '$.callID') IS NOT NULL)
157595
+ OR (json_extract(p.data, '$.type') = 'tool_use'
157596
+ AND json_extract(p.data, '$.id') IS NOT NULL)
157597
+ )
157598
+ ORDER BY
157599
+ m.time_created ASC,
157600
+ m.id ASC,
157601
+ p.time_created ASC,
157602
+ p.id ASC`).all(sessionId);
157603
+ const oldestByCallId = new Map;
157604
+ for (const r of rows) {
157605
+ if (typeof r.callid !== "string" || r.callid.length === 0)
157606
+ continue;
157607
+ if (!oldestByCallId.has(r.callid)) {
157608
+ oldestByCallId.set(r.callid, r.owner_id);
157609
+ }
157610
+ }
157611
+ return oldestByCallId;
157612
+ }
157613
+ function applyOwnersForSession(db, sessionId, ownersByCallId) {
157614
+ if (ownersByCallId.size === 0) {
157615
+ const leftNull = db.prepare(`SELECT COUNT(*) AS c FROM tags
157616
+ WHERE session_id = ? AND type = 'tool'
157617
+ AND tool_owner_message_id IS NULL`).get(sessionId).c;
157618
+ return { rowsUpdated: 0, rowsLeftNull: leftNull };
157619
+ }
157620
+ const findOrphanStmt = db.prepare(`SELECT id FROM tags
157621
+ WHERE session_id = ? AND message_id = ? AND type = 'tool'
157622
+ AND tool_owner_message_id IS NULL
157623
+ ORDER BY tag_number ASC
157624
+ LIMIT 1`);
157625
+ const updateRowStmt = db.prepare(`UPDATE tags
157626
+ SET tool_owner_message_id = ?
157627
+ WHERE id = ? AND tool_owner_message_id IS NULL`);
157628
+ let rowsUpdated = 0;
157629
+ db.transaction(() => {
157630
+ for (const [callId, ownerId] of ownersByCallId) {
157631
+ const orphan = findOrphanStmt.get(sessionId, callId);
157632
+ if (!orphan)
157633
+ continue;
157634
+ const result = updateRowStmt.run(ownerId, orphan.id);
157635
+ rowsUpdated += result.changes ?? 0;
157636
+ }
157637
+ })();
157638
+ const rowsLeftNull = db.prepare(`SELECT COUNT(*) AS c FROM tags
157639
+ WHERE session_id = ? AND type = 'tool'
157640
+ AND tool_owner_message_id IS NULL`).get(sessionId).c;
157641
+ return { rowsUpdated, rowsLeftNull };
157642
+ }
157643
+ function backfillToolOwnersInChunks(db, result) {
157644
+ const sessionIds = getSessionsNeedingBackfill(db);
157645
+ let lastRenewedAt = Date.now();
157646
+ for (const sessionId of sessionIds) {
157647
+ const now = Date.now();
157648
+ result.sessionsProcessed += 1;
157649
+ const acquired = acquireSessionLease(db, sessionId, now);
157650
+ if (!acquired) {
157651
+ result.sessionsBlockedByLease += 1;
157652
+ continue;
157653
+ }
157654
+ try {
157655
+ const owners = buildSessionOwnerMap(db, sessionId);
157656
+ const { rowsUpdated, rowsLeftNull } = applyOwnersForSession(db, sessionId, owners);
157657
+ result.rowsUpdated += rowsUpdated;
157658
+ result.rowsLeftNull += rowsLeftNull;
157659
+ if (owners.size === 0) {
157660
+ markSessionSkipped(db, sessionId, Date.now(), "no_oc_matches");
157661
+ result.sessionsSkippedNoMatches += 1;
157662
+ } else {
157663
+ markSessionCompleted(db, sessionId, Date.now());
157664
+ result.sessionsCompleted += 1;
157665
+ }
157666
+ } catch (error48) {
157667
+ log(`[backfill] session=${sessionId} errored: ${error48 instanceof Error ? error48.message : String(error48)}`);
157668
+ markSessionErrored(db, sessionId, error48);
157669
+ result.sessionsErrored += 1;
157670
+ }
157671
+ const sinceRenew = Date.now() - lastRenewedAt;
157672
+ if (sinceRenew > LEASE_RENEWAL_MS) {
157673
+ renewSessionLease(db, sessionId, Date.now());
157674
+ lastRenewedAt = Date.now();
157675
+ }
157676
+ }
157677
+ }
157678
+
156755
157679
  // ../plugin/src/features/magic-context/storage-db.ts
156756
157680
  var databases = new Map;
156757
157681
  var persistenceByDatabase = new WeakMap;
156758
157682
  var persistenceErrorByDatabase = new WeakMap;
156759
157683
  function resolveDatabasePath() {
156760
157684
  const dbDir = getMagicContextStorageDir();
156761
- return { dbDir, dbPath: join5(dbDir, "context.db") };
157685
+ return { dbDir, dbPath: join7(dbDir, "context.db") };
156762
157686
  }
156763
157687
  function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
156764
- if (existsSync(targetDbPath))
157688
+ if (existsSync3(targetDbPath))
156765
157689
  return;
156766
157690
  const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
156767
- const legacyDbPath = join5(legacyDir, "context.db");
156768
- if (!existsSync(legacyDbPath))
157691
+ const legacyDbPath = join7(legacyDir, "context.db");
157692
+ if (!existsSync3(legacyDbPath))
156769
157693
  return;
156770
157694
  log(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
156771
- mkdirSync2(targetDbDir, { recursive: true });
157695
+ mkdirSync3(targetDbDir, { recursive: true });
156772
157696
  for (const suffix of ["", "-wal", "-shm"]) {
156773
157697
  const src = `${legacyDbPath}${suffix}`;
156774
- const dst = join5(targetDbDir, `context.db${suffix}`);
156775
- if (existsSync(src)) {
157698
+ const dst = join7(targetDbDir, `context.db${suffix}`);
157699
+ if (existsSync3(src)) {
156776
157700
  try {
156777
157701
  copyFileSync(src, dst);
156778
157702
  } catch (error48) {
@@ -156780,9 +157704,9 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
156780
157704
  }
156781
157705
  }
156782
157706
  }
156783
- const legacyModelsDir = join5(legacyDir, "models");
156784
- const targetModelsDir = join5(targetDbDir, "models");
156785
- if (existsSync(legacyModelsDir) && !existsSync(targetModelsDir)) {
157707
+ const legacyModelsDir = join7(legacyDir, "models");
157708
+ const targetModelsDir = join7(targetDbDir, "models");
157709
+ if (existsSync3(legacyModelsDir) && !existsSync3(targetModelsDir)) {
156786
157710
  try {
156787
157711
  cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
156788
157712
  } catch (error48) {
@@ -157068,6 +157992,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
157068
157992
  ensureColumn(db, "tags", "tool_name", "TEXT");
157069
157993
  ensureColumn(db, "tags", "input_byte_size", "INTEGER DEFAULT 0");
157070
157994
  ensureColumn(db, "tags", "caveman_depth", "INTEGER DEFAULT 0");
157995
+ ensureColumn(db, "tags", "tool_owner_message_id", "TEXT DEFAULT NULL");
157071
157996
  ensureColumn(db, "session_meta", "system_prompt_tokens", "INTEGER DEFAULT 0");
157072
157997
  ensureColumn(db, "session_meta", "compaction_marker_state", "TEXT DEFAULT ''");
157073
157998
  ensureColumn(db, "session_meta", "key_files", "TEXT DEFAULT ''");
@@ -157162,10 +158087,17 @@ function openDatabase() {
157162
158087
  }
157163
158088
  try {
157164
158089
  migrateLegacyStorageIfNeeded(dbPath, dbDir);
157165
- mkdirSync2(dbDir, { recursive: true });
158090
+ mkdirSync3(dbDir, { recursive: true });
157166
158091
  const db = new Database(dbPath);
157167
158092
  initializeDatabase(db);
157168
158093
  runMigrations(db);
158094
+ try {
158095
+ runToolOwnerBackfill(db);
158096
+ } catch (error48) {
158097
+ log(`[magic-context] tool-owner backfill failed (continuing with lazy adoption fallback): ${getErrorMessage(error48)}`);
158098
+ }
158099
+ setDatabase(db);
158100
+ loadToolDefinitionMeasurements(db);
157169
158101
  databases.set(dbPath, db);
157170
158102
  persistenceByDatabase.set(db, true);
157171
158103
  persistenceErrorByDatabase.delete(db);
@@ -157773,7 +158705,7 @@ var getTagNumberByMessageIdStatements = new WeakMap;
157773
158705
  function getInsertTagStatement(db) {
157774
158706
  let stmt = insertTagStatements.get(db);
157775
158707
  if (!stmt) {
157776
- stmt = db.prepare("INSERT INTO tags (session_id, message_id, type, byte_size, reasoning_byte_size, tag_number, tool_name, input_byte_size, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
158708
+ stmt = db.prepare("INSERT INTO tags (session_id, message_id, type, byte_size, reasoning_byte_size, tag_number, tool_name, input_byte_size, harness, tool_owner_message_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
157777
158709
  insertTagStatements.set(db, stmt);
157778
158710
  }
157779
158711
  return stmt;
@@ -157854,7 +158786,8 @@ function toTagEntry(row) {
157854
158786
  byteSize: row.byte_size,
157855
158787
  reasoningByteSize: row.reasoning_byte_size ?? 0,
157856
158788
  sessionId: row.session_id,
157857
- cavemanDepth: typeof row.caveman_depth === "number" && Number.isFinite(row.caveman_depth) ? row.caveman_depth : 0
158789
+ cavemanDepth: typeof row.caveman_depth === "number" && Number.isFinite(row.caveman_depth) ? row.caveman_depth : 0,
158790
+ toolOwnerMessageId: typeof row.tool_owner_message_id === "string" ? row.tool_owner_message_id : null
157858
158791
  };
157859
158792
  }
157860
158793
  function isTagNumberRow(row) {
@@ -157869,8 +158802,8 @@ function isMaxTagNumberRow(row) {
157869
158802
  const r = row;
157870
158803
  return typeof r.max_tag_number === "number";
157871
158804
  }
157872
- function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0) {
157873
- getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness());
158805
+ function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0, toolOwnerMessageId = null) {
158806
+ getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness(), toolOwnerMessageId);
157874
158807
  return tagNumber;
157875
158808
  }
157876
158809
  function updateTagStatus(db, sessionId, tagId, status) {
@@ -157882,6 +158815,7 @@ function updateTagDropMode(db, sessionId, tagNumber, dropMode) {
157882
158815
  function updateCavemanDepth(db, sessionId, tagNumber, depth) {
157883
158816
  db.prepare("UPDATE tags SET caveman_depth = ? WHERE session_id = ? AND tag_number = ?").run(depth, sessionId, tagNumber);
157884
158817
  }
158818
+ var getOwnerScopedToolTagNumbersStatements = new WeakMap;
157885
158819
  function getMaxTagNumberBySession(db, sessionId) {
157886
158820
  const row = getMaxTagNumberBySessionStatement(db).get(sessionId);
157887
158821
  return isMaxTagNumberRow(row) ? row.max_tag_number : 0;
@@ -157890,17 +158824,103 @@ function getTagNumberByMessageId(db, sessionId, messageId) {
157890
158824
  const row = getTagNumberByMessageIdStatement(db).get(sessionId, messageId);
157891
158825
  return isTagNumberRow(row) ? row.tag_number : null;
157892
158826
  }
158827
+ var TAG_SELECT_COLUMNS = "id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth, tool_owner_message_id";
157893
158828
  function getTagsBySession(db, sessionId) {
157894
- const rows = db.prepare("SELECT id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth FROM tags WHERE session_id = ? ORDER BY tag_number ASC, id ASC").all(sessionId).filter(isTagRow);
158829
+ const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? ORDER BY tag_number ASC, id ASC`).all(sessionId).filter(isTagRow);
158830
+ return rows.map(toTagEntry);
158831
+ }
158832
+ var getActiveTagsBySessionStatements = new WeakMap;
158833
+ var getMaxDroppedTagNumberStatements = new WeakMap;
158834
+ function getActiveTagsBySessionStatement(db) {
158835
+ let stmt = getActiveTagsBySessionStatements.get(db);
158836
+ if (!stmt) {
158837
+ stmt = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND status = 'active' ORDER BY tag_number ASC, id ASC`);
158838
+ getActiveTagsBySessionStatements.set(db, stmt);
158839
+ }
158840
+ return stmt;
158841
+ }
158842
+ function getActiveTagsBySession(db, sessionId) {
158843
+ const rows = getActiveTagsBySessionStatement(db).all(sessionId).filter(isTagRow);
158844
+ return rows.map(toTagEntry);
158845
+ }
158846
+ function getTagsByNumbers(db, sessionId, tagNumbers) {
158847
+ if (tagNumbers.length === 0)
158848
+ return [];
158849
+ if (tagNumbers.length > 900) {
158850
+ const all = [];
158851
+ for (let i = 0;i < tagNumbers.length; i += 900) {
158852
+ all.push(...getTagsByNumbers(db, sessionId, tagNumbers.slice(i, i + 900)));
158853
+ }
158854
+ return all;
158855
+ }
158856
+ const placeholders = tagNumbers.map(() => "?").join(",");
158857
+ const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${placeholders}) ORDER BY tag_number ASC, id ASC`).all(sessionId, ...tagNumbers).filter(isTagRow);
157895
158858
  return rows.map(toTagEntry);
157896
158859
  }
157897
158860
  function getTopNBySize(db, sessionId, n) {
157898
158861
  if (n <= 0) {
157899
158862
  return [];
157900
158863
  }
157901
- const rows = db.prepare("SELECT id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth FROM tags WHERE session_id = ? AND status = 'active' ORDER BY byte_size DESC, tag_number ASC LIMIT ?").all(sessionId, n).filter(isTagRow);
158864
+ const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND status = 'active' ORDER BY byte_size DESC, tag_number ASC LIMIT ?`).all(sessionId, n).filter(isTagRow);
157902
158865
  return rows.map(toTagEntry);
157903
158866
  }
158867
+ var getToolTagNumberByOwnerStatements = new WeakMap;
158868
+ var getNullOwnerToolTagStatements = new WeakMap;
158869
+ var adoptNullOwnerToolTagStatements = new WeakMap;
158870
+ var deleteToolTagsByOwnerStatements = new WeakMap;
158871
+ function getGetToolTagNumberByOwnerStatement(db) {
158872
+ let stmt = getToolTagNumberByOwnerStatements.get(db);
158873
+ if (!stmt) {
158874
+ stmt = db.prepare(`SELECT tag_number FROM tags
158875
+ WHERE session_id = ? AND message_id = ?
158876
+ AND type = 'tool' AND tool_owner_message_id = ?
158877
+ LIMIT 1`);
158878
+ getToolTagNumberByOwnerStatements.set(db, stmt);
158879
+ }
158880
+ return stmt;
158881
+ }
158882
+ function getToolTagNumberByOwner(db, sessionId, callId, ownerMsgId) {
158883
+ const row = getGetToolTagNumberByOwnerStatement(db).get(sessionId, callId, ownerMsgId);
158884
+ return isTagNumberRow(row) ? row.tag_number : null;
158885
+ }
158886
+ function isNullOwnerToolTagRow(row) {
158887
+ if (row === null || typeof row !== "object")
158888
+ return false;
158889
+ const r = row;
158890
+ return typeof r.id === "number" && typeof r.tag_number === "number";
158891
+ }
158892
+ function getGetNullOwnerToolTagStatement(db) {
158893
+ let stmt = getNullOwnerToolTagStatements.get(db);
158894
+ if (!stmt) {
158895
+ stmt = db.prepare(`SELECT id, tag_number FROM tags
158896
+ WHERE session_id = ? AND message_id = ?
158897
+ AND type = 'tool' AND tool_owner_message_id IS NULL
158898
+ ORDER BY tag_number ASC
158899
+ LIMIT 1`);
158900
+ getNullOwnerToolTagStatements.set(db, stmt);
158901
+ }
158902
+ return stmt;
158903
+ }
158904
+ function getNullOwnerToolTag(db, sessionId, callId) {
158905
+ const row = getGetNullOwnerToolTagStatement(db).get(sessionId, callId);
158906
+ if (!isNullOwnerToolTagRow(row))
158907
+ return null;
158908
+ return { id: row.id, tagNumber: row.tag_number };
158909
+ }
158910
+ function getAdoptNullOwnerToolTagStatement(db) {
158911
+ let stmt = adoptNullOwnerToolTagStatements.get(db);
158912
+ if (!stmt) {
158913
+ stmt = db.prepare(`UPDATE tags
158914
+ SET tool_owner_message_id = ?
158915
+ WHERE id = ? AND tool_owner_message_id IS NULL`);
158916
+ adoptNullOwnerToolTagStatements.set(db, stmt);
158917
+ }
158918
+ return stmt;
158919
+ }
158920
+ function adoptNullOwnerToolTag(db, rowId, ownerMsgId) {
158921
+ const result = getAdoptNullOwnerToolTagStatement(db).run(ownerMsgId, rowId);
158922
+ return (result.changes ?? 0) === 1;
158923
+ }
157904
158924
  // ../plugin/src/agents/historian.ts
157905
158925
  var HISTORIAN_AGENT = "historian";
157906
158926
  var HISTORIAN_EDITOR_AGENT = "historian-editor";
@@ -157958,11 +158978,12 @@ function expandFallbackChain(chain) {
157958
158978
  init_data_path();
157959
158979
  init_logger();
157960
158980
  import { createHash as createHash3 } from "node:crypto";
157961
- import { existsSync as existsSync2, readFileSync } from "node:fs";
158981
+ import { existsSync as existsSync4, readFileSync } from "node:fs";
157962
158982
  import { homedir as homedir2, platform } from "node:os";
157963
- import { join as join6 } from "node:path";
158983
+ import { join as join8 } from "node:path";
157964
158984
  var RELOAD_INTERVAL_MS = 5 * 60 * 1000;
157965
158985
  var apiCache = null;
158986
+ var recentlySeenApiSizes = new Set;
157966
158987
  var fileCache = null;
157967
158988
  var fileLastAttempt = 0;
157968
158989
  function hashFast(input) {
@@ -157975,16 +158996,16 @@ function getModelsJsonPath() {
157975
158996
  const cacheBase = getCacheDir();
157976
158997
  const source = process.env.OPENCODE_MODELS_URL?.trim();
157977
158998
  const filename = source && source !== "https://models.dev" ? `models-${hashFast(source)}.json` : "models.json";
157978
- return join6(cacheBase, "opencode", filename);
158999
+ return join8(cacheBase, "opencode", filename);
157979
159000
  }
157980
159001
  function getOpencodeConfigPath() {
157981
159002
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
157982
- const configDir = envDir ? envDir : platform() === "win32" ? join6(homedir2(), ".config", "opencode") : join6(process.env.XDG_CONFIG_HOME || join6(homedir2(), ".config"), "opencode");
157983
- const jsonc = join6(configDir, "opencode.jsonc");
157984
- if (existsSync2(jsonc))
159003
+ const configDir = envDir ? envDir : platform() === "win32" ? join8(homedir2(), ".config", "opencode") : join8(process.env.XDG_CONFIG_HOME || join8(homedir2(), ".config"), "opencode");
159004
+ const jsonc = join8(configDir, "opencode.jsonc");
159005
+ if (existsSync4(jsonc))
157985
159006
  return jsonc;
157986
- const json2 = join6(configDir, "opencode.json");
157987
- if (existsSync2(json2))
159007
+ const json2 = join8(configDir, "opencode.json");
159008
+ if (existsSync4(json2))
157988
159009
  return json2;
157989
159010
  return null;
157990
159011
  }
@@ -157997,23 +159018,12 @@ function resolveLimit(limit) {
157997
159018
  return limit.context;
157998
159019
  return;
157999
159020
  }
158000
- function resolveInterleavedField(interleaved) {
158001
- if (interleaved && typeof interleaved === "object" && typeof interleaved.field === "string" && interleaved.field.length > 0) {
158002
- return interleaved.field;
158003
- }
158004
- return;
158005
- }
158006
159021
  function setCachedModelMetadata(cache, key, model) {
158007
159022
  const limit = resolveLimit(model?.limit);
158008
- const interleavedField = resolveInterleavedField(model?.capabilities?.interleaved) ?? resolveInterleavedField(model?.interleaved);
158009
- if (limit === undefined && interleavedField === undefined) {
159023
+ if (limit === undefined) {
158010
159024
  return;
158011
159025
  }
158012
- const value = {};
158013
- if (limit !== undefined)
158014
- value.limit = limit;
158015
- if (interleavedField !== undefined)
158016
- value.interleavedField = interleavedField;
159026
+ const value = { limit };
158017
159027
  cache.set(key, value);
158018
159028
  const modes = model?.experimental?.modes;
158019
159029
  if (modes && typeof modes === "object") {
@@ -158027,7 +159037,7 @@ function loadModelsDevMetadataFromFile() {
158027
159037
  const modelsJsonPath = getModelsJsonPath();
158028
159038
  let fileFound = false;
158029
159039
  try {
158030
- if (existsSync2(modelsJsonPath)) {
159040
+ if (existsSync4(modelsJsonPath)) {
158031
159041
  fileFound = true;
158032
159042
  const raw = readFileSync(modelsJsonPath, "utf-8");
158033
159043
  const data = JSON.parse(raw);
@@ -158044,7 +159054,7 @@ function loadModelsDevMetadataFromFile() {
158044
159054
  }
158045
159055
  try {
158046
159056
  const configPath = getOpencodeConfigPath();
158047
- if (configPath && existsSync2(configPath)) {
159057
+ if (configPath && existsSync4(configPath)) {
158048
159058
  let raw = readFileSync(configPath, "utf-8");
158049
159059
  raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) => match.startsWith('"') ? match : "");
158050
159060
  const config2 = JSON.parse(raw);
@@ -158078,22 +159088,6 @@ function getModelsDevContextLimit(providerID, modelID) {
158078
159088
  }
158079
159089
  return fileCache.get(key)?.limit;
158080
159090
  }
158081
- function getModelsDevInterleavedField(providerID, modelID) {
158082
- const key = `${providerID}/${modelID}`;
158083
- if (apiCache) {
158084
- const fromApi = apiCache.get(key)?.interleavedField;
158085
- if (typeof fromApi === "string" && fromApi.length > 0) {
158086
- return fromApi;
158087
- }
158088
- }
158089
- const now = Date.now();
158090
- if (!fileCache || now - fileLastAttempt > RELOAD_INTERVAL_MS) {
158091
- fileLastAttempt = now;
158092
- fileCache = loadModelsDevMetadataFromFile();
158093
- }
158094
- const fromFile = fileCache.get(key)?.interleavedField;
158095
- return typeof fromFile === "string" && fromFile.length > 0 ? fromFile : undefined;
158096
- }
158097
159091
 
158098
159092
  // ../plugin/src/hooks/magic-context/derive-budgets.ts
158099
159093
  var TRIGGER_BUDGET_PERCENTAGE = 0.05;
@@ -158387,15 +159381,15 @@ init_logger();
158387
159381
 
158388
159382
  // src/subagent-runner.ts
158389
159383
  import * as childProcess from "node:child_process";
158390
- import { existsSync as existsSync3 } from "node:fs";
158391
- import { dirname, resolve as resolvePath } from "node:path";
159384
+ import { existsSync as existsSync5 } from "node:fs";
159385
+ import { dirname as dirname2, resolve as resolvePath } from "node:path";
158392
159386
  import { createInterface } from "node:readline";
158393
159387
  import { fileURLToPath } from "node:url";
158394
159388
  function resolveSubagentEntryPath() {
158395
159389
  try {
158396
- const here = dirname(fileURLToPath(import.meta.url));
159390
+ const here = dirname2(fileURLToPath(import.meta.url));
158397
159391
  const candidate = resolvePath(here, "subagent-entry.js");
158398
- if (existsSync3(candidate))
159392
+ if (existsSync5(candidate))
158399
159393
  return candidate;
158400
159394
  return;
158401
159395
  } catch {
@@ -158941,7 +159935,7 @@ function deleteDreamState(db, key) {
158941
159935
  var LEASE_HOLDER_KEY = "dreaming_lease_holder";
158942
159936
  var LEASE_HEARTBEAT_KEY = "dreaming_lease_heartbeat";
158943
159937
  var LEASE_EXPIRY_KEY = "dreaming_lease_expiry";
158944
- var LEASE_DURATION_MS = 2 * 60 * 1000;
159938
+ var LEASE_DURATION_MS2 = 2 * 60 * 1000;
158945
159939
  function getLeaseExpiry(db) {
158946
159940
  const value = getDreamState(db, LEASE_EXPIRY_KEY);
158947
159941
  if (!value) {
@@ -158968,7 +159962,7 @@ function acquireLease(db, holderId) {
158968
159962
  const now = Date.now();
158969
159963
  setDreamState(db, LEASE_HOLDER_KEY, holderId);
158970
159964
  setDreamState(db, LEASE_HEARTBEAT_KEY, String(now));
158971
- setDreamState(db, LEASE_EXPIRY_KEY, String(now + LEASE_DURATION_MS));
159965
+ setDreamState(db, LEASE_EXPIRY_KEY, String(now + LEASE_DURATION_MS2));
158972
159966
  return true;
158973
159967
  })();
158974
159968
  }
@@ -158979,7 +159973,7 @@ function renewLease(db, holderId) {
158979
159973
  }
158980
159974
  const now = Date.now();
158981
159975
  setDreamState(db, LEASE_HEARTBEAT_KEY, String(now));
158982
- setDreamState(db, LEASE_EXPIRY_KEY, String(now + LEASE_DURATION_MS));
159976
+ setDreamState(db, LEASE_EXPIRY_KEY, String(now + LEASE_DURATION_MS2));
158983
159977
  return true;
158984
159978
  })();
158985
159979
  }
@@ -158994,8 +159988,8 @@ function releaseLease(db, holderId) {
158994
159988
  })();
158995
159989
  }
158996
159990
  // ../plugin/src/features/magic-context/dreamer/runner.ts
158997
- import { existsSync as existsSync4 } from "node:fs";
158998
- import { join as join7 } from "node:path";
159991
+ import { existsSync as existsSync6 } from "node:fs";
159992
+ import { join as join9 } from "node:path";
158999
159993
 
159000
159994
  // ../plugin/src/shared/index.ts
159001
159995
  init_logger();
@@ -159126,11 +160120,6 @@ function normalizeSDKResponse(response, fallback, options) {
159126
160120
  }
159127
160121
  return fallback;
159128
160122
  }
159129
- // ../plugin/src/shared/record-type-guard.ts
159130
- function isRecord(value) {
159131
- return typeof value === "object" && value !== null && !Array.isArray(value);
159132
- }
159133
-
159134
160123
  // ../plugin/src/shared/assistant-message-extractor.ts
159135
160124
  function asSessionMessage(value) {
159136
160125
  if (!isRecord(value))
@@ -160393,11 +161382,11 @@ function countNewIds(beforeIds, afterIds) {
160393
161382
  return count;
160394
161383
  }
160395
161384
  function getOpenCodeDbPath2() {
160396
- return join7(getDataDir(), "opencode", "opencode.db");
161385
+ return join9(getDataDir(), "opencode", "opencode.db");
160397
161386
  }
160398
161387
  function openOpenCodeDb() {
160399
161388
  const dbPath = getOpenCodeDbPath2();
160400
- if (!existsSync4(dbPath)) {
161389
+ if (!existsSync6(dbPath)) {
160401
161390
  log(`[key-files] OpenCode DB not found at ${dbPath} — skipping`);
160402
161391
  return null;
160403
161392
  }
@@ -160647,8 +161636,8 @@ async function runDream(args) {
160647
161636
  try {
160648
161637
  const docsDir = args.sessionDirectory ?? args.projectIdentity;
160649
161638
  const existingDocs = taskName === "maintain-docs" ? {
160650
- architecture: existsSync4(join7(docsDir, "ARCHITECTURE.md")),
160651
- structure: existsSync4(join7(docsDir, "STRUCTURE.md"))
161639
+ architecture: existsSync6(join9(docsDir, "ARCHITECTURE.md")),
161640
+ structure: existsSync6(join9(docsDir, "STRUCTURE.md"))
160652
161641
  } : undefined;
160653
161642
  const userMemories = taskName === "archive-stale" ? getActiveUserMemories(args.db).map((um) => ({
160654
161643
  id: um.id,
@@ -162158,14 +163147,46 @@ function createScheduler(config2) {
162158
163147
  }
162159
163148
 
162160
163149
  // ../plugin/src/features/magic-context/tagger.ts
163150
+ var TOOL_COMPOSITE_KEY_SEP = "\x00";
163151
+ function makeToolCompositeKey(ownerMsgId, callId) {
163152
+ return `${ownerMsgId}${TOOL_COMPOSITE_KEY_SEP}${callId}`;
163153
+ }
162161
163154
  var GET_COUNTER_SQL = `SELECT counter FROM session_meta WHERE session_id = ?`;
162162
- var GET_ASSIGNMENTS_SQL = "SELECT message_id, tag_number FROM tags WHERE session_id = ? ORDER BY tag_number ASC";
163155
+ var GET_ASSIGNMENTS_SQL = "SELECT message_id, tag_number, type, tool_owner_message_id FROM tags WHERE session_id = ? ORDER BY tag_number ASC";
163156
+ var PROBE_DATA_VERSION_SQL = "PRAGMA main.data_version";
163157
+ var PROBE_TOTAL_CHANGES_SQL = "SELECT total_changes() AS tc";
163158
+ var probeDataVersionStatements = new WeakMap;
163159
+ var probeTotalChangesStatements = new WeakMap;
163160
+ function getProbeDataVersionStatement(db) {
163161
+ let stmt = probeDataVersionStatements.get(db);
163162
+ if (!stmt) {
163163
+ stmt = db.prepare(PROBE_DATA_VERSION_SQL);
163164
+ probeDataVersionStatements.set(db, stmt);
163165
+ }
163166
+ return stmt;
163167
+ }
163168
+ function getProbeTotalChangesStatement(db) {
163169
+ let stmt = probeTotalChangesStatements.get(db);
163170
+ if (!stmt) {
163171
+ stmt = db.prepare(PROBE_TOTAL_CHANGES_SQL);
163172
+ probeTotalChangesStatements.set(db, stmt);
163173
+ }
163174
+ return stmt;
163175
+ }
162163
163176
  function isAssignmentRow(row) {
162164
163177
  if (row === null || typeof row !== "object") {
162165
163178
  return false;
162166
163179
  }
162167
163180
  const candidate = row;
162168
- return typeof candidate.message_id === "string" && typeof candidate.tag_number === "number";
163181
+ if (typeof candidate.message_id !== "string")
163182
+ return false;
163183
+ if (typeof candidate.tag_number !== "number")
163184
+ return false;
163185
+ if (candidate.type !== "message" && candidate.type !== "tool" && candidate.type !== "file")
163186
+ return false;
163187
+ if (candidate.tool_owner_message_id !== null && typeof candidate.tool_owner_message_id !== "string")
163188
+ return false;
163189
+ return true;
162169
163190
  }
162170
163191
  var UPSERT_COUNTER_SQL = `
162171
163192
  INSERT INTO session_meta (session_id, counter, harness)
@@ -162199,6 +163220,7 @@ var MAX_TAG_ALLOC_RETRIES = 5;
162199
163220
  function createTagger() {
162200
163221
  const counters = new Map;
162201
163222
  const assignments = new Map;
163223
+ const loadSignatures = new Map;
162202
163224
  function getSessionAssignments(sessionId) {
162203
163225
  let map2 = assignments.get(sessionId);
162204
163226
  if (!map2) {
@@ -162217,15 +163239,15 @@ function createTagger() {
162217
163239
  counters.set(sessionId, next);
162218
163240
  getUpsertCounterStatement(db).run(sessionId, next, getHarness());
162219
163241
  }
162220
- function assignTag(sessionId, messageId, type, byteSize2, db, reasoningByteSize = 0, toolName = null, inputByteSize = 0) {
163242
+ function allocateTag(sessionId, messageId, type, byteSize2, db, reasoningByteSize, toolName, inputByteSize, toolOwnerMessageId, mapKey, dbExistingLookup) {
162221
163243
  const sessionAssignments = getSessionAssignments(sessionId);
162222
- const existing = sessionAssignments.get(messageId);
163244
+ const existing = sessionAssignments.get(mapKey);
162223
163245
  if (existing !== undefined) {
162224
163246
  return existing;
162225
163247
  }
162226
- const dbExisting = getTagNumberByMessageId(db, sessionId, messageId);
163248
+ const dbExisting = dbExistingLookup();
162227
163249
  if (dbExisting !== null) {
162228
- sessionAssignments.set(messageId, dbExisting);
163250
+ sessionAssignments.set(mapKey, dbExisting);
162229
163251
  syncCounterAtLeast(sessionId, db, dbExisting);
162230
163252
  return dbExisting;
162231
163253
  }
@@ -162235,16 +163257,16 @@ function createTagger() {
162235
163257
  const next = Math.max(memCounter, dbMax) + 1;
162236
163258
  try {
162237
163259
  db.transaction(() => {
162238
- insertTag(db, sessionId, messageId, type, byteSize2, next, reasoningByteSize, toolName, inputByteSize);
163260
+ insertTag(db, sessionId, messageId, type, byteSize2, next, reasoningByteSize, toolName, inputByteSize, toolOwnerMessageId);
162239
163261
  getUpsertCounterStatement(db).run(sessionId, next, getHarness());
162240
163262
  })();
162241
163263
  } catch (error48) {
162242
163264
  if (!isUniqueConstraintError(error48)) {
162243
163265
  throw error48;
162244
163266
  }
162245
- const racedRow = getTagNumberByMessageId(db, sessionId, messageId);
163267
+ const racedRow = dbExistingLookup();
162246
163268
  if (racedRow !== null) {
162247
- sessionAssignments.set(messageId, racedRow);
163269
+ sessionAssignments.set(mapKey, racedRow);
162248
163270
  syncCounterAtLeast(sessionId, db, racedRow);
162249
163271
  return racedRow;
162250
163272
  }
@@ -162253,51 +163275,124 @@ function createTagger() {
162253
163275
  continue;
162254
163276
  }
162255
163277
  counters.set(sessionId, next);
162256
- sessionAssignments.set(messageId, next);
163278
+ sessionAssignments.set(mapKey, next);
162257
163279
  return next;
162258
163280
  }
162259
- throw new Error(`tagger.assignTag: failed to allocate tag for session=${sessionId} message=${messageId} after ${MAX_TAG_ALLOC_RETRIES} retries`);
163281
+ throw new Error(`tagger.allocateTag: failed to allocate tag for session=${sessionId} key=${mapKey} after ${MAX_TAG_ALLOC_RETRIES} retries`);
162260
163282
  }
162261
- function getTag(sessionId, messageId) {
163283
+ function assignTag(sessionId, messageId, type, byteSize2, db, reasoningByteSize = 0, toolName = null, inputByteSize = 0) {
163284
+ if (type === "tool") {
163285
+ throw new Error("tagger.assignTag: type='tool' is forbidden — use assignToolTag(sessionId, callId, ownerMsgId, ...)");
163286
+ }
163287
+ return allocateTag(sessionId, messageId, type, byteSize2, db, reasoningByteSize, toolName, inputByteSize, null, messageId, () => getTagNumberByMessageId(db, sessionId, messageId));
163288
+ }
163289
+ function assignToolTag(sessionId, callId, ownerMsgId, byteSize2, db, reasoningByteSize = 0, toolName = null, inputByteSize = 0) {
163290
+ const compositeKey = makeToolCompositeKey(ownerMsgId, callId);
163291
+ const sessionAssignments = getSessionAssignments(sessionId);
163292
+ const existing = sessionAssignments.get(compositeKey);
163293
+ if (existing !== undefined) {
163294
+ return existing;
163295
+ }
163296
+ const dbHit = getToolTagNumberByOwner(db, sessionId, callId, ownerMsgId);
163297
+ if (dbHit !== null) {
163298
+ sessionAssignments.set(compositeKey, dbHit);
163299
+ syncCounterAtLeast(sessionId, db, dbHit);
163300
+ return dbHit;
163301
+ }
163302
+ for (let attempt = 0;attempt < MAX_TAG_ALLOC_RETRIES; attempt += 1) {
163303
+ const orphan = getNullOwnerToolTag(db, sessionId, callId);
163304
+ if (orphan === null)
163305
+ break;
163306
+ const claimed = adoptNullOwnerToolTag(db, orphan.id, ownerMsgId);
163307
+ if (claimed) {
163308
+ sessionAssignments.set(compositeKey, orphan.tagNumber);
163309
+ syncCounterAtLeast(sessionId, db, orphan.tagNumber);
163310
+ return orphan.tagNumber;
163311
+ }
163312
+ const recheck = getToolTagNumberByOwner(db, sessionId, callId, ownerMsgId);
163313
+ if (recheck !== null) {
163314
+ sessionAssignments.set(compositeKey, recheck);
163315
+ syncCounterAtLeast(sessionId, db, recheck);
163316
+ return recheck;
163317
+ }
163318
+ }
163319
+ return allocateTag(sessionId, callId, "tool", byteSize2, db, reasoningByteSize, toolName, inputByteSize, ownerMsgId, compositeKey, () => getToolTagNumberByOwner(db, sessionId, callId, ownerMsgId));
163320
+ }
163321
+ function getTag(sessionId, messageId, _type) {
162262
163322
  return assignments.get(sessionId)?.get(messageId);
162263
163323
  }
163324
+ function getToolTag(sessionId, callId, ownerMsgId) {
163325
+ return assignments.get(sessionId)?.get(makeToolCompositeKey(ownerMsgId, callId));
163326
+ }
162264
163327
  function bindTag(sessionId, messageId, tagNumber) {
162265
163328
  getSessionAssignments(sessionId).set(messageId, tagNumber);
162266
163329
  }
163330
+ function bindToolTag(sessionId, callId, ownerMsgId, tagNumber) {
163331
+ getSessionAssignments(sessionId).set(makeToolCompositeKey(ownerMsgId, callId), tagNumber);
163332
+ }
162267
163333
  function getAssignments(sessionId) {
162268
163334
  return getSessionAssignments(sessionId);
162269
163335
  }
162270
163336
  function resetCounter(sessionId, db) {
162271
163337
  counters.set(sessionId, 0);
162272
163338
  assignments.delete(sessionId);
163339
+ loadSignatures.delete(sessionId);
162273
163340
  getResetCounterStatement(db).run(sessionId, getHarness());
162274
163341
  }
162275
163342
  function getCounter(sessionId) {
162276
163343
  return counters.get(sessionId) ?? 0;
162277
163344
  }
163345
+ function probeSignature(db) {
163346
+ const dvRow = getProbeDataVersionStatement(db).get();
163347
+ const tcRow = getProbeTotalChangesStatement(db).get();
163348
+ return {
163349
+ dataVersion: dvRow?.data_version ?? 0,
163350
+ totalChanges: tcRow?.tc ?? 0
163351
+ };
163352
+ }
162278
163353
  function initFromDb(sessionId, db) {
163354
+ const probe = probeSignature(db);
163355
+ const cached2 = loadSignatures.get(sessionId);
163356
+ if (cached2 !== undefined && cached2.db === db && cached2.dataVersion === probe.dataVersion && cached2.totalChanges === probe.totalChanges) {
163357
+ return;
163358
+ }
162279
163359
  const row = db.prepare(GET_COUNTER_SQL).get(sessionId);
162280
163360
  const assignmentRows = db.prepare(GET_ASSIGNMENTS_SQL).all(sessionId).filter(isAssignmentRow);
162281
163361
  const sessionAssignments = getSessionAssignments(sessionId);
162282
163362
  sessionAssignments.clear();
162283
163363
  let maxTagNumber = 0;
162284
163364
  for (const assignment of assignmentRows) {
162285
- sessionAssignments.set(assignment.message_id, assignment.tag_number);
163365
+ if (assignment.type === "tool") {
163366
+ if (assignment.tool_owner_message_id !== null) {
163367
+ sessionAssignments.set(makeToolCompositeKey(assignment.tool_owner_message_id, assignment.message_id), assignment.tag_number);
163368
+ }
163369
+ } else {
163370
+ sessionAssignments.set(assignment.message_id, assignment.tag_number);
163371
+ }
162286
163372
  if (assignment.tag_number > maxTagNumber) {
162287
163373
  maxTagNumber = assignment.tag_number;
162288
163374
  }
162289
163375
  }
162290
163376
  const counter = Math.max(row?.counter ?? 0, maxTagNumber, counters.get(sessionId) ?? 0);
162291
163377
  counters.set(sessionId, counter);
163378
+ loadSignatures.set(sessionId, {
163379
+ db,
163380
+ dataVersion: probe.dataVersion,
163381
+ totalChanges: probe.totalChanges
163382
+ });
162292
163383
  }
162293
163384
  function cleanup(sessionId) {
162294
163385
  counters.delete(sessionId);
162295
163386
  assignments.delete(sessionId);
163387
+ loadSignatures.delete(sessionId);
162296
163388
  }
162297
163389
  return {
162298
163390
  assignTag,
163391
+ assignToolTag,
162299
163392
  getTag,
163393
+ getToolTag,
162300
163394
  bindTag,
163395
+ bindToolTag,
162301
163396
  getAssignments,
162302
163397
  resetCounter,
162303
163398
  getCounter,
@@ -163310,7 +164405,7 @@ function createNudger(config2) {
163310
164405
  }
163311
164406
  const largest = formatLargestTags(topNFn(db, sessionId, 3));
163312
164407
  const protectedCount = config2.protected_tags;
163313
- const activeTags = (preloadedTags ?? getTagsBySession(db, sessionId)).filter((t) => t.status === "active");
164408
+ const activeTags = preloadedTags ? preloadedTags.filter((t) => t.status === "active") : getActiveTagsBySession(db, sessionId);
163314
164409
  const highestProtected = activeTags.map((t) => t.tagNumber).sort((a, b) => b - a).slice(0, protectedCount)[0];
163315
164410
  const protectedHint = highestProtected ? ` Tags §${highestProtected}§ and above are protected (last ${protectedCount}) — You MUST NOT try to reduce those.` : "";
163316
164411
  const oldToolHint = formatOldToolTags(activeTags, protectedCount, 5);
@@ -163401,7 +164496,7 @@ function estimateProjectedPercentage(db, sessionId, contextUsage, preloadedTags)
163401
164496
  if (pendingDrops.length === 0) {
163402
164497
  return null;
163403
164498
  }
163404
- const activeTags = (preloadedTags ?? getTagsBySession(db, sessionId)).filter((t) => t.status === "active");
164499
+ const activeTags = preloadedTags ? preloadedTags.filter((t) => t.status === "active") : getActiveTagsBySession(db, sessionId);
163405
164500
  const totalActiveBytes = activeTags.reduce((sum, t) => sum + t.byteSize, 0);
163406
164501
  if (totalActiveBytes === 0) {
163407
164502
  return null;
@@ -163412,15 +164507,6 @@ function estimateProjectedPercentage(db, sessionId, contextUsage, preloadedTags)
163412
164507
  return contextUsage.percentage * (1 - dropRatio);
163413
164508
  }
163414
164509
 
163415
- // ../plugin/src/hooks/magic-context/reasoning-capability.ts
163416
- function modelRequiresInterleavedReasoning(model) {
163417
- if (!model?.providerID || !model?.modelID) {
163418
- return false;
163419
- }
163420
- const field = getModelsDevInterleavedField(model.providerID, model.modelID);
163421
- return typeof field === "string" && field.length > 0;
163422
- }
163423
-
163424
164510
  // src/context-handler.ts
163425
164511
  init_logger();
163426
164512
 
@@ -163429,107 +164515,105 @@ function tagTranscript(sessionId, transcript, tagger, db, options = {}) {
163429
164515
  const skipPrefixInjection = options.skipPrefixInjection === true;
163430
164516
  const targets = new Map;
163431
164517
  const toolAggregates = new Map;
163432
- db.transaction(() => {
163433
- for (let msgIndex = 0;msgIndex < transcript.messages.length; msgIndex += 1) {
163434
- const message = transcript.messages[msgIndex];
163435
- if (message === undefined)
164518
+ for (let msgIndex = 0;msgIndex < transcript.messages.length; msgIndex += 1) {
164519
+ const message = transcript.messages[msgIndex];
164520
+ if (message === undefined)
164521
+ continue;
164522
+ const messageId = message.info.id;
164523
+ let textOrdinal = 0;
164524
+ for (let partIndex = 0;partIndex < message.parts.length; partIndex += 1) {
164525
+ const part = message.parts[partIndex];
164526
+ if (part === undefined)
163436
164527
  continue;
163437
- const messageId = message.info.id;
163438
- let textOrdinal = 0;
163439
- for (let partIndex = 0;partIndex < message.parts.length; partIndex += 1) {
163440
- const part = message.parts[partIndex];
163441
- if (part === undefined)
164528
+ if (part.kind === "text") {
164529
+ if (messageId === undefined) {
164530
+ textOrdinal += 1;
163442
164531
  continue;
163443
- if (part.kind === "text") {
163444
- if (messageId === undefined) {
163445
- textOrdinal += 1;
163446
- continue;
163447
- }
163448
- tagTextPart({
164532
+ }
164533
+ tagTextPart({
164534
+ sessionId,
164535
+ message,
164536
+ messageId,
164537
+ msgIndex,
164538
+ textOrdinal,
164539
+ part,
164540
+ tagger,
164541
+ db,
164542
+ targets,
164543
+ skipPrefixInjection
164544
+ });
164545
+ textOrdinal += 1;
164546
+ continue;
164547
+ }
164548
+ if (part.kind === "tool_use" || part.kind === "tool_result") {
164549
+ if (messageId === undefined)
164550
+ continue;
164551
+ const callId = part.id;
164552
+ const text = part.getText() ?? "";
164553
+ const meta3 = part.getToolMetadata();
164554
+ if (typeof callId !== "string" || callId.length === 0) {
164555
+ tagToolPart({
163449
164556
  sessionId,
163450
164557
  message,
163451
164558
  messageId,
163452
164559
  msgIndex,
163453
- textOrdinal,
164560
+ partIndex,
163454
164561
  part,
163455
164562
  tagger,
163456
164563
  db,
163457
164564
  targets,
163458
164565
  skipPrefixInjection
163459
164566
  });
163460
- textOrdinal += 1;
163461
164567
  continue;
163462
164568
  }
163463
- if (part.kind === "tool_use" || part.kind === "tool_result") {
163464
- if (messageId === undefined)
163465
- continue;
163466
- const callId = part.id;
163467
- const text = part.getText() ?? "";
163468
- const meta3 = part.getToolMetadata();
163469
- if (typeof callId !== "string" || callId.length === 0) {
163470
- tagToolPart({
163471
- sessionId,
163472
- message,
163473
- messageId,
163474
- msgIndex,
163475
- partIndex,
163476
- part,
163477
- tagger,
163478
- db,
163479
- targets,
163480
- skipPrefixInjection
163481
- });
163482
- continue;
164569
+ const existing = toolAggregates.get(callId);
164570
+ if (existing) {
164571
+ existing.occurrences.push({
164572
+ message,
164573
+ part,
164574
+ kind: part.kind
164575
+ });
164576
+ const newByteSize = byteSize(text);
164577
+ if (newByteSize > existing.maxByteSize) {
164578
+ existing.maxByteSize = newByteSize;
164579
+ updateTagByteSize(db, sessionId, existing.tagId, newByteSize);
163483
164580
  }
163484
- const existing = toolAggregates.get(callId);
163485
- if (existing) {
163486
- existing.occurrences.push({
163487
- message,
163488
- part,
163489
- kind: part.kind
163490
- });
163491
- const newByteSize = byteSize(text);
163492
- if (newByteSize > existing.maxByteSize) {
163493
- existing.maxByteSize = newByteSize;
163494
- updateTagByteSize(db, sessionId, existing.tagId, newByteSize);
163495
- }
163496
- if (existing.toolName === null && meta3.toolName) {
163497
- existing.toolName = meta3.toolName;
163498
- }
163499
- if (existing.inputByteSize === 0 && part.kind === "tool_use" && meta3.inputByteSize > 0) {
163500
- existing.inputByteSize = meta3.inputByteSize;
163501
- updateTagInputByteSize(db, sessionId, existing.tagId, meta3.inputByteSize);
163502
- }
163503
- if (!skipPrefixInjection && part.kind === "tool_result") {
163504
- part.setText(prependTag(existing.tagId, text));
163505
- }
163506
- targets.set(existing.tagId, buildAggregateTarget(existing.tagId, existing.occurrences));
163507
- } else {
163508
- const tagId = tagger.assignTag(sessionId, callId, "tool", byteSize(text), db, 0, meta3.toolName ?? null, meta3.inputByteSize);
163509
- const aggregate = {
163510
- callId,
163511
- tagId,
163512
- occurrences: [
163513
- {
163514
- message,
163515
- part,
163516
- kind: part.kind
163517
- }
163518
- ],
163519
- maxByteSize: byteSize(text),
163520
- toolName: meta3.toolName ?? null,
163521
- inputByteSize: part.kind === "tool_use" ? meta3.inputByteSize : 0
163522
- };
163523
- toolAggregates.set(callId, aggregate);
163524
- if (!skipPrefixInjection && part.kind === "tool_result") {
163525
- part.setText(prependTag(tagId, text));
163526
- }
163527
- targets.set(tagId, buildAggregateTarget(tagId, aggregate.occurrences));
164581
+ if (existing.toolName === null && meta3.toolName) {
164582
+ existing.toolName = meta3.toolName;
164583
+ }
164584
+ if (existing.inputByteSize === 0 && part.kind === "tool_use" && meta3.inputByteSize > 0) {
164585
+ existing.inputByteSize = meta3.inputByteSize;
164586
+ updateTagInputByteSize(db, sessionId, existing.tagId, meta3.inputByteSize);
164587
+ }
164588
+ if (!skipPrefixInjection && part.kind === "tool_result") {
164589
+ part.setText(prependTag(existing.tagId, text));
164590
+ }
164591
+ targets.set(existing.tagId, buildAggregateTarget(existing.tagId, existing.occurrences));
164592
+ } else {
164593
+ const tagId = tagger.assignToolTag(sessionId, callId, messageId, byteSize(text), db, 0, meta3.toolName ?? null, meta3.inputByteSize);
164594
+ const aggregate = {
164595
+ callId,
164596
+ tagId,
164597
+ occurrences: [
164598
+ {
164599
+ message,
164600
+ part,
164601
+ kind: part.kind
164602
+ }
164603
+ ],
164604
+ maxByteSize: byteSize(text),
164605
+ toolName: meta3.toolName ?? null,
164606
+ inputByteSize: part.kind === "tool_use" ? meta3.inputByteSize : 0
164607
+ };
164608
+ toolAggregates.set(callId, aggregate);
164609
+ if (!skipPrefixInjection && part.kind === "tool_result") {
164610
+ part.setText(prependTag(tagId, text));
163528
164611
  }
164612
+ targets.set(tagId, buildAggregateTarget(tagId, aggregate.occurrences));
163529
164613
  }
163530
164614
  }
163531
164615
  }
163532
- })();
164616
+ }
163533
164617
  return { targets };
163534
164618
  }
163535
164619
  function tagTextPart(args) {
@@ -163550,7 +164634,7 @@ function tagToolPart(args) {
163550
164634
  const contentId = stableId ?? `${args.messageId}:t${args.partIndex}`;
163551
164635
  const text = args.part.getText() ?? "";
163552
164636
  const meta3 = args.part.getToolMetadata();
163553
- const tagId = args.tagger.assignTag(args.sessionId, contentId, "tool", byteSize(text), args.db, 0, meta3.toolName ?? null, meta3.inputByteSize);
164637
+ const tagId = args.tagger.assignToolTag(args.sessionId, contentId, contentId, byteSize(text), args.db, 0, meta3.toolName ?? null, meta3.inputByteSize);
163554
164638
  if (!args.skipPrefixInjection && args.part.kind === "tool_result") {
163555
164639
  const tagged = prependTag(tagId, text);
163556
164640
  args.part.setText(tagged);
@@ -163790,11 +164874,7 @@ function getMessageOrdinal(value) {
163790
164874
  }
163791
164875
  async function getSemanticScores(args) {
163792
164876
  const semanticScores = new Map;
163793
- if (!args.embeddingEnabled || !args.isEmbeddingRuntimeEnabled() || args.memories.length === 0) {
163794
- return semanticScores;
163795
- }
163796
- const queryEmbedding = await args.embedQuery(args.query, args.signal);
163797
- if (!queryEmbedding) {
164877
+ if (!args.queryEmbedding || args.memories.length === 0) {
163798
164878
  return semanticScores;
163799
164879
  }
163800
164880
  const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
@@ -163808,7 +164888,7 @@ async function getSemanticScores(args) {
163808
164888
  if (!memoryEmbedding) {
163809
164889
  continue;
163810
164890
  }
163811
- semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(queryEmbedding, memoryEmbedding)));
164891
+ semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
163812
164892
  }
163813
164893
  return semanticScores;
163814
164894
  }
@@ -163904,12 +164984,8 @@ async function searchMemories(args) {
163904
164984
  const semanticScores = await getSemanticScores({
163905
164985
  db: args.db,
163906
164986
  projectPath: args.projectPath,
163907
- query: args.query,
163908
164987
  memories: semanticCandidates,
163909
- embeddingEnabled: args.embeddingEnabled,
163910
- embedQuery: args.embedQuery,
163911
- isEmbeddingRuntimeEnabled: args.isEmbeddingRuntimeEnabled,
163912
- signal: args.signal
164988
+ queryEmbedding: args.queryEmbedding
163913
164989
  });
163914
164990
  return mergeMemoryResults({
163915
164991
  memories,
@@ -163925,7 +165001,6 @@ function linearDecayScore(rank, total) {
163925
165001
  return Math.max(0, 1 - rank / total);
163926
165002
  }
163927
165003
  function searchMessages(args) {
163928
- ensureMessagesIndexed(args.db, args.sessionId, args.readMessages);
163929
165004
  const sanitizedQuery = sanitizeFtsQuery(args.query.trim());
163930
165005
  if (sanitizedQuery.length === 0) {
163931
165006
  return [];
@@ -163996,20 +165071,12 @@ function toGitCommitResult(hit) {
163996
165071
  matchType: hit.matchType
163997
165072
  };
163998
165073
  }
163999
- async function searchGitCommitsAsync(args) {
165074
+ function searchGitCommits(args) {
164000
165075
  if (args.limit <= 0)
164001
165076
  return [];
164002
- let queryEmbedding = null;
164003
- if (args.embeddingEnabled && args.isEmbeddingRuntimeEnabled()) {
164004
- try {
164005
- queryEmbedding = await args.embedQuery(args.query, args.signal);
164006
- } catch (error48) {
164007
- log(`[search] git commit query embedding failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
164008
- }
164009
- }
164010
165077
  const hits = searchGitCommitsSync(args.db, args.projectPath, args.query, {
164011
165078
  limit: args.limit,
164012
- queryEmbedding
165079
+ queryEmbedding: args.queryEmbedding
164013
165080
  });
164014
165081
  return hits.map(toGitCommitResult);
164015
165082
  }
@@ -164040,37 +165107,37 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
164040
165107
  const runMemory = activeSources.has("memory") && (options.memoryEnabled ?? true);
164041
165108
  const runMessages = activeSources.has("message");
164042
165109
  const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
164043
- const [memoryResults, messageResults, gitCommitResults] = await Promise.all([
165110
+ const needsEmbedding = (runMemory || runGitCommits) && embeddingEnabled && isEmbeddingRuntimeEnabled();
165111
+ const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error48) => {
165112
+ log(`[search] query embedding failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
165113
+ return null;
165114
+ }) : Promise.resolve(null);
165115
+ await Promise.resolve();
165116
+ const messageResults = runMessages ? searchMessages({
165117
+ db,
165118
+ sessionId,
165119
+ query: trimmedQuery,
165120
+ limit: tierLimit,
165121
+ maxOrdinal: options.maxMessageOrdinal
165122
+ }) : [];
165123
+ const queryEmbedding = await queryEmbeddingPromise;
165124
+ const [memoryResults, gitCommitResults] = await Promise.all([
164044
165125
  runMemory ? searchMemories({
164045
165126
  db,
164046
165127
  projectPath,
164047
165128
  query: trimmedQuery,
164048
165129
  limit: tierLimit,
164049
165130
  memoryEnabled: true,
164050
- embeddingEnabled,
164051
- embedQuery,
164052
- isEmbeddingRuntimeEnabled,
164053
- visibleMemoryIds: options.visibleMemoryIds,
164054
- signal: options.signal
165131
+ queryEmbedding,
165132
+ visibleMemoryIds: options.visibleMemoryIds
164055
165133
  }) : Promise.resolve([]),
164056
- runMessages ? Promise.resolve(searchMessages({
164057
- db,
164058
- sessionId,
164059
- query: trimmedQuery,
164060
- limit: tierLimit,
164061
- readMessages: options.readMessages ?? readRawSessionMessages,
164062
- maxOrdinal: options.maxMessageOrdinal
164063
- })) : Promise.resolve([]),
164064
- runGitCommits ? searchGitCommitsAsync({
165134
+ runGitCommits ? Promise.resolve(searchGitCommits({
164065
165135
  db,
164066
165136
  projectPath,
164067
165137
  query: trimmedQuery,
164068
165138
  limit: tierLimit,
164069
- embeddingEnabled,
164070
- embedQuery,
164071
- isEmbeddingRuntimeEnabled,
164072
- signal: options.signal
164073
- }) : Promise.resolve([])
165139
+ queryEmbedding
165140
+ })) : Promise.resolve([])
164074
165141
  ]);
164075
165142
  const results = [...memoryResults, ...messageResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
164076
165143
  const countRetrievals = options.countRetrievals ?? true;
@@ -164487,8 +165554,8 @@ function collectStaleReduceCallIds(messages, messageIdToMaxTag, toolAgeCutoff) {
164487
165554
  return staleCallIds;
164488
165555
  }
164489
165556
  function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config2, preloadedTags) {
164490
- const tags = preloadedTags ?? getTagsBySession(db, sessionId);
164491
- const maxTag = tags.reduce((max, t) => Math.max(max, t.tagNumber), 0);
165557
+ const tags = preloadedTags ?? getActiveTagsBySession(db, sessionId);
165558
+ const maxTag = getMaxTagNumberBySession(db, sessionId);
164492
165559
  const toolAgeCutoff = maxTag - config2.autoDropToolAge;
164493
165560
  const protectedCutoff = maxTag - config2.protectedTags;
164494
165561
  let droppedTools = 0;
@@ -165601,12 +166668,24 @@ function clearPiCompressorState(sessionId) {
165601
166668
  init_logger();
165602
166669
  function queueDropsForCompartmentalizedMessages(db, sessionId, upToMessageIndex) {
165603
166670
  const tags = getTagsBySession(db, sessionId);
165604
- const rawTagKeys = new Set(getRawSessionTagKeysThrough(sessionId, upToMessageIndex));
166671
+ const { messageFileKeys, toolObservations } = getRawSessionTagKeysThrough(sessionId, upToMessageIndex);
165605
166672
  let dropsQueued = 0;
165606
166673
  for (const tag of tags) {
165607
166674
  if (tag.status !== "active")
165608
166675
  continue;
165609
- if (rawTagKeys.has(tag.messageId)) {
166676
+ if (tag.type === "tool") {
166677
+ const observedOwners = toolObservations.get(tag.messageId);
166678
+ if (!observedOwners)
166679
+ continue;
166680
+ if (tag.toolOwnerMessageId !== null) {
166681
+ if (!observedOwners.has(tag.toolOwnerMessageId))
166682
+ continue;
166683
+ }
166684
+ queuePendingOp(db, sessionId, tag.tagNumber, "drop");
166685
+ dropsQueued += 1;
166686
+ continue;
166687
+ }
166688
+ if (messageFileKeys.has(tag.messageId)) {
165610
166689
  queuePendingOp(db, sessionId, tag.tagNumber, "drop");
165611
166690
  dropsQueued += 1;
165612
166691
  }
@@ -165812,28 +166891,28 @@ function getReducedRecompTokenBudget(currentBudget) {
165812
166891
  }
165813
166892
 
165814
166893
  // ../plugin/src/hooks/magic-context/historian-state-file.ts
165815
- import { mkdirSync as mkdirSync3, unlinkSync, writeFileSync } from "node:fs";
166894
+ import { mkdirSync as mkdirSync4, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
165816
166895
  import { tmpdir as tmpdir2 } from "node:os";
165817
- import { join as join8 } from "node:path";
166896
+ import { join as join10 } from "node:path";
165818
166897
  var HISTORIAN_STATE_INLINE_THRESHOLD = 30000;
165819
- var HISTORIAN_STATE_DIR = join8(tmpdir2(), "magic-context-historian");
166898
+ var HISTORIAN_STATE_DIR = join10(tmpdir2(), "magic-context-historian");
165820
166899
  function maybeWriteHistorianStateFile(sessionId, existingState) {
165821
166900
  if (existingState.length <= HISTORIAN_STATE_INLINE_THRESHOLD)
165822
166901
  return;
165823
166902
  try {
165824
- mkdirSync3(HISTORIAN_STATE_DIR, { recursive: true });
165825
- const path4 = join8(HISTORIAN_STATE_DIR, `state-${sessionId}-${Date.now()}.xml`);
165826
- writeFileSync(path4, existingState, "utf8");
165827
- return path4;
166903
+ mkdirSync4(HISTORIAN_STATE_DIR, { recursive: true });
166904
+ const path5 = join10(HISTORIAN_STATE_DIR, `state-${sessionId}-${Date.now()}.xml`);
166905
+ writeFileSync2(path5, existingState, "utf8");
166906
+ return path5;
165828
166907
  } catch {
165829
166908
  return;
165830
166909
  }
165831
166910
  }
165832
- function cleanupHistorianStateFile(path4) {
165833
- if (!path4)
166911
+ function cleanupHistorianStateFile(path5) {
166912
+ if (!path5)
165834
166913
  return;
165835
166914
  try {
165836
- unlinkSync(path4);
166915
+ unlinkSync(path5);
165837
166916
  } catch {}
165838
166917
  }
165839
166918
 
@@ -165932,24 +167011,12 @@ ${chunk.text}`, { stateFilePath });
165932
167011
  const maxExistingSequence = priorCompartments.reduce((max, c) => c.sequence > max ? c.sequence : max, -1);
165933
167012
  const sequenceOffset = priorCompartments.length === 0 ? 0 : maxExistingSequence + 1;
165934
167013
  sessionLog(sessionId, `pi-historian: invoking subagent (model=${historianModel}, chunk=${chunk.startIndex}-${chunk.endIndex}, ${chunk.messageCount} msgs, ~${chunk.tokenEstimate} tokens)`);
167014
+ const traceRawEvents = process.env.MC_PI_HISTORIAN_TRACE === "1";
165935
167015
  const buildProgressLogger = (passLabel) => {
165936
167016
  return (event) => {
165937
167017
  try {
165938
- if (event.type === "raw_event") {
165939
- let serialized;
165940
- try {
165941
- serialized = JSON.stringify(event.event);
165942
- } catch {
165943
- serialized = "[unserializable]";
165944
- }
165945
- if (serialized.length > 4000) {
165946
- serialized = `${serialized.slice(0, 4000)}…[truncated ${serialized.length - 4000} chars]`;
165947
- }
165948
- sessionLog(sessionId, `pi-historian[${passLabel}] raw_event @${event.ms}ms type=${event.eventType ?? "?"}: ${serialized}`);
165949
- } else if (event.type === "spawned") {
167018
+ if (event.type === "spawned") {
165950
167019
  sessionLog(sessionId, `pi-historian[${passLabel}] spawned pid=${event.pid ?? "?"} argv=${event.argv.length} args`);
165951
- } else if (event.type === "first_event") {
165952
- sessionLog(sessionId, `pi-historian[${passLabel}] first_event @${event.ms}ms type=${event.eventType}`);
165953
167020
  } else if (event.type === "terminal") {
165954
167021
  sessionLog(sessionId, `pi-historian[${passLabel}] terminal @${event.ms}ms stopReason=${event.stopReason ?? "?"} textLen=${event.textLength} hasToolCall=${event.hasToolCall}`);
165955
167022
  } else if (event.type === "stderr") {
@@ -165959,6 +167026,21 @@ ${chunk.text}`, { stateFilePath });
165959
167026
  }
165960
167027
  } else if (event.type === "child_exit") {
165961
167028
  sessionLog(sessionId, `pi-historian[${passLabel}] child_exit @${event.ms}ms code=${event.code} signal=${event.signal}`);
167029
+ } else if (traceRawEvents) {
167030
+ if (event.type === "raw_event") {
167031
+ let serialized;
167032
+ try {
167033
+ serialized = JSON.stringify(event.event);
167034
+ } catch {
167035
+ serialized = "[unserializable]";
167036
+ }
167037
+ if (serialized.length > 4000) {
167038
+ serialized = `${serialized.slice(0, 4000)}…[truncated ${serialized.length - 4000} chars]`;
167039
+ }
167040
+ sessionLog(sessionId, `pi-historian[${passLabel}] raw_event @${event.ms}ms type=${event.eventType ?? "?"}: ${serialized}`);
167041
+ } else if (event.type === "first_event") {
167042
+ sessionLog(sessionId, `pi-historian[${passLabel}] first_event @${event.ms}ms type=${event.eventType}`);
167043
+ }
165962
167044
  }
165963
167045
  } catch {}
165964
167046
  };
@@ -166373,16 +167455,7 @@ function clearOldReasoningPi(args) {
166373
167455
  return { cleared, newWatermark };
166374
167456
  }
166375
167457
  function replayClearedReasoningPi(args) {
166376
- const {
166377
- db,
166378
- sessionId,
166379
- messages,
166380
- messageIdToMaxTag,
166381
- piMessageStableId,
166382
- skipTypedReasoningCleanup
166383
- } = args;
166384
- if (skipTypedReasoningCleanup)
166385
- return 0;
167458
+ const { db, sessionId, messages, messageIdToMaxTag, piMessageStableId } = args;
166386
167459
  const meta3 = getOrCreateSessionMeta(db, sessionId);
166387
167460
  const watermark = meta3.clearedReasoningThroughTag ?? 0;
166388
167461
  if (watermark <= 0)
@@ -167082,19 +168155,6 @@ var TOOL_HEAVY_TURN_REMINDER_THRESHOLD = 5;
167082
168155
  var TOOL_HEAVY_TURN_REMINDER_TEXT = `
167083
168156
 
167084
168157
  <instruction name="ctx_reduce_turn_cleanup">Also drop via \`ctx_reduce\` things you don't need anymore from the last turn before continuing.</instruction>`;
167085
- function resolveLiveModelId(ctx) {
167086
- const model = ctx.model;
167087
- if (!model)
167088
- return;
167089
- const providerID = model.provider;
167090
- const modelID = model.id;
167091
- if (typeof providerID !== "string" || typeof modelID !== "string") {
167092
- return;
167093
- }
167094
- if (providerID.length === 0 || modelID.length === 0)
167095
- return;
167096
- return { providerID, modelID };
167097
- }
167098
168158
  var DEFAULT_CLEAR_REASONING_AGE = 50;
167099
168159
  var lastEmergencyNotificationAtMs = new Map;
167100
168160
  var EMERGENCY_NOTIFICATION_COOLDOWN_MS = 60000;
@@ -167107,6 +168167,9 @@ var recentReduceBySession = new Map;
167107
168167
  var liveModelBySession = new Map;
167108
168168
  var toolUsageSinceUserTurn = new Map;
167109
168169
  var latestUserMessageBySession = new Map;
168170
+ function readPiSessionMessageById(ctx, messageId) {
168171
+ return readPiSessionMessages(ctx).find((message) => message.id === messageId) ?? null;
168172
+ }
167110
168173
  function signalPiHistoryRefresh(sessionId) {
167111
168174
  historyRefreshSessions.add(sessionId);
167112
168175
  }
@@ -167307,8 +168370,15 @@ function registerPiContextHandler(pi, options) {
167307
168370
  return;
167308
168371
  }
167309
168372
  sessionIdForError = sessionId;
168373
+ const rawMessageProvider = {
168374
+ readMessages: () => readPiSessionMessages(ctx),
168375
+ readMessageById: (messageId) => readPiSessionMessageById(ctx, messageId)
168376
+ };
168377
+ setRawMessageProvider(sessionId, rawMessageProvider);
168378
+ scheduleReconciliation(options.db, sessionId, readRawSessionMessages);
167310
168379
  const latestUserId = findLatestUserMessageIdPi(event.messages);
167311
168380
  if (latestUserId) {
168381
+ scheduleIncrementalIndex(options.db, sessionId, latestUserId, (_sessionId, messageId) => readPiSessionMessageById(ctx, messageId));
167312
168382
  const previousUserId = latestUserMessageBySession.get(sessionId);
167313
168383
  if (previousUserId !== latestUserId) {
167314
168384
  onPiNewUserMessage({ db: options.db, sessionId });
@@ -167371,8 +168441,6 @@ function registerPiContextHandler(pi, options) {
167371
168441
  }
167372
168442
  const isCacheBusting = historyRefreshSessions.has(sessionId);
167373
168443
  sessionLog(sessionId, `pi transform: usage=${usagePercentage.toFixed(1)}% (${usageInputTokens} tokens, limit=${usageContextLimit ?? "?"}) decision=${schedulerDecision}${forceMaterialization ? " force=true" : ""}${isEmergency ? " EMERGENCY=true" : ""}${isCacheBusting ? " busting=true" : ""}`);
167374
- const liveModelId = resolveLiveModelId(ctx);
167375
- const skipTypedReasoningCleanup = liveModelId ? modelRequiresInterleavedReasoning(liveModelId) : false;
167376
168444
  const entryIds = collectMessageEntryIds(ctx, event.messages.length, sessionId);
167377
168445
  const result = await runPipeline({
167378
168446
  db: options.db,
@@ -167389,8 +168457,7 @@ function registerPiContextHandler(pi, options) {
167389
168457
  forceMaterialization: forceMaterialization || isEmergency,
167390
168458
  isCacheBusting,
167391
168459
  reasoningClearing: {
167392
- clearReasoningAge: options.heuristics?.clearReasoningAge ?? DEFAULT_CLEAR_REASONING_AGE,
167393
- skipTypedReasoningCleanup
168460
+ clearReasoningAge: options.heuristics?.clearReasoningAge ?? DEFAULT_CLEAR_REASONING_AGE
167394
168461
  },
167395
168462
  temporalAwareness: options.injection?.temporalAwareness === true
167396
168463
  });
@@ -167738,7 +168805,10 @@ async function runPipeline(args) {
167738
168805
  consumePendingMaterialization(args.sessionId);
167739
168806
  }
167740
168807
  }
167741
- applyFlushedStatuses(args.sessionId, args.db, targets);
168808
+ const flushedSliceTags = getTagsByNumbers(args.db, args.sessionId, [
168809
+ ...targets.keys()
168810
+ ]);
168811
+ applyFlushedStatuses(args.sessionId, args.db, targets, flushedSliceTags);
167742
168812
  const messageIdToMaxTag = buildMessageIdToMaxTag(targets);
167743
168813
  if (args.reasoningClearing) {
167744
168814
  try {
@@ -167747,8 +168817,7 @@ async function runPipeline(args) {
167747
168817
  sessionId: args.sessionId,
167748
168818
  messages: args.messages,
167749
168819
  messageIdToMaxTag,
167750
- piMessageStableId,
167751
- skipTypedReasoningCleanup: args.reasoningClearing.skipTypedReasoningCleanup
168820
+ piMessageStableId
167752
168821
  });
167753
168822
  const inlineReplay = replayStrippedInlineThinkingPi({
167754
168823
  db: args.db,
@@ -167765,7 +168834,8 @@ async function runPipeline(args) {
167765
168834
  }
167766
168835
  }
167767
168836
  try {
167768
- const tags = getTagsBySession(args.db, args.sessionId);
168837
+ const targetTagNumbers = [...targets.keys()];
168838
+ const tags = getTagsByNumbers(args.db, args.sessionId, targetTagNumbers);
167769
168839
  const replayed = replayCavemanCompression(args.sessionId, args.db, targets, tags);
167770
168840
  if (replayed > 0) {
167771
168841
  sessionLog(args.sessionId, `pi caveman replay: ${replayed} tags re-compressed from source`);
@@ -167790,7 +168860,7 @@ async function runPipeline(args) {
167790
168860
  sessionLog(args.sessionId, `pi heuristic cleanup failed (continuing): ${err instanceof Error ? err.message : String(err)}`);
167791
168861
  }
167792
168862
  }
167793
- if (args.reasoningClearing && !args.reasoningClearing.skipTypedReasoningCleanup && (args.schedulerDecision === "execute" || args.forceMaterialization === true)) {
168863
+ if (args.reasoningClearing && (args.schedulerDecision === "execute" || args.forceMaterialization === true)) {
167794
168864
  try {
167795
168865
  const clearOutcome = clearOldReasoningPi({
167796
168866
  messages: args.messages,
@@ -167859,7 +168929,7 @@ function applyRollingNudge(args) {
167859
168929
  inputTokens: piUsage.tokens,
167860
168930
  contextLimit: piUsage.contextWindow
167861
168931
  };
167862
- const tags = getTagsBySession(db, sessionId);
168932
+ const tags = getActiveTagsBySession(db, sessionId);
167863
168933
  const messagesSinceLastUser = countMessagesSinceLastUserPi(messages);
167864
168934
  const nudge = nudgerFn(sessionId, usage, db, getTopNBySize, tags, messagesSinceLastUser, undefined);
167865
168935
  if (!nudge)
@@ -167989,6 +169059,7 @@ function clearContextHandlerSession(sessionId) {
167989
169059
  liveModelBySession.delete(sessionId);
167990
169060
  toolUsageSinceUserTurn.delete(sessionId);
167991
169061
  latestUserMessageBySession.delete(sessionId);
169062
+ clearSessionTracking(sessionId);
167992
169063
  clearPiCompressorState(sessionId);
167993
169064
  }
167994
169065
 
@@ -168038,7 +169109,7 @@ init_logger();
168038
169109
  init_data_path();
168039
169110
  init_logger();
168040
169111
  await init_sqlite();
168041
- import { join as join9 } from "node:path";
169112
+ import { join as join11 } from "node:path";
168042
169113
  var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
168043
169114
  function randomBase62(length) {
168044
169115
  const chars = [];
@@ -168059,7 +169130,7 @@ function generatePartId(timestampMs, counter = 0n) {
168059
169130
  return generateId("prt", timestampMs, counter);
168060
169131
  }
168061
169132
  function getOpenCodeDbPath3() {
168062
- return join9(getDataDir(), "opencode", "opencode.db");
169133
+ return join11(getDataDir(), "opencode", "opencode.db");
168063
169134
  }
168064
169135
  var cachedWriteDb = null;
168065
169136
  var REQUIRED_MESSAGE_COLUMNS = ["id", "session_id", "time_created", "time_updated", "data"];
@@ -168612,11 +169683,11 @@ async function runCompressorPass2(args) {
168612
169683
  }
168613
169684
 
168614
169685
  // ../plugin/src/hooks/magic-context/compartment-runner-historian.ts
168615
- import { mkdirSync as mkdirSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
169686
+ import { mkdirSync as mkdirSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
168616
169687
  import { tmpdir as tmpdir3 } from "node:os";
168617
- import { join as join10 } from "node:path";
169688
+ import { join as join12 } from "node:path";
168618
169689
  init_magic_context();
168619
- var HISTORIAN_RESPONSE_DUMP_DIR = join10(tmpdir3(), "magic-context-historian");
169690
+ var HISTORIAN_RESPONSE_DUMP_DIR = join12(tmpdir3(), "magic-context-historian");
168620
169691
  var MAX_HISTORIAN_RETRIES = 2;
168621
169692
  async function runValidatedHistorianPass(args) {
168622
169693
  const firstRun = await runHistorianPrompt({
@@ -168857,11 +169928,11 @@ function cleanupHistorianDump(sessionId, dumpPath) {
168857
169928
  }
168858
169929
  function dumpHistorianResponse(sessionId, label, text) {
168859
169930
  try {
168860
- mkdirSync4(HISTORIAN_RESPONSE_DUMP_DIR, { recursive: true });
169931
+ mkdirSync5(HISTORIAN_RESPONSE_DUMP_DIR, { recursive: true });
168861
169932
  const safeSessionId = sanitizeDumpName(sessionId);
168862
169933
  const safeLabel = sanitizeDumpName(label);
168863
- const dumpPath = join10(HISTORIAN_RESPONSE_DUMP_DIR, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
168864
- writeFileSync2(dumpPath, text, "utf8");
169934
+ const dumpPath = join12(HISTORIAN_RESPONSE_DUMP_DIR, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
169935
+ writeFileSync3(dumpPath, text, "utf8");
168865
169936
  sessionLog(sessionId, "compartment agent: historian response dumped", {
168866
169937
  label,
168867
169938
  dumpPath
@@ -169872,8 +170943,8 @@ function createPiRecompClient(args) {
169872
170943
  function readPathId(input) {
169873
170944
  if (typeof input !== "object" || input === null)
169874
170945
  return "";
169875
- const path4 = input.path;
169876
- return typeof path4?.id === "string" ? path4.id : "";
170946
+ const path5 = input.path;
170947
+ return typeof path5?.id === "string" ? path5.id : "";
169877
170948
  }
169878
170949
  function readBody(input) {
169879
170950
  if (typeof input !== "object" || input === null)
@@ -170028,7 +171099,7 @@ import {
170028
171099
  // package.json
170029
171100
  var package_default = {
170030
171101
  name: "@cortexkit/pi-magic-context",
170031
- version: "0.16.2",
171102
+ version: "0.17.0",
170032
171103
  type: "module",
170033
171104
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
170034
171105
  main: "dist/index.js",
@@ -170565,14 +171636,14 @@ function readHistorianState(db, sessionId, meta3) {
170565
171636
 
170566
171637
  // src/config/index.ts
170567
171638
  init_magic_context();
170568
- import { existsSync as existsSync6, readFileSync as readFileSync3 } from "node:fs";
171639
+ import { existsSync as existsSync8, readFileSync as readFileSync3 } from "node:fs";
170569
171640
  import { homedir as homedir4 } from "node:os";
170570
- import { join as join11 } from "node:path";
171641
+ import { join as join13 } from "node:path";
170571
171642
 
170572
171643
  // ../plugin/src/config/variable.ts
170573
- import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
171644
+ import { existsSync as existsSync7, readFileSync as readFileSync2 } from "node:fs";
170574
171645
  import { homedir as homedir3 } from "node:os";
170575
- import { dirname as dirname2, isAbsolute, resolve } from "node:path";
171646
+ import { dirname as dirname3, isAbsolute, resolve } from "node:path";
170576
171647
  var ENV_PATTERN = /\{env:([^}]+)\}/g;
170577
171648
  var FILE_PATTERN = /\{file:([^}]+)\}/g;
170578
171649
  function substituteConfigVariables(input) {
@@ -170591,7 +171662,7 @@ function substituteConfigVariables(input) {
170591
171662
  if (fileMatches.length === 0) {
170592
171663
  return { text, warnings };
170593
171664
  }
170594
- const configDir = input.configPath ? dirname2(input.configPath) : process.cwd();
171665
+ const configDir = input.configPath ? dirname3(input.configPath) : process.cwd();
170595
171666
  let output = "";
170596
171667
  let cursor = 0;
170597
171668
  for (const match of fileMatches) {
@@ -170613,7 +171684,7 @@ function substituteConfigVariables(input) {
170613
171684
  } else if (!isAbsolute(filePath)) {
170614
171685
  filePath = resolve(configDir, filePath);
170615
171686
  }
170616
- if (!existsSync5(filePath)) {
171687
+ if (!existsSync7(filePath)) {
170617
171688
  warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
170618
171689
  continue;
170619
171690
  }
@@ -170635,38 +171706,38 @@ function substituteConfigVariables(input) {
170635
171706
  var import_comment_json = __toESM(require_src2(), 1);
170636
171707
  var CONFIG_FILE_NAME = "magic-context";
170637
171708
  function getProjectConfigPaths(cwd) {
170638
- const basePath = join11(cwd, ".pi", CONFIG_FILE_NAME);
171709
+ const basePath = join13(cwd, ".pi", CONFIG_FILE_NAME);
170639
171710
  return [`${basePath}.jsonc`, `${basePath}.json`];
170640
171711
  }
170641
171712
  function getUserConfigPaths() {
170642
171713
  const home = process.env.HOME ?? homedir4();
170643
- const basePath = join11(home, ".pi", "agent", CONFIG_FILE_NAME);
171714
+ const basePath = join13(home, ".pi", "agent", CONFIG_FILE_NAME);
170644
171715
  return [`${basePath}.jsonc`, `${basePath}.json`];
170645
171716
  }
170646
171717
  function resolveFirstExisting(paths) {
170647
- return paths.find((path4) => existsSync6(path4));
171718
+ return paths.find((path5) => existsSync8(path5));
170648
171719
  }
170649
- function loadConfigFile(path4, scope) {
171720
+ function loadConfigFile(path5, scope) {
170650
171721
  try {
170651
- const rawText = readFileSync3(path4, "utf-8");
171722
+ const rawText = readFileSync3(path5, "utf-8");
170652
171723
  const substituted = substituteConfigVariables({
170653
171724
  text: rawText,
170654
- configPath: path4
171725
+ configPath: path5
170655
171726
  });
170656
171727
  return {
170657
- path: path4,
171728
+ path: path5,
170658
171729
  scope,
170659
171730
  config: import_comment_json.parse(substituted.text),
170660
- warnings: substituted.warnings.map((warning) => `${path4}: ${warning}`)
171731
+ warnings: substituted.warnings.map((warning) => `${path5}: ${warning}`)
170661
171732
  };
170662
171733
  } catch (error48) {
170663
171734
  const message = error48 instanceof Error ? error48.message : String(error48);
170664
171735
  return {
170665
- path: path4,
171736
+ path: path5,
170666
171737
  scope,
170667
171738
  config: {},
170668
171739
  warnings: [
170669
- `${path4}: failed to load config: ${message}; using defaults for this file.`
171740
+ `${path5}: failed to load config: ${message}; using defaults for this file.`
170670
171741
  ]
170671
171742
  };
170672
171743
  }
@@ -170796,8 +171867,8 @@ function stripTagPrefixFromAssistantMessage(message) {
170796
171867
 
170797
171868
  // src/system-prompt.ts
170798
171869
  import { createHash as createHash4 } from "node:crypto";
170799
- import { existsSync as existsSync7, readFileSync as readFileSync4, realpathSync } from "node:fs";
170800
- import { join as join12, resolve as resolve2, sep } from "node:path";
171870
+ import { existsSync as existsSync9, readFileSync as readFileSync4, realpathSync } from "node:fs";
171871
+ import { join as join14, resolve as resolve2, sep } from "node:path";
170801
171872
 
170802
171873
  // ../plugin/src/agents/magic-context-prompt.ts
170803
171874
  function getToolHistoryGuidance(dropToolStructure) {
@@ -170899,9 +171970,9 @@ var DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
170899
171970
  function readProjectDocs(directory) {
170900
171971
  const sections = [];
170901
171972
  for (const filename of DOC_FILES) {
170902
- const filePath = join12(directory, filename);
171973
+ const filePath = join14(directory, filename);
170903
171974
  try {
170904
- if (existsSync7(filePath)) {
171975
+ if (existsSync9(filePath)) {
170905
171976
  const content = readFileSync4(filePath, "utf-8").trim();
170906
171977
  if (content.length > 0) {
170907
171978
  sections.push(`<${filename}>
@@ -170945,7 +172016,7 @@ function buildKeyFilesBlock(db, sessionId, directory, tokenBudget) {
170945
172016
  log(`[magic-context-pi] key file path escapes project root, skipping: ${entry.filePath}`);
170946
172017
  continue;
170947
172018
  }
170948
- if (!existsSync7(absPath))
172019
+ if (!existsSync9(absPath))
170949
172020
  continue;
170950
172021
  let realPath;
170951
172022
  try {
@@ -176022,7 +177093,7 @@ function registerMagicContextTools(pi, opts) {
176022
177093
  }
176023
177094
 
176024
177095
  // src/index.ts
176025
- var PREFIX = "[magic-context][pi]";
177096
+ var PREFIX2 = "[magic-context][pi]";
176026
177097
  function persistPiMessageEndModelMeta(args) {
176027
177098
  if (!args.message || typeof args.message !== "object")
176028
177099
  return;
@@ -176039,14 +177110,14 @@ function persistPiMessageEndModelMeta(args) {
176039
177110
  }
176040
177111
  }
176041
177112
  function info(message, data) {
176042
- log(`${PREFIX} ${message}`, data);
177113
+ log(`${PREFIX2} ${message}`, data);
176043
177114
  }
176044
177115
  function warn(message, data) {
176045
- log(`${PREFIX} WARN ${message}`, data);
177116
+ log(`${PREFIX2} WARN ${message}`, data);
176046
177117
  }
176047
177118
  var PLUGIN_VERSION = (() => {
176048
177119
  try {
176049
- const req = createRequire(import.meta.url);
177120
+ const req = createRequire2(import.meta.url);
176050
177121
  return req("../package.json").version;
176051
177122
  } catch {
176052
177123
  return "0.0.0";
@@ -176127,7 +177198,7 @@ function resolveDreamerFromConfig(config2) {
176127
177198
  }
176128
177199
  async function src_default2(pi) {
176129
177200
  const storageDir = getMagicContextStorageDir();
176130
- const dbPath = join13(storageDir, "context.db");
177201
+ const dbPath = join15(storageDir, "context.db");
176131
177202
  let db;
176132
177203
  try {
176133
177204
  db = openDatabase();
@@ -176381,6 +177452,11 @@ ${block}` : event.systemPrompt;
176381
177452
  const sessionId = sm?.getSessionId?.();
176382
177453
  if (typeof sessionId !== "string" || sessionId.length === 0)
176383
177454
  return;
177455
+ const rawMessages = readPiSessionMessages(ctx);
177456
+ const latest = rawMessages[rawMessages.length - 1];
177457
+ if (latest?.role === "assistant" && latest.id.length > 0) {
177458
+ scheduleIncrementalIndex(db, sessionId, latest.id, () => latest);
177459
+ }
176384
177460
  persistPiMessageEndModelMeta({
176385
177461
  db,
176386
177462
  sessionId,