@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.
package/dist/index.js CHANGED
@@ -86,9 +86,6 @@ function getMagicContextStorageDir() {
86
86
  function getLegacyOpenCodeMagicContextStorageDir() {
87
87
  return path2.join(getOpenCodeStorageDir(), "plugin", "magic-context");
88
88
  }
89
- function getCacheDir() {
90
- return process.env.XDG_CACHE_HOME ?? path2.join(os.homedir(), ".cache");
91
- }
92
89
  var init_data_path = () => {};
93
90
 
94
91
  // ../plugin/src/shared/logger.ts
@@ -142698,7 +142695,7 @@ var databases = new Map;
142698
142695
  var persistenceByDatabase = new WeakMap;
142699
142696
  var persistenceErrorByDatabase = new WeakMap;
142700
142697
  var lastSchemaFenceRejection = null;
142701
- var LATEST_SUPPORTED_VERSION = 27;
142698
+ var LATEST_SUPPORTED_VERSION = 29;
142702
142699
  function resolveDatabasePath(dbPathOverride) {
142703
142700
  if (dbPathOverride) {
142704
142701
  return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
@@ -143018,6 +143015,17 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143018
143015
  updated_at INTEGER NOT NULL DEFAULT 0
143019
143016
  );
143020
143017
 
143018
+ CREATE TABLE IF NOT EXISTS git_sweep_coordinator (
143019
+ project_path TEXT PRIMARY KEY,
143020
+ lease_holder TEXT,
143021
+ lease_expires_at INTEGER,
143022
+ last_swept_at INTEGER
143023
+ );
143024
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_lease_expires
143025
+ ON git_sweep_coordinator(lease_expires_at);
143026
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_last_swept
143027
+ ON git_sweep_coordinator(last_swept_at);
143028
+
143021
143029
  CREATE TABLE IF NOT EXISTS m0_mutation_log (
143022
143030
  id INTEGER PRIMARY KEY AUTOINCREMENT,
143023
143031
  session_id TEXT NOT NULL,
@@ -144240,6 +144248,38 @@ var MIGRATIONS = [
144240
144248
  ON tags(session_id, entry_fingerprint)
144241
144249
  WHERE type='message' AND entry_fingerprint IS NOT NULL`);
144242
144250
  }
144251
+ },
144252
+ {
144253
+ version: 28,
144254
+ description: "Add git commit sweep coordinator lease/cooldown table",
144255
+ up: (db) => {
144256
+ db.exec(`
144257
+ CREATE TABLE IF NOT EXISTS git_sweep_coordinator (
144258
+ project_path TEXT PRIMARY KEY,
144259
+ lease_holder TEXT,
144260
+ lease_expires_at INTEGER,
144261
+ last_swept_at INTEGER
144262
+ );
144263
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_lease_expires
144264
+ ON git_sweep_coordinator(lease_expires_at);
144265
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_last_swept
144266
+ ON git_sweep_coordinator(last_swept_at);
144267
+ `);
144268
+ }
144269
+ },
144270
+ {
144271
+ version: 29,
144272
+ description: "Add anchor_ordinal to notes (traceback to the conversation tail)",
144273
+ up: (db) => {
144274
+ const notesExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='notes'").get();
144275
+ if (!notesExists) {
144276
+ return;
144277
+ }
144278
+ const columns = db.prepare("PRAGMA table_info(notes)").all();
144279
+ if (!columns.some((column) => column.name === "anchor_ordinal")) {
144280
+ db.exec("ALTER TABLE notes ADD COLUMN anchor_ordinal INTEGER");
144281
+ }
144282
+ }
144243
144283
  }
144244
144284
  ];
144245
144285
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -145127,7 +145167,8 @@ function toNote(row) {
145127
145167
  updatedAt: row.updated_at,
145128
145168
  lastCheckedAt: toNullableNumber(row.last_checked_at),
145129
145169
  readyAt: toNullableNumber(row.ready_at),
145130
- readyReason: toNullableString(row.ready_reason)
145170
+ readyReason: toNullableString(row.ready_reason),
145171
+ anchorOrdinal: toNullableNumber(row.anchor_ordinal)
145131
145172
  };
145132
145173
  }
145133
145174
  function getNoteById(db, noteId) {
@@ -145179,7 +145220,7 @@ function getNotes(db, options = {}) {
145179
145220
  }
145180
145221
  function addNote(db, type, options) {
145181
145222
  const now = Date.now();
145182
- const result = type === "session" ? db.prepare("INSERT INTO notes (type, status, content, session_id, created_at, updated_at, harness) VALUES ('session', 'active', ?, ?, ?, ?, ?) RETURNING *").get(options.content, options.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(options.content, options.sessionId ?? null, options.projectPath, options.surfaceCondition, now, now, getHarness());
145223
+ 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(options.content, options.sessionId, now, now, getHarness(), options.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(options.content, options.sessionId ?? null, options.projectPath, options.surfaceCondition, now, now, getHarness(), options.anchorOrdinal ?? null);
145183
145224
  if (!isNoteRow(result)) {
145184
145225
  throw new Error("[notes] failed to insert note");
145185
145226
  }
@@ -145949,212 +145990,41 @@ function getAgentFallbackModels(agent) {
145949
145990
 
145950
145991
  // ../plugin/src/shared/models-dev-cache.ts
145951
145992
  init_data_path();
145952
- import { createHash as createHash5 } from "node:crypto";
145953
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
145954
- import { homedir as homedir2, platform } from "node:os";
145993
+ init_logger();
145994
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync, writeFileSync } from "node:fs";
145955
145995
  import { join as join6 } from "node:path";
145956
-
145957
- // ../plugin/src/shared/jsonc-parser.ts
145958
- function stripJsonComments(content) {
145959
- let result = "";
145960
- let inString = false;
145961
- let escaped = false;
145962
- let inLineComment = false;
145963
- let inBlockComment = false;
145964
- for (let index = 0;index < content.length; index += 1) {
145965
- const char = content[index];
145966
- const next = content[index + 1];
145967
- if (inLineComment) {
145968
- if (char === `
145969
- `) {
145970
- inLineComment = false;
145971
- result += char;
145972
- }
145973
- continue;
145974
- }
145975
- if (inBlockComment) {
145976
- if (char === "*" && next === "/") {
145977
- inBlockComment = false;
145978
- index += 1;
145979
- }
145980
- continue;
145981
- }
145982
- if (inString) {
145983
- result += char;
145984
- if (escaped) {
145985
- escaped = false;
145986
- } else if (char === "\\") {
145987
- escaped = true;
145988
- } else if (char === '"') {
145989
- inString = false;
145990
- }
145991
- continue;
145992
- }
145993
- if (char === '"') {
145994
- inString = true;
145995
- result += char;
145996
- continue;
145997
- }
145998
- if (char === "/" && next === "/") {
145999
- inLineComment = true;
146000
- index += 1;
146001
- continue;
146002
- }
146003
- if (char === "/" && next === "*") {
146004
- inBlockComment = true;
146005
- index += 1;
146006
- continue;
146007
- }
146008
- result += char;
146009
- }
146010
- return result;
146011
- }
146012
- function stripTrailingCommas(content) {
146013
- let result = "";
146014
- let inString = false;
146015
- let escaped = false;
146016
- for (let index = 0;index < content.length; index += 1) {
146017
- const char = content[index];
146018
- if (inString) {
146019
- result += char;
146020
- if (escaped) {
146021
- escaped = false;
146022
- } else if (char === "\\") {
146023
- escaped = true;
146024
- } else if (char === '"') {
146025
- inString = false;
146026
- }
146027
- continue;
146028
- }
146029
- if (char === '"') {
146030
- inString = true;
146031
- result += char;
146032
- continue;
146033
- }
146034
- if (char === ",") {
146035
- let lookahead = index + 1;
146036
- while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
146037
- lookahead += 1;
146038
- }
146039
- const next = content[lookahead];
146040
- if (next === "}" || next === "]") {
146041
- continue;
146042
- }
146043
- }
146044
- result += char;
146045
- }
146046
- return result;
145996
+ var MIN_SANE_LIMIT = 20000;
145997
+ var MAX_SANE_LIMIT = 3000000;
145998
+ function isSaneLimit(limit) {
145999
+ return typeof limit === "number" && limit >= MIN_SANE_LIMIT && limit <= MAX_SANE_LIMIT;
146047
146000
  }
146048
- function parseJsonc(content) {
146049
- const normalized = stripTrailingCommas(stripJsonComments(content));
146050
- return JSON.parse(normalized);
146051
- }
146052
-
146053
- // ../plugin/src/shared/models-dev-cache.ts
146054
- init_logger();
146055
- var RELOAD_INTERVAL_MS = 5 * 60 * 1000;
146056
146001
  var apiCache = null;
146057
- var apiLoadedAt = 0;
146058
- var fileCache = null;
146059
- var fileLastAttempt = 0;
146060
- function hashFast(input) {
146061
- return createHash5("sha1").update(input).digest("hex");
146062
- }
146063
- function getModelsJsonPath() {
146064
- const explicit = process.env.OPENCODE_MODELS_PATH?.trim();
146065
- if (explicit)
146066
- return explicit;
146067
- const cacheBase = getCacheDir();
146068
- const source = process.env.OPENCODE_MODELS_URL?.trim();
146069
- const filename = source && source !== "https://models.dev" ? `models-${hashFast(source)}.json` : "models.json";
146070
- return join6(cacheBase, "opencode", filename);
146071
- }
146072
- function getOpencodeConfigPath() {
146073
- const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
146074
- const configDir = envDir ? envDir : platform() === "win32" ? join6(homedir2(), ".config", "opencode") : join6(process.env.XDG_CONFIG_HOME || join6(homedir2(), ".config"), "opencode");
146075
- const jsonc = join6(configDir, "opencode.jsonc");
146076
- if (existsSync5(jsonc))
146077
- return jsonc;
146078
- const json = join6(configDir, "opencode.json");
146079
- if (existsSync5(json))
146080
- return json;
146081
- return null;
146002
+ var persistSeedLoaded = false;
146003
+ function persistFilePath() {
146004
+ return join6(getMagicContextStorageDir(), `model-context-limits-${getHarness()}.json`);
146082
146005
  }
146083
- function resolveLimit(limit) {
146084
- if (!limit)
146006
+ function loadPersistedApiCacheOnce() {
146007
+ if (persistSeedLoaded || apiCache !== null)
146085
146008
  return;
146086
- if (typeof limit.input === "number" && limit.input > 0)
146087
- return limit.input;
146088
- if (typeof limit.context === "number" && limit.context > 0)
146089
- return limit.context;
146090
- return;
146091
- }
146092
- function setCachedModelMetadata(cache, key, model) {
146093
- const limit = resolveLimit(model?.limit);
146094
- if (limit === undefined) {
146095
- return;
146096
- }
146097
- const value = { limit };
146098
- cache.set(key, value);
146099
- const modes = model?.experimental?.modes;
146100
- if (modes && typeof modes === "object") {
146101
- for (const mode of Object.keys(modes)) {
146102
- cache.set(`${key}-${mode}`, value);
146103
- }
146104
- }
146105
- }
146106
- function loadModelsDevMetadataFromFile() {
146107
- const metadata = new Map;
146108
- const modelsJsonPath = getModelsJsonPath();
146109
- let fileFound = false;
146009
+ persistSeedLoaded = true;
146110
146010
  try {
146111
- if (existsSync5(modelsJsonPath)) {
146112
- fileFound = true;
146113
- const raw = readFileSync3(modelsJsonPath, "utf-8");
146114
- const data = JSON.parse(raw);
146115
- for (const [providerId, provider] of Object.entries(data)) {
146116
- if (!provider?.models || typeof provider.models !== "object")
146117
- continue;
146118
- for (const [modelId, model] of Object.entries(provider.models)) {
146119
- setCachedModelMetadata(metadata, `${providerId}/${modelId}`, model);
146120
- }
146121
- }
146011
+ const raw = readFileSync3(persistFilePath(), "utf-8");
146012
+ const obj = JSON.parse(raw);
146013
+ const map = new Map;
146014
+ for (const [key, limit] of Object.entries(obj)) {
146015
+ if (isSaneLimit(limit))
146016
+ map.set(key, { limit });
146122
146017
  }
146123
- } catch (error) {
146124
- sessionLog("global", `models-dev-cache: failed to read models.json at ${modelsJsonPath}:`, error instanceof Error ? error.message : String(error));
146125
- }
146126
- try {
146127
- const configPath = getOpencodeConfigPath();
146128
- if (configPath && existsSync5(configPath)) {
146129
- const config = parseJsonc(readFileSync3(configPath, "utf-8"));
146130
- if (config.provider && typeof config.provider === "object") {
146131
- for (const [providerId, provider] of Object.entries(config.provider)) {
146132
- if (!provider?.models || typeof provider.models !== "object")
146133
- continue;
146134
- for (const [modelId, model] of Object.entries(provider.models)) {
146135
- setCachedModelMetadata(metadata, `${providerId}/${modelId}`, model);
146136
- }
146137
- }
146138
- }
146018
+ if (map.size > 0) {
146019
+ apiCache = map;
146020
+ sessionLog("global", `models-dev-cache: seeded ${map.size} entries from persisted cache (cold start)`);
146139
146021
  }
146140
- } catch (error) {
146141
- sessionLog("global", "models-dev-cache: failed to read opencode config for custom models:", error instanceof Error ? error.message : String(error));
146142
- }
146143
- sessionLog("global", `models-dev-cache: file-layer loaded ${metadata.size} model metadata entries (modelsJsonPath=${modelsJsonPath}, found=${fileFound})`);
146144
- return metadata;
146022
+ } catch {}
146145
146023
  }
146146
- function getModelsDevContextLimit(providerID, modelID) {
146147
- const now = Date.now();
146148
- if (!fileCache || now - fileLastAttempt > RELOAD_INTERVAL_MS) {
146149
- fileLastAttempt = now;
146150
- fileCache = loadModelsDevMetadataFromFile();
146151
- }
146024
+ function getSdkContextLimit(providerID, modelID) {
146025
+ loadPersistedApiCacheOnce();
146152
146026
  const fromApi = lookupLimitWithTagFallback(apiCache, providerID, modelID);
146153
- const fromFile = lookupLimitWithTagFallback(fileCache, providerID, modelID);
146154
- if (typeof fromApi === "number" && typeof fromFile === "number") {
146155
- return Math.max(fromApi, fromFile);
146156
- }
146157
- return fromApi ?? fromFile;
146027
+ return isSaneLimit(fromApi) ? fromApi : undefined;
146158
146028
  }
146159
146029
  function lookupLimitWithTagFallback(cache, providerID, modelID) {
146160
146030
  if (!cache)
@@ -146171,12 +146041,6 @@ function lookupLimitWithTagFallback(cache, providerID, modelID) {
146171
146041
  }
146172
146042
  return;
146173
146043
  }
146174
- function clearModelsDevCache() {
146175
- apiCache = null;
146176
- apiLoadedAt = 0;
146177
- fileCache = null;
146178
- fileLastAttempt = 0;
146179
- }
146180
146044
 
146181
146045
  // ../plugin/src/hooks/magic-context/derive-budgets.ts
146182
146046
  var TRIGGER_BUDGET_PERCENTAGE = 0.05;
@@ -146207,7 +146071,7 @@ function resolveHistorianContextLimit(historianModelOverride) {
146207
146071
  const [providerID, ...rest] = historianModelOverride.split("/");
146208
146072
  const modelID = rest.join("/");
146209
146073
  if (providerID && modelID) {
146210
- const limit = getModelsDevContextLimit(providerID, modelID);
146074
+ const limit = getSdkContextLimit(providerID, modelID);
146211
146075
  if (typeof limit === "number" && limit > 0)
146212
146076
  return limit;
146213
146077
  }
@@ -146226,7 +146090,7 @@ function resolveHistorianContextLimit(historianModelOverride) {
146226
146090
  const modelID = rest.join("/");
146227
146091
  if (!providerID || !modelID)
146228
146092
  continue;
146229
- const limit = getModelsDevContextLimit(providerID, modelID);
146093
+ const limit = getSdkContextLimit(providerID, modelID);
146230
146094
  if (typeof limit !== "number" || limit <= 0)
146231
146095
  continue;
146232
146096
  if (minLimit === undefined || limit < minLimit)
@@ -146239,37 +146103,6 @@ function resolveHistorianContextLimit(historianModelOverride) {
146239
146103
  init_logger();
146240
146104
  var DEFAULT_CONTEXT_LIMIT = 128000;
146241
146105
  var MAX_EXECUTE_THRESHOLD = 80;
146242
- function resolveContextLimit(providerID, modelID, ctx) {
146243
- const fromModelsDev = providerID && modelID ? getModelsDevContextLimit(providerID, modelID) : undefined;
146244
- const baseline = fromModelsDev ?? DEFAULT_CONTEXT_LIMIT;
146245
- if (ctx?.db && ctx.sessionID) {
146246
- try {
146247
- const overflow = getOverflowState(ctx.db, ctx.sessionID);
146248
- if (overflow.detectedContextLimit > 0 && overflow.detectedContextLimit < baseline) {
146249
- return overflow.detectedContextLimit;
146250
- }
146251
- } catch {}
146252
- }
146253
- return baseline;
146254
- }
146255
- function resolveTrustedContextLimit(providerID, modelID, ctx) {
146256
- const fromModelsDev = providerID && modelID ? getModelsDevContextLimit(providerID, modelID) : undefined;
146257
- let detected;
146258
- if (ctx?.db && ctx.sessionID) {
146259
- try {
146260
- const overflow = getOverflowState(ctx.db, ctx.sessionID);
146261
- if (overflow.detectedContextLimit > 0) {
146262
- detected = overflow.detectedContextLimit;
146263
- }
146264
- } catch {}
146265
- }
146266
- if (typeof fromModelsDev === "number" && fromModelsDev > 0) {
146267
- if (detected !== undefined && detected < fromModelsDev)
146268
- return detected;
146269
- return fromModelsDev;
146270
- }
146271
- return detected;
146272
- }
146273
146106
  function resolveCacheTtl(cacheTtl, modelKey) {
146274
146107
  if (typeof cacheTtl === "string") {
146275
146108
  return cacheTtl;
@@ -146490,7 +146323,7 @@ function clearNoteNudgeTriggerOnly(db, sessionId) {
146490
146323
  }
146491
146324
 
146492
146325
  // ../plugin/src/hooks/magic-context/todo-view.ts
146493
- import { createHash as createHash6 } from "node:crypto";
146326
+ import { createHash as createHash5 } from "node:crypto";
146494
146327
  var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
146495
146328
  var TITLE_DONE_STATUSES = new Set(["completed"]);
146496
146329
  var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
@@ -146535,7 +146368,7 @@ function buildSyntheticTodoPart(stateJson) {
146535
146368
  };
146536
146369
  }
146537
146370
  function computeSyntheticCallId(stateJson) {
146538
- const hash = createHash6("sha256").update(stateJson).digest("hex").slice(0, 16);
146371
+ const hash = createHash5("sha256").update(stateJson).digest("hex").slice(0, 16);
146539
146372
  return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
146540
146373
  }
146541
146374
  function parseTodoState(stateJson) {
@@ -146789,7 +146622,7 @@ init_logger();
146789
146622
 
146790
146623
  // src/subagent-runner.ts
146791
146624
  import * as childProcess from "node:child_process";
146792
- import { existsSync as existsSync7 } from "node:fs";
146625
+ import { existsSync as existsSync6 } from "node:fs";
146793
146626
  import { createRequire as createRequire2 } from "node:module";
146794
146627
  import { dirname as dirname3, join as join8, resolve as resolvePath } from "node:path";
146795
146628
  import { createInterface } from "node:readline";
@@ -146893,7 +146726,7 @@ function resolveBundledPiCli() {
146893
146726
  const require_ = createRequire2(import.meta.url);
146894
146727
  const pkgJson = require_.resolve("@earendil-works/pi-coding-agent/package.json");
146895
146728
  const cliPath = join8(dirname3(pkgJson), "dist/cli.js");
146896
- if (existsSync7(cliPath))
146729
+ if (existsSync6(cliPath))
146897
146730
  return cliPath;
146898
146731
  return null;
146899
146732
  } catch {
@@ -146904,7 +146737,7 @@ function resolveSubagentEntryPath() {
146904
146737
  try {
146905
146738
  const here = dirname3(fileURLToPath(import.meta.url));
146906
146739
  const candidate = resolvePath(here, "subagent-entry.js");
146907
- if (existsSync7(candidate))
146740
+ if (existsSync6(candidate))
146908
146741
  return candidate;
146909
146742
  return;
146910
146743
  } catch {
@@ -147664,7 +147497,7 @@ function clearStaleEntries(db, maxAgeMs, projectIdentity) {
147664
147497
  // src/commands/ctx-dream.ts
147665
147498
  init_logger();
147666
147499
  // ../plugin/src/features/magic-context/dreamer/runner.ts
147667
- import { existsSync as existsSync9 } from "node:fs";
147500
+ import { existsSync as existsSync8 } from "node:fs";
147668
147501
  import { join as join11 } from "node:path";
147669
147502
 
147670
147503
  // ../plugin/src/shared/index.ts
@@ -147918,12 +147751,12 @@ init_logger();
147918
147751
 
147919
147752
  // ../plugin/src/features/magic-context/key-files/aft-availability.ts
147920
147753
  var import_comment_json = __toESM(require_src2(), 1);
147921
- import { existsSync as existsSync8, readFileSync as readFileSync5 } from "node:fs";
147922
- import { homedir as homedir3 } from "node:os";
147754
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
147755
+ import { homedir as homedir2 } from "node:os";
147923
147756
  import { join as join9 } from "node:path";
147924
147757
  var overrideAvailability = null;
147925
147758
  function parseConfig(path7) {
147926
- if (!existsSync8(path7))
147759
+ if (!existsSync7(path7))
147927
147760
  return null;
147928
147761
  return import_comment_json.parse(readFileSync5(path7, "utf-8"));
147929
147762
  }
@@ -147945,7 +147778,7 @@ function hasAftAtKeys(value, keys) {
147945
147778
  return false;
147946
147779
  }
147947
147780
  function getAftAvailability() {
147948
- const home = process.env.HOME || homedir3();
147781
+ const home = process.env.HOME || homedir2();
147949
147782
  const opencodePaths = [
147950
147783
  join9(home, ".config", "opencode", "opencode.jsonc"),
147951
147784
  join9(home, ".config", "opencode", "opencode.json")
@@ -148589,13 +148422,13 @@ function invalidateMemory(projectPath, memoryId) {
148589
148422
  }
148590
148423
 
148591
148424
  // ../plugin/src/features/magic-context/memory/normalize-hash.ts
148592
- import { createHash as createHash7 } from "node:crypto";
148425
+ import { createHash as createHash6 } from "node:crypto";
148593
148426
  function normalizeMemoryContent(content) {
148594
148427
  return content.toLowerCase().replace(/\s+/g, " ").trim();
148595
148428
  }
148596
148429
  function computeNormalizedHash(content) {
148597
148430
  const normalized = normalizeMemoryContent(content);
148598
- return createHash7("md5").update(normalized).digest("hex");
148431
+ return createHash6("md5").update(normalized).digest("hex");
148599
148432
  }
148600
148433
 
148601
148434
  // ../plugin/src/features/magic-context/memory/storage-memory.ts
@@ -149746,7 +149579,7 @@ function getOpenCodeDbPath2() {
149746
149579
  }
149747
149580
  function openOpenCodeDb() {
149748
149581
  const dbPath = getOpenCodeDbPath2();
149749
- if (!existsSync9(dbPath)) {
149582
+ if (!existsSync8(dbPath)) {
149750
149583
  log(`[key-files] OpenCode DB not found at ${dbPath} — skipping`);
149751
149584
  return null;
149752
149585
  }
@@ -149896,8 +149729,8 @@ async function runDream(args) {
149896
149729
  try {
149897
149730
  const docsDir = args.sessionDirectory ?? args.projectIdentity;
149898
149731
  const existingDocs = taskName === "maintain-docs" ? {
149899
- architecture: existsSync9(join11(docsDir, "ARCHITECTURE.md")),
149900
- structure: existsSync9(join11(docsDir, "STRUCTURE.md"))
149732
+ architecture: existsSync8(join11(docsDir, "ARCHITECTURE.md")),
149733
+ structure: existsSync8(join11(docsDir, "STRUCTURE.md"))
149901
149734
  } : undefined;
149902
149735
  const userMemories = taskName === "archive-stale" ? getActiveUserMemories(args.db).map((um) => ({
149903
149736
  id: um.id,
@@ -165103,7 +164936,7 @@ function getEmbeddingProviderIdentity(config2) {
165103
164936
  }
165104
164937
 
165105
164938
  // ../plugin/src/features/magic-context/memory/embedding-local.ts
165106
- import { mkdirSync as mkdirSync4 } from "node:fs";
164939
+ import { mkdirSync as mkdirSync5 } from "node:fs";
165107
164940
  import { open, stat, unlink, writeFile } from "node:fs/promises";
165108
164941
  import { dirname as dirname4, join as join12 } from "node:path";
165109
164942
  import { pathToFileURL } from "node:url";
@@ -165284,7 +165117,7 @@ class LocalEmbeddingProvider {
165284
165117
  }
165285
165118
  const modelCacheDir = join12(getMagicContextStorageDir(), "models");
165286
165119
  try {
165287
- mkdirSync4(modelCacheDir, { recursive: true });
165120
+ mkdirSync5(modelCacheDir, { recursive: true });
165288
165121
  env.cacheDir = modelCacheDir;
165289
165122
  } catch {
165290
165123
  log("[magic-context] could not create model cache dir, using library default");
@@ -165659,7 +165492,7 @@ class OpenAICompatibleEmbeddingProvider {
165659
165492
  }
165660
165493
 
165661
165494
  // ../plugin/src/features/magic-context/project-embedding-registry.ts
165662
- import { createHash as createHash8 } from "node:crypto";
165495
+ import { createHash as createHash7, randomUUID } from "node:crypto";
165663
165496
  init_logger();
165664
165497
 
165665
165498
  // ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
@@ -165763,6 +165596,125 @@ function getDistinctCommitEmbeddingModelIds(db, projectPath) {
165763
165596
  return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
165764
165597
  }
165765
165598
 
165599
+ // ../plugin/src/features/magic-context/git-commits/sweep-coordinator.ts
165600
+ var GIT_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
165601
+ var GIT_SWEEP_LEASE_TTL_MS = 5 * 60 * 1000;
165602
+ var GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
165603
+ function runImmediate2(db, body) {
165604
+ db.exec("BEGIN IMMEDIATE");
165605
+ let committed = false;
165606
+ try {
165607
+ const result = body();
165608
+ db.exec("COMMIT");
165609
+ committed = true;
165610
+ return result;
165611
+ } finally {
165612
+ if (!committed) {
165613
+ try {
165614
+ db.exec("ROLLBACK");
165615
+ } catch {}
165616
+ }
165617
+ }
165618
+ }
165619
+ function rowToState(row) {
165620
+ return {
165621
+ projectPath: row.project_path,
165622
+ leaseHolder: row.lease_holder,
165623
+ leaseExpiresAt: row.lease_expires_at,
165624
+ lastSweptAt: row.last_swept_at
165625
+ };
165626
+ }
165627
+ function getGitSweepCoordinatorState(db, projectPath) {
165628
+ const row = db.prepare(`SELECT project_path, lease_holder, lease_expires_at, last_swept_at
165629
+ FROM git_sweep_coordinator
165630
+ WHERE project_path = ?`).get(projectPath);
165631
+ return row ? rowToState(row) : null;
165632
+ }
165633
+ function acquireGitSweepLease(db, projectPath, holderId, options = {}) {
165634
+ const cooldownMs = options.cooldownMs ?? GIT_SWEEP_COOLDOWN_MS;
165635
+ const leaseTtlMs = options.leaseTtlMs ?? GIT_SWEEP_LEASE_TTL_MS;
165636
+ return runImmediate2(db, () => {
165637
+ const now = Date.now();
165638
+ const row = getGitSweepCoordinatorState(db, projectPath);
165639
+ if (row?.leaseHolder && row.leaseExpiresAt !== null && row.leaseExpiresAt > now) {
165640
+ return {
165641
+ acquired: false,
165642
+ projectPath,
165643
+ reason: "lease_active",
165644
+ leaseHolder: row.leaseHolder,
165645
+ leaseExpiresAt: row.leaseExpiresAt,
165646
+ lastSweptAt: row.lastSweptAt,
165647
+ nextAllowedAt: null
165648
+ };
165649
+ }
165650
+ if (!options.ignoreCooldown && row?.lastSweptAt !== null && row?.lastSweptAt !== undefined) {
165651
+ const nextAllowedAt = row.lastSweptAt + cooldownMs;
165652
+ if (nextAllowedAt > now) {
165653
+ return {
165654
+ acquired: false,
165655
+ projectPath,
165656
+ reason: "cooldown_active",
165657
+ leaseHolder: row.leaseHolder,
165658
+ leaseExpiresAt: row.leaseExpiresAt,
165659
+ lastSweptAt: row.lastSweptAt,
165660
+ nextAllowedAt
165661
+ };
165662
+ }
165663
+ }
165664
+ const leaseExpiresAt = now + leaseTtlMs;
165665
+ db.prepare(`INSERT INTO git_sweep_coordinator (
165666
+ project_path,
165667
+ lease_holder,
165668
+ lease_expires_at,
165669
+ last_swept_at
165670
+ ) VALUES (?, ?, ?, NULL)
165671
+ ON CONFLICT(project_path) DO UPDATE SET
165672
+ lease_holder = excluded.lease_holder,
165673
+ lease_expires_at = excluded.lease_expires_at`).run(projectPath, holderId, leaseExpiresAt);
165674
+ return {
165675
+ acquired: true,
165676
+ projectPath,
165677
+ holderId,
165678
+ acquiredAt: now,
165679
+ leaseExpiresAt
165680
+ };
165681
+ });
165682
+ }
165683
+ function renewGitSweepLease(db, projectPath, holderId, leaseTtlMs = GIT_SWEEP_LEASE_TTL_MS) {
165684
+ return runImmediate2(db, () => {
165685
+ const now = Date.now();
165686
+ const leaseExpiresAt = now + leaseTtlMs;
165687
+ const result = db.prepare(`UPDATE git_sweep_coordinator
165688
+ SET lease_expires_at = ?
165689
+ WHERE project_path = ?
165690
+ AND lease_holder = ?
165691
+ AND lease_expires_at > ?`).run(leaseExpiresAt, projectPath, holderId, now);
165692
+ return result.changes === 1;
165693
+ });
165694
+ }
165695
+ function markGitSweepSuccessAndRelease(db, projectPath, holderId) {
165696
+ return runImmediate2(db, () => {
165697
+ const now = Date.now();
165698
+ const result = db.prepare(`UPDATE git_sweep_coordinator
165699
+ SET lease_holder = NULL,
165700
+ lease_expires_at = NULL,
165701
+ last_swept_at = ?
165702
+ WHERE project_path = ?
165703
+ AND lease_holder = ?
165704
+ AND lease_expires_at > ?`).run(now, projectPath, holderId, now);
165705
+ return result.changes === 1;
165706
+ });
165707
+ }
165708
+ function releaseGitSweepLease(db, projectPath, holderId) {
165709
+ runImmediate2(db, () => {
165710
+ db.prepare(`UPDATE git_sweep_coordinator
165711
+ SET lease_holder = NULL,
165712
+ lease_expires_at = NULL
165713
+ WHERE project_path = ?
165714
+ AND lease_holder = ?`).run(projectPath, holderId);
165715
+ });
165716
+ }
165717
+
165766
165718
  // ../plugin/src/features/magic-context/project-embedding-registry.ts
165767
165719
  var OFF_PROVIDER_IDENTITY = "embedding-provider:off";
165768
165720
  var SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
@@ -165815,7 +165767,7 @@ function stableStringify2(value) {
165815
165767
  return JSON.stringify(value);
165816
165768
  }
165817
165769
  function sha256Prefix(value, length = 16) {
165818
- return createHash8("sha256").update(value).digest("hex").slice(0, length);
165770
+ return createHash7("sha256").update(value).digest("hex").slice(0, length);
165819
165771
  }
165820
165772
  function getRuntimeFingerprint(config2) {
165821
165773
  if (config2.provider === "off") {
@@ -166080,6 +166032,7 @@ var insertStatements = new WeakMap;
166080
166032
  var existingShasStatements = new WeakMap;
166081
166033
  var projectCountStatements = new WeakMap;
166082
166034
  var evictStatements = new WeakMap;
166035
+ var evictOverflowStatements = new WeakMap;
166083
166036
  var latestCommitTimeStatements = new WeakMap;
166084
166037
  function getInsertStatement(db) {
166085
166038
  let stmt = insertStatements.get(db);
@@ -166122,17 +166075,17 @@ function getLatestCommitTimeStatement(db) {
166122
166075
  }
166123
166076
  return stmt;
166124
166077
  }
166125
- function getEvictStatement(db) {
166126
- let stmt = evictStatements.get(db);
166078
+ function getEvictOverflowStatement(db) {
166079
+ let stmt = evictOverflowStatements.get(db);
166127
166080
  if (!stmt) {
166128
166081
  stmt = db.prepare(`DELETE FROM git_commits
166129
- WHERE sha IN (
166130
- SELECT sha FROM git_commits
166082
+ WHERE rowid IN (
166083
+ SELECT rowid FROM git_commits
166131
166084
  WHERE project_path = ?
166132
- ORDER BY committed_at ASC
166133
- LIMIT ?
166085
+ ORDER BY committed_at DESC, sha DESC
166086
+ LIMIT -1 OFFSET ?
166134
166087
  )`);
166135
- evictStatements.set(db, stmt);
166088
+ evictOverflowStatements.set(db, stmt);
166136
166089
  }
166137
166090
  return stmt;
166138
166091
  }
@@ -166170,22 +166123,15 @@ function getLatestIndexedCommitTimeMs(db, projectPath) {
166170
166123
  const row = getLatestCommitTimeStatement(db).get(projectPath);
166171
166124
  return row?.latest ?? null;
166172
166125
  }
166173
- function evictOldestCommits(db, projectPath, excess) {
166174
- if (excess <= 0)
166175
- return 0;
166176
- const before = getCommitCount(db, projectPath);
166177
- getEvictStatement(db).run(projectPath, excess);
166178
- const after = getCommitCount(db, projectPath);
166179
- return Math.max(0, before - after);
166180
- }
166181
166126
  function enforceProjectCap(db, projectPath, maxCommits) {
166182
166127
  if (maxCommits <= 0)
166183
166128
  return 0;
166184
166129
  const count = getCommitCount(db, projectPath);
166185
166130
  if (count <= maxCommits)
166186
166131
  return 0;
166187
- const excess = count - maxCommits;
166188
- const evicted = evictOldestCommits(db, projectPath, excess);
166132
+ getEvictOverflowStatement(db).run(projectPath, maxCommits);
166133
+ const after = getCommitCount(db, projectPath);
166134
+ const evicted = Math.max(0, count - after);
166189
166135
  if (evicted > 0) {
166190
166136
  log(`[git-commits] evicted ${evicted} oldest commits for project ${projectPath} (cap=${maxCommits}, was=${count})`);
166191
166137
  }
@@ -166565,10 +166511,31 @@ async function sweepProject(reg, origin, db, gitCommitEnabled = getProjectEmbedd
166565
166511
  log(`[dreamer] timer-triggered queue processing failed for ${reg.directory}:`, error51);
166566
166512
  }
166567
166513
  }
166514
+ function startGitSweepLeaseRenewal(db, projectIdentity, holderId) {
166515
+ const timer = setInterval(() => {
166516
+ try {
166517
+ if (!renewGitSweepLease(db, projectIdentity, holderId)) {
166518
+ log(`[git-commits] sweep lease renewal failed for ${projectIdentity}`);
166519
+ }
166520
+ } catch (error51) {
166521
+ log(`[git-commits] sweep lease renewal errored for ${projectIdentity}: ${error51 instanceof Error ? error51.message : String(error51)}`);
166522
+ }
166523
+ }, GIT_SWEEP_LEASE_RENEWAL_MS);
166524
+ timer.unref?.();
166525
+ return () => clearInterval(timer);
166526
+ }
166568
166527
  async function sweepGitCommits(args) {
166569
166528
  const { directory, projectIdentity, db, gitCommitIndexing } = args;
166529
+ const holderId = crypto.randomUUID();
166530
+ const lease2 = acquireGitSweepLease(db, projectIdentity, holderId);
166531
+ if (!lease2.acquired) {
166532
+ const reason = lease2.reason === "cooldown_active" ? `cooldown active until ${lease2.nextAllowedAt}` : `lease held by ${lease2.leaseHolder ?? "another holder"} until ${lease2.leaseExpiresAt ?? "unknown"}`;
166533
+ log(`[git-commits] sweep skipped for ${projectIdentity} (${directory}): ${reason}`);
166534
+ return;
166535
+ }
166570
166536
  const startedAt = Date.now();
166571
- log(`[git-commits] sweep starting for ${directory} (sinceDays=${gitCommitIndexing.since_days} maxCommits=${gitCommitIndexing.max_commits})`);
166537
+ const stopRenewal = startGitSweepLeaseRenewal(db, projectIdentity, holderId);
166538
+ log(`[git-commits] sweep starting for ${directory} (project=${projectIdentity} sinceDays=${gitCommitIndexing.since_days} maxCommits=${gitCommitIndexing.max_commits})`);
166572
166539
  try {
166573
166540
  const result = await indexCommitsForProject(db, projectIdentity, directory, {
166574
166541
  sinceDays: gitCommitIndexing.since_days,
@@ -166578,16 +166545,24 @@ async function sweepGitCommits(args) {
166578
166545
  if (result.embedded > 0) {
166579
166546
  drainedEmbeddings = await embedUnembeddedCommits(db, projectIdentity);
166580
166547
  }
166548
+ const cooldownMarked = markGitSweepSuccessAndRelease(db, projectIdentity, holderId);
166549
+ if (!cooldownMarked) {
166550
+ releaseGitSweepLease(db, projectIdentity, holderId);
166551
+ log(`[git-commits] sweep finished for ${projectIdentity}, but lease was no longer active; cooldown not advanced`);
166552
+ }
166581
166553
  const elapsedMs = Date.now() - startedAt;
166582
166554
  log(`[git-commits] sweep finished for ${projectIdentity} in ${elapsedMs}ms: scanned=${result.scanned} inserted=${result.inserted} updated=${result.updated} evicted=${result.evicted} embedded=${result.embedded} drained=${drainedEmbeddings}`);
166583
166555
  } catch (error51) {
166556
+ releaseGitSweepLease(db, projectIdentity, holderId);
166584
166557
  const elapsedMs = Date.now() - startedAt;
166585
166558
  log(`[git-commits] sweep failed for ${directory} after ${elapsedMs}ms: ${error51 instanceof Error ? error51.message : String(error51)}`);
166559
+ } finally {
166560
+ stopRenewal();
166586
166561
  }
166587
166562
  }
166588
166563
 
166589
166564
  // ../plugin/src/plugin/embedding-bootstrap-helpers.ts
166590
- import { createHash as createHash9 } from "node:crypto";
166565
+ import { createHash as createHash8 } from "node:crypto";
166591
166566
  init_logger();
166592
166567
  var EMBEDDING_AFFECTING_KEYS = new Set([
166593
166568
  "embedding.api_key",
@@ -166599,7 +166574,7 @@ var EMBEDDING_AFFECTING_TOP_LEVEL_KEYS = new Set(["embedding", "memory", "experi
166599
166574
  var EMBEDDING_WARNING_TERMS = ["api_key", "endpoint", "model", "provider", "embedding"];
166600
166575
  var loggedFailureSignatures = new Map;
166601
166576
  function sha256Prefix2(value, length = 16) {
166602
- return createHash9("sha256").update(value).digest("hex").slice(0, length);
166577
+ return createHash8("sha256").update(value).digest("hex").slice(0, length);
166603
166578
  }
166604
166579
  function warningLooksEmbeddingRelated(message) {
166605
166580
  const lower = message.toLowerCase();
@@ -166663,8 +166638,8 @@ function handleUntrustedLoad(db, projectIdentity, directory, detailed) {
166663
166638
  }
166664
166639
 
166665
166640
  // src/config/index.ts
166666
- import { existsSync as existsSync11, readFileSync as readFileSync8 } from "node:fs";
166667
- import { homedir as homedir5 } from "node:os";
166641
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "node:fs";
166642
+ import { homedir as homedir4 } from "node:os";
166668
166643
  import { join as join13 } from "node:path";
166669
166644
 
166670
166645
  // ../plugin/src/config/migrate-experimental.ts
@@ -166754,9 +166729,67 @@ function migrateLegacyExperimental(rawConfig, warnings) {
166754
166729
  }
166755
166730
 
166756
166731
  // ../plugin/src/config/variable.ts
166757
- import { existsSync as existsSync10, readFileSync as readFileSync7 } from "node:fs";
166758
- import { homedir as homedir4 } from "node:os";
166732
+ import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
166733
+ import { homedir as homedir3 } from "node:os";
166759
166734
  import { dirname as dirname5, isAbsolute as isAbsolute2, resolve as resolve3 } from "node:path";
166735
+
166736
+ // ../plugin/src/shared/jsonc-parser.ts
166737
+ function stripJsonComments(content) {
166738
+ let result = "";
166739
+ let inString = false;
166740
+ let escaped = false;
166741
+ let inLineComment = false;
166742
+ let inBlockComment = false;
166743
+ for (let index = 0;index < content.length; index += 1) {
166744
+ const char = content[index];
166745
+ const next = content[index + 1];
166746
+ if (inLineComment) {
166747
+ if (char === `
166748
+ `) {
166749
+ inLineComment = false;
166750
+ result += char;
166751
+ }
166752
+ continue;
166753
+ }
166754
+ if (inBlockComment) {
166755
+ if (char === "*" && next === "/") {
166756
+ inBlockComment = false;
166757
+ index += 1;
166758
+ }
166759
+ continue;
166760
+ }
166761
+ if (inString) {
166762
+ result += char;
166763
+ if (escaped) {
166764
+ escaped = false;
166765
+ } else if (char === "\\") {
166766
+ escaped = true;
166767
+ } else if (char === '"') {
166768
+ inString = false;
166769
+ }
166770
+ continue;
166771
+ }
166772
+ if (char === '"') {
166773
+ inString = true;
166774
+ result += char;
166775
+ continue;
166776
+ }
166777
+ if (char === "/" && next === "/") {
166778
+ inLineComment = true;
166779
+ index += 1;
166780
+ continue;
166781
+ }
166782
+ if (char === "/" && next === "*") {
166783
+ inBlockComment = true;
166784
+ index += 1;
166785
+ continue;
166786
+ }
166787
+ result += char;
166788
+ }
166789
+ return result;
166790
+ }
166791
+
166792
+ // ../plugin/src/config/variable.ts
166760
166793
  var ENV_PATTERN = /\{env:([^}]+)\}/g;
166761
166794
  var FILE_PATTERN = /\{file:([^}]+)\}/g;
166762
166795
  function substituteConfigVariables(input) {
@@ -166808,11 +166841,11 @@ function substituteConfigVariables(input) {
166808
166841
  }
166809
166842
  let filePath = rawPath.trim();
166810
166843
  if (filePath.startsWith("~/")) {
166811
- filePath = resolve3(homedir4(), filePath.slice(2));
166844
+ filePath = resolve3(homedir3(), filePath.slice(2));
166812
166845
  } else if (!isAbsolute2(filePath)) {
166813
166846
  filePath = resolve3(configDir, filePath);
166814
166847
  }
166815
- if (!existsSync10(filePath)) {
166848
+ if (!existsSync9(filePath)) {
166816
166849
  warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
166817
166850
  continue;
166818
166851
  }
@@ -166838,12 +166871,12 @@ function getProjectConfigPaths(cwd) {
166838
166871
  return [`${basePath}.jsonc`, `${basePath}.json`];
166839
166872
  }
166840
166873
  function getUserConfigPaths() {
166841
- const home = process.env.HOME ?? homedir5();
166874
+ const home = process.env.HOME ?? homedir4();
166842
166875
  const basePath = join13(home, ".pi", "agent", CONFIG_FILE_NAME);
166843
166876
  return [`${basePath}.jsonc`, `${basePath}.json`];
166844
166877
  }
166845
166878
  function resolveFirstExisting(paths) {
166846
- return paths.find((path7) => existsSync11(path7));
166879
+ return paths.find((path7) => existsSync10(path7));
166847
166880
  }
166848
166881
  function loadConfigFile(path7, scope) {
166849
166882
  try {
@@ -169447,6 +169480,62 @@ function buildToolTarget(part, message) {
169447
169480
 
169448
169481
  // ../plugin/src/features/magic-context/search.ts
169449
169482
  init_logger();
169483
+
169484
+ // ../plugin/src/features/magic-context/literal-probes.ts
169485
+ var MAX_PROBES = 5;
169486
+ var MIN_PROBE_LENGTH = 3;
169487
+ var SLASH_COMMAND_RE = /\/[a-z][a-z0-9]*(?:-[a-z0-9]+)+/gi;
169488
+ var KEBAB_SNAKE_RE = /[a-z][a-z0-9]*(?:[-_][a-z0-9]+)+/gi;
169489
+ var DOTTED_RE = /[a-z0-9][a-z0-9_-]*(?:\.[a-z0-9_-]+)+/gi;
169490
+ var CAMEL_RE = /\b[a-zA-Z][a-z0-9]*(?:[A-Z][a-z0-9]*)+\b/g;
169491
+ var SHA_RE = /\b[0-9a-f]{7,40}\b/gi;
169492
+ var ERROR_CODE_RE = /\b(?:TS\d{4,}|ERR_[A-Z][A-Z0-9_]*)\b/g;
169493
+ var QUOTED_RE = /["`]([^"`]{3,80})["`]/g;
169494
+ function looksLikeSha(token) {
169495
+ return /[0-9]/.test(token) && /^[0-9a-f]{7,40}$/i.test(token);
169496
+ }
169497
+ function extractLiteralProbes(query) {
169498
+ const trimmed = query.trim();
169499
+ if (trimmed.length === 0)
169500
+ return [];
169501
+ const ordered = [];
169502
+ const seen = new Set;
169503
+ const add = (raw) => {
169504
+ if (!raw)
169505
+ return;
169506
+ const probe = raw.trim();
169507
+ if (probe.length < MIN_PROBE_LENGTH)
169508
+ return;
169509
+ const key = probe.toLowerCase();
169510
+ if (seen.has(key))
169511
+ return;
169512
+ seen.add(key);
169513
+ ordered.push(probe);
169514
+ };
169515
+ for (const m of trimmed.matchAll(QUOTED_RE))
169516
+ add(m[1]);
169517
+ for (const m of trimmed.matchAll(SLASH_COMMAND_RE))
169518
+ add(m[0]);
169519
+ for (const m of trimmed.matchAll(ERROR_CODE_RE))
169520
+ add(m[0]);
169521
+ for (const m of trimmed.matchAll(DOTTED_RE))
169522
+ add(m[0]);
169523
+ for (const m of trimmed.matchAll(KEBAB_SNAKE_RE))
169524
+ add(m[0]);
169525
+ for (const m of trimmed.matchAll(CAMEL_RE))
169526
+ add(m[0]);
169527
+ for (const m of trimmed.matchAll(SHA_RE)) {
169528
+ if (looksLikeSha(m[0]))
169529
+ add(m[0]);
169530
+ }
169531
+ return ordered.slice(0, MAX_PROBES);
169532
+ }
169533
+ function containsProbeVerbatim(text, probes) {
169534
+ if (probes.length === 0)
169535
+ return false;
169536
+ const haystack = text.toLowerCase();
169537
+ return probes.some((probe) => haystack.includes(probe.toLowerCase()));
169538
+ }
169450
169539
  // ../plugin/src/features/magic-context/memory/embedding-backfill.ts
169451
169540
  init_logger();
169452
169541
  async function ensureMemoryEmbeddings(args) {
@@ -169709,36 +169798,82 @@ function linearDecayScore(rank, total) {
169709
169798
  return 0;
169710
169799
  return Math.max(0, 1 - rank / total);
169711
169800
  }
169712
- function searchMessages(args) {
169713
- const sanitizedQuery = sanitizeFtsQuery(args.query.trim());
169714
- if (sanitizedQuery.length === 0) {
169801
+ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
169802
+ if (ftsQuery.length === 0)
169715
169803
  return [];
169716
- }
169717
- const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
169718
- const rows = getMessageSearchStatement(args.db).all(args.sessionId, sanitizedQuery, fetchLimit).map((row) => row);
169719
- const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
169720
- const filtered = rows.map((row) => {
169804
+ const rows = getMessageSearchStatement(db).all(sessionId, ftsQuery, fetchLimit).map((row) => row);
169805
+ const result = [];
169806
+ for (const row of rows) {
169721
169807
  const messageOrdinal = getMessageOrdinal(row.messageOrdinal);
169722
169808
  if (messageOrdinal === null || typeof row.messageId !== "string" || typeof row.role !== "string" || typeof row.content !== "string") {
169723
- return null;
169809
+ continue;
169724
169810
  }
169725
169811
  if (cutoff !== null && messageOrdinal > cutoff) {
169726
- return null;
169812
+ continue;
169727
169813
  }
169728
- return {
169814
+ result.push({
169729
169815
  messageOrdinal,
169730
169816
  messageId: row.messageId,
169731
169817
  role: row.role,
169732
169818
  content: row.content
169733
- };
169734
- }).filter((result) => result !== null).slice(0, args.limit);
169735
- return filtered.map((row, rank) => ({
169819
+ });
169820
+ }
169821
+ return result;
169822
+ }
169823
+ var RRF_K = 60;
169824
+ var VERBATIM_PROBE_BONUS = 0.5;
169825
+ function searchMessages(args) {
169826
+ const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
169827
+ const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
169828
+ const baseQuery = sanitizeFtsQuery(args.query.trim());
169829
+ const probes = args.probes ?? [];
169830
+ if (probes.length === 0) {
169831
+ const filtered = runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff).slice(0, args.limit);
169832
+ return filtered.map((row, rank) => ({
169833
+ source: "message",
169834
+ content: previewText(row.content),
169835
+ score: linearDecayScore(rank, filtered.length),
169836
+ messageOrdinal: row.messageOrdinal,
169837
+ messageId: row.messageId,
169838
+ role: row.role
169839
+ }));
169840
+ }
169841
+ const queryLists = [];
169842
+ if (baseQuery.length > 0) {
169843
+ queryLists.push(runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff));
169844
+ }
169845
+ for (const probe of probes) {
169846
+ const probeQuery = sanitizeFtsQuery(probe);
169847
+ if (probeQuery.length === 0)
169848
+ continue;
169849
+ queryLists.push(runMessageFtsQuery(args.db, args.sessionId, probeQuery, fetchLimit, cutoff));
169850
+ }
169851
+ const fused = new Map;
169852
+ for (const list of queryLists) {
169853
+ list.forEach((row, rank) => {
169854
+ const rrf = 1 / (RRF_K + rank);
169855
+ const existing = fused.get(row.messageId);
169856
+ if (existing) {
169857
+ existing.score += rrf;
169858
+ } else {
169859
+ fused.set(row.messageId, { row, score: rrf });
169860
+ }
169861
+ });
169862
+ }
169863
+ for (const entry of fused.values()) {
169864
+ if (containsProbeVerbatim(entry.row.content, probes)) {
169865
+ entry.score += VERBATIM_PROBE_BONUS;
169866
+ }
169867
+ }
169868
+ 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);
169869
+ const maxScore = ranked.length > 0 ? ranked[0].score : 1;
169870
+ return ranked.map((entry) => ({
169736
169871
  source: "message",
169737
- content: previewText(row.content),
169738
- score: linearDecayScore(rank, filtered.length),
169739
- messageOrdinal: row.messageOrdinal,
169740
- messageId: row.messageId,
169741
- role: row.role
169872
+ content: previewText(entry.row.content),
169873
+ score: maxScore > 0 ? entry.score / maxScore : 0,
169874
+ messageOrdinal: entry.row.messageOrdinal,
169875
+ messageId: entry.row.messageId,
169876
+ role: entry.row.role
169742
169877
  }));
169743
169878
  }
169744
169879
  function getSourceBoost(result) {
@@ -169822,12 +169957,14 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
169822
169957
  return null;
169823
169958
  }) : Promise.resolve(null);
169824
169959
  await Promise.resolve();
169960
+ const messageProbes = options.explicitSearch ? extractLiteralProbes(trimmedQuery) : [];
169825
169961
  const messageResults = runMessages ? searchMessages({
169826
169962
  db,
169827
169963
  sessionId,
169828
169964
  query: trimmedQuery,
169829
169965
  limit: tierLimit,
169830
- maxOrdinal: options.maxMessageOrdinal
169966
+ maxOrdinal: options.maxMessageOrdinal,
169967
+ probes: messageProbes
169831
169968
  }) : [];
169832
169969
  const queryEmbedding = await queryEmbeddingPromise;
169833
169970
  const [memoryResults, gitCommitResults] = await Promise.all([
@@ -175690,7 +175827,7 @@ function stripPiDroppedPlaceholderMessages(args) {
175690
175827
  }
175691
175828
 
175692
175829
  // src/system-prompt.ts
175693
- import { createHash as createHash10 } from "node:crypto";
175830
+ import { createHash as createHash9 } from "node:crypto";
175694
175831
 
175695
175832
  // ../plugin/src/agents/magic-context-prompt.ts
175696
175833
  var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
@@ -175835,7 +175972,7 @@ function processSystemPromptForCache(args) {
175835
175972
  sessionLog(sessionId, `system prompt date frozen: real=${liveDate}, using=${stickyDate} (cache-stable pass)`);
175836
175973
  }
175837
175974
  }
175838
- const currentHash = createHash10("md5").update(frozenPrompt).digest("hex");
175975
+ const currentHash = createHash9("md5").update(frozenPrompt).digest("hex");
175839
175976
  const hashChanged = !isFirstHash && currentHash !== previousHash;
175840
175977
  if (hashChanged) {
175841
175978
  sessionLog(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${frozenPrompt.length})`);
@@ -176951,14 +177088,10 @@ function registerPiContextHandler(pi, options) {
176951
177088
  }
176952
177089
  const sessionMeta = sessionMetaForUsage;
176953
177090
  const modelKey = liveModelBySession.get(sessionId);
176954
- if (usageContextLimit === undefined && modelKey) {
176955
- const { providerID, modelID } = splitModelKeyForPi(modelKey);
176956
- const trusted = resolveTrustedContextLimit(providerID, modelID, {
176957
- db: options.db,
176958
- sessionID: sessionId
176959
- });
176960
- if (trusted !== undefined && trusted > 0) {
176961
- usageContextLimit = trusted;
177091
+ if (usageContextLimit === undefined) {
177092
+ const modelWindow = ctx.model?.contextWindow;
177093
+ if (isSaneLimit(modelWindow)) {
177094
+ usageContextLimit = modelWindow;
176962
177095
  }
176963
177096
  }
176964
177097
  let schedulerDecision;
@@ -177211,27 +177344,8 @@ async function awaitInFlightHistorians() {
177211
177344
  return;
177212
177345
  await Promise.allSettled(Array.from(inFlightHistorian.values()));
177213
177346
  }
177214
- function splitModelKeyForPi(modelKey) {
177215
- if (!modelKey)
177216
- return { providerID: undefined, modelID: undefined };
177217
- const slash = modelKey.indexOf("/");
177218
- if (slash <= 0 || slash === modelKey.length - 1) {
177219
- return { providerID: undefined, modelID: undefined };
177220
- }
177221
- return {
177222
- providerID: modelKey.slice(0, slash),
177223
- modelID: modelKey.slice(slash + 1)
177224
- };
177225
- }
177226
177347
  function resolvePiHistorianTriggerInputs(args) {
177227
- const { providerID, modelID } = splitModelKeyForPi(args.modelKey);
177228
- let contextLimit = resolveContextLimit(providerID, modelID, {
177229
- db: args.db,
177230
- sessionID: args.sessionId
177231
- });
177232
- if ((providerID === undefined || modelID === undefined) && typeof args.usageContextLimit === "number" && Number.isFinite(args.usageContextLimit) && args.usageContextLimit > 0) {
177233
- contextLimit = args.usageContextLimit;
177234
- }
177348
+ const contextLimit = typeof args.usageContextLimit === "number" && Number.isFinite(args.usageContextLimit) && args.usageContextLimit > 0 ? args.usageContextLimit : DEFAULT_CONTEXT_LIMIT;
177235
177349
  const executeThresholdPercentage = resolveExecuteThreshold(args.historian.executeThresholdPercentage ?? 65, args.modelKey, 65, {
177236
177350
  tokensConfig: args.historian.executeThresholdTokens,
177237
177351
  contextLimit,
@@ -178053,7 +178167,7 @@ ${result}`;
178053
178167
  init_logger();
178054
178168
 
178055
178169
  // ../plugin/src/hooks/magic-context/historian-state-file.ts
178056
- import { mkdirSync as mkdirSync5, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
178170
+ import { mkdirSync as mkdirSync6, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
178057
178171
  init_data_path();
178058
178172
  function cleanupHistorianStateFile(path7) {
178059
178173
  if (!path7)
@@ -178257,7 +178371,7 @@ function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEn
178257
178371
  }
178258
178372
 
178259
178373
  // ../plugin/src/hooks/magic-context/compartment-runner-historian.ts
178260
- import { mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
178374
+ import { mkdirSync as mkdirSync7, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
178261
178375
  import { join as join16 } from "node:path";
178262
178376
  init_data_path();
178263
178377
  function historianResponseDumpDir(directory) {
@@ -178562,11 +178676,11 @@ function cleanupHistorianDump(sessionId, dumpPath) {
178562
178676
  function dumpHistorianResponse(sessionId, directory, label, text) {
178563
178677
  try {
178564
178678
  const dumpDir = historianResponseDumpDir(directory);
178565
- mkdirSync6(dumpDir, { recursive: true });
178679
+ mkdirSync7(dumpDir, { recursive: true });
178566
178680
  const safeSessionId = sanitizeDumpName(sessionId);
178567
178681
  const safeLabel = sanitizeDumpName(label);
178568
178682
  const dumpPath = join16(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
178569
- writeFileSync3(dumpPath, text, "utf8");
178683
+ writeFileSync4(dumpPath, text, "utf8");
178570
178684
  sessionLog(sessionId, "compartment agent: historian response dumped", {
178571
178685
  label,
178572
178686
  dumpPath
@@ -180478,7 +180592,7 @@ function formatThresholdPercent(value) {
180478
180592
  // package.json
180479
180593
  var package_default = {
180480
180594
  name: "@cortexkit/pi-magic-context",
180481
- version: "0.22.1",
180595
+ version: "0.22.2",
180482
180596
  type: "module",
180483
180597
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
180484
180598
  main: "dist/index.js",
@@ -185582,15 +185696,26 @@ function err3(text) {
185582
185696
  isError: true
185583
185697
  };
185584
185698
  }
185699
+ function captureAnchorOrdinal(db, sessionId) {
185700
+ try {
185701
+ const ordinal = getLastIndexedOrdinal(db, sessionId);
185702
+ return ordinal > 0 ? ordinal : null;
185703
+ } catch {
185704
+ return null;
185705
+ }
185706
+ }
185707
+ function anchorSuffix(note) {
185708
+ return note.anchorOrdinal !== null ? ` ↳ @msg ${note.anchorOrdinal}` : "";
185709
+ }
185585
185710
  function formatNoteLine(note) {
185586
185711
  if (note.type === "smart") {
185587
185712
  const conditionLine = note.status === "ready" ? note.readyReason ?? note.surfaceCondition ?? "Condition satisfied" : note.surfaceCondition ?? "No condition recorded";
185588
185713
  const statusSuffix2 = note.status === "active" ? "" : ` (${note.status})`;
185589
- return `- **#${note.id}**${statusSuffix2}: ${note.content}
185714
+ return `- **#${note.id}**${statusSuffix2}: ${note.content}${anchorSuffix(note)}
185590
185715
  *Condition*: ${conditionLine}`;
185591
185716
  }
185592
185717
  const statusSuffix = note.status === "active" ? "" : ` (${note.status})`;
185593
- return `- **#${note.id}**${statusSuffix}: ${note.content}`;
185718
+ return `- **#${note.id}**${statusSuffix}: ${note.content}${anchorSuffix(note)}`;
185594
185719
  }
185595
185720
  var DISMISS_FOOTER = `
185596
185721
 
@@ -185612,6 +185737,7 @@ function createCtxNoteTool(deps) {
185612
185737
  const content = params.content?.trim();
185613
185738
  if (!content)
185614
185739
  return err3("Error: 'content' is required when action is 'write'.");
185740
+ const anchorOrdinal = captureAnchorOrdinal(deps.db, sessionId);
185615
185741
  const surfaceCondition = params.surface_condition?.trim();
185616
185742
  if (surfaceCondition) {
185617
185743
  if (deps.dreamerEnabled !== true) {
@@ -185624,13 +185750,18 @@ function createCtxNoteTool(deps) {
185624
185750
  const note2 = addNote(deps.db, "smart", {
185625
185751
  content,
185626
185752
  projectPath: projectIdentity,
185627
- surfaceCondition
185753
+ surfaceCondition,
185754
+ anchorOrdinal
185628
185755
  });
185629
185756
  return ok3(`Created smart note #${note2.id}. Dreamer will evaluate the condition during nightly runs:
185630
185757
  - Content: ${content}
185631
185758
  - Condition: ${surfaceCondition}`);
185632
185759
  }
185633
- const note = addNote(deps.db, "session", { sessionId, content });
185760
+ const note = addNote(deps.db, "session", {
185761
+ sessionId,
185762
+ content,
185763
+ anchorOrdinal
185764
+ });
185634
185765
  return ok3(`Saved session note #${note.id}.`);
185635
185766
  }
185636
185767
  if (action2 === "dismiss") {
@@ -185693,9 +185824,13 @@ function createCtxNoteTool(deps) {
185693
185824
 
185694
185825
  No notes for the current filter.`);
185695
185826
  }
185696
- return ok3(`${sections.join(`
185827
+ const body = sections.join(`
185828
+
185829
+ `);
185830
+ const anchorHint = body.includes("↳ @msg ") ? `
185697
185831
 
185698
- `)}${DISMISS_FOOTER}`);
185832
+ ↳ @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).` : "";
185833
+ return ok3(`${body}${anchorHint}${DISMISS_FOOTER}`);
185699
185834
  }
185700
185835
  };
185701
185836
  }
@@ -186040,7 +186175,8 @@ function createCtxSearchTool(deps) {
186040
186175
  maxMessageOrdinal: lastCompartmentEnd >= 0 ? lastCompartmentEnd : undefined,
186041
186176
  gitCommitsEnabled,
186042
186177
  sources: params.sources,
186043
- visibleMemoryIds
186178
+ visibleMemoryIds,
186179
+ explicitSearch: true
186044
186180
  });
186045
186181
  return {
186046
186182
  content: [{ type: "text", text: formatSearchResults(query, results) }],
@@ -186188,8 +186324,7 @@ function getPiMessageModel(message) {
186188
186324
  };
186189
186325
  }
186190
186326
  function resolvePiPressureContextLimit(args) {
186191
- const cachedLimit = args.provider && args.model ? getModelsDevContextLimit(args.provider, args.model) : undefined;
186192
- let effectiveContextLimit = cachedLimit ?? args.piContextWindow;
186327
+ let effectiveContextLimit = isSaneLimit(args.piContextWindow) ? args.piContextWindow : 0;
186193
186328
  try {
186194
186329
  const overflowState = getOverflowState(args.db, args.sessionId);
186195
186330
  if (overflowState.detectedContextLimit > 0) {
@@ -186205,8 +186340,6 @@ async function persistPiPressureFromMessageEnd(args) {
186205
186340
  const effectiveContextLimit = resolvePiPressureContextLimit({
186206
186341
  db: args.db,
186207
186342
  sessionId: args.sessionId,
186208
- provider: provider2,
186209
- model,
186210
186343
  piContextWindow: args.piContextWindow
186211
186344
  });
186212
186345
  const usage = extractAssistantUsage(args.message);
@@ -186215,24 +186348,12 @@ async function persistPiPressureFromMessageEnd(args) {
186215
186348
  const messageHadOverflowError = typeof msg?.errorMessage === "string" && detectOverflow(msg.errorMessage).isOverflow;
186216
186349
  const updates = { lastResponseTime: Date.now() };
186217
186350
  if (pressure) {
186218
- let percentage = pressure.percentage;
186219
- let contextLimit = effectiveContextLimit;
186351
+ const percentage = pressure.percentage;
186352
+ const contextLimit = effectiveContextLimit;
186220
186353
  const meta3 = getOrCreateSessionMeta(args.db, args.sessionId);
186221
186354
  const observedSafeInputTokens = meta3.observedSafeInputTokens ?? 0;
186222
186355
  if (percentage > 100 && observedSafeInputTokens > 0 && pressure.inputTokens <= observedSafeInputTokens * 2) {
186223
- const oldLimit = contextLimit;
186224
- clearModelsDevCache();
186225
- contextLimit = resolvePiPressureContextLimit({
186226
- db: args.db,
186227
- sessionId: args.sessionId,
186228
- provider: provider2,
186229
- model,
186230
- piContextWindow: args.piContextWindow
186231
- });
186232
- if (contextLimit >= pressure.inputTokens) {
186233
- percentage = pressure.inputTokens / contextLimit * 100;
186234
- log(`${PREFIX} models-dev-cache: regression recovered for ${provider2}/${model} via Pi cache reload (was=${oldLimit}, now=${contextLimit})`);
186235
- } else if (!meta3.cacheAlertSent) {
186356
+ if (!meta3.cacheAlertSent) {
186236
186357
  updates.cacheAlertSent = true;
186237
186358
  const safeTokens = Math.max(observedSafeInputTokens, pressure.inputTokens);
186238
186359
  const modelLabel = provider2 && model ? `${provider2}/${model}` : "the active model";
@@ -186703,7 +186824,7 @@ ${block}` : event.systemPrompt;
186703
186824
  cacheTtlConfig: config2.cache_ttl
186704
186825
  });
186705
186826
  const piUsage = ctx.getContextUsage?.();
186706
- const piContextWindow = piUsage && typeof piUsage.contextWindow === "number" ? piUsage.contextWindow : 0;
186827
+ const piContextWindow = piUsage && typeof piUsage.contextWindow === "number" && piUsage.contextWindow > 0 ? piUsage.contextWindow : ctx.model?.contextWindow ?? 0;
186707
186828
  await persistPiPressureFromMessageEnd({
186708
186829
  db,
186709
186830
  sessionId,