@retaw106/mmc-pi 2.2.0 → 2.3.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.
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  withSqliteBackgroundWriter,
3
3
  withoutSqliteTransformPass
4
- } from "./index-ny303arh.js";
5
- import"./index-54cgx9gm.js";
4
+ } from "./index-3qawqvws.js";
5
+ import"./index-83p1tc98.js";
6
6
  import {
7
7
  logSlowWriteTransaction
8
- } from "./index-dx9vhsy8.js";
8
+ } from "./index-4ktngyya.js";
9
9
 
10
10
  // ../plugin/src/features/magic-context/message-time-backfill.ts
11
11
  var MESSAGE_TIME_BACKFILL_BATCH_SIZE = 500;
@@ -24,9 +24,9 @@ import {
24
24
  getRawSessionTagKeysThrough2,
25
25
  getLegacyProtectedTailStartOrdinal2,
26
26
  readSessionChunk2
27
- } from "./index-j0jjtcwm.js";
28
- import"./index-ny303arh.js";
29
- import"./index-54cgx9gm.js";
27
+ } from "./index-f7z4jc1f.js";
28
+ import"./index-3qawqvws.js";
29
+ import"./index-83p1tc98.js";
30
30
  export {
31
31
  cleanUserText2 as cleanUserText,
32
32
  compareRawSessionMessageOrder2 as compareRawSessionMessageOrder,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  isDefaultSessionTitle2,
3
3
  waitForSafeNotificationTarget2
4
- } from "./index-v6scmxvt.js";
5
- import"./index-54cgx9gm.js";
4
+ } from "./index-1p318k54.js";
5
+ import"./index-83p1tc98.js";
6
6
  export {
7
7
  isDefaultSessionTitle2 as isDefaultSessionTitle,
8
8
  waitForSafeNotificationTarget2 as waitForSafeNotificationTarget
package/dist/web/main.js CHANGED
@@ -381,8 +381,12 @@ function flush() {
381
381
  let currentSize = getCurrentLogSize(logFile);
382
382
  const dataSize = Buffer.byteLength(data);
383
383
  if (currentSize > 0 && currentSize + dataSize > MAX_LOG_FILE_BYTES) {
384
- rotateLogFile(logFile, currentSize);
385
- currentSize = 0;
384
+ flushesSinceSizeCheck = SIZE_CHECK_INTERVAL_FLUSHES;
385
+ currentSize = getCurrentLogSize(logFile);
386
+ if (currentSize > 0 && currentSize + dataSize > MAX_LOG_FILE_BYTES) {
387
+ rotateLogFile(logFile, currentSize);
388
+ currentSize = 0;
389
+ }
386
390
  }
387
391
  fs.appendFileSync(logFile, data, { encoding: "utf8", mode: 384 });
388
392
  buffer = [];
@@ -446,12 +450,14 @@ import { AsyncLocalStorage } from "node:async_hooks";
446
450
  function registerSlowWriteReporter(reporter) {
447
451
  reportSlowPrivilegedWrite = reporter;
448
452
  }
449
- function registerSqliteDiagnosticSink(sink) {
453
+ function registerSqliteDiagnosticSink(sink, host) {
450
454
  sqliteDiagnosticSink = sink;
455
+ if (host)
456
+ sqliteDiagnosticHost = host;
451
457
  }
452
458
  function reportSqliteDiagnostic(message) {
453
459
  try {
454
- sqliteDiagnosticSink?.(`[magic-context] ${message}`);
460
+ sqliteDiagnosticSink?.(`[magic-context] ${message} pid=${process.pid} host=${sqliteDiagnosticHost()}`);
455
461
  } catch {}
456
462
  }
457
463
  function detectSqliteRuntime() {
@@ -473,10 +479,31 @@ function isModuleNotFoundError(error, specifier) {
473
479
  return false;
474
480
  return code === "ERR_MODULE_NOT_FOUND" || code === "ERR_UNKNOWN_BUILTIN_MODULE" || code === "MODULE_NOT_FOUND" || name === "ResolveMessage" || details.includes("module not found") || details.includes("cannot find module") || details.includes("cannot find package") || details.includes("no such built-in module");
475
481
  }
482
+ function isNodeSqliteExperimentalWarning(args) {
483
+ const [warning, options] = args;
484
+ const message = warning instanceof Error ? warning.message : warning;
485
+ const type = typeof options === "string" ? options : options && typeof options === "object" ? options.type : undefined;
486
+ return type === "ExperimentalWarning" && typeof message === "string" && message.startsWith("SQLite is an experimental feature");
487
+ }
488
+ async function importSqliteModuleForRuntime(runtime, specifier, importer) {
489
+ if (runtime !== "Node.js")
490
+ return importer(specifier);
491
+ const originalEmitWarning = process.emitWarning;
492
+ process.emitWarning = function(...args) {
493
+ if (isNodeSqliteExperimentalWarning(args))
494
+ return;
495
+ Reflect.apply(originalEmitWarning, this, args);
496
+ };
497
+ try {
498
+ return await importer(specifier);
499
+ } finally {
500
+ process.emitWarning = originalEmitWarning;
501
+ }
502
+ }
476
503
  async function loadSqliteModule(runtime = detectSqliteRuntime(), importer = importSqliteModule) {
477
504
  const specifier = runtime === "Bun" ? bunSpec : nodeSpec;
478
505
  try {
479
- return await importer(specifier);
506
+ return await importSqliteModuleForRuntime(runtime, specifier, importer);
480
507
  } catch (error) {
481
508
  if (isModuleNotFoundError(error, specifier)) {
482
509
  throw new SqliteRuntimeUnavailableError(runtime, specifier, error);
@@ -484,6 +511,64 @@ async function loadSqliteModule(runtime = detectSqliteRuntime(), importer = impo
484
511
  throw error;
485
512
  }
486
513
  }
514
+ function mayChangeTagIdentity(sql) {
515
+ if (!/\btags\b/i.test(sql) || /^\s*(?:SELECT|EXPLAIN|PRAGMA)\b/i.test(sql))
516
+ return false;
517
+ if (/^\s*WITH\b/i.test(sql) && !/\b(?:INSERT|UPDATE|DELETE|REPLACE)\b/i.test(sql))
518
+ return false;
519
+ if (/;\s*\S/.test(sql) || /\bREPLACE\b/i.test(sql) || /\bON\s+CONFLICT\b/i.test(sql))
520
+ return true;
521
+ const insert = /^\s*INSERT\s+INTO\s+(?:main\.)?["`]?tags["`]?\s*\(([^)]*)\)/i.exec(sql);
522
+ if (insert) {
523
+ const columns = (insert[1] ?? "").split(",").map((column) => column.trim().replace(/["`[\]]/g, "").toLowerCase());
524
+ return columns.includes("id") || columns.includes("rowid");
525
+ }
526
+ const update = /^\s*UPDATE\s+(?:main\.)?["`]?tags["`]?\s+SET\s+([\s\S]*?)\bWHERE\b/i.exec(sql);
527
+ if (update && !/\bSELECT\b/i.test(sql)) {
528
+ const assignments = topLevelCommaSegments(update[1] ?? "");
529
+ if (!assignments)
530
+ return true;
531
+ return !assignments.every((assignment) => {
532
+ const column = /^\s*["`]?(\w+)["`]?\s*=(?!=)/.exec(assignment)?.[1];
533
+ return column !== undefined && TAG_COLUMNS_OUTSIDE_IDENTITY.has(column.toLowerCase());
534
+ });
535
+ }
536
+ return true;
537
+ }
538
+ function topLevelCommaSegments(text) {
539
+ const segments = [];
540
+ let depth = 0;
541
+ let quote = null;
542
+ let start = 0;
543
+ for (let index = 0;index < text.length; index += 1) {
544
+ const char = text[index];
545
+ if (quote) {
546
+ if (char === quote) {
547
+ if (text[index + 1] === quote)
548
+ index += 1;
549
+ else
550
+ quote = null;
551
+ }
552
+ continue;
553
+ }
554
+ if (char === "'" || char === '"' || char === "`")
555
+ quote = char;
556
+ else if (char === "(")
557
+ depth += 1;
558
+ else if (char === ")") {
559
+ depth -= 1;
560
+ if (depth < 0)
561
+ return null;
562
+ } else if (char === "," && depth === 0) {
563
+ segments.push(text.slice(start, index));
564
+ start = index + 1;
565
+ }
566
+ }
567
+ if (quote || depth !== 0)
568
+ return null;
569
+ segments.push(text.slice(start));
570
+ return segments;
571
+ }
487
572
  function installTransactionRouting(db, readonly) {
488
573
  const nativeExec = db.exec.bind(db);
489
574
  Object.defineProperty(db, "exec", {
@@ -494,16 +579,30 @@ function installTransactionRouting(db, readonly) {
494
579
  assertTransformWrite();
495
580
  if (/^\s*BEGIN\s+(?:IMMEDIATE|EXCLUSIVE)(?:\s+TRANSACTION)?\s*;?\s*$/i.test(sql)) {
496
581
  openWriterTransactions.delete(db);
497
- if (transformPassScope.getStore()?.active || backgroundWriterScope.getStore())
582
+ if (transformPassScope.getStore()?.active || backgroundWriterScope.getStore()) {
498
583
  acquireShort(db, () => nativeExec(sql), sql.trim());
499
- else
584
+ } else {
500
585
  nativeExec(sql);
586
+ openWriterTransactions.set(db, {
587
+ site: sql.trim(),
588
+ lane: "background",
589
+ acquireMs: 0,
590
+ attempts: 1,
591
+ acquiredAt: performance.now()
592
+ });
593
+ }
501
594
  return db;
502
595
  }
503
596
  if (WRITER_TRANSACTION_END.test(sql) && openWriterTransactions.has(db))
504
597
  return endWriterTransaction(db, () => nativeExec(sql), sql);
505
- if (!/^\s*(?:SELECT|EXPLAIN|PRAGMA|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\b/i.test(sql))
506
- return withAutocommitTimeout(db, () => nativeExec(sql));
598
+ if (!/^\s*(?:SELECT|EXPLAIN|PRAGMA|COMMIT|END|ROLLBACK|SAVEPOINT|RELEASE)\b/i.test(sql)) {
599
+ try {
600
+ return withAutocommitTimeout(db, () => nativeExec(sql));
601
+ } finally {
602
+ if (mayChangeTagIdentity(sql))
603
+ tagIdentityWriteGeneration += 1;
604
+ }
605
+ }
507
606
  return nativeExec(sql);
508
607
  }
509
608
  });
@@ -514,13 +613,23 @@ function installTransactionRouting(db, readonly) {
514
613
  value: (sql) => {
515
614
  const statement = nativePrepare(sql);
516
615
  if (!readonly && !/^\s*(?:SELECT|EXPLAIN|PRAGMA)\b/i.test(sql)) {
616
+ const changesTagIdentity = mayChangeTagIdentity(sql);
517
617
  for (const method of ["run", "get", "all"]) {
518
618
  const execute = statement[method].bind(statement);
519
619
  Object.defineProperty(statement, method, {
520
620
  configurable: true,
521
- value: (...args) => withAutocommitTimeout(db, () => execute(...args))
621
+ value: (...args) => {
622
+ try {
623
+ return withAutocommitTimeout(db, () => execute(...args));
624
+ } finally {
625
+ if (changesTagIdentity)
626
+ tagIdentityWriteGeneration += 1;
627
+ }
628
+ }
522
629
  });
523
630
  }
631
+ if (changesTagIdentity)
632
+ wrapRemainingTagWriteForms(statement);
524
633
  }
525
634
  return statement;
526
635
  }
@@ -568,6 +677,35 @@ function installTransactionRouting(db, readonly) {
568
677
  }
569
678
  });
570
679
  }
680
+ function wrapRemainingTagWriteForms(statement) {
681
+ if (typeof statement.iterate === "function") {
682
+ const iterate = statement.iterate.bind(statement);
683
+ Object.defineProperty(statement, "iterate", {
684
+ configurable: true,
685
+ value: function* (...args) {
686
+ tagIdentityWriteGeneration += 1;
687
+ try {
688
+ yield* iterate(...args);
689
+ } finally {
690
+ tagIdentityWriteGeneration += 1;
691
+ }
692
+ }
693
+ });
694
+ }
695
+ if (typeof statement.values === "function") {
696
+ const values = statement.values.bind(statement);
697
+ Object.defineProperty(statement, "values", {
698
+ configurable: true,
699
+ value: (...args) => {
700
+ try {
701
+ return values(...args);
702
+ } finally {
703
+ tagIdentityWriteGeneration += 1;
704
+ }
705
+ }
706
+ });
707
+ }
708
+ }
571
709
  function trackSqliteConnection(db, filename, options) {
572
710
  const originalClose = db.close.bind(db);
573
711
  const sequence = nextSqliteConnectionSequence++;
@@ -704,22 +842,30 @@ function foregroundWaitLease() {
704
842
  function withAutocommitTimeout(db, operation) {
705
843
  assertTransformWrite();
706
844
  const lease = foregroundWaitLease();
707
- if (isInTransaction(db) || !lease && !backgroundWriterScope.getStore())
845
+ if (isInTransaction(db))
708
846
  return operation();
709
- const previous = pragmaNumber(db, "busy_timeout");
710
- db.exec(`PRAGMA busy_timeout=${lease ? Math.floor(lease.remainingWaitMs) : SHORT_BUSY_TIMEOUT_MS}`);
847
+ const scoped = lease || backgroundWriterScope.getStore();
848
+ const previous = scoped ? pragmaNumber(db, "busy_timeout") : null;
849
+ if (scoped)
850
+ db.exec(`PRAGMA busy_timeout=${lease ? Math.floor(Math.min(lease.remainingWaitMs, lease.guard?.remainingMs() ?? Infinity)) : SHORT_BUSY_TIMEOUT_MS}`);
711
851
  const started = performance.now();
852
+ let completed = false;
712
853
  try {
713
- return operation();
854
+ const result = operation();
855
+ completed = true;
856
+ return result;
714
857
  } catch (error) {
715
858
  if (lease && isTransientSqliteError(error))
716
859
  throw new SqliteAcquisitionBusyError(error, "autocommit");
717
860
  throw error;
718
861
  } finally {
862
+ const elapsed = performance.now() - started;
719
863
  if (lease)
720
- lease.remainingWaitMs = Math.max(0, lease.remainingWaitMs - (performance.now() - started));
864
+ lease.remainingWaitMs = Math.max(0, lease.remainingWaitMs - elapsed);
721
865
  if (previous !== null)
722
866
  db.exec(`PRAGMA busy_timeout=${previous}`);
867
+ if (elapsed >= SLOW_WRITER_LOG_MS)
868
+ reportSqliteDiagnostic(`sqlite writer site=autocommit lane=${lease ? "foreground" : "background"} elapsed_ms=${Math.round(elapsed)} timing=statement_including_acquisition outcome=${completed ? "completed" : "failed"} caller=${writerCaller()}`);
723
869
  }
724
870
  }
725
871
  function acquireShort(db, acquire, site) {
@@ -776,16 +922,20 @@ function endWriterTransaction(db, end, sql) {
776
922
  const holdMs = performance.now() - open.acquiredAt;
777
923
  if (open.acquireMs >= SLOW_WRITER_LOG_MS || holdMs >= SLOW_WRITER_LOG_MS) {
778
924
  const outcome = /^\s*ROLLBACK/i.test(sql) ? "rolled_back" : ended ? "committed" : "failed";
779
- reportSqliteDiagnostic(`sqlite writer site=${open.site} lane=${open.lane} acquire_ms=${Math.round(open.acquireMs)} hold_ms=${Math.round(holdMs)} attempts=${open.attempts} outcome=${outcome}`);
925
+ reportSqliteDiagnostic(`sqlite writer site=${open.site} lane=${open.lane} acquire_ms=${Math.round(open.acquireMs)} hold_ms=${Math.round(holdMs)} attempts=${open.attempts} outcome=${outcome} timing=through_commit_upper_bound caller=${writerCaller()}`);
780
926
  }
781
927
  }
782
928
  }
783
929
  }
930
+ function writerCaller() {
931
+ return new Error().stack?.split(`
932
+ `).find((line) => line.includes(" at ") && !/[/\\]sqlite\.[tj]s[:)]/.test(line) && !/\b(?:writerCaller|endWriterTransaction|withAutocommitTimeout|value)\b/.test(line))?.trim().replace(/\s+/g, "_") ?? "unknown";
933
+ }
784
934
  function isInTransaction(db) {
785
935
  const candidate = db;
786
936
  return candidate.inTransaction === true || candidate.isTransaction === true;
787
937
  }
788
- var reportSlowPrivilegedWrite, sqliteDiagnosticSink, bunSpec, nodeSpec, SqliteRuntimeUnavailableError, detectedRuntime, isBun, sqliteModule, DatabaseImpl, trackedSqliteConnections, nextSqliteConnectionSequence = 1, TrackedDatabase, Database, statementOwners, FIRST_PRUNE_AT = 256, privilegeDepth, transformPassScope, admissionScope, backgroundWriterScope, SqliteAcquisitionBusyError, SHORT_BUSY_TIMEOUT_MS = 25, SLOW_WRITER_LOG_MS = 250, WRITER_TRANSACTION_END, writerAcquisitionScope, openWriterTransactions;
938
+ var reportSlowPrivilegedWrite, sqliteDiagnosticSink, sqliteDiagnosticHost = () => "unknown", bunSpec, nodeSpec, SqliteRuntimeUnavailableError, detectedRuntime, isBun, sqliteModule, DatabaseImpl, trackedSqliteConnections, nextSqliteConnectionSequence = 1, TAG_COLUMNS_OUTSIDE_IDENTITY, tagIdentityWriteGeneration = 0, TrackedDatabase, Database, statementOwners, FIRST_PRUNE_AT = 256, privilegeDepth, transformPassScope, admissionScope, backgroundWriterScope, SqliteAcquisitionBusyError, SHORT_BUSY_TIMEOUT_MS = 25, SLOW_WRITER_LOG_MS = 100, WRITER_TRANSACTION_END, writerAcquisitionScope, openWriterTransactions, indexCoordinationKey, indexCoordinationHeap, indexCoordinationBuffer, indexCoordinationState;
789
939
  var init_sqlite = __esm(async () => {
790
940
  bunSpec = "bun:" + "sqlite";
791
941
  nodeSpec = "node:" + "sqlite";
@@ -805,6 +955,19 @@ var init_sqlite = __esm(async () => {
805
955
  sqliteModule = await loadSqliteModule(detectedRuntime);
806
956
  DatabaseImpl = isBun ? sqliteModule.Database : buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
807
957
  trackedSqliteConnections = new Map;
958
+ TAG_COLUMNS_OUTSIDE_IDENTITY = new Set([
959
+ "status",
960
+ "drop_mode",
961
+ "byte_size",
962
+ "input_byte_size",
963
+ "reasoning_byte_size",
964
+ "token_count",
965
+ "input_token_count",
966
+ "caveman_depth",
967
+ "entry_fingerprint",
968
+ "tool_name",
969
+ "harness"
970
+ ]);
808
971
  TrackedDatabase = new Proxy(DatabaseImpl, {
809
972
  construct(target, args) {
810
973
  const db = Reflect.construct(target, args, target);
@@ -829,6 +992,11 @@ var init_sqlite = __esm(async () => {
829
992
  WRITER_TRANSACTION_END = /^\s*(?:COMMIT|END|ROLLBACK)(?:\s+TRANSACTION)?\s*;?\s*$/i;
830
993
  writerAcquisitionScope = new AsyncLocalStorage;
831
994
  openWriterTransactions = new WeakMap;
995
+ indexCoordinationKey = Symbol.for("magic-context.index-foreground-coordination.v1");
996
+ indexCoordinationHeap = globalThis;
997
+ indexCoordinationBuffer = indexCoordinationHeap[indexCoordinationKey] ?? new SharedArrayBuffer(3 * Int32Array.BYTES_PER_ELEMENT);
998
+ indexCoordinationHeap[indexCoordinationKey] = indexCoordinationBuffer;
999
+ indexCoordinationState = new Int32Array(indexCoordinationBuffer);
832
1000
  });
833
1001
 
834
1002
  // ../plugin/src/shared/sqlite-helpers.ts
@@ -885,15 +1053,108 @@ var init_migration_v3_perf_schema = __esm(() => {
885
1053
  tagOrderIndexes = new WeakMap;
886
1054
  });
887
1055
 
1056
+ // ../plugin/src/features/magic-context/storage-tag-identity-revision.ts
1057
+ function installTagIdentityRevisionTrigger(db) {
1058
+ db.exec(`DROP TRIGGER IF EXISTS temp.mc_tag_identity_revision_au;
1059
+ DROP TRIGGER IF EXISTS temp.mc_tag_revision_bi;
1060
+ DROP TRIGGER IF EXISTS temp.mc_tag_revision_ai;
1061
+ DROP TRIGGER IF EXISTS temp.mc_tag_revision_au;
1062
+ DROP TRIGGER IF EXISTS temp.mc_tag_revision_ad;
1063
+ DROP TRIGGER IF EXISTS temp.mc_tag_revision_seed_ai;`);
1064
+ db.exec(`CREATE TEMP TRIGGER mc_tag_revision_seed_ai AFTER INSERT ON main.schema_migrations_meta
1065
+ WHEN INSTR(NEW.value, ':') = 0 AND (
1066
+ SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
1067
+ OR SUBSTR(NEW.key, 1, ${TAG_IDENTITY_REVISION_PREFIX.length}) = '${TAG_IDENTITY_REVISION_PREFIX}')
1068
+ BEGIN
1069
+ INSERT INTO schema_migrations_meta (key, value) VALUES ('${TAG_REVISION_INCARNATION_KEY}', '1')
1070
+ ON CONFLICT(key) DO UPDATE SET value = CAST(CASE
1071
+ WHEN CAST(value AS INTEGER) < 9223372036854775807 THEN CAST(value AS INTEGER) + 1
1072
+ ELSE NULL END AS TEXT);
1073
+ UPDATE schema_migrations_meta SET value =
1074
+ (SELECT value FROM schema_migrations_meta WHERE key = '${TAG_REVISION_INCARNATION_KEY}')
1075
+ || ':' || CAST(NEW.value AS TEXT) WHERE key = NEW.key;
1076
+ INSERT INTO schema_migrations_meta (key, value)
1077
+ SELECT '${TAG_REVISION_INCARNATION_KEY}', '1'
1078
+ WHERE SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
1079
+ AND NOT EXISTS (SELECT 1 FROM schema_migrations_meta
1080
+ WHERE key = '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}))
1081
+ ON CONFLICT(key) DO UPDATE SET value = CAST(CASE
1082
+ WHEN CAST(value AS INTEGER) < 9223372036854775807 THEN CAST(value AS INTEGER) + 1
1083
+ ELSE NULL END AS TEXT);
1084
+ INSERT INTO schema_migrations_meta (key, value)
1085
+ SELECT '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}),
1086
+ (SELECT value FROM schema_migrations_meta WHERE key = '${TAG_REVISION_INCARNATION_KEY}') || ':0'
1087
+ WHERE SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
1088
+ AND NOT EXISTS (SELECT 1 FROM schema_migrations_meta
1089
+ WHERE key = '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}));
1090
+ END;`);
1091
+ db.exec(TRIGGER_SQL);
1092
+ db.exec(`CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_bi BEFORE INSERT ON main.tags BEGIN
1093
+ ${BUMP_INSERT_CONFLICTS(TAG_REVISION_PREFIX)};
1094
+ ${BUMP_INSERT_CONFLICTS(TAG_IDENTITY_REVISION_PREFIX)};
1095
+ UPDATE session_meta SET tags_version = tags_version + 1
1096
+ WHERE session_id IN (SELECT session_id FROM (${TAG_INSERT_CONFLICT_ROWS}));
1097
+ END;`);
1098
+ db.exec(`CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_ai AFTER INSERT ON main.tags BEGIN
1099
+ ${BUMP("NEW.session_id", TAG_REVISION_PREFIX)};
1100
+ END;
1101
+ CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_au AFTER UPDATE ON main.tags BEGIN
1102
+ ${BUMP("OLD.session_id", TAG_REVISION_PREFIX)};
1103
+ INSERT INTO schema_migrations_meta (key, value)
1104
+ SELECT '${TAG_REVISION_PREFIX}' || NEW.session_id, '1'
1105
+ WHERE NEW.session_id IS NOT OLD.session_id
1106
+ ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()};
1107
+ END;
1108
+ CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_ad AFTER DELETE ON main.tags BEGIN
1109
+ ${BUMP("OLD.session_id", TAG_REVISION_PREFIX)};
1110
+ END;`);
1111
+ }
1112
+ var TAG_IDENTITY_REVISION_PREFIX = "tag_identity_revision:", TAG_REVISION_PREFIX = "tag_revision:", TAG_REVISION_INCARNATION_KEY = "tag_revision_incarnation", tagRevisionIncarnationSql = (value) => `CASE WHEN INSTR(${value}, ':') > 0 THEN SUBSTR(${value}, 1, INSTR(${value}, ':') - 1) ELSE '0' END`, tagRevisionCountSql = (value) => `CAST(CASE WHEN INSTR(${value}, ':') > 0 THEN SUBSTR(${value}, INSTR(${value}, ':') + 1) ELSE ${value} END AS INTEGER)`, ADVANCE = (delta = "1") => `CASE
1113
+ WHEN ${tagRevisionCountSql("value")} <= 9223372036854775807 - ${delta}
1114
+ THEN (${tagRevisionIncarnationSql("value")}) || ':' || CAST(${tagRevisionCountSql("value")} + ${delta} AS TEXT)
1115
+ ELSE NULL END`, BUMP = (session, prefix = TAG_IDENTITY_REVISION_PREFIX) => `INSERT INTO schema_migrations_meta (key, value)
1116
+ VALUES ('${prefix}' || ${session}, '1')
1117
+ ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()}`, TAG_INSERT_CONFLICT_ROWS = `SELECT id, session_id, tag_number FROM tags WHERE id = NEW.id
1118
+ UNION SELECT id, session_id, tag_number FROM tags WHERE session_id = NEW.session_id AND tag_number = NEW.tag_number
1119
+ UNION SELECT id, session_id, tag_number FROM tags
1120
+ WHERE NEW.type = 'tool' AND NEW.tool_owner_message_id IS NOT NULL
1121
+ AND type = 'tool' AND tool_owner_message_id IS NOT NULL
1122
+ AND session_id = NEW.session_id AND message_id = NEW.message_id
1123
+ AND tool_owner_message_id = NEW.tool_owner_message_id`, BUMP_INSERT_CONFLICTS = (prefix) => `INSERT INTO schema_migrations_meta (key, value)
1124
+ SELECT '${prefix}' || session_id, CAST(COUNT(*) AS TEXT)
1125
+ FROM (${TAG_INSERT_CONFLICT_ROWS}) GROUP BY session_id
1126
+ ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE("CAST(excluded.value AS INTEGER)")}`, TRIGGER_SQL;
1127
+ var init_storage_tag_identity_revision = __esm(() => {
1128
+ TRIGGER_SQL = `CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_identity_revision_au
1129
+ AFTER UPDATE OF id, session_id, message_id, tag_number, type, tool_owner_message_id, reasoning_token_count
1130
+ ON main.tags
1131
+ BEGIN
1132
+ ${BUMP("OLD.session_id")};
1133
+ INSERT INTO schema_migrations_meta (key, value)
1134
+ SELECT '${TAG_IDENTITY_REVISION_PREFIX}' || NEW.session_id, '1'
1135
+ WHERE NEW.session_id IS NOT OLD.session_id
1136
+ ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()};
1137
+ END`;
1138
+ });
1139
+
888
1140
  // ../plugin/src/shared/commit-detection.ts
889
1141
  var HASH_HEX = "[0-9a-f]{7,12}", COMMIT_HASH_TEST_PATTERN;
890
1142
  var init_commit_detection = __esm(() => {
891
1143
  COMMIT_HASH_TEST_PATTERN = new RegExp(`\\b${HASH_HEX}\\b`, "i");
892
1144
  });
1145
+ // ../plugin/src/hooks/magic-context/token-count-exact.ts
1146
+ var textEncoder, textDecoder, mergeCaches;
1147
+ var init_token_count_exact = __esm(() => {
1148
+ textEncoder = new TextEncoder;
1149
+ textDecoder = new TextDecoder("utf-8");
1150
+ mergeCaches = new WeakMap;
1151
+ });
1152
+
893
1153
  // ../plugin/src/hooks/magic-context/read-session-formatting.ts
894
1154
  var promptTokenCounts, PROMPT_TOKEN_COUNT_BYTES;
895
1155
  var init_read_session_formatting = __esm(() => {
896
1156
  init_commit_detection();
1157
+ init_token_count_exact();
897
1158
  promptTokenCounts = new Map;
898
1159
  PROMPT_TOKEN_COUNT_BYTES = 8 * 1024 * 1024;
899
1160
  });
@@ -1379,6 +1640,89 @@ function installV4TemporalDecisions(db) {
1379
1640
  init_logger();
1380
1641
  init_write_transaction_timing();
1381
1642
  init_migration_v3_perf_schema();
1643
+
1644
+ // ../plugin/src/features/magic-context/storage-compartment-history-version.ts
1645
+ function definitions(db) {
1646
+ const hasPrivilegeTable = Boolean(db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='context_privilege_state'").get());
1647
+ const externalUpdate = hasPrivilegeTable ? "CASE WHEN COALESCE((SELECT enabled FROM context_privilege_state WHERE id=1),0)=0 THEN 1 ELSE 0 END" : "1";
1648
+ return [
1649
+ {
1650
+ type: "table",
1651
+ name: "compartment_history_versions",
1652
+ sql: `CREATE TABLE compartment_history_versions (
1653
+ session_id TEXT PRIMARY KEY NOT NULL,
1654
+ generation TEXT NOT NULL DEFAULT (lower(hex(randomblob(16)))),
1655
+ version INTEGER NOT NULL DEFAULT 0 CHECK (version >= 0),
1656
+ rewrite_version INTEGER NOT NULL DEFAULT 0 CHECK (rewrite_version >= 0),
1657
+ seeded INTEGER NOT NULL DEFAULT 0 CHECK (seeded IN (0, 1))
1658
+ )`
1659
+ },
1660
+ {
1661
+ type: "trigger",
1662
+ name: "compartment_history_ai",
1663
+ sql: `CREATE TRIGGER compartment_history_ai AFTER INSERT ON compartments BEGIN
1664
+ INSERT INTO compartment_history_versions(session_id, version) VALUES (NEW.session_id, 1)
1665
+ ON CONFLICT(session_id) DO UPDATE SET version = version + 1;
1666
+ END`
1667
+ },
1668
+ {
1669
+ type: "trigger",
1670
+ name: "compartment_history_ad",
1671
+ sql: `CREATE TRIGGER compartment_history_ad AFTER DELETE ON compartments BEGIN
1672
+ INSERT INTO compartment_history_versions(session_id, version) VALUES (OLD.session_id, 1)
1673
+ ON CONFLICT(session_id) DO UPDATE SET version = version + 1;
1674
+ END`
1675
+ },
1676
+ {
1677
+ type: "trigger",
1678
+ name: "compartment_history_au",
1679
+ sql: `CREATE TRIGGER compartment_history_au AFTER UPDATE ON compartments BEGIN
1680
+ INSERT INTO compartment_history_versions(session_id, version, rewrite_version) VALUES (OLD.session_id, 1, ${externalUpdate})
1681
+ ON CONFLICT(session_id) DO UPDATE SET version = version + 1, rewrite_version = rewrite_version + ${externalUpdate};
1682
+ INSERT INTO compartment_history_versions(session_id, version, rewrite_version)
1683
+ SELECT NEW.session_id, 1, ${externalUpdate} WHERE NEW.session_id != OLD.session_id
1684
+ ON CONFLICT(session_id) DO UPDATE SET version = version + 1, rewrite_version = rewrite_version + ${externalUpdate};
1685
+ END`
1686
+ }
1687
+ ];
1688
+ }
1689
+ function installedDefinitions(db) {
1690
+ const rows = db.prepare(`SELECT type, name, sql FROM sqlite_master
1691
+ WHERE name IN ('compartment_history_versions', 'compartment_history_ai', 'compartment_history_ad', 'compartment_history_au')`).all();
1692
+ return new Map(rows.map((row) => [`${row.type}:${row.name}`, row.sql]));
1693
+ }
1694
+ function matches(expected, installed) {
1695
+ return expected.every((definition) => installed.get(`${definition.type}:${definition.name}`) === definition.sql);
1696
+ }
1697
+ function installCompartmentHistoryVersions(db) {
1698
+ if (!db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='compartments'").get())
1699
+ return;
1700
+ if (matches(definitions(db), installedDefinitions(db)))
1701
+ return;
1702
+ db.transaction(() => {
1703
+ const expected = definitions(db);
1704
+ const installed = installedDefinitions(db);
1705
+ if (matches(expected, installed))
1706
+ return;
1707
+ const table = expected[0];
1708
+ const existingTable = installed.get(`table:${table.name}`);
1709
+ if (existingTable !== undefined && existingTable !== table.sql) {
1710
+ throw new Error("compartment_history_versions schema differs from v5; refusing to replace revision data");
1711
+ }
1712
+ if (existingTable === undefined)
1713
+ db.exec(table.sql);
1714
+ db.exec(`INSERT OR IGNORE INTO compartment_history_versions(session_id, seeded)
1715
+ SELECT DISTINCT session_id, 1 FROM compartments`);
1716
+ for (const trigger of expected.slice(1)) {
1717
+ if (installed.get(`trigger:${trigger.name}`) === trigger.sql)
1718
+ continue;
1719
+ db.exec(`DROP TRIGGER IF EXISTS ${trigger.name}`);
1720
+ db.exec(trigger.sql);
1721
+ }
1722
+ }).immediate();
1723
+ }
1724
+
1725
+ // ../plugin/src/features/magic-context/migrations.ts
1382
1726
  var FORK_MIGRATION_VERSION_FLOOR = 1e4;
1383
1727
  class MigrationLockBusyError extends Error {
1384
1728
  constructor(message) {
@@ -1421,6 +1765,13 @@ var MIGRATIONS = [
1421
1765
  up(db) {
1422
1766
  installV4TemporalDecisions(db);
1423
1767
  }
1768
+ },
1769
+ {
1770
+ version: 5,
1771
+ description: "per-session compartment history revision for shared readers",
1772
+ up(db) {
1773
+ installCompartmentHistoryVersions(db);
1774
+ }
1424
1775
  }
1425
1776
  ];
1426
1777
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -1562,6 +1913,7 @@ function ensureColumn(db, table, column, definition) {
1562
1913
  }
1563
1914
 
1564
1915
  // ../plugin/src/features/magic-context/storage-db.ts
1916
+ init_storage_tag_identity_revision();
1565
1917
  init_tool_definition_tokens();
1566
1918
 
1567
1919
  // ../plugin/src/features/magic-context/tool-owner-backfill.ts
@@ -1572,13 +1924,13 @@ var LEASE_RENEWAL_MS = 60 * 1000;
1572
1924
 
1573
1925
  // ../plugin/src/features/magic-context/storage-db.ts
1574
1926
  registerSlowWriteReporter(logSlowWriteTransaction);
1575
- registerSqliteDiagnosticSink((message) => log(message));
1927
+ registerSqliteDiagnosticSink((message) => log(message), getHarness);
1576
1928
  var databases = new Map;
1577
1929
  var pendingAsyncOpens = new Map;
1578
1930
  var persistenceByDatabase = new WeakMap;
1579
1931
  var persistenceErrorByDatabase = new WeakMap;
1580
1932
  var pathByDatabase = new WeakMap;
1581
- var LATEST_SUPPORTED_VERSION = 4;
1933
+ var LATEST_SUPPORTED_VERSION = 5;
1582
1934
  var BOOT_SQLITE_BUSY_TIMEOUT_MS = 5000;
1583
1935
  function resolveBootBusyTimeoutMs(value) {
1584
1936
  if (value === undefined)
@@ -3039,6 +3391,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
3039
3391
  `);
3040
3392
  installV3PerfSchema(db);
3041
3393
  installV4TemporalDecisions(db);
3394
+ installCompartmentHistoryVersions(db);
3395
+ installTagIdentityRevisionTrigger(db);
3042
3396
  }
3043
3397
  var CHANNEL2_CLAIM_TTL_MS = 10 * 60000;
3044
3398
  var channel2HealStatements = new WeakMap;
@@ -7471,12 +7825,31 @@ function attachPiPartVersion(parts, version) {
7471
7825
  return part;
7472
7826
  });
7473
7827
  }
7474
- function* iterateEntriesToRawMessageRange(entries, afterOrdinal, limit, finalWatermark, synthIdAliases) {
7828
+ var UNREACHABLE_PI_STORE_TYPE = "unavailable";
7829
+ function unreachablePiOrdinalSlot(ordinal) {
7830
+ const slot = { ordinal, id: "", role: "system", parts: [] };
7831
+ Object.defineProperty(slot, "storeType", {
7832
+ value: UNREACHABLE_PI_STORE_TYPE,
7833
+ enumerable: false
7834
+ });
7835
+ return slot;
7836
+ }
7837
+ function* iterateEntriesToRawMessageRange(entries, afterOrdinal, limit, finalWatermark, synthIdAliases, ordinalOffset = 0) {
7475
7838
  let emitted = 0;
7476
7839
  const normalizedAfter = Math.max(0, Math.floor(afterOrdinal));
7477
7840
  const normalizedLimit = Math.max(1, Math.floor(limit));
7478
7841
  const normalizedWatermark = Math.max(normalizedAfter, Math.floor(finalWatermark));
7479
- let nextOrdinal = 1;
7842
+ const prefix = Number.isSafeInteger(ordinalOffset) && ordinalOffset > 0 ? ordinalOffset : 0;
7843
+ const prefixEnd = Math.min(prefix, normalizedWatermark);
7844
+ for (let ordinal = normalizedAfter + 1;ordinal <= prefixEnd; ordinal++) {
7845
+ emitted++;
7846
+ yield unreachablePiOrdinalSlot(ordinal);
7847
+ if (emitted >= normalizedLimit)
7848
+ return;
7849
+ }
7850
+ if (prefix >= normalizedWatermark)
7851
+ return;
7852
+ let nextOrdinal = prefix + 1;
7480
7853
  let heldToolRow = null;
7481
7854
  let orphanToolParts = [];
7482
7855
  const buildOrphanParts = (results) => results.flatMap(({ msg, version }) => attachPiPartVersion(synthesizeToolResultParts(msg), version));
@@ -7591,9 +7964,9 @@ function* iterateEntriesToRawMessageRange(entries, afterOrdinal, limit, finalWat
7591
7964
  yield* appendMessage(`${SYNTH_USER_ID_PREFIX}${orphanFirstId}`, "user", orphanFirstVersion, orphanFirstCreatedAt, () => buildOrphanParts(trailingOrphanResults));
7592
7965
  }
7593
7966
  }
7594
- function convertEntriesToRawMessages(entries) {
7967
+ function convertEntriesToRawMessages(entries, ordinalOffset = 0) {
7595
7968
  return [
7596
- ...iterateEntriesToRawMessageRange(entries, 0, Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER)
7969
+ ...iterateEntriesToRawMessageRange(entries, 0, Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, undefined, ordinalOffset)
7597
7970
  ];
7598
7971
  }
7599
7972
  function buildPiSynthUserIdAlias(entries) {