@cortexkit/pi-magic-context 0.16.3 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -15453,7 +15453,8 @@ function findLastAssistantModelFromOpenCodeDb(sessionId) {
15453
15453
  try {
15454
15454
  return withReadOnlySessionDb((db) => {
15455
15455
  const row = db.prepare(`SELECT json_extract(data, '$.providerID') as providerID,
15456
- json_extract(data, '$.modelID') as modelID
15456
+ json_extract(data, '$.modelID') as modelID,
15457
+ json_extract(data, '$.agent') as agent
15457
15458
  FROM message
15458
15459
  WHERE session_id = ?
15459
15460
  AND json_extract(data, '$.role') = 'assistant'
@@ -15464,7 +15465,12 @@ function findLastAssistantModelFromOpenCodeDb(sessionId) {
15464
15465
  if (!row || typeof row.providerID !== "string" || typeof row.modelID !== "string") {
15465
15466
  return null;
15466
15467
  }
15467
- return { providerID: row.providerID, modelID: row.modelID };
15468
+ const agent = typeof row.agent === "string" && row.agent.length > 0 ? row.agent : undefined;
15469
+ return {
15470
+ providerID: row.providerID,
15471
+ modelID: row.modelID,
15472
+ ...agent ? { agent } : {}
15473
+ };
15468
15474
  });
15469
15475
  } catch (error48) {
15470
15476
  log("[magic-context] failed to recover live model from OpenCode DB:", error48);
@@ -23112,10 +23118,10 @@ var require_stringify = __commonJS((exports, module) => {
23112
23118
  replacer = null;
23113
23119
  indent = EMPTY;
23114
23120
  };
23115
- var join12 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one, gap)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two, gap)), gap) : EMPTY;
23121
+ var join13 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one, gap)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two, gap)), gap) : EMPTY;
23116
23122
  var join_content = (inside, value, gap) => {
23117
23123
  const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
23118
- return join12(comment, inside, gap);
23124
+ return join13(comment, inside, gap);
23119
23125
  };
23120
23126
  var stringify_string = (holder, key, value) => {
23121
23127
  const raw = get_raw_string_literal(holder, key);
@@ -23137,13 +23143,13 @@ var require_stringify = __commonJS((exports, module) => {
23137
23143
  if (i !== 0) {
23138
23144
  inside += COMMA;
23139
23145
  }
23140
- const before = join12(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
23146
+ const before = join13(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
23141
23147
  inside += before || LF + deeper_gap;
23142
23148
  inside += stringify(i, value, deeper_gap) || STR_NULL;
23143
23149
  inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
23144
23150
  after_comma = process_comments(value, AFTER(i), deeper_gap);
23145
23151
  }
23146
- inside += join12(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
23152
+ inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
23147
23153
  return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
23148
23154
  };
23149
23155
  var object_stringify = (value, gap) => {
@@ -23164,13 +23170,13 @@ var require_stringify = __commonJS((exports, module) => {
23164
23170
  inside += COMMA;
23165
23171
  }
23166
23172
  first = false;
23167
- const before = join12(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
23173
+ const before = join13(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
23168
23174
  inside += before || LF + deeper_gap;
23169
23175
  inside += quote(key) + process_comments(value, AFTER_PROP(key), deeper_gap) + COLON + process_comments(value, AFTER_COLON(key), deeper_gap) + SPACE + sv + process_comments(value, AFTER_VALUE(key), deeper_gap);
23170
23176
  after_comma = process_comments(value, AFTER(key), deeper_gap);
23171
23177
  };
23172
23178
  keys.forEach(iteratee);
23173
- inside += join12(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
23179
+ inside += join13(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
23174
23180
  return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
23175
23181
  };
23176
23182
  function stringify(key, holder, gap) {
@@ -23265,7 +23271,7 @@ var require_src2 = __commonJS((exports, module) => {
23265
23271
  // src/index.ts
23266
23272
  init_embedding();
23267
23273
  import { createRequire as createRequire2 } from "node:module";
23268
- import { join as join14 } from "node:path";
23274
+ import { join as join15 } from "node:path";
23269
23275
 
23270
23276
  // ../plugin/src/features/magic-context/memory/project-identity.ts
23271
23277
  import { execSync } from "node:child_process";
@@ -23305,422 +23311,9 @@ function resolveProjectIdentity(directory) {
23305
23311
  return identity;
23306
23312
  }
23307
23313
 
23308
- // ../plugin/src/features/magic-context/overflow-detection.ts
23309
- var OVERFLOW_PATTERNS = [
23310
- /prompt is too long/i,
23311
- /input is too long for requested model/i,
23312
- /exceeds the context window/i,
23313
- /input token count.*exceeds the maximum/i,
23314
- /maximum prompt length is \d+/i,
23315
- /reduce the length of the messages/i,
23316
- /maximum context length is \d+ tokens/i,
23317
- /exceeds the limit of \d+/i,
23318
- /exceeds the available context size/i,
23319
- /greater than the context length/i,
23320
- /context window exceeds limit/i,
23321
- /exceeded model token limit/i,
23322
- /context[_ ]length[_ ]exceeded/i,
23323
- /request entity too large/i,
23324
- /context length is only \d+ tokens/i,
23325
- /input length.*exceeds.*context length/i,
23326
- /prompt too long; exceeded (?:max )?context length/i,
23327
- /too large for model with \d+ maximum context length/i,
23328
- /model_context_window_exceeded/i,
23329
- /context size has been exceeded/i
23330
- ];
23331
- var LIMIT_EXTRACTION_PATTERNS = [
23332
- /maximum prompt length is (\d+)/i,
23333
- /maximum context length is (\d+) tokens?/i,
23334
- /context length is only (\d+) tokens?/i,
23335
- /exceeds the limit of (\d+)/i,
23336
- /too large for model with (\d+) maximum context length/i,
23337
- /context size.*(\d+) tokens?/i,
23338
- /exceeds? the context length of (\d+)/i,
23339
- /max(?:imum)?.*context.*?(\d+)/i
23340
- ];
23341
- var MIN_PLAUSIBLE_LIMIT = 1024;
23342
- var MAX_PLAUSIBLE_LIMIT = 1e7;
23343
- function extractErrorMessage(error48) {
23344
- if (!error48)
23345
- return "";
23346
- if (typeof error48 === "string")
23347
- return error48;
23348
- if (typeof error48 === "object") {
23349
- const obj = error48;
23350
- const nested = obj.error;
23351
- if (nested && typeof nested.message === "string" && nested.message.length > 0) {
23352
- return nested.message;
23353
- }
23354
- }
23355
- if (error48 instanceof Error)
23356
- return error48.message;
23357
- if (typeof error48 === "object") {
23358
- const obj = error48;
23359
- if (typeof obj.message === "string")
23360
- return obj.message;
23361
- if (typeof obj.responseBody === "string")
23362
- return obj.responseBody;
23363
- try {
23364
- return JSON.stringify(error48);
23365
- } catch {
23366
- return String(error48);
23367
- }
23368
- }
23369
- return String(error48);
23370
- }
23371
- function detectOverflow(error48) {
23372
- const message = extractErrorMessage(error48);
23373
- if (!message) {
23374
- return { isOverflow: false };
23375
- }
23376
- const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
23377
- let matched;
23378
- for (const pattern of OVERFLOW_PATTERNS) {
23379
- if (pattern.test(message)) {
23380
- matched = pattern;
23381
- break;
23382
- }
23383
- }
23384
- if (!matched && !hasStatus413) {
23385
- return { isOverflow: false };
23386
- }
23387
- const reportedLimit = parseReportedLimit(message);
23388
- return {
23389
- isOverflow: true,
23390
- reportedLimit,
23391
- matchedPattern: matched?.source
23392
- };
23393
- }
23394
- function parseReportedLimit(message) {
23395
- if (!message)
23396
- return;
23397
- for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
23398
- const match = message.match(pattern);
23399
- if (!match)
23400
- continue;
23401
- const raw = match[1];
23402
- if (!raw)
23403
- continue;
23404
- const value = Number.parseInt(raw, 10);
23405
- if (!Number.isFinite(value))
23406
- continue;
23407
- if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
23408
- continue;
23409
- return value;
23410
- }
23411
- return;
23412
- }
23413
-
23414
- // ../plugin/src/shared/harness.ts
23415
- var currentHarness = "opencode";
23416
- var harnessLocked = false;
23417
- function setHarness(value) {
23418
- if (harnessLocked && currentHarness !== value) {
23419
- throw new Error(`Magic Context: harness already locked to "${currentHarness}"; cannot change to "${value}"`);
23420
- }
23421
- currentHarness = value;
23422
- harnessLocked = true;
23423
- }
23424
- function getHarness() {
23425
- return currentHarness;
23426
- }
23314
+ // ../plugin/src/features/magic-context/message-index-async.ts
23315
+ init_logger();
23427
23316
 
23428
- // ../plugin/src/features/magic-context/compartment-storage.ts
23429
- var insertCompartmentStatements = new WeakMap;
23430
- var insertFactStatements = new WeakMap;
23431
- function getInsertCompartmentStatement(db) {
23432
- let stmt = insertCompartmentStatements.get(db);
23433
- if (!stmt) {
23434
- stmt = db.prepare("INSERT INTO compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, created_at, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
23435
- insertCompartmentStatements.set(db, stmt);
23436
- }
23437
- return stmt;
23438
- }
23439
- function getInsertFactStatement(db) {
23440
- let stmt = insertFactStatements.get(db);
23441
- if (!stmt) {
23442
- stmt = db.prepare("INSERT INTO session_facts (session_id, category, content, created_at, updated_at, harness) VALUES (?, ?, ?, ?, ?, ?)");
23443
- insertFactStatements.set(db, stmt);
23444
- }
23445
- return stmt;
23446
- }
23447
- function isCompartmentRow(row) {
23448
- if (row === null || typeof row !== "object")
23449
- return false;
23450
- const candidate = row;
23451
- return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number";
23452
- }
23453
- function isSessionFactRow(row) {
23454
- if (row === null || typeof row !== "object")
23455
- return false;
23456
- const candidate = row;
23457
- return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.category === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number" && typeof candidate.updated_at === "number";
23458
- }
23459
- function insertCompartmentRows(db, sessionId, compartments, now) {
23460
- const stmt = getInsertCompartmentStatement(db);
23461
- for (const compartment of compartments) {
23462
- stmt.run(sessionId, compartment.sequence, compartment.startMessage, compartment.endMessage, compartment.startMessageId, compartment.endMessageId, compartment.title, compartment.content, now, getHarness());
23463
- }
23464
- }
23465
- function insertFactRows(db, sessionId, facts, now) {
23466
- const stmt = getInsertFactStatement(db);
23467
- for (const fact of facts) {
23468
- stmt.run(sessionId, fact.category, fact.content, now, now, getHarness());
23469
- }
23470
- }
23471
- function toCompartment(row) {
23472
- return {
23473
- id: row.id,
23474
- sessionId: row.session_id,
23475
- sequence: row.sequence,
23476
- startMessage: row.start_message,
23477
- endMessage: row.end_message,
23478
- startMessageId: row.start_message_id,
23479
- endMessageId: row.end_message_id,
23480
- title: row.title,
23481
- content: row.content,
23482
- createdAt: row.created_at
23483
- };
23484
- }
23485
- function toSessionFact(row) {
23486
- return {
23487
- id: row.id,
23488
- sessionId: row.session_id,
23489
- category: row.category,
23490
- content: row.content,
23491
- createdAt: row.created_at,
23492
- updatedAt: row.updated_at
23493
- };
23494
- }
23495
- function getCompartments(db, sessionId) {
23496
- const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isCompartmentRow);
23497
- return rows.map(toCompartment);
23498
- }
23499
- function getLastCompartmentEndMessage(db, sessionId) {
23500
- const row = db.prepare("SELECT MAX(end_message) as max_end FROM compartments WHERE session_id = ?").get(sessionId);
23501
- return row?.max_end ?? -1;
23502
- }
23503
- function appendCompartments(db, sessionId, compartments) {
23504
- if (compartments.length === 0)
23505
- return;
23506
- const now = Date.now();
23507
- db.transaction(() => {
23508
- insertCompartmentRows(db, sessionId, compartments, now);
23509
- })();
23510
- }
23511
- function replaceSessionFacts(db, sessionId, facts) {
23512
- const now = Date.now();
23513
- db.transaction(() => {
23514
- db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
23515
- insertFactRows(db, sessionId, facts, now);
23516
- db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
23517
- })();
23518
- }
23519
- function getSessionFacts(db, sessionId) {
23520
- const rows = db.prepare("SELECT * FROM session_facts WHERE session_id = ? ORDER BY category ASC, id ASC").all(sessionId).filter(isSessionFactRow);
23521
- return rows.map(toSessionFact);
23522
- }
23523
- function replaceAllCompartmentState(db, sessionId, compartments, facts) {
23524
- const now = Date.now();
23525
- db.transaction(() => {
23526
- db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
23527
- db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
23528
- insertCompartmentRows(db, sessionId, compartments, now);
23529
- insertFactRows(db, sessionId, facts, now);
23530
- db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
23531
- })();
23532
- }
23533
- function buildCompartmentBlock(compartments, facts, memoryBlock, dateRanges) {
23534
- const lines = [];
23535
- if (memoryBlock) {
23536
- lines.push(memoryBlock);
23537
- lines.push("");
23538
- }
23539
- for (const c of compartments) {
23540
- const dates = dateRanges?.byId.get(c.id);
23541
- const dateAttr = dates ? ` start-date="${dates.start}" end-date="${dates.end}"` : "";
23542
- lines.push(`<compartment start="${c.startMessage}" end="${c.endMessage}"${dateAttr} title="${escapeXmlAttr(c.title)}">`);
23543
- lines.push(escapeXmlContent(c.content));
23544
- lines.push("</compartment>");
23545
- lines.push("");
23546
- }
23547
- const factsByCategory = new Map;
23548
- for (const f of facts) {
23549
- const existing = factsByCategory.get(f.category) ?? [];
23550
- existing.push(f.content);
23551
- factsByCategory.set(f.category, existing);
23552
- }
23553
- for (const [category, items] of factsByCategory) {
23554
- lines.push(`${category}:`);
23555
- for (const item of items) {
23556
- lines.push(`* ${escapeXmlContent(item)}`);
23557
- }
23558
- lines.push("");
23559
- }
23560
- return lines.join(`
23561
- `).trimEnd();
23562
- }
23563
- function saveRecompStagingPass(db, sessionId, passNumber, compartments, facts) {
23564
- const now = Date.now();
23565
- db.transaction(() => {
23566
- db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
23567
- const compartmentStmt = db.prepare("INSERT OR REPLACE INTO recomp_compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, pass_number, created_at, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
23568
- for (const c of compartments) {
23569
- compartmentStmt.run(sessionId, c.sequence, c.startMessage, c.endMessage, c.startMessageId, c.endMessageId, c.title, c.content, passNumber, now, getHarness());
23570
- }
23571
- const factStmt = db.prepare("INSERT INTO recomp_facts (session_id, category, content, pass_number, created_at, harness) VALUES (?, ?, ?, ?, ?, ?)");
23572
- for (const f of facts) {
23573
- factStmt.run(sessionId, f.category, f.content, passNumber, now, getHarness());
23574
- }
23575
- })();
23576
- }
23577
- function getRecompStaging(db, sessionId) {
23578
- const compartmentRows = db.prepare("SELECT * FROM recomp_compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isRecompCompartmentRow);
23579
- if (compartmentRows.length === 0)
23580
- return null;
23581
- const compartments = compartmentRows.map((row) => ({
23582
- sequence: row.sequence,
23583
- startMessage: row.start_message,
23584
- endMessage: row.end_message,
23585
- startMessageId: row.start_message_id,
23586
- endMessageId: row.end_message_id,
23587
- title: row.title,
23588
- content: row.content
23589
- }));
23590
- const factRows = db.prepare("SELECT category, content FROM recomp_facts WHERE session_id = ?").all(sessionId).filter(isRecompFactRow);
23591
- const maxPass = compartmentRows.reduce((m, r) => Math.max(m, r.pass_number), 0);
23592
- const lastEnd = compartmentRows[compartmentRows.length - 1]?.end_message ?? 0;
23593
- return {
23594
- compartments,
23595
- facts: factRows,
23596
- passCount: maxPass,
23597
- lastEndMessage: lastEnd
23598
- };
23599
- }
23600
- function promoteRecompStaging(db, sessionId) {
23601
- const now = Date.now();
23602
- return db.transaction(() => {
23603
- const staging = getRecompStaging(db, sessionId);
23604
- if (!staging || staging.compartments.length === 0)
23605
- return null;
23606
- db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
23607
- db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
23608
- insertCompartmentRows(db, sessionId, staging.compartments, now);
23609
- insertFactRows(db, sessionId, staging.facts, now);
23610
- db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
23611
- db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
23612
- db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE session_id = ?").run(sessionId);
23613
- return { compartments: staging.compartments, facts: staging.facts };
23614
- })();
23615
- }
23616
- function invalidateAllMemoryBlockCaches(db) {
23617
- try {
23618
- db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE memory_block_cache != '' OR memory_block_ids != ''").run();
23619
- } catch {}
23620
- }
23621
- function clearRecompStaging(db, sessionId) {
23622
- db.transaction(() => {
23623
- db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
23624
- db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
23625
- try {
23626
- db.prepare("UPDATE session_meta SET recomp_partial_range_start = 0, recomp_partial_range_end = 0 WHERE session_id = ?").run(sessionId);
23627
- } catch {}
23628
- })();
23629
- }
23630
- function getRecompPartialRange(db, sessionId) {
23631
- try {
23632
- const row = db.prepare("SELECT recomp_partial_range_start AS start, recomp_partial_range_end AS end FROM session_meta WHERE session_id = ?").get(sessionId);
23633
- const start = typeof row?.start === "number" ? row.start : 0;
23634
- const end = typeof row?.end === "number" ? row.end : 0;
23635
- if (start <= 0 || end <= 0)
23636
- return null;
23637
- return { start, end };
23638
- } catch {
23639
- return null;
23640
- }
23641
- }
23642
- function setRecompPartialRange(db, sessionId, range) {
23643
- const start = range ? range.start : 0;
23644
- const end = range ? range.end : 0;
23645
- db.prepare("INSERT OR IGNORE INTO session_meta (session_id) VALUES (?)").run(sessionId);
23646
- db.prepare("UPDATE session_meta SET recomp_partial_range_start = ?, recomp_partial_range_end = ? WHERE session_id = ?").run(start, end, sessionId);
23647
- }
23648
- function isRecompCompartmentRow(row) {
23649
- if (row === null || typeof row !== "object")
23650
- return false;
23651
- const candidate = row;
23652
- return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && typeof candidate.pass_number === "number" && typeof candidate.created_at === "number";
23653
- }
23654
- function isRecompFactRow(row) {
23655
- if (row === null || typeof row !== "object")
23656
- return false;
23657
- const candidate = row;
23658
- return typeof candidate.category === "string" && typeof candidate.content === "string";
23659
- }
23660
- function escapeXmlAttr(s) {
23661
- return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&apos;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
23662
- }
23663
- function escapeXmlContent(s) {
23664
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
23665
- }
23666
- // ../plugin/src/features/magic-context/compression-depth-storage.ts
23667
- var incrementDepthStatements = new WeakMap;
23668
- var totalDepthStatements = new WeakMap;
23669
- var maxDepthStatements = new WeakMap;
23670
- var clearDepthStatements = new WeakMap;
23671
- function getIncrementDepthStatement(db) {
23672
- let stmt = incrementDepthStatements.get(db);
23673
- if (!stmt) {
23674
- stmt = db.prepare("INSERT INTO compression_depth (session_id, message_ordinal, depth, harness) VALUES (?, ?, 1, ?) ON CONFLICT(session_id, message_ordinal) DO UPDATE SET depth = depth + 1");
23675
- incrementDepthStatements.set(db, stmt);
23676
- }
23677
- return stmt;
23678
- }
23679
- function getTotalDepthStatement(db) {
23680
- let stmt = totalDepthStatements.get(db);
23681
- if (!stmt) {
23682
- stmt = db.prepare("SELECT COALESCE(SUM(depth), 0) AS total_depth FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?");
23683
- totalDepthStatements.set(db, stmt);
23684
- }
23685
- return stmt;
23686
- }
23687
- function getClearDepthStatement(db) {
23688
- let stmt = clearDepthStatements.get(db);
23689
- if (!stmt) {
23690
- stmt = db.prepare("DELETE FROM compression_depth WHERE session_id = ?");
23691
- clearDepthStatements.set(db, stmt);
23692
- }
23693
- return stmt;
23694
- }
23695
- function incrementCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
23696
- if (endOrdinal < startOrdinal) {
23697
- return;
23698
- }
23699
- db.transaction(() => {
23700
- const stmt = getIncrementDepthStatement(db);
23701
- for (let ordinal = startOrdinal;ordinal <= endOrdinal; ordinal += 1) {
23702
- stmt.run(sessionId, ordinal, getHarness());
23703
- }
23704
- })();
23705
- }
23706
- function getAverageCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
23707
- if (endOrdinal < startOrdinal) {
23708
- return 0;
23709
- }
23710
- const row = getTotalDepthStatement(db).get(sessionId, startOrdinal, endOrdinal);
23711
- const totalDepth = typeof row?.total_depth === "number" ? row.total_depth : 0;
23712
- const messageCount = endOrdinal - startOrdinal + 1;
23713
- return totalDepth / messageCount;
23714
- }
23715
- function clearCompressionDepth(db, sessionId) {
23716
- getClearDepthStatement(db).run(sessionId);
23717
- }
23718
- function clearCompressionDepthRange(db, sessionId, startOrdinal, endOrdinal) {
23719
- if (endOrdinal < startOrdinal) {
23720
- return;
23721
- }
23722
- db.prepare("DELETE FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?").run(sessionId, startOrdinal, endOrdinal);
23723
- }
23724
23317
  // ../plugin/src/shared/internal-initiator-marker.ts
23725
23318
  var OMO_INTERNAL_INITIATOR_MARKER = "<!-- OMO_INTERNAL_INITIATOR -->";
23726
23319
 
@@ -156398,21 +155991,85 @@ function isTextPart(part) {
156398
155991
  const p = part;
156399
155992
  return p.type === "text" && typeof p.text === "string";
156400
155993
  }
156401
- function isToolPartWithOutput(part) {
155994
+ function isFilePart(part) {
156402
155995
  if (part === null || typeof part !== "object")
156403
155996
  return false;
156404
155997
  const p = part;
156405
- if (p.type !== "tool" || typeof p.callID !== "string")
155998
+ return p.type === "file" && typeof p.url === "string";
155999
+ }
156000
+
156001
+ // ../plugin/src/shared/record-type-guard.ts
156002
+ function isRecord(value) {
156003
+ return typeof value === "object" && value !== null && !Array.isArray(value);
156004
+ }
156005
+
156006
+ // ../plugin/src/hooks/magic-context/tool-drop-target.ts
156007
+ var IGNORE_PART_TYPES = new Set([
156008
+ "thinking",
156009
+ "reasoning",
156010
+ "redacted_thinking",
156011
+ "meta",
156012
+ "step-start",
156013
+ "step-finish"
156014
+ ]);
156015
+ function isToolCallId(value) {
156016
+ return typeof value === "string" && value.length > 0;
156017
+ }
156018
+ function hasMeaningfulPart(part) {
156019
+ if (!isRecord(part))
156406
156020
  return false;
156407
- if (p.state === null || typeof p.state !== "object")
156021
+ const type = part.type;
156022
+ if (type === "text") {
156023
+ return typeof part.text === "string" && part.text.trim().length > 0;
156024
+ }
156025
+ if (typeof type !== "string")
156408
156026
  return false;
156409
- return typeof p.state.output === "string";
156410
- }
156411
- function isFilePart(part) {
156412
- if (part === null || typeof part !== "object")
156027
+ if (IGNORE_PART_TYPES.has(type))
156413
156028
  return false;
156414
- const p = part;
156415
- return p.type === "file" && typeof p.url === "string";
156029
+ return true;
156030
+ }
156031
+ function extractToolCallObservation(part) {
156032
+ if (!isRecord(part))
156033
+ return null;
156034
+ if (part.type === "tool" && isToolCallId(part.callID)) {
156035
+ return { callId: part.callID, kind: "result" };
156036
+ }
156037
+ if (part.type === "tool-invocation" && isToolCallId(part.callID)) {
156038
+ return { callId: part.callID, kind: "invocation" };
156039
+ }
156040
+ if (part.type === "tool_use" && isToolCallId(part.id)) {
156041
+ return { callId: part.id, kind: "invocation" };
156042
+ }
156043
+ if (part.type === "tool_result" && isToolCallId(part.tool_use_id)) {
156044
+ return { callId: part.tool_use_id, kind: "result" };
156045
+ }
156046
+ return null;
156047
+ }
156048
+ class ToolMutationBatch {
156049
+ partsToRemove = new Set;
156050
+ affectedMessages = new Set;
156051
+ messages;
156052
+ constructor(messages) {
156053
+ this.messages = messages;
156054
+ }
156055
+ markForRemoval(occurrence) {
156056
+ this.partsToRemove.add(occurrence.part);
156057
+ this.affectedMessages.add(occurrence.message);
156058
+ }
156059
+ finalize() {
156060
+ if (this.partsToRemove.size === 0)
156061
+ return;
156062
+ for (const message of this.affectedMessages) {
156063
+ message.parts = message.parts.filter((p) => !this.partsToRemove.has(p));
156064
+ }
156065
+ for (let i = this.messages.length - 1;i >= 0; i -= 1) {
156066
+ if (!this.messages[i].parts.some(hasMeaningfulPart)) {
156067
+ this.messages.splice(i, 1);
156068
+ }
156069
+ }
156070
+ this.partsToRemove.clear();
156071
+ this.affectedMessages.clear();
156072
+ }
156416
156073
  }
156417
156074
 
156418
156075
  // ../plugin/src/hooks/magic-context/read-session-chunk.ts
@@ -156479,23 +156136,47 @@ function getRawSessionMessageCount(sessionId) {
156479
156136
  }
156480
156137
  function getRawSessionTagKeysThrough(sessionId, upToMessageIndex) {
156481
156138
  const messages = readRawSessionMessages(sessionId);
156482
- const keys = [];
156139
+ const messageFileKeys = new Set;
156140
+ const toolObservations = new Map;
156141
+ const unpairedInvocations = new Map;
156483
156142
  for (const message of messages) {
156484
156143
  if (message.ordinal > upToMessageIndex)
156485
156144
  break;
156486
156145
  for (const [partIndex, part] of message.parts.entries()) {
156487
156146
  if (isTextPart(part)) {
156488
- keys.push(`${message.id}:p${partIndex}`);
156147
+ messageFileKeys.add(`${message.id}:p${partIndex}`);
156148
+ continue;
156489
156149
  }
156490
156150
  if (isFilePart(part)) {
156491
- keys.push(`${message.id}:file${partIndex}`);
156151
+ messageFileKeys.add(`${message.id}:file${partIndex}`);
156152
+ continue;
156492
156153
  }
156493
- if (isToolPartWithOutput(part)) {
156494
- keys.push(part.callID);
156154
+ const obs = extractToolCallObservation(part);
156155
+ if (!obs)
156156
+ continue;
156157
+ let ownerMsgId;
156158
+ if (obs.kind === "invocation") {
156159
+ ownerMsgId = message.id;
156160
+ const queue = unpairedInvocations.get(obs.callId) ?? [];
156161
+ queue.push(message.id);
156162
+ unpairedInvocations.set(obs.callId, queue);
156163
+ } else {
156164
+ const queue = unpairedInvocations.get(obs.callId);
156165
+ if (queue && queue.length > 0) {
156166
+ const popped = queue.shift();
156167
+ if (queue.length === 0)
156168
+ unpairedInvocations.delete(obs.callId);
156169
+ ownerMsgId = popped ?? message.id;
156170
+ } else {
156171
+ ownerMsgId = message.id;
156172
+ }
156495
156173
  }
156174
+ const owners = toolObservations.get(obs.callId) ?? new Set;
156175
+ owners.add(ownerMsgId);
156176
+ toolObservations.set(obs.callId, owners);
156496
156177
  }
156497
156178
  }
156498
- return keys;
156179
+ return { messageFileKeys, toolObservations };
156499
156180
  }
156500
156181
  var PROTECTED_TAIL_USER_TURNS = 5;
156501
156182
  function getProtectedTailStartOrdinal(sessionId) {
@@ -156644,6 +156325,79 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
156644
156325
  };
156645
156326
  }
156646
156327
 
156328
+ // ../plugin/src/shared/harness.ts
156329
+ var currentHarness = "opencode";
156330
+ var harnessLocked = false;
156331
+ function setHarness(value) {
156332
+ if (harnessLocked && currentHarness !== value) {
156333
+ throw new Error(`Magic Context: harness already locked to "${currentHarness}"; cannot change to "${value}"`);
156334
+ }
156335
+ currentHarness = value;
156336
+ harnessLocked = true;
156337
+ }
156338
+ function getHarness() {
156339
+ return currentHarness;
156340
+ }
156341
+
156342
+ // ../plugin/src/features/magic-context/compression-depth-storage.ts
156343
+ var incrementDepthStatements = new WeakMap;
156344
+ var totalDepthStatements = new WeakMap;
156345
+ var maxDepthStatements = new WeakMap;
156346
+ var clearDepthStatements = new WeakMap;
156347
+ function getIncrementDepthStatement(db) {
156348
+ let stmt = incrementDepthStatements.get(db);
156349
+ if (!stmt) {
156350
+ stmt = db.prepare("INSERT INTO compression_depth (session_id, message_ordinal, depth, harness) VALUES (?, ?, 1, ?) ON CONFLICT(session_id, message_ordinal) DO UPDATE SET depth = depth + 1");
156351
+ incrementDepthStatements.set(db, stmt);
156352
+ }
156353
+ return stmt;
156354
+ }
156355
+ function getTotalDepthStatement(db) {
156356
+ let stmt = totalDepthStatements.get(db);
156357
+ if (!stmt) {
156358
+ stmt = db.prepare("SELECT COALESCE(SUM(depth), 0) AS total_depth FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?");
156359
+ totalDepthStatements.set(db, stmt);
156360
+ }
156361
+ return stmt;
156362
+ }
156363
+ function getClearDepthStatement(db) {
156364
+ let stmt = clearDepthStatements.get(db);
156365
+ if (!stmt) {
156366
+ stmt = db.prepare("DELETE FROM compression_depth WHERE session_id = ?");
156367
+ clearDepthStatements.set(db, stmt);
156368
+ }
156369
+ return stmt;
156370
+ }
156371
+ function incrementCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
156372
+ if (endOrdinal < startOrdinal) {
156373
+ return;
156374
+ }
156375
+ db.transaction(() => {
156376
+ const stmt = getIncrementDepthStatement(db);
156377
+ for (let ordinal = startOrdinal;ordinal <= endOrdinal; ordinal += 1) {
156378
+ stmt.run(sessionId, ordinal, getHarness());
156379
+ }
156380
+ })();
156381
+ }
156382
+ function getAverageCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
156383
+ if (endOrdinal < startOrdinal) {
156384
+ return 0;
156385
+ }
156386
+ const row = getTotalDepthStatement(db).get(sessionId, startOrdinal, endOrdinal);
156387
+ const totalDepth = typeof row?.total_depth === "number" ? row.total_depth : 0;
156388
+ const messageCount = endOrdinal - startOrdinal + 1;
156389
+ return totalDepth / messageCount;
156390
+ }
156391
+ function clearCompressionDepth(db, sessionId) {
156392
+ getClearDepthStatement(db).run(sessionId);
156393
+ }
156394
+ function clearCompressionDepthRange(db, sessionId, startOrdinal, endOrdinal) {
156395
+ if (endOrdinal < startOrdinal) {
156396
+ return;
156397
+ }
156398
+ db.prepare("DELETE FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?").run(sessionId, startOrdinal, endOrdinal);
156399
+ }
156400
+
156647
156401
  // ../plugin/src/features/magic-context/message-index.ts
156648
156402
  var lastIndexedStatements = new WeakMap;
156649
156403
  var insertMessageStatements = new WeakMap;
@@ -156651,6 +156405,7 @@ var upsertIndexStatements = new WeakMap;
156651
156405
  var deleteFtsStatements = new WeakMap;
156652
156406
  var deleteIndexStatements = new WeakMap;
156653
156407
  var countIndexedMessageStatements = new WeakMap;
156408
+ var indexedMessageIdStatements = new WeakMap;
156654
156409
  function normalizeIndexText(text) {
156655
156410
  return text.replace(/\s+/g, " ").trim();
156656
156411
  }
@@ -156694,10 +156449,34 @@ function getDeleteIndexStatement(db) {
156694
156449
  }
156695
156450
  return stmt;
156696
156451
  }
156452
+ function getCountIndexedMessageStatement(db) {
156453
+ let stmt = countIndexedMessageStatements.get(db);
156454
+ if (!stmt) {
156455
+ stmt = db.prepare("SELECT COUNT(*) AS count FROM message_history_fts WHERE session_id = ? AND message_id = ?");
156456
+ countIndexedMessageStatements.set(db, stmt);
156457
+ }
156458
+ return stmt;
156459
+ }
156460
+ function getIndexedMessageIdStatement(db) {
156461
+ let stmt = indexedMessageIdStatements.get(db);
156462
+ if (!stmt) {
156463
+ stmt = db.prepare("SELECT message_id AS messageId FROM message_history_fts WHERE session_id = ?");
156464
+ indexedMessageIdStatements.set(db, stmt);
156465
+ }
156466
+ return stmt;
156467
+ }
156697
156468
  function getLastIndexedOrdinal(db, sessionId) {
156698
156469
  const row = getLastIndexedStatement(db).get(sessionId);
156699
156470
  return typeof row?.last_indexed_ordinal === "number" ? row.last_indexed_ordinal : 0;
156700
156471
  }
156472
+ function isMessageAlreadyIndexed(db, sessionId, messageId) {
156473
+ const row = getCountIndexedMessageStatement(db).get(sessionId, messageId);
156474
+ return (typeof row?.count === "number" ? row.count : 0) > 0;
156475
+ }
156476
+ function advanceIndexWatermark(db, sessionId, ordinal, now) {
156477
+ const current = getLastIndexedOrdinal(db, sessionId);
156478
+ getUpsertIndexStatement(db).run(sessionId, Math.max(current, ordinal), now, getHarness());
156479
+ }
156701
156480
  function clearIndexedMessages(db, sessionId) {
156702
156481
  db.transaction(() => {
156703
156482
  getDeleteFtsStatement(db).run(sessionId);
@@ -156717,39 +156496,510 @@ function getIndexableContent(role, parts) {
156717
156496
  }
156718
156497
  return "";
156719
156498
  }
156720
- function ensureMessagesIndexed(db, sessionId, readMessages) {
156721
- const messages = readMessages(sessionId);
156722
- if (messages.length === 0) {
156723
- db.transaction(() => clearIndexedMessages(db, sessionId))();
156499
+ function indexSingleMessageInTransaction(db, sessionId, message, now) {
156500
+ if (message.role !== "user" && message.role !== "assistant") {
156501
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
156502
+ return false;
156503
+ }
156504
+ const content = getIndexableContent(message.role, message.parts);
156505
+ if (content.length === 0) {
156506
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
156507
+ return false;
156508
+ }
156509
+ if (isMessageAlreadyIndexed(db, sessionId, message.id)) {
156510
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
156511
+ return false;
156512
+ }
156513
+ getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
156514
+ advanceIndexWatermark(db, sessionId, message.ordinal, now);
156515
+ return true;
156516
+ }
156517
+ function indexSingleMessage(db, sessionId, message) {
156518
+ return db.transaction(() => indexSingleMessageInTransaction(db, sessionId, message, Date.now()))();
156519
+ }
156520
+ function indexMessagesAfterOrdinal(db, sessionId, messages, lastIndexedOrdinal, finalWatermark = messages.length) {
156521
+ const now = Date.now();
156522
+ let inserted = 0;
156523
+ db.transaction(() => {
156524
+ const existingMessageIds = new Set(getIndexedMessageIdStatement(db).all(sessionId).map((row) => row.messageId).filter((messageId) => typeof messageId === "string"));
156525
+ const insertMessage = getInsertMessageStatement(db);
156526
+ for (const message of messages) {
156527
+ if (message.ordinal <= lastIndexedOrdinal) {
156528
+ continue;
156529
+ }
156530
+ if (message.role !== "user" && message.role !== "assistant") {
156531
+ continue;
156532
+ }
156533
+ const content = getIndexableContent(message.role, message.parts);
156534
+ if (content.length === 0 || existingMessageIds.has(message.id)) {
156535
+ continue;
156536
+ }
156537
+ insertMessage.run(sessionId, message.ordinal, message.id, message.role, content);
156538
+ existingMessageIds.add(message.id);
156539
+ inserted++;
156540
+ }
156541
+ getUpsertIndexStatement(db).run(sessionId, finalWatermark, now, getHarness());
156542
+ })();
156543
+ return inserted;
156544
+ }
156545
+
156546
+ // ../plugin/src/features/magic-context/message-index-async.ts
156547
+ var INCREMENTAL_DEBOUNCE_MS = 100;
156548
+ var reconciledSessions = new Set;
156549
+ var reconciliationScheduledSessions = new Set;
156550
+ var sessionLocks = new Map;
156551
+ var incrementalTimers = new Map;
156552
+ var pendingIncrementalKeys = new Set;
156553
+ function defer(fn) {
156554
+ const immediate = globalThis.setImmediate;
156555
+ if (typeof immediate === "function") {
156556
+ immediate(fn);
156724
156557
  return;
156725
156558
  }
156726
- let lastIndexedOrdinal = getLastIndexedOrdinal(db, sessionId);
156727
- if (lastIndexedOrdinal > messages.length) {
156728
- db.transaction(() => clearIndexedMessages(db, sessionId))();
156729
- lastIndexedOrdinal = 0;
156559
+ setTimeout(fn, 0);
156560
+ }
156561
+ function runWithSessionLock(sessionId, operation) {
156562
+ const previous = sessionLocks.get(sessionId) ?? Promise.resolve();
156563
+ const run = previous.catch(() => {
156564
+ return;
156565
+ }).then(async () => {
156566
+ await operation();
156567
+ });
156568
+ sessionLocks.set(sessionId, run);
156569
+ run.finally(() => {
156570
+ if (sessionLocks.get(sessionId) === run) {
156571
+ sessionLocks.delete(sessionId);
156572
+ }
156573
+ }).catch(() => {
156574
+ return;
156575
+ });
156576
+ return run;
156577
+ }
156578
+ function logIndexingError(sessionId, action, error48) {
156579
+ sessionLog(sessionId, `message FTS async ${action} failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
156580
+ log(`[message-index-async] ${action} failed for ${sessionId}:`, error48);
156581
+ }
156582
+ async function reconcileSessionIndex(db, sessionId, readMessages) {
156583
+ await runWithSessionLock(sessionId, () => {
156584
+ if (reconciledSessions.has(sessionId)) {
156585
+ return;
156586
+ }
156587
+ const messages = readMessages(sessionId);
156588
+ if (messages.length === 0) {
156589
+ clearIndexedMessages(db, sessionId);
156590
+ reconciledSessions.add(sessionId);
156591
+ return;
156592
+ }
156593
+ let lastIndexedOrdinal = getLastIndexedOrdinal(db, sessionId);
156594
+ if (lastIndexedOrdinal > messages.length) {
156595
+ clearIndexedMessages(db, sessionId);
156596
+ lastIndexedOrdinal = 0;
156597
+ }
156598
+ const watermark = Math.min(lastIndexedOrdinal, messages.length);
156599
+ indexMessagesAfterOrdinal(db, sessionId, messages, watermark, messages.length);
156600
+ reconciledSessions.add(sessionId);
156601
+ });
156602
+ }
156603
+ function scheduleReconciliation(db, sessionId, readMessages) {
156604
+ if (reconciledSessions.has(sessionId) || reconciliationScheduledSessions.has(sessionId)) {
156605
+ return;
156730
156606
  }
156731
- if (lastIndexedOrdinal >= messages.length) {
156607
+ reconciliationScheduledSessions.add(sessionId);
156608
+ defer(() => {
156609
+ reconcileSessionIndex(db, sessionId, readMessages).catch((error48) => {
156610
+ reconciliationScheduledSessions.delete(sessionId);
156611
+ logIndexingError(sessionId, "reconciliation", error48);
156612
+ });
156613
+ });
156614
+ }
156615
+ function scheduleIncrementalIndex(db, sessionId, messageId, readSingleMessage) {
156616
+ const key = `${sessionId}\x00${messageId}`;
156617
+ if (incrementalTimers.has(key) || pendingIncrementalKeys.has(key)) {
156732
156618
  return;
156733
156619
  }
156734
- const messagesToInsert = messages.filter((message) => message.ordinal > lastIndexedOrdinal).filter((message) => message.role === "user" || message.role === "assistant").map((message) => ({
156735
- ordinal: message.ordinal,
156736
- id: message.id,
156737
- role: message.role,
156738
- content: getIndexableContent(message.role, message.parts)
156739
- })).filter((message) => message.content.length > 0);
156620
+ const timer = setTimeout(() => {
156621
+ incrementalTimers.delete(key);
156622
+ pendingIncrementalKeys.add(key);
156623
+ runWithSessionLock(sessionId, () => {
156624
+ const message = readSingleMessage(sessionId, messageId);
156625
+ if (!message) {
156626
+ return;
156627
+ }
156628
+ indexSingleMessage(db, sessionId, message);
156629
+ }).catch((error48) => {
156630
+ logIndexingError(sessionId, `incremental index for ${messageId}`, error48);
156631
+ }).finally(() => {
156632
+ pendingIncrementalKeys.delete(key);
156633
+ });
156634
+ }, INCREMENTAL_DEBOUNCE_MS);
156635
+ incrementalTimers.set(key, timer);
156636
+ }
156637
+ function clearSessionTracking(sessionId) {
156638
+ reconciledSessions.delete(sessionId);
156639
+ reconciliationScheduledSessions.delete(sessionId);
156640
+ sessionLocks.delete(sessionId);
156641
+ const prefix = `${sessionId}\x00`;
156642
+ for (const [key, timer] of incrementalTimers) {
156643
+ if (key.startsWith(prefix)) {
156644
+ clearTimeout(timer);
156645
+ incrementalTimers.delete(key);
156646
+ }
156647
+ }
156648
+ for (const key of pendingIncrementalKeys) {
156649
+ if (key.startsWith(prefix)) {
156650
+ pendingIncrementalKeys.delete(key);
156651
+ }
156652
+ }
156653
+ }
156654
+
156655
+ // ../plugin/src/features/magic-context/overflow-detection.ts
156656
+ var OVERFLOW_PATTERNS = [
156657
+ /prompt is too long/i,
156658
+ /input is too long for requested model/i,
156659
+ /exceeds the context window/i,
156660
+ /input token count.*exceeds the maximum/i,
156661
+ /maximum prompt length is \d+/i,
156662
+ /reduce the length of the messages/i,
156663
+ /maximum context length is \d+ tokens/i,
156664
+ /exceeds the limit of \d+/i,
156665
+ /exceeds the available context size/i,
156666
+ /greater than the context length/i,
156667
+ /context window exceeds limit/i,
156668
+ /exceeded model token limit/i,
156669
+ /context[_ ]length[_ ]exceeded/i,
156670
+ /request entity too large/i,
156671
+ /context length is only \d+ tokens/i,
156672
+ /input length.*exceeds.*context length/i,
156673
+ /prompt too long; exceeded (?:max )?context length/i,
156674
+ /too large for model with \d+ maximum context length/i,
156675
+ /model_context_window_exceeded/i,
156676
+ /context size has been exceeded/i
156677
+ ];
156678
+ var LIMIT_EXTRACTION_PATTERNS = [
156679
+ /maximum prompt length is (\d+)/i,
156680
+ /maximum context length is (\d+) tokens?/i,
156681
+ /context length is only (\d+) tokens?/i,
156682
+ /exceeds the limit of (\d+)/i,
156683
+ /too large for model with (\d+) maximum context length/i,
156684
+ /context size.*(\d+) tokens?/i,
156685
+ /exceeds? the context length of (\d+)/i,
156686
+ /max(?:imum)?.*context.*?(\d+)/i
156687
+ ];
156688
+ var MIN_PLAUSIBLE_LIMIT = 1024;
156689
+ var MAX_PLAUSIBLE_LIMIT = 1e7;
156690
+ function extractErrorMessage(error48) {
156691
+ if (!error48)
156692
+ return "";
156693
+ if (typeof error48 === "string")
156694
+ return error48;
156695
+ if (typeof error48 === "object") {
156696
+ const obj = error48;
156697
+ const nested = obj.error;
156698
+ if (nested && typeof nested.message === "string" && nested.message.length > 0) {
156699
+ return nested.message;
156700
+ }
156701
+ }
156702
+ if (error48 instanceof Error)
156703
+ return error48.message;
156704
+ if (typeof error48 === "object") {
156705
+ const obj = error48;
156706
+ if (typeof obj.message === "string")
156707
+ return obj.message;
156708
+ if (typeof obj.responseBody === "string")
156709
+ return obj.responseBody;
156710
+ try {
156711
+ return JSON.stringify(error48);
156712
+ } catch {
156713
+ return String(error48);
156714
+ }
156715
+ }
156716
+ return String(error48);
156717
+ }
156718
+ function detectOverflow(error48) {
156719
+ const message = extractErrorMessage(error48);
156720
+ if (!message) {
156721
+ return { isOverflow: false };
156722
+ }
156723
+ const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
156724
+ let matched;
156725
+ for (const pattern of OVERFLOW_PATTERNS) {
156726
+ if (pattern.test(message)) {
156727
+ matched = pattern;
156728
+ break;
156729
+ }
156730
+ }
156731
+ if (!matched && !hasStatus413) {
156732
+ return { isOverflow: false };
156733
+ }
156734
+ const reportedLimit = parseReportedLimit(message);
156735
+ return {
156736
+ isOverflow: true,
156737
+ reportedLimit,
156738
+ matchedPattern: matched?.source
156739
+ };
156740
+ }
156741
+ function parseReportedLimit(message) {
156742
+ if (!message)
156743
+ return;
156744
+ for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
156745
+ const match = message.match(pattern);
156746
+ if (!match)
156747
+ continue;
156748
+ const raw = match[1];
156749
+ if (!raw)
156750
+ continue;
156751
+ const value = Number.parseInt(raw, 10);
156752
+ if (!Number.isFinite(value))
156753
+ continue;
156754
+ if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
156755
+ continue;
156756
+ return value;
156757
+ }
156758
+ return;
156759
+ }
156760
+
156761
+ // ../plugin/src/features/magic-context/compartment-storage.ts
156762
+ var insertCompartmentStatements = new WeakMap;
156763
+ var insertFactStatements = new WeakMap;
156764
+ function getInsertCompartmentStatement(db) {
156765
+ let stmt = insertCompartmentStatements.get(db);
156766
+ if (!stmt) {
156767
+ stmt = db.prepare("INSERT INTO compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, created_at, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
156768
+ insertCompartmentStatements.set(db, stmt);
156769
+ }
156770
+ return stmt;
156771
+ }
156772
+ function getInsertFactStatement(db) {
156773
+ let stmt = insertFactStatements.get(db);
156774
+ if (!stmt) {
156775
+ stmt = db.prepare("INSERT INTO session_facts (session_id, category, content, created_at, updated_at, harness) VALUES (?, ?, ?, ?, ?, ?)");
156776
+ insertFactStatements.set(db, stmt);
156777
+ }
156778
+ return stmt;
156779
+ }
156780
+ function isCompartmentRow(row) {
156781
+ if (row === null || typeof row !== "object")
156782
+ return false;
156783
+ const candidate = row;
156784
+ return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number";
156785
+ }
156786
+ function isSessionFactRow(row) {
156787
+ if (row === null || typeof row !== "object")
156788
+ return false;
156789
+ const candidate = row;
156790
+ return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.category === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number" && typeof candidate.updated_at === "number";
156791
+ }
156792
+ function insertCompartmentRows(db, sessionId, compartments, now) {
156793
+ const stmt = getInsertCompartmentStatement(db);
156794
+ for (const compartment of compartments) {
156795
+ stmt.run(sessionId, compartment.sequence, compartment.startMessage, compartment.endMessage, compartment.startMessageId, compartment.endMessageId, compartment.title, compartment.content, now, getHarness());
156796
+ }
156797
+ }
156798
+ function insertFactRows(db, sessionId, facts, now) {
156799
+ const stmt = getInsertFactStatement(db);
156800
+ for (const fact of facts) {
156801
+ stmt.run(sessionId, fact.category, fact.content, now, now, getHarness());
156802
+ }
156803
+ }
156804
+ function toCompartment(row) {
156805
+ return {
156806
+ id: row.id,
156807
+ sessionId: row.session_id,
156808
+ sequence: row.sequence,
156809
+ startMessage: row.start_message,
156810
+ endMessage: row.end_message,
156811
+ startMessageId: row.start_message_id,
156812
+ endMessageId: row.end_message_id,
156813
+ title: row.title,
156814
+ content: row.content,
156815
+ createdAt: row.created_at
156816
+ };
156817
+ }
156818
+ function toSessionFact(row) {
156819
+ return {
156820
+ id: row.id,
156821
+ sessionId: row.session_id,
156822
+ category: row.category,
156823
+ content: row.content,
156824
+ createdAt: row.created_at,
156825
+ updatedAt: row.updated_at
156826
+ };
156827
+ }
156828
+ function getCompartments(db, sessionId) {
156829
+ const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isCompartmentRow);
156830
+ return rows.map(toCompartment);
156831
+ }
156832
+ function getLastCompartmentEndMessage(db, sessionId) {
156833
+ const row = db.prepare("SELECT MAX(end_message) as max_end FROM compartments WHERE session_id = ?").get(sessionId);
156834
+ return row?.max_end ?? -1;
156835
+ }
156836
+ function appendCompartments(db, sessionId, compartments) {
156837
+ if (compartments.length === 0)
156838
+ return;
156740
156839
  const now = Date.now();
156741
156840
  db.transaction(() => {
156742
- const insertMessage = getInsertMessageStatement(db);
156743
- for (const message of messagesToInsert) {
156744
- insertMessage.run(sessionId, message.ordinal, message.id, message.role, message.content);
156841
+ insertCompartmentRows(db, sessionId, compartments, now);
156842
+ })();
156843
+ }
156844
+ function replaceSessionFacts(db, sessionId, facts) {
156845
+ const now = Date.now();
156846
+ db.transaction(() => {
156847
+ db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
156848
+ insertFactRows(db, sessionId, facts, now);
156849
+ db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
156850
+ })();
156851
+ }
156852
+ function getSessionFacts(db, sessionId) {
156853
+ const rows = db.prepare("SELECT * FROM session_facts WHERE session_id = ? ORDER BY category ASC, id ASC").all(sessionId).filter(isSessionFactRow);
156854
+ return rows.map(toSessionFact);
156855
+ }
156856
+ function replaceAllCompartmentState(db, sessionId, compartments, facts) {
156857
+ const now = Date.now();
156858
+ db.transaction(() => {
156859
+ db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
156860
+ db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
156861
+ insertCompartmentRows(db, sessionId, compartments, now);
156862
+ insertFactRows(db, sessionId, facts, now);
156863
+ db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
156864
+ })();
156865
+ }
156866
+ function buildCompartmentBlock(compartments, facts, memoryBlock, dateRanges) {
156867
+ const lines = [];
156868
+ if (memoryBlock) {
156869
+ lines.push(memoryBlock);
156870
+ lines.push("");
156871
+ }
156872
+ for (const c of compartments) {
156873
+ const dates = dateRanges?.byId.get(c.id);
156874
+ const dateAttr = dates ? ` start-date="${dates.start}" end-date="${dates.end}"` : "";
156875
+ lines.push(`<compartment start="${c.startMessage}" end="${c.endMessage}"${dateAttr} title="${escapeXmlAttr(c.title)}">`);
156876
+ lines.push(escapeXmlContent(c.content));
156877
+ lines.push("</compartment>");
156878
+ lines.push("");
156879
+ }
156880
+ const factsByCategory = new Map;
156881
+ for (const f of facts) {
156882
+ const existing = factsByCategory.get(f.category) ?? [];
156883
+ existing.push(f.content);
156884
+ factsByCategory.set(f.category, existing);
156885
+ }
156886
+ for (const [category, items] of factsByCategory) {
156887
+ lines.push(`${category}:`);
156888
+ for (const item of items) {
156889
+ lines.push(`* ${escapeXmlContent(item)}`);
156890
+ }
156891
+ lines.push("");
156892
+ }
156893
+ return lines.join(`
156894
+ `).trimEnd();
156895
+ }
156896
+ function saveRecompStagingPass(db, sessionId, passNumber, compartments, facts) {
156897
+ const now = Date.now();
156898
+ db.transaction(() => {
156899
+ db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
156900
+ const compartmentStmt = db.prepare("INSERT OR REPLACE INTO recomp_compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, pass_number, created_at, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
156901
+ for (const c of compartments) {
156902
+ compartmentStmt.run(sessionId, c.sequence, c.startMessage, c.endMessage, c.startMessageId, c.endMessageId, c.title, c.content, passNumber, now, getHarness());
156903
+ }
156904
+ const factStmt = db.prepare("INSERT INTO recomp_facts (session_id, category, content, pass_number, created_at, harness) VALUES (?, ?, ?, ?, ?, ?)");
156905
+ for (const f of facts) {
156906
+ factStmt.run(sessionId, f.category, f.content, passNumber, now, getHarness());
156745
156907
  }
156746
- getUpsertIndexStatement(db).run(sessionId, messages.length, now, getHarness());
156747
156908
  })();
156748
156909
  }
156910
+ function getRecompStaging(db, sessionId) {
156911
+ const compartmentRows = db.prepare("SELECT * FROM recomp_compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isRecompCompartmentRow);
156912
+ if (compartmentRows.length === 0)
156913
+ return null;
156914
+ const compartments = compartmentRows.map((row) => ({
156915
+ sequence: row.sequence,
156916
+ startMessage: row.start_message,
156917
+ endMessage: row.end_message,
156918
+ startMessageId: row.start_message_id,
156919
+ endMessageId: row.end_message_id,
156920
+ title: row.title,
156921
+ content: row.content
156922
+ }));
156923
+ const factRows = db.prepare("SELECT category, content FROM recomp_facts WHERE session_id = ?").all(sessionId).filter(isRecompFactRow);
156924
+ const maxPass = compartmentRows.reduce((m, r) => Math.max(m, r.pass_number), 0);
156925
+ const lastEnd = compartmentRows[compartmentRows.length - 1]?.end_message ?? 0;
156926
+ return {
156927
+ compartments,
156928
+ facts: factRows,
156929
+ passCount: maxPass,
156930
+ lastEndMessage: lastEnd
156931
+ };
156932
+ }
156933
+ function promoteRecompStaging(db, sessionId) {
156934
+ const now = Date.now();
156935
+ return db.transaction(() => {
156936
+ const staging = getRecompStaging(db, sessionId);
156937
+ if (!staging || staging.compartments.length === 0)
156938
+ return null;
156939
+ db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
156940
+ db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
156941
+ insertCompartmentRows(db, sessionId, staging.compartments, now);
156942
+ insertFactRows(db, sessionId, staging.facts, now);
156943
+ db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
156944
+ db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
156945
+ db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE session_id = ?").run(sessionId);
156946
+ return { compartments: staging.compartments, facts: staging.facts };
156947
+ })();
156948
+ }
156949
+ function invalidateAllMemoryBlockCaches(db) {
156950
+ try {
156951
+ db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE memory_block_cache != '' OR memory_block_ids != ''").run();
156952
+ } catch {}
156953
+ }
156954
+ function clearRecompStaging(db, sessionId) {
156955
+ db.transaction(() => {
156956
+ db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
156957
+ db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
156958
+ try {
156959
+ db.prepare("UPDATE session_meta SET recomp_partial_range_start = 0, recomp_partial_range_end = 0 WHERE session_id = ?").run(sessionId);
156960
+ } catch {}
156961
+ })();
156962
+ }
156963
+ function getRecompPartialRange(db, sessionId) {
156964
+ try {
156965
+ const row = db.prepare("SELECT recomp_partial_range_start AS start, recomp_partial_range_end AS end FROM session_meta WHERE session_id = ?").get(sessionId);
156966
+ const start = typeof row?.start === "number" ? row.start : 0;
156967
+ const end = typeof row?.end === "number" ? row.end : 0;
156968
+ if (start <= 0 || end <= 0)
156969
+ return null;
156970
+ return { start, end };
156971
+ } catch {
156972
+ return null;
156973
+ }
156974
+ }
156975
+ function setRecompPartialRange(db, sessionId, range) {
156976
+ const start = range ? range.start : 0;
156977
+ const end = range ? range.end : 0;
156978
+ db.prepare("INSERT OR IGNORE INTO session_meta (session_id) VALUES (?)").run(sessionId);
156979
+ db.prepare("UPDATE session_meta SET recomp_partial_range_start = ?, recomp_partial_range_end = ? WHERE session_id = ?").run(start, end, sessionId);
156980
+ }
156981
+ function isRecompCompartmentRow(row) {
156982
+ if (row === null || typeof row !== "object")
156983
+ return false;
156984
+ const candidate = row;
156985
+ return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && typeof candidate.pass_number === "number" && typeof candidate.created_at === "number";
156986
+ }
156987
+ function isRecompFactRow(row) {
156988
+ if (row === null || typeof row !== "object")
156989
+ return false;
156990
+ const candidate = row;
156991
+ return typeof candidate.category === "string" && typeof candidate.content === "string";
156992
+ }
156993
+ function escapeXmlAttr(s) {
156994
+ return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&apos;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
156995
+ }
156996
+ function escapeXmlContent(s) {
156997
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
156998
+ }
156749
156999
  // ../plugin/src/features/magic-context/storage-db.ts
156750
157000
  init_data_path();
156751
- import { copyFileSync, cpSync, existsSync as existsSync2, mkdirSync as mkdirSync3 } from "node:fs";
156752
- import { join as join6 } from "node:path";
157001
+ import { copyFileSync, cpSync, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "node:fs";
157002
+ import { join as join7 } from "node:path";
156753
157003
 
156754
157004
  // ../plugin/src/shared/error-message.ts
156755
157005
  function getErrorMessage(error48) {
@@ -157034,6 +157284,58 @@ var MIGRATIONS = [
157034
157284
  db.exec("ALTER TABLE notes ADD COLUMN harness TEXT NOT NULL DEFAULT 'opencode'");
157035
157285
  }
157036
157286
  }
157287
+ },
157288
+ {
157289
+ version: 8,
157290
+ description: "Add partial indexes on tags(session_id, tag_number) for active and dropped",
157291
+ up: (db) => {
157292
+ db.exec(`
157293
+ CREATE INDEX IF NOT EXISTS idx_tags_active_session_tag_number
157294
+ ON tags(session_id, tag_number)
157295
+ WHERE status = 'active';
157296
+
157297
+ CREATE INDEX IF NOT EXISTS idx_tags_dropped_session_tag_number
157298
+ ON tags(session_id, tag_number)
157299
+ WHERE status = 'dropped';
157300
+ `);
157301
+ db.exec("ANALYZE tags;");
157302
+ }
157303
+ },
157304
+ {
157305
+ version: 9,
157306
+ description: "Persist tool_definition_measurements across plugin restarts",
157307
+ up: (db) => {
157308
+ db.exec(`
157309
+ CREATE TABLE IF NOT EXISTS tool_definition_measurements (
157310
+ provider_id TEXT NOT NULL,
157311
+ model_id TEXT NOT NULL,
157312
+ agent_name TEXT NOT NULL,
157313
+ tool_id TEXT NOT NULL,
157314
+ token_count INTEGER NOT NULL,
157315
+ recorded_at INTEGER NOT NULL,
157316
+ PRIMARY KEY (provider_id, model_id, agent_name, tool_id)
157317
+ );
157318
+ `);
157319
+ }
157320
+ },
157321
+ {
157322
+ version: 10,
157323
+ description: "Add tool_owner_message_id column to tags + composite identity indexes",
157324
+ up: (db) => {
157325
+ const cols = db.prepare("PRAGMA table_info(tags)").all();
157326
+ if (!cols.some((c) => c.name === "tool_owner_message_id")) {
157327
+ db.exec("ALTER TABLE tags ADD COLUMN tool_owner_message_id TEXT DEFAULT NULL");
157328
+ }
157329
+ db.exec(`
157330
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_tags_tool_composite
157331
+ ON tags(session_id, message_id, tool_owner_message_id)
157332
+ WHERE type = 'tool' AND tool_owner_message_id IS NOT NULL;
157333
+
157334
+ CREATE INDEX IF NOT EXISTS idx_tags_tool_null_owner
157335
+ ON tags(session_id, message_id)
157336
+ WHERE type = 'tool' AND tool_owner_message_id IS NULL;
157337
+ `);
157338
+ }
157037
157339
  }
157038
157340
  ];
157039
157341
  function ensureMigrationsTable(db) {
@@ -157049,22 +157351,51 @@ function getCurrentVersion(db) {
157049
157351
  const row = db.prepare("SELECT MAX(version) as version FROM schema_migrations").get();
157050
157352
  return row?.version ?? 0;
157051
157353
  }
157354
+ function isSiblingMigrationConflict(error48, version2) {
157355
+ if (!(error48 instanceof Error))
157356
+ return false;
157357
+ const code = error48.code;
157358
+ if (code !== "SQLITE_CONSTRAINT_PRIMARYKEY" && code !== "SQLITE_CONSTRAINT_UNIQUE") {
157359
+ return false;
157360
+ }
157361
+ const msg = error48.message;
157362
+ if (!msg.includes("schema_migrations"))
157363
+ return false;
157364
+ if (!msg.toLowerCase().includes("version"))
157365
+ return false;
157366
+ return true;
157367
+ }
157052
157368
  function runMigrations(db) {
157053
157369
  ensureMigrationsTable(db);
157054
- const currentVersion = getCurrentVersion(db);
157055
- const pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
157370
+ let currentVersion = getCurrentVersion(db);
157371
+ let pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
157056
157372
  if (pendingMigrations.length === 0) {
157057
157373
  return;
157058
157374
  }
157059
157375
  log(`[migrations] current schema version: ${currentVersion}, applying ${pendingMigrations.length} migration(s)`);
157060
- for (const migration of pendingMigrations) {
157376
+ let migrationIndex = 0;
157377
+ while (migrationIndex < pendingMigrations.length) {
157378
+ const migration = pendingMigrations[migrationIndex];
157061
157379
  try {
157062
157380
  db.transaction(() => {
157063
157381
  migration.up(db);
157064
157382
  db.prepare("INSERT INTO schema_migrations (version, description, applied_at) VALUES (?, ?, ?)").run(migration.version, migration.description, Date.now());
157065
157383
  })();
157066
157384
  log(`[migrations] applied v${migration.version}: ${migration.description}`);
157385
+ migrationIndex += 1;
157067
157386
  } catch (error48) {
157387
+ if (isSiblingMigrationConflict(error48, migration.version)) {
157388
+ log(`[migrations] v${migration.version} already applied by sibling instance — resuming with re-read version`);
157389
+ const reReadVersion = getCurrentVersion(db);
157390
+ if (reReadVersion <= currentVersion) {
157391
+ log(`[migrations] FAILED v${migration.version}: sibling-conflict shape but version not advanced (${reReadVersion} <= ${currentVersion}) — failing closed`);
157392
+ throw new Error(`Migration v${migration.version} failed: sibling conflict reported but version did not advance. Database may need manual repair.`);
157393
+ }
157394
+ currentVersion = reReadVersion;
157395
+ pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
157396
+ migrationIndex = 0;
157397
+ continue;
157398
+ }
157068
157399
  log(`[migrations] FAILED v${migration.version}: ${migration.description} — ${error48 instanceof Error ? error48.message : String(error48)}`);
157069
157400
  throw new Error(`Migration v${migration.version} failed: ${error48 instanceof Error ? error48.message : String(error48)}. Database may need manual repair.`);
157070
157401
  }
@@ -157072,27 +157403,300 @@ function runMigrations(db) {
157072
157403
  log(`[migrations] schema version now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
157073
157404
  }
157074
157405
 
157406
+ // ../plugin/src/features/magic-context/tool-definition-tokens.ts
157407
+ var measurements = new Map;
157408
+ var persistenceDb = null;
157409
+ function keyFor(providerID, modelID, agentName) {
157410
+ const agent = agentName && agentName.length > 0 ? agentName : "default";
157411
+ return `${providerID}/${modelID}/${agent}`;
157412
+ }
157413
+ function setDatabase(db) {
157414
+ persistenceDb = db;
157415
+ }
157416
+ function loadToolDefinitionMeasurements(db) {
157417
+ let rows = [];
157418
+ try {
157419
+ rows = db.prepare("SELECT provider_id, model_id, agent_name, tool_id, token_count FROM tool_definition_measurements").all();
157420
+ } catch {
157421
+ return;
157422
+ }
157423
+ for (const row of rows) {
157424
+ const key = keyFor(row.provider_id, row.model_id, row.agent_name);
157425
+ let inner = measurements.get(key);
157426
+ if (!inner) {
157427
+ inner = new Map;
157428
+ measurements.set(key, inner);
157429
+ }
157430
+ inner.set(row.tool_id, row.token_count);
157431
+ }
157432
+ }
157433
+
157434
+ // ../plugin/src/features/magic-context/tool-owner-backfill.ts
157435
+ init_data_path();
157436
+ init_logger();
157437
+ import { existsSync as existsSync2 } from "node:fs";
157438
+ import { join as join6 } from "node:path";
157439
+ var LEASE_DURATION_MS = 5 * 60 * 1000;
157440
+ var LEASE_RENEWAL_MS = 60 * 1000;
157441
+ function resolveOpencodeDbPath() {
157442
+ return join6(getDataDir(), "opencode", "opencode.db");
157443
+ }
157444
+ function ensureBackfillStateTable(db) {
157445
+ db.exec(`
157446
+ CREATE TABLE IF NOT EXISTS tool_owner_backfill_state (
157447
+ session_id TEXT PRIMARY KEY,
157448
+ status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'skipped')),
157449
+ started_at INTEGER,
157450
+ lease_expires_at INTEGER,
157451
+ completed_at INTEGER,
157452
+ last_error TEXT
157453
+ );
157454
+ CREATE INDEX IF NOT EXISTS idx_tool_owner_backfill_state_status
157455
+ ON tool_owner_backfill_state(status);
157456
+ `);
157457
+ }
157458
+ function runToolOwnerBackfill(db) {
157459
+ const startedAt = performance.now();
157460
+ ensureBackfillStateTable(db);
157461
+ const result = {
157462
+ sessionsProcessed: 0,
157463
+ sessionsSkippedNoOcDb: 0,
157464
+ sessionsSkippedNoMatches: 0,
157465
+ sessionsCompleted: 0,
157466
+ sessionsBlockedByLease: 0,
157467
+ sessionsErrored: 0,
157468
+ rowsUpdated: 0,
157469
+ rowsLeftNull: 0,
157470
+ durationMs: 0
157471
+ };
157472
+ if (!isToolOwnerBackfillNeeded(db)) {
157473
+ result.durationMs = performance.now() - startedAt;
157474
+ return result;
157475
+ }
157476
+ const opencodeDbPath = resolveOpencodeDbPath();
157477
+ if (!existsSync2(opencodeDbPath)) {
157478
+ log(`[backfill] OpenCode DB not found at ${opencodeDbPath} — marking all unbackfilled sessions as skipped. Lazy adoption (defense-in-depth) handles legacy rows at runtime.`);
157479
+ markAllUnbackfilledSessionsSkipped(db);
157480
+ result.sessionsSkippedNoOcDb = countSessionsByStatus(db, "skipped");
157481
+ result.durationMs = performance.now() - startedAt;
157482
+ return result;
157483
+ }
157484
+ db.exec(`ATTACH '${opencodeDbPath}' AS oc_backfill`);
157485
+ try {
157486
+ backfillToolOwnersInChunks(db, result);
157487
+ } finally {
157488
+ try {
157489
+ db.exec("DETACH DATABASE oc_backfill");
157490
+ } catch (error48) {
157491
+ log(`[backfill] failed to detach oc_backfill database: ${error48 instanceof Error ? error48.message : String(error48)}`);
157492
+ }
157493
+ }
157494
+ result.durationMs = performance.now() - startedAt;
157495
+ log(`[backfill] sessions=${result.sessionsProcessed} completed=${result.sessionsCompleted} skipped_no_oc=${result.sessionsSkippedNoOcDb} skipped_no_matches=${result.sessionsSkippedNoMatches} blocked_by_lease=${result.sessionsBlockedByLease} errored=${result.sessionsErrored} rows_updated=${result.rowsUpdated} rows_left_null=${result.rowsLeftNull} duration_ms=${Math.round(result.durationMs)}`);
157496
+ return result;
157497
+ }
157498
+ function isToolOwnerBackfillNeeded(db) {
157499
+ ensureBackfillStateTable(db);
157500
+ const row = db.prepare(`SELECT 1 AS hit
157501
+ FROM tags
157502
+ WHERE type = 'tool' AND tool_owner_message_id IS NULL
157503
+ AND NOT EXISTS (
157504
+ SELECT 1 FROM tool_owner_backfill_state s
157505
+ WHERE s.session_id = tags.session_id
157506
+ AND s.status IN ('completed', 'skipped')
157507
+ )
157508
+ LIMIT 1`).get();
157509
+ return row !== null && row !== undefined;
157510
+ }
157511
+ function markAllUnbackfilledSessionsSkipped(db) {
157512
+ const now = Date.now();
157513
+ db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, started_at, completed_at, last_error)
157514
+ SELECT DISTINCT session_id, 'skipped', NULL, ?, NULL
157515
+ FROM tags
157516
+ WHERE type = 'tool' AND tool_owner_message_id IS NULL
157517
+ ON CONFLICT(session_id) DO UPDATE SET
157518
+ status = 'skipped',
157519
+ completed_at = excluded.completed_at,
157520
+ last_error = NULL
157521
+ WHERE tool_owner_backfill_state.status NOT IN ('completed', 'running')`).run(now);
157522
+ }
157523
+ function countSessionsByStatus(db, status) {
157524
+ const row = db.prepare("SELECT COUNT(*) AS c FROM tool_owner_backfill_state WHERE status = ?").get(status);
157525
+ return row.c;
157526
+ }
157527
+ function acquireSessionLease(db, sessionId, now) {
157528
+ const expiresAt = now + LEASE_DURATION_MS;
157529
+ const result = db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, started_at, lease_expires_at)
157530
+ VALUES (?, 'running', ?, ?)
157531
+ ON CONFLICT(session_id) DO UPDATE SET
157532
+ status = 'running',
157533
+ started_at = excluded.started_at,
157534
+ lease_expires_at = excluded.lease_expires_at,
157535
+ last_error = NULL
157536
+ WHERE tool_owner_backfill_state.status IN ('pending', 'skipped')
157537
+ OR (tool_owner_backfill_state.status = 'running'
157538
+ AND tool_owner_backfill_state.lease_expires_at < ?)`).run(sessionId, now, expiresAt, now);
157539
+ return (result.changes ?? 0) === 1;
157540
+ }
157541
+ function renewSessionLease(db, sessionId, now) {
157542
+ const expiresAt = now + LEASE_DURATION_MS;
157543
+ db.prepare(`UPDATE tool_owner_backfill_state
157544
+ SET lease_expires_at = ?
157545
+ WHERE session_id = ? AND status = 'running'`).run(expiresAt, sessionId);
157546
+ }
157547
+ function markSessionCompleted(db, sessionId, now) {
157548
+ db.prepare(`UPDATE tool_owner_backfill_state
157549
+ SET status = 'completed', completed_at = ?, lease_expires_at = NULL, last_error = NULL
157550
+ WHERE session_id = ?`).run(now, sessionId);
157551
+ }
157552
+ function markSessionSkipped(db, sessionId, now, reason) {
157553
+ db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, completed_at, last_error)
157554
+ VALUES (?, 'skipped', ?, ?)
157555
+ ON CONFLICT(session_id) DO UPDATE SET
157556
+ status = 'skipped',
157557
+ completed_at = excluded.completed_at,
157558
+ last_error = excluded.last_error,
157559
+ lease_expires_at = NULL`).run(sessionId, now, reason);
157560
+ }
157561
+ function markSessionErrored(db, sessionId, error48) {
157562
+ const message = error48 instanceof Error ? error48.message : String(error48);
157563
+ db.prepare(`UPDATE tool_owner_backfill_state
157564
+ SET last_error = ?, lease_expires_at = NULL
157565
+ WHERE session_id = ?`).run(message, sessionId);
157566
+ }
157567
+ function getSessionsNeedingBackfill(db) {
157568
+ const rows = db.prepare(`SELECT DISTINCT t.session_id
157569
+ FROM tags t
157570
+ LEFT JOIN tool_owner_backfill_state s ON s.session_id = t.session_id
157571
+ WHERE t.type = 'tool' AND t.tool_owner_message_id IS NULL
157572
+ AND (s.status IS NULL OR s.status NOT IN ('completed', 'skipped'))
157573
+ ORDER BY t.session_id ASC`).all();
157574
+ return rows.map((r) => r.session_id);
157575
+ }
157576
+ function buildSessionOwnerMap(db, sessionId) {
157577
+ const rows = db.prepare(`SELECT
157578
+ COALESCE(
157579
+ CASE WHEN json_extract(p.data, '$.type') = 'tool_use'
157580
+ THEN json_extract(p.data, '$.id')
157581
+ END,
157582
+ json_extract(p.data, '$.callID')
157583
+ ) AS callid,
157584
+ m.id AS owner_id,
157585
+ m.time_created AS owner_t_created,
157586
+ p.id AS part_id,
157587
+ p.time_created AS part_t_created
157588
+ FROM oc_backfill.message m
157589
+ INNER JOIN oc_backfill.part p ON p.message_id = m.id
157590
+ WHERE m.session_id = ?
157591
+ AND json_extract(m.data, '$.role') = 'assistant'
157592
+ AND (
157593
+ (json_extract(p.data, '$.type') IN ('tool', 'tool-invocation')
157594
+ AND json_extract(p.data, '$.callID') IS NOT NULL)
157595
+ OR (json_extract(p.data, '$.type') = 'tool_use'
157596
+ AND json_extract(p.data, '$.id') IS NOT NULL)
157597
+ )
157598
+ ORDER BY
157599
+ m.time_created ASC,
157600
+ m.id ASC,
157601
+ p.time_created ASC,
157602
+ p.id ASC`).all(sessionId);
157603
+ const oldestByCallId = new Map;
157604
+ for (const r of rows) {
157605
+ if (typeof r.callid !== "string" || r.callid.length === 0)
157606
+ continue;
157607
+ if (!oldestByCallId.has(r.callid)) {
157608
+ oldestByCallId.set(r.callid, r.owner_id);
157609
+ }
157610
+ }
157611
+ return oldestByCallId;
157612
+ }
157613
+ function applyOwnersForSession(db, sessionId, ownersByCallId) {
157614
+ if (ownersByCallId.size === 0) {
157615
+ const leftNull = db.prepare(`SELECT COUNT(*) AS c FROM tags
157616
+ WHERE session_id = ? AND type = 'tool'
157617
+ AND tool_owner_message_id IS NULL`).get(sessionId).c;
157618
+ return { rowsUpdated: 0, rowsLeftNull: leftNull };
157619
+ }
157620
+ const findOrphanStmt = db.prepare(`SELECT id FROM tags
157621
+ WHERE session_id = ? AND message_id = ? AND type = 'tool'
157622
+ AND tool_owner_message_id IS NULL
157623
+ ORDER BY tag_number ASC
157624
+ LIMIT 1`);
157625
+ const updateRowStmt = db.prepare(`UPDATE tags
157626
+ SET tool_owner_message_id = ?
157627
+ WHERE id = ? AND tool_owner_message_id IS NULL`);
157628
+ let rowsUpdated = 0;
157629
+ db.transaction(() => {
157630
+ for (const [callId, ownerId] of ownersByCallId) {
157631
+ const orphan = findOrphanStmt.get(sessionId, callId);
157632
+ if (!orphan)
157633
+ continue;
157634
+ const result = updateRowStmt.run(ownerId, orphan.id);
157635
+ rowsUpdated += result.changes ?? 0;
157636
+ }
157637
+ })();
157638
+ const rowsLeftNull = db.prepare(`SELECT COUNT(*) AS c FROM tags
157639
+ WHERE session_id = ? AND type = 'tool'
157640
+ AND tool_owner_message_id IS NULL`).get(sessionId).c;
157641
+ return { rowsUpdated, rowsLeftNull };
157642
+ }
157643
+ function backfillToolOwnersInChunks(db, result) {
157644
+ const sessionIds = getSessionsNeedingBackfill(db);
157645
+ let lastRenewedAt = Date.now();
157646
+ for (const sessionId of sessionIds) {
157647
+ const now = Date.now();
157648
+ result.sessionsProcessed += 1;
157649
+ const acquired = acquireSessionLease(db, sessionId, now);
157650
+ if (!acquired) {
157651
+ result.sessionsBlockedByLease += 1;
157652
+ continue;
157653
+ }
157654
+ try {
157655
+ const owners = buildSessionOwnerMap(db, sessionId);
157656
+ const { rowsUpdated, rowsLeftNull } = applyOwnersForSession(db, sessionId, owners);
157657
+ result.rowsUpdated += rowsUpdated;
157658
+ result.rowsLeftNull += rowsLeftNull;
157659
+ if (owners.size === 0) {
157660
+ markSessionSkipped(db, sessionId, Date.now(), "no_oc_matches");
157661
+ result.sessionsSkippedNoMatches += 1;
157662
+ } else {
157663
+ markSessionCompleted(db, sessionId, Date.now());
157664
+ result.sessionsCompleted += 1;
157665
+ }
157666
+ } catch (error48) {
157667
+ log(`[backfill] session=${sessionId} errored: ${error48 instanceof Error ? error48.message : String(error48)}`);
157668
+ markSessionErrored(db, sessionId, error48);
157669
+ result.sessionsErrored += 1;
157670
+ }
157671
+ const sinceRenew = Date.now() - lastRenewedAt;
157672
+ if (sinceRenew > LEASE_RENEWAL_MS) {
157673
+ renewSessionLease(db, sessionId, Date.now());
157674
+ lastRenewedAt = Date.now();
157675
+ }
157676
+ }
157677
+ }
157678
+
157075
157679
  // ../plugin/src/features/magic-context/storage-db.ts
157076
157680
  var databases = new Map;
157077
157681
  var persistenceByDatabase = new WeakMap;
157078
157682
  var persistenceErrorByDatabase = new WeakMap;
157079
157683
  function resolveDatabasePath() {
157080
157684
  const dbDir = getMagicContextStorageDir();
157081
- return { dbDir, dbPath: join6(dbDir, "context.db") };
157685
+ return { dbDir, dbPath: join7(dbDir, "context.db") };
157082
157686
  }
157083
157687
  function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
157084
- if (existsSync2(targetDbPath))
157688
+ if (existsSync3(targetDbPath))
157085
157689
  return;
157086
157690
  const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
157087
- const legacyDbPath = join6(legacyDir, "context.db");
157088
- if (!existsSync2(legacyDbPath))
157691
+ const legacyDbPath = join7(legacyDir, "context.db");
157692
+ if (!existsSync3(legacyDbPath))
157089
157693
  return;
157090
157694
  log(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
157091
157695
  mkdirSync3(targetDbDir, { recursive: true });
157092
157696
  for (const suffix of ["", "-wal", "-shm"]) {
157093
157697
  const src = `${legacyDbPath}${suffix}`;
157094
- const dst = join6(targetDbDir, `context.db${suffix}`);
157095
- if (existsSync2(src)) {
157698
+ const dst = join7(targetDbDir, `context.db${suffix}`);
157699
+ if (existsSync3(src)) {
157096
157700
  try {
157097
157701
  copyFileSync(src, dst);
157098
157702
  } catch (error48) {
@@ -157100,9 +157704,9 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
157100
157704
  }
157101
157705
  }
157102
157706
  }
157103
- const legacyModelsDir = join6(legacyDir, "models");
157104
- const targetModelsDir = join6(targetDbDir, "models");
157105
- if (existsSync2(legacyModelsDir) && !existsSync2(targetModelsDir)) {
157707
+ const legacyModelsDir = join7(legacyDir, "models");
157708
+ const targetModelsDir = join7(targetDbDir, "models");
157709
+ if (existsSync3(legacyModelsDir) && !existsSync3(targetModelsDir)) {
157106
157710
  try {
157107
157711
  cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
157108
157712
  } catch (error48) {
@@ -157388,6 +157992,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
157388
157992
  ensureColumn(db, "tags", "tool_name", "TEXT");
157389
157993
  ensureColumn(db, "tags", "input_byte_size", "INTEGER DEFAULT 0");
157390
157994
  ensureColumn(db, "tags", "caveman_depth", "INTEGER DEFAULT 0");
157995
+ ensureColumn(db, "tags", "tool_owner_message_id", "TEXT DEFAULT NULL");
157391
157996
  ensureColumn(db, "session_meta", "system_prompt_tokens", "INTEGER DEFAULT 0");
157392
157997
  ensureColumn(db, "session_meta", "compaction_marker_state", "TEXT DEFAULT ''");
157393
157998
  ensureColumn(db, "session_meta", "key_files", "TEXT DEFAULT ''");
@@ -157486,6 +158091,13 @@ function openDatabase() {
157486
158091
  const db = new Database(dbPath);
157487
158092
  initializeDatabase(db);
157488
158093
  runMigrations(db);
158094
+ try {
158095
+ runToolOwnerBackfill(db);
158096
+ } catch (error48) {
158097
+ log(`[magic-context] tool-owner backfill failed (continuing with lazy adoption fallback): ${getErrorMessage(error48)}`);
158098
+ }
158099
+ setDatabase(db);
158100
+ loadToolDefinitionMeasurements(db);
157489
158101
  databases.set(dbPath, db);
157490
158102
  persistenceByDatabase.set(db, true);
157491
158103
  persistenceErrorByDatabase.delete(db);
@@ -158093,7 +158705,7 @@ var getTagNumberByMessageIdStatements = new WeakMap;
158093
158705
  function getInsertTagStatement(db) {
158094
158706
  let stmt = insertTagStatements.get(db);
158095
158707
  if (!stmt) {
158096
- stmt = db.prepare("INSERT INTO tags (session_id, message_id, type, byte_size, reasoning_byte_size, tag_number, tool_name, input_byte_size, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
158708
+ stmt = db.prepare("INSERT INTO tags (session_id, message_id, type, byte_size, reasoning_byte_size, tag_number, tool_name, input_byte_size, harness, tool_owner_message_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
158097
158709
  insertTagStatements.set(db, stmt);
158098
158710
  }
158099
158711
  return stmt;
@@ -158174,7 +158786,8 @@ function toTagEntry(row) {
158174
158786
  byteSize: row.byte_size,
158175
158787
  reasoningByteSize: row.reasoning_byte_size ?? 0,
158176
158788
  sessionId: row.session_id,
158177
- cavemanDepth: typeof row.caveman_depth === "number" && Number.isFinite(row.caveman_depth) ? row.caveman_depth : 0
158789
+ cavemanDepth: typeof row.caveman_depth === "number" && Number.isFinite(row.caveman_depth) ? row.caveman_depth : 0,
158790
+ toolOwnerMessageId: typeof row.tool_owner_message_id === "string" ? row.tool_owner_message_id : null
158178
158791
  };
158179
158792
  }
158180
158793
  function isTagNumberRow(row) {
@@ -158189,8 +158802,8 @@ function isMaxTagNumberRow(row) {
158189
158802
  const r = row;
158190
158803
  return typeof r.max_tag_number === "number";
158191
158804
  }
158192
- function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0) {
158193
- getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness());
158805
+ function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0, toolOwnerMessageId = null) {
158806
+ getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness(), toolOwnerMessageId);
158194
158807
  return tagNumber;
158195
158808
  }
158196
158809
  function updateTagStatus(db, sessionId, tagId, status) {
@@ -158202,6 +158815,7 @@ function updateTagDropMode(db, sessionId, tagNumber, dropMode) {
158202
158815
  function updateCavemanDepth(db, sessionId, tagNumber, depth) {
158203
158816
  db.prepare("UPDATE tags SET caveman_depth = ? WHERE session_id = ? AND tag_number = ?").run(depth, sessionId, tagNumber);
158204
158817
  }
158818
+ var getOwnerScopedToolTagNumbersStatements = new WeakMap;
158205
158819
  function getMaxTagNumberBySession(db, sessionId) {
158206
158820
  const row = getMaxTagNumberBySessionStatement(db).get(sessionId);
158207
158821
  return isMaxTagNumberRow(row) ? row.max_tag_number : 0;
@@ -158210,17 +158824,103 @@ function getTagNumberByMessageId(db, sessionId, messageId) {
158210
158824
  const row = getTagNumberByMessageIdStatement(db).get(sessionId, messageId);
158211
158825
  return isTagNumberRow(row) ? row.tag_number : null;
158212
158826
  }
158827
+ var TAG_SELECT_COLUMNS = "id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth, tool_owner_message_id";
158213
158828
  function getTagsBySession(db, sessionId) {
158214
- const rows = db.prepare("SELECT id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth FROM tags WHERE session_id = ? ORDER BY tag_number ASC, id ASC").all(sessionId).filter(isTagRow);
158829
+ const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? ORDER BY tag_number ASC, id ASC`).all(sessionId).filter(isTagRow);
158830
+ return rows.map(toTagEntry);
158831
+ }
158832
+ var getActiveTagsBySessionStatements = new WeakMap;
158833
+ var getMaxDroppedTagNumberStatements = new WeakMap;
158834
+ function getActiveTagsBySessionStatement(db) {
158835
+ let stmt = getActiveTagsBySessionStatements.get(db);
158836
+ if (!stmt) {
158837
+ stmt = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND status = 'active' ORDER BY tag_number ASC, id ASC`);
158838
+ getActiveTagsBySessionStatements.set(db, stmt);
158839
+ }
158840
+ return stmt;
158841
+ }
158842
+ function getActiveTagsBySession(db, sessionId) {
158843
+ const rows = getActiveTagsBySessionStatement(db).all(sessionId).filter(isTagRow);
158844
+ return rows.map(toTagEntry);
158845
+ }
158846
+ function getTagsByNumbers(db, sessionId, tagNumbers) {
158847
+ if (tagNumbers.length === 0)
158848
+ return [];
158849
+ if (tagNumbers.length > 900) {
158850
+ const all = [];
158851
+ for (let i = 0;i < tagNumbers.length; i += 900) {
158852
+ all.push(...getTagsByNumbers(db, sessionId, tagNumbers.slice(i, i + 900)));
158853
+ }
158854
+ return all;
158855
+ }
158856
+ const placeholders = tagNumbers.map(() => "?").join(",");
158857
+ const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${placeholders}) ORDER BY tag_number ASC, id ASC`).all(sessionId, ...tagNumbers).filter(isTagRow);
158215
158858
  return rows.map(toTagEntry);
158216
158859
  }
158217
158860
  function getTopNBySize(db, sessionId, n) {
158218
158861
  if (n <= 0) {
158219
158862
  return [];
158220
158863
  }
158221
- const rows = db.prepare("SELECT id, message_id, type, status, drop_mode, tool_name, input_byte_size, byte_size, reasoning_byte_size, session_id, tag_number, caveman_depth FROM tags WHERE session_id = ? AND status = 'active' ORDER BY byte_size DESC, tag_number ASC LIMIT ?").all(sessionId, n).filter(isTagRow);
158864
+ const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND status = 'active' ORDER BY byte_size DESC, tag_number ASC LIMIT ?`).all(sessionId, n).filter(isTagRow);
158222
158865
  return rows.map(toTagEntry);
158223
158866
  }
158867
+ var getToolTagNumberByOwnerStatements = new WeakMap;
158868
+ var getNullOwnerToolTagStatements = new WeakMap;
158869
+ var adoptNullOwnerToolTagStatements = new WeakMap;
158870
+ var deleteToolTagsByOwnerStatements = new WeakMap;
158871
+ function getGetToolTagNumberByOwnerStatement(db) {
158872
+ let stmt = getToolTagNumberByOwnerStatements.get(db);
158873
+ if (!stmt) {
158874
+ stmt = db.prepare(`SELECT tag_number FROM tags
158875
+ WHERE session_id = ? AND message_id = ?
158876
+ AND type = 'tool' AND tool_owner_message_id = ?
158877
+ LIMIT 1`);
158878
+ getToolTagNumberByOwnerStatements.set(db, stmt);
158879
+ }
158880
+ return stmt;
158881
+ }
158882
+ function getToolTagNumberByOwner(db, sessionId, callId, ownerMsgId) {
158883
+ const row = getGetToolTagNumberByOwnerStatement(db).get(sessionId, callId, ownerMsgId);
158884
+ return isTagNumberRow(row) ? row.tag_number : null;
158885
+ }
158886
+ function isNullOwnerToolTagRow(row) {
158887
+ if (row === null || typeof row !== "object")
158888
+ return false;
158889
+ const r = row;
158890
+ return typeof r.id === "number" && typeof r.tag_number === "number";
158891
+ }
158892
+ function getGetNullOwnerToolTagStatement(db) {
158893
+ let stmt = getNullOwnerToolTagStatements.get(db);
158894
+ if (!stmt) {
158895
+ stmt = db.prepare(`SELECT id, tag_number FROM tags
158896
+ WHERE session_id = ? AND message_id = ?
158897
+ AND type = 'tool' AND tool_owner_message_id IS NULL
158898
+ ORDER BY tag_number ASC
158899
+ LIMIT 1`);
158900
+ getNullOwnerToolTagStatements.set(db, stmt);
158901
+ }
158902
+ return stmt;
158903
+ }
158904
+ function getNullOwnerToolTag(db, sessionId, callId) {
158905
+ const row = getGetNullOwnerToolTagStatement(db).get(sessionId, callId);
158906
+ if (!isNullOwnerToolTagRow(row))
158907
+ return null;
158908
+ return { id: row.id, tagNumber: row.tag_number };
158909
+ }
158910
+ function getAdoptNullOwnerToolTagStatement(db) {
158911
+ let stmt = adoptNullOwnerToolTagStatements.get(db);
158912
+ if (!stmt) {
158913
+ stmt = db.prepare(`UPDATE tags
158914
+ SET tool_owner_message_id = ?
158915
+ WHERE id = ? AND tool_owner_message_id IS NULL`);
158916
+ adoptNullOwnerToolTagStatements.set(db, stmt);
158917
+ }
158918
+ return stmt;
158919
+ }
158920
+ function adoptNullOwnerToolTag(db, rowId, ownerMsgId) {
158921
+ const result = getAdoptNullOwnerToolTagStatement(db).run(ownerMsgId, rowId);
158922
+ return (result.changes ?? 0) === 1;
158923
+ }
158224
158924
  // ../plugin/src/agents/historian.ts
158225
158925
  var HISTORIAN_AGENT = "historian";
158226
158926
  var HISTORIAN_EDITOR_AGENT = "historian-editor";
@@ -158278,11 +158978,12 @@ function expandFallbackChain(chain) {
158278
158978
  init_data_path();
158279
158979
  init_logger();
158280
158980
  import { createHash as createHash3 } from "node:crypto";
158281
- import { existsSync as existsSync3, readFileSync } from "node:fs";
158981
+ import { existsSync as existsSync4, readFileSync } from "node:fs";
158282
158982
  import { homedir as homedir2, platform } from "node:os";
158283
- import { join as join7 } from "node:path";
158983
+ import { join as join8 } from "node:path";
158284
158984
  var RELOAD_INTERVAL_MS = 5 * 60 * 1000;
158285
158985
  var apiCache = null;
158986
+ var recentlySeenApiSizes = new Set;
158286
158987
  var fileCache = null;
158287
158988
  var fileLastAttempt = 0;
158288
158989
  function hashFast(input) {
@@ -158295,16 +158996,16 @@ function getModelsJsonPath() {
158295
158996
  const cacheBase = getCacheDir();
158296
158997
  const source = process.env.OPENCODE_MODELS_URL?.trim();
158297
158998
  const filename = source && source !== "https://models.dev" ? `models-${hashFast(source)}.json` : "models.json";
158298
- return join7(cacheBase, "opencode", filename);
158999
+ return join8(cacheBase, "opencode", filename);
158299
159000
  }
158300
159001
  function getOpencodeConfigPath() {
158301
159002
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
158302
- const configDir = envDir ? envDir : platform() === "win32" ? join7(homedir2(), ".config", "opencode") : join7(process.env.XDG_CONFIG_HOME || join7(homedir2(), ".config"), "opencode");
158303
- const jsonc = join7(configDir, "opencode.jsonc");
158304
- if (existsSync3(jsonc))
159003
+ const configDir = envDir ? envDir : platform() === "win32" ? join8(homedir2(), ".config", "opencode") : join8(process.env.XDG_CONFIG_HOME || join8(homedir2(), ".config"), "opencode");
159004
+ const jsonc = join8(configDir, "opencode.jsonc");
159005
+ if (existsSync4(jsonc))
158305
159006
  return jsonc;
158306
- const json2 = join7(configDir, "opencode.json");
158307
- if (existsSync3(json2))
159007
+ const json2 = join8(configDir, "opencode.json");
159008
+ if (existsSync4(json2))
158308
159009
  return json2;
158309
159010
  return null;
158310
159011
  }
@@ -158317,23 +159018,12 @@ function resolveLimit(limit) {
158317
159018
  return limit.context;
158318
159019
  return;
158319
159020
  }
158320
- function resolveInterleavedField(interleaved) {
158321
- if (interleaved && typeof interleaved === "object" && typeof interleaved.field === "string" && interleaved.field.length > 0) {
158322
- return interleaved.field;
158323
- }
158324
- return;
158325
- }
158326
159021
  function setCachedModelMetadata(cache, key, model) {
158327
159022
  const limit = resolveLimit(model?.limit);
158328
- const interleavedField = resolveInterleavedField(model?.capabilities?.interleaved) ?? resolveInterleavedField(model?.interleaved);
158329
- if (limit === undefined && interleavedField === undefined) {
159023
+ if (limit === undefined) {
158330
159024
  return;
158331
159025
  }
158332
- const value = {};
158333
- if (limit !== undefined)
158334
- value.limit = limit;
158335
- if (interleavedField !== undefined)
158336
- value.interleavedField = interleavedField;
159026
+ const value = { limit };
158337
159027
  cache.set(key, value);
158338
159028
  const modes = model?.experimental?.modes;
158339
159029
  if (modes && typeof modes === "object") {
@@ -158347,7 +159037,7 @@ function loadModelsDevMetadataFromFile() {
158347
159037
  const modelsJsonPath = getModelsJsonPath();
158348
159038
  let fileFound = false;
158349
159039
  try {
158350
- if (existsSync3(modelsJsonPath)) {
159040
+ if (existsSync4(modelsJsonPath)) {
158351
159041
  fileFound = true;
158352
159042
  const raw = readFileSync(modelsJsonPath, "utf-8");
158353
159043
  const data = JSON.parse(raw);
@@ -158364,7 +159054,7 @@ function loadModelsDevMetadataFromFile() {
158364
159054
  }
158365
159055
  try {
158366
159056
  const configPath = getOpencodeConfigPath();
158367
- if (configPath && existsSync3(configPath)) {
159057
+ if (configPath && existsSync4(configPath)) {
158368
159058
  let raw = readFileSync(configPath, "utf-8");
158369
159059
  raw = raw.replace(/"(?:[^"\\]|\\.)*"|\/\/.*$/gm, (match) => match.startsWith('"') ? match : "");
158370
159060
  const config2 = JSON.parse(raw);
@@ -158398,22 +159088,6 @@ function getModelsDevContextLimit(providerID, modelID) {
158398
159088
  }
158399
159089
  return fileCache.get(key)?.limit;
158400
159090
  }
158401
- function getModelsDevInterleavedField(providerID, modelID) {
158402
- const key = `${providerID}/${modelID}`;
158403
- if (apiCache) {
158404
- const fromApi = apiCache.get(key)?.interleavedField;
158405
- if (typeof fromApi === "string" && fromApi.length > 0) {
158406
- return fromApi;
158407
- }
158408
- }
158409
- const now = Date.now();
158410
- if (!fileCache || now - fileLastAttempt > RELOAD_INTERVAL_MS) {
158411
- fileLastAttempt = now;
158412
- fileCache = loadModelsDevMetadataFromFile();
158413
- }
158414
- const fromFile = fileCache.get(key)?.interleavedField;
158415
- return typeof fromFile === "string" && fromFile.length > 0 ? fromFile : undefined;
158416
- }
158417
159091
 
158418
159092
  // ../plugin/src/hooks/magic-context/derive-budgets.ts
158419
159093
  var TRIGGER_BUDGET_PERCENTAGE = 0.05;
@@ -158707,7 +159381,7 @@ init_logger();
158707
159381
 
158708
159382
  // src/subagent-runner.ts
158709
159383
  import * as childProcess from "node:child_process";
158710
- import { existsSync as existsSync4 } from "node:fs";
159384
+ import { existsSync as existsSync5 } from "node:fs";
158711
159385
  import { dirname as dirname2, resolve as resolvePath } from "node:path";
158712
159386
  import { createInterface } from "node:readline";
158713
159387
  import { fileURLToPath } from "node:url";
@@ -158715,7 +159389,7 @@ function resolveSubagentEntryPath() {
158715
159389
  try {
158716
159390
  const here = dirname2(fileURLToPath(import.meta.url));
158717
159391
  const candidate = resolvePath(here, "subagent-entry.js");
158718
- if (existsSync4(candidate))
159392
+ if (existsSync5(candidate))
158719
159393
  return candidate;
158720
159394
  return;
158721
159395
  } catch {
@@ -159261,7 +159935,7 @@ function deleteDreamState(db, key) {
159261
159935
  var LEASE_HOLDER_KEY = "dreaming_lease_holder";
159262
159936
  var LEASE_HEARTBEAT_KEY = "dreaming_lease_heartbeat";
159263
159937
  var LEASE_EXPIRY_KEY = "dreaming_lease_expiry";
159264
- var LEASE_DURATION_MS = 2 * 60 * 1000;
159938
+ var LEASE_DURATION_MS2 = 2 * 60 * 1000;
159265
159939
  function getLeaseExpiry(db) {
159266
159940
  const value = getDreamState(db, LEASE_EXPIRY_KEY);
159267
159941
  if (!value) {
@@ -159288,7 +159962,7 @@ function acquireLease(db, holderId) {
159288
159962
  const now = Date.now();
159289
159963
  setDreamState(db, LEASE_HOLDER_KEY, holderId);
159290
159964
  setDreamState(db, LEASE_HEARTBEAT_KEY, String(now));
159291
- setDreamState(db, LEASE_EXPIRY_KEY, String(now + LEASE_DURATION_MS));
159965
+ setDreamState(db, LEASE_EXPIRY_KEY, String(now + LEASE_DURATION_MS2));
159292
159966
  return true;
159293
159967
  })();
159294
159968
  }
@@ -159299,7 +159973,7 @@ function renewLease(db, holderId) {
159299
159973
  }
159300
159974
  const now = Date.now();
159301
159975
  setDreamState(db, LEASE_HEARTBEAT_KEY, String(now));
159302
- setDreamState(db, LEASE_EXPIRY_KEY, String(now + LEASE_DURATION_MS));
159976
+ setDreamState(db, LEASE_EXPIRY_KEY, String(now + LEASE_DURATION_MS2));
159303
159977
  return true;
159304
159978
  })();
159305
159979
  }
@@ -159314,8 +159988,8 @@ function releaseLease(db, holderId) {
159314
159988
  })();
159315
159989
  }
159316
159990
  // ../plugin/src/features/magic-context/dreamer/runner.ts
159317
- import { existsSync as existsSync5 } from "node:fs";
159318
- import { join as join8 } from "node:path";
159991
+ import { existsSync as existsSync6 } from "node:fs";
159992
+ import { join as join9 } from "node:path";
159319
159993
 
159320
159994
  // ../plugin/src/shared/index.ts
159321
159995
  init_logger();
@@ -159446,11 +160120,6 @@ function normalizeSDKResponse(response, fallback, options) {
159446
160120
  }
159447
160121
  return fallback;
159448
160122
  }
159449
- // ../plugin/src/shared/record-type-guard.ts
159450
- function isRecord(value) {
159451
- return typeof value === "object" && value !== null && !Array.isArray(value);
159452
- }
159453
-
159454
160123
  // ../plugin/src/shared/assistant-message-extractor.ts
159455
160124
  function asSessionMessage(value) {
159456
160125
  if (!isRecord(value))
@@ -160713,11 +161382,11 @@ function countNewIds(beforeIds, afterIds) {
160713
161382
  return count;
160714
161383
  }
160715
161384
  function getOpenCodeDbPath2() {
160716
- return join8(getDataDir(), "opencode", "opencode.db");
161385
+ return join9(getDataDir(), "opencode", "opencode.db");
160717
161386
  }
160718
161387
  function openOpenCodeDb() {
160719
161388
  const dbPath = getOpenCodeDbPath2();
160720
- if (!existsSync5(dbPath)) {
161389
+ if (!existsSync6(dbPath)) {
160721
161390
  log(`[key-files] OpenCode DB not found at ${dbPath} — skipping`);
160722
161391
  return null;
160723
161392
  }
@@ -160967,8 +161636,8 @@ async function runDream(args) {
160967
161636
  try {
160968
161637
  const docsDir = args.sessionDirectory ?? args.projectIdentity;
160969
161638
  const existingDocs = taskName === "maintain-docs" ? {
160970
- architecture: existsSync5(join8(docsDir, "ARCHITECTURE.md")),
160971
- structure: existsSync5(join8(docsDir, "STRUCTURE.md"))
161639
+ architecture: existsSync6(join9(docsDir, "ARCHITECTURE.md")),
161640
+ structure: existsSync6(join9(docsDir, "STRUCTURE.md"))
160972
161641
  } : undefined;
160973
161642
  const userMemories = taskName === "archive-stale" ? getActiveUserMemories(args.db).map((um) => ({
160974
161643
  id: um.id,
@@ -162478,14 +163147,46 @@ function createScheduler(config2) {
162478
163147
  }
162479
163148
 
162480
163149
  // ../plugin/src/features/magic-context/tagger.ts
163150
+ var TOOL_COMPOSITE_KEY_SEP = "\x00";
163151
+ function makeToolCompositeKey(ownerMsgId, callId) {
163152
+ return `${ownerMsgId}${TOOL_COMPOSITE_KEY_SEP}${callId}`;
163153
+ }
162481
163154
  var GET_COUNTER_SQL = `SELECT counter FROM session_meta WHERE session_id = ?`;
162482
- var GET_ASSIGNMENTS_SQL = "SELECT message_id, tag_number FROM tags WHERE session_id = ? ORDER BY tag_number ASC";
163155
+ var GET_ASSIGNMENTS_SQL = "SELECT message_id, tag_number, type, tool_owner_message_id FROM tags WHERE session_id = ? ORDER BY tag_number ASC";
163156
+ var PROBE_DATA_VERSION_SQL = "PRAGMA main.data_version";
163157
+ var PROBE_TOTAL_CHANGES_SQL = "SELECT total_changes() AS tc";
163158
+ var probeDataVersionStatements = new WeakMap;
163159
+ var probeTotalChangesStatements = new WeakMap;
163160
+ function getProbeDataVersionStatement(db) {
163161
+ let stmt = probeDataVersionStatements.get(db);
163162
+ if (!stmt) {
163163
+ stmt = db.prepare(PROBE_DATA_VERSION_SQL);
163164
+ probeDataVersionStatements.set(db, stmt);
163165
+ }
163166
+ return stmt;
163167
+ }
163168
+ function getProbeTotalChangesStatement(db) {
163169
+ let stmt = probeTotalChangesStatements.get(db);
163170
+ if (!stmt) {
163171
+ stmt = db.prepare(PROBE_TOTAL_CHANGES_SQL);
163172
+ probeTotalChangesStatements.set(db, stmt);
163173
+ }
163174
+ return stmt;
163175
+ }
162483
163176
  function isAssignmentRow(row) {
162484
163177
  if (row === null || typeof row !== "object") {
162485
163178
  return false;
162486
163179
  }
162487
163180
  const candidate = row;
162488
- return typeof candidate.message_id === "string" && typeof candidate.tag_number === "number";
163181
+ if (typeof candidate.message_id !== "string")
163182
+ return false;
163183
+ if (typeof candidate.tag_number !== "number")
163184
+ return false;
163185
+ if (candidate.type !== "message" && candidate.type !== "tool" && candidate.type !== "file")
163186
+ return false;
163187
+ if (candidate.tool_owner_message_id !== null && typeof candidate.tool_owner_message_id !== "string")
163188
+ return false;
163189
+ return true;
162489
163190
  }
162490
163191
  var UPSERT_COUNTER_SQL = `
162491
163192
  INSERT INTO session_meta (session_id, counter, harness)
@@ -162519,6 +163220,7 @@ var MAX_TAG_ALLOC_RETRIES = 5;
162519
163220
  function createTagger() {
162520
163221
  const counters = new Map;
162521
163222
  const assignments = new Map;
163223
+ const loadSignatures = new Map;
162522
163224
  function getSessionAssignments(sessionId) {
162523
163225
  let map2 = assignments.get(sessionId);
162524
163226
  if (!map2) {
@@ -162537,15 +163239,15 @@ function createTagger() {
162537
163239
  counters.set(sessionId, next);
162538
163240
  getUpsertCounterStatement(db).run(sessionId, next, getHarness());
162539
163241
  }
162540
- function assignTag(sessionId, messageId, type, byteSize2, db, reasoningByteSize = 0, toolName = null, inputByteSize = 0) {
163242
+ function allocateTag(sessionId, messageId, type, byteSize2, db, reasoningByteSize, toolName, inputByteSize, toolOwnerMessageId, mapKey, dbExistingLookup) {
162541
163243
  const sessionAssignments = getSessionAssignments(sessionId);
162542
- const existing = sessionAssignments.get(messageId);
163244
+ const existing = sessionAssignments.get(mapKey);
162543
163245
  if (existing !== undefined) {
162544
163246
  return existing;
162545
163247
  }
162546
- const dbExisting = getTagNumberByMessageId(db, sessionId, messageId);
163248
+ const dbExisting = dbExistingLookup();
162547
163249
  if (dbExisting !== null) {
162548
- sessionAssignments.set(messageId, dbExisting);
163250
+ sessionAssignments.set(mapKey, dbExisting);
162549
163251
  syncCounterAtLeast(sessionId, db, dbExisting);
162550
163252
  return dbExisting;
162551
163253
  }
@@ -162555,16 +163257,16 @@ function createTagger() {
162555
163257
  const next = Math.max(memCounter, dbMax) + 1;
162556
163258
  try {
162557
163259
  db.transaction(() => {
162558
- insertTag(db, sessionId, messageId, type, byteSize2, next, reasoningByteSize, toolName, inputByteSize);
163260
+ insertTag(db, sessionId, messageId, type, byteSize2, next, reasoningByteSize, toolName, inputByteSize, toolOwnerMessageId);
162559
163261
  getUpsertCounterStatement(db).run(sessionId, next, getHarness());
162560
163262
  })();
162561
163263
  } catch (error48) {
162562
163264
  if (!isUniqueConstraintError(error48)) {
162563
163265
  throw error48;
162564
163266
  }
162565
- const racedRow = getTagNumberByMessageId(db, sessionId, messageId);
163267
+ const racedRow = dbExistingLookup();
162566
163268
  if (racedRow !== null) {
162567
- sessionAssignments.set(messageId, racedRow);
163269
+ sessionAssignments.set(mapKey, racedRow);
162568
163270
  syncCounterAtLeast(sessionId, db, racedRow);
162569
163271
  return racedRow;
162570
163272
  }
@@ -162573,51 +163275,124 @@ function createTagger() {
162573
163275
  continue;
162574
163276
  }
162575
163277
  counters.set(sessionId, next);
162576
- sessionAssignments.set(messageId, next);
163278
+ sessionAssignments.set(mapKey, next);
162577
163279
  return next;
162578
163280
  }
162579
- throw new Error(`tagger.assignTag: failed to allocate tag for session=${sessionId} message=${messageId} after ${MAX_TAG_ALLOC_RETRIES} retries`);
163281
+ throw new Error(`tagger.allocateTag: failed to allocate tag for session=${sessionId} key=${mapKey} after ${MAX_TAG_ALLOC_RETRIES} retries`);
162580
163282
  }
162581
- function getTag(sessionId, messageId) {
163283
+ function assignTag(sessionId, messageId, type, byteSize2, db, reasoningByteSize = 0, toolName = null, inputByteSize = 0) {
163284
+ if (type === "tool") {
163285
+ throw new Error("tagger.assignTag: type='tool' is forbidden — use assignToolTag(sessionId, callId, ownerMsgId, ...)");
163286
+ }
163287
+ return allocateTag(sessionId, messageId, type, byteSize2, db, reasoningByteSize, toolName, inputByteSize, null, messageId, () => getTagNumberByMessageId(db, sessionId, messageId));
163288
+ }
163289
+ function assignToolTag(sessionId, callId, ownerMsgId, byteSize2, db, reasoningByteSize = 0, toolName = null, inputByteSize = 0) {
163290
+ const compositeKey = makeToolCompositeKey(ownerMsgId, callId);
163291
+ const sessionAssignments = getSessionAssignments(sessionId);
163292
+ const existing = sessionAssignments.get(compositeKey);
163293
+ if (existing !== undefined) {
163294
+ return existing;
163295
+ }
163296
+ const dbHit = getToolTagNumberByOwner(db, sessionId, callId, ownerMsgId);
163297
+ if (dbHit !== null) {
163298
+ sessionAssignments.set(compositeKey, dbHit);
163299
+ syncCounterAtLeast(sessionId, db, dbHit);
163300
+ return dbHit;
163301
+ }
163302
+ for (let attempt = 0;attempt < MAX_TAG_ALLOC_RETRIES; attempt += 1) {
163303
+ const orphan = getNullOwnerToolTag(db, sessionId, callId);
163304
+ if (orphan === null)
163305
+ break;
163306
+ const claimed = adoptNullOwnerToolTag(db, orphan.id, ownerMsgId);
163307
+ if (claimed) {
163308
+ sessionAssignments.set(compositeKey, orphan.tagNumber);
163309
+ syncCounterAtLeast(sessionId, db, orphan.tagNumber);
163310
+ return orphan.tagNumber;
163311
+ }
163312
+ const recheck = getToolTagNumberByOwner(db, sessionId, callId, ownerMsgId);
163313
+ if (recheck !== null) {
163314
+ sessionAssignments.set(compositeKey, recheck);
163315
+ syncCounterAtLeast(sessionId, db, recheck);
163316
+ return recheck;
163317
+ }
163318
+ }
163319
+ return allocateTag(sessionId, callId, "tool", byteSize2, db, reasoningByteSize, toolName, inputByteSize, ownerMsgId, compositeKey, () => getToolTagNumberByOwner(db, sessionId, callId, ownerMsgId));
163320
+ }
163321
+ function getTag(sessionId, messageId, _type) {
162582
163322
  return assignments.get(sessionId)?.get(messageId);
162583
163323
  }
163324
+ function getToolTag(sessionId, callId, ownerMsgId) {
163325
+ return assignments.get(sessionId)?.get(makeToolCompositeKey(ownerMsgId, callId));
163326
+ }
162584
163327
  function bindTag(sessionId, messageId, tagNumber) {
162585
163328
  getSessionAssignments(sessionId).set(messageId, tagNumber);
162586
163329
  }
163330
+ function bindToolTag(sessionId, callId, ownerMsgId, tagNumber) {
163331
+ getSessionAssignments(sessionId).set(makeToolCompositeKey(ownerMsgId, callId), tagNumber);
163332
+ }
162587
163333
  function getAssignments(sessionId) {
162588
163334
  return getSessionAssignments(sessionId);
162589
163335
  }
162590
163336
  function resetCounter(sessionId, db) {
162591
163337
  counters.set(sessionId, 0);
162592
163338
  assignments.delete(sessionId);
163339
+ loadSignatures.delete(sessionId);
162593
163340
  getResetCounterStatement(db).run(sessionId, getHarness());
162594
163341
  }
162595
163342
  function getCounter(sessionId) {
162596
163343
  return counters.get(sessionId) ?? 0;
162597
163344
  }
163345
+ function probeSignature(db) {
163346
+ const dvRow = getProbeDataVersionStatement(db).get();
163347
+ const tcRow = getProbeTotalChangesStatement(db).get();
163348
+ return {
163349
+ dataVersion: dvRow?.data_version ?? 0,
163350
+ totalChanges: tcRow?.tc ?? 0
163351
+ };
163352
+ }
162598
163353
  function initFromDb(sessionId, db) {
163354
+ const probe = probeSignature(db);
163355
+ const cached2 = loadSignatures.get(sessionId);
163356
+ if (cached2 !== undefined && cached2.db === db && cached2.dataVersion === probe.dataVersion && cached2.totalChanges === probe.totalChanges) {
163357
+ return;
163358
+ }
162599
163359
  const row = db.prepare(GET_COUNTER_SQL).get(sessionId);
162600
163360
  const assignmentRows = db.prepare(GET_ASSIGNMENTS_SQL).all(sessionId).filter(isAssignmentRow);
162601
163361
  const sessionAssignments = getSessionAssignments(sessionId);
162602
163362
  sessionAssignments.clear();
162603
163363
  let maxTagNumber = 0;
162604
163364
  for (const assignment of assignmentRows) {
162605
- sessionAssignments.set(assignment.message_id, assignment.tag_number);
163365
+ if (assignment.type === "tool") {
163366
+ if (assignment.tool_owner_message_id !== null) {
163367
+ sessionAssignments.set(makeToolCompositeKey(assignment.tool_owner_message_id, assignment.message_id), assignment.tag_number);
163368
+ }
163369
+ } else {
163370
+ sessionAssignments.set(assignment.message_id, assignment.tag_number);
163371
+ }
162606
163372
  if (assignment.tag_number > maxTagNumber) {
162607
163373
  maxTagNumber = assignment.tag_number;
162608
163374
  }
162609
163375
  }
162610
163376
  const counter = Math.max(row?.counter ?? 0, maxTagNumber, counters.get(sessionId) ?? 0);
162611
163377
  counters.set(sessionId, counter);
163378
+ loadSignatures.set(sessionId, {
163379
+ db,
163380
+ dataVersion: probe.dataVersion,
163381
+ totalChanges: probe.totalChanges
163382
+ });
162612
163383
  }
162613
163384
  function cleanup(sessionId) {
162614
163385
  counters.delete(sessionId);
162615
163386
  assignments.delete(sessionId);
163387
+ loadSignatures.delete(sessionId);
162616
163388
  }
162617
163389
  return {
162618
163390
  assignTag,
163391
+ assignToolTag,
162619
163392
  getTag,
163393
+ getToolTag,
162620
163394
  bindTag,
163395
+ bindToolTag,
162621
163396
  getAssignments,
162622
163397
  resetCounter,
162623
163398
  getCounter,
@@ -163630,7 +164405,7 @@ function createNudger(config2) {
163630
164405
  }
163631
164406
  const largest = formatLargestTags(topNFn(db, sessionId, 3));
163632
164407
  const protectedCount = config2.protected_tags;
163633
- const activeTags = (preloadedTags ?? getTagsBySession(db, sessionId)).filter((t) => t.status === "active");
164408
+ const activeTags = preloadedTags ? preloadedTags.filter((t) => t.status === "active") : getActiveTagsBySession(db, sessionId);
163634
164409
  const highestProtected = activeTags.map((t) => t.tagNumber).sort((a, b) => b - a).slice(0, protectedCount)[0];
163635
164410
  const protectedHint = highestProtected ? ` Tags §${highestProtected}§ and above are protected (last ${protectedCount}) — You MUST NOT try to reduce those.` : "";
163636
164411
  const oldToolHint = formatOldToolTags(activeTags, protectedCount, 5);
@@ -163721,7 +164496,7 @@ function estimateProjectedPercentage(db, sessionId, contextUsage, preloadedTags)
163721
164496
  if (pendingDrops.length === 0) {
163722
164497
  return null;
163723
164498
  }
163724
- const activeTags = (preloadedTags ?? getTagsBySession(db, sessionId)).filter((t) => t.status === "active");
164499
+ const activeTags = preloadedTags ? preloadedTags.filter((t) => t.status === "active") : getActiveTagsBySession(db, sessionId);
163725
164500
  const totalActiveBytes = activeTags.reduce((sum, t) => sum + t.byteSize, 0);
163726
164501
  if (totalActiveBytes === 0) {
163727
164502
  return null;
@@ -163732,15 +164507,6 @@ function estimateProjectedPercentage(db, sessionId, contextUsage, preloadedTags)
163732
164507
  return contextUsage.percentage * (1 - dropRatio);
163733
164508
  }
163734
164509
 
163735
- // ../plugin/src/hooks/magic-context/reasoning-capability.ts
163736
- function modelRequiresInterleavedReasoning(model) {
163737
- if (!model?.providerID || !model?.modelID) {
163738
- return false;
163739
- }
163740
- const field = getModelsDevInterleavedField(model.providerID, model.modelID);
163741
- return typeof field === "string" && field.length > 0;
163742
- }
163743
-
163744
164510
  // src/context-handler.ts
163745
164511
  init_logger();
163746
164512
 
@@ -163749,107 +164515,105 @@ function tagTranscript(sessionId, transcript, tagger, db, options = {}) {
163749
164515
  const skipPrefixInjection = options.skipPrefixInjection === true;
163750
164516
  const targets = new Map;
163751
164517
  const toolAggregates = new Map;
163752
- db.transaction(() => {
163753
- for (let msgIndex = 0;msgIndex < transcript.messages.length; msgIndex += 1) {
163754
- const message = transcript.messages[msgIndex];
163755
- if (message === undefined)
164518
+ for (let msgIndex = 0;msgIndex < transcript.messages.length; msgIndex += 1) {
164519
+ const message = transcript.messages[msgIndex];
164520
+ if (message === undefined)
164521
+ continue;
164522
+ const messageId = message.info.id;
164523
+ let textOrdinal = 0;
164524
+ for (let partIndex = 0;partIndex < message.parts.length; partIndex += 1) {
164525
+ const part = message.parts[partIndex];
164526
+ if (part === undefined)
163756
164527
  continue;
163757
- const messageId = message.info.id;
163758
- let textOrdinal = 0;
163759
- for (let partIndex = 0;partIndex < message.parts.length; partIndex += 1) {
163760
- const part = message.parts[partIndex];
163761
- if (part === undefined)
164528
+ if (part.kind === "text") {
164529
+ if (messageId === undefined) {
164530
+ textOrdinal += 1;
163762
164531
  continue;
163763
- if (part.kind === "text") {
163764
- if (messageId === undefined) {
163765
- textOrdinal += 1;
163766
- continue;
163767
- }
163768
- tagTextPart({
164532
+ }
164533
+ tagTextPart({
164534
+ sessionId,
164535
+ message,
164536
+ messageId,
164537
+ msgIndex,
164538
+ textOrdinal,
164539
+ part,
164540
+ tagger,
164541
+ db,
164542
+ targets,
164543
+ skipPrefixInjection
164544
+ });
164545
+ textOrdinal += 1;
164546
+ continue;
164547
+ }
164548
+ if (part.kind === "tool_use" || part.kind === "tool_result") {
164549
+ if (messageId === undefined)
164550
+ continue;
164551
+ const callId = part.id;
164552
+ const text = part.getText() ?? "";
164553
+ const meta3 = part.getToolMetadata();
164554
+ if (typeof callId !== "string" || callId.length === 0) {
164555
+ tagToolPart({
163769
164556
  sessionId,
163770
164557
  message,
163771
164558
  messageId,
163772
164559
  msgIndex,
163773
- textOrdinal,
164560
+ partIndex,
163774
164561
  part,
163775
164562
  tagger,
163776
164563
  db,
163777
164564
  targets,
163778
164565
  skipPrefixInjection
163779
164566
  });
163780
- textOrdinal += 1;
163781
164567
  continue;
163782
164568
  }
163783
- if (part.kind === "tool_use" || part.kind === "tool_result") {
163784
- if (messageId === undefined)
163785
- continue;
163786
- const callId = part.id;
163787
- const text = part.getText() ?? "";
163788
- const meta3 = part.getToolMetadata();
163789
- if (typeof callId !== "string" || callId.length === 0) {
163790
- tagToolPart({
163791
- sessionId,
163792
- message,
163793
- messageId,
163794
- msgIndex,
163795
- partIndex,
163796
- part,
163797
- tagger,
163798
- db,
163799
- targets,
163800
- skipPrefixInjection
163801
- });
163802
- continue;
164569
+ const existing = toolAggregates.get(callId);
164570
+ if (existing) {
164571
+ existing.occurrences.push({
164572
+ message,
164573
+ part,
164574
+ kind: part.kind
164575
+ });
164576
+ const newByteSize = byteSize(text);
164577
+ if (newByteSize > existing.maxByteSize) {
164578
+ existing.maxByteSize = newByteSize;
164579
+ updateTagByteSize(db, sessionId, existing.tagId, newByteSize);
163803
164580
  }
163804
- const existing = toolAggregates.get(callId);
163805
- if (existing) {
163806
- existing.occurrences.push({
163807
- message,
163808
- part,
163809
- kind: part.kind
163810
- });
163811
- const newByteSize = byteSize(text);
163812
- if (newByteSize > existing.maxByteSize) {
163813
- existing.maxByteSize = newByteSize;
163814
- updateTagByteSize(db, sessionId, existing.tagId, newByteSize);
163815
- }
163816
- if (existing.toolName === null && meta3.toolName) {
163817
- existing.toolName = meta3.toolName;
163818
- }
163819
- if (existing.inputByteSize === 0 && part.kind === "tool_use" && meta3.inputByteSize > 0) {
163820
- existing.inputByteSize = meta3.inputByteSize;
163821
- updateTagInputByteSize(db, sessionId, existing.tagId, meta3.inputByteSize);
163822
- }
163823
- if (!skipPrefixInjection && part.kind === "tool_result") {
163824
- part.setText(prependTag(existing.tagId, text));
163825
- }
163826
- targets.set(existing.tagId, buildAggregateTarget(existing.tagId, existing.occurrences));
163827
- } else {
163828
- const tagId = tagger.assignTag(sessionId, callId, "tool", byteSize(text), db, 0, meta3.toolName ?? null, meta3.inputByteSize);
163829
- const aggregate = {
163830
- callId,
163831
- tagId,
163832
- occurrences: [
163833
- {
163834
- message,
163835
- part,
163836
- kind: part.kind
163837
- }
163838
- ],
163839
- maxByteSize: byteSize(text),
163840
- toolName: meta3.toolName ?? null,
163841
- inputByteSize: part.kind === "tool_use" ? meta3.inputByteSize : 0
163842
- };
163843
- toolAggregates.set(callId, aggregate);
163844
- if (!skipPrefixInjection && part.kind === "tool_result") {
163845
- part.setText(prependTag(tagId, text));
163846
- }
163847
- targets.set(tagId, buildAggregateTarget(tagId, aggregate.occurrences));
164581
+ if (existing.toolName === null && meta3.toolName) {
164582
+ existing.toolName = meta3.toolName;
164583
+ }
164584
+ if (existing.inputByteSize === 0 && part.kind === "tool_use" && meta3.inputByteSize > 0) {
164585
+ existing.inputByteSize = meta3.inputByteSize;
164586
+ updateTagInputByteSize(db, sessionId, existing.tagId, meta3.inputByteSize);
164587
+ }
164588
+ if (!skipPrefixInjection && part.kind === "tool_result") {
164589
+ part.setText(prependTag(existing.tagId, text));
163848
164590
  }
164591
+ targets.set(existing.tagId, buildAggregateTarget(existing.tagId, existing.occurrences));
164592
+ } else {
164593
+ const tagId = tagger.assignToolTag(sessionId, callId, messageId, byteSize(text), db, 0, meta3.toolName ?? null, meta3.inputByteSize);
164594
+ const aggregate = {
164595
+ callId,
164596
+ tagId,
164597
+ occurrences: [
164598
+ {
164599
+ message,
164600
+ part,
164601
+ kind: part.kind
164602
+ }
164603
+ ],
164604
+ maxByteSize: byteSize(text),
164605
+ toolName: meta3.toolName ?? null,
164606
+ inputByteSize: part.kind === "tool_use" ? meta3.inputByteSize : 0
164607
+ };
164608
+ toolAggregates.set(callId, aggregate);
164609
+ if (!skipPrefixInjection && part.kind === "tool_result") {
164610
+ part.setText(prependTag(tagId, text));
164611
+ }
164612
+ targets.set(tagId, buildAggregateTarget(tagId, aggregate.occurrences));
163849
164613
  }
163850
164614
  }
163851
164615
  }
163852
- })();
164616
+ }
163853
164617
  return { targets };
163854
164618
  }
163855
164619
  function tagTextPart(args) {
@@ -163870,7 +164634,7 @@ function tagToolPart(args) {
163870
164634
  const contentId = stableId ?? `${args.messageId}:t${args.partIndex}`;
163871
164635
  const text = args.part.getText() ?? "";
163872
164636
  const meta3 = args.part.getToolMetadata();
163873
- const tagId = args.tagger.assignTag(args.sessionId, contentId, "tool", byteSize(text), args.db, 0, meta3.toolName ?? null, meta3.inputByteSize);
164637
+ const tagId = args.tagger.assignToolTag(args.sessionId, contentId, contentId, byteSize(text), args.db, 0, meta3.toolName ?? null, meta3.inputByteSize);
163874
164638
  if (!args.skipPrefixInjection && args.part.kind === "tool_result") {
163875
164639
  const tagged = prependTag(tagId, text);
163876
164640
  args.part.setText(tagged);
@@ -164110,11 +164874,7 @@ function getMessageOrdinal(value) {
164110
164874
  }
164111
164875
  async function getSemanticScores(args) {
164112
164876
  const semanticScores = new Map;
164113
- if (!args.embeddingEnabled || !args.isEmbeddingRuntimeEnabled() || args.memories.length === 0) {
164114
- return semanticScores;
164115
- }
164116
- const queryEmbedding = await args.embedQuery(args.query, args.signal);
164117
- if (!queryEmbedding) {
164877
+ if (!args.queryEmbedding || args.memories.length === 0) {
164118
164878
  return semanticScores;
164119
164879
  }
164120
164880
  const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
@@ -164128,7 +164888,7 @@ async function getSemanticScores(args) {
164128
164888
  if (!memoryEmbedding) {
164129
164889
  continue;
164130
164890
  }
164131
- semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(queryEmbedding, memoryEmbedding)));
164891
+ semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
164132
164892
  }
164133
164893
  return semanticScores;
164134
164894
  }
@@ -164224,12 +164984,8 @@ async function searchMemories(args) {
164224
164984
  const semanticScores = await getSemanticScores({
164225
164985
  db: args.db,
164226
164986
  projectPath: args.projectPath,
164227
- query: args.query,
164228
164987
  memories: semanticCandidates,
164229
- embeddingEnabled: args.embeddingEnabled,
164230
- embedQuery: args.embedQuery,
164231
- isEmbeddingRuntimeEnabled: args.isEmbeddingRuntimeEnabled,
164232
- signal: args.signal
164988
+ queryEmbedding: args.queryEmbedding
164233
164989
  });
164234
164990
  return mergeMemoryResults({
164235
164991
  memories,
@@ -164245,7 +165001,6 @@ function linearDecayScore(rank, total) {
164245
165001
  return Math.max(0, 1 - rank / total);
164246
165002
  }
164247
165003
  function searchMessages(args) {
164248
- ensureMessagesIndexed(args.db, args.sessionId, args.readMessages);
164249
165004
  const sanitizedQuery = sanitizeFtsQuery(args.query.trim());
164250
165005
  if (sanitizedQuery.length === 0) {
164251
165006
  return [];
@@ -164316,20 +165071,12 @@ function toGitCommitResult(hit) {
164316
165071
  matchType: hit.matchType
164317
165072
  };
164318
165073
  }
164319
- async function searchGitCommitsAsync(args) {
165074
+ function searchGitCommits(args) {
164320
165075
  if (args.limit <= 0)
164321
165076
  return [];
164322
- let queryEmbedding = null;
164323
- if (args.embeddingEnabled && args.isEmbeddingRuntimeEnabled()) {
164324
- try {
164325
- queryEmbedding = await args.embedQuery(args.query, args.signal);
164326
- } catch (error48) {
164327
- log(`[search] git commit query embedding failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
164328
- }
164329
- }
164330
165077
  const hits = searchGitCommitsSync(args.db, args.projectPath, args.query, {
164331
165078
  limit: args.limit,
164332
- queryEmbedding
165079
+ queryEmbedding: args.queryEmbedding
164333
165080
  });
164334
165081
  return hits.map(toGitCommitResult);
164335
165082
  }
@@ -164360,37 +165107,37 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
164360
165107
  const runMemory = activeSources.has("memory") && (options.memoryEnabled ?? true);
164361
165108
  const runMessages = activeSources.has("message");
164362
165109
  const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
164363
- const [memoryResults, messageResults, gitCommitResults] = await Promise.all([
165110
+ const needsEmbedding = (runMemory || runGitCommits) && embeddingEnabled && isEmbeddingRuntimeEnabled();
165111
+ const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error48) => {
165112
+ log(`[search] query embedding failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
165113
+ return null;
165114
+ }) : Promise.resolve(null);
165115
+ await Promise.resolve();
165116
+ const messageResults = runMessages ? searchMessages({
165117
+ db,
165118
+ sessionId,
165119
+ query: trimmedQuery,
165120
+ limit: tierLimit,
165121
+ maxOrdinal: options.maxMessageOrdinal
165122
+ }) : [];
165123
+ const queryEmbedding = await queryEmbeddingPromise;
165124
+ const [memoryResults, gitCommitResults] = await Promise.all([
164364
165125
  runMemory ? searchMemories({
164365
165126
  db,
164366
165127
  projectPath,
164367
165128
  query: trimmedQuery,
164368
165129
  limit: tierLimit,
164369
165130
  memoryEnabled: true,
164370
- embeddingEnabled,
164371
- embedQuery,
164372
- isEmbeddingRuntimeEnabled,
164373
- visibleMemoryIds: options.visibleMemoryIds,
164374
- signal: options.signal
165131
+ queryEmbedding,
165132
+ visibleMemoryIds: options.visibleMemoryIds
164375
165133
  }) : Promise.resolve([]),
164376
- runMessages ? Promise.resolve(searchMessages({
164377
- db,
164378
- sessionId,
164379
- query: trimmedQuery,
164380
- limit: tierLimit,
164381
- readMessages: options.readMessages ?? readRawSessionMessages,
164382
- maxOrdinal: options.maxMessageOrdinal
164383
- })) : Promise.resolve([]),
164384
- runGitCommits ? searchGitCommitsAsync({
165134
+ runGitCommits ? Promise.resolve(searchGitCommits({
164385
165135
  db,
164386
165136
  projectPath,
164387
165137
  query: trimmedQuery,
164388
165138
  limit: tierLimit,
164389
- embeddingEnabled,
164390
- embedQuery,
164391
- isEmbeddingRuntimeEnabled,
164392
- signal: options.signal
164393
- }) : Promise.resolve([])
165139
+ queryEmbedding
165140
+ })) : Promise.resolve([])
164394
165141
  ]);
164395
165142
  const results = [...memoryResults, ...messageResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
164396
165143
  const countRetrievals = options.countRetrievals ?? true;
@@ -164807,8 +165554,8 @@ function collectStaleReduceCallIds(messages, messageIdToMaxTag, toolAgeCutoff) {
164807
165554
  return staleCallIds;
164808
165555
  }
164809
165556
  function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config2, preloadedTags) {
164810
- const tags = preloadedTags ?? getTagsBySession(db, sessionId);
164811
- const maxTag = tags.reduce((max, t) => Math.max(max, t.tagNumber), 0);
165557
+ const tags = preloadedTags ?? getActiveTagsBySession(db, sessionId);
165558
+ const maxTag = getMaxTagNumberBySession(db, sessionId);
164812
165559
  const toolAgeCutoff = maxTag - config2.autoDropToolAge;
164813
165560
  const protectedCutoff = maxTag - config2.protectedTags;
164814
165561
  let droppedTools = 0;
@@ -165921,12 +166668,24 @@ function clearPiCompressorState(sessionId) {
165921
166668
  init_logger();
165922
166669
  function queueDropsForCompartmentalizedMessages(db, sessionId, upToMessageIndex) {
165923
166670
  const tags = getTagsBySession(db, sessionId);
165924
- const rawTagKeys = new Set(getRawSessionTagKeysThrough(sessionId, upToMessageIndex));
166671
+ const { messageFileKeys, toolObservations } = getRawSessionTagKeysThrough(sessionId, upToMessageIndex);
165925
166672
  let dropsQueued = 0;
165926
166673
  for (const tag of tags) {
165927
166674
  if (tag.status !== "active")
165928
166675
  continue;
165929
- if (rawTagKeys.has(tag.messageId)) {
166676
+ if (tag.type === "tool") {
166677
+ const observedOwners = toolObservations.get(tag.messageId);
166678
+ if (!observedOwners)
166679
+ continue;
166680
+ if (tag.toolOwnerMessageId !== null) {
166681
+ if (!observedOwners.has(tag.toolOwnerMessageId))
166682
+ continue;
166683
+ }
166684
+ queuePendingOp(db, sessionId, tag.tagNumber, "drop");
166685
+ dropsQueued += 1;
166686
+ continue;
166687
+ }
166688
+ if (messageFileKeys.has(tag.messageId)) {
165930
166689
  queuePendingOp(db, sessionId, tag.tagNumber, "drop");
165931
166690
  dropsQueued += 1;
165932
166691
  }
@@ -166134,15 +166893,15 @@ function getReducedRecompTokenBudget(currentBudget) {
166134
166893
  // ../plugin/src/hooks/magic-context/historian-state-file.ts
166135
166894
  import { mkdirSync as mkdirSync4, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
166136
166895
  import { tmpdir as tmpdir2 } from "node:os";
166137
- import { join as join9 } from "node:path";
166896
+ import { join as join10 } from "node:path";
166138
166897
  var HISTORIAN_STATE_INLINE_THRESHOLD = 30000;
166139
- var HISTORIAN_STATE_DIR = join9(tmpdir2(), "magic-context-historian");
166898
+ var HISTORIAN_STATE_DIR = join10(tmpdir2(), "magic-context-historian");
166140
166899
  function maybeWriteHistorianStateFile(sessionId, existingState) {
166141
166900
  if (existingState.length <= HISTORIAN_STATE_INLINE_THRESHOLD)
166142
166901
  return;
166143
166902
  try {
166144
166903
  mkdirSync4(HISTORIAN_STATE_DIR, { recursive: true });
166145
- const path5 = join9(HISTORIAN_STATE_DIR, `state-${sessionId}-${Date.now()}.xml`);
166904
+ const path5 = join10(HISTORIAN_STATE_DIR, `state-${sessionId}-${Date.now()}.xml`);
166146
166905
  writeFileSync2(path5, existingState, "utf8");
166147
166906
  return path5;
166148
166907
  } catch {
@@ -166252,24 +167011,12 @@ ${chunk.text}`, { stateFilePath });
166252
167011
  const maxExistingSequence = priorCompartments.reduce((max, c) => c.sequence > max ? c.sequence : max, -1);
166253
167012
  const sequenceOffset = priorCompartments.length === 0 ? 0 : maxExistingSequence + 1;
166254
167013
  sessionLog(sessionId, `pi-historian: invoking subagent (model=${historianModel}, chunk=${chunk.startIndex}-${chunk.endIndex}, ${chunk.messageCount} msgs, ~${chunk.tokenEstimate} tokens)`);
167014
+ const traceRawEvents = process.env.MC_PI_HISTORIAN_TRACE === "1";
166255
167015
  const buildProgressLogger = (passLabel) => {
166256
167016
  return (event) => {
166257
167017
  try {
166258
- if (event.type === "raw_event") {
166259
- let serialized;
166260
- try {
166261
- serialized = JSON.stringify(event.event);
166262
- } catch {
166263
- serialized = "[unserializable]";
166264
- }
166265
- if (serialized.length > 4000) {
166266
- serialized = `${serialized.slice(0, 4000)}…[truncated ${serialized.length - 4000} chars]`;
166267
- }
166268
- sessionLog(sessionId, `pi-historian[${passLabel}] raw_event @${event.ms}ms type=${event.eventType ?? "?"}: ${serialized}`);
166269
- } else if (event.type === "spawned") {
167018
+ if (event.type === "spawned") {
166270
167019
  sessionLog(sessionId, `pi-historian[${passLabel}] spawned pid=${event.pid ?? "?"} argv=${event.argv.length} args`);
166271
- } else if (event.type === "first_event") {
166272
- sessionLog(sessionId, `pi-historian[${passLabel}] first_event @${event.ms}ms type=${event.eventType}`);
166273
167020
  } else if (event.type === "terminal") {
166274
167021
  sessionLog(sessionId, `pi-historian[${passLabel}] terminal @${event.ms}ms stopReason=${event.stopReason ?? "?"} textLen=${event.textLength} hasToolCall=${event.hasToolCall}`);
166275
167022
  } else if (event.type === "stderr") {
@@ -166279,6 +167026,21 @@ ${chunk.text}`, { stateFilePath });
166279
167026
  }
166280
167027
  } else if (event.type === "child_exit") {
166281
167028
  sessionLog(sessionId, `pi-historian[${passLabel}] child_exit @${event.ms}ms code=${event.code} signal=${event.signal}`);
167029
+ } else if (traceRawEvents) {
167030
+ if (event.type === "raw_event") {
167031
+ let serialized;
167032
+ try {
167033
+ serialized = JSON.stringify(event.event);
167034
+ } catch {
167035
+ serialized = "[unserializable]";
167036
+ }
167037
+ if (serialized.length > 4000) {
167038
+ serialized = `${serialized.slice(0, 4000)}…[truncated ${serialized.length - 4000} chars]`;
167039
+ }
167040
+ sessionLog(sessionId, `pi-historian[${passLabel}] raw_event @${event.ms}ms type=${event.eventType ?? "?"}: ${serialized}`);
167041
+ } else if (event.type === "first_event") {
167042
+ sessionLog(sessionId, `pi-historian[${passLabel}] first_event @${event.ms}ms type=${event.eventType}`);
167043
+ }
166282
167044
  }
166283
167045
  } catch {}
166284
167046
  };
@@ -166693,16 +167455,7 @@ function clearOldReasoningPi(args) {
166693
167455
  return { cleared, newWatermark };
166694
167456
  }
166695
167457
  function replayClearedReasoningPi(args) {
166696
- const {
166697
- db,
166698
- sessionId,
166699
- messages,
166700
- messageIdToMaxTag,
166701
- piMessageStableId,
166702
- skipTypedReasoningCleanup
166703
- } = args;
166704
- if (skipTypedReasoningCleanup)
166705
- return 0;
167458
+ const { db, sessionId, messages, messageIdToMaxTag, piMessageStableId } = args;
166706
167459
  const meta3 = getOrCreateSessionMeta(db, sessionId);
166707
167460
  const watermark = meta3.clearedReasoningThroughTag ?? 0;
166708
167461
  if (watermark <= 0)
@@ -167402,19 +168155,6 @@ var TOOL_HEAVY_TURN_REMINDER_THRESHOLD = 5;
167402
168155
  var TOOL_HEAVY_TURN_REMINDER_TEXT = `
167403
168156
 
167404
168157
  <instruction name="ctx_reduce_turn_cleanup">Also drop via \`ctx_reduce\` things you don't need anymore from the last turn before continuing.</instruction>`;
167405
- function resolveLiveModelId(ctx) {
167406
- const model = ctx.model;
167407
- if (!model)
167408
- return;
167409
- const providerID = model.provider;
167410
- const modelID = model.id;
167411
- if (typeof providerID !== "string" || typeof modelID !== "string") {
167412
- return;
167413
- }
167414
- if (providerID.length === 0 || modelID.length === 0)
167415
- return;
167416
- return { providerID, modelID };
167417
- }
167418
168158
  var DEFAULT_CLEAR_REASONING_AGE = 50;
167419
168159
  var lastEmergencyNotificationAtMs = new Map;
167420
168160
  var EMERGENCY_NOTIFICATION_COOLDOWN_MS = 60000;
@@ -167427,6 +168167,9 @@ var recentReduceBySession = new Map;
167427
168167
  var liveModelBySession = new Map;
167428
168168
  var toolUsageSinceUserTurn = new Map;
167429
168169
  var latestUserMessageBySession = new Map;
168170
+ function readPiSessionMessageById(ctx, messageId) {
168171
+ return readPiSessionMessages(ctx).find((message) => message.id === messageId) ?? null;
168172
+ }
167430
168173
  function signalPiHistoryRefresh(sessionId) {
167431
168174
  historyRefreshSessions.add(sessionId);
167432
168175
  }
@@ -167627,8 +168370,15 @@ function registerPiContextHandler(pi, options) {
167627
168370
  return;
167628
168371
  }
167629
168372
  sessionIdForError = sessionId;
168373
+ const rawMessageProvider = {
168374
+ readMessages: () => readPiSessionMessages(ctx),
168375
+ readMessageById: (messageId) => readPiSessionMessageById(ctx, messageId)
168376
+ };
168377
+ setRawMessageProvider(sessionId, rawMessageProvider);
168378
+ scheduleReconciliation(options.db, sessionId, readRawSessionMessages);
167630
168379
  const latestUserId = findLatestUserMessageIdPi(event.messages);
167631
168380
  if (latestUserId) {
168381
+ scheduleIncrementalIndex(options.db, sessionId, latestUserId, (_sessionId, messageId) => readPiSessionMessageById(ctx, messageId));
167632
168382
  const previousUserId = latestUserMessageBySession.get(sessionId);
167633
168383
  if (previousUserId !== latestUserId) {
167634
168384
  onPiNewUserMessage({ db: options.db, sessionId });
@@ -167691,8 +168441,6 @@ function registerPiContextHandler(pi, options) {
167691
168441
  }
167692
168442
  const isCacheBusting = historyRefreshSessions.has(sessionId);
167693
168443
  sessionLog(sessionId, `pi transform: usage=${usagePercentage.toFixed(1)}% (${usageInputTokens} tokens, limit=${usageContextLimit ?? "?"}) decision=${schedulerDecision}${forceMaterialization ? " force=true" : ""}${isEmergency ? " EMERGENCY=true" : ""}${isCacheBusting ? " busting=true" : ""}`);
167694
- const liveModelId = resolveLiveModelId(ctx);
167695
- const skipTypedReasoningCleanup = liveModelId ? modelRequiresInterleavedReasoning(liveModelId) : false;
167696
168444
  const entryIds = collectMessageEntryIds(ctx, event.messages.length, sessionId);
167697
168445
  const result = await runPipeline({
167698
168446
  db: options.db,
@@ -167709,8 +168457,7 @@ function registerPiContextHandler(pi, options) {
167709
168457
  forceMaterialization: forceMaterialization || isEmergency,
167710
168458
  isCacheBusting,
167711
168459
  reasoningClearing: {
167712
- clearReasoningAge: options.heuristics?.clearReasoningAge ?? DEFAULT_CLEAR_REASONING_AGE,
167713
- skipTypedReasoningCleanup
168460
+ clearReasoningAge: options.heuristics?.clearReasoningAge ?? DEFAULT_CLEAR_REASONING_AGE
167714
168461
  },
167715
168462
  temporalAwareness: options.injection?.temporalAwareness === true
167716
168463
  });
@@ -168058,7 +168805,10 @@ async function runPipeline(args) {
168058
168805
  consumePendingMaterialization(args.sessionId);
168059
168806
  }
168060
168807
  }
168061
- applyFlushedStatuses(args.sessionId, args.db, targets);
168808
+ const flushedSliceTags = getTagsByNumbers(args.db, args.sessionId, [
168809
+ ...targets.keys()
168810
+ ]);
168811
+ applyFlushedStatuses(args.sessionId, args.db, targets, flushedSliceTags);
168062
168812
  const messageIdToMaxTag = buildMessageIdToMaxTag(targets);
168063
168813
  if (args.reasoningClearing) {
168064
168814
  try {
@@ -168067,8 +168817,7 @@ async function runPipeline(args) {
168067
168817
  sessionId: args.sessionId,
168068
168818
  messages: args.messages,
168069
168819
  messageIdToMaxTag,
168070
- piMessageStableId,
168071
- skipTypedReasoningCleanup: args.reasoningClearing.skipTypedReasoningCleanup
168820
+ piMessageStableId
168072
168821
  });
168073
168822
  const inlineReplay = replayStrippedInlineThinkingPi({
168074
168823
  db: args.db,
@@ -168085,7 +168834,8 @@ async function runPipeline(args) {
168085
168834
  }
168086
168835
  }
168087
168836
  try {
168088
- const tags = getTagsBySession(args.db, args.sessionId);
168837
+ const targetTagNumbers = [...targets.keys()];
168838
+ const tags = getTagsByNumbers(args.db, args.sessionId, targetTagNumbers);
168089
168839
  const replayed = replayCavemanCompression(args.sessionId, args.db, targets, tags);
168090
168840
  if (replayed > 0) {
168091
168841
  sessionLog(args.sessionId, `pi caveman replay: ${replayed} tags re-compressed from source`);
@@ -168110,7 +168860,7 @@ async function runPipeline(args) {
168110
168860
  sessionLog(args.sessionId, `pi heuristic cleanup failed (continuing): ${err instanceof Error ? err.message : String(err)}`);
168111
168861
  }
168112
168862
  }
168113
- if (args.reasoningClearing && !args.reasoningClearing.skipTypedReasoningCleanup && (args.schedulerDecision === "execute" || args.forceMaterialization === true)) {
168863
+ if (args.reasoningClearing && (args.schedulerDecision === "execute" || args.forceMaterialization === true)) {
168114
168864
  try {
168115
168865
  const clearOutcome = clearOldReasoningPi({
168116
168866
  messages: args.messages,
@@ -168179,7 +168929,7 @@ function applyRollingNudge(args) {
168179
168929
  inputTokens: piUsage.tokens,
168180
168930
  contextLimit: piUsage.contextWindow
168181
168931
  };
168182
- const tags = getTagsBySession(db, sessionId);
168932
+ const tags = getActiveTagsBySession(db, sessionId);
168183
168933
  const messagesSinceLastUser = countMessagesSinceLastUserPi(messages);
168184
168934
  const nudge = nudgerFn(sessionId, usage, db, getTopNBySize, tags, messagesSinceLastUser, undefined);
168185
168935
  if (!nudge)
@@ -168309,6 +169059,7 @@ function clearContextHandlerSession(sessionId) {
168309
169059
  liveModelBySession.delete(sessionId);
168310
169060
  toolUsageSinceUserTurn.delete(sessionId);
168311
169061
  latestUserMessageBySession.delete(sessionId);
169062
+ clearSessionTracking(sessionId);
168312
169063
  clearPiCompressorState(sessionId);
168313
169064
  }
168314
169065
 
@@ -168358,7 +169109,7 @@ init_logger();
168358
169109
  init_data_path();
168359
169110
  init_logger();
168360
169111
  await init_sqlite();
168361
- import { join as join10 } from "node:path";
169112
+ import { join as join11 } from "node:path";
168362
169113
  var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
168363
169114
  function randomBase62(length) {
168364
169115
  const chars = [];
@@ -168379,7 +169130,7 @@ function generatePartId(timestampMs, counter = 0n) {
168379
169130
  return generateId("prt", timestampMs, counter);
168380
169131
  }
168381
169132
  function getOpenCodeDbPath3() {
168382
- return join10(getDataDir(), "opencode", "opencode.db");
169133
+ return join11(getDataDir(), "opencode", "opencode.db");
168383
169134
  }
168384
169135
  var cachedWriteDb = null;
168385
169136
  var REQUIRED_MESSAGE_COLUMNS = ["id", "session_id", "time_created", "time_updated", "data"];
@@ -168934,9 +169685,9 @@ async function runCompressorPass2(args) {
168934
169685
  // ../plugin/src/hooks/magic-context/compartment-runner-historian.ts
168935
169686
  import { mkdirSync as mkdirSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
168936
169687
  import { tmpdir as tmpdir3 } from "node:os";
168937
- import { join as join11 } from "node:path";
169688
+ import { join as join12 } from "node:path";
168938
169689
  init_magic_context();
168939
- var HISTORIAN_RESPONSE_DUMP_DIR = join11(tmpdir3(), "magic-context-historian");
169690
+ var HISTORIAN_RESPONSE_DUMP_DIR = join12(tmpdir3(), "magic-context-historian");
168940
169691
  var MAX_HISTORIAN_RETRIES = 2;
168941
169692
  async function runValidatedHistorianPass(args) {
168942
169693
  const firstRun = await runHistorianPrompt({
@@ -169180,7 +169931,7 @@ function dumpHistorianResponse(sessionId, label, text) {
169180
169931
  mkdirSync5(HISTORIAN_RESPONSE_DUMP_DIR, { recursive: true });
169181
169932
  const safeSessionId = sanitizeDumpName(sessionId);
169182
169933
  const safeLabel = sanitizeDumpName(label);
169183
- const dumpPath = join11(HISTORIAN_RESPONSE_DUMP_DIR, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
169934
+ const dumpPath = join12(HISTORIAN_RESPONSE_DUMP_DIR, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
169184
169935
  writeFileSync3(dumpPath, text, "utf8");
169185
169936
  sessionLog(sessionId, "compartment agent: historian response dumped", {
169186
169937
  label,
@@ -170348,7 +171099,7 @@ import {
170348
171099
  // package.json
170349
171100
  var package_default = {
170350
171101
  name: "@cortexkit/pi-magic-context",
170351
- version: "0.16.3",
171102
+ version: "0.17.0",
170352
171103
  type: "module",
170353
171104
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
170354
171105
  main: "dist/index.js",
@@ -170885,12 +171636,12 @@ function readHistorianState(db, sessionId, meta3) {
170885
171636
 
170886
171637
  // src/config/index.ts
170887
171638
  init_magic_context();
170888
- import { existsSync as existsSync7, readFileSync as readFileSync3 } from "node:fs";
171639
+ import { existsSync as existsSync8, readFileSync as readFileSync3 } from "node:fs";
170889
171640
  import { homedir as homedir4 } from "node:os";
170890
- import { join as join12 } from "node:path";
171641
+ import { join as join13 } from "node:path";
170891
171642
 
170892
171643
  // ../plugin/src/config/variable.ts
170893
- import { existsSync as existsSync6, readFileSync as readFileSync2 } from "node:fs";
171644
+ import { existsSync as existsSync7, readFileSync as readFileSync2 } from "node:fs";
170894
171645
  import { homedir as homedir3 } from "node:os";
170895
171646
  import { dirname as dirname3, isAbsolute, resolve } from "node:path";
170896
171647
  var ENV_PATTERN = /\{env:([^}]+)\}/g;
@@ -170933,7 +171684,7 @@ function substituteConfigVariables(input) {
170933
171684
  } else if (!isAbsolute(filePath)) {
170934
171685
  filePath = resolve(configDir, filePath);
170935
171686
  }
170936
- if (!existsSync6(filePath)) {
171687
+ if (!existsSync7(filePath)) {
170937
171688
  warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
170938
171689
  continue;
170939
171690
  }
@@ -170955,16 +171706,16 @@ function substituteConfigVariables(input) {
170955
171706
  var import_comment_json = __toESM(require_src2(), 1);
170956
171707
  var CONFIG_FILE_NAME = "magic-context";
170957
171708
  function getProjectConfigPaths(cwd) {
170958
- const basePath = join12(cwd, ".pi", CONFIG_FILE_NAME);
171709
+ const basePath = join13(cwd, ".pi", CONFIG_FILE_NAME);
170959
171710
  return [`${basePath}.jsonc`, `${basePath}.json`];
170960
171711
  }
170961
171712
  function getUserConfigPaths() {
170962
171713
  const home = process.env.HOME ?? homedir4();
170963
- const basePath = join12(home, ".pi", "agent", CONFIG_FILE_NAME);
171714
+ const basePath = join13(home, ".pi", "agent", CONFIG_FILE_NAME);
170964
171715
  return [`${basePath}.jsonc`, `${basePath}.json`];
170965
171716
  }
170966
171717
  function resolveFirstExisting(paths) {
170967
- return paths.find((path5) => existsSync7(path5));
171718
+ return paths.find((path5) => existsSync8(path5));
170968
171719
  }
170969
171720
  function loadConfigFile(path5, scope) {
170970
171721
  try {
@@ -171116,8 +171867,8 @@ function stripTagPrefixFromAssistantMessage(message) {
171116
171867
 
171117
171868
  // src/system-prompt.ts
171118
171869
  import { createHash as createHash4 } from "node:crypto";
171119
- import { existsSync as existsSync8, readFileSync as readFileSync4, realpathSync } from "node:fs";
171120
- import { join as join13, resolve as resolve2, sep } from "node:path";
171870
+ import { existsSync as existsSync9, readFileSync as readFileSync4, realpathSync } from "node:fs";
171871
+ import { join as join14, resolve as resolve2, sep } from "node:path";
171121
171872
 
171122
171873
  // ../plugin/src/agents/magic-context-prompt.ts
171123
171874
  function getToolHistoryGuidance(dropToolStructure) {
@@ -171219,9 +171970,9 @@ var DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
171219
171970
  function readProjectDocs(directory) {
171220
171971
  const sections = [];
171221
171972
  for (const filename of DOC_FILES) {
171222
- const filePath = join13(directory, filename);
171973
+ const filePath = join14(directory, filename);
171223
171974
  try {
171224
- if (existsSync8(filePath)) {
171975
+ if (existsSync9(filePath)) {
171225
171976
  const content = readFileSync4(filePath, "utf-8").trim();
171226
171977
  if (content.length > 0) {
171227
171978
  sections.push(`<${filename}>
@@ -171265,7 +172016,7 @@ function buildKeyFilesBlock(db, sessionId, directory, tokenBudget) {
171265
172016
  log(`[magic-context-pi] key file path escapes project root, skipping: ${entry.filePath}`);
171266
172017
  continue;
171267
172018
  }
171268
- if (!existsSync8(absPath))
172019
+ if (!existsSync9(absPath))
171269
172020
  continue;
171270
172021
  let realPath;
171271
172022
  try {
@@ -176447,7 +177198,7 @@ function resolveDreamerFromConfig(config2) {
176447
177198
  }
176448
177199
  async function src_default2(pi) {
176449
177200
  const storageDir = getMagicContextStorageDir();
176450
- const dbPath = join14(storageDir, "context.db");
177201
+ const dbPath = join15(storageDir, "context.db");
176451
177202
  let db;
176452
177203
  try {
176453
177204
  db = openDatabase();
@@ -176701,6 +177452,11 @@ ${block}` : event.systemPrompt;
176701
177452
  const sessionId = sm?.getSessionId?.();
176702
177453
  if (typeof sessionId !== "string" || sessionId.length === 0)
176703
177454
  return;
177455
+ const rawMessages = readPiSessionMessages(ctx);
177456
+ const latest = rawMessages[rawMessages.length - 1];
177457
+ if (latest?.role === "assistant" && latest.id.length > 0) {
177458
+ scheduleIncrementalIndex(db, sessionId, latest.id, () => latest);
177459
+ }
176704
177460
  persistPiMessageEndModelMeta({
176705
177461
  db,
176706
177462
  sessionId,