@cortexkit/pi-magic-context 0.22.1 → 0.22.2

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,
@@ -157402,46 +157442,6 @@ function stripJsonComments(content) {
157402
157442
  }
157403
157443
  return result;
157404
157444
  }
157405
- function stripTrailingCommas(content) {
157406
- let result = "";
157407
- let inString = false;
157408
- let escaped = false;
157409
- for (let index = 0;index < content.length; index += 1) {
157410
- const char = content[index];
157411
- if (inString) {
157412
- result += char;
157413
- if (escaped) {
157414
- escaped = false;
157415
- } else if (char === "\\") {
157416
- escaped = true;
157417
- } else if (char === '"') {
157418
- inString = false;
157419
- }
157420
- continue;
157421
- }
157422
- if (char === '"') {
157423
- inString = true;
157424
- result += char;
157425
- continue;
157426
- }
157427
- if (char === ",") {
157428
- let lookahead = index + 1;
157429
- while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
157430
- lookahead += 1;
157431
- }
157432
- const next = content[lookahead];
157433
- if (next === "}" || next === "]") {
157434
- continue;
157435
- }
157436
- }
157437
- result += char;
157438
- }
157439
- return result;
157440
- }
157441
- function parseJsonc(content) {
157442
- const normalized = stripTrailingCommas(stripJsonComments(content));
157443
- return JSON.parse(normalized);
157444
- }
157445
157445
 
157446
157446
  // ../plugin/src/config/variable.ts
157447
157447
  var ENV_PATTERN = /\{env:([^}]+)\}/g;
@@ -158441,7 +158441,7 @@ function getDistinctStoredModelIds(db, projectPath) {
158441
158441
  }
158442
158442
 
158443
158443
  // ../plugin/src/features/magic-context/project-embedding-registry.ts
158444
- import { createHash as createHash3 } from "node:crypto";
158444
+ import { createHash as createHash3, randomUUID } from "node:crypto";
158445
158445
  init_logger();
158446
158446
 
158447
158447
  // ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
@@ -158545,6 +158545,125 @@ function getDistinctCommitEmbeddingModelIds(db, projectPath) {
158545
158545
  return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
158546
158546
  }
158547
158547
 
158548
+ // ../plugin/src/features/magic-context/git-commits/sweep-coordinator.ts
158549
+ var GIT_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
158550
+ var GIT_SWEEP_LEASE_TTL_MS = 5 * 60 * 1000;
158551
+ var GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
158552
+ function runImmediate(db, body) {
158553
+ db.exec("BEGIN IMMEDIATE");
158554
+ let committed = false;
158555
+ try {
158556
+ const result = body();
158557
+ db.exec("COMMIT");
158558
+ committed = true;
158559
+ return result;
158560
+ } finally {
158561
+ if (!committed) {
158562
+ try {
158563
+ db.exec("ROLLBACK");
158564
+ } catch {}
158565
+ }
158566
+ }
158567
+ }
158568
+ function rowToState(row) {
158569
+ return {
158570
+ projectPath: row.project_path,
158571
+ leaseHolder: row.lease_holder,
158572
+ leaseExpiresAt: row.lease_expires_at,
158573
+ lastSweptAt: row.last_swept_at
158574
+ };
158575
+ }
158576
+ function getGitSweepCoordinatorState(db, projectPath) {
158577
+ const row = db.prepare(`SELECT project_path, lease_holder, lease_expires_at, last_swept_at
158578
+ FROM git_sweep_coordinator
158579
+ WHERE project_path = ?`).get(projectPath);
158580
+ return row ? rowToState(row) : null;
158581
+ }
158582
+ function acquireGitSweepLease(db, projectPath, holderId, options = {}) {
158583
+ const cooldownMs = options.cooldownMs ?? GIT_SWEEP_COOLDOWN_MS;
158584
+ const leaseTtlMs = options.leaseTtlMs ?? GIT_SWEEP_LEASE_TTL_MS;
158585
+ return runImmediate(db, () => {
158586
+ const now = Date.now();
158587
+ const row = getGitSweepCoordinatorState(db, projectPath);
158588
+ if (row?.leaseHolder && row.leaseExpiresAt !== null && row.leaseExpiresAt > now) {
158589
+ return {
158590
+ acquired: false,
158591
+ projectPath,
158592
+ reason: "lease_active",
158593
+ leaseHolder: row.leaseHolder,
158594
+ leaseExpiresAt: row.leaseExpiresAt,
158595
+ lastSweptAt: row.lastSweptAt,
158596
+ nextAllowedAt: null
158597
+ };
158598
+ }
158599
+ if (!options.ignoreCooldown && row?.lastSweptAt !== null && row?.lastSweptAt !== undefined) {
158600
+ const nextAllowedAt = row.lastSweptAt + cooldownMs;
158601
+ if (nextAllowedAt > now) {
158602
+ return {
158603
+ acquired: false,
158604
+ projectPath,
158605
+ reason: "cooldown_active",
158606
+ leaseHolder: row.leaseHolder,
158607
+ leaseExpiresAt: row.leaseExpiresAt,
158608
+ lastSweptAt: row.lastSweptAt,
158609
+ nextAllowedAt
158610
+ };
158611
+ }
158612
+ }
158613
+ const leaseExpiresAt = now + leaseTtlMs;
158614
+ db.prepare(`INSERT INTO git_sweep_coordinator (
158615
+ project_path,
158616
+ lease_holder,
158617
+ lease_expires_at,
158618
+ last_swept_at
158619
+ ) VALUES (?, ?, ?, NULL)
158620
+ ON CONFLICT(project_path) DO UPDATE SET
158621
+ lease_holder = excluded.lease_holder,
158622
+ lease_expires_at = excluded.lease_expires_at`).run(projectPath, holderId, leaseExpiresAt);
158623
+ return {
158624
+ acquired: true,
158625
+ projectPath,
158626
+ holderId,
158627
+ acquiredAt: now,
158628
+ leaseExpiresAt
158629
+ };
158630
+ });
158631
+ }
158632
+ function renewGitSweepLease(db, projectPath, holderId, leaseTtlMs = GIT_SWEEP_LEASE_TTL_MS) {
158633
+ return runImmediate(db, () => {
158634
+ const now = Date.now();
158635
+ const leaseExpiresAt = now + leaseTtlMs;
158636
+ const result = db.prepare(`UPDATE git_sweep_coordinator
158637
+ SET lease_expires_at = ?
158638
+ WHERE project_path = ?
158639
+ AND lease_holder = ?
158640
+ AND lease_expires_at > ?`).run(leaseExpiresAt, projectPath, holderId, now);
158641
+ return result.changes === 1;
158642
+ });
158643
+ }
158644
+ function markGitSweepSuccessAndRelease(db, projectPath, holderId) {
158645
+ return runImmediate(db, () => {
158646
+ const now = Date.now();
158647
+ const result = db.prepare(`UPDATE git_sweep_coordinator
158648
+ SET lease_holder = NULL,
158649
+ lease_expires_at = NULL,
158650
+ last_swept_at = ?
158651
+ WHERE project_path = ?
158652
+ AND lease_holder = ?
158653
+ AND lease_expires_at > ?`).run(now, projectPath, holderId, now);
158654
+ return result.changes === 1;
158655
+ });
158656
+ }
158657
+ function releaseGitSweepLease(db, projectPath, holderId) {
158658
+ runImmediate(db, () => {
158659
+ db.prepare(`UPDATE git_sweep_coordinator
158660
+ SET lease_holder = NULL,
158661
+ lease_expires_at = NULL
158662
+ WHERE project_path = ?
158663
+ AND lease_holder = ?`).run(projectPath, holderId);
158664
+ });
158665
+ }
158666
+
158548
158667
  // ../plugin/src/features/magic-context/memory/embedding-cache.ts
158549
158668
  var DEFAULT_EMBEDDING_CACHE_TTL_MS = 60000;
158550
158669
  var projectEmbeddingCache = new Map;
@@ -166040,7 +166159,8 @@ function toNote(row) {
166040
166159
  updatedAt: row.updated_at,
166041
166160
  lastCheckedAt: toNullableNumber(row.last_checked_at),
166042
166161
  readyAt: toNullableNumber(row.ready_at),
166043
- readyReason: toNullableString(row.ready_reason)
166162
+ readyReason: toNullableString(row.ready_reason),
166163
+ anchorOrdinal: toNullableNumber(row.anchor_ordinal)
166044
166164
  };
166045
166165
  }
166046
166166
  function getNoteById(db, noteId) {
@@ -166092,7 +166212,7 @@ function getNotes(db, options3 = {}) {
166092
166212
  }
166093
166213
  function addNote(db, type, options3) {
166094
166214
  const now = Date.now();
166095
- 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());
166215
+ 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);
166096
166216
  if (!isNoteRow(result)) {
166097
166217
  throw new Error("[notes] failed to insert note");
166098
166218
  }
@@ -166946,15 +167066,26 @@ function err3(text) {
166946
167066
  isError: true
166947
167067
  };
166948
167068
  }
167069
+ function captureAnchorOrdinal(db, sessionId) {
167070
+ try {
167071
+ const ordinal = getLastIndexedOrdinal(db, sessionId);
167072
+ return ordinal > 0 ? ordinal : null;
167073
+ } catch {
167074
+ return null;
167075
+ }
167076
+ }
167077
+ function anchorSuffix(note) {
167078
+ return note.anchorOrdinal !== null ? ` ↳ @msg ${note.anchorOrdinal}` : "";
167079
+ }
166949
167080
  function formatNoteLine(note) {
166950
167081
  if (note.type === "smart") {
166951
167082
  const conditionLine = note.status === "ready" ? note.readyReason ?? note.surfaceCondition ?? "Condition satisfied" : note.surfaceCondition ?? "No condition recorded";
166952
167083
  const statusSuffix2 = note.status === "active" ? "" : ` (${note.status})`;
166953
- return `- **#${note.id}**${statusSuffix2}: ${note.content}
167084
+ return `- **#${note.id}**${statusSuffix2}: ${note.content}${anchorSuffix(note)}
166954
167085
  *Condition*: ${conditionLine}`;
166955
167086
  }
166956
167087
  const statusSuffix = note.status === "active" ? "" : ` (${note.status})`;
166957
- return `- **#${note.id}**${statusSuffix}: ${note.content}`;
167088
+ return `- **#${note.id}**${statusSuffix}: ${note.content}${anchorSuffix(note)}`;
166958
167089
  }
166959
167090
  var DISMISS_FOOTER = `
166960
167091
 
@@ -166976,6 +167107,7 @@ function createCtxNoteTool(deps) {
166976
167107
  const content = params.content?.trim();
166977
167108
  if (!content)
166978
167109
  return err3("Error: 'content' is required when action is 'write'.");
167110
+ const anchorOrdinal = captureAnchorOrdinal(deps.db, sessionId);
166979
167111
  const surfaceCondition = params.surface_condition?.trim();
166980
167112
  if (surfaceCondition) {
166981
167113
  if (deps.dreamerEnabled !== true) {
@@ -166988,13 +167120,18 @@ function createCtxNoteTool(deps) {
166988
167120
  const note2 = addNote(deps.db, "smart", {
166989
167121
  content,
166990
167122
  projectPath: projectIdentity,
166991
- surfaceCondition
167123
+ surfaceCondition,
167124
+ anchorOrdinal
166992
167125
  });
166993
167126
  return ok3(`Created smart note #${note2.id}. Dreamer will evaluate the condition during nightly runs:
166994
167127
  - Content: ${content}
166995
167128
  - Condition: ${surfaceCondition}`);
166996
167129
  }
166997
- const note = addNote(deps.db, "session", { sessionId, content });
167130
+ const note = addNote(deps.db, "session", {
167131
+ sessionId,
167132
+ content,
167133
+ anchorOrdinal
167134
+ });
166998
167135
  return ok3(`Saved session note #${note.id}.`);
166999
167136
  }
167000
167137
  if (action2 === "dismiss") {
@@ -167057,9 +167194,13 @@ function createCtxNoteTool(deps) {
167057
167194
 
167058
167195
  No notes for the current filter.`);
167059
167196
  }
167060
- return ok3(`${sections.join(`
167197
+ const body = sections.join(`
167198
+
167199
+ `);
167200
+ const anchorHint = body.includes("↳ @msg ") ? `
167061
167201
 
167062
- `)}${DISMISS_FOOTER}`);
167202
+ ↳ @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).` : "";
167203
+ return ok3(`${body}${anchorHint}${DISMISS_FOOTER}`);
167063
167204
  }
167064
167205
  };
167065
167206
  }
@@ -167374,6 +167515,7 @@ var insertStatements = new WeakMap;
167374
167515
  var existingShasStatements = new WeakMap;
167375
167516
  var projectCountStatements = new WeakMap;
167376
167517
  var evictStatements = new WeakMap;
167518
+ var evictOverflowStatements = new WeakMap;
167377
167519
  var latestCommitTimeStatements = new WeakMap;
167378
167520
  function getInsertStatement(db) {
167379
167521
  let stmt = insertStatements.get(db);
@@ -167416,17 +167558,17 @@ function getLatestCommitTimeStatement(db) {
167416
167558
  }
167417
167559
  return stmt;
167418
167560
  }
167419
- function getEvictStatement(db) {
167420
- let stmt = evictStatements.get(db);
167561
+ function getEvictOverflowStatement(db) {
167562
+ let stmt = evictOverflowStatements.get(db);
167421
167563
  if (!stmt) {
167422
167564
  stmt = db.prepare(`DELETE FROM git_commits
167423
- WHERE sha IN (
167424
- SELECT sha FROM git_commits
167565
+ WHERE rowid IN (
167566
+ SELECT rowid FROM git_commits
167425
167567
  WHERE project_path = ?
167426
- ORDER BY committed_at ASC
167427
- LIMIT ?
167568
+ ORDER BY committed_at DESC, sha DESC
167569
+ LIMIT -1 OFFSET ?
167428
167570
  )`);
167429
- evictStatements.set(db, stmt);
167571
+ evictOverflowStatements.set(db, stmt);
167430
167572
  }
167431
167573
  return stmt;
167432
167574
  }
@@ -167464,22 +167606,15 @@ function getLatestIndexedCommitTimeMs(db, projectPath) {
167464
167606
  const row = getLatestCommitTimeStatement(db).get(projectPath);
167465
167607
  return row?.latest ?? null;
167466
167608
  }
167467
- function evictOldestCommits(db, projectPath, excess) {
167468
- if (excess <= 0)
167469
- return 0;
167470
- const before = getCommitCount(db, projectPath);
167471
- getEvictStatement(db).run(projectPath, excess);
167472
- const after = getCommitCount(db, projectPath);
167473
- return Math.max(0, before - after);
167474
- }
167475
167609
  function enforceProjectCap(db, projectPath, maxCommits) {
167476
167610
  if (maxCommits <= 0)
167477
167611
  return 0;
167478
167612
  const count = getCommitCount(db, projectPath);
167479
167613
  if (count <= maxCommits)
167480
167614
  return 0;
167481
- const excess = count - maxCommits;
167482
- const evicted = evictOldestCommits(db, projectPath, excess);
167615
+ getEvictOverflowStatement(db).run(projectPath, maxCommits);
167616
+ const after = getCommitCount(db, projectPath);
167617
+ const evicted = Math.max(0, count - after);
167483
167618
  if (evicted > 0) {
167484
167619
  log(`[git-commits] evicted ${evicted} oldest commits for project ${projectPath} (cap=${maxCommits}, was=${count})`);
167485
167620
  }
@@ -167718,6 +167853,62 @@ function searchGitCommitsSync(db, projectPath, query, options3) {
167718
167853
  });
167719
167854
  return results.slice(0, options3.limit);
167720
167855
  }
167856
+ // ../plugin/src/features/magic-context/literal-probes.ts
167857
+ var MAX_PROBES = 5;
167858
+ var MIN_PROBE_LENGTH = 3;
167859
+ var SLASH_COMMAND_RE = /\/[a-z][a-z0-9]*(?:-[a-z0-9]+)+/gi;
167860
+ var KEBAB_SNAKE_RE = /[a-z][a-z0-9]*(?:[-_][a-z0-9]+)+/gi;
167861
+ var DOTTED_RE = /[a-z0-9][a-z0-9_-]*(?:\.[a-z0-9_-]+)+/gi;
167862
+ var CAMEL_RE = /\b[a-zA-Z][a-z0-9]*(?:[A-Z][a-z0-9]*)+\b/g;
167863
+ var SHA_RE = /\b[0-9a-f]{7,40}\b/gi;
167864
+ var ERROR_CODE_RE = /\b(?:TS\d{4,}|ERR_[A-Z][A-Z0-9_]*)\b/g;
167865
+ var QUOTED_RE = /["`]([^"`]{3,80})["`]/g;
167866
+ function looksLikeSha(token) {
167867
+ return /[0-9]/.test(token) && /^[0-9a-f]{7,40}$/i.test(token);
167868
+ }
167869
+ function extractLiteralProbes(query) {
167870
+ const trimmed = query.trim();
167871
+ if (trimmed.length === 0)
167872
+ return [];
167873
+ const ordered = [];
167874
+ const seen = new Set;
167875
+ const add = (raw) => {
167876
+ if (!raw)
167877
+ return;
167878
+ const probe = raw.trim();
167879
+ if (probe.length < MIN_PROBE_LENGTH)
167880
+ return;
167881
+ const key = probe.toLowerCase();
167882
+ if (seen.has(key))
167883
+ return;
167884
+ seen.add(key);
167885
+ ordered.push(probe);
167886
+ };
167887
+ for (const m of trimmed.matchAll(QUOTED_RE))
167888
+ add(m[1]);
167889
+ for (const m of trimmed.matchAll(SLASH_COMMAND_RE))
167890
+ add(m[0]);
167891
+ for (const m of trimmed.matchAll(ERROR_CODE_RE))
167892
+ add(m[0]);
167893
+ for (const m of trimmed.matchAll(DOTTED_RE))
167894
+ add(m[0]);
167895
+ for (const m of trimmed.matchAll(KEBAB_SNAKE_RE))
167896
+ add(m[0]);
167897
+ for (const m of trimmed.matchAll(CAMEL_RE))
167898
+ add(m[0]);
167899
+ for (const m of trimmed.matchAll(SHA_RE)) {
167900
+ if (looksLikeSha(m[0]))
167901
+ add(m[0]);
167902
+ }
167903
+ return ordered.slice(0, MAX_PROBES);
167904
+ }
167905
+ function containsProbeVerbatim(text, probes) {
167906
+ if (probes.length === 0)
167907
+ return false;
167908
+ const haystack = text.toLowerCase();
167909
+ return probes.some((probe) => haystack.includes(probe.toLowerCase()));
167910
+ }
167911
+
167721
167912
  // ../plugin/src/features/magic-context/search.ts
167722
167913
  var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
167723
167914
  var FTS_SEMANTIC_CANDIDATE_LIMIT = 50;
@@ -167895,36 +168086,82 @@ function linearDecayScore(rank, total) {
167895
168086
  return 0;
167896
168087
  return Math.max(0, 1 - rank / total);
167897
168088
  }
167898
- function searchMessages(args) {
167899
- const sanitizedQuery = sanitizeFtsQuery(args.query.trim());
167900
- if (sanitizedQuery.length === 0) {
168089
+ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
168090
+ if (ftsQuery.length === 0)
167901
168091
  return [];
167902
- }
167903
- const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
167904
- const rows = getMessageSearchStatement(args.db).all(args.sessionId, sanitizedQuery, fetchLimit).map((row) => row);
167905
- const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
167906
- const filtered = rows.map((row) => {
168092
+ const rows = getMessageSearchStatement(db).all(sessionId, ftsQuery, fetchLimit).map((row) => row);
168093
+ const result = [];
168094
+ for (const row of rows) {
167907
168095
  const messageOrdinal = getMessageOrdinal(row.messageOrdinal);
167908
168096
  if (messageOrdinal === null || typeof row.messageId !== "string" || typeof row.role !== "string" || typeof row.content !== "string") {
167909
- return null;
168097
+ continue;
167910
168098
  }
167911
168099
  if (cutoff !== null && messageOrdinal > cutoff) {
167912
- return null;
168100
+ continue;
167913
168101
  }
167914
- return {
168102
+ result.push({
167915
168103
  messageOrdinal,
167916
168104
  messageId: row.messageId,
167917
168105
  role: row.role,
167918
168106
  content: row.content
167919
- };
167920
- }).filter((result) => result !== null).slice(0, args.limit);
167921
- return filtered.map((row, rank) => ({
168107
+ });
168108
+ }
168109
+ return result;
168110
+ }
168111
+ var RRF_K = 60;
168112
+ var VERBATIM_PROBE_BONUS = 0.5;
168113
+ function searchMessages(args) {
168114
+ const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
168115
+ const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
168116
+ const baseQuery = sanitizeFtsQuery(args.query.trim());
168117
+ const probes = args.probes ?? [];
168118
+ if (probes.length === 0) {
168119
+ const filtered = runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff).slice(0, args.limit);
168120
+ return filtered.map((row, rank) => ({
168121
+ source: "message",
168122
+ content: previewText(row.content),
168123
+ score: linearDecayScore(rank, filtered.length),
168124
+ messageOrdinal: row.messageOrdinal,
168125
+ messageId: row.messageId,
168126
+ role: row.role
168127
+ }));
168128
+ }
168129
+ const queryLists = [];
168130
+ if (baseQuery.length > 0) {
168131
+ queryLists.push(runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff));
168132
+ }
168133
+ for (const probe of probes) {
168134
+ const probeQuery = sanitizeFtsQuery(probe);
168135
+ if (probeQuery.length === 0)
168136
+ continue;
168137
+ queryLists.push(runMessageFtsQuery(args.db, args.sessionId, probeQuery, fetchLimit, cutoff));
168138
+ }
168139
+ const fused = new Map;
168140
+ for (const list of queryLists) {
168141
+ list.forEach((row, rank) => {
168142
+ const rrf = 1 / (RRF_K + rank);
168143
+ const existing = fused.get(row.messageId);
168144
+ if (existing) {
168145
+ existing.score += rrf;
168146
+ } else {
168147
+ fused.set(row.messageId, { row, score: rrf });
168148
+ }
168149
+ });
168150
+ }
168151
+ for (const entry of fused.values()) {
168152
+ if (containsProbeVerbatim(entry.row.content, probes)) {
168153
+ entry.score += VERBATIM_PROBE_BONUS;
168154
+ }
168155
+ }
168156
+ 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);
168157
+ const maxScore = ranked.length > 0 ? ranked[0].score : 1;
168158
+ return ranked.map((entry) => ({
167922
168159
  source: "message",
167923
- content: previewText(row.content),
167924
- score: linearDecayScore(rank, filtered.length),
167925
- messageOrdinal: row.messageOrdinal,
167926
- messageId: row.messageId,
167927
- role: row.role
168160
+ content: previewText(entry.row.content),
168161
+ score: maxScore > 0 ? entry.score / maxScore : 0,
168162
+ messageOrdinal: entry.row.messageOrdinal,
168163
+ messageId: entry.row.messageId,
168164
+ role: entry.row.role
167928
168165
  }));
167929
168166
  }
167930
168167
  function getSourceBoost(result) {
@@ -168008,12 +168245,14 @@ async function unifiedSearch(db, sessionId, projectPath, query, options3 = {}) {
168008
168245
  return null;
168009
168246
  }) : Promise.resolve(null);
168010
168247
  await Promise.resolve();
168248
+ const messageProbes = options3.explicitSearch ? extractLiteralProbes(trimmedQuery) : [];
168011
168249
  const messageResults = runMessages ? searchMessages({
168012
168250
  db,
168013
168251
  sessionId,
168014
168252
  query: trimmedQuery,
168015
168253
  limit: tierLimit,
168016
- maxOrdinal: options3.maxMessageOrdinal
168254
+ maxOrdinal: options3.maxMessageOrdinal,
168255
+ probes: messageProbes
168017
168256
  }) : [];
168018
168257
  const queryEmbedding = await queryEmbeddingPromise;
168019
168258
  const [memoryResults, gitCommitResults] = await Promise.all([
@@ -168784,7 +169023,8 @@ function createCtxSearchTool(deps) {
168784
169023
  maxMessageOrdinal: lastCompartmentEnd >= 0 ? lastCompartmentEnd : undefined,
168785
169024
  gitCommitsEnabled,
168786
169025
  sources: params.sources,
168787
- visibleMemoryIds
169026
+ visibleMemoryIds,
169027
+ explicitSearch: true
168788
169028
  });
168789
169029
  return {
168790
169030
  content: [{ type: "text", text: formatSearchResults(query, results) }],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/pi-magic-context",
3
- "version": "0.22.1",
3
+ "version": "0.22.2",
4
4
  "type": "module",
5
5
  "description": "Pi coding agent extension for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",