@cortexkit/pi-magic-context 0.32.0 → 0.32.1

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.
@@ -8128,11 +8128,11 @@ function buildNodeSqliteDatabaseClass(DatabaseSync) {
8128
8128
  }
8129
8129
  transaction(fn) {
8130
8130
  const self = this;
8131
- const wrapped = function(...args) {
8131
+ const execute = (mode, receiver, args) => {
8132
8132
  const nested = self.isTransaction === true;
8133
- self.exec(nested ? `SAVEPOINT ${SAVEPOINT}` : "BEGIN");
8133
+ self.exec(nested ? `SAVEPOINT ${SAVEPOINT}` : `BEGIN${mode ? ` ${mode}` : ""}`);
8134
8134
  try {
8135
- const result = fn.apply(this, args);
8135
+ const result = fn.apply(receiver, args);
8136
8136
  self.exec(nested ? `RELEASE ${SAVEPOINT}` : "COMMIT");
8137
8137
  return result;
8138
8138
  } catch (error) {
@@ -8145,6 +8145,21 @@ function buildNodeSqliteDatabaseClass(DatabaseSync) {
8145
8145
  throw error;
8146
8146
  }
8147
8147
  };
8148
+ const wrapped = function(...args) {
8149
+ return execute("", this, args);
8150
+ };
8151
+ wrapped.default = function(...args) {
8152
+ return execute("", this, args);
8153
+ };
8154
+ wrapped.deferred = function(...args) {
8155
+ return execute("DEFERRED", this, args);
8156
+ };
8157
+ wrapped.immediate = function(...args) {
8158
+ return execute("IMMEDIATE", this, args);
8159
+ };
8160
+ wrapped.exclusive = function(...args) {
8161
+ return execute("EXCLUSIVE", this, args);
8162
+ };
8148
8163
  return wrapped;
8149
8164
  }
8150
8165
  }
@@ -8188,10 +8203,16 @@ function healAllNullColumns(db) {
8188
8203
  healNullIntegerColumns(db);
8189
8204
  healMissingMemoryBlockIds(db);
8190
8205
  }
8206
+ function getSessionMetaColumns(db) {
8207
+ const rows = db.prepare("PRAGMA table_info(session_meta)").all();
8208
+ return new Set(rows.flatMap((row) => typeof row.name === "string" ? [row.name] : []));
8209
+ }
8191
8210
  function healMissingMemoryBlockIds(db) {
8192
- try {
8193
- db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != '' AND (memory_block_ids IS NULL OR memory_block_ids = '') AND memory_block_count > 0").run();
8194
- } catch {}
8211
+ const columns = getSessionMetaColumns(db);
8212
+ if (!columns.has("memory_block_cache") || !columns.has("memory_block_ids") || !columns.has("memory_block_count")) {
8213
+ return;
8214
+ }
8215
+ db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != '' AND (memory_block_ids IS NULL OR memory_block_ids = '') AND memory_block_count > 0").run();
8195
8216
  }
8196
8217
  function healNullTextColumns(db) {
8197
8218
  const columns = [
@@ -8220,10 +8241,11 @@ function healNullTextColumns(db) {
8220
8241
  ["compaction_marker_state", ""],
8221
8242
  ["key_files", ""]
8222
8243
  ];
8244
+ const existingColumns = getSessionMetaColumns(db);
8223
8245
  for (const [column, fallback] of columns) {
8224
- try {
8225
- db.prepare(`UPDATE session_meta SET ${column} = ? WHERE ${column} IS NULL`).run(fallback);
8226
- } catch (_error) {}
8246
+ if (!existingColumns.has(column))
8247
+ continue;
8248
+ db.prepare(`UPDATE session_meta SET ${column} = ? WHERE ${column} IS NULL`).run(fallback);
8227
8249
  }
8228
8250
  }
8229
8251
  function healNullIntegerColumns(db) {
@@ -8254,10 +8276,11 @@ function healNullIntegerColumns(db) {
8254
8276
  ["emergency_drain_active", 0],
8255
8277
  ["historian_drain_failure_at", 0]
8256
8278
  ];
8279
+ const existingColumns = getSessionMetaColumns(db);
8257
8280
  for (const [column, fallback] of columns) {
8258
- try {
8259
- db.prepare(`UPDATE session_meta SET ${column} = ? WHERE ${column} IS NULL`).run(fallback);
8260
- } catch (_error) {}
8281
+ if (!existingColumns.has(column))
8282
+ continue;
8283
+ db.prepare(`UPDATE session_meta SET ${column} = ? WHERE ${column} IS NULL`).run(fallback);
8261
8284
  }
8262
8285
  }
8263
8286
 
@@ -10209,6 +10232,34 @@ var MIGRATIONS = [
10209
10232
  ensureColumn(db, "session_meta", "wrapup_in_progress_state", "TEXT");
10210
10233
  }
10211
10234
  }
10235
+ },
10236
+ {
10237
+ version: 51,
10238
+ description: "version tool-owner backfill state and repair legacy NULL session metadata",
10239
+ up(db) {
10240
+ db.exec(`
10241
+ CREATE TABLE IF NOT EXISTS tool_owner_backfill_state (
10242
+ session_id TEXT PRIMARY KEY,
10243
+ status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'skipped')),
10244
+ started_at INTEGER,
10245
+ lease_expires_at INTEGER,
10246
+ completed_at INTEGER,
10247
+ last_error TEXT
10248
+ );
10249
+ CREATE INDEX IF NOT EXISTS idx_tool_owner_backfill_state_status
10250
+ ON tool_owner_backfill_state(status);
10251
+ `);
10252
+ healAllNullColumns(db);
10253
+ }
10254
+ },
10255
+ {
10256
+ version: 52,
10257
+ description: "persist emergency recovery origin",
10258
+ up(db) {
10259
+ if (tableExists2(db, "session_meta")) {
10260
+ ensureColumn(db, "session_meta", "emergency_recovery_origin", "TEXT DEFAULT ''");
10261
+ }
10262
+ }
10212
10263
  }
10213
10264
  ];
10214
10265
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -10238,40 +10289,45 @@ function isSiblingMigrationConflict(db, error, version) {
10238
10289
  }
10239
10290
  function runMigrations(db) {
10240
10291
  ensureMigrationsTable(db);
10241
- let currentVersion = getCurrentVersion(db);
10242
- let pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
10243
- if (pendingMigrations.length === 0) {
10244
- return;
10245
- }
10246
- log(`[migrations] current schema version: ${currentVersion}, applying ${pendingMigrations.length} migration(s)`);
10247
- let migrationIndex = 0;
10248
- while (migrationIndex < pendingMigrations.length) {
10249
- const migration = pendingMigrations[migrationIndex];
10292
+ let loggedPlan = false;
10293
+ while (true) {
10294
+ let migration;
10295
+ let currentVersion = 0;
10250
10296
  try {
10251
- db.transaction(() => {
10297
+ const applied = db.transaction(() => {
10298
+ currentVersion = getCurrentVersion(db);
10299
+ migration = MIGRATIONS.find((candidate) => candidate.version > currentVersion);
10300
+ if (!migration)
10301
+ return false;
10302
+ if (!loggedPlan) {
10303
+ const pendingCount = MIGRATIONS.filter((candidate) => candidate.version > currentVersion).length;
10304
+ log(`[migrations] current schema version: ${currentVersion}, applying ${pendingCount} migration(s)`);
10305
+ loggedPlan = true;
10306
+ }
10252
10307
  migration.up(db);
10253
10308
  db.prepare("INSERT INTO schema_migrations (version, description, applied_at) VALUES (?, ?, ?)").run(migration.version, migration.description, Date.now());
10254
- })();
10309
+ return true;
10310
+ }).immediate();
10311
+ if (!applied || !migration)
10312
+ break;
10255
10313
  log(`[migrations] applied v${migration.version}: ${migration.description}`);
10256
- migrationIndex += 1;
10257
10314
  } catch (error) {
10258
- if (isSiblingMigrationConflict(db, error, migration.version)) {
10315
+ if (migration && isSiblingMigrationConflict(db, error, migration.version)) {
10259
10316
  log(`[migrations] v${migration.version} already applied by sibling instance — resuming with re-read version`);
10260
10317
  const reReadVersion = getCurrentVersion(db);
10261
- if (reReadVersion <= currentVersion) {
10262
- log(`[migrations] FAILED v${migration.version}: sibling-conflict shape but version not advanced (${reReadVersion} <= ${currentVersion}) — failing closed`);
10263
- throw new Error(`Migration v${migration.version} failed: sibling conflict reported but version did not advance. Database may need manual repair.`);
10264
- }
10265
- currentVersion = reReadVersion;
10266
- pendingMigrations = MIGRATIONS.filter((m) => m.version > currentVersion);
10267
- migrationIndex = 0;
10268
- continue;
10318
+ if (reReadVersion > currentVersion)
10319
+ continue;
10320
+ throw new Error(`Migration v${migration.version} failed: sibling conflict reported but version did not advance. Database may need manual repair.`);
10269
10321
  }
10270
- log(`[migrations] FAILED v${migration.version}: ${migration.description} — ${error instanceof Error ? error.message : String(error)}`);
10271
- throw new Error(`Migration v${migration.version} failed: ${error instanceof Error ? error.message : String(error)}. Database may need manual repair.`);
10322
+ const version = migration?.version ?? currentVersion + 1;
10323
+ const description = migration?.description ?? "acquire migration write lock";
10324
+ log(`[migrations] FAILED v${version}: ${description} — ${error instanceof Error ? error.message : String(error)}`);
10325
+ throw new Error(`Migration v${version} failed: ${error instanceof Error ? error.message : String(error)}. Database may need manual repair.`);
10272
10326
  }
10273
10327
  }
10274
- log(`[migrations] schema version now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
10328
+ if (loggedPlan) {
10329
+ log(`[migrations] schema version now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
10330
+ }
10275
10331
  }
10276
10332
 
10277
10333
  // ../plugin/src/shared/commit-detection.ts
@@ -143025,7 +143081,8 @@ function countSessionsByStatus(db, status) {
143025
143081
  function acquireSessionLease(db, sessionId, now) {
143026
143082
  const expiresAt = now + LEASE_DURATION_MS;
143027
143083
  const result = db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, started_at, lease_expires_at)
143028
- VALUES (?, 'running', ?, ?)
143084
+ SELECT ?, 'running', ?, ?
143085
+ WHERE EXISTS (SELECT 1 FROM tags WHERE session_id = ?)
143029
143086
  ON CONFLICT(session_id) DO UPDATE SET
143030
143087
  status = 'running',
143031
143088
  started_at = excluded.started_at,
@@ -143033,7 +143090,7 @@ function acquireSessionLease(db, sessionId, now) {
143033
143090
  last_error = NULL
143034
143091
  WHERE tool_owner_backfill_state.status IN ('pending', 'skipped')
143035
143092
  OR (tool_owner_backfill_state.status = 'running'
143036
- AND tool_owner_backfill_state.lease_expires_at < ?)`).run(sessionId, now, expiresAt, now);
143093
+ AND tool_owner_backfill_state.lease_expires_at < ?)`).run(sessionId, now, expiresAt, sessionId, now);
143037
143094
  return (result.changes ?? 0) === 1;
143038
143095
  }
143039
143096
  function renewSessionLease(db, sessionId, now) {
@@ -143053,13 +143110,9 @@ function markSessionPendingRetry(db, sessionId) {
143053
143110
  WHERE session_id = ?`).run(sessionId);
143054
143111
  }
143055
143112
  function markSessionSkipped(db, sessionId, now, reason) {
143056
- db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, completed_at, last_error)
143057
- VALUES (?, 'skipped', ?, ?)
143058
- ON CONFLICT(session_id) DO UPDATE SET
143059
- status = 'skipped',
143060
- completed_at = excluded.completed_at,
143061
- last_error = excluded.last_error,
143062
- lease_expires_at = NULL`).run(sessionId, now, reason);
143113
+ db.prepare(`UPDATE tool_owner_backfill_state
143114
+ SET status = 'skipped', completed_at = ?, last_error = ?, lease_expires_at = NULL
143115
+ WHERE session_id = ? AND status = 'running'`).run(now, reason, sessionId);
143063
143116
  }
143064
143117
  function markSessionErrored(db, sessionId, error) {
143065
143118
  const message = error instanceof Error ? error.message : String(error);
@@ -143143,7 +143196,7 @@ function applyOwnersForSession(db, sessionId, ownersByCallId) {
143143
143196
  const result = updateRowStmt.run(ownerId, orphan.id);
143144
143197
  rowsUpdated += result.changes ?? 0;
143145
143198
  }
143146
- })();
143199
+ }).immediate();
143147
143200
  const rowsLeftNull = db.prepare(`SELECT COUNT(*) AS c FROM tags
143148
143201
  WHERE session_id = ? AND type = 'tool'
143149
143202
  AND tool_owner_message_id IS NULL`).get(sessionId).c;
@@ -143193,7 +143246,7 @@ var persistenceByDatabase = new WeakMap;
143193
143246
  var persistenceErrorByDatabase = new WeakMap;
143194
143247
  var pathByDatabase = new WeakMap;
143195
143248
  var lastSchemaFenceRejection = null;
143196
- var LATEST_SUPPORTED_VERSION = 50;
143249
+ var LATEST_SUPPORTED_VERSION = 52;
143197
143250
  var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
143198
143251
  function ensureSecureStorageDir(dir) {
143199
143252
  mkdirSync3(dir, { recursive: true, mode: 448 });
@@ -143886,6 +143939,17 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143886
143939
  pi_stable_id_scheme INTEGER
143887
143940
  );
143888
143941
 
143942
+ CREATE TABLE IF NOT EXISTS tool_owner_backfill_state (
143943
+ session_id TEXT PRIMARY KEY,
143944
+ status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'skipped')),
143945
+ started_at INTEGER,
143946
+ lease_expires_at INTEGER,
143947
+ completed_at INTEGER,
143948
+ last_error TEXT
143949
+ );
143950
+ CREATE INDEX IF NOT EXISTS idx_tool_owner_backfill_state_status
143951
+ ON tool_owner_backfill_state(status);
143952
+
143889
143953
  CREATE TABLE IF NOT EXISTS subagent_invocations (
143890
143954
  id INTEGER PRIMARY KEY AUTOINCREMENT,
143891
143955
  session_id TEXT NOT NULL,
@@ -144119,6 +144183,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
144119
144183
  ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
144120
144184
  ensureColumn(db, "session_meta", "detected_context_limit_model_key", "TEXT");
144121
144185
  ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
144186
+ ensureColumn(db, "session_meta", "emergency_recovery_origin", "TEXT DEFAULT ''");
144122
144187
  ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
144123
144188
  ensureColumn(db, "session_meta", "pending_pi_compaction_marker_state", "TEXT");
144124
144189
  ensureColumn(db, "session_meta", "new_work_tokens", "INTEGER NOT NULL DEFAULT 0");
@@ -159576,10 +159641,10 @@ function civilMinuteKey(date5) {
159576
159641
  const p = (n, w = 2) => String(n).padStart(w, "0");
159577
159642
  return `${p(date5.getFullYear(), 4)}-${p(date5.getMonth() + 1)}-${p(date5.getDate())} ${p(date5.getHours())}:${p(date5.getMinutes())}`;
159578
159643
  }
159579
- function nextOccurrence(cron, after, excludeCivilMinute) {
159644
+ function nextOccurrence(cron, after, excludeCivilMinute, maxSearchMs = MAX_SEARCH_MS) {
159580
159645
  const afterMs = after.getTime();
159581
159646
  let cursorMs = Math.floor(afterMs / MINUTE_MS) * MINUTE_MS + MINUTE_MS;
159582
- const capMs = afterMs + MAX_SEARCH_MS;
159647
+ const capMs = afterMs + Math.max(0, Math.min(MAX_SEARCH_MS, maxSearchMs));
159583
159648
  while (cursorMs <= capMs) {
159584
159649
  const candidate = new Date(cursorMs);
159585
159650
  if (matchesCron(cron, candidate)) {
@@ -159591,14 +159656,14 @@ function nextOccurrence(cron, after, excludeCivilMinute) {
159591
159656
  }
159592
159657
  return null;
159593
159658
  }
159594
- function nextDueAtMs(expression, afterMs, consumedScheduledAtMs) {
159659
+ function nextDueAtMs(expression, afterMs, consumedScheduledAtMs, maxSearchMs = MAX_SEARCH_MS) {
159595
159660
  if (expression.trim().length === 0)
159596
159661
  return null;
159597
159662
  const parsed = parseCron(expression);
159598
159663
  if (!parsed.ok)
159599
159664
  return null;
159600
159665
  const exclude = consumedScheduledAtMs !== undefined ? civilMinuteKey(new Date(consumedScheduledAtMs)) : undefined;
159601
- const next = nextOccurrence(parsed.cron, new Date(afterMs), exclude);
159666
+ const next = nextOccurrence(parsed.cron, new Date(afterMs), exclude, maxSearchMs);
159602
159667
  return next ? next.getTime() : null;
159603
159668
  }
159604
159669
 
@@ -160842,22 +160907,6 @@ function getInsertEmbeddingStatement(db) {
160842
160907
  }
160843
160908
  return stmt;
160844
160909
  }
160845
- function getClearProjectStatement(db) {
160846
- let stmt = clearProjectStatements.get(db);
160847
- if (!stmt) {
160848
- stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ?");
160849
- clearProjectStatements.set(db, stmt);
160850
- }
160851
- return stmt;
160852
- }
160853
- function getClearProjectModelStatement(db) {
160854
- let stmt = clearProjectModelStatements.get(db);
160855
- if (!stmt) {
160856
- stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ? AND model_id = ?");
160857
- clearProjectModelStatements.set(db, stmt);
160858
- }
160859
- return stmt;
160860
- }
160861
160910
  function getSearchRowsStatement(db, withModel) {
160862
160911
  const map2 = withModel ? searchRowsByModelStatements : searchRowsStatements;
160863
160912
  let stmt = map2.get(db);
@@ -161161,12 +161210,6 @@ function replaceCompartmentChunkEmbeddings(db, rows) {
161161
161210
  }
161162
161211
  })();
161163
161212
  }
161164
- function clearChunkEmbeddingsForProject(db, projectPath, modelId) {
161165
- if (modelId) {
161166
- return getClearProjectModelStatement(db).run(projectPath, modelId).changes;
161167
- }
161168
- return getClearProjectStatement(db).run(projectPath).changes;
161169
- }
161170
161213
  function loadCompartmentChunkEmbeddingsForSearch(db, sessionId, projectPath, modelId) {
161171
161214
  if (!modelId) {
161172
161215
  throw new Error("loadCompartmentChunkEmbeddingsForSearch requires a current model id");
@@ -162091,22 +162134,6 @@ function getLoadAllEmbeddingsStatement(db) {
162091
162134
  }
162092
162135
  return stmt;
162093
162136
  }
162094
- function getClearAllEmbeddingsStatement(db) {
162095
- let stmt = clearAllEmbeddingsStatements.get(db);
162096
- if (!stmt) {
162097
- stmt = db.prepare("DELETE FROM memory_embeddings WHERE memory_id IN (SELECT id FROM memories WHERE project_path = ?)");
162098
- clearAllEmbeddingsStatements.set(db, stmt);
162099
- }
162100
- return stmt;
162101
- }
162102
- function getClearModelEmbeddingsStatement(db) {
162103
- let stmt = clearModelEmbeddingsStatements.get(db);
162104
- if (!stmt) {
162105
- stmt = db.prepare("DELETE FROM memory_embeddings WHERE model_id = ? AND memory_id IN (SELECT id FROM memories WHERE project_path = ?)");
162106
- clearModelEmbeddingsStatements.set(db, stmt);
162107
- }
162108
- return stmt;
162109
- }
162110
162137
  function saveEmbedding(db, memoryId, embedding, modelId) {
162111
162138
  const blob = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
162112
162139
  getSaveEmbeddingStatement(db).run(memoryId, blob, modelId);
@@ -162126,12 +162153,6 @@ function loadAllEmbeddings(db, projectPath, modelId) {
162126
162153
  }
162127
162154
  return embeddings;
162128
162155
  }
162129
- function clearEmbeddingsForProject(db, projectPath, modelId) {
162130
- if (modelId) {
162131
- return getClearModelEmbeddingsStatement(db).run(modelId, projectPath).changes;
162132
- }
162133
- return getClearAllEmbeddingsStatement(db).run(projectPath).changes;
162134
- }
162135
162156
  function getMemoryEmbedCoverage(db, projectPath, modelId) {
162136
162157
  const row = db.prepare(`SELECT
162137
162158
  COUNT(*) AS total,
@@ -162204,24 +162225,6 @@ function getCountEmbeddedStatement(db) {
162204
162225
  }
162205
162226
  return stmt;
162206
162227
  }
162207
- function getClearProjectStatement2(db) {
162208
- let stmt = clearProjectStatements2.get(db);
162209
- if (!stmt) {
162210
- stmt = db.prepare(`DELETE FROM git_commit_embeddings
162211
- WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
162212
- clearProjectStatements2.set(db, stmt);
162213
- }
162214
- return stmt;
162215
- }
162216
- function getClearProjectModelStatement2(db) {
162217
- let stmt = clearProjectModelStatements2.get(db);
162218
- if (!stmt) {
162219
- stmt = db.prepare(`DELETE FROM git_commit_embeddings
162220
- WHERE model_id = ? AND sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
162221
- clearProjectModelStatements2.set(db, stmt);
162222
- }
162223
- return stmt;
162224
- }
162225
162228
  function saveCommitEmbedding(db, sha, embedding, modelId) {
162226
162229
  const bytes = new Uint8Array(embedding.buffer, embedding.byteOffset, embedding.byteLength);
162227
162230
  getSaveStatement(db).run(sha, bytes, modelId, Date.now());
@@ -162242,12 +162245,6 @@ function countEmbeddedCommits(db, projectPath, modelId) {
162242
162245
  const row = getCountEmbeddedStatement(db).get(projectPath, modelId);
162243
162246
  return row?.count ?? 0;
162244
162247
  }
162245
- function clearProjectCommitEmbeddings(db, projectPath, modelId) {
162246
- if (modelId) {
162247
- return getClearProjectModelStatement2(db).run(modelId, projectPath).changes;
162248
- }
162249
- return getClearProjectStatement2(db).run(projectPath).changes;
162250
- }
162251
162248
 
162252
162249
  // ../plugin/src/features/magic-context/git-commits/storage-git-commits.ts
162253
162250
  init_logger();
@@ -162549,6 +162546,7 @@ function invalidateMemory(projectPath, memoryId) {
162549
162546
  }
162550
162547
 
162551
162548
  // ../plugin/src/features/magic-context/session-project-storage.ts
162549
+ var SESSION_CHUNK_REPAIR_BATCH_SIZE = 100;
162552
162550
  var upsertSessionProjectStatements = new WeakMap;
162553
162551
  var repairSessionChunkProjectStatements = new WeakMap;
162554
162552
  var repairProjectChunkProjectStatements = new WeakMap;
@@ -162570,9 +162568,14 @@ function getRepairSessionChunkProjectStatement(db) {
162570
162568
  if (!stmt) {
162571
162569
  stmt = db.prepare(`UPDATE compartment_chunk_embeddings
162572
162570
  SET project_path = ?
162573
- WHERE session_id = ?
162574
- AND harness = ?
162575
- AND project_path <> ?`);
162571
+ WHERE id IN (
162572
+ SELECT id
162573
+ FROM compartment_chunk_embeddings
162574
+ WHERE session_id = ?
162575
+ AND harness = ?
162576
+ AND project_path <> ?
162577
+ LIMIT ?
162578
+ )`);
162576
162579
  repairSessionChunkProjectStatements.set(db, stmt);
162577
162580
  }
162578
162581
  return stmt;
@@ -162610,7 +162613,7 @@ function recordSessionProjectIdentity(db, sessionId, projectPath) {
162610
162613
  const now = Date.now();
162611
162614
  db.transaction(() => {
162612
162615
  getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
162613
- getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath);
162616
+ getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath, SESSION_CHUNK_REPAIR_BATCH_SIZE);
162614
162617
  })();
162615
162618
  }
162616
162619
  function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
@@ -162626,6 +162629,7 @@ var COMMIT_DRAIN_BATCH_SIZE = 16;
162626
162629
  var COMMIT_DRAIN_MAX_PER_SWEEP = 500;
162627
162630
  var CHUNK_DRAIN_BATCH_SIZE = 8;
162628
162631
  var EMBEDDING_IDENTITY_GC_GRACE_MS = 14 * 24 * 60 * 60 * 1000;
162632
+ var STALE_EMBEDDING_GC_BATCH_SIZE = 250;
162629
162633
  var MAX_WINDOWS_PER_EMBED_CALL = 2;
162630
162634
  var SESSION_EMBED_LEASE_RENEWAL_MS = 60 * 1000;
162631
162635
  var EMBED_SLICE_RETRY_ATTEMPTS = 3;
@@ -162854,6 +162858,55 @@ function staleModelsForScope(db, projectIdentity, scope, currentModelId, cutoff)
162854
162858
  const rows = getStaleIdentityStatement(db, scope).all(projectIdentity, scope, currentModelId, cutoff);
162855
162859
  return rows.map((row) => row.modelId).filter((modelId) => typeof modelId === "string");
162856
162860
  }
162861
+ function deleteStaleEmbeddingBatch(db, scope, projectIdentity, modelId, limit) {
162862
+ if (scope === "memory") {
162863
+ return db.prepare(`DELETE FROM memory_embeddings
162864
+ WHERE rowid IN (
162865
+ SELECT me.rowid
162866
+ FROM memory_embeddings me
162867
+ JOIN memories m ON m.id = me.memory_id
162868
+ WHERE m.project_path = ? AND me.model_id = ?
162869
+ LIMIT ?
162870
+ )`).run(projectIdentity, modelId, limit).changes;
162871
+ }
162872
+ if (scope === "commit") {
162873
+ return db.prepare(`DELETE FROM git_commit_embeddings
162874
+ WHERE rowid IN (
162875
+ SELECT gce.rowid
162876
+ FROM git_commit_embeddings gce
162877
+ JOIN git_commits gc ON gc.sha = gce.sha
162878
+ WHERE gc.project_path = ? AND gce.model_id = ?
162879
+ LIMIT ?
162880
+ )`).run(projectIdentity, modelId, limit).changes;
162881
+ }
162882
+ return db.prepare(`DELETE FROM compartment_chunk_embeddings
162883
+ WHERE id IN (
162884
+ SELECT id
162885
+ FROM compartment_chunk_embeddings
162886
+ WHERE project_path = ? AND model_id = ?
162887
+ LIMIT ?
162888
+ )`).run(projectIdentity, modelId, limit).changes;
162889
+ }
162890
+ function hasStaleEmbeddingRows(db, scope, projectIdentity, modelId) {
162891
+ if (scope === "memory") {
162892
+ return Boolean(db.prepare(`SELECT 1
162893
+ FROM memory_embeddings me
162894
+ JOIN memories m ON m.id = me.memory_id
162895
+ WHERE m.project_path = ? AND me.model_id = ?
162896
+ LIMIT 1`).get(projectIdentity, modelId));
162897
+ }
162898
+ if (scope === "commit") {
162899
+ return Boolean(db.prepare(`SELECT 1
162900
+ FROM git_commit_embeddings gce
162901
+ JOIN git_commits gc ON gc.sha = gce.sha
162902
+ WHERE gc.project_path = ? AND gce.model_id = ?
162903
+ LIMIT 1`).get(projectIdentity, modelId));
162904
+ }
162905
+ return Boolean(db.prepare(`SELECT 1
162906
+ FROM compartment_chunk_embeddings
162907
+ WHERE project_path = ? AND model_id = ?
162908
+ LIMIT 1`).get(projectIdentity, modelId));
162909
+ }
162857
162910
  function sweepStaleEmbeddingIdentitiesForProject(db, projectIdentity, now = Date.now()) {
162858
162911
  const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
162859
162912
  const result = {
@@ -162868,24 +162921,45 @@ function sweepStaleEmbeddingIdentitiesForProject(db, projectIdentity, now = Date
162868
162921
  return result;
162869
162922
  const cutoff = now - EMBEDDING_IDENTITY_GC_GRACE_MS;
162870
162923
  const deleteTracking = getDeleteActiveIdentityStatement(db);
162924
+ const scopes = [
162925
+ {
162926
+ scope: "memory",
162927
+ enabled: snapshot.enabled && snapshot.modelId !== "off",
162928
+ currentModelId: snapshot.modelId
162929
+ },
162930
+ {
162931
+ scope: "commit",
162932
+ enabled: snapshot.gitCommitEnabled && snapshot.modelId !== "off",
162933
+ currentModelId: snapshot.modelId
162934
+ },
162935
+ {
162936
+ scope: "chunk",
162937
+ enabled: snapshot.enabled && snapshot.chunkModelId !== "off",
162938
+ currentModelId: snapshot.chunkModelId
162939
+ }
162940
+ ];
162941
+ let remainingBudget = STALE_EMBEDDING_GC_BATCH_SIZE;
162871
162942
  db.exec("BEGIN IMMEDIATE");
162872
162943
  try {
162873
- if (snapshot.enabled && snapshot.modelId !== "off") {
162874
- for (const modelId of staleModelsForScope(db, projectIdentity, "memory", snapshot.modelId, cutoff)) {
162875
- result.memoryRowsDeleted += clearEmbeddingsForProject(db, projectIdentity, modelId);
162876
- result.trackingRowsDeleted += deleteTracking.run(projectIdentity, "memory", modelId).changes;
162877
- }
162878
- }
162879
- if (snapshot.gitCommitEnabled && snapshot.modelId !== "off") {
162880
- for (const modelId of staleModelsForScope(db, projectIdentity, "commit", snapshot.modelId, cutoff)) {
162881
- result.commitRowsDeleted += clearProjectCommitEmbeddings(db, projectIdentity, modelId);
162882
- result.trackingRowsDeleted += deleteTracking.run(projectIdentity, "commit", modelId).changes;
162883
- }
162884
- }
162885
- if (snapshot.enabled && snapshot.chunkModelId !== "off") {
162886
- for (const modelId of staleModelsForScope(db, projectIdentity, "chunk", snapshot.chunkModelId, cutoff)) {
162887
- result.chunkRowsDeleted += clearChunkEmbeddingsForProject(db, projectIdentity, modelId);
162888
- result.trackingRowsDeleted += deleteTracking.run(projectIdentity, "chunk", modelId).changes;
162944
+ for (const { scope, enabled, currentModelId } of scopes) {
162945
+ if (!enabled || remainingBudget === 0)
162946
+ continue;
162947
+ for (const modelId of staleModelsForScope(db, projectIdentity, scope, currentModelId, cutoff)) {
162948
+ if (remainingBudget === 0)
162949
+ break;
162950
+ const deleted = deleteStaleEmbeddingBatch(db, scope, projectIdentity, modelId, remainingBudget);
162951
+ remainingBudget -= deleted;
162952
+ if (scope === "memory")
162953
+ result.memoryRowsDeleted += deleted;
162954
+ else if (scope === "commit")
162955
+ result.commitRowsDeleted += deleted;
162956
+ else
162957
+ result.chunkRowsDeleted += deleted;
162958
+ if (!hasStaleEmbeddingRows(db, scope, projectIdentity, modelId)) {
162959
+ result.trackingRowsDeleted += deleteTracking.run(projectIdentity, scope, modelId).changes;
162960
+ } else if (deleted === 0) {
162961
+ remainingBudget = 0;
162962
+ }
162889
162963
  }
162890
162964
  }
162891
162965
  db.exec("COMMIT");
@@ -162895,9 +162969,8 @@ function sweepStaleEmbeddingIdentitiesForProject(db, projectIdentity, now = Date
162895
162969
  } catch {}
162896
162970
  throw error51;
162897
162971
  }
162898
- if (result.memoryRowsDeleted > 0) {
162972
+ if (result.memoryRowsDeleted > 0)
162899
162973
  invalidateProject(projectIdentity);
162900
- }
162901
162974
  return result;
162902
162975
  }
162903
162976
  function registerProjectEmbedding(db, projectIdentity, config2, features, sourceDirectory) {
@@ -163117,16 +163190,27 @@ async function drainCommitBacklogForProject(db, projectIdentity, deadline) {
163117
163190
  return 0;
163118
163191
  }
163119
163192
  let total = 0;
163193
+ let leaseLost = false;
163194
+ const renewal = setInterval(() => {
163195
+ try {
163196
+ if (!renewGitSweepLease(db, projectIdentity, holderId))
163197
+ leaseLost = true;
163198
+ } catch {}
163199
+ }, SESSION_EMBED_LEASE_RENEWAL_MS);
163200
+ renewal.unref?.();
163120
163201
  try {
163121
- while (Date.now() < deadline && total < COMMIT_DRAIN_MAX_PER_SWEEP) {
163202
+ while (!leaseLost && Date.now() < deadline && total < COMMIT_DRAIN_MAX_PER_SWEEP) {
163122
163203
  const embedded = await embedCommitBatch(db, projectIdentity, COMMIT_DRAIN_BATCH_SIZE);
163123
- if (embedded === 0)
163204
+ if (!renewGitSweepLease(db, projectIdentity, holderId))
163205
+ leaseLost = true;
163206
+ if (leaseLost || embedded === 0)
163124
163207
  break;
163125
163208
  total += embedded;
163126
163209
  if (embedded < COMMIT_DRAIN_BATCH_SIZE)
163127
163210
  break;
163128
163211
  }
163129
163212
  } finally {
163213
+ clearInterval(renewal);
163130
163214
  releaseGitSweepLease(db, projectIdentity, holderId);
163131
163215
  }
163132
163216
  return total;
@@ -163237,9 +163321,19 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
163237
163321
  const lease = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
163238
163322
  if (!lease.acquired)
163239
163323
  return { status: "busy", embedded: 0, total };
163324
+ let leaseLost = false;
163325
+ const drainAbort = new AbortController;
163326
+ const forwardCallerAbort = () => drainAbort.abort();
163327
+ if (options?.signal?.aborted)
163328
+ drainAbort.abort();
163329
+ else
163330
+ options?.signal?.addEventListener("abort", forwardCallerAbort, { once: true });
163240
163331
  const renewal = setInterval(() => {
163241
163332
  try {
163242
- renewGitSweepLease(db, projectIdentity, holderId);
163333
+ if (!renewGitSweepLease(db, projectIdentity, holderId)) {
163334
+ leaseLost = true;
163335
+ drainAbort.abort();
163336
+ }
163243
163337
  } catch {}
163244
163338
  }, SESSION_EMBED_LEASE_RENEWAL_MS);
163245
163339
  renewal.unref?.();
@@ -163253,7 +163347,7 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
163253
163347
  try {
163254
163348
  options?.onProgress?.({ embedded, total });
163255
163349
  for (;; ) {
163256
- if (options?.signal?.aborted) {
163350
+ if (leaseLost || drainAbort.signal.aborted) {
163257
163351
  aborted2 = true;
163258
163352
  break;
163259
163353
  }
@@ -163264,7 +163358,13 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
163264
163358
  embedded: n,
163265
163359
  noWork,
163266
163360
  failed
163267
- } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, options?.signal);
163361
+ } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, drainAbort.signal);
163362
+ if (leaseLost || !renewGitSweepLease(db, projectIdentity, holderId)) {
163363
+ leaseLost = true;
163364
+ drainAbort.abort();
163365
+ aborted2 = true;
163366
+ break;
163367
+ }
163268
163368
  for (const id of noWork)
163269
163369
  skipIds.push(id);
163270
163370
  for (const id of failed)
@@ -163284,6 +163384,7 @@ async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, opt
163284
163384
  }
163285
163385
  } finally {
163286
163386
  clearInterval(renewal);
163387
+ options?.signal?.removeEventListener("abort", forwardCallerAbort);
163287
163388
  try {
163288
163389
  releaseGitSweepLease(db, projectIdentity, holderId);
163289
163390
  } catch (error51) {
@@ -164199,6 +164300,66 @@ function readRawSessionMessagesFromDb(db, sessionId) {
164199
164300
  };
164200
164301
  });
164201
164302
  }
164303
+ function readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, finalWatermark = Number.MAX_SAFE_INTEGER) {
164304
+ const remaining = Math.max(0, Math.floor(finalWatermark) - Math.floor(afterOrdinal));
164305
+ const pageSize = Math.min(Math.max(1, Math.floor(limit)), remaining);
164306
+ if (pageSize === 0)
164307
+ return [];
164308
+ const messageRows = db.prepare(`SELECT id, data, time_created, time_updated
164309
+ FROM message
164310
+ WHERE session_id = ?
164311
+ AND NOT (
164312
+ CASE WHEN json_valid(data) = 1
164313
+ THEN COALESCE(json_extract(data, '$.summary'), 0)
164314
+ ELSE 0 END = 1
164315
+ AND CASE WHEN json_valid(data) = 1
164316
+ THEN COALESCE(json_extract(data, '$.finish'), '')
164317
+ ELSE '' END = 'stop'
164318
+ )
164319
+ ORDER BY time_created ASC, id ASC
164320
+ LIMIT ? OFFSET ?`).all(sessionId, pageSize, Math.max(0, Math.floor(afterOrdinal))).filter(isRawMessageRow).map((row, index) => ({
164321
+ ...row,
164322
+ ordinal: Math.floor(afterOrdinal) + index + 1
164323
+ }));
164324
+ if (messageRows.length === 0)
164325
+ return [];
164326
+ const placeholders2 = messageRows.map(() => "?").join(", ");
164327
+ const partRows = db.prepare(`SELECT message_id, data, time_updated
164328
+ FROM part
164329
+ WHERE session_id = ? AND message_id IN (${placeholders2})
164330
+ ORDER BY time_created ASC, id ASC`).all(sessionId, ...messageRows.map((row) => row.id)).filter(isRawPartRow);
164331
+ const partsByMessageId = new Map;
164332
+ for (const part of partRows) {
164333
+ const list = partsByMessageId.get(part.message_id) ?? [];
164334
+ list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
164335
+ partsByMessageId.set(part.message_id, list);
164336
+ }
164337
+ return messageRows.map((row) => {
164338
+ const info = parseJsonRecord(row.data);
164339
+ return {
164340
+ ordinal: row.ordinal,
164341
+ id: row.id,
164342
+ role: typeof info?.role === "string" ? info.role : "unknown",
164343
+ parts: partsByMessageId.get(row.id) ?? [],
164344
+ createdAt: row.time_created ?? null,
164345
+ version: row.time_updated ?? null
164346
+ };
164347
+ });
164348
+ }
164349
+ function countRawSessionMessageOrdinalsFromDb(db, sessionId) {
164350
+ const row = db.prepare(`SELECT COUNT(*) AS count
164351
+ FROM message
164352
+ WHERE session_id = ?
164353
+ AND NOT (
164354
+ CASE WHEN json_valid(data) = 1
164355
+ THEN COALESCE(json_extract(data, '$.summary'), 0)
164356
+ ELSE 0 END = 1
164357
+ AND CASE WHEN json_valid(data) = 1
164358
+ THEN COALESCE(json_extract(data, '$.finish'), '')
164359
+ ELSE '' END = 'stop'
164360
+ )`).get(sessionId);
164361
+ return typeof row?.count === "number" ? row.count : 0;
164362
+ }
164202
164363
  function isAnchorRow(row) {
164203
164364
  return row !== null && typeof row === "object" && typeof row.time_created === "number" && typeof row.id === "string";
164204
164365
  }
@@ -164506,6 +164667,31 @@ function readRawSessionMessages(sessionId) {
164506
164667
  }
164507
164668
  return readRawSessionMessagesFromSource(sessionId);
164508
164669
  }
164670
+ function readRawSessionMessagePage(sessionId, afterOrdinal, limit, finalWatermark) {
164671
+ const provider2 = sessionProviders.get(sessionId);
164672
+ if (provider2?.readMessagePage) {
164673
+ return provider2.readMessagePage(afterOrdinal, limit, finalWatermark);
164674
+ }
164675
+ if (provider2) {
164676
+ return provider2.readMessages().filter((message) => message.ordinal > afterOrdinal && message.ordinal <= finalWatermark).slice(0, limit);
164677
+ }
164678
+ if (!openCodeDbExists())
164679
+ return [];
164680
+ return withReadOnlySessionDb((db) => readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, finalWatermark));
164681
+ }
164682
+ function getRawSessionMessageOrdinalCount(sessionId) {
164683
+ const provider2 = sessionProviders.get(sessionId);
164684
+ if (provider2) {
164685
+ if (provider2.getMessageCount)
164686
+ return provider2.getMessageCount();
164687
+ return provider2.readMessages().length;
164688
+ }
164689
+ if (!openCodeDbExists())
164690
+ return 0;
164691
+ return withReadOnlySessionDb((db) => countRawSessionMessageOrdinalsFromDb(db, sessionId));
164692
+ }
164693
+ readRawSessionMessages.readPage = readRawSessionMessagePage;
164694
+ readRawSessionMessages.getCount = getRawSessionMessageOrdinalCount;
164509
164695
  function primeTailRawMessageCache(args) {
164510
164696
  const { sessionId, lastCompartmentEnd, anchorMessageId } = args;
164511
164697
  if (!activeRawMessageCache)
@@ -170663,11 +170849,10 @@ async function normalizeVerificationFiles(args) {
170663
170849
  // ../plugin/src/features/magic-context/message-index.ts
170664
170850
  var lastIndexedStatements = new WeakMap;
170665
170851
  var insertMessageStatements = new WeakMap;
170666
- var upsertIndexStatements = new WeakMap;
170667
- var upsertCleanIndexStatements = new WeakMap;
170852
+ var upsertProgressStatements = new WeakMap;
170668
170853
  var upsertDirtyFloorStatements = new WeakMap;
170669
170854
  var deleteFtsStatements = new WeakMap;
170670
- var deleteFtsFromOrdinalStatements = new WeakMap;
170855
+ var deleteFtsRangeStatements = new WeakMap;
170671
170856
  var deleteIndexStatements = new WeakMap;
170672
170857
  var countIndexedMessageStatements = new WeakMap;
170673
170858
  function normalizeIndexText(text) {
@@ -170689,19 +170874,11 @@ function getInsertMessageStatement(db) {
170689
170874
  }
170690
170875
  return stmt;
170691
170876
  }
170692
- function getUpsertIndexStatement(db) {
170693
- let stmt = upsertIndexStatements.get(db);
170694
- if (!stmt) {
170695
- stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, updated_at, harness) VALUES (?, ?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET last_indexed_ordinal = excluded.last_indexed_ordinal, updated_at = excluded.updated_at");
170696
- upsertIndexStatements.set(db, stmt);
170697
- }
170698
- return stmt;
170699
- }
170700
- function getUpsertCleanIndexStatement(db) {
170701
- let stmt = upsertCleanIndexStatements.get(db);
170877
+ function getUpsertProgressStatement(db) {
170878
+ let stmt = upsertProgressStatements.get(db);
170702
170879
  if (!stmt) {
170703
- stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, dirty_floor_ordinal, updated_at, harness) VALUES (?, ?, 0, ?, ?) ON CONFLICT(session_id) DO UPDATE SET last_indexed_ordinal = excluded.last_indexed_ordinal, dirty_floor_ordinal = 0, updated_at = excluded.updated_at");
170704
- upsertCleanIndexStatements.set(db, stmt);
170880
+ stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, dirty_floor_ordinal, updated_at, harness) VALUES (?, ?, ?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET last_indexed_ordinal = excluded.last_indexed_ordinal, dirty_floor_ordinal = excluded.dirty_floor_ordinal, updated_at = excluded.updated_at");
170881
+ upsertProgressStatements.set(db, stmt);
170705
170882
  }
170706
170883
  return stmt;
170707
170884
  }
@@ -170713,27 +170890,11 @@ function getUpsertDirtyFloorStatement(db) {
170713
170890
  }
170714
170891
  return stmt;
170715
170892
  }
170716
- function getDeleteFtsStatement(db) {
170717
- let stmt = deleteFtsStatements.get(db);
170718
- if (!stmt) {
170719
- stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ?");
170720
- deleteFtsStatements.set(db, stmt);
170721
- }
170722
- return stmt;
170723
- }
170724
- function getDeleteFtsFromOrdinalStatement(db) {
170725
- let stmt = deleteFtsFromOrdinalStatements.get(db);
170893
+ function getDeleteFtsRangeStatement(db) {
170894
+ let stmt = deleteFtsRangeStatements.get(db);
170726
170895
  if (!stmt) {
170727
- stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ? AND CAST(message_ordinal AS INTEGER) >= ?");
170728
- deleteFtsFromOrdinalStatements.set(db, stmt);
170729
- }
170730
- return stmt;
170731
- }
170732
- function getDeleteIndexStatement(db) {
170733
- let stmt = deleteIndexStatements.get(db);
170734
- if (!stmt) {
170735
- stmt = db.prepare("DELETE FROM message_history_index WHERE session_id = ?");
170736
- deleteIndexStatements.set(db, stmt);
170896
+ stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ? AND CAST(message_ordinal AS INTEGER) BETWEEN ? AND ?");
170897
+ deleteFtsRangeStatements.set(db, stmt);
170737
170898
  }
170738
170899
  return stmt;
170739
170900
  }
@@ -170761,16 +170922,17 @@ function isMessageAlreadyIndexed(db, sessionId, messageId) {
170761
170922
  const row = getCountIndexedMessageStatement(db).get(sessionId, messageId);
170762
170923
  return (typeof row?.count === "number" ? row.count : 0) > 0;
170763
170924
  }
170764
- function advanceIndexWatermark(db, sessionId, ordinal, now) {
170765
- const current = getLastIndexedOrdinal(db, sessionId);
170766
- getUpsertIndexStatement(db).run(sessionId, Math.max(current, ordinal), now, getHarness());
170925
+ function setIndexProgress(db, sessionId, watermark, dirtyFloor, now) {
170926
+ getUpsertProgressStatement(db).run(sessionId, Math.max(0, Math.floor(watermark)), dirtyFloor ?? 0, now, getHarness());
170767
170927
  }
170768
- function clearIndexedMessages(db, sessionId) {
170769
- db.transaction(() => {
170770
- getDeleteFtsStatement(db).run(sessionId);
170771
- getDeleteIndexStatement(db).run(sessionId);
170772
- clearCompressionDepth(db, sessionId);
170773
- })();
170928
+ function getMessageIndexReconciliationStartOrdinal(db, sessionId) {
170929
+ const watermark = getLastIndexedOrdinal(db, sessionId);
170930
+ const dirtyFloor = getDirtyIndexFloor(db, sessionId);
170931
+ return dirtyFloor === null ? watermark : Math.min(watermark, dirtyFloor - 1);
170932
+ }
170933
+ function isMessageIndexReconciledThrough(db, sessionId, finalWatermark) {
170934
+ const dirtyFloor = getDirtyIndexFloor(db, sessionId);
170935
+ return getLastIndexedOrdinal(db, sessionId) >= finalWatermark && dirtyFloor === null;
170774
170936
  }
170775
170937
  function getIndexableContent(role, parts) {
170776
170938
  if (role === "user") {
@@ -170785,22 +170947,21 @@ function getIndexableContent(role, parts) {
170785
170947
  return "";
170786
170948
  }
170787
170949
  function indexSingleMessageInTransaction(db, sessionId, message, now) {
170788
- if (message.role !== "user" && message.role !== "assistant") {
170789
- advanceIndexWatermark(db, sessionId, message.ordinal, now);
170790
- return false;
170791
- }
170792
- const content = getIndexableContent(message.role, message.parts);
170793
- if (content.length === 0) {
170794
- advanceIndexWatermark(db, sessionId, message.ordinal, now);
170950
+ const currentWatermark = getLastIndexedOrdinal(db, sessionId);
170951
+ const dirtyFloor = getDirtyIndexFloor(db, sessionId);
170952
+ if (message.ordinal !== currentWatermark + 1 || dirtyFloor !== null && dirtyFloor !== message.ordinal) {
170795
170953
  return false;
170796
170954
  }
170797
- if (isMessageAlreadyIndexed(db, sessionId, message.id)) {
170798
- advanceIndexWatermark(db, sessionId, message.ordinal, now);
170799
- return false;
170955
+ let inserted = false;
170956
+ if (message.role === "user" || message.role === "assistant") {
170957
+ const content = getIndexableContent(message.role, message.parts);
170958
+ if (content.length > 0 && !isMessageAlreadyIndexed(db, sessionId, message.id)) {
170959
+ getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
170960
+ inserted = true;
170961
+ }
170800
170962
  }
170801
- getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
170802
- advanceIndexWatermark(db, sessionId, message.ordinal, now);
170803
- return true;
170963
+ setIndexProgress(db, sessionId, message.ordinal, null, now);
170964
+ return inserted;
170804
170965
  }
170805
170966
  function indexSingleMessage(db, sessionId, message) {
170806
170967
  db.exec("BEGIN IMMEDIATE");
@@ -170818,38 +170979,44 @@ function indexSingleMessage(db, sessionId, message) {
170818
170979
  }
170819
170980
  }
170820
170981
  }
170821
- function indexMessagesAfterOrdinal(db, sessionId, messages, lastIndexedOrdinal, finalWatermark = messages.length) {
170982
+ function indexMessagesAfterOrdinal(db, sessionId, messages, _lastIndexedOrdinal, finalWatermark = messages.length) {
170822
170983
  const now = Date.now();
170823
170984
  let inserted = 0;
170824
170985
  db.exec("BEGIN IMMEDIATE");
170825
170986
  let committed = false;
170826
170987
  try {
170827
- let effectiveWatermark = Math.max(lastIndexedOrdinal, getLastIndexedOrdinal(db, sessionId));
170988
+ const currentWatermark = getLastIndexedOrdinal(db, sessionId);
170828
170989
  const dirtyFloor = getDirtyIndexFloor(db, sessionId);
170829
- if (dirtyFloor !== null) {
170830
- const rewindOrdinal = Math.max(1, Math.min(dirtyFloor, finalWatermark + 1));
170831
- if (rewindOrdinal <= finalWatermark) {
170832
- getDeleteFtsFromOrdinalStatement(db).run(sessionId, rewindOrdinal);
170833
- }
170834
- effectiveWatermark = Math.min(effectiveWatermark, rewindOrdinal - 1);
170990
+ const effectiveWatermark = dirtyFloor === null ? currentWatermark : Math.min(currentWatermark, Math.max(0, dirtyFloor - 1));
170991
+ if (dirtyFloor !== null && dirtyFloor <= finalWatermark) {
170992
+ getDeleteFtsRangeStatement(db).run(sessionId, dirtyFloor, finalWatermark);
170835
170993
  }
170836
- const insertMessage = getInsertMessageStatement(db);
170994
+ const messagesByOrdinal = new Map;
170837
170995
  for (const message of messages) {
170838
- if (message.ordinal <= effectiveWatermark) {
170839
- continue;
170996
+ if (message.ordinal > effectiveWatermark && message.ordinal <= finalWatermark) {
170997
+ messagesByOrdinal.set(message.ordinal, message);
170840
170998
  }
170841
- if (message.role !== "user" && message.role !== "assistant") {
170999
+ }
171000
+ let coveredWatermark = effectiveWatermark;
171001
+ while (coveredWatermark < finalWatermark && messagesByOrdinal.has(coveredWatermark + 1)) {
171002
+ coveredWatermark += 1;
171003
+ }
171004
+ for (let ordinal = effectiveWatermark + 1;ordinal <= coveredWatermark; ordinal++) {
171005
+ const message = messagesByOrdinal.get(ordinal);
171006
+ if (!message || message.role !== "user" && message.role !== "assistant") {
170842
171007
  continue;
170843
171008
  }
170844
171009
  const content = getIndexableContent(message.role, message.parts);
170845
- if (content.length === 0) {
171010
+ if (content.length === 0 || isMessageAlreadyIndexed(db, sessionId, message.id)) {
170846
171011
  continue;
170847
171012
  }
170848
- insertMessage.run(sessionId, message.ordinal, message.id, message.role, content);
170849
- inserted++;
171013
+ getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
171014
+ inserted += 1;
170850
171015
  }
170851
- const newWatermark = Math.max(effectiveWatermark, finalWatermark);
170852
- getUpsertCleanIndexStatement(db).run(sessionId, newWatermark, now, getHarness());
171016
+ const missingFloor = coveredWatermark < finalWatermark ? coveredWatermark + 1 : null;
171017
+ const preservedFloor = dirtyFloor !== null && dirtyFloor > finalWatermark ? dirtyFloor : null;
171018
+ const nextDirtyFloor = missingFloor === null ? preservedFloor : preservedFloor === null ? missingFloor : Math.min(missingFloor, preservedFloor);
171019
+ setIndexProgress(db, sessionId, coveredWatermark, nextDirtyFloor, now);
170853
171020
  db.exec("COMMIT");
170854
171021
  committed = true;
170855
171022
  } finally {
@@ -171990,13 +172157,17 @@ function clearHistorianFailureState(db, sessionId) {
171990
172157
  function normalizeDetectedLimitModelKey(modelKey) {
171991
172158
  return typeof modelKey === "string" && modelKey.length > 0 ? modelKey : null;
171992
172159
  }
172160
+ function normalizeEmergencyRecoveryOrigin(value) {
172161
+ return value === "provider_overflow" || value === "proactive_model_shrink" ? value : null;
172162
+ }
171993
172163
  function getOverflowState(db, sessionId, modelKey) {
171994
- const result = db.prepare("SELECT detected_context_limit, detected_context_limit_model_key, needs_emergency_recovery FROM session_meta WHERE session_id = ?").get(sessionId);
172164
+ const result = db.prepare("SELECT detected_context_limit, detected_context_limit_model_key, needs_emergency_recovery, emergency_recovery_origin FROM session_meta WHERE session_id = ?").get(sessionId);
171995
172165
  if (!result) {
171996
172166
  return {
171997
172167
  detectedContextLimit: 0,
171998
172168
  detectedContextLimitModelKey: null,
171999
- needsEmergencyRecovery: false
172169
+ needsEmergencyRecovery: false,
172170
+ emergencyRecoveryOrigin: null
172000
172171
  };
172001
172172
  }
172002
172173
  const storedModelKey = normalizeDetectedLimitModelKey(result.detected_context_limit_model_key);
@@ -172004,19 +172175,22 @@ function getOverflowState(db, sessionId, modelKey) {
172004
172175
  const limit = typeof result.detected_context_limit === "number" && result.detected_context_limit > 0 ? result.detected_context_limit : 0;
172005
172176
  const modelMatches = limit > 0 && requestedModelKey && storedModelKey ? requestedModelKey === storedModelKey : true;
172006
172177
  const needs = typeof result.needs_emergency_recovery === "number" && result.needs_emergency_recovery > 0;
172178
+ const persistedOrigin = normalizeEmergencyRecoveryOrigin(result.emergency_recovery_origin);
172179
+ const recoveryOrigin = needs ? persistedOrigin ?? (limit > 0 ? "provider_overflow" : null) : null;
172007
172180
  return {
172008
172181
  detectedContextLimit: modelMatches ? limit : 0,
172009
172182
  detectedContextLimitModelKey: storedModelKey,
172010
- needsEmergencyRecovery: needs
172183
+ needsEmergencyRecovery: needs,
172184
+ emergencyRecoveryOrigin: recoveryOrigin
172011
172185
  };
172012
172186
  }
172013
- function recordOverflowDetected(db, sessionId, reportedLimit, modelKey) {
172187
+ function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin = "provider_overflow") {
172014
172188
  db.transaction(() => {
172015
172189
  ensureSessionMetaRow(db, sessionId);
172016
172190
  if (typeof reportedLimit === "number" && reportedLimit > 0) {
172017
- db.prepare("UPDATE session_meta SET detected_context_limit = ?, detected_context_limit_model_key = ?, needs_emergency_recovery = 1, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, normalizeDetectedLimitModelKey(modelKey), sessionId);
172191
+ db.prepare("UPDATE session_meta SET detected_context_limit = ?, detected_context_limit_model_key = ?, needs_emergency_recovery = 1, emergency_recovery_origin = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, normalizeDetectedLimitModelKey(modelKey), origin, sessionId);
172018
172192
  } else {
172019
- db.prepare("UPDATE session_meta SET needs_emergency_recovery = 1, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(sessionId);
172193
+ db.prepare("UPDATE session_meta SET needs_emergency_recovery = 1, emergency_recovery_origin = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(origin, sessionId);
172020
172194
  }
172021
172195
  })();
172022
172196
  }
@@ -172024,9 +172198,9 @@ function clearEmergencyRecovery(db, sessionId) {
172024
172198
  db.transaction(() => {
172025
172199
  ensureSessionMetaRow(db, sessionId);
172026
172200
  try {
172027
- db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0, recovery_no_eligible_head_count = 0 WHERE session_id = ?").run(sessionId);
172201
+ db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0, emergency_recovery_origin = '', recovery_no_eligible_head_count = 0 WHERE session_id = ?").run(sessionId);
172028
172202
  } catch {
172029
- db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0 WHERE session_id = ?").run(sessionId);
172203
+ db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0, emergency_recovery_origin = '' WHERE session_id = ?").run(sessionId);
172030
172204
  }
172031
172205
  })();
172032
172206
  }
@@ -175768,6 +175942,30 @@ class BoundedSessionMap {
175768
175942
  // ../plugin/src/hooks/magic-context/inject-compartments.ts
175769
175943
  init_logger();
175770
175944
 
175945
+ // ../plugin/src/hooks/magic-context/compartment-render-epoch.ts
175946
+ var COMPARTMENT_RENDER_EPOCH = "cre2";
175947
+ var EPOCH_COMPONENT_PREFIX = "|compartment-render:";
175948
+ function encodeCachedM0UpgradeIdentity(upgradeState, compartmentRenderEpoch = COMPARTMENT_RENDER_EPOCH) {
175949
+ if (compartmentRenderEpoch === null)
175950
+ return upgradeState;
175951
+ return `${upgradeState ?? ""}${EPOCH_COMPONENT_PREFIX}${compartmentRenderEpoch}`;
175952
+ }
175953
+ function decodeCachedM0UpgradeIdentity(value) {
175954
+ if (value === null) {
175955
+ return { upgradeState: null, compartmentRenderEpoch: null };
175956
+ }
175957
+ const componentIndex = value.lastIndexOf(EPOCH_COMPONENT_PREFIX);
175958
+ if (componentIndex < 0) {
175959
+ return { upgradeState: value, compartmentRenderEpoch: null };
175960
+ }
175961
+ const upgradeState = value.slice(0, componentIndex);
175962
+ const compartmentRenderEpoch = value.slice(componentIndex + EPOCH_COMPONENT_PREFIX.length);
175963
+ return {
175964
+ upgradeState: upgradeState.length > 0 ? upgradeState : null,
175965
+ compartmentRenderEpoch: compartmentRenderEpoch.length > 0 ? compartmentRenderEpoch : null
175966
+ };
175967
+ }
175968
+
175771
175969
  // ../plugin/src/hooks/magic-context/decay-curve.ts
175772
175970
  var H50 = 24;
175773
175971
  var D = 25;
@@ -175837,10 +176035,13 @@ function formatDateRange(startDate, endDate) {
175837
176035
  return `${startDate}→${endDate.slice(8)}`;
175838
176036
  return `${startDate}→${endDate}`;
175839
176037
  }
176038
+ function sanitizeCompartmentTitle(title) {
176039
+ return escapeXmlContent2(title.replace(/[\p{Cc}\p{Zl}\p{Zp}]+/gu, " "));
176040
+ }
175840
176041
  function compartmentHeading(c) {
175841
176042
  const dateRange = formatDateRange(c.startDate, c.endDate);
175842
176043
  const dateSegment = dateRange ? ` · ${dateRange}` : "";
175843
- return `## ${c.startMessage}-${c.endMessage}${dateSegment} · ${c.title}`;
176044
+ return `## ${c.startMessage}-${c.endMessage}${dateSegment} · ${sanitizeCompartmentTitle(c.title)}`;
175844
176045
  }
175845
176046
  function guardCompartmentBody(body) {
175846
176047
  return body.replace(/^## /gm, " ## ");