@wolfx/pi-magic-context 0.22.1-patch.0 → 0.22.3

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.
@@ -86,9 +86,6 @@ function getMagicContextStorageDir() {
86
86
  function getLegacyOpenCodeMagicContextStorageDir() {
87
87
  return path.join(getOpenCodeStorageDir(), "plugin", "magic-context");
88
88
  }
89
- function getCacheDir() {
90
- return process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), ".cache");
91
- }
92
89
  var init_data_path = () => {};
93
90
 
94
91
  // ../plugin/src/shared/logger.ts
@@ -8919,6 +8916,38 @@ var MIGRATIONS = [
8919
8916
  ON tags(session_id, entry_fingerprint)
8920
8917
  WHERE type='message' AND entry_fingerprint IS NOT NULL`);
8921
8918
  }
8919
+ },
8920
+ {
8921
+ version: 28,
8922
+ description: "Add git commit sweep coordinator lease/cooldown table",
8923
+ up: (db) => {
8924
+ db.exec(`
8925
+ CREATE TABLE IF NOT EXISTS git_sweep_coordinator (
8926
+ project_path TEXT PRIMARY KEY,
8927
+ lease_holder TEXT,
8928
+ lease_expires_at INTEGER,
8929
+ last_swept_at INTEGER
8930
+ );
8931
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_lease_expires
8932
+ ON git_sweep_coordinator(lease_expires_at);
8933
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_last_swept
8934
+ ON git_sweep_coordinator(last_swept_at);
8935
+ `);
8936
+ }
8937
+ },
8938
+ {
8939
+ version: 29,
8940
+ description: "Add anchor_ordinal to notes (traceback to the conversation tail)",
8941
+ up: (db) => {
8942
+ const notesExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='notes'").get();
8943
+ if (!notesExists) {
8944
+ return;
8945
+ }
8946
+ const columns = db.prepare("PRAGMA table_info(notes)").all();
8947
+ if (!columns.some((column) => column.name === "anchor_ordinal")) {
8948
+ db.exec("ALTER TABLE notes ADD COLUMN anchor_ordinal INTEGER");
8949
+ }
8950
+ }
8922
8951
  }
8923
8952
  ];
8924
8953
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -141883,7 +141912,7 @@ var databases = new Map;
141883
141912
  var persistenceByDatabase = new WeakMap;
141884
141913
  var persistenceErrorByDatabase = new WeakMap;
141885
141914
  var lastSchemaFenceRejection = null;
141886
- var LATEST_SUPPORTED_VERSION = 27;
141915
+ var LATEST_SUPPORTED_VERSION = 29;
141887
141916
  function resolveDatabasePath(dbPathOverride) {
141888
141917
  if (dbPathOverride) {
141889
141918
  return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
@@ -142203,6 +142232,17 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
142203
142232
  updated_at INTEGER NOT NULL DEFAULT 0
142204
142233
  );
142205
142234
 
142235
+ CREATE TABLE IF NOT EXISTS git_sweep_coordinator (
142236
+ project_path TEXT PRIMARY KEY,
142237
+ lease_holder TEXT,
142238
+ lease_expires_at INTEGER,
142239
+ last_swept_at INTEGER
142240
+ );
142241
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_lease_expires
142242
+ ON git_sweep_coordinator(lease_expires_at);
142243
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_last_swept
142244
+ ON git_sweep_coordinator(last_swept_at);
142245
+
142206
142246
  CREATE TABLE IF NOT EXISTS m0_mutation_log (
142207
142247
  id INTEGER PRIMARY KEY AUTOINCREMENT,
142208
142248
  session_id TEXT NOT NULL,
@@ -157409,46 +157449,6 @@ function stripJsonComments(content) {
157409
157449
  }
157410
157450
  return result;
157411
157451
  }
157412
- function stripTrailingCommas(content) {
157413
- let result = "";
157414
- let inString = false;
157415
- let escaped = false;
157416
- for (let index = 0;index < content.length; index += 1) {
157417
- const char = content[index];
157418
- if (inString) {
157419
- result += char;
157420
- if (escaped) {
157421
- escaped = false;
157422
- } else if (char === "\\") {
157423
- escaped = true;
157424
- } else if (char === '"') {
157425
- inString = false;
157426
- }
157427
- continue;
157428
- }
157429
- if (char === '"') {
157430
- inString = true;
157431
- result += char;
157432
- continue;
157433
- }
157434
- if (char === ",") {
157435
- let lookahead = index + 1;
157436
- while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
157437
- lookahead += 1;
157438
- }
157439
- const next = content[lookahead];
157440
- if (next === "}" || next === "]") {
157441
- continue;
157442
- }
157443
- }
157444
- result += char;
157445
- }
157446
- return result;
157447
- }
157448
- function parseJsonc(content) {
157449
- const normalized = stripTrailingCommas(stripJsonComments(content));
157450
- return JSON.parse(normalized);
157451
- }
157452
157452
 
157453
157453
  // ../plugin/src/config/variable.ts
157454
157454
  var ENV_PATTERN = /\{env:([^}]+)\}/g;
@@ -158448,7 +158448,7 @@ function getDistinctStoredModelIds(db, projectPath) {
158448
158448
  }
158449
158449
 
158450
158450
  // ../plugin/src/features/magic-context/project-embedding-registry.ts
158451
- import { createHash as createHash3 } from "node:crypto";
158451
+ import { createHash as createHash3, randomUUID } from "node:crypto";
158452
158452
  init_logger();
158453
158453
 
158454
158454
  // ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
@@ -158552,6 +158552,125 @@ function getDistinctCommitEmbeddingModelIds(db, projectPath) {
158552
158552
  return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
158553
158553
  }
158554
158554
 
158555
+ // ../plugin/src/features/magic-context/git-commits/sweep-coordinator.ts
158556
+ var GIT_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
158557
+ var GIT_SWEEP_LEASE_TTL_MS = 5 * 60 * 1000;
158558
+ var GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
158559
+ function runImmediate(db, body) {
158560
+ db.exec("BEGIN IMMEDIATE");
158561
+ let committed = false;
158562
+ try {
158563
+ const result = body();
158564
+ db.exec("COMMIT");
158565
+ committed = true;
158566
+ return result;
158567
+ } finally {
158568
+ if (!committed) {
158569
+ try {
158570
+ db.exec("ROLLBACK");
158571
+ } catch {}
158572
+ }
158573
+ }
158574
+ }
158575
+ function rowToState(row) {
158576
+ return {
158577
+ projectPath: row.project_path,
158578
+ leaseHolder: row.lease_holder,
158579
+ leaseExpiresAt: row.lease_expires_at,
158580
+ lastSweptAt: row.last_swept_at
158581
+ };
158582
+ }
158583
+ function getGitSweepCoordinatorState(db, projectPath) {
158584
+ const row = db.prepare(`SELECT project_path, lease_holder, lease_expires_at, last_swept_at
158585
+ FROM git_sweep_coordinator
158586
+ WHERE project_path = ?`).get(projectPath);
158587
+ return row ? rowToState(row) : null;
158588
+ }
158589
+ function acquireGitSweepLease(db, projectPath, holderId, options = {}) {
158590
+ const cooldownMs = options.cooldownMs ?? GIT_SWEEP_COOLDOWN_MS;
158591
+ const leaseTtlMs = options.leaseTtlMs ?? GIT_SWEEP_LEASE_TTL_MS;
158592
+ return runImmediate(db, () => {
158593
+ const now = Date.now();
158594
+ const row = getGitSweepCoordinatorState(db, projectPath);
158595
+ if (row?.leaseHolder && row.leaseExpiresAt !== null && row.leaseExpiresAt > now) {
158596
+ return {
158597
+ acquired: false,
158598
+ projectPath,
158599
+ reason: "lease_active",
158600
+ leaseHolder: row.leaseHolder,
158601
+ leaseExpiresAt: row.leaseExpiresAt,
158602
+ lastSweptAt: row.lastSweptAt,
158603
+ nextAllowedAt: null
158604
+ };
158605
+ }
158606
+ if (!options.ignoreCooldown && row?.lastSweptAt !== null && row?.lastSweptAt !== undefined) {
158607
+ const nextAllowedAt = row.lastSweptAt + cooldownMs;
158608
+ if (nextAllowedAt > now) {
158609
+ return {
158610
+ acquired: false,
158611
+ projectPath,
158612
+ reason: "cooldown_active",
158613
+ leaseHolder: row.leaseHolder,
158614
+ leaseExpiresAt: row.leaseExpiresAt,
158615
+ lastSweptAt: row.lastSweptAt,
158616
+ nextAllowedAt
158617
+ };
158618
+ }
158619
+ }
158620
+ const leaseExpiresAt = now + leaseTtlMs;
158621
+ db.prepare(`INSERT INTO git_sweep_coordinator (
158622
+ project_path,
158623
+ lease_holder,
158624
+ lease_expires_at,
158625
+ last_swept_at
158626
+ ) VALUES (?, ?, ?, NULL)
158627
+ ON CONFLICT(project_path) DO UPDATE SET
158628
+ lease_holder = excluded.lease_holder,
158629
+ lease_expires_at = excluded.lease_expires_at`).run(projectPath, holderId, leaseExpiresAt);
158630
+ return {
158631
+ acquired: true,
158632
+ projectPath,
158633
+ holderId,
158634
+ acquiredAt: now,
158635
+ leaseExpiresAt
158636
+ };
158637
+ });
158638
+ }
158639
+ function renewGitSweepLease(db, projectPath, holderId, leaseTtlMs = GIT_SWEEP_LEASE_TTL_MS) {
158640
+ return runImmediate(db, () => {
158641
+ const now = Date.now();
158642
+ const leaseExpiresAt = now + leaseTtlMs;
158643
+ const result = db.prepare(`UPDATE git_sweep_coordinator
158644
+ SET lease_expires_at = ?
158645
+ WHERE project_path = ?
158646
+ AND lease_holder = ?
158647
+ AND lease_expires_at > ?`).run(leaseExpiresAt, projectPath, holderId, now);
158648
+ return result.changes === 1;
158649
+ });
158650
+ }
158651
+ function markGitSweepSuccessAndRelease(db, projectPath, holderId) {
158652
+ return runImmediate(db, () => {
158653
+ const now = Date.now();
158654
+ const result = db.prepare(`UPDATE git_sweep_coordinator
158655
+ SET lease_holder = NULL,
158656
+ lease_expires_at = NULL,
158657
+ last_swept_at = ?
158658
+ WHERE project_path = ?
158659
+ AND lease_holder = ?
158660
+ AND lease_expires_at > ?`).run(now, projectPath, holderId, now);
158661
+ return result.changes === 1;
158662
+ });
158663
+ }
158664
+ function releaseGitSweepLease(db, projectPath, holderId) {
158665
+ runImmediate(db, () => {
158666
+ db.prepare(`UPDATE git_sweep_coordinator
158667
+ SET lease_holder = NULL,
158668
+ lease_expires_at = NULL
158669
+ WHERE project_path = ?
158670
+ AND lease_holder = ?`).run(projectPath, holderId);
158671
+ });
158672
+ }
158673
+
158555
158674
  // ../plugin/src/features/magic-context/memory/embedding-cache.ts
158556
158675
  var DEFAULT_EMBEDDING_CACHE_TTL_MS = 60000;
158557
158676
  var projectEmbeddingCache = new Map;
@@ -159723,14 +159842,48 @@ function readRawSessionMessagesFromDb(db, sessionId) {
159723
159842
  var encoder = new TextEncoder;
159724
159843
  var TAG_PREFIX_REGEX = /^(?:§\d+§\s*)+/;
159725
159844
  var MALFORMED_TAG_PREFIX_REGEX = /^(?:§\d+">§(?:\d+§)?\s*)+/;
159845
+ var COMPLETE_TAG_PAIR_GLOBAL_REGEX = /\u00a7\d+\u00a7/g;
159846
+ var MALFORMED_TAG_GLOBAL_REGEX = /\u00a7\d+">(?:\u00a7(?:\d+\u00a7)?)?/g;
159847
+ var STRAY_SECTION_CHAR_REGEX = /\u00a7/g;
159848
+ function stripWellFormedLeadingTagPrefix(value) {
159849
+ return value.replace(/^(\u00a7\d+\u00a7\s*)+/, "");
159850
+ }
159851
+ function stripCompleteTagPairsGlobally(value) {
159852
+ return value.replace(COMPLETE_TAG_PAIR_GLOBAL_REGEX, "");
159853
+ }
159854
+ function stripMalformedTagNotationGlobally(value) {
159855
+ return value.replace(MALFORMED_TAG_GLOBAL_REGEX, "");
159856
+ }
159857
+ function stripTagSectionCharacters(value) {
159858
+ return value.replace(STRAY_SECTION_CHAR_REGEX, "");
159859
+ }
159860
+ function stripPersistedAssistantText(value) {
159861
+ let text = stripWellFormedLeadingTagPrefix(value);
159862
+ text = stripCompleteTagPairsGlobally(text);
159863
+ text = stripMalformedTagNotationGlobally(text);
159864
+ text = stripTagSectionCharacters(text);
159865
+ return text.trim();
159866
+ }
159726
159867
  function byteSize(value) {
159727
159868
  return encoder.encode(value).length;
159728
159869
  }
159729
159870
  function stripTagPrefix(value) {
159730
- let stripped = value.replace(MALFORMED_TAG_PREFIX_REGEX, "");
159731
- stripped = stripped.replace(TAG_PREFIX_REGEX, "");
159871
+ let stripped = value;
159872
+ for (let pass = 0;pass < 8; pass++) {
159873
+ const prev = stripped;
159874
+ stripped = stripped.replace(MALFORMED_TAG_PREFIX_REGEX, "");
159875
+ stripped = stripped.replace(TAG_PREFIX_REGEX, "");
159876
+ if (stripped === prev)
159877
+ break;
159878
+ }
159732
159879
  return stripped;
159733
159880
  }
159881
+ function peelLeadingMcTagNotation(value) {
159882
+ const body = stripTagPrefix(value);
159883
+ if (body === value)
159884
+ return { tagPrefix: "", body };
159885
+ return { tagPrefix: value.slice(0, value.length - body.length), body };
159886
+ }
159734
159887
  function prependTag(tagId, value) {
159735
159888
  const stripped = stripTagPrefix(value);
159736
159889
  return `§${tagId}§ ${stripped}`;
@@ -159772,7 +159925,9 @@ function hasMeaningfulPart(part) {
159772
159925
  return false;
159773
159926
  const type = part.type;
159774
159927
  if (type === "text") {
159775
- return typeof part.text === "string" && part.text.trim().length > 0;
159928
+ if (typeof part.text !== "string")
159929
+ return false;
159930
+ return stripTagPrefix(part.text).trim().length > 0;
159776
159931
  }
159777
159932
  if (typeof type !== "string")
159778
159933
  return false;
@@ -166047,7 +166202,8 @@ function toNote(row) {
166047
166202
  updatedAt: row.updated_at,
166048
166203
  lastCheckedAt: toNullableNumber(row.last_checked_at),
166049
166204
  readyAt: toNullableNumber(row.ready_at),
166050
- readyReason: toNullableString(row.ready_reason)
166205
+ readyReason: toNullableString(row.ready_reason),
166206
+ anchorOrdinal: toNullableNumber(row.anchor_ordinal)
166051
166207
  };
166052
166208
  }
166053
166209
  function getNoteById(db, noteId) {
@@ -166099,7 +166255,7 @@ function getNotes(db, options3 = {}) {
166099
166255
  }
166100
166256
  function addNote(db, type, options3) {
166101
166257
  const now = Date.now();
166102
- const result = type === "session" ? db.prepare("INSERT INTO notes (type, status, content, session_id, created_at, updated_at, harness) VALUES ('session', 'active', ?, ?, ?, ?, ?) RETURNING *").get(options3.content, options3.sessionId, now, now, getHarness()) : db.prepare("INSERT INTO notes (type, status, content, session_id, project_path, surface_condition, created_at, updated_at, harness) VALUES ('smart', 'pending', ?, ?, ?, ?, ?, ?, ?) RETURNING *").get(options3.content, options3.sessionId ?? null, options3.projectPath, options3.surfaceCondition, now, now, getHarness());
166258
+ const result = type === "session" ? db.prepare("INSERT INTO notes (type, status, content, session_id, created_at, updated_at, harness, anchor_ordinal) VALUES ('session', 'active', ?, ?, ?, ?, ?, ?) RETURNING *").get(options3.content, options3.sessionId, now, now, getHarness(), options3.anchorOrdinal ?? null) : db.prepare("INSERT INTO notes (type, status, content, session_id, project_path, surface_condition, created_at, updated_at, harness, anchor_ordinal) VALUES ('smart', 'pending', ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *").get(options3.content, options3.sessionId ?? null, options3.projectPath, options3.surfaceCondition, now, now, getHarness(), options3.anchorOrdinal ?? null);
166103
166259
  if (!isNoteRow(result)) {
166104
166260
  throw new Error("[notes] failed to insert note");
166105
166261
  }
@@ -166953,15 +167109,26 @@ function err3(text) {
166953
167109
  isError: true
166954
167110
  };
166955
167111
  }
167112
+ function captureAnchorOrdinal(db, sessionId) {
167113
+ try {
167114
+ const ordinal = getLastIndexedOrdinal(db, sessionId);
167115
+ return ordinal > 0 ? ordinal : null;
167116
+ } catch {
167117
+ return null;
167118
+ }
167119
+ }
167120
+ function anchorSuffix(note) {
167121
+ return note.anchorOrdinal !== null ? ` ↳ @msg ${note.anchorOrdinal}` : "";
167122
+ }
166956
167123
  function formatNoteLine(note) {
166957
167124
  if (note.type === "smart") {
166958
167125
  const conditionLine = note.status === "ready" ? note.readyReason ?? note.surfaceCondition ?? "Condition satisfied" : note.surfaceCondition ?? "No condition recorded";
166959
167126
  const statusSuffix2 = note.status === "active" ? "" : ` (${note.status})`;
166960
- return `- **#${note.id}**${statusSuffix2}: ${note.content}
167127
+ return `- **#${note.id}**${statusSuffix2}: ${note.content}${anchorSuffix(note)}
166961
167128
  *Condition*: ${conditionLine}`;
166962
167129
  }
166963
167130
  const statusSuffix = note.status === "active" ? "" : ` (${note.status})`;
166964
- return `- **#${note.id}**${statusSuffix}: ${note.content}`;
167131
+ return `- **#${note.id}**${statusSuffix}: ${note.content}${anchorSuffix(note)}`;
166965
167132
  }
166966
167133
  var DISMISS_FOOTER = `
166967
167134
 
@@ -166983,6 +167150,7 @@ function createCtxNoteTool(deps) {
166983
167150
  const content = params.content?.trim();
166984
167151
  if (!content)
166985
167152
  return err3("Error: 'content' is required when action is 'write'.");
167153
+ const anchorOrdinal = captureAnchorOrdinal(deps.db, sessionId);
166986
167154
  const surfaceCondition = params.surface_condition?.trim();
166987
167155
  if (surfaceCondition) {
166988
167156
  if (deps.dreamerEnabled !== true) {
@@ -166995,13 +167163,18 @@ function createCtxNoteTool(deps) {
166995
167163
  const note2 = addNote(deps.db, "smart", {
166996
167164
  content,
166997
167165
  projectPath: projectIdentity,
166998
- surfaceCondition
167166
+ surfaceCondition,
167167
+ anchorOrdinal
166999
167168
  });
167000
167169
  return ok3(`Created smart note #${note2.id}. Dreamer will evaluate the condition during nightly runs:
167001
167170
  - Content: ${content}
167002
167171
  - Condition: ${surfaceCondition}`);
167003
167172
  }
167004
- const note = addNote(deps.db, "session", { sessionId, content });
167173
+ const note = addNote(deps.db, "session", {
167174
+ sessionId,
167175
+ content,
167176
+ anchorOrdinal
167177
+ });
167005
167178
  return ok3(`Saved session note #${note.id}.`);
167006
167179
  }
167007
167180
  if (action2 === "dismiss") {
@@ -167064,9 +167237,13 @@ function createCtxNoteTool(deps) {
167064
167237
 
167065
167238
  No notes for the current filter.`);
167066
167239
  }
167067
- return ok3(`${sections.join(`
167240
+ const body = sections.join(`
167068
167241
 
167069
- `)}${DISMISS_FOOTER}`);
167242
+ `);
167243
+ const anchorHint = body.includes("↳ @msg ") ? `
167244
+
167245
+ ↳ @msg N marks the conversation tail when a note was written. To see what led to it: ctx_expand(start=N-x, end=N) (pick x for how far back to look).` : "";
167246
+ return ok3(`${body}${anchorHint}${DISMISS_FOOTER}`);
167070
167247
  }
167071
167248
  };
167072
167249
  }
@@ -167302,6 +167479,7 @@ async function readGitCommits(directory, options3 = {}) {
167302
167479
  if (revision.startsWith("-")) {
167303
167480
  throw new Error(`readGitCommits: refusing revision that looks like an option: "${revision}"`);
167304
167481
  }
167482
+ const projectLabel = options3.projectIdentity ?? "<project>";
167305
167483
  const args = [
167306
167484
  "log",
167307
167485
  revision,
@@ -167324,11 +167502,11 @@ async function readGitCommits(directory, options3 = {}) {
167324
167502
  stdout = result.stdout;
167325
167503
  } catch (error51) {
167326
167504
  const message = error51 instanceof Error ? error51.message : String(error51);
167327
- log(`[git-commits] readGitCommits failed at cwd=${directory}: ${message.slice(0, 500)}`);
167505
+ log(`[git-commits] readGitCommits failed for ${projectLabel}: ${message.slice(0, 500)}`);
167328
167506
  return [];
167329
167507
  }
167330
167508
  if (stdout.trim().length === 0) {
167331
- log(`[git-commits] readGitCommits returned empty stdout at cwd=${directory} (sinceMs=${options3.sinceMs ?? "none"} args=${args.slice(0, 4).join(" ")})`);
167509
+ log(`[git-commits] readGitCommits returned empty stdout for ${projectLabel} (sinceMs=${options3.sinceMs ?? "none"} args=${args.slice(0, 4).join(" ")})`);
167332
167510
  }
167333
167511
  return parseGitLogOutput(stdout);
167334
167512
  }
@@ -167381,6 +167559,7 @@ var insertStatements = new WeakMap;
167381
167559
  var existingShasStatements = new WeakMap;
167382
167560
  var projectCountStatements = new WeakMap;
167383
167561
  var evictStatements = new WeakMap;
167562
+ var evictOverflowStatements = new WeakMap;
167384
167563
  var latestCommitTimeStatements = new WeakMap;
167385
167564
  function getInsertStatement(db) {
167386
167565
  let stmt = insertStatements.get(db);
@@ -167423,17 +167602,17 @@ function getLatestCommitTimeStatement(db) {
167423
167602
  }
167424
167603
  return stmt;
167425
167604
  }
167426
- function getEvictStatement(db) {
167427
- let stmt = evictStatements.get(db);
167605
+ function getEvictOverflowStatement(db) {
167606
+ let stmt = evictOverflowStatements.get(db);
167428
167607
  if (!stmt) {
167429
167608
  stmt = db.prepare(`DELETE FROM git_commits
167430
- WHERE sha IN (
167431
- SELECT sha FROM git_commits
167609
+ WHERE rowid IN (
167610
+ SELECT rowid FROM git_commits
167432
167611
  WHERE project_path = ?
167433
- ORDER BY committed_at ASC
167434
- LIMIT ?
167612
+ ORDER BY committed_at DESC, sha DESC
167613
+ LIMIT -1 OFFSET ?
167435
167614
  )`);
167436
- evictStatements.set(db, stmt);
167615
+ evictOverflowStatements.set(db, stmt);
167437
167616
  }
167438
167617
  return stmt;
167439
167618
  }
@@ -167471,22 +167650,15 @@ function getLatestIndexedCommitTimeMs(db, projectPath) {
167471
167650
  const row = getLatestCommitTimeStatement(db).get(projectPath);
167472
167651
  return row?.latest ?? null;
167473
167652
  }
167474
- function evictOldestCommits(db, projectPath, excess) {
167475
- if (excess <= 0)
167476
- return 0;
167477
- const before = getCommitCount(db, projectPath);
167478
- getEvictStatement(db).run(projectPath, excess);
167479
- const after = getCommitCount(db, projectPath);
167480
- return Math.max(0, before - after);
167481
- }
167482
167653
  function enforceProjectCap(db, projectPath, maxCommits) {
167483
167654
  if (maxCommits <= 0)
167484
167655
  return 0;
167485
167656
  const count = getCommitCount(db, projectPath);
167486
167657
  if (count <= maxCommits)
167487
167658
  return 0;
167488
- const excess = count - maxCommits;
167489
- const evicted = evictOldestCommits(db, projectPath, excess);
167659
+ getEvictOverflowStatement(db).run(projectPath, maxCommits);
167660
+ const after = getCommitCount(db, projectPath);
167661
+ const evicted = Math.max(0, count - after);
167490
167662
  if (evicted > 0) {
167491
167663
  log(`[git-commits] evicted ${evicted} oldest commits for project ${projectPath} (cap=${maxCommits}, was=${count})`);
167492
167664
  }
@@ -167518,7 +167690,8 @@ async function indexCommitsForProject(db, projectPath, directory, options3) {
167518
167690
  const sinceMs = latestIndexed !== null ? Math.max(latestIndexed - 60000, Date.now() - options3.sinceDays * MS_PER_DAY) : Date.now() - options3.sinceDays * MS_PER_DAY;
167519
167691
  const commits = await readGitCommits(directory, {
167520
167692
  sinceMs,
167521
- maxCommits: options3.maxCommits
167693
+ maxCommits: options3.maxCommits,
167694
+ projectIdentity: projectPath
167522
167695
  });
167523
167696
  result.scanned = commits.length;
167524
167697
  if (commits.length === 0) {
@@ -167725,6 +167898,62 @@ function searchGitCommitsSync(db, projectPath, query, options3) {
167725
167898
  });
167726
167899
  return results.slice(0, options3.limit);
167727
167900
  }
167901
+ // ../plugin/src/features/magic-context/literal-probes.ts
167902
+ var MAX_PROBES = 5;
167903
+ var MIN_PROBE_LENGTH = 3;
167904
+ var SLASH_COMMAND_RE = /\/[a-z][a-z0-9]*(?:-[a-z0-9]+)+/gi;
167905
+ var KEBAB_SNAKE_RE = /[a-z][a-z0-9]*(?:[-_][a-z0-9]+)+/gi;
167906
+ var DOTTED_RE = /[a-z0-9][a-z0-9_-]*(?:\.[a-z0-9_-]+)+/gi;
167907
+ var CAMEL_RE = /\b[a-zA-Z][a-z0-9]*(?:[A-Z][a-z0-9]*)+\b/g;
167908
+ var SHA_RE = /\b[0-9a-f]{7,40}\b/gi;
167909
+ var ERROR_CODE_RE = /\b(?:TS\d{4,}|ERR_[A-Z][A-Z0-9_]*)\b/g;
167910
+ var QUOTED_RE = /["`]([^"`]{3,80})["`]/g;
167911
+ function looksLikeSha(token) {
167912
+ return /[0-9]/.test(token) && /^[0-9a-f]{7,40}$/i.test(token);
167913
+ }
167914
+ function extractLiteralProbes(query) {
167915
+ const trimmed = query.trim();
167916
+ if (trimmed.length === 0)
167917
+ return [];
167918
+ const ordered = [];
167919
+ const seen = new Set;
167920
+ const add = (raw) => {
167921
+ if (!raw)
167922
+ return;
167923
+ const probe = raw.trim();
167924
+ if (probe.length < MIN_PROBE_LENGTH)
167925
+ return;
167926
+ const key = probe.toLowerCase();
167927
+ if (seen.has(key))
167928
+ return;
167929
+ seen.add(key);
167930
+ ordered.push(probe);
167931
+ };
167932
+ for (const m of trimmed.matchAll(QUOTED_RE))
167933
+ add(m[1]);
167934
+ for (const m of trimmed.matchAll(SLASH_COMMAND_RE))
167935
+ add(m[0]);
167936
+ for (const m of trimmed.matchAll(ERROR_CODE_RE))
167937
+ add(m[0]);
167938
+ for (const m of trimmed.matchAll(DOTTED_RE))
167939
+ add(m[0]);
167940
+ for (const m of trimmed.matchAll(KEBAB_SNAKE_RE))
167941
+ add(m[0]);
167942
+ for (const m of trimmed.matchAll(CAMEL_RE))
167943
+ add(m[0]);
167944
+ for (const m of trimmed.matchAll(SHA_RE)) {
167945
+ if (looksLikeSha(m[0]))
167946
+ add(m[0]);
167947
+ }
167948
+ return ordered.slice(0, MAX_PROBES);
167949
+ }
167950
+ function containsProbeVerbatim(text, probes) {
167951
+ if (probes.length === 0)
167952
+ return false;
167953
+ const haystack = text.toLowerCase();
167954
+ return probes.some((probe) => haystack.includes(probe.toLowerCase()));
167955
+ }
167956
+
167728
167957
  // ../plugin/src/features/magic-context/search.ts
167729
167958
  var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
167730
167959
  var FTS_SEMANTIC_CANDIDATE_LIMIT = 50;
@@ -167902,36 +168131,82 @@ function linearDecayScore(rank, total) {
167902
168131
  return 0;
167903
168132
  return Math.max(0, 1 - rank / total);
167904
168133
  }
167905
- function searchMessages(args) {
167906
- const sanitizedQuery = sanitizeFtsQuery(args.query.trim());
167907
- if (sanitizedQuery.length === 0) {
168134
+ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
168135
+ if (ftsQuery.length === 0)
167908
168136
  return [];
167909
- }
167910
- const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
167911
- const rows = getMessageSearchStatement(args.db).all(args.sessionId, sanitizedQuery, fetchLimit).map((row) => row);
167912
- const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
167913
- const filtered = rows.map((row) => {
168137
+ const rows = getMessageSearchStatement(db).all(sessionId, ftsQuery, fetchLimit).map((row) => row);
168138
+ const result = [];
168139
+ for (const row of rows) {
167914
168140
  const messageOrdinal = getMessageOrdinal(row.messageOrdinal);
167915
168141
  if (messageOrdinal === null || typeof row.messageId !== "string" || typeof row.role !== "string" || typeof row.content !== "string") {
167916
- return null;
168142
+ continue;
167917
168143
  }
167918
168144
  if (cutoff !== null && messageOrdinal > cutoff) {
167919
- return null;
168145
+ continue;
167920
168146
  }
167921
- return {
168147
+ result.push({
167922
168148
  messageOrdinal,
167923
168149
  messageId: row.messageId,
167924
168150
  role: row.role,
167925
168151
  content: row.content
167926
- };
167927
- }).filter((result) => result !== null).slice(0, args.limit);
167928
- return filtered.map((row, rank) => ({
168152
+ });
168153
+ }
168154
+ return result;
168155
+ }
168156
+ var RRF_K = 60;
168157
+ var VERBATIM_PROBE_BONUS = 0.5;
168158
+ function searchMessages(args) {
168159
+ const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
168160
+ const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
168161
+ const baseQuery = sanitizeFtsQuery(args.query.trim());
168162
+ const probes = args.probes ?? [];
168163
+ if (probes.length === 0) {
168164
+ const filtered = runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff).slice(0, args.limit);
168165
+ return filtered.map((row, rank) => ({
168166
+ source: "message",
168167
+ content: previewText(row.content),
168168
+ score: linearDecayScore(rank, filtered.length),
168169
+ messageOrdinal: row.messageOrdinal,
168170
+ messageId: row.messageId,
168171
+ role: row.role
168172
+ }));
168173
+ }
168174
+ const queryLists = [];
168175
+ if (baseQuery.length > 0) {
168176
+ queryLists.push(runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff));
168177
+ }
168178
+ for (const probe of probes) {
168179
+ const probeQuery = sanitizeFtsQuery(probe);
168180
+ if (probeQuery.length === 0)
168181
+ continue;
168182
+ queryLists.push(runMessageFtsQuery(args.db, args.sessionId, probeQuery, fetchLimit, cutoff));
168183
+ }
168184
+ const fused = new Map;
168185
+ for (const list of queryLists) {
168186
+ list.forEach((row, rank) => {
168187
+ const rrf = 1 / (RRF_K + rank);
168188
+ const existing = fused.get(row.messageId);
168189
+ if (existing) {
168190
+ existing.score += rrf;
168191
+ } else {
168192
+ fused.set(row.messageId, { row, score: rrf });
168193
+ }
168194
+ });
168195
+ }
168196
+ for (const entry of fused.values()) {
168197
+ if (containsProbeVerbatim(entry.row.content, probes)) {
168198
+ entry.score += VERBATIM_PROBE_BONUS;
168199
+ }
168200
+ }
168201
+ const ranked = [...fused.values()].sort((a, b) => b.score !== a.score ? b.score - a.score : a.row.messageOrdinal - b.row.messageOrdinal).slice(0, args.limit);
168202
+ const maxScore = ranked.length > 0 ? ranked[0].score : 1;
168203
+ return ranked.map((entry) => ({
167929
168204
  source: "message",
167930
- content: previewText(row.content),
167931
- score: linearDecayScore(rank, filtered.length),
167932
- messageOrdinal: row.messageOrdinal,
167933
- messageId: row.messageId,
167934
- role: row.role
168205
+ content: previewText(entry.row.content),
168206
+ score: maxScore > 0 ? entry.score / maxScore : 0,
168207
+ messageOrdinal: entry.row.messageOrdinal,
168208
+ messageId: entry.row.messageId,
168209
+ role: entry.row.role
167935
168210
  }));
167936
168211
  }
167937
168212
  function getSourceBoost(result) {
@@ -168015,12 +168290,14 @@ async function unifiedSearch(db, sessionId, projectPath, query, options3 = {}) {
168015
168290
  return null;
168016
168291
  }) : Promise.resolve(null);
168017
168292
  await Promise.resolve();
168293
+ const messageProbes = options3.explicitSearch ? extractLiteralProbes(trimmedQuery) : [];
168018
168294
  const messageResults = runMessages ? searchMessages({
168019
168295
  db,
168020
168296
  sessionId,
168021
168297
  query: trimmedQuery,
168022
168298
  limit: tierLimit,
168023
- maxOrdinal: options3.maxMessageOrdinal
168299
+ maxOrdinal: options3.maxMessageOrdinal,
168300
+ probes: messageProbes
168024
168301
  }) : [];
168025
168302
  const queryEmbedding = await queryEmbeddingPromise;
168026
168303
  const [memoryResults, gitCommitResults] = await Promise.all([
@@ -168791,7 +169068,8 @@ function createCtxSearchTool(deps) {
168791
169068
  maxMessageOrdinal: lastCompartmentEnd >= 0 ? lastCompartmentEnd : undefined,
168792
169069
  gitCommitsEnabled,
168793
169070
  sources: params.sources,
168794
- visibleMemoryIds
169071
+ visibleMemoryIds,
169072
+ explicitSearch: true
168795
169073
  });
168796
169074
  return {
168797
169075
  content: [{ type: "text", text: formatSearchResults(query, results) }],