@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.
@@ -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(path3) {
15147
+ let normalized = path3.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 (path3.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 path3 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 = path3.dirname(pkgJsonPath);
15260
+ const pkgJson = requireFn(pkgJsonPath);
15261
+ const binaryPath = path3.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 path3.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(path3.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
 
@@ -15159,12 +15479,12 @@ var require_esprima = __commonJS((exports, module) => {
15159
15479
  }
15160
15480
  exports2.parseScript = parseScript;
15161
15481
  function tokenize(code, options, delegate) {
15162
- var tokenizer = new tokenizer_1.Tokenizer(code, options);
15482
+ var tokenizer2 = new tokenizer_1.Tokenizer(code, options);
15163
15483
  var tokens;
15164
15484
  tokens = [];
15165
15485
  try {
15166
15486
  while (true) {
15167
- var token = tokenizer.getNextToken();
15487
+ var token = tokenizer2.getNextToken();
15168
15488
  if (!token) {
15169
15489
  break;
15170
15490
  }
@@ -15174,10 +15494,10 @@ var require_esprima = __commonJS((exports, module) => {
15174
15494
  tokens.push(token);
15175
15495
  }
15176
15496
  } catch (e) {
15177
- tokenizer.errorHandler.tolerate(e);
15497
+ tokenizer2.errorHandler.tolerate(e);
15178
15498
  }
15179
- if (tokenizer.errorHandler.tolerant) {
15180
- tokens.errors = tokenizer.errors();
15499
+ if (tokenizer2.errorHandler.tolerant) {
15500
+ tokens.errors = tokenizer2.errors();
15181
15501
  }
15182
15502
  return tokens;
15183
15503
  }
@@ -15752,13 +16072,13 @@ var require_esprima = __commonJS((exports, module) => {
15752
16072
  };
15753
16073
  JSXParser2.prototype.parseJSXNameValueAttribute = function() {
15754
16074
  var node = this.createJSXNode();
15755
- var name = this.parseJSXAttributeName();
16075
+ var name2 = this.parseJSXAttributeName();
15756
16076
  var value = null;
15757
16077
  if (this.matchJSX("=")) {
15758
16078
  this.expectJSX("=");
15759
16079
  value = this.parseJSXAttributeValue();
15760
16080
  }
15761
- return this.finalize(node, new JSXNode.JSXAttribute(name, value));
16081
+ return this.finalize(node, new JSXNode.JSXAttribute(name2, value));
15762
16082
  };
15763
16083
  JSXParser2.prototype.parseJSXSpreadAttribute = function() {
15764
16084
  var node = this.createJSXNode();
@@ -15780,14 +16100,14 @@ var require_esprima = __commonJS((exports, module) => {
15780
16100
  JSXParser2.prototype.parseJSXOpeningElement = function() {
15781
16101
  var node = this.createJSXNode();
15782
16102
  this.expectJSX("<");
15783
- var name = this.parseJSXElementName();
16103
+ var name2 = this.parseJSXElementName();
15784
16104
  var attributes = this.parseJSXAttributes();
15785
16105
  var selfClosing = this.matchJSX("/");
15786
16106
  if (selfClosing) {
15787
16107
  this.expectJSX("/");
15788
16108
  }
15789
16109
  this.expectJSX(">");
15790
- return this.finalize(node, new JSXNode.JSXOpeningElement(name, selfClosing, attributes));
16110
+ return this.finalize(node, new JSXNode.JSXOpeningElement(name2, selfClosing, attributes));
15791
16111
  };
15792
16112
  JSXParser2.prototype.parseJSXBoundaryElement = function() {
15793
16113
  var node = this.createJSXNode();
@@ -15798,14 +16118,14 @@ var require_esprima = __commonJS((exports, module) => {
15798
16118
  this.expectJSX(">");
15799
16119
  return this.finalize(node, new JSXNode.JSXClosingElement(name_3));
15800
16120
  }
15801
- var name = this.parseJSXElementName();
16121
+ var name2 = this.parseJSXElementName();
15802
16122
  var attributes = this.parseJSXAttributes();
15803
16123
  var selfClosing = this.matchJSX("/");
15804
16124
  if (selfClosing) {
15805
16125
  this.expectJSX("/");
15806
16126
  }
15807
16127
  this.expectJSX(">");
15808
- return this.finalize(node, new JSXNode.JSXOpeningElement(name, selfClosing, attributes));
16128
+ return this.finalize(node, new JSXNode.JSXOpeningElement(name2, selfClosing, attributes));
15809
16129
  };
15810
16130
  JSXParser2.prototype.parseJSXEmptyExpression = function() {
15811
16131
  var node = this.createJSXChildNode();
@@ -15948,9 +16268,9 @@ var require_esprima = __commonJS((exports, module) => {
15948
16268
  Object.defineProperty(exports2, "__esModule", { value: true });
15949
16269
  var jsx_syntax_1 = __webpack_require__(6);
15950
16270
  var JSXClosingElement = function() {
15951
- function JSXClosingElement2(name) {
16271
+ function JSXClosingElement2(name2) {
15952
16272
  this.type = jsx_syntax_1.JSXSyntax.JSXClosingElement;
15953
- this.name = name;
16273
+ this.name = name2;
15954
16274
  }
15955
16275
  return JSXClosingElement2;
15956
16276
  }();
@@ -15981,9 +16301,9 @@ var require_esprima = __commonJS((exports, module) => {
15981
16301
  }();
15982
16302
  exports2.JSXExpressionContainer = JSXExpressionContainer;
15983
16303
  var JSXIdentifier = function() {
15984
- function JSXIdentifier2(name) {
16304
+ function JSXIdentifier2(name2) {
15985
16305
  this.type = jsx_syntax_1.JSXSyntax.JSXIdentifier;
15986
- this.name = name;
16306
+ this.name = name2;
15987
16307
  }
15988
16308
  return JSXIdentifier2;
15989
16309
  }();
@@ -15998,27 +16318,27 @@ var require_esprima = __commonJS((exports, module) => {
15998
16318
  }();
15999
16319
  exports2.JSXMemberExpression = JSXMemberExpression;
16000
16320
  var JSXAttribute = function() {
16001
- function JSXAttribute2(name, value) {
16321
+ function JSXAttribute2(name2, value) {
16002
16322
  this.type = jsx_syntax_1.JSXSyntax.JSXAttribute;
16003
- this.name = name;
16323
+ this.name = name2;
16004
16324
  this.value = value;
16005
16325
  }
16006
16326
  return JSXAttribute2;
16007
16327
  }();
16008
16328
  exports2.JSXAttribute = JSXAttribute;
16009
16329
  var JSXNamespacedName = function() {
16010
- function JSXNamespacedName2(namespace, name) {
16330
+ function JSXNamespacedName2(namespace, name2) {
16011
16331
  this.type = jsx_syntax_1.JSXSyntax.JSXNamespacedName;
16012
16332
  this.namespace = namespace;
16013
- this.name = name;
16333
+ this.name = name2;
16014
16334
  }
16015
16335
  return JSXNamespacedName2;
16016
16336
  }();
16017
16337
  exports2.JSXNamespacedName = JSXNamespacedName;
16018
16338
  var JSXOpeningElement = function() {
16019
- function JSXOpeningElement2(name, selfClosing, attributes) {
16339
+ function JSXOpeningElement2(name2, selfClosing, attributes) {
16020
16340
  this.type = jsx_syntax_1.JSXSyntax.JSXOpeningElement;
16021
- this.name = name;
16341
+ this.name = name2;
16022
16342
  this.selfClosing = selfClosing;
16023
16343
  this.attributes = attributes;
16024
16344
  }
@@ -16392,9 +16712,9 @@ var require_esprima = __commonJS((exports, module) => {
16392
16712
  }();
16393
16713
  exports2.FunctionExpression = FunctionExpression;
16394
16714
  var Identifier = function() {
16395
- function Identifier2(name) {
16715
+ function Identifier2(name2) {
16396
16716
  this.type = syntax_1.Syntax.Identifier;
16397
- this.name = name;
16717
+ this.name = name2;
16398
16718
  }
16399
16719
  return Identifier2;
16400
16720
  }();
@@ -18900,10 +19220,10 @@ var require_esprima = __commonJS((exports, module) => {
18900
19220
  this.context.inFunctionBody = previousInFunctionBody;
18901
19221
  return this.finalize(node, new Node.BlockStatement(body));
18902
19222
  };
18903
- Parser2.prototype.validateParam = function(options, param, name) {
18904
- var key = "$" + name;
19223
+ Parser2.prototype.validateParam = function(options, param, name2) {
19224
+ var key = "$" + name2;
18905
19225
  if (this.context.strict) {
18906
- if (this.scanner.isRestrictedWord(name)) {
19226
+ if (this.scanner.isRestrictedWord(name2)) {
18907
19227
  options.stricted = param;
18908
19228
  options.message = messages_1.Messages.StrictParamName;
18909
19229
  }
@@ -18912,10 +19232,10 @@ var require_esprima = __commonJS((exports, module) => {
18912
19232
  options.message = messages_1.Messages.StrictParamDupe;
18913
19233
  }
18914
19234
  } else if (!options.firstRestricted) {
18915
- if (this.scanner.isRestrictedWord(name)) {
19235
+ if (this.scanner.isRestrictedWord(name2)) {
18916
19236
  options.firstRestricted = param;
18917
19237
  options.message = messages_1.Messages.StrictParamName;
18918
- } else if (this.scanner.isStrictModeReservedWord(name)) {
19238
+ } else if (this.scanner.isStrictModeReservedWord(name2)) {
18919
19239
  options.firstRestricted = param;
18920
19240
  options.message = messages_1.Messages.StrictReservedWord;
18921
19241
  } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
@@ -21123,8 +21443,8 @@ var require_esprima = __commonJS((exports, module) => {
21123
21443
  };
21124
21444
  return Reader2;
21125
21445
  }();
21126
- var Tokenizer = function() {
21127
- function Tokenizer2(code, config2) {
21446
+ var Tokenizer2 = function() {
21447
+ function Tokenizer3(code, config2) {
21128
21448
  this.errorHandler = new error_handler_1.ErrorHandler;
21129
21449
  this.errorHandler.tolerant = config2 ? typeof config2.tolerant === "boolean" && config2.tolerant : false;
21130
21450
  this.scanner = new scanner_1.Scanner(code, this.errorHandler);
@@ -21134,10 +21454,10 @@ var require_esprima = __commonJS((exports, module) => {
21134
21454
  this.buffer = [];
21135
21455
  this.reader = new Reader;
21136
21456
  }
21137
- Tokenizer2.prototype.errors = function() {
21457
+ Tokenizer3.prototype.errors = function() {
21138
21458
  return this.errorHandler.errors;
21139
21459
  };
21140
- Tokenizer2.prototype.getNextToken = function() {
21460
+ Tokenizer3.prototype.getNextToken = function() {
21141
21461
  if (this.buffer.length === 0) {
21142
21462
  var comments = this.scanner.scanComments();
21143
21463
  if (this.scanner.trackComment) {
@@ -21195,9 +21515,9 @@ var require_esprima = __commonJS((exports, module) => {
21195
21515
  }
21196
21516
  return this.buffer.shift();
21197
21517
  };
21198
- return Tokenizer2;
21518
+ return Tokenizer3;
21199
21519
  }();
21200
- exports2.Tokenizer = Tokenizer;
21520
+ exports2.Tokenizer = Tokenizer2;
21201
21521
  }
21202
21522
  ]);
21203
21523
  });
@@ -22422,7 +22742,7 @@ var require_parse = __commonJS((exports, module) => {
22422
22742
  set_comments_host(obj);
22423
22743
  set_prop(UNDEFINED, true);
22424
22744
  let started = false;
22425
- let name;
22745
+ let name2;
22426
22746
  parse_comments();
22427
22747
  while (!is(CURLY_BRACKET_CLOSE)) {
22428
22748
  if (started) {
@@ -22437,15 +22757,15 @@ var require_parse = __commonJS((exports, module) => {
22437
22757
  }
22438
22758
  started = true;
22439
22759
  expect("String");
22440
- name = JSON.parse(current.value);
22441
- set_prop(name);
22760
+ name2 = JSON.parse(current.value);
22761
+ set_prop(name2);
22442
22762
  assign_comments(PREFIX_BEFORE);
22443
22763
  next();
22444
22764
  parse_comments(PREFIX_AFTER_PROP);
22445
22765
  expect(COLON);
22446
22766
  next();
22447
22767
  parse_comments(PREFIX_AFTER_COLON);
22448
- obj[name] = transform2(name, walk());
22768
+ obj[name2] = transform2(name2, walk());
22449
22769
  parse_comments();
22450
22770
  }
22451
22771
  if (started) {
@@ -22670,10 +22990,10 @@ var require_stringify = __commonJS((exports, module) => {
22670
22990
  replacer = null;
22671
22991
  indent = EMPTY;
22672
22992
  };
22673
- var join5 = (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;
22993
+ var join7 = (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;
22674
22994
  var join_content = (inside, value, gap) => {
22675
22995
  const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
22676
- return join5(comment, inside, gap);
22996
+ return join7(comment, inside, gap);
22677
22997
  };
22678
22998
  var stringify_string = (holder, key, value) => {
22679
22999
  const raw = get_raw_string_literal(holder, key);
@@ -22695,13 +23015,13 @@ var require_stringify = __commonJS((exports, module) => {
22695
23015
  if (i !== 0) {
22696
23016
  inside += COMMA;
22697
23017
  }
22698
- const before = join5(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
23018
+ const before = join7(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
22699
23019
  inside += before || LF + deeper_gap;
22700
23020
  inside += stringify(i, value, deeper_gap) || STR_NULL;
22701
23021
  inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
22702
23022
  after_comma = process_comments(value, AFTER(i), deeper_gap);
22703
23023
  }
22704
- inside += join5(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
23024
+ inside += join7(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
22705
23025
  return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
22706
23026
  };
22707
23027
  var object_stringify = (value, gap) => {
@@ -22722,13 +23042,13 @@ var require_stringify = __commonJS((exports, module) => {
22722
23042
  inside += COMMA;
22723
23043
  }
22724
23044
  first = false;
22725
- const before = join5(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
23045
+ const before = join7(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
22726
23046
  inside += before || LF + deeper_gap;
22727
23047
  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);
22728
23048
  after_comma = process_comments(value, AFTER(key), deeper_gap);
22729
23049
  };
22730
23050
  keys.forEach(iteratee);
22731
- inside += join5(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
23051
+ inside += join7(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
22732
23052
  return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
22733
23053
  };
22734
23054
  function stringify(key, holder, gap) {
@@ -22829,9 +23149,9 @@ __export(exports_read_session_db, {
22829
23149
  findLastAssistantModelFromOpenCodeDb: () => findLastAssistantModelFromOpenCodeDb,
22830
23150
  closeReadOnlySessionDb: () => closeReadOnlySessionDb
22831
23151
  });
22832
- import { join as join6 } from "node:path";
23152
+ import { join as join8 } from "node:path";
22833
23153
  function getOpenCodeDbPath() {
22834
- return join6(getDataDir(), "opencode", "opencode.db");
23154
+ return join8(getDataDir(), "opencode", "opencode.db");
22835
23155
  }
22836
23156
  function closeCachedReadOnlyDb() {
22837
23157
  if (!cachedReadOnlyDb) {
@@ -22890,7 +23210,8 @@ function findLastAssistantModelFromOpenCodeDb(sessionId) {
22890
23210
  try {
22891
23211
  return withReadOnlySessionDb((db) => {
22892
23212
  const row = db.prepare(`SELECT json_extract(data, '$.providerID') as providerID,
22893
- json_extract(data, '$.modelID') as modelID
23213
+ json_extract(data, '$.modelID') as modelID,
23214
+ json_extract(data, '$.agent') as agent
22894
23215
  FROM message
22895
23216
  WHERE session_id = ?
22896
23217
  AND json_extract(data, '$.role') = 'assistant'
@@ -22901,7 +23222,12 @@ function findLastAssistantModelFromOpenCodeDb(sessionId) {
22901
23222
  if (!row || typeof row.providerID !== "string" || typeof row.modelID !== "string") {
22902
23223
  return null;
22903
23224
  }
22904
- return { providerID: row.providerID, modelID: row.modelID };
23225
+ const agent = typeof row.agent === "string" && row.agent.length > 0 ? row.agent : undefined;
23226
+ return {
23227
+ providerID: row.providerID,
23228
+ modelID: row.modelID,
23229
+ ...agent ? { agent } : {}
23230
+ };
22905
23231
  });
22906
23232
  } catch (error48) {
22907
23233
  log("[magic-context] failed to recover live model from OpenCode DB:", error48);
@@ -22920,8 +23246,8 @@ init_embedding();
22920
23246
 
22921
23247
  // ../plugin/src/features/magic-context/storage-db.ts
22922
23248
  init_data_path();
22923
- import { copyFileSync, cpSync, existsSync, mkdirSync as mkdirSync2 } from "node:fs";
22924
- import { join as join4 } from "node:path";
23249
+ import { copyFileSync, cpSync, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "node:fs";
23250
+ import { join as join6 } from "node:path";
22925
23251
 
22926
23252
  // ../plugin/src/shared/error-message.ts
22927
23253
  function getErrorMessage(error48) {
@@ -23206,6 +23532,58 @@ var MIGRATIONS = [
23206
23532
  db.exec("ALTER TABLE notes ADD COLUMN harness TEXT NOT NULL DEFAULT 'opencode'");
23207
23533
  }
23208
23534
  }
23535
+ },
23536
+ {
23537
+ version: 8,
23538
+ description: "Add partial indexes on tags(session_id, tag_number) for active and dropped",
23539
+ up: (db) => {
23540
+ db.exec(`
23541
+ CREATE INDEX IF NOT EXISTS idx_tags_active_session_tag_number
23542
+ ON tags(session_id, tag_number)
23543
+ WHERE status = 'active';
23544
+
23545
+ CREATE INDEX IF NOT EXISTS idx_tags_dropped_session_tag_number
23546
+ ON tags(session_id, tag_number)
23547
+ WHERE status = 'dropped';
23548
+ `);
23549
+ db.exec("ANALYZE tags;");
23550
+ }
23551
+ },
23552
+ {
23553
+ version: 9,
23554
+ description: "Persist tool_definition_measurements across plugin restarts",
23555
+ up: (db) => {
23556
+ db.exec(`
23557
+ CREATE TABLE IF NOT EXISTS tool_definition_measurements (
23558
+ provider_id TEXT NOT NULL,
23559
+ model_id TEXT NOT NULL,
23560
+ agent_name TEXT NOT NULL,
23561
+ tool_id TEXT NOT NULL,
23562
+ token_count INTEGER NOT NULL,
23563
+ recorded_at INTEGER NOT NULL,
23564
+ PRIMARY KEY (provider_id, model_id, agent_name, tool_id)
23565
+ );
23566
+ `);
23567
+ }
23568
+ },
23569
+ {
23570
+ version: 10,
23571
+ description: "Add tool_owner_message_id column to tags + composite identity indexes",
23572
+ up: (db) => {
23573
+ const cols = db.prepare("PRAGMA table_info(tags)").all();
23574
+ if (!cols.some((c) => c.name === "tool_owner_message_id")) {
23575
+ db.exec("ALTER TABLE tags ADD COLUMN tool_owner_message_id TEXT DEFAULT NULL");
23576
+ }
23577
+ db.exec(`
23578
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_tags_tool_composite
23579
+ ON tags(session_id, message_id, tool_owner_message_id)
23580
+ WHERE type = 'tool' AND tool_owner_message_id IS NOT NULL;
23581
+
23582
+ CREATE INDEX IF NOT EXISTS idx_tags_tool_null_owner
23583
+ ON tags(session_id, message_id)
23584
+ WHERE type = 'tool' AND tool_owner_message_id IS NULL;
23585
+ `);
23586
+ }
23209
23587
  }
23210
23588
  ];
23211
23589
  function ensureMigrationsTable(db) {
@@ -23221,22 +23599,51 @@ function getCurrentVersion(db) {
23221
23599
  const row = db.prepare("SELECT MAX(version) as version FROM schema_migrations").get();
23222
23600
  return row?.version ?? 0;
23223
23601
  }
23602
+ function isSiblingMigrationConflict(error48, version2) {
23603
+ if (!(error48 instanceof Error))
23604
+ return false;
23605
+ const code = error48.code;
23606
+ if (code !== "SQLITE_CONSTRAINT_PRIMARYKEY" && code !== "SQLITE_CONSTRAINT_UNIQUE") {
23607
+ return false;
23608
+ }
23609
+ const msg = error48.message;
23610
+ if (!msg.includes("schema_migrations"))
23611
+ return false;
23612
+ if (!msg.toLowerCase().includes("version"))
23613
+ return false;
23614
+ return true;
23615
+ }
23224
23616
  function runMigrations(db) {
23225
23617
  ensureMigrationsTable(db);
23226
- const currentVersion = getCurrentVersion(db);
23227
- const pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
23618
+ let currentVersion = getCurrentVersion(db);
23619
+ let pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
23228
23620
  if (pendingMigrations.length === 0) {
23229
23621
  return;
23230
23622
  }
23231
23623
  log(`[migrations] current schema version: ${currentVersion}, applying ${pendingMigrations.length} migration(s)`);
23232
- for (const migration of pendingMigrations) {
23624
+ let migrationIndex = 0;
23625
+ while (migrationIndex < pendingMigrations.length) {
23626
+ const migration = pendingMigrations[migrationIndex];
23233
23627
  try {
23234
23628
  db.transaction(() => {
23235
23629
  migration.up(db);
23236
23630
  db.prepare("INSERT INTO schema_migrations (version, description, applied_at) VALUES (?, ?, ?)").run(migration.version, migration.description, Date.now());
23237
23631
  })();
23238
23632
  log(`[migrations] applied v${migration.version}: ${migration.description}`);
23633
+ migrationIndex += 1;
23239
23634
  } catch (error48) {
23635
+ if (isSiblingMigrationConflict(error48, migration.version)) {
23636
+ log(`[migrations] v${migration.version} already applied by sibling instance — resuming with re-read version`);
23637
+ const reReadVersion = getCurrentVersion(db);
23638
+ if (reReadVersion <= currentVersion) {
23639
+ log(`[migrations] FAILED v${migration.version}: sibling-conflict shape but version not advanced (${reReadVersion} <= ${currentVersion}) — failing closed`);
23640
+ throw new Error(`Migration v${migration.version} failed: sibling conflict reported but version did not advance. Database may need manual repair.`);
23641
+ }
23642
+ currentVersion = reReadVersion;
23643
+ pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
23644
+ migrationIndex = 0;
23645
+ continue;
23646
+ }
23240
23647
  log(`[migrations] FAILED v${migration.version}: ${migration.description} — ${error48 instanceof Error ? error48.message : String(error48)}`);
23241
23648
  throw new Error(`Migration v${migration.version} failed: ${error48 instanceof Error ? error48.message : String(error48)}. Database may need manual repair.`);
23242
23649
  }
@@ -23244,655 +23651,6 @@ function runMigrations(db) {
23244
23651
  log(`[migrations] schema version now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
23245
23652
  }
23246
23653
 
23247
- // ../plugin/src/features/magic-context/storage-db.ts
23248
- var databases = new Map;
23249
- var persistenceByDatabase = new WeakMap;
23250
- var persistenceErrorByDatabase = new WeakMap;
23251
- function resolveDatabasePath() {
23252
- const dbDir = getMagicContextStorageDir();
23253
- return { dbDir, dbPath: join4(dbDir, "context.db") };
23254
- }
23255
- function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
23256
- if (existsSync(targetDbPath))
23257
- return;
23258
- const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
23259
- const legacyDbPath = join4(legacyDir, "context.db");
23260
- if (!existsSync(legacyDbPath))
23261
- return;
23262
- log(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
23263
- mkdirSync2(targetDbDir, { recursive: true });
23264
- for (const suffix of ["", "-wal", "-shm"]) {
23265
- const src = `${legacyDbPath}${suffix}`;
23266
- const dst = join4(targetDbDir, `context.db${suffix}`);
23267
- if (existsSync(src)) {
23268
- try {
23269
- copyFileSync(src, dst);
23270
- } catch (error48) {
23271
- log(`[magic-context] failed to copy ${src}:`, getErrorMessage(error48));
23272
- }
23273
- }
23274
- }
23275
- const legacyModelsDir = join4(legacyDir, "models");
23276
- const targetModelsDir = join4(targetDbDir, "models");
23277
- if (existsSync(legacyModelsDir) && !existsSync(targetModelsDir)) {
23278
- try {
23279
- cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
23280
- } catch (error48) {
23281
- log("[magic-context] failed to copy embedding model cache:", getErrorMessage(error48));
23282
- }
23283
- }
23284
- }
23285
- function initializeDatabase(db) {
23286
- db.exec("PRAGMA journal_mode=WAL");
23287
- db.exec("PRAGMA busy_timeout=5000");
23288
- db.exec("PRAGMA foreign_keys=ON");
23289
- db.exec(`
23290
- CREATE TABLE IF NOT EXISTS tags (
23291
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23292
- session_id TEXT,
23293
- message_id TEXT,
23294
- type TEXT,
23295
- status TEXT DEFAULT 'active',
23296
- byte_size INTEGER,
23297
- tag_number INTEGER,
23298
- harness TEXT NOT NULL DEFAULT 'opencode',
23299
- UNIQUE(session_id, tag_number)
23300
- );
23301
-
23302
- CREATE TABLE IF NOT EXISTS pending_ops (
23303
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23304
- session_id TEXT,
23305
- tag_id INTEGER,
23306
- operation TEXT,
23307
- queued_at INTEGER,
23308
- harness TEXT NOT NULL DEFAULT 'opencode'
23309
- );
23310
-
23311
- CREATE TABLE IF NOT EXISTS source_contents (
23312
- tag_id INTEGER,
23313
- session_id TEXT,
23314
- content TEXT,
23315
- created_at INTEGER,
23316
- harness TEXT NOT NULL DEFAULT 'opencode',
23317
- PRIMARY KEY(session_id, tag_id)
23318
- );
23319
-
23320
- CREATE TABLE IF NOT EXISTS compartments (
23321
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23322
- session_id TEXT NOT NULL,
23323
- sequence INTEGER NOT NULL,
23324
- start_message INTEGER NOT NULL,
23325
- end_message INTEGER NOT NULL,
23326
- start_message_id TEXT DEFAULT '',
23327
- end_message_id TEXT DEFAULT '',
23328
- title TEXT NOT NULL,
23329
- content TEXT NOT NULL,
23330
- created_at INTEGER NOT NULL,
23331
- harness TEXT NOT NULL DEFAULT 'opencode',
23332
- UNIQUE(session_id, sequence)
23333
- );
23334
- CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
23335
-
23336
- CREATE TABLE IF NOT EXISTS compression_depth (
23337
- session_id TEXT NOT NULL,
23338
- message_ordinal INTEGER NOT NULL,
23339
- depth INTEGER NOT NULL DEFAULT 0,
23340
- harness TEXT NOT NULL DEFAULT 'opencode',
23341
- PRIMARY KEY(session_id, message_ordinal)
23342
- );
23343
- CREATE INDEX IF NOT EXISTS idx_compression_depth_session ON compression_depth(session_id);
23344
-
23345
- CREATE TABLE IF NOT EXISTS session_facts (
23346
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23347
- session_id TEXT NOT NULL,
23348
- category TEXT NOT NULL,
23349
- content TEXT NOT NULL,
23350
- created_at INTEGER NOT NULL,
23351
- updated_at INTEGER NOT NULL,
23352
- harness TEXT NOT NULL DEFAULT 'opencode'
23353
- );
23354
-
23355
- -- session_notes and smart_notes were merged into the unified notes table
23356
- -- by migration v1 (see features/magic-context/migrations.ts). The old tables
23357
- -- are never recreated; fresh DBs create only notes, upgraded DBs have
23358
- -- their old tables migrated and dropped by the migration runner.
23359
-
23360
- CREATE TABLE IF NOT EXISTS memories (
23361
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23362
- project_path TEXT NOT NULL,
23363
- category TEXT NOT NULL,
23364
- content TEXT NOT NULL,
23365
- normalized_hash TEXT NOT NULL,
23366
- source_session_id TEXT,
23367
- source_type TEXT DEFAULT 'historian',
23368
- seen_count INTEGER DEFAULT 1,
23369
- retrieval_count INTEGER DEFAULT 0,
23370
- first_seen_at INTEGER NOT NULL,
23371
- created_at INTEGER NOT NULL,
23372
- updated_at INTEGER NOT NULL,
23373
- last_seen_at INTEGER NOT NULL,
23374
- last_retrieved_at INTEGER,
23375
- status TEXT DEFAULT 'active',
23376
- expires_at INTEGER,
23377
- verification_status TEXT DEFAULT 'unverified',
23378
- verified_at INTEGER,
23379
- superseded_by_memory_id INTEGER,
23380
- merged_from TEXT,
23381
- metadata_json TEXT,
23382
- UNIQUE(project_path, category, normalized_hash)
23383
- );
23384
-
23385
- CREATE TABLE IF NOT EXISTS memory_embeddings (
23386
- memory_id INTEGER PRIMARY KEY REFERENCES memories(id) ON DELETE CASCADE,
23387
- embedding BLOB NOT NULL,
23388
- model_id TEXT
23389
- );
23390
-
23391
- CREATE TABLE IF NOT EXISTS dream_state (
23392
- key TEXT PRIMARY KEY,
23393
- value TEXT NOT NULL
23394
- );
23395
-
23396
- CREATE TABLE IF NOT EXISTS dream_queue (
23397
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23398
- project_path TEXT NOT NULL,
23399
- reason TEXT NOT NULL,
23400
- enqueued_at INTEGER NOT NULL,
23401
- started_at INTEGER,
23402
- retry_count INTEGER DEFAULT 0
23403
- );
23404
- CREATE INDEX IF NOT EXISTS idx_dream_queue_project ON dream_queue(project_path);
23405
- CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, enqueued_at);
23406
-
23407
- CREATE TABLE IF NOT EXISTS dream_runs (
23408
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23409
- project_path TEXT NOT NULL,
23410
- started_at INTEGER NOT NULL,
23411
- finished_at INTEGER NOT NULL,
23412
- holder_id TEXT NOT NULL,
23413
- tasks_json TEXT NOT NULL,
23414
- tasks_succeeded INTEGER NOT NULL DEFAULT 0,
23415
- tasks_failed INTEGER NOT NULL DEFAULT 0,
23416
- smart_notes_surfaced INTEGER NOT NULL DEFAULT 0,
23417
- smart_notes_pending INTEGER NOT NULL DEFAULT 0,
23418
- memory_changes_json TEXT
23419
- );
23420
- CREATE INDEX IF NOT EXISTS idx_dream_runs_project ON dream_runs(project_path, finished_at DESC);
23421
-
23422
- -- (smart_notes: see note above; merged into unified notes table by migration v1)
23423
-
23424
- CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
23425
- content,
23426
- category,
23427
- content='memories',
23428
- content_rowid='id',
23429
- tokenize='porter unicode61'
23430
- );
23431
-
23432
- CREATE VIRTUAL TABLE IF NOT EXISTS message_history_fts USING fts5(
23433
- session_id UNINDEXED,
23434
- message_ordinal UNINDEXED,
23435
- message_id UNINDEXED,
23436
- role,
23437
- content,
23438
- tokenize='porter unicode61'
23439
- );
23440
-
23441
- CREATE TABLE IF NOT EXISTS message_history_index (
23442
- session_id TEXT PRIMARY KEY,
23443
- last_indexed_ordinal INTEGER NOT NULL DEFAULT 0,
23444
- updated_at INTEGER NOT NULL,
23445
- harness TEXT NOT NULL DEFAULT 'opencode'
23446
- );
23447
-
23448
- CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
23449
- INSERT INTO memories_fts(rowid, content, category) VALUES (new.id, new.content, new.category);
23450
- END;
23451
-
23452
- CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
23453
- INSERT INTO memories_fts(memories_fts, rowid, content, category) VALUES ('delete', old.id, old.content, old.category);
23454
- END;
23455
-
23456
- CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
23457
- INSERT INTO memories_fts(memories_fts, rowid, content, category) VALUES ('delete', old.id, old.content, old.category);
23458
- INSERT INTO memories_fts(rowid, content, category) VALUES (new.id, new.content, new.category);
23459
- END;
23460
-
23461
- CREATE TABLE IF NOT EXISTS session_meta (
23462
- session_id TEXT PRIMARY KEY,
23463
- harness TEXT NOT NULL DEFAULT 'opencode',
23464
- last_response_time INTEGER,
23465
- cache_ttl TEXT,
23466
- counter INTEGER DEFAULT 0,
23467
- last_nudge_tokens INTEGER DEFAULT 0,
23468
- last_nudge_band TEXT DEFAULT '',
23469
- last_transform_error TEXT DEFAULT '',
23470
- nudge_anchor_message_id TEXT DEFAULT '',
23471
- nudge_anchor_text TEXT DEFAULT '',
23472
- sticky_turn_reminder_text TEXT DEFAULT '',
23473
- sticky_turn_reminder_message_id TEXT DEFAULT '',
23474
- note_nudge_trigger_pending INTEGER DEFAULT 0,
23475
- note_nudge_trigger_message_id TEXT DEFAULT '',
23476
- note_nudge_sticky_text TEXT DEFAULT '',
23477
- note_nudge_sticky_message_id TEXT DEFAULT '',
23478
- is_subagent INTEGER DEFAULT 0,
23479
- last_context_percentage REAL DEFAULT 0,
23480
- last_input_tokens INTEGER DEFAULT 0,
23481
- times_execute_threshold_reached INTEGER DEFAULT 0,
23482
- compartment_in_progress INTEGER DEFAULT 0,
23483
- historian_failure_count INTEGER DEFAULT 0,
23484
- historian_last_error TEXT DEFAULT NULL,
23485
- historian_last_failure_at INTEGER DEFAULT NULL,
23486
- system_prompt_hash TEXT DEFAULT '',
23487
- memory_block_cache TEXT DEFAULT '',
23488
- memory_block_count INTEGER DEFAULT 0,
23489
- memory_block_ids TEXT DEFAULT ''
23490
- );
23491
-
23492
- CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
23493
- CREATE INDEX IF NOT EXISTS idx_tags_session_message_id ON tags(session_id, message_id);
23494
- CREATE INDEX IF NOT EXISTS idx_pending_ops_session ON pending_ops(session_id);
23495
- CREATE INDEX IF NOT EXISTS idx_pending_ops_session_tag_id ON pending_ops(session_id, tag_id);
23496
- CREATE INDEX IF NOT EXISTS idx_source_contents_session ON source_contents(session_id);
23497
-
23498
- CREATE TABLE IF NOT EXISTS recomp_compartments (
23499
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23500
- session_id TEXT NOT NULL,
23501
- sequence INTEGER NOT NULL,
23502
- start_message INTEGER NOT NULL,
23503
- end_message INTEGER NOT NULL,
23504
- start_message_id TEXT DEFAULT '',
23505
- end_message_id TEXT DEFAULT '',
23506
- title TEXT NOT NULL,
23507
- content TEXT NOT NULL,
23508
- pass_number INTEGER NOT NULL,
23509
- created_at INTEGER NOT NULL,
23510
- harness TEXT NOT NULL DEFAULT 'opencode',
23511
- UNIQUE(session_id, sequence)
23512
- );
23513
-
23514
- CREATE TABLE IF NOT EXISTS recomp_facts (
23515
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23516
- session_id TEXT NOT NULL,
23517
- category TEXT NOT NULL,
23518
- content TEXT NOT NULL,
23519
- pass_number INTEGER NOT NULL,
23520
- created_at INTEGER NOT NULL,
23521
- harness TEXT NOT NULL DEFAULT 'opencode'
23522
- );
23523
-
23524
- CREATE INDEX IF NOT EXISTS idx_session_facts_session ON session_facts(session_id);
23525
- CREATE INDEX IF NOT EXISTS idx_recomp_compartments_session ON recomp_compartments(session_id);
23526
- CREATE INDEX IF NOT EXISTS idx_recomp_facts_session ON recomp_facts(session_id);
23527
- CREATE INDEX IF NOT EXISTS idx_memories_project_status_category ON memories(project_path, status, category);
23528
- CREATE INDEX IF NOT EXISTS idx_memories_project_status_expires ON memories(project_path, status, expires_at);
23529
- CREATE INDEX IF NOT EXISTS idx_memories_project_category_hash ON memories(project_path, category, normalized_hash);
23530
- CREATE INDEX IF NOT EXISTS idx_message_history_index_updated_at ON message_history_index(updated_at);
23531
- `);
23532
- ensureColumn(db, "session_meta", "last_nudge_band", "TEXT DEFAULT ''");
23533
- ensureColumn(db, "session_meta", "last_transform_error", "TEXT DEFAULT ''");
23534
- ensureColumn(db, "session_meta", "nudge_anchor_message_id", "TEXT DEFAULT ''");
23535
- ensureColumn(db, "session_meta", "nudge_anchor_text", "TEXT DEFAULT ''");
23536
- ensureColumn(db, "session_meta", "sticky_turn_reminder_text", "TEXT DEFAULT ''");
23537
- ensureColumn(db, "session_meta", "sticky_turn_reminder_message_id", "TEXT DEFAULT ''");
23538
- ensureColumn(db, "session_meta", "note_nudge_trigger_pending", "INTEGER DEFAULT 0");
23539
- ensureColumn(db, "session_meta", "note_nudge_trigger_message_id", "TEXT DEFAULT ''");
23540
- ensureColumn(db, "session_meta", "note_nudge_sticky_text", "TEXT DEFAULT ''");
23541
- ensureColumn(db, "session_meta", "note_nudge_sticky_message_id", "TEXT DEFAULT ''");
23542
- ensureColumn(db, "session_meta", "note_last_read_at", "INTEGER DEFAULT 0");
23543
- ensureColumn(db, "session_meta", "times_execute_threshold_reached", "INTEGER DEFAULT 0");
23544
- ensureColumn(db, "session_meta", "compartment_in_progress", "INTEGER DEFAULT 0");
23545
- ensureColumn(db, "session_meta", "historian_failure_count", "INTEGER DEFAULT 0");
23546
- ensureColumn(db, "session_meta", "historian_last_error", "TEXT DEFAULT NULL");
23547
- ensureColumn(db, "session_meta", "historian_last_failure_at", "INTEGER DEFAULT NULL");
23548
- ensureColumn(db, "session_meta", "system_prompt_hash", "TEXT DEFAULT ''");
23549
- ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
23550
- ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
23551
- ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
23552
- ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
23553
- ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
23554
- ensureColumn(db, "session_meta", "memory_block_cache", "TEXT DEFAULT ''");
23555
- ensureColumn(db, "session_meta", "memory_block_count", "INTEGER DEFAULT 0");
23556
- ensureColumn(db, "session_meta", "memory_block_ids", "TEXT DEFAULT ''");
23557
- ensureColumn(db, "dream_queue", "retry_count", "INTEGER DEFAULT 0");
23558
- ensureColumn(db, "tags", "reasoning_byte_size", "INTEGER DEFAULT 0");
23559
- ensureColumn(db, "tags", "drop_mode", "TEXT DEFAULT 'full'");
23560
- ensureColumn(db, "tags", "tool_name", "TEXT");
23561
- ensureColumn(db, "tags", "input_byte_size", "INTEGER DEFAULT 0");
23562
- ensureColumn(db, "tags", "caveman_depth", "INTEGER DEFAULT 0");
23563
- ensureColumn(db, "session_meta", "system_prompt_tokens", "INTEGER DEFAULT 0");
23564
- ensureColumn(db, "session_meta", "compaction_marker_state", "TEXT DEFAULT ''");
23565
- ensureColumn(db, "session_meta", "key_files", "TEXT DEFAULT ''");
23566
- ensureColumn(db, "session_meta", "conversation_tokens", "INTEGER DEFAULT 0");
23567
- ensureColumn(db, "session_meta", "tool_call_tokens", "INTEGER DEFAULT 0");
23568
- ensureColumn(db, "session_meta", "recomp_partial_range_start", "INTEGER DEFAULT 0");
23569
- ensureColumn(db, "session_meta", "recomp_partial_range_end", "INTEGER DEFAULT 0");
23570
- ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
23571
- ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
23572
- ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
23573
- ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
23574
- ensureColumn(db, "source_contents", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
23575
- ensureColumn(db, "compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
23576
- ensureColumn(db, "compression_depth", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
23577
- ensureColumn(db, "session_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
23578
- ensureColumn(db, "session_meta", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
23579
- ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
23580
- ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
23581
- ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
23582
- }
23583
- function healAllNullColumns(db) {
23584
- healNullTextColumns(db);
23585
- healNullIntegerColumns(db);
23586
- healMissingMemoryBlockIds(db);
23587
- }
23588
- function healMissingMemoryBlockIds(db) {
23589
- try {
23590
- db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != '' AND (memory_block_ids IS NULL OR memory_block_ids = '') AND memory_block_count > 0").run();
23591
- } catch {}
23592
- }
23593
- function healNullTextColumns(db) {
23594
- const columns = [
23595
- ["cache_ttl", ""],
23596
- ["last_nudge_band", ""],
23597
- ["last_transform_error", ""],
23598
- ["nudge_anchor_message_id", ""],
23599
- ["nudge_anchor_text", ""],
23600
- ["sticky_turn_reminder_text", ""],
23601
- ["sticky_turn_reminder_message_id", ""],
23602
- ["note_nudge_trigger_message_id", ""],
23603
- ["note_nudge_sticky_text", ""],
23604
- ["note_nudge_sticky_message_id", ""],
23605
- ["system_prompt_hash", ""],
23606
- ["stripped_placeholder_ids", ""],
23607
- ["memory_block_cache", ""],
23608
- ["memory_block_ids", ""],
23609
- ["compaction_marker_state", ""],
23610
- ["key_files", ""]
23611
- ];
23612
- for (const [column, fallback] of columns) {
23613
- try {
23614
- db.prepare(`UPDATE session_meta SET ${column} = ? WHERE ${column} IS NULL`).run(fallback);
23615
- } catch (_error) {}
23616
- }
23617
- }
23618
- function healNullIntegerColumns(db) {
23619
- const columns = [
23620
- ["times_execute_threshold_reached", 0],
23621
- ["compartment_in_progress", 0],
23622
- ["historian_failure_count", 0],
23623
- ["cleared_reasoning_through_tag", 0],
23624
- ["memory_block_count", 0],
23625
- ["system_prompt_tokens", 0],
23626
- ["conversation_tokens", 0],
23627
- ["tool_call_tokens", 0],
23628
- ["note_nudge_trigger_pending", 0]
23629
- ];
23630
- for (const [column, fallback] of columns) {
23631
- try {
23632
- db.prepare(`UPDATE session_meta SET ${column} = ? WHERE ${column} IS NULL`).run(fallback);
23633
- } catch (_error) {}
23634
- }
23635
- }
23636
- function ensureColumn(db, table, column, definition) {
23637
- if (!/^[a-z_]+$/.test(table) || !/^[a-z_]+$/.test(column) || !/^[A-Z0-9_'(),\s]+$/i.test(definition)) {
23638
- throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
23639
- }
23640
- const rows = db.prepare(`PRAGMA table_info(${table})`).all();
23641
- if (rows.some((row) => row.name === column)) {
23642
- return;
23643
- }
23644
- db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
23645
- }
23646
- function openDatabase() {
23647
- const { dbDir, dbPath } = resolveDatabasePath();
23648
- const existing = databases.get(dbPath);
23649
- if (existing) {
23650
- if (!persistenceByDatabase.has(existing)) {
23651
- persistenceByDatabase.set(existing, true);
23652
- }
23653
- return existing;
23654
- }
23655
- try {
23656
- migrateLegacyStorageIfNeeded(dbPath, dbDir);
23657
- mkdirSync2(dbDir, { recursive: true });
23658
- const db = new Database(dbPath);
23659
- initializeDatabase(db);
23660
- runMigrations(db);
23661
- databases.set(dbPath, db);
23662
- persistenceByDatabase.set(db, true);
23663
- persistenceErrorByDatabase.delete(db);
23664
- return db;
23665
- } catch (error48) {
23666
- const detail = getErrorMessage(error48);
23667
- log(`[magic-context] storage fatal: failed to open ${dbPath}: ${detail}`);
23668
- throw new Error(`[magic-context] storage unavailable: ${detail}. Magic Context is disabled for this run; check log for details.`);
23669
- }
23670
- }
23671
-
23672
- // ../plugin/src/shared/harness.ts
23673
- var currentHarness = "opencode";
23674
- var harnessLocked = false;
23675
- function setHarness(value) {
23676
- if (harnessLocked && currentHarness !== value) {
23677
- throw new Error(`Magic Context: harness already locked to "${currentHarness}"; cannot change to "${value}"`);
23678
- }
23679
- currentHarness = value;
23680
- harnessLocked = true;
23681
- }
23682
- function getHarness() {
23683
- return currentHarness;
23684
- }
23685
-
23686
- // src/subagent-entry.ts
23687
- init_logger();
23688
-
23689
- // src/config/index.ts
23690
- init_magic_context();
23691
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
23692
- import { homedir as homedir3 } from "node:os";
23693
- import { join as join5 } from "node:path";
23694
-
23695
- // ../plugin/src/config/variable.ts
23696
- import { existsSync as existsSync2, readFileSync } from "node:fs";
23697
- import { homedir as homedir2 } from "node:os";
23698
- import { dirname, isAbsolute, resolve } from "node:path";
23699
- var ENV_PATTERN = /\{env:([^}]+)\}/g;
23700
- var FILE_PATTERN = /\{file:([^}]+)\}/g;
23701
- function substituteConfigVariables(input) {
23702
- const warnings = [];
23703
- let text = input.text;
23704
- text = text.replace(ENV_PATTERN, (_, rawName) => {
23705
- const varName = rawName.trim();
23706
- const value = varName ? process.env[varName] : undefined;
23707
- if (value === undefined || value === "") {
23708
- warnings.push(`Environment variable ${varName} is not set (referenced via {env:${varName}}); using empty string`);
23709
- return "";
23710
- }
23711
- return value;
23712
- });
23713
- const fileMatches = Array.from(text.matchAll(FILE_PATTERN));
23714
- if (fileMatches.length === 0) {
23715
- return { text, warnings };
23716
- }
23717
- const configDir = input.configPath ? dirname(input.configPath) : process.cwd();
23718
- let output = "";
23719
- let cursor = 0;
23720
- for (const match of fileMatches) {
23721
- const token = match[0];
23722
- const rawPath = match[1] ?? "";
23723
- const index = match.index ?? 0;
23724
- output += text.slice(cursor, index);
23725
- cursor = index + token.length;
23726
- const lineStart = text.lastIndexOf(`
23727
- `, index - 1) + 1;
23728
- const prefix = text.slice(lineStart, index).trimStart();
23729
- if (prefix.startsWith("//")) {
23730
- output += token;
23731
- continue;
23732
- }
23733
- let filePath = rawPath.trim();
23734
- if (filePath.startsWith("~/")) {
23735
- filePath = resolve(homedir2(), filePath.slice(2));
23736
- } else if (!isAbsolute(filePath)) {
23737
- filePath = resolve(configDir, filePath);
23738
- }
23739
- if (!existsSync2(filePath)) {
23740
- warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
23741
- continue;
23742
- }
23743
- let contents;
23744
- try {
23745
- contents = readFileSync(filePath, "utf-8").trim();
23746
- } catch (error48) {
23747
- const message = error48 instanceof Error ? error48.message : String(error48);
23748
- warnings.push(`Failed to read file for ${token} (${filePath}): ${message}; using empty string`);
23749
- continue;
23750
- }
23751
- output += JSON.stringify(contents).slice(1, -1);
23752
- }
23753
- output += text.slice(cursor);
23754
- return { text: output, warnings };
23755
- }
23756
-
23757
- // src/config/index.ts
23758
- var import_comment_json = __toESM(require_src2(), 1);
23759
- var CONFIG_FILE_NAME = "magic-context";
23760
- function getProjectConfigPaths(cwd) {
23761
- const basePath = join5(cwd, ".pi", CONFIG_FILE_NAME);
23762
- return [`${basePath}.jsonc`, `${basePath}.json`];
23763
- }
23764
- function getUserConfigPaths() {
23765
- const home = process.env.HOME ?? homedir3();
23766
- const basePath = join5(home, ".pi", "agent", CONFIG_FILE_NAME);
23767
- return [`${basePath}.jsonc`, `${basePath}.json`];
23768
- }
23769
- function resolveFirstExisting(paths) {
23770
- return paths.find((path3) => existsSync3(path3));
23771
- }
23772
- function loadConfigFile(path3, scope) {
23773
- try {
23774
- const rawText = readFileSync2(path3, "utf-8");
23775
- const substituted = substituteConfigVariables({
23776
- text: rawText,
23777
- configPath: path3
23778
- });
23779
- return {
23780
- path: path3,
23781
- scope,
23782
- config: import_comment_json.parse(substituted.text),
23783
- warnings: substituted.warnings.map((warning) => `${path3}: ${warning}`)
23784
- };
23785
- } catch (error48) {
23786
- const message = error48 instanceof Error ? error48.message : String(error48);
23787
- return {
23788
- path: path3,
23789
- scope,
23790
- config: {},
23791
- warnings: [
23792
- `${path3}: failed to load config: ${message}; using defaults for this file.`
23793
- ]
23794
- };
23795
- }
23796
- }
23797
- function redactConfigValue(value) {
23798
- if (value === undefined)
23799
- return "<missing>";
23800
- if (value === null)
23801
- return "null";
23802
- if (typeof value === "string") {
23803
- return `string, ${value.length} char${value.length === 1 ? "" : "s"}`;
23804
- }
23805
- if (typeof value === "number")
23806
- return `number ${value}`;
23807
- if (typeof value === "boolean")
23808
- return `boolean ${value}`;
23809
- if (Array.isArray(value))
23810
- return `array, ${value.length} item${value.length === 1 ? "" : "s"}`;
23811
- if (typeof value === "object") {
23812
- const keys = Object.keys(value);
23813
- return `object with keys [${keys.join(", ")}]`;
23814
- }
23815
- return typeof value;
23816
- }
23817
- function isPlainObject2(value) {
23818
- return typeof value === "object" && value !== null && !Array.isArray(value);
23819
- }
23820
- function mergeRawConfigs(base, override) {
23821
- const merged = { ...base };
23822
- for (const [key, overrideValue] of Object.entries(override)) {
23823
- const baseValue = merged[key];
23824
- merged[key] = isPlainObject2(baseValue) && isPlainObject2(overrideValue) ? mergeRawConfigs(baseValue, overrideValue) : overrideValue;
23825
- }
23826
- return merged;
23827
- }
23828
- function parsePiConfig(rawConfig) {
23829
- const parsed = MagicContextConfigSchema.safeParse(rawConfig);
23830
- if (parsed.success) {
23831
- return { config: parsed.data, warnings: [] };
23832
- }
23833
- const defaults = MagicContextConfigSchema.parse({});
23834
- const errorPaths = new Set;
23835
- for (const issue2 of parsed.error.issues) {
23836
- const topKey = issue2.path[0];
23837
- if (topKey !== undefined) {
23838
- errorPaths.add(String(topKey));
23839
- }
23840
- }
23841
- const patched = { ...rawConfig };
23842
- const warnings = [];
23843
- for (const key of errorPaths) {
23844
- const isAgentConfig = key === "historian" || key === "dreamer" || key === "sidekick";
23845
- delete patched[key];
23846
- if (isAgentConfig) {
23847
- warnings.push(`"${key}": invalid agent configuration, ignoring. Check your magic-context.jsonc.`);
23848
- continue;
23849
- }
23850
- const defaultValue = defaults[key];
23851
- warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultValue)}.`);
23852
- }
23853
- const retryParsed = MagicContextConfigSchema.safeParse(patched);
23854
- if (retryParsed.success) {
23855
- return { config: retryParsed.data, warnings };
23856
- }
23857
- warnings.push("Config recovery failed, using all defaults.");
23858
- return { config: defaults, warnings };
23859
- }
23860
- function loadPiConfig(opts = {}) {
23861
- const cwd = opts.cwd ?? process.cwd();
23862
- const loadedFiles = [];
23863
- const warnings = [];
23864
- const projectPath = resolveFirstExisting(getProjectConfigPaths(cwd));
23865
- if (projectPath) {
23866
- const loaded = loadConfigFile(projectPath, "project");
23867
- if (loaded)
23868
- loadedFiles.push(loaded);
23869
- }
23870
- const userPath = resolveFirstExisting(getUserConfigPaths());
23871
- if (userPath) {
23872
- const loaded = loadConfigFile(userPath, "user");
23873
- if (loaded)
23874
- loadedFiles.push(loaded);
23875
- }
23876
- let rawConfig = {};
23877
- const mergeFiles = [...loadedFiles].sort((a, b) => {
23878
- if (a.scope === b.scope)
23879
- return 0;
23880
- return a.scope === "user" ? -1 : 1;
23881
- });
23882
- for (const loaded of mergeFiles) {
23883
- const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
23884
- warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
23885
- rawConfig = mergeRawConfigs(rawConfig, loaded.config);
23886
- }
23887
- const parsed = parsePiConfig(rawConfig);
23888
- warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
23889
- return {
23890
- config: parsed.config,
23891
- warnings,
23892
- loadedFromPaths: loadedFiles.map((loaded) => loaded.path)
23893
- };
23894
- }
23895
-
23896
23654
  // ../plugin/src/shared/internal-initiator-marker.ts
23897
23655
  var OMO_INTERNAL_INITIATOR_MARKER = "<!-- OMO_INTERNAL_INITIATOR -->";
23898
23656
 
@@ -23905,9 +23663,6 @@ function removeSystemReminders(text) {
23905
23663
  return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, "").trim();
23906
23664
  }
23907
23665
 
23908
- // ../plugin/src/hooks/magic-context/read-session-chunk.ts
23909
- await init_read_session_db();
23910
-
23911
23666
  // ../../node_modules/.bun/ai-tokenizer@1.0.6/node_modules/ai-tokenizer/dist/index.js
23912
23667
  function _typeof(o) {
23913
23668
  "@babel/helpers - typeof";
@@ -156488,6 +156243,939 @@ function mergeCommitHashes(existing, next) {
156488
156243
  return merged;
156489
156244
  }
156490
156245
 
156246
+ // ../plugin/src/features/magic-context/tool-definition-tokens.ts
156247
+ var measurements = new Map;
156248
+ var persistenceDb = null;
156249
+ function keyFor(providerID, modelID, agentName) {
156250
+ const agent = agentName && agentName.length > 0 ? agentName : "default";
156251
+ return `${providerID}/${modelID}/${agent}`;
156252
+ }
156253
+ function setDatabase(db) {
156254
+ persistenceDb = db;
156255
+ }
156256
+ function loadToolDefinitionMeasurements(db) {
156257
+ let rows = [];
156258
+ try {
156259
+ rows = db.prepare("SELECT provider_id, model_id, agent_name, tool_id, token_count FROM tool_definition_measurements").all();
156260
+ } catch {
156261
+ return;
156262
+ }
156263
+ for (const row of rows) {
156264
+ const key = keyFor(row.provider_id, row.model_id, row.agent_name);
156265
+ let inner = measurements.get(key);
156266
+ if (!inner) {
156267
+ inner = new Map;
156268
+ measurements.set(key, inner);
156269
+ }
156270
+ inner.set(row.tool_id, row.token_count);
156271
+ }
156272
+ }
156273
+
156274
+ // ../plugin/src/features/magic-context/tool-owner-backfill.ts
156275
+ init_data_path();
156276
+ init_logger();
156277
+ import { existsSync as existsSync2 } from "node:fs";
156278
+ import { join as join5 } from "node:path";
156279
+ var LEASE_DURATION_MS = 5 * 60 * 1000;
156280
+ var LEASE_RENEWAL_MS = 60 * 1000;
156281
+ function resolveOpencodeDbPath() {
156282
+ return join5(getDataDir(), "opencode", "opencode.db");
156283
+ }
156284
+ function ensureBackfillStateTable(db) {
156285
+ db.exec(`
156286
+ CREATE TABLE IF NOT EXISTS tool_owner_backfill_state (
156287
+ session_id TEXT PRIMARY KEY,
156288
+ status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'skipped')),
156289
+ started_at INTEGER,
156290
+ lease_expires_at INTEGER,
156291
+ completed_at INTEGER,
156292
+ last_error TEXT
156293
+ );
156294
+ CREATE INDEX IF NOT EXISTS idx_tool_owner_backfill_state_status
156295
+ ON tool_owner_backfill_state(status);
156296
+ `);
156297
+ }
156298
+ function runToolOwnerBackfill(db) {
156299
+ const startedAt = performance.now();
156300
+ ensureBackfillStateTable(db);
156301
+ const result = {
156302
+ sessionsProcessed: 0,
156303
+ sessionsSkippedNoOcDb: 0,
156304
+ sessionsSkippedNoMatches: 0,
156305
+ sessionsCompleted: 0,
156306
+ sessionsBlockedByLease: 0,
156307
+ sessionsErrored: 0,
156308
+ rowsUpdated: 0,
156309
+ rowsLeftNull: 0,
156310
+ durationMs: 0
156311
+ };
156312
+ if (!isToolOwnerBackfillNeeded(db)) {
156313
+ result.durationMs = performance.now() - startedAt;
156314
+ return result;
156315
+ }
156316
+ const opencodeDbPath = resolveOpencodeDbPath();
156317
+ if (!existsSync2(opencodeDbPath)) {
156318
+ log(`[backfill] OpenCode DB not found at ${opencodeDbPath} — marking all unbackfilled sessions as skipped. Lazy adoption (defense-in-depth) handles legacy rows at runtime.`);
156319
+ markAllUnbackfilledSessionsSkipped(db);
156320
+ result.sessionsSkippedNoOcDb = countSessionsByStatus(db, "skipped");
156321
+ result.durationMs = performance.now() - startedAt;
156322
+ return result;
156323
+ }
156324
+ db.exec(`ATTACH '${opencodeDbPath}' AS oc_backfill`);
156325
+ try {
156326
+ backfillToolOwnersInChunks(db, result);
156327
+ } finally {
156328
+ try {
156329
+ db.exec("DETACH DATABASE oc_backfill");
156330
+ } catch (error48) {
156331
+ log(`[backfill] failed to detach oc_backfill database: ${error48 instanceof Error ? error48.message : String(error48)}`);
156332
+ }
156333
+ }
156334
+ result.durationMs = performance.now() - startedAt;
156335
+ 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)}`);
156336
+ return result;
156337
+ }
156338
+ function isToolOwnerBackfillNeeded(db) {
156339
+ ensureBackfillStateTable(db);
156340
+ const row = db.prepare(`SELECT 1 AS hit
156341
+ FROM tags
156342
+ WHERE type = 'tool' AND tool_owner_message_id IS NULL
156343
+ AND NOT EXISTS (
156344
+ SELECT 1 FROM tool_owner_backfill_state s
156345
+ WHERE s.session_id = tags.session_id
156346
+ AND s.status IN ('completed', 'skipped')
156347
+ )
156348
+ LIMIT 1`).get();
156349
+ return row !== null && row !== undefined;
156350
+ }
156351
+ function markAllUnbackfilledSessionsSkipped(db) {
156352
+ const now = Date.now();
156353
+ db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, started_at, completed_at, last_error)
156354
+ SELECT DISTINCT session_id, 'skipped', NULL, ?, NULL
156355
+ FROM tags
156356
+ WHERE type = 'tool' AND tool_owner_message_id IS NULL
156357
+ ON CONFLICT(session_id) DO UPDATE SET
156358
+ status = 'skipped',
156359
+ completed_at = excluded.completed_at,
156360
+ last_error = NULL
156361
+ WHERE tool_owner_backfill_state.status NOT IN ('completed', 'running')`).run(now);
156362
+ }
156363
+ function countSessionsByStatus(db, status) {
156364
+ const row = db.prepare("SELECT COUNT(*) AS c FROM tool_owner_backfill_state WHERE status = ?").get(status);
156365
+ return row.c;
156366
+ }
156367
+ function acquireSessionLease(db, sessionId, now) {
156368
+ const expiresAt = now + LEASE_DURATION_MS;
156369
+ const result = db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, started_at, lease_expires_at)
156370
+ VALUES (?, 'running', ?, ?)
156371
+ ON CONFLICT(session_id) DO UPDATE SET
156372
+ status = 'running',
156373
+ started_at = excluded.started_at,
156374
+ lease_expires_at = excluded.lease_expires_at,
156375
+ last_error = NULL
156376
+ WHERE tool_owner_backfill_state.status IN ('pending', 'skipped')
156377
+ OR (tool_owner_backfill_state.status = 'running'
156378
+ AND tool_owner_backfill_state.lease_expires_at < ?)`).run(sessionId, now, expiresAt, now);
156379
+ return (result.changes ?? 0) === 1;
156380
+ }
156381
+ function renewSessionLease(db, sessionId, now) {
156382
+ const expiresAt = now + LEASE_DURATION_MS;
156383
+ db.prepare(`UPDATE tool_owner_backfill_state
156384
+ SET lease_expires_at = ?
156385
+ WHERE session_id = ? AND status = 'running'`).run(expiresAt, sessionId);
156386
+ }
156387
+ function markSessionCompleted(db, sessionId, now) {
156388
+ db.prepare(`UPDATE tool_owner_backfill_state
156389
+ SET status = 'completed', completed_at = ?, lease_expires_at = NULL, last_error = NULL
156390
+ WHERE session_id = ?`).run(now, sessionId);
156391
+ }
156392
+ function markSessionSkipped(db, sessionId, now, reason) {
156393
+ db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, completed_at, last_error)
156394
+ VALUES (?, 'skipped', ?, ?)
156395
+ ON CONFLICT(session_id) DO UPDATE SET
156396
+ status = 'skipped',
156397
+ completed_at = excluded.completed_at,
156398
+ last_error = excluded.last_error,
156399
+ lease_expires_at = NULL`).run(sessionId, now, reason);
156400
+ }
156401
+ function markSessionErrored(db, sessionId, error48) {
156402
+ const message = error48 instanceof Error ? error48.message : String(error48);
156403
+ db.prepare(`UPDATE tool_owner_backfill_state
156404
+ SET last_error = ?, lease_expires_at = NULL
156405
+ WHERE session_id = ?`).run(message, sessionId);
156406
+ }
156407
+ function getSessionsNeedingBackfill(db) {
156408
+ const rows = db.prepare(`SELECT DISTINCT t.session_id
156409
+ FROM tags t
156410
+ LEFT JOIN tool_owner_backfill_state s ON s.session_id = t.session_id
156411
+ WHERE t.type = 'tool' AND t.tool_owner_message_id IS NULL
156412
+ AND (s.status IS NULL OR s.status NOT IN ('completed', 'skipped'))
156413
+ ORDER BY t.session_id ASC`).all();
156414
+ return rows.map((r) => r.session_id);
156415
+ }
156416
+ function buildSessionOwnerMap(db, sessionId) {
156417
+ const rows = db.prepare(`SELECT
156418
+ COALESCE(
156419
+ CASE WHEN json_extract(p.data, '$.type') = 'tool_use'
156420
+ THEN json_extract(p.data, '$.id')
156421
+ END,
156422
+ json_extract(p.data, '$.callID')
156423
+ ) AS callid,
156424
+ m.id AS owner_id,
156425
+ m.time_created AS owner_t_created,
156426
+ p.id AS part_id,
156427
+ p.time_created AS part_t_created
156428
+ FROM oc_backfill.message m
156429
+ INNER JOIN oc_backfill.part p ON p.message_id = m.id
156430
+ WHERE m.session_id = ?
156431
+ AND json_extract(m.data, '$.role') = 'assistant'
156432
+ AND (
156433
+ (json_extract(p.data, '$.type') IN ('tool', 'tool-invocation')
156434
+ AND json_extract(p.data, '$.callID') IS NOT NULL)
156435
+ OR (json_extract(p.data, '$.type') = 'tool_use'
156436
+ AND json_extract(p.data, '$.id') IS NOT NULL)
156437
+ )
156438
+ ORDER BY
156439
+ m.time_created ASC,
156440
+ m.id ASC,
156441
+ p.time_created ASC,
156442
+ p.id ASC`).all(sessionId);
156443
+ const oldestByCallId = new Map;
156444
+ for (const r of rows) {
156445
+ if (typeof r.callid !== "string" || r.callid.length === 0)
156446
+ continue;
156447
+ if (!oldestByCallId.has(r.callid)) {
156448
+ oldestByCallId.set(r.callid, r.owner_id);
156449
+ }
156450
+ }
156451
+ return oldestByCallId;
156452
+ }
156453
+ function applyOwnersForSession(db, sessionId, ownersByCallId) {
156454
+ if (ownersByCallId.size === 0) {
156455
+ const leftNull = db.prepare(`SELECT COUNT(*) AS c FROM tags
156456
+ WHERE session_id = ? AND type = 'tool'
156457
+ AND tool_owner_message_id IS NULL`).get(sessionId).c;
156458
+ return { rowsUpdated: 0, rowsLeftNull: leftNull };
156459
+ }
156460
+ const findOrphanStmt = db.prepare(`SELECT id FROM tags
156461
+ WHERE session_id = ? AND message_id = ? AND type = 'tool'
156462
+ AND tool_owner_message_id IS NULL
156463
+ ORDER BY tag_number ASC
156464
+ LIMIT 1`);
156465
+ const updateRowStmt = db.prepare(`UPDATE tags
156466
+ SET tool_owner_message_id = ?
156467
+ WHERE id = ? AND tool_owner_message_id IS NULL`);
156468
+ let rowsUpdated = 0;
156469
+ db.transaction(() => {
156470
+ for (const [callId, ownerId] of ownersByCallId) {
156471
+ const orphan = findOrphanStmt.get(sessionId, callId);
156472
+ if (!orphan)
156473
+ continue;
156474
+ const result = updateRowStmt.run(ownerId, orphan.id);
156475
+ rowsUpdated += result.changes ?? 0;
156476
+ }
156477
+ })();
156478
+ const rowsLeftNull = db.prepare(`SELECT COUNT(*) AS c FROM tags
156479
+ WHERE session_id = ? AND type = 'tool'
156480
+ AND tool_owner_message_id IS NULL`).get(sessionId).c;
156481
+ return { rowsUpdated, rowsLeftNull };
156482
+ }
156483
+ function backfillToolOwnersInChunks(db, result) {
156484
+ const sessionIds = getSessionsNeedingBackfill(db);
156485
+ let lastRenewedAt = Date.now();
156486
+ for (const sessionId of sessionIds) {
156487
+ const now = Date.now();
156488
+ result.sessionsProcessed += 1;
156489
+ const acquired = acquireSessionLease(db, sessionId, now);
156490
+ if (!acquired) {
156491
+ result.sessionsBlockedByLease += 1;
156492
+ continue;
156493
+ }
156494
+ try {
156495
+ const owners = buildSessionOwnerMap(db, sessionId);
156496
+ const { rowsUpdated, rowsLeftNull } = applyOwnersForSession(db, sessionId, owners);
156497
+ result.rowsUpdated += rowsUpdated;
156498
+ result.rowsLeftNull += rowsLeftNull;
156499
+ if (owners.size === 0) {
156500
+ markSessionSkipped(db, sessionId, Date.now(), "no_oc_matches");
156501
+ result.sessionsSkippedNoMatches += 1;
156502
+ } else {
156503
+ markSessionCompleted(db, sessionId, Date.now());
156504
+ result.sessionsCompleted += 1;
156505
+ }
156506
+ } catch (error48) {
156507
+ log(`[backfill] session=${sessionId} errored: ${error48 instanceof Error ? error48.message : String(error48)}`);
156508
+ markSessionErrored(db, sessionId, error48);
156509
+ result.sessionsErrored += 1;
156510
+ }
156511
+ const sinceRenew = Date.now() - lastRenewedAt;
156512
+ if (sinceRenew > LEASE_RENEWAL_MS) {
156513
+ renewSessionLease(db, sessionId, Date.now());
156514
+ lastRenewedAt = Date.now();
156515
+ }
156516
+ }
156517
+ }
156518
+
156519
+ // ../plugin/src/features/magic-context/storage-db.ts
156520
+ var databases = new Map;
156521
+ var persistenceByDatabase = new WeakMap;
156522
+ var persistenceErrorByDatabase = new WeakMap;
156523
+ function resolveDatabasePath() {
156524
+ const dbDir = getMagicContextStorageDir();
156525
+ return { dbDir, dbPath: join6(dbDir, "context.db") };
156526
+ }
156527
+ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
156528
+ if (existsSync3(targetDbPath))
156529
+ return;
156530
+ const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
156531
+ const legacyDbPath = join6(legacyDir, "context.db");
156532
+ if (!existsSync3(legacyDbPath))
156533
+ return;
156534
+ log(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
156535
+ mkdirSync3(targetDbDir, { recursive: true });
156536
+ for (const suffix of ["", "-wal", "-shm"]) {
156537
+ const src = `${legacyDbPath}${suffix}`;
156538
+ const dst = join6(targetDbDir, `context.db${suffix}`);
156539
+ if (existsSync3(src)) {
156540
+ try {
156541
+ copyFileSync(src, dst);
156542
+ } catch (error48) {
156543
+ log(`[magic-context] failed to copy ${src}:`, getErrorMessage(error48));
156544
+ }
156545
+ }
156546
+ }
156547
+ const legacyModelsDir = join6(legacyDir, "models");
156548
+ const targetModelsDir = join6(targetDbDir, "models");
156549
+ if (existsSync3(legacyModelsDir) && !existsSync3(targetModelsDir)) {
156550
+ try {
156551
+ cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
156552
+ } catch (error48) {
156553
+ log("[magic-context] failed to copy embedding model cache:", getErrorMessage(error48));
156554
+ }
156555
+ }
156556
+ }
156557
+ function initializeDatabase(db) {
156558
+ db.exec("PRAGMA journal_mode=WAL");
156559
+ db.exec("PRAGMA busy_timeout=5000");
156560
+ db.exec("PRAGMA foreign_keys=ON");
156561
+ db.exec(`
156562
+ CREATE TABLE IF NOT EXISTS tags (
156563
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
156564
+ session_id TEXT,
156565
+ message_id TEXT,
156566
+ type TEXT,
156567
+ status TEXT DEFAULT 'active',
156568
+ byte_size INTEGER,
156569
+ tag_number INTEGER,
156570
+ harness TEXT NOT NULL DEFAULT 'opencode',
156571
+ UNIQUE(session_id, tag_number)
156572
+ );
156573
+
156574
+ CREATE TABLE IF NOT EXISTS pending_ops (
156575
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
156576
+ session_id TEXT,
156577
+ tag_id INTEGER,
156578
+ operation TEXT,
156579
+ queued_at INTEGER,
156580
+ harness TEXT NOT NULL DEFAULT 'opencode'
156581
+ );
156582
+
156583
+ CREATE TABLE IF NOT EXISTS source_contents (
156584
+ tag_id INTEGER,
156585
+ session_id TEXT,
156586
+ content TEXT,
156587
+ created_at INTEGER,
156588
+ harness TEXT NOT NULL DEFAULT 'opencode',
156589
+ PRIMARY KEY(session_id, tag_id)
156590
+ );
156591
+
156592
+ CREATE TABLE IF NOT EXISTS compartments (
156593
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
156594
+ session_id TEXT NOT NULL,
156595
+ sequence INTEGER NOT NULL,
156596
+ start_message INTEGER NOT NULL,
156597
+ end_message INTEGER NOT NULL,
156598
+ start_message_id TEXT DEFAULT '',
156599
+ end_message_id TEXT DEFAULT '',
156600
+ title TEXT NOT NULL,
156601
+ content TEXT NOT NULL,
156602
+ created_at INTEGER NOT NULL,
156603
+ harness TEXT NOT NULL DEFAULT 'opencode',
156604
+ UNIQUE(session_id, sequence)
156605
+ );
156606
+ CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
156607
+
156608
+ CREATE TABLE IF NOT EXISTS compression_depth (
156609
+ session_id TEXT NOT NULL,
156610
+ message_ordinal INTEGER NOT NULL,
156611
+ depth INTEGER NOT NULL DEFAULT 0,
156612
+ harness TEXT NOT NULL DEFAULT 'opencode',
156613
+ PRIMARY KEY(session_id, message_ordinal)
156614
+ );
156615
+ CREATE INDEX IF NOT EXISTS idx_compression_depth_session ON compression_depth(session_id);
156616
+
156617
+ CREATE TABLE IF NOT EXISTS session_facts (
156618
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
156619
+ session_id TEXT NOT NULL,
156620
+ category TEXT NOT NULL,
156621
+ content TEXT NOT NULL,
156622
+ created_at INTEGER NOT NULL,
156623
+ updated_at INTEGER NOT NULL,
156624
+ harness TEXT NOT NULL DEFAULT 'opencode'
156625
+ );
156626
+
156627
+ -- session_notes and smart_notes were merged into the unified notes table
156628
+ -- by migration v1 (see features/magic-context/migrations.ts). The old tables
156629
+ -- are never recreated; fresh DBs create only notes, upgraded DBs have
156630
+ -- their old tables migrated and dropped by the migration runner.
156631
+
156632
+ CREATE TABLE IF NOT EXISTS memories (
156633
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
156634
+ project_path TEXT NOT NULL,
156635
+ category TEXT NOT NULL,
156636
+ content TEXT NOT NULL,
156637
+ normalized_hash TEXT NOT NULL,
156638
+ source_session_id TEXT,
156639
+ source_type TEXT DEFAULT 'historian',
156640
+ seen_count INTEGER DEFAULT 1,
156641
+ retrieval_count INTEGER DEFAULT 0,
156642
+ first_seen_at INTEGER NOT NULL,
156643
+ created_at INTEGER NOT NULL,
156644
+ updated_at INTEGER NOT NULL,
156645
+ last_seen_at INTEGER NOT NULL,
156646
+ last_retrieved_at INTEGER,
156647
+ status TEXT DEFAULT 'active',
156648
+ expires_at INTEGER,
156649
+ verification_status TEXT DEFAULT 'unverified',
156650
+ verified_at INTEGER,
156651
+ superseded_by_memory_id INTEGER,
156652
+ merged_from TEXT,
156653
+ metadata_json TEXT,
156654
+ UNIQUE(project_path, category, normalized_hash)
156655
+ );
156656
+
156657
+ CREATE TABLE IF NOT EXISTS memory_embeddings (
156658
+ memory_id INTEGER PRIMARY KEY REFERENCES memories(id) ON DELETE CASCADE,
156659
+ embedding BLOB NOT NULL,
156660
+ model_id TEXT
156661
+ );
156662
+
156663
+ CREATE TABLE IF NOT EXISTS dream_state (
156664
+ key TEXT PRIMARY KEY,
156665
+ value TEXT NOT NULL
156666
+ );
156667
+
156668
+ CREATE TABLE IF NOT EXISTS dream_queue (
156669
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
156670
+ project_path TEXT NOT NULL,
156671
+ reason TEXT NOT NULL,
156672
+ enqueued_at INTEGER NOT NULL,
156673
+ started_at INTEGER,
156674
+ retry_count INTEGER DEFAULT 0
156675
+ );
156676
+ CREATE INDEX IF NOT EXISTS idx_dream_queue_project ON dream_queue(project_path);
156677
+ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, enqueued_at);
156678
+
156679
+ CREATE TABLE IF NOT EXISTS dream_runs (
156680
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
156681
+ project_path TEXT NOT NULL,
156682
+ started_at INTEGER NOT NULL,
156683
+ finished_at INTEGER NOT NULL,
156684
+ holder_id TEXT NOT NULL,
156685
+ tasks_json TEXT NOT NULL,
156686
+ tasks_succeeded INTEGER NOT NULL DEFAULT 0,
156687
+ tasks_failed INTEGER NOT NULL DEFAULT 0,
156688
+ smart_notes_surfaced INTEGER NOT NULL DEFAULT 0,
156689
+ smart_notes_pending INTEGER NOT NULL DEFAULT 0,
156690
+ memory_changes_json TEXT
156691
+ );
156692
+ CREATE INDEX IF NOT EXISTS idx_dream_runs_project ON dream_runs(project_path, finished_at DESC);
156693
+
156694
+ -- (smart_notes: see note above; merged into unified notes table by migration v1)
156695
+
156696
+ CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
156697
+ content,
156698
+ category,
156699
+ content='memories',
156700
+ content_rowid='id',
156701
+ tokenize='porter unicode61'
156702
+ );
156703
+
156704
+ CREATE VIRTUAL TABLE IF NOT EXISTS message_history_fts USING fts5(
156705
+ session_id UNINDEXED,
156706
+ message_ordinal UNINDEXED,
156707
+ message_id UNINDEXED,
156708
+ role,
156709
+ content,
156710
+ tokenize='porter unicode61'
156711
+ );
156712
+
156713
+ CREATE TABLE IF NOT EXISTS message_history_index (
156714
+ session_id TEXT PRIMARY KEY,
156715
+ last_indexed_ordinal INTEGER NOT NULL DEFAULT 0,
156716
+ updated_at INTEGER NOT NULL,
156717
+ harness TEXT NOT NULL DEFAULT 'opencode'
156718
+ );
156719
+
156720
+ CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
156721
+ INSERT INTO memories_fts(rowid, content, category) VALUES (new.id, new.content, new.category);
156722
+ END;
156723
+
156724
+ CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
156725
+ INSERT INTO memories_fts(memories_fts, rowid, content, category) VALUES ('delete', old.id, old.content, old.category);
156726
+ END;
156727
+
156728
+ CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
156729
+ INSERT INTO memories_fts(memories_fts, rowid, content, category) VALUES ('delete', old.id, old.content, old.category);
156730
+ INSERT INTO memories_fts(rowid, content, category) VALUES (new.id, new.content, new.category);
156731
+ END;
156732
+
156733
+ CREATE TABLE IF NOT EXISTS session_meta (
156734
+ session_id TEXT PRIMARY KEY,
156735
+ harness TEXT NOT NULL DEFAULT 'opencode',
156736
+ last_response_time INTEGER,
156737
+ cache_ttl TEXT,
156738
+ counter INTEGER DEFAULT 0,
156739
+ last_nudge_tokens INTEGER DEFAULT 0,
156740
+ last_nudge_band TEXT DEFAULT '',
156741
+ last_transform_error TEXT DEFAULT '',
156742
+ nudge_anchor_message_id TEXT DEFAULT '',
156743
+ nudge_anchor_text TEXT DEFAULT '',
156744
+ sticky_turn_reminder_text TEXT DEFAULT '',
156745
+ sticky_turn_reminder_message_id TEXT DEFAULT '',
156746
+ note_nudge_trigger_pending INTEGER DEFAULT 0,
156747
+ note_nudge_trigger_message_id TEXT DEFAULT '',
156748
+ note_nudge_sticky_text TEXT DEFAULT '',
156749
+ note_nudge_sticky_message_id TEXT DEFAULT '',
156750
+ is_subagent INTEGER DEFAULT 0,
156751
+ last_context_percentage REAL DEFAULT 0,
156752
+ last_input_tokens INTEGER DEFAULT 0,
156753
+ times_execute_threshold_reached INTEGER DEFAULT 0,
156754
+ compartment_in_progress INTEGER DEFAULT 0,
156755
+ historian_failure_count INTEGER DEFAULT 0,
156756
+ historian_last_error TEXT DEFAULT NULL,
156757
+ historian_last_failure_at INTEGER DEFAULT NULL,
156758
+ system_prompt_hash TEXT DEFAULT '',
156759
+ memory_block_cache TEXT DEFAULT '',
156760
+ memory_block_count INTEGER DEFAULT 0,
156761
+ memory_block_ids TEXT DEFAULT ''
156762
+ );
156763
+
156764
+ CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
156765
+ CREATE INDEX IF NOT EXISTS idx_tags_session_message_id ON tags(session_id, message_id);
156766
+ CREATE INDEX IF NOT EXISTS idx_pending_ops_session ON pending_ops(session_id);
156767
+ CREATE INDEX IF NOT EXISTS idx_pending_ops_session_tag_id ON pending_ops(session_id, tag_id);
156768
+ CREATE INDEX IF NOT EXISTS idx_source_contents_session ON source_contents(session_id);
156769
+
156770
+ CREATE TABLE IF NOT EXISTS recomp_compartments (
156771
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
156772
+ session_id TEXT NOT NULL,
156773
+ sequence INTEGER NOT NULL,
156774
+ start_message INTEGER NOT NULL,
156775
+ end_message INTEGER NOT NULL,
156776
+ start_message_id TEXT DEFAULT '',
156777
+ end_message_id TEXT DEFAULT '',
156778
+ title TEXT NOT NULL,
156779
+ content TEXT NOT NULL,
156780
+ pass_number INTEGER NOT NULL,
156781
+ created_at INTEGER NOT NULL,
156782
+ harness TEXT NOT NULL DEFAULT 'opencode',
156783
+ UNIQUE(session_id, sequence)
156784
+ );
156785
+
156786
+ CREATE TABLE IF NOT EXISTS recomp_facts (
156787
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
156788
+ session_id TEXT NOT NULL,
156789
+ category TEXT NOT NULL,
156790
+ content TEXT NOT NULL,
156791
+ pass_number INTEGER NOT NULL,
156792
+ created_at INTEGER NOT NULL,
156793
+ harness TEXT NOT NULL DEFAULT 'opencode'
156794
+ );
156795
+
156796
+ CREATE INDEX IF NOT EXISTS idx_session_facts_session ON session_facts(session_id);
156797
+ CREATE INDEX IF NOT EXISTS idx_recomp_compartments_session ON recomp_compartments(session_id);
156798
+ CREATE INDEX IF NOT EXISTS idx_recomp_facts_session ON recomp_facts(session_id);
156799
+ CREATE INDEX IF NOT EXISTS idx_memories_project_status_category ON memories(project_path, status, category);
156800
+ CREATE INDEX IF NOT EXISTS idx_memories_project_status_expires ON memories(project_path, status, expires_at);
156801
+ CREATE INDEX IF NOT EXISTS idx_memories_project_category_hash ON memories(project_path, category, normalized_hash);
156802
+ CREATE INDEX IF NOT EXISTS idx_message_history_index_updated_at ON message_history_index(updated_at);
156803
+ `);
156804
+ ensureColumn(db, "session_meta", "last_nudge_band", "TEXT DEFAULT ''");
156805
+ ensureColumn(db, "session_meta", "last_transform_error", "TEXT DEFAULT ''");
156806
+ ensureColumn(db, "session_meta", "nudge_anchor_message_id", "TEXT DEFAULT ''");
156807
+ ensureColumn(db, "session_meta", "nudge_anchor_text", "TEXT DEFAULT ''");
156808
+ ensureColumn(db, "session_meta", "sticky_turn_reminder_text", "TEXT DEFAULT ''");
156809
+ ensureColumn(db, "session_meta", "sticky_turn_reminder_message_id", "TEXT DEFAULT ''");
156810
+ ensureColumn(db, "session_meta", "note_nudge_trigger_pending", "INTEGER DEFAULT 0");
156811
+ ensureColumn(db, "session_meta", "note_nudge_trigger_message_id", "TEXT DEFAULT ''");
156812
+ ensureColumn(db, "session_meta", "note_nudge_sticky_text", "TEXT DEFAULT ''");
156813
+ ensureColumn(db, "session_meta", "note_nudge_sticky_message_id", "TEXT DEFAULT ''");
156814
+ ensureColumn(db, "session_meta", "note_last_read_at", "INTEGER DEFAULT 0");
156815
+ ensureColumn(db, "session_meta", "times_execute_threshold_reached", "INTEGER DEFAULT 0");
156816
+ ensureColumn(db, "session_meta", "compartment_in_progress", "INTEGER DEFAULT 0");
156817
+ ensureColumn(db, "session_meta", "historian_failure_count", "INTEGER DEFAULT 0");
156818
+ ensureColumn(db, "session_meta", "historian_last_error", "TEXT DEFAULT NULL");
156819
+ ensureColumn(db, "session_meta", "historian_last_failure_at", "INTEGER DEFAULT NULL");
156820
+ ensureColumn(db, "session_meta", "system_prompt_hash", "TEXT DEFAULT ''");
156821
+ ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
156822
+ ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
156823
+ ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
156824
+ ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
156825
+ ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
156826
+ ensureColumn(db, "session_meta", "memory_block_cache", "TEXT DEFAULT ''");
156827
+ ensureColumn(db, "session_meta", "memory_block_count", "INTEGER DEFAULT 0");
156828
+ ensureColumn(db, "session_meta", "memory_block_ids", "TEXT DEFAULT ''");
156829
+ ensureColumn(db, "dream_queue", "retry_count", "INTEGER DEFAULT 0");
156830
+ ensureColumn(db, "tags", "reasoning_byte_size", "INTEGER DEFAULT 0");
156831
+ ensureColumn(db, "tags", "drop_mode", "TEXT DEFAULT 'full'");
156832
+ ensureColumn(db, "tags", "tool_name", "TEXT");
156833
+ ensureColumn(db, "tags", "input_byte_size", "INTEGER DEFAULT 0");
156834
+ ensureColumn(db, "tags", "caveman_depth", "INTEGER DEFAULT 0");
156835
+ ensureColumn(db, "tags", "tool_owner_message_id", "TEXT DEFAULT NULL");
156836
+ ensureColumn(db, "session_meta", "system_prompt_tokens", "INTEGER DEFAULT 0");
156837
+ ensureColumn(db, "session_meta", "compaction_marker_state", "TEXT DEFAULT ''");
156838
+ ensureColumn(db, "session_meta", "key_files", "TEXT DEFAULT ''");
156839
+ ensureColumn(db, "session_meta", "conversation_tokens", "INTEGER DEFAULT 0");
156840
+ ensureColumn(db, "session_meta", "tool_call_tokens", "INTEGER DEFAULT 0");
156841
+ ensureColumn(db, "session_meta", "recomp_partial_range_start", "INTEGER DEFAULT 0");
156842
+ ensureColumn(db, "session_meta", "recomp_partial_range_end", "INTEGER DEFAULT 0");
156843
+ ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
156844
+ ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
156845
+ ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
156846
+ ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
156847
+ ensureColumn(db, "source_contents", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
156848
+ ensureColumn(db, "compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
156849
+ ensureColumn(db, "compression_depth", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
156850
+ ensureColumn(db, "session_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
156851
+ ensureColumn(db, "session_meta", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
156852
+ ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
156853
+ ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
156854
+ ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
156855
+ }
156856
+ function healAllNullColumns(db) {
156857
+ healNullTextColumns(db);
156858
+ healNullIntegerColumns(db);
156859
+ healMissingMemoryBlockIds(db);
156860
+ }
156861
+ function healMissingMemoryBlockIds(db) {
156862
+ try {
156863
+ db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != '' AND (memory_block_ids IS NULL OR memory_block_ids = '') AND memory_block_count > 0").run();
156864
+ } catch {}
156865
+ }
156866
+ function healNullTextColumns(db) {
156867
+ const columns = [
156868
+ ["cache_ttl", ""],
156869
+ ["last_nudge_band", ""],
156870
+ ["last_transform_error", ""],
156871
+ ["nudge_anchor_message_id", ""],
156872
+ ["nudge_anchor_text", ""],
156873
+ ["sticky_turn_reminder_text", ""],
156874
+ ["sticky_turn_reminder_message_id", ""],
156875
+ ["note_nudge_trigger_message_id", ""],
156876
+ ["note_nudge_sticky_text", ""],
156877
+ ["note_nudge_sticky_message_id", ""],
156878
+ ["system_prompt_hash", ""],
156879
+ ["stripped_placeholder_ids", ""],
156880
+ ["memory_block_cache", ""],
156881
+ ["memory_block_ids", ""],
156882
+ ["compaction_marker_state", ""],
156883
+ ["key_files", ""]
156884
+ ];
156885
+ for (const [column, fallback] of columns) {
156886
+ try {
156887
+ db.prepare(`UPDATE session_meta SET ${column} = ? WHERE ${column} IS NULL`).run(fallback);
156888
+ } catch (_error) {}
156889
+ }
156890
+ }
156891
+ function healNullIntegerColumns(db) {
156892
+ const columns = [
156893
+ ["times_execute_threshold_reached", 0],
156894
+ ["compartment_in_progress", 0],
156895
+ ["historian_failure_count", 0],
156896
+ ["cleared_reasoning_through_tag", 0],
156897
+ ["memory_block_count", 0],
156898
+ ["system_prompt_tokens", 0],
156899
+ ["conversation_tokens", 0],
156900
+ ["tool_call_tokens", 0],
156901
+ ["note_nudge_trigger_pending", 0]
156902
+ ];
156903
+ for (const [column, fallback] of columns) {
156904
+ try {
156905
+ db.prepare(`UPDATE session_meta SET ${column} = ? WHERE ${column} IS NULL`).run(fallback);
156906
+ } catch (_error) {}
156907
+ }
156908
+ }
156909
+ function ensureColumn(db, table, column, definition) {
156910
+ if (!/^[a-z_]+$/.test(table) || !/^[a-z_]+$/.test(column) || !/^[A-Z0-9_'(),\s]+$/i.test(definition)) {
156911
+ throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
156912
+ }
156913
+ const rows = db.prepare(`PRAGMA table_info(${table})`).all();
156914
+ if (rows.some((row) => row.name === column)) {
156915
+ return;
156916
+ }
156917
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
156918
+ }
156919
+ function openDatabase() {
156920
+ const { dbDir, dbPath } = resolveDatabasePath();
156921
+ const existing = databases.get(dbPath);
156922
+ if (existing) {
156923
+ if (!persistenceByDatabase.has(existing)) {
156924
+ persistenceByDatabase.set(existing, true);
156925
+ }
156926
+ return existing;
156927
+ }
156928
+ try {
156929
+ migrateLegacyStorageIfNeeded(dbPath, dbDir);
156930
+ mkdirSync3(dbDir, { recursive: true });
156931
+ const db = new Database(dbPath);
156932
+ initializeDatabase(db);
156933
+ runMigrations(db);
156934
+ try {
156935
+ runToolOwnerBackfill(db);
156936
+ } catch (error48) {
156937
+ log(`[magic-context] tool-owner backfill failed (continuing with lazy adoption fallback): ${getErrorMessage(error48)}`);
156938
+ }
156939
+ setDatabase(db);
156940
+ loadToolDefinitionMeasurements(db);
156941
+ databases.set(dbPath, db);
156942
+ persistenceByDatabase.set(db, true);
156943
+ persistenceErrorByDatabase.delete(db);
156944
+ return db;
156945
+ } catch (error48) {
156946
+ const detail = getErrorMessage(error48);
156947
+ log(`[magic-context] storage fatal: failed to open ${dbPath}: ${detail}`);
156948
+ throw new Error(`[magic-context] storage unavailable: ${detail}. Magic Context is disabled for this run; check log for details.`);
156949
+ }
156950
+ }
156951
+
156952
+ // ../plugin/src/shared/harness.ts
156953
+ var currentHarness = "opencode";
156954
+ var harnessLocked = false;
156955
+ function setHarness(value) {
156956
+ if (harnessLocked && currentHarness !== value) {
156957
+ throw new Error(`Magic Context: harness already locked to "${currentHarness}"; cannot change to "${value}"`);
156958
+ }
156959
+ currentHarness = value;
156960
+ harnessLocked = true;
156961
+ }
156962
+ function getHarness() {
156963
+ return currentHarness;
156964
+ }
156965
+
156966
+ // src/subagent-entry.ts
156967
+ init_logger();
156968
+
156969
+ // src/config/index.ts
156970
+ init_magic_context();
156971
+ import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
156972
+ import { homedir as homedir3 } from "node:os";
156973
+ import { join as join7 } from "node:path";
156974
+
156975
+ // ../plugin/src/config/variable.ts
156976
+ import { existsSync as existsSync4, readFileSync } from "node:fs";
156977
+ import { homedir as homedir2 } from "node:os";
156978
+ import { dirname as dirname2, isAbsolute, resolve } from "node:path";
156979
+ var ENV_PATTERN = /\{env:([^}]+)\}/g;
156980
+ var FILE_PATTERN = /\{file:([^}]+)\}/g;
156981
+ function substituteConfigVariables(input) {
156982
+ const warnings = [];
156983
+ let text = input.text;
156984
+ text = text.replace(ENV_PATTERN, (_, rawName) => {
156985
+ const varName = rawName.trim();
156986
+ const value = varName ? process.env[varName] : undefined;
156987
+ if (value === undefined || value === "") {
156988
+ warnings.push(`Environment variable ${varName} is not set (referenced via {env:${varName}}); using empty string`);
156989
+ return "";
156990
+ }
156991
+ return value;
156992
+ });
156993
+ const fileMatches = Array.from(text.matchAll(FILE_PATTERN));
156994
+ if (fileMatches.length === 0) {
156995
+ return { text, warnings };
156996
+ }
156997
+ const configDir = input.configPath ? dirname2(input.configPath) : process.cwd();
156998
+ let output = "";
156999
+ let cursor = 0;
157000
+ for (const match of fileMatches) {
157001
+ const token = match[0];
157002
+ const rawPath = match[1] ?? "";
157003
+ const index = match.index ?? 0;
157004
+ output += text.slice(cursor, index);
157005
+ cursor = index + token.length;
157006
+ const lineStart = text.lastIndexOf(`
157007
+ `, index - 1) + 1;
157008
+ const prefix = text.slice(lineStart, index).trimStart();
157009
+ if (prefix.startsWith("//")) {
157010
+ output += token;
157011
+ continue;
157012
+ }
157013
+ let filePath = rawPath.trim();
157014
+ if (filePath.startsWith("~/")) {
157015
+ filePath = resolve(homedir2(), filePath.slice(2));
157016
+ } else if (!isAbsolute(filePath)) {
157017
+ filePath = resolve(configDir, filePath);
157018
+ }
157019
+ if (!existsSync4(filePath)) {
157020
+ warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
157021
+ continue;
157022
+ }
157023
+ let contents;
157024
+ try {
157025
+ contents = readFileSync(filePath, "utf-8").trim();
157026
+ } catch (error48) {
157027
+ const message = error48 instanceof Error ? error48.message : String(error48);
157028
+ warnings.push(`Failed to read file for ${token} (${filePath}): ${message}; using empty string`);
157029
+ continue;
157030
+ }
157031
+ output += JSON.stringify(contents).slice(1, -1);
157032
+ }
157033
+ output += text.slice(cursor);
157034
+ return { text: output, warnings };
157035
+ }
157036
+
157037
+ // src/config/index.ts
157038
+ var import_comment_json = __toESM(require_src2(), 1);
157039
+ var CONFIG_FILE_NAME = "magic-context";
157040
+ function getProjectConfigPaths(cwd) {
157041
+ const basePath = join7(cwd, ".pi", CONFIG_FILE_NAME);
157042
+ return [`${basePath}.jsonc`, `${basePath}.json`];
157043
+ }
157044
+ function getUserConfigPaths() {
157045
+ const home = process.env.HOME ?? homedir3();
157046
+ const basePath = join7(home, ".pi", "agent", CONFIG_FILE_NAME);
157047
+ return [`${basePath}.jsonc`, `${basePath}.json`];
157048
+ }
157049
+ function resolveFirstExisting(paths) {
157050
+ return paths.find((path4) => existsSync5(path4));
157051
+ }
157052
+ function loadConfigFile(path4, scope) {
157053
+ try {
157054
+ const rawText = readFileSync2(path4, "utf-8");
157055
+ const substituted = substituteConfigVariables({
157056
+ text: rawText,
157057
+ configPath: path4
157058
+ });
157059
+ return {
157060
+ path: path4,
157061
+ scope,
157062
+ config: import_comment_json.parse(substituted.text),
157063
+ warnings: substituted.warnings.map((warning) => `${path4}: ${warning}`)
157064
+ };
157065
+ } catch (error48) {
157066
+ const message = error48 instanceof Error ? error48.message : String(error48);
157067
+ return {
157068
+ path: path4,
157069
+ scope,
157070
+ config: {},
157071
+ warnings: [
157072
+ `${path4}: failed to load config: ${message}; using defaults for this file.`
157073
+ ]
157074
+ };
157075
+ }
157076
+ }
157077
+ function redactConfigValue(value) {
157078
+ if (value === undefined)
157079
+ return "<missing>";
157080
+ if (value === null)
157081
+ return "null";
157082
+ if (typeof value === "string") {
157083
+ return `string, ${value.length} char${value.length === 1 ? "" : "s"}`;
157084
+ }
157085
+ if (typeof value === "number")
157086
+ return `number ${value}`;
157087
+ if (typeof value === "boolean")
157088
+ return `boolean ${value}`;
157089
+ if (Array.isArray(value))
157090
+ return `array, ${value.length} item${value.length === 1 ? "" : "s"}`;
157091
+ if (typeof value === "object") {
157092
+ const keys = Object.keys(value);
157093
+ return `object with keys [${keys.join(", ")}]`;
157094
+ }
157095
+ return typeof value;
157096
+ }
157097
+ function isPlainObject2(value) {
157098
+ return typeof value === "object" && value !== null && !Array.isArray(value);
157099
+ }
157100
+ function mergeRawConfigs(base, override) {
157101
+ const merged = { ...base };
157102
+ for (const [key, overrideValue] of Object.entries(override)) {
157103
+ const baseValue = merged[key];
157104
+ merged[key] = isPlainObject2(baseValue) && isPlainObject2(overrideValue) ? mergeRawConfigs(baseValue, overrideValue) : overrideValue;
157105
+ }
157106
+ return merged;
157107
+ }
157108
+ function parsePiConfig(rawConfig) {
157109
+ const parsed = MagicContextConfigSchema.safeParse(rawConfig);
157110
+ if (parsed.success) {
157111
+ return { config: parsed.data, warnings: [] };
157112
+ }
157113
+ const defaults = MagicContextConfigSchema.parse({});
157114
+ const errorPaths = new Set;
157115
+ for (const issue2 of parsed.error.issues) {
157116
+ const topKey = issue2.path[0];
157117
+ if (topKey !== undefined) {
157118
+ errorPaths.add(String(topKey));
157119
+ }
157120
+ }
157121
+ const patched = { ...rawConfig };
157122
+ const warnings = [];
157123
+ for (const key of errorPaths) {
157124
+ const isAgentConfig = key === "historian" || key === "dreamer" || key === "sidekick";
157125
+ delete patched[key];
157126
+ if (isAgentConfig) {
157127
+ warnings.push(`"${key}": invalid agent configuration, ignoring. Check your magic-context.jsonc.`);
157128
+ continue;
157129
+ }
157130
+ const defaultValue = defaults[key];
157131
+ warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultValue)}.`);
157132
+ }
157133
+ const retryParsed = MagicContextConfigSchema.safeParse(patched);
157134
+ if (retryParsed.success) {
157135
+ return { config: retryParsed.data, warnings };
157136
+ }
157137
+ warnings.push("Config recovery failed, using all defaults.");
157138
+ return { config: defaults, warnings };
157139
+ }
157140
+ function loadPiConfig(opts = {}) {
157141
+ const cwd = opts.cwd ?? process.cwd();
157142
+ const loadedFiles = [];
157143
+ const warnings = [];
157144
+ const projectPath = resolveFirstExisting(getProjectConfigPaths(cwd));
157145
+ if (projectPath) {
157146
+ const loaded = loadConfigFile(projectPath, "project");
157147
+ if (loaded)
157148
+ loadedFiles.push(loaded);
157149
+ }
157150
+ const userPath = resolveFirstExisting(getUserConfigPaths());
157151
+ if (userPath) {
157152
+ const loaded = loadConfigFile(userPath, "user");
157153
+ if (loaded)
157154
+ loadedFiles.push(loaded);
157155
+ }
157156
+ let rawConfig = {};
157157
+ const mergeFiles = [...loadedFiles].sort((a, b) => {
157158
+ if (a.scope === b.scope)
157159
+ return 0;
157160
+ return a.scope === "user" ? -1 : 1;
157161
+ });
157162
+ for (const loaded of mergeFiles) {
157163
+ const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
157164
+ warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
157165
+ rawConfig = mergeRawConfigs(rawConfig, loaded.config);
157166
+ }
157167
+ const parsed = parsePiConfig(rawConfig);
157168
+ warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
157169
+ return {
157170
+ config: parsed.config,
157171
+ warnings,
157172
+ loadedFromPaths: loadedFiles.map((loaded) => loaded.path)
157173
+ };
157174
+ }
157175
+
157176
+ // ../plugin/src/hooks/magic-context/read-session-chunk.ts
157177
+ await init_read_session_db();
157178
+
156491
157179
  // ../plugin/src/hooks/magic-context/read-session-raw.ts
156492
157180
  function isRawMessageRow(row) {
156493
157181
  if (row === null || typeof row !== "object")
@@ -156570,21 +157258,85 @@ function isTextPart(part) {
156570
157258
  const p = part;
156571
157259
  return p.type === "text" && typeof p.text === "string";
156572
157260
  }
156573
- function isToolPartWithOutput(part) {
157261
+ function isFilePart(part) {
156574
157262
  if (part === null || typeof part !== "object")
156575
157263
  return false;
156576
157264
  const p = part;
156577
- if (p.type !== "tool" || typeof p.callID !== "string")
157265
+ return p.type === "file" && typeof p.url === "string";
157266
+ }
157267
+
157268
+ // ../plugin/src/shared/record-type-guard.ts
157269
+ function isRecord(value) {
157270
+ return typeof value === "object" && value !== null && !Array.isArray(value);
157271
+ }
157272
+
157273
+ // ../plugin/src/hooks/magic-context/tool-drop-target.ts
157274
+ var IGNORE_PART_TYPES = new Set([
157275
+ "thinking",
157276
+ "reasoning",
157277
+ "redacted_thinking",
157278
+ "meta",
157279
+ "step-start",
157280
+ "step-finish"
157281
+ ]);
157282
+ function isToolCallId(value) {
157283
+ return typeof value === "string" && value.length > 0;
157284
+ }
157285
+ function hasMeaningfulPart(part) {
157286
+ if (!isRecord(part))
157287
+ return false;
157288
+ const type = part.type;
157289
+ if (type === "text") {
157290
+ return typeof part.text === "string" && part.text.trim().length > 0;
157291
+ }
157292
+ if (typeof type !== "string")
156578
157293
  return false;
156579
- if (p.state === null || typeof p.state !== "object")
157294
+ if (IGNORE_PART_TYPES.has(type))
156580
157295
  return false;
156581
- return typeof p.state.output === "string";
157296
+ return true;
156582
157297
  }
156583
- function isFilePart(part) {
156584
- if (part === null || typeof part !== "object")
156585
- return false;
156586
- const p = part;
156587
- return p.type === "file" && typeof p.url === "string";
157298
+ function extractToolCallObservation(part) {
157299
+ if (!isRecord(part))
157300
+ return null;
157301
+ if (part.type === "tool" && isToolCallId(part.callID)) {
157302
+ return { callId: part.callID, kind: "result" };
157303
+ }
157304
+ if (part.type === "tool-invocation" && isToolCallId(part.callID)) {
157305
+ return { callId: part.callID, kind: "invocation" };
157306
+ }
157307
+ if (part.type === "tool_use" && isToolCallId(part.id)) {
157308
+ return { callId: part.id, kind: "invocation" };
157309
+ }
157310
+ if (part.type === "tool_result" && isToolCallId(part.tool_use_id)) {
157311
+ return { callId: part.tool_use_id, kind: "result" };
157312
+ }
157313
+ return null;
157314
+ }
157315
+ class ToolMutationBatch {
157316
+ partsToRemove = new Set;
157317
+ affectedMessages = new Set;
157318
+ messages;
157319
+ constructor(messages) {
157320
+ this.messages = messages;
157321
+ }
157322
+ markForRemoval(occurrence) {
157323
+ this.partsToRemove.add(occurrence.part);
157324
+ this.affectedMessages.add(occurrence.message);
157325
+ }
157326
+ finalize() {
157327
+ if (this.partsToRemove.size === 0)
157328
+ return;
157329
+ for (const message of this.affectedMessages) {
157330
+ message.parts = message.parts.filter((p) => !this.partsToRemove.has(p));
157331
+ }
157332
+ for (let i = this.messages.length - 1;i >= 0; i -= 1) {
157333
+ if (!this.messages[i].parts.some(hasMeaningfulPart)) {
157334
+ this.messages.splice(i, 1);
157335
+ }
157336
+ }
157337
+ this.partsToRemove.clear();
157338
+ this.affectedMessages.clear();
157339
+ }
156588
157340
  }
156589
157341
 
156590
157342
  // ../plugin/src/hooks/magic-context/read-session-chunk.ts
@@ -156651,23 +157403,47 @@ function getRawSessionMessageCount(sessionId) {
156651
157403
  }
156652
157404
  function getRawSessionTagKeysThrough(sessionId, upToMessageIndex) {
156653
157405
  const messages = readRawSessionMessages(sessionId);
156654
- const keys = [];
157406
+ const messageFileKeys = new Set;
157407
+ const toolObservations = new Map;
157408
+ const unpairedInvocations = new Map;
156655
157409
  for (const message of messages) {
156656
157410
  if (message.ordinal > upToMessageIndex)
156657
157411
  break;
156658
157412
  for (const [partIndex, part] of message.parts.entries()) {
156659
157413
  if (isTextPart(part)) {
156660
- keys.push(`${message.id}:p${partIndex}`);
157414
+ messageFileKeys.add(`${message.id}:p${partIndex}`);
157415
+ continue;
156661
157416
  }
156662
157417
  if (isFilePart(part)) {
156663
- keys.push(`${message.id}:file${partIndex}`);
157418
+ messageFileKeys.add(`${message.id}:file${partIndex}`);
157419
+ continue;
156664
157420
  }
156665
- if (isToolPartWithOutput(part)) {
156666
- keys.push(part.callID);
157421
+ const obs = extractToolCallObservation(part);
157422
+ if (!obs)
157423
+ continue;
157424
+ let ownerMsgId;
157425
+ if (obs.kind === "invocation") {
157426
+ ownerMsgId = message.id;
157427
+ const queue = unpairedInvocations.get(obs.callId) ?? [];
157428
+ queue.push(message.id);
157429
+ unpairedInvocations.set(obs.callId, queue);
157430
+ } else {
157431
+ const queue = unpairedInvocations.get(obs.callId);
157432
+ if (queue && queue.length > 0) {
157433
+ const popped = queue.shift();
157434
+ if (queue.length === 0)
157435
+ unpairedInvocations.delete(obs.callId);
157436
+ ownerMsgId = popped ?? message.id;
157437
+ } else {
157438
+ ownerMsgId = message.id;
157439
+ }
156667
157440
  }
157441
+ const owners = toolObservations.get(obs.callId) ?? new Set;
157442
+ owners.add(ownerMsgId);
157443
+ toolObservations.set(obs.callId, owners);
156668
157444
  }
156669
157445
  }
156670
- return keys;
157446
+ return { messageFileKeys, toolObservations };
156671
157447
  }
156672
157448
  var PROTECTED_TAIL_USER_TURNS = 5;
156673
157449
  function getProtectedTailStartOrdinal(sessionId) {
@@ -161456,7 +162232,7 @@ init_normalize_hash();
161456
162232
  // ../plugin/src/features/magic-context/memory/project-identity.ts
161457
162233
  import { execSync } from "node:child_process";
161458
162234
  import { createHash as createHash2 } from "node:crypto";
161459
- import path3 from "node:path";
162235
+ import path4 from "node:path";
161460
162236
  var GIT_TIMEOUT_MS = 5000;
161461
162237
  var resolvedCache = new Map;
161462
162238
  function getRootCommitHash(directory) {
@@ -161475,12 +162251,12 @@ function getRootCommitHash(directory) {
161475
162251
  }
161476
162252
  }
161477
162253
  function directoryFallback(directory) {
161478
- const canonical = path3.resolve(directory);
162254
+ const canonical = path4.resolve(directory);
161479
162255
  const hash2 = createHash2("md5").update(canonical).digest("hex").slice(0, 12);
161480
162256
  return `dir:${hash2}`;
161481
162257
  }
161482
162258
  function resolveProjectIdentity(directory) {
161483
- const resolved = path3.resolve(directory);
162259
+ const resolved = path4.resolve(directory);
161484
162260
  const cached2 = resolvedCache.get(resolved);
161485
162261
  if (cached2 !== undefined) {
161486
162262
  return cached2;
@@ -162304,6 +163080,7 @@ var upsertIndexStatements = new WeakMap;
162304
163080
  var deleteFtsStatements = new WeakMap;
162305
163081
  var deleteIndexStatements = new WeakMap;
162306
163082
  var countIndexedMessageStatements = new WeakMap;
163083
+ var indexedMessageIdStatements = new WeakMap;
162307
163084
  function normalizeIndexText(text) {
162308
163085
  return text.replace(/\s+/g, " ").trim();
162309
163086
  }
@@ -162347,10 +163124,34 @@ function getDeleteIndexStatement(db) {
162347
163124
  }
162348
163125
  return stmt;
162349
163126
  }
163127
+ function getCountIndexedMessageStatement(db) {
163128
+ let stmt = countIndexedMessageStatements.get(db);
163129
+ if (!stmt) {
163130
+ stmt = db.prepare("SELECT COUNT(*) AS count FROM message_history_fts WHERE session_id = ? AND message_id = ?");
163131
+ countIndexedMessageStatements.set(db, stmt);
163132
+ }
163133
+ return stmt;
163134
+ }
163135
+ function getIndexedMessageIdStatement(db) {
163136
+ let stmt = indexedMessageIdStatements.get(db);
163137
+ if (!stmt) {
163138
+ stmt = db.prepare("SELECT message_id AS messageId FROM message_history_fts WHERE session_id = ?");
163139
+ indexedMessageIdStatements.set(db, stmt);
163140
+ }
163141
+ return stmt;
163142
+ }
162350
163143
  function getLastIndexedOrdinal(db, sessionId) {
162351
163144
  const row = getLastIndexedStatement(db).get(sessionId);
162352
163145
  return typeof row?.last_indexed_ordinal === "number" ? row.last_indexed_ordinal : 0;
162353
163146
  }
163147
+ function isMessageAlreadyIndexed(db, sessionId, messageId) {
163148
+ const row = getCountIndexedMessageStatement(db).get(sessionId, messageId);
163149
+ return (typeof row?.count === "number" ? row.count : 0) > 0;
163150
+ }
163151
+ function advanceIndexWatermark(db, sessionId, ordinal, now) {
163152
+ const current = getLastIndexedOrdinal(db, sessionId);
163153
+ getUpsertIndexStatement(db).run(sessionId, Math.max(current, ordinal), now, getHarness());
163154
+ }
162354
163155
  function clearIndexedMessages(db, sessionId) {
162355
163156
  db.transaction(() => {
162356
163157
  getDeleteFtsStatement(db).run(sessionId);
@@ -162370,34 +163171,51 @@ function getIndexableContent(role, parts) {
162370
163171
  }
162371
163172
  return "";
162372
163173
  }
162373
- function ensureMessagesIndexed(db, sessionId, readMessages) {
162374
- const messages = readMessages(sessionId);
162375
- if (messages.length === 0) {
162376
- db.transaction(() => clearIndexedMessages(db, sessionId))();
162377
- return;
163174
+ function indexSingleMessageInTransaction(db, sessionId, message, now) {
163175
+ if (message.role !== "user" && message.role !== "assistant") {
163176
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
163177
+ return false;
162378
163178
  }
162379
- let lastIndexedOrdinal = getLastIndexedOrdinal(db, sessionId);
162380
- if (lastIndexedOrdinal > messages.length) {
162381
- db.transaction(() => clearIndexedMessages(db, sessionId))();
162382
- lastIndexedOrdinal = 0;
163179
+ const content = getIndexableContent(message.role, message.parts);
163180
+ if (content.length === 0) {
163181
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
163182
+ return false;
162383
163183
  }
162384
- if (lastIndexedOrdinal >= messages.length) {
162385
- return;
163184
+ if (isMessageAlreadyIndexed(db, sessionId, message.id)) {
163185
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
163186
+ return false;
162386
163187
  }
162387
- const messagesToInsert = messages.filter((message) => message.ordinal > lastIndexedOrdinal).filter((message) => message.role === "user" || message.role === "assistant").map((message) => ({
162388
- ordinal: message.ordinal,
162389
- id: message.id,
162390
- role: message.role,
162391
- content: getIndexableContent(message.role, message.parts)
162392
- })).filter((message) => message.content.length > 0);
163188
+ getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
163189
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
163190
+ return true;
163191
+ }
163192
+ function indexSingleMessage(db, sessionId, message) {
163193
+ return db.transaction(() => indexSingleMessageInTransaction(db, sessionId, message, Date.now()))();
163194
+ }
163195
+ function indexMessagesAfterOrdinal(db, sessionId, messages, lastIndexedOrdinal, finalWatermark = messages.length) {
162393
163196
  const now = Date.now();
163197
+ let inserted = 0;
162394
163198
  db.transaction(() => {
163199
+ const existingMessageIds = new Set(getIndexedMessageIdStatement(db).all(sessionId).map((row) => row.messageId).filter((messageId) => typeof messageId === "string"));
162395
163200
  const insertMessage = getInsertMessageStatement(db);
162396
- for (const message of messagesToInsert) {
162397
- insertMessage.run(sessionId, message.ordinal, message.id, message.role, message.content);
163201
+ for (const message of messages) {
163202
+ if (message.ordinal <= lastIndexedOrdinal) {
163203
+ continue;
163204
+ }
163205
+ if (message.role !== "user" && message.role !== "assistant") {
163206
+ continue;
163207
+ }
163208
+ const content = getIndexableContent(message.role, message.parts);
163209
+ if (content.length === 0 || existingMessageIds.has(message.id)) {
163210
+ continue;
163211
+ }
163212
+ insertMessage.run(sessionId, message.ordinal, message.id, message.role, content);
163213
+ existingMessageIds.add(message.id);
163214
+ inserted++;
162398
163215
  }
162399
- getUpsertIndexStatement(db).run(sessionId, messages.length, now, getHarness());
163216
+ getUpsertIndexStatement(db).run(sessionId, finalWatermark, now, getHarness());
162400
163217
  })();
163218
+ return inserted;
162401
163219
  }
162402
163220
  // ../plugin/src/features/magic-context/storage-meta-persisted.ts
162403
163221
  init_logger();
@@ -162996,7 +163814,7 @@ var getTagNumberByMessageIdStatements = new WeakMap;
162996
163814
  function getInsertTagStatement(db) {
162997
163815
  let stmt = insertTagStatements.get(db);
162998
163816
  if (!stmt) {
162999
- 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 (?, ?, ?, ?, ?, ?, ?, ?, ?)");
163817
+ 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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
163000
163818
  insertTagStatements.set(db, stmt);
163001
163819
  }
163002
163820
  return stmt;
@@ -163077,7 +163895,8 @@ function toTagEntry(row) {
163077
163895
  byteSize: row.byte_size,
163078
163896
  reasoningByteSize: row.reasoning_byte_size ?? 0,
163079
163897
  sessionId: row.session_id,
163080
- cavemanDepth: typeof row.caveman_depth === "number" && Number.isFinite(row.caveman_depth) ? row.caveman_depth : 0
163898
+ cavemanDepth: typeof row.caveman_depth === "number" && Number.isFinite(row.caveman_depth) ? row.caveman_depth : 0,
163899
+ toolOwnerMessageId: typeof row.tool_owner_message_id === "string" ? row.tool_owner_message_id : null
163081
163900
  };
163082
163901
  }
163083
163902
  function isTagNumberRow(row) {
@@ -163092,8 +163911,8 @@ function isMaxTagNumberRow(row) {
163092
163911
  const r = row;
163093
163912
  return typeof r.max_tag_number === "number";
163094
163913
  }
163095
- function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0) {
163096
- getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness());
163914
+ function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0, toolOwnerMessageId = null) {
163915
+ getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness(), toolOwnerMessageId);
163097
163916
  return tagNumber;
163098
163917
  }
163099
163918
  function updateTagStatus(db, sessionId, tagId, status) {
@@ -163105,6 +163924,7 @@ function updateTagDropMode(db, sessionId, tagNumber, dropMode) {
163105
163924
  function updateCavemanDepth(db, sessionId, tagNumber, depth) {
163106
163925
  db.prepare("UPDATE tags SET caveman_depth = ? WHERE session_id = ? AND tag_number = ?").run(depth, sessionId, tagNumber);
163107
163926
  }
163927
+ var getOwnerScopedToolTagNumbersStatements = new WeakMap;
163108
163928
  function getMaxTagNumberBySession(db, sessionId) {
163109
163929
  const row = getMaxTagNumberBySessionStatement(db).get(sessionId);
163110
163930
  return isMaxTagNumberRow(row) ? row.max_tag_number : 0;
@@ -163113,17 +163933,103 @@ function getTagNumberByMessageId(db, sessionId, messageId) {
163113
163933
  const row = getTagNumberByMessageIdStatement(db).get(sessionId, messageId);
163114
163934
  return isTagNumberRow(row) ? row.tag_number : null;
163115
163935
  }
163936
+ 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";
163116
163937
  function getTagsBySession(db, sessionId) {
163117
- 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);
163938
+ const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? ORDER BY tag_number ASC, id ASC`).all(sessionId).filter(isTagRow);
163939
+ return rows.map(toTagEntry);
163940
+ }
163941
+ var getActiveTagsBySessionStatements = new WeakMap;
163942
+ var getMaxDroppedTagNumberStatements = new WeakMap;
163943
+ function getActiveTagsBySessionStatement(db) {
163944
+ let stmt = getActiveTagsBySessionStatements.get(db);
163945
+ if (!stmt) {
163946
+ stmt = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND status = 'active' ORDER BY tag_number ASC, id ASC`);
163947
+ getActiveTagsBySessionStatements.set(db, stmt);
163948
+ }
163949
+ return stmt;
163950
+ }
163951
+ function getActiveTagsBySession(db, sessionId) {
163952
+ const rows = getActiveTagsBySessionStatement(db).all(sessionId).filter(isTagRow);
163953
+ return rows.map(toTagEntry);
163954
+ }
163955
+ function getTagsByNumbers(db, sessionId, tagNumbers) {
163956
+ if (tagNumbers.length === 0)
163957
+ return [];
163958
+ if (tagNumbers.length > 900) {
163959
+ const all = [];
163960
+ for (let i = 0;i < tagNumbers.length; i += 900) {
163961
+ all.push(...getTagsByNumbers(db, sessionId, tagNumbers.slice(i, i + 900)));
163962
+ }
163963
+ return all;
163964
+ }
163965
+ const placeholders = tagNumbers.map(() => "?").join(",");
163966
+ 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);
163118
163967
  return rows.map(toTagEntry);
163119
163968
  }
163120
163969
  function getTopNBySize(db, sessionId, n) {
163121
163970
  if (n <= 0) {
163122
163971
  return [];
163123
163972
  }
163124
- 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);
163973
+ 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);
163125
163974
  return rows.map(toTagEntry);
163126
163975
  }
163976
+ var getToolTagNumberByOwnerStatements = new WeakMap;
163977
+ var getNullOwnerToolTagStatements = new WeakMap;
163978
+ var adoptNullOwnerToolTagStatements = new WeakMap;
163979
+ var deleteToolTagsByOwnerStatements = new WeakMap;
163980
+ function getGetToolTagNumberByOwnerStatement(db) {
163981
+ let stmt = getToolTagNumberByOwnerStatements.get(db);
163982
+ if (!stmt) {
163983
+ stmt = db.prepare(`SELECT tag_number FROM tags
163984
+ WHERE session_id = ? AND message_id = ?
163985
+ AND type = 'tool' AND tool_owner_message_id = ?
163986
+ LIMIT 1`);
163987
+ getToolTagNumberByOwnerStatements.set(db, stmt);
163988
+ }
163989
+ return stmt;
163990
+ }
163991
+ function getToolTagNumberByOwner(db, sessionId, callId, ownerMsgId) {
163992
+ const row = getGetToolTagNumberByOwnerStatement(db).get(sessionId, callId, ownerMsgId);
163993
+ return isTagNumberRow(row) ? row.tag_number : null;
163994
+ }
163995
+ function isNullOwnerToolTagRow(row) {
163996
+ if (row === null || typeof row !== "object")
163997
+ return false;
163998
+ const r = row;
163999
+ return typeof r.id === "number" && typeof r.tag_number === "number";
164000
+ }
164001
+ function getGetNullOwnerToolTagStatement(db) {
164002
+ let stmt = getNullOwnerToolTagStatements.get(db);
164003
+ if (!stmt) {
164004
+ stmt = db.prepare(`SELECT id, tag_number FROM tags
164005
+ WHERE session_id = ? AND message_id = ?
164006
+ AND type = 'tool' AND tool_owner_message_id IS NULL
164007
+ ORDER BY tag_number ASC
164008
+ LIMIT 1`);
164009
+ getNullOwnerToolTagStatements.set(db, stmt);
164010
+ }
164011
+ return stmt;
164012
+ }
164013
+ function getNullOwnerToolTag(db, sessionId, callId) {
164014
+ const row = getGetNullOwnerToolTagStatement(db).get(sessionId, callId);
164015
+ if (!isNullOwnerToolTagRow(row))
164016
+ return null;
164017
+ return { id: row.id, tagNumber: row.tag_number };
164018
+ }
164019
+ function getAdoptNullOwnerToolTagStatement(db) {
164020
+ let stmt = adoptNullOwnerToolTagStatements.get(db);
164021
+ if (!stmt) {
164022
+ stmt = db.prepare(`UPDATE tags
164023
+ SET tool_owner_message_id = ?
164024
+ WHERE id = ? AND tool_owner_message_id IS NULL`);
164025
+ adoptNullOwnerToolTagStatements.set(db, stmt);
164026
+ }
164027
+ return stmt;
164028
+ }
164029
+ function adoptNullOwnerToolTag(db, rowId, ownerMsgId) {
164030
+ const result = getAdoptNullOwnerToolTagStatement(db).run(ownerMsgId, rowId);
164031
+ return (result.changes ?? 0) === 1;
164032
+ }
163127
164033
  // src/tools/ctx-note.ts
163128
164034
  var FILTER_VALUES = [
163129
164035
  "active",
@@ -164040,11 +164946,7 @@ function getMessageOrdinal(value) {
164040
164946
  }
164041
164947
  async function getSemanticScores(args) {
164042
164948
  const semanticScores = new Map;
164043
- if (!args.embeddingEnabled || !args.isEmbeddingRuntimeEnabled() || args.memories.length === 0) {
164044
- return semanticScores;
164045
- }
164046
- const queryEmbedding = await args.embedQuery(args.query, args.signal);
164047
- if (!queryEmbedding) {
164949
+ if (!args.queryEmbedding || args.memories.length === 0) {
164048
164950
  return semanticScores;
164049
164951
  }
164050
164952
  const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
@@ -164058,7 +164960,7 @@ async function getSemanticScores(args) {
164058
164960
  if (!memoryEmbedding) {
164059
164961
  continue;
164060
164962
  }
164061
- semanticScores.set(memory2.id, normalizeCosineScore(cosineSimilarity(queryEmbedding, memoryEmbedding)));
164963
+ semanticScores.set(memory2.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
164062
164964
  }
164063
164965
  return semanticScores;
164064
164966
  }
@@ -164154,12 +165056,8 @@ async function searchMemories(args) {
164154
165056
  const semanticScores = await getSemanticScores({
164155
165057
  db: args.db,
164156
165058
  projectPath: args.projectPath,
164157
- query: args.query,
164158
165059
  memories: semanticCandidates,
164159
- embeddingEnabled: args.embeddingEnabled,
164160
- embedQuery: args.embedQuery,
164161
- isEmbeddingRuntimeEnabled: args.isEmbeddingRuntimeEnabled,
164162
- signal: args.signal
165060
+ queryEmbedding: args.queryEmbedding
164163
165061
  });
164164
165062
  return mergeMemoryResults({
164165
165063
  memories,
@@ -164175,7 +165073,6 @@ function linearDecayScore(rank, total) {
164175
165073
  return Math.max(0, 1 - rank / total);
164176
165074
  }
164177
165075
  function searchMessages(args) {
164178
- ensureMessagesIndexed(args.db, args.sessionId, args.readMessages);
164179
165076
  const sanitizedQuery = sanitizeFtsQuery(args.query.trim());
164180
165077
  if (sanitizedQuery.length === 0) {
164181
165078
  return [];
@@ -164246,20 +165143,12 @@ function toGitCommitResult(hit) {
164246
165143
  matchType: hit.matchType
164247
165144
  };
164248
165145
  }
164249
- async function searchGitCommitsAsync(args) {
165146
+ function searchGitCommits(args) {
164250
165147
  if (args.limit <= 0)
164251
165148
  return [];
164252
- let queryEmbedding = null;
164253
- if (args.embeddingEnabled && args.isEmbeddingRuntimeEnabled()) {
164254
- try {
164255
- queryEmbedding = await args.embedQuery(args.query, args.signal);
164256
- } catch (error48) {
164257
- log(`[search] git commit query embedding failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
164258
- }
164259
- }
164260
165149
  const hits = searchGitCommitsSync(args.db, args.projectPath, args.query, {
164261
165150
  limit: args.limit,
164262
- queryEmbedding
165151
+ queryEmbedding: args.queryEmbedding
164263
165152
  });
164264
165153
  return hits.map(toGitCommitResult);
164265
165154
  }
@@ -164290,37 +165179,37 @@ async function unifiedSearch(db, sessionId, projectPath, query, options3 = {}) {
164290
165179
  const runMemory = activeSources.has("memory") && (options3.memoryEnabled ?? true);
164291
165180
  const runMessages = activeSources.has("message");
164292
165181
  const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
164293
- const [memoryResults, messageResults, gitCommitResults] = await Promise.all([
165182
+ const needsEmbedding = (runMemory || runGitCommits) && embeddingEnabled && isEmbeddingRuntimeEnabled();
165183
+ const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options3.signal).catch((error48) => {
165184
+ log(`[search] query embedding failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
165185
+ return null;
165186
+ }) : Promise.resolve(null);
165187
+ await Promise.resolve();
165188
+ const messageResults = runMessages ? searchMessages({
165189
+ db,
165190
+ sessionId,
165191
+ query: trimmedQuery,
165192
+ limit: tierLimit,
165193
+ maxOrdinal: options3.maxMessageOrdinal
165194
+ }) : [];
165195
+ const queryEmbedding = await queryEmbeddingPromise;
165196
+ const [memoryResults, gitCommitResults] = await Promise.all([
164294
165197
  runMemory ? searchMemories({
164295
165198
  db,
164296
165199
  projectPath,
164297
165200
  query: trimmedQuery,
164298
165201
  limit: tierLimit,
164299
165202
  memoryEnabled: true,
164300
- embeddingEnabled,
164301
- embedQuery,
164302
- isEmbeddingRuntimeEnabled,
164303
- visibleMemoryIds: options3.visibleMemoryIds,
164304
- signal: options3.signal
165203
+ queryEmbedding,
165204
+ visibleMemoryIds: options3.visibleMemoryIds
164305
165205
  }) : Promise.resolve([]),
164306
- runMessages ? Promise.resolve(searchMessages({
164307
- db,
164308
- sessionId,
164309
- query: trimmedQuery,
164310
- limit: tierLimit,
164311
- readMessages: options3.readMessages ?? readRawSessionMessages,
164312
- maxOrdinal: options3.maxMessageOrdinal
164313
- })) : Promise.resolve([]),
164314
- runGitCommits ? searchGitCommitsAsync({
165206
+ runGitCommits ? Promise.resolve(searchGitCommits({
164315
165207
  db,
164316
165208
  projectPath,
164317
165209
  query: trimmedQuery,
164318
165210
  limit: tierLimit,
164319
- embeddingEnabled,
164320
- embedQuery,
164321
- isEmbeddingRuntimeEnabled,
164322
- signal: options3.signal
164323
- }) : Promise.resolve([])
165211
+ queryEmbedding
165212
+ })) : Promise.resolve([])
164324
165213
  ]);
164325
165214
  const results = [...memoryResults, ...messageResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
164326
165215
  const countRetrievals = options3.countRetrievals ?? true;