@cortexkit/pi-magic-context 0.22.1 → 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.
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
@@ -140945,14 +140942,48 @@ function readRawSessionMessagesFromDb(db, sessionId) {
140945
140942
  var encoder = new TextEncoder;
140946
140943
  var TAG_PREFIX_REGEX = /^(?:§\d+§\s*)+/;
140947
140944
  var MALFORMED_TAG_PREFIX_REGEX = /^(?:§\d+">§(?:\d+§)?\s*)+/;
140945
+ var COMPLETE_TAG_PAIR_GLOBAL_REGEX = /\u00a7\d+\u00a7/g;
140946
+ var MALFORMED_TAG_GLOBAL_REGEX = /\u00a7\d+">(?:\u00a7(?:\d+\u00a7)?)?/g;
140947
+ var STRAY_SECTION_CHAR_REGEX = /\u00a7/g;
140948
+ function stripWellFormedLeadingTagPrefix(value) {
140949
+ return value.replace(/^(\u00a7\d+\u00a7\s*)+/, "");
140950
+ }
140951
+ function stripCompleteTagPairsGlobally(value) {
140952
+ return value.replace(COMPLETE_TAG_PAIR_GLOBAL_REGEX, "");
140953
+ }
140954
+ function stripMalformedTagNotationGlobally(value) {
140955
+ return value.replace(MALFORMED_TAG_GLOBAL_REGEX, "");
140956
+ }
140957
+ function stripTagSectionCharacters(value) {
140958
+ return value.replace(STRAY_SECTION_CHAR_REGEX, "");
140959
+ }
140960
+ function stripPersistedAssistantText(value) {
140961
+ let text = stripWellFormedLeadingTagPrefix(value);
140962
+ text = stripCompleteTagPairsGlobally(text);
140963
+ text = stripMalformedTagNotationGlobally(text);
140964
+ text = stripTagSectionCharacters(text);
140965
+ return text.trim();
140966
+ }
140948
140967
  function byteSize(value) {
140949
140968
  return encoder.encode(value).length;
140950
140969
  }
140951
140970
  function stripTagPrefix(value) {
140952
- let stripped = value.replace(MALFORMED_TAG_PREFIX_REGEX, "");
140953
- stripped = stripped.replace(TAG_PREFIX_REGEX, "");
140971
+ let stripped = value;
140972
+ for (let pass = 0;pass < 8; pass++) {
140973
+ const prev = stripped;
140974
+ stripped = stripped.replace(MALFORMED_TAG_PREFIX_REGEX, "");
140975
+ stripped = stripped.replace(TAG_PREFIX_REGEX, "");
140976
+ if (stripped === prev)
140977
+ break;
140978
+ }
140954
140979
  return stripped;
140955
140980
  }
140981
+ function peelLeadingMcTagNotation(value) {
140982
+ const body = stripTagPrefix(value);
140983
+ if (body === value)
140984
+ return { tagPrefix: "", body };
140985
+ return { tagPrefix: value.slice(0, value.length - body.length), body };
140986
+ }
140956
140987
  function prependTag(tagId, value) {
140957
140988
  const stripped = stripTagPrefix(value);
140958
140989
  return `§${tagId}§ ${stripped}`;
@@ -140994,7 +141025,9 @@ function hasMeaningfulPart(part) {
140994
141025
  return false;
140995
141026
  const type = part.type;
140996
141027
  if (type === "text") {
140997
- return typeof part.text === "string" && part.text.trim().length > 0;
141028
+ if (typeof part.text !== "string")
141029
+ return false;
141030
+ return stripTagPrefix(part.text).trim().length > 0;
140998
141031
  }
140999
141032
  if (typeof type !== "string")
141000
141033
  return false;
@@ -142698,7 +142731,7 @@ var databases = new Map;
142698
142731
  var persistenceByDatabase = new WeakMap;
142699
142732
  var persistenceErrorByDatabase = new WeakMap;
142700
142733
  var lastSchemaFenceRejection = null;
142701
- var LATEST_SUPPORTED_VERSION = 27;
142734
+ var LATEST_SUPPORTED_VERSION = 29;
142702
142735
  function resolveDatabasePath(dbPathOverride) {
142703
142736
  if (dbPathOverride) {
142704
142737
  return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
@@ -143018,6 +143051,17 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143018
143051
  updated_at INTEGER NOT NULL DEFAULT 0
143019
143052
  );
143020
143053
 
143054
+ CREATE TABLE IF NOT EXISTS git_sweep_coordinator (
143055
+ project_path TEXT PRIMARY KEY,
143056
+ lease_holder TEXT,
143057
+ lease_expires_at INTEGER,
143058
+ last_swept_at INTEGER
143059
+ );
143060
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_lease_expires
143061
+ ON git_sweep_coordinator(lease_expires_at);
143062
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_last_swept
143063
+ ON git_sweep_coordinator(last_swept_at);
143064
+
143021
143065
  CREATE TABLE IF NOT EXISTS m0_mutation_log (
143022
143066
  id INTEGER PRIMARY KEY AUTOINCREMENT,
143023
143067
  session_id TEXT NOT NULL,
@@ -144240,6 +144284,38 @@ var MIGRATIONS = [
144240
144284
  ON tags(session_id, entry_fingerprint)
144241
144285
  WHERE type='message' AND entry_fingerprint IS NOT NULL`);
144242
144286
  }
144287
+ },
144288
+ {
144289
+ version: 28,
144290
+ description: "Add git commit sweep coordinator lease/cooldown table",
144291
+ up: (db) => {
144292
+ db.exec(`
144293
+ CREATE TABLE IF NOT EXISTS git_sweep_coordinator (
144294
+ project_path TEXT PRIMARY KEY,
144295
+ lease_holder TEXT,
144296
+ lease_expires_at INTEGER,
144297
+ last_swept_at INTEGER
144298
+ );
144299
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_lease_expires
144300
+ ON git_sweep_coordinator(lease_expires_at);
144301
+ CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_last_swept
144302
+ ON git_sweep_coordinator(last_swept_at);
144303
+ `);
144304
+ }
144305
+ },
144306
+ {
144307
+ version: 29,
144308
+ description: "Add anchor_ordinal to notes (traceback to the conversation tail)",
144309
+ up: (db) => {
144310
+ const notesExists = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='notes'").get();
144311
+ if (!notesExists) {
144312
+ return;
144313
+ }
144314
+ const columns = db.prepare("PRAGMA table_info(notes)").all();
144315
+ if (!columns.some((column) => column.name === "anchor_ordinal")) {
144316
+ db.exec("ALTER TABLE notes ADD COLUMN anchor_ordinal INTEGER");
144317
+ }
144318
+ }
144243
144319
  }
144244
144320
  ];
144245
144321
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -145127,7 +145203,8 @@ function toNote(row) {
145127
145203
  updatedAt: row.updated_at,
145128
145204
  lastCheckedAt: toNullableNumber(row.last_checked_at),
145129
145205
  readyAt: toNullableNumber(row.ready_at),
145130
- readyReason: toNullableString(row.ready_reason)
145206
+ readyReason: toNullableString(row.ready_reason),
145207
+ anchorOrdinal: toNullableNumber(row.anchor_ordinal)
145131
145208
  };
145132
145209
  }
145133
145210
  function getNoteById(db, noteId) {
@@ -145179,7 +145256,7 @@ function getNotes(db, options = {}) {
145179
145256
  }
145180
145257
  function addNote(db, type, options) {
145181
145258
  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());
145259
+ 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
145260
  if (!isNoteRow(result)) {
145184
145261
  throw new Error("[notes] failed to insert note");
145185
145262
  }
@@ -145949,212 +146026,41 @@ function getAgentFallbackModels(agent) {
145949
146026
 
145950
146027
  // ../plugin/src/shared/models-dev-cache.ts
145951
146028
  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";
146029
+ init_logger();
146030
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync, writeFileSync } from "node:fs";
145955
146031
  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;
146032
+ var MIN_SANE_LIMIT = 20000;
146033
+ var MAX_SANE_LIMIT = 3000000;
146034
+ function isSaneLimit(limit) {
146035
+ return typeof limit === "number" && limit >= MIN_SANE_LIMIT && limit <= MAX_SANE_LIMIT;
146047
146036
  }
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
146037
  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;
146082
- }
146083
- function resolveLimit(limit) {
146084
- if (!limit)
146085
- 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;
146038
+ var persistSeedLoaded = false;
146039
+ function persistFilePath() {
146040
+ return join6(getMagicContextStorageDir(), `model-context-limits-${getHarness()}.json`);
146091
146041
  }
146092
- function setCachedModelMetadata(cache, key, model) {
146093
- const limit = resolveLimit(model?.limit);
146094
- if (limit === undefined) {
146042
+ function loadPersistedApiCacheOnce() {
146043
+ if (persistSeedLoaded || apiCache !== null)
146095
146044
  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;
146045
+ persistSeedLoaded = true;
146110
146046
  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
- }
146047
+ const raw = readFileSync3(persistFilePath(), "utf-8");
146048
+ const obj = JSON.parse(raw);
146049
+ const map = new Map;
146050
+ for (const [key, limit] of Object.entries(obj)) {
146051
+ if (isSaneLimit(limit))
146052
+ map.set(key, { limit });
146122
146053
  }
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
- }
146054
+ if (map.size > 0) {
146055
+ apiCache = map;
146056
+ sessionLog("global", `models-dev-cache: seeded ${map.size} entries from persisted cache (cold start)`);
146139
146057
  }
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;
146058
+ } catch {}
146145
146059
  }
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
- }
146060
+ function getSdkContextLimit(providerID, modelID) {
146061
+ loadPersistedApiCacheOnce();
146152
146062
  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;
146063
+ return isSaneLimit(fromApi) ? fromApi : undefined;
146158
146064
  }
146159
146065
  function lookupLimitWithTagFallback(cache, providerID, modelID) {
146160
146066
  if (!cache)
@@ -146171,12 +146077,6 @@ function lookupLimitWithTagFallback(cache, providerID, modelID) {
146171
146077
  }
146172
146078
  return;
146173
146079
  }
146174
- function clearModelsDevCache() {
146175
- apiCache = null;
146176
- apiLoadedAt = 0;
146177
- fileCache = null;
146178
- fileLastAttempt = 0;
146179
- }
146180
146080
 
146181
146081
  // ../plugin/src/hooks/magic-context/derive-budgets.ts
146182
146082
  var TRIGGER_BUDGET_PERCENTAGE = 0.05;
@@ -146207,7 +146107,7 @@ function resolveHistorianContextLimit(historianModelOverride) {
146207
146107
  const [providerID, ...rest] = historianModelOverride.split("/");
146208
146108
  const modelID = rest.join("/");
146209
146109
  if (providerID && modelID) {
146210
- const limit = getModelsDevContextLimit(providerID, modelID);
146110
+ const limit = getSdkContextLimit(providerID, modelID);
146211
146111
  if (typeof limit === "number" && limit > 0)
146212
146112
  return limit;
146213
146113
  }
@@ -146226,7 +146126,7 @@ function resolveHistorianContextLimit(historianModelOverride) {
146226
146126
  const modelID = rest.join("/");
146227
146127
  if (!providerID || !modelID)
146228
146128
  continue;
146229
- const limit = getModelsDevContextLimit(providerID, modelID);
146129
+ const limit = getSdkContextLimit(providerID, modelID);
146230
146130
  if (typeof limit !== "number" || limit <= 0)
146231
146131
  continue;
146232
146132
  if (minLimit === undefined || limit < minLimit)
@@ -146239,37 +146139,6 @@ function resolveHistorianContextLimit(historianModelOverride) {
146239
146139
  init_logger();
146240
146140
  var DEFAULT_CONTEXT_LIMIT = 128000;
146241
146141
  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
146142
  function resolveCacheTtl(cacheTtl, modelKey) {
146274
146143
  if (typeof cacheTtl === "string") {
146275
146144
  return cacheTtl;
@@ -146490,7 +146359,7 @@ function clearNoteNudgeTriggerOnly(db, sessionId) {
146490
146359
  }
146491
146360
 
146492
146361
  // ../plugin/src/hooks/magic-context/todo-view.ts
146493
- import { createHash as createHash6 } from "node:crypto";
146362
+ import { createHash as createHash5 } from "node:crypto";
146494
146363
  var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
146495
146364
  var TITLE_DONE_STATUSES = new Set(["completed"]);
146496
146365
  var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
@@ -146535,7 +146404,7 @@ function buildSyntheticTodoPart(stateJson) {
146535
146404
  };
146536
146405
  }
146537
146406
  function computeSyntheticCallId(stateJson) {
146538
- const hash = createHash6("sha256").update(stateJson).digest("hex").slice(0, 16);
146407
+ const hash = createHash5("sha256").update(stateJson).digest("hex").slice(0, 16);
146539
146408
  return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
146540
146409
  }
146541
146410
  function parseTodoState(stateJson) {
@@ -146789,7 +146658,7 @@ init_logger();
146789
146658
 
146790
146659
  // src/subagent-runner.ts
146791
146660
  import * as childProcess from "node:child_process";
146792
- import { existsSync as existsSync7 } from "node:fs";
146661
+ import { existsSync as existsSync6 } from "node:fs";
146793
146662
  import { createRequire as createRequire2 } from "node:module";
146794
146663
  import { dirname as dirname3, join as join8, resolve as resolvePath } from "node:path";
146795
146664
  import { createInterface } from "node:readline";
@@ -146893,7 +146762,7 @@ function resolveBundledPiCli() {
146893
146762
  const require_ = createRequire2(import.meta.url);
146894
146763
  const pkgJson = require_.resolve("@earendil-works/pi-coding-agent/package.json");
146895
146764
  const cliPath = join8(dirname3(pkgJson), "dist/cli.js");
146896
- if (existsSync7(cliPath))
146765
+ if (existsSync6(cliPath))
146897
146766
  return cliPath;
146898
146767
  return null;
146899
146768
  } catch {
@@ -146904,7 +146773,7 @@ function resolveSubagentEntryPath() {
146904
146773
  try {
146905
146774
  const here = dirname3(fileURLToPath(import.meta.url));
146906
146775
  const candidate = resolvePath(here, "subagent-entry.js");
146907
- if (existsSync7(candidate))
146776
+ if (existsSync6(candidate))
146908
146777
  return candidate;
146909
146778
  return;
146910
146779
  } catch {
@@ -147664,7 +147533,7 @@ function clearStaleEntries(db, maxAgeMs, projectIdentity) {
147664
147533
  // src/commands/ctx-dream.ts
147665
147534
  init_logger();
147666
147535
  // ../plugin/src/features/magic-context/dreamer/runner.ts
147667
- import { existsSync as existsSync9 } from "node:fs";
147536
+ import { existsSync as existsSync8 } from "node:fs";
147668
147537
  import { join as join11 } from "node:path";
147669
147538
 
147670
147539
  // ../plugin/src/shared/index.ts
@@ -147918,12 +147787,12 @@ init_logger();
147918
147787
 
147919
147788
  // ../plugin/src/features/magic-context/key-files/aft-availability.ts
147920
147789
  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";
147790
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
147791
+ import { homedir as homedir2 } from "node:os";
147923
147792
  import { join as join9 } from "node:path";
147924
147793
  var overrideAvailability = null;
147925
147794
  function parseConfig(path7) {
147926
- if (!existsSync8(path7))
147795
+ if (!existsSync7(path7))
147927
147796
  return null;
147928
147797
  return import_comment_json.parse(readFileSync5(path7, "utf-8"));
147929
147798
  }
@@ -147945,7 +147814,7 @@ function hasAftAtKeys(value, keys) {
147945
147814
  return false;
147946
147815
  }
147947
147816
  function getAftAvailability() {
147948
- const home = process.env.HOME || homedir3();
147817
+ const home = process.env.HOME || homedir2();
147949
147818
  const opencodePaths = [
147950
147819
  join9(home, ".config", "opencode", "opencode.jsonc"),
147951
147820
  join9(home, ".config", "opencode", "opencode.json")
@@ -148589,13 +148458,13 @@ function invalidateMemory(projectPath, memoryId) {
148589
148458
  }
148590
148459
 
148591
148460
  // ../plugin/src/features/magic-context/memory/normalize-hash.ts
148592
- import { createHash as createHash7 } from "node:crypto";
148461
+ import { createHash as createHash6 } from "node:crypto";
148593
148462
  function normalizeMemoryContent(content) {
148594
148463
  return content.toLowerCase().replace(/\s+/g, " ").trim();
148595
148464
  }
148596
148465
  function computeNormalizedHash(content) {
148597
148466
  const normalized = normalizeMemoryContent(content);
148598
- return createHash7("md5").update(normalized).digest("hex");
148467
+ return createHash6("md5").update(normalized).digest("hex");
148599
148468
  }
148600
148469
 
148601
148470
  // ../plugin/src/features/magic-context/memory/storage-memory.ts
@@ -149746,7 +149615,7 @@ function getOpenCodeDbPath2() {
149746
149615
  }
149747
149616
  function openOpenCodeDb() {
149748
149617
  const dbPath = getOpenCodeDbPath2();
149749
- if (!existsSync9(dbPath)) {
149618
+ if (!existsSync8(dbPath)) {
149750
149619
  log(`[key-files] OpenCode DB not found at ${dbPath} — skipping`);
149751
149620
  return null;
149752
149621
  }
@@ -149896,8 +149765,8 @@ async function runDream(args) {
149896
149765
  try {
149897
149766
  const docsDir = args.sessionDirectory ?? args.projectIdentity;
149898
149767
  const existingDocs = taskName === "maintain-docs" ? {
149899
- architecture: existsSync9(join11(docsDir, "ARCHITECTURE.md")),
149900
- structure: existsSync9(join11(docsDir, "STRUCTURE.md"))
149768
+ architecture: existsSync8(join11(docsDir, "ARCHITECTURE.md")),
149769
+ structure: existsSync8(join11(docsDir, "STRUCTURE.md"))
149901
149770
  } : undefined;
149902
149771
  const userMemories = taskName === "archive-stale" ? getActiveUserMemories(args.db).map((um) => ({
149903
149772
  id: um.id,
@@ -150387,7 +150256,7 @@ async function processDreamQueue(args) {
150387
150256
  return null;
150388
150257
  }
150389
150258
  const projectDirectory = args.sessionDirectoryOverride ?? resolveDreamSessionDirectory(entry.projectIdentity);
150390
- log(`[dreamer] dequeued project ${entry.projectIdentity} (dir=${projectDirectory}), starting dream run`);
150259
+ log(`[dreamer] dequeued project ${entry.projectIdentity}, starting dream run`);
150391
150260
  let result;
150392
150261
  try {
150393
150262
  result = await runDream({
@@ -150511,6 +150380,7 @@ async function readGitCommits(directory, options = {}) {
150511
150380
  if (revision.startsWith("-")) {
150512
150381
  throw new Error(`readGitCommits: refusing revision that looks like an option: "${revision}"`);
150513
150382
  }
150383
+ const projectLabel = options.projectIdentity ?? "<project>";
150514
150384
  const args = [
150515
150385
  "log",
150516
150386
  revision,
@@ -150533,11 +150403,11 @@ async function readGitCommits(directory, options = {}) {
150533
150403
  stdout = result.stdout;
150534
150404
  } catch (error) {
150535
150405
  const message = error instanceof Error ? error.message : String(error);
150536
- log(`[git-commits] readGitCommits failed at cwd=${directory}: ${message.slice(0, 500)}`);
150406
+ log(`[git-commits] readGitCommits failed for ${projectLabel}: ${message.slice(0, 500)}`);
150537
150407
  return [];
150538
150408
  }
150539
150409
  if (stdout.trim().length === 0) {
150540
- log(`[git-commits] readGitCommits returned empty stdout at cwd=${directory} (sinceMs=${options.sinceMs ?? "none"} args=${args.slice(0, 4).join(" ")})`);
150410
+ log(`[git-commits] readGitCommits returned empty stdout for ${projectLabel} (sinceMs=${options.sinceMs ?? "none"} args=${args.slice(0, 4).join(" ")})`);
150541
150411
  }
150542
150412
  return parseGitLogOutput(stdout);
150543
150413
  }
@@ -165103,7 +164973,7 @@ function getEmbeddingProviderIdentity(config2) {
165103
164973
  }
165104
164974
 
165105
164975
  // ../plugin/src/features/magic-context/memory/embedding-local.ts
165106
- import { mkdirSync as mkdirSync4 } from "node:fs";
164976
+ import { mkdirSync as mkdirSync5 } from "node:fs";
165107
164977
  import { open, stat, unlink, writeFile } from "node:fs/promises";
165108
164978
  import { dirname as dirname4, join as join12 } from "node:path";
165109
164979
  import { pathToFileURL } from "node:url";
@@ -165284,7 +165154,7 @@ class LocalEmbeddingProvider {
165284
165154
  }
165285
165155
  const modelCacheDir = join12(getMagicContextStorageDir(), "models");
165286
165156
  try {
165287
- mkdirSync4(modelCacheDir, { recursive: true });
165157
+ mkdirSync5(modelCacheDir, { recursive: true });
165288
165158
  env.cacheDir = modelCacheDir;
165289
165159
  } catch {
165290
165160
  log("[magic-context] could not create model cache dir, using library default");
@@ -165659,7 +165529,7 @@ class OpenAICompatibleEmbeddingProvider {
165659
165529
  }
165660
165530
 
165661
165531
  // ../plugin/src/features/magic-context/project-embedding-registry.ts
165662
- import { createHash as createHash8 } from "node:crypto";
165532
+ import { createHash as createHash7, randomUUID } from "node:crypto";
165663
165533
  init_logger();
165664
165534
 
165665
165535
  // ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
@@ -165763,6 +165633,125 @@ function getDistinctCommitEmbeddingModelIds(db, projectPath) {
165763
165633
  return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
165764
165634
  }
165765
165635
 
165636
+ // ../plugin/src/features/magic-context/git-commits/sweep-coordinator.ts
165637
+ var GIT_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
165638
+ var GIT_SWEEP_LEASE_TTL_MS = 5 * 60 * 1000;
165639
+ var GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
165640
+ function runImmediate2(db, body) {
165641
+ db.exec("BEGIN IMMEDIATE");
165642
+ let committed = false;
165643
+ try {
165644
+ const result = body();
165645
+ db.exec("COMMIT");
165646
+ committed = true;
165647
+ return result;
165648
+ } finally {
165649
+ if (!committed) {
165650
+ try {
165651
+ db.exec("ROLLBACK");
165652
+ } catch {}
165653
+ }
165654
+ }
165655
+ }
165656
+ function rowToState(row) {
165657
+ return {
165658
+ projectPath: row.project_path,
165659
+ leaseHolder: row.lease_holder,
165660
+ leaseExpiresAt: row.lease_expires_at,
165661
+ lastSweptAt: row.last_swept_at
165662
+ };
165663
+ }
165664
+ function getGitSweepCoordinatorState(db, projectPath) {
165665
+ const row = db.prepare(`SELECT project_path, lease_holder, lease_expires_at, last_swept_at
165666
+ FROM git_sweep_coordinator
165667
+ WHERE project_path = ?`).get(projectPath);
165668
+ return row ? rowToState(row) : null;
165669
+ }
165670
+ function acquireGitSweepLease(db, projectPath, holderId, options = {}) {
165671
+ const cooldownMs = options.cooldownMs ?? GIT_SWEEP_COOLDOWN_MS;
165672
+ const leaseTtlMs = options.leaseTtlMs ?? GIT_SWEEP_LEASE_TTL_MS;
165673
+ return runImmediate2(db, () => {
165674
+ const now = Date.now();
165675
+ const row = getGitSweepCoordinatorState(db, projectPath);
165676
+ if (row?.leaseHolder && row.leaseExpiresAt !== null && row.leaseExpiresAt > now) {
165677
+ return {
165678
+ acquired: false,
165679
+ projectPath,
165680
+ reason: "lease_active",
165681
+ leaseHolder: row.leaseHolder,
165682
+ leaseExpiresAt: row.leaseExpiresAt,
165683
+ lastSweptAt: row.lastSweptAt,
165684
+ nextAllowedAt: null
165685
+ };
165686
+ }
165687
+ if (!options.ignoreCooldown && row?.lastSweptAt !== null && row?.lastSweptAt !== undefined) {
165688
+ const nextAllowedAt = row.lastSweptAt + cooldownMs;
165689
+ if (nextAllowedAt > now) {
165690
+ return {
165691
+ acquired: false,
165692
+ projectPath,
165693
+ reason: "cooldown_active",
165694
+ leaseHolder: row.leaseHolder,
165695
+ leaseExpiresAt: row.leaseExpiresAt,
165696
+ lastSweptAt: row.lastSweptAt,
165697
+ nextAllowedAt
165698
+ };
165699
+ }
165700
+ }
165701
+ const leaseExpiresAt = now + leaseTtlMs;
165702
+ db.prepare(`INSERT INTO git_sweep_coordinator (
165703
+ project_path,
165704
+ lease_holder,
165705
+ lease_expires_at,
165706
+ last_swept_at
165707
+ ) VALUES (?, ?, ?, NULL)
165708
+ ON CONFLICT(project_path) DO UPDATE SET
165709
+ lease_holder = excluded.lease_holder,
165710
+ lease_expires_at = excluded.lease_expires_at`).run(projectPath, holderId, leaseExpiresAt);
165711
+ return {
165712
+ acquired: true,
165713
+ projectPath,
165714
+ holderId,
165715
+ acquiredAt: now,
165716
+ leaseExpiresAt
165717
+ };
165718
+ });
165719
+ }
165720
+ function renewGitSweepLease(db, projectPath, holderId, leaseTtlMs = GIT_SWEEP_LEASE_TTL_MS) {
165721
+ return runImmediate2(db, () => {
165722
+ const now = Date.now();
165723
+ const leaseExpiresAt = now + leaseTtlMs;
165724
+ const result = db.prepare(`UPDATE git_sweep_coordinator
165725
+ SET lease_expires_at = ?
165726
+ WHERE project_path = ?
165727
+ AND lease_holder = ?
165728
+ AND lease_expires_at > ?`).run(leaseExpiresAt, projectPath, holderId, now);
165729
+ return result.changes === 1;
165730
+ });
165731
+ }
165732
+ function markGitSweepSuccessAndRelease(db, projectPath, holderId) {
165733
+ return runImmediate2(db, () => {
165734
+ const now = Date.now();
165735
+ const result = db.prepare(`UPDATE git_sweep_coordinator
165736
+ SET lease_holder = NULL,
165737
+ lease_expires_at = NULL,
165738
+ last_swept_at = ?
165739
+ WHERE project_path = ?
165740
+ AND lease_holder = ?
165741
+ AND lease_expires_at > ?`).run(now, projectPath, holderId, now);
165742
+ return result.changes === 1;
165743
+ });
165744
+ }
165745
+ function releaseGitSweepLease(db, projectPath, holderId) {
165746
+ runImmediate2(db, () => {
165747
+ db.prepare(`UPDATE git_sweep_coordinator
165748
+ SET lease_holder = NULL,
165749
+ lease_expires_at = NULL
165750
+ WHERE project_path = ?
165751
+ AND lease_holder = ?`).run(projectPath, holderId);
165752
+ });
165753
+ }
165754
+
165766
165755
  // ../plugin/src/features/magic-context/project-embedding-registry.ts
165767
165756
  var OFF_PROVIDER_IDENTITY = "embedding-provider:off";
165768
165757
  var SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
@@ -165815,7 +165804,7 @@ function stableStringify2(value) {
165815
165804
  return JSON.stringify(value);
165816
165805
  }
165817
165806
  function sha256Prefix(value, length = 16) {
165818
- return createHash8("sha256").update(value).digest("hex").slice(0, length);
165807
+ return createHash7("sha256").update(value).digest("hex").slice(0, length);
165819
165808
  }
165820
165809
  function getRuntimeFingerprint(config2) {
165821
165810
  if (config2.provider === "off") {
@@ -166080,6 +166069,7 @@ var insertStatements = new WeakMap;
166080
166069
  var existingShasStatements = new WeakMap;
166081
166070
  var projectCountStatements = new WeakMap;
166082
166071
  var evictStatements = new WeakMap;
166072
+ var evictOverflowStatements = new WeakMap;
166083
166073
  var latestCommitTimeStatements = new WeakMap;
166084
166074
  function getInsertStatement(db) {
166085
166075
  let stmt = insertStatements.get(db);
@@ -166122,17 +166112,17 @@ function getLatestCommitTimeStatement(db) {
166122
166112
  }
166123
166113
  return stmt;
166124
166114
  }
166125
- function getEvictStatement(db) {
166126
- let stmt = evictStatements.get(db);
166115
+ function getEvictOverflowStatement(db) {
166116
+ let stmt = evictOverflowStatements.get(db);
166127
166117
  if (!stmt) {
166128
166118
  stmt = db.prepare(`DELETE FROM git_commits
166129
- WHERE sha IN (
166130
- SELECT sha FROM git_commits
166119
+ WHERE rowid IN (
166120
+ SELECT rowid FROM git_commits
166131
166121
  WHERE project_path = ?
166132
- ORDER BY committed_at ASC
166133
- LIMIT ?
166122
+ ORDER BY committed_at DESC, sha DESC
166123
+ LIMIT -1 OFFSET ?
166134
166124
  )`);
166135
- evictStatements.set(db, stmt);
166125
+ evictOverflowStatements.set(db, stmt);
166136
166126
  }
166137
166127
  return stmt;
166138
166128
  }
@@ -166170,22 +166160,15 @@ function getLatestIndexedCommitTimeMs(db, projectPath) {
166170
166160
  const row = getLatestCommitTimeStatement(db).get(projectPath);
166171
166161
  return row?.latest ?? null;
166172
166162
  }
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
166163
  function enforceProjectCap(db, projectPath, maxCommits) {
166182
166164
  if (maxCommits <= 0)
166183
166165
  return 0;
166184
166166
  const count = getCommitCount(db, projectPath);
166185
166167
  if (count <= maxCommits)
166186
166168
  return 0;
166187
- const excess = count - maxCommits;
166188
- const evicted = evictOldestCommits(db, projectPath, excess);
166169
+ getEvictOverflowStatement(db).run(projectPath, maxCommits);
166170
+ const after = getCommitCount(db, projectPath);
166171
+ const evicted = Math.max(0, count - after);
166189
166172
  if (evicted > 0) {
166190
166173
  log(`[git-commits] evicted ${evicted} oldest commits for project ${projectPath} (cap=${maxCommits}, was=${count})`);
166191
166174
  }
@@ -166217,7 +166200,8 @@ async function indexCommitsForProject(db, projectPath, directory, options) {
166217
166200
  const sinceMs = latestIndexed !== null ? Math.max(latestIndexed - 60000, Date.now() - options.sinceDays * MS_PER_DAY) : Date.now() - options.sinceDays * MS_PER_DAY;
166218
166201
  const commits = await readGitCommits(directory, {
166219
166202
  sinceMs,
166220
- maxCommits: options.maxCommits
166203
+ maxCommits: options.maxCommits,
166204
+ projectIdentity: projectPath
166221
166205
  });
166222
166206
  result.scanned = commits.length;
166223
166207
  if (commits.length === 0) {
@@ -166484,7 +166468,7 @@ async function startDreamScheduleTimer(args) {
166484
166468
  const isNewRegistration = !registeredProjects.has(args.directory);
166485
166469
  registeredProjects.set(args.directory, args);
166486
166470
  if (isNewRegistration) {
166487
- log(`[dreamer] registered project ${args.directory} (dreaming=${dreamingEnabled} embeddings=${embeddingSweepEnabled} commits=${commitIndexingEnabled}; total=${registeredProjects.size})`);
166471
+ log(`[dreamer] registered project ${args.projectIdentity} (dreaming=${dreamingEnabled} embeddings=${embeddingSweepEnabled} commits=${commitIndexingEnabled}; total=${registeredProjects.size})`);
166488
166472
  }
166489
166473
  if (!activeTimer) {
166490
166474
  log(`[dreamer] started independent schedule timer (every ${DREAM_TIMER_INTERVAL_MS / 60000}m)`);
@@ -166499,7 +166483,7 @@ async function startDreamScheduleTimer(args) {
166499
166483
  }
166500
166484
  return () => {
166501
166485
  registeredProjects.delete(args.directory);
166502
- log(`[dreamer] unregistered project ${args.directory} (remaining=${registeredProjects.size})`);
166486
+ log(`[dreamer] unregistered project ${args.projectIdentity} (remaining=${registeredProjects.size})`);
166503
166487
  if (registeredProjects.size === 0 && activeTimer) {
166504
166488
  clearInterval(activeTimer);
166505
166489
  activeTimer = null;
@@ -166547,7 +166531,7 @@ async function sweepProject(reg, origin, db, gitCommitEnabled = getProjectEmbedd
166547
166531
  return;
166548
166532
  }
166549
166533
  try {
166550
- log(`[dreamer] timer tick (${origin}) ${reg.directory} — checking schedule window "${reg.dreamerConfig.schedule}"`);
166534
+ log(`[dreamer] timer tick (${origin}) ${reg.projectIdentity} — checking schedule window "${reg.dreamerConfig.schedule}"`);
166551
166535
  checkScheduleAndEnqueue(db, reg.dreamerConfig.schedule, reg.projectIdentity);
166552
166536
  await processDreamQueue({
166553
166537
  db,
@@ -166562,13 +166546,34 @@ async function sweepProject(reg, origin, db, gitCommitEnabled = getProjectEmbedd
166562
166546
  fallbackModels: resolveFallbackChain(DREAMER_AGENT, reg.dreamerConfig.fallback_models)
166563
166547
  });
166564
166548
  } catch (error51) {
166565
- log(`[dreamer] timer-triggered queue processing failed for ${reg.directory}:`, error51);
166549
+ log(`[dreamer] timer-triggered queue processing failed for ${reg.projectIdentity}:`, error51);
166566
166550
  }
166567
166551
  }
166552
+ function startGitSweepLeaseRenewal(db, projectIdentity, holderId) {
166553
+ const timer = setInterval(() => {
166554
+ try {
166555
+ if (!renewGitSweepLease(db, projectIdentity, holderId)) {
166556
+ log(`[git-commits] sweep lease renewal failed for ${projectIdentity}`);
166557
+ }
166558
+ } catch (error51) {
166559
+ log(`[git-commits] sweep lease renewal errored for ${projectIdentity}: ${error51 instanceof Error ? error51.message : String(error51)}`);
166560
+ }
166561
+ }, GIT_SWEEP_LEASE_RENEWAL_MS);
166562
+ timer.unref?.();
166563
+ return () => clearInterval(timer);
166564
+ }
166568
166565
  async function sweepGitCommits(args) {
166569
166566
  const { directory, projectIdentity, db, gitCommitIndexing } = args;
166567
+ const holderId = crypto.randomUUID();
166568
+ const lease2 = acquireGitSweepLease(db, projectIdentity, holderId);
166569
+ if (!lease2.acquired) {
166570
+ const reason = lease2.reason === "cooldown_active" ? `cooldown active until ${lease2.nextAllowedAt}` : `lease held by ${lease2.leaseHolder ?? "another holder"} until ${lease2.leaseExpiresAt ?? "unknown"}`;
166571
+ log(`[git-commits] sweep skipped for ${projectIdentity}: ${reason}`);
166572
+ return;
166573
+ }
166570
166574
  const startedAt = Date.now();
166571
- log(`[git-commits] sweep starting for ${directory} (sinceDays=${gitCommitIndexing.since_days} maxCommits=${gitCommitIndexing.max_commits})`);
166575
+ const stopRenewal = startGitSweepLeaseRenewal(db, projectIdentity, holderId);
166576
+ log(`[git-commits] sweep starting for ${projectIdentity} (sinceDays=${gitCommitIndexing.since_days} maxCommits=${gitCommitIndexing.max_commits})`);
166572
166577
  try {
166573
166578
  const result = await indexCommitsForProject(db, projectIdentity, directory, {
166574
166579
  sinceDays: gitCommitIndexing.since_days,
@@ -166578,16 +166583,24 @@ async function sweepGitCommits(args) {
166578
166583
  if (result.embedded > 0) {
166579
166584
  drainedEmbeddings = await embedUnembeddedCommits(db, projectIdentity);
166580
166585
  }
166586
+ const cooldownMarked = markGitSweepSuccessAndRelease(db, projectIdentity, holderId);
166587
+ if (!cooldownMarked) {
166588
+ releaseGitSweepLease(db, projectIdentity, holderId);
166589
+ log(`[git-commits] sweep finished for ${projectIdentity}, but lease was no longer active; cooldown not advanced`);
166590
+ }
166581
166591
  const elapsedMs = Date.now() - startedAt;
166582
166592
  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
166593
  } catch (error51) {
166594
+ releaseGitSweepLease(db, projectIdentity, holderId);
166584
166595
  const elapsedMs = Date.now() - startedAt;
166585
- log(`[git-commits] sweep failed for ${directory} after ${elapsedMs}ms: ${error51 instanceof Error ? error51.message : String(error51)}`);
166596
+ log(`[git-commits] sweep failed for ${projectIdentity} after ${elapsedMs}ms: ${error51 instanceof Error ? error51.message : String(error51)}`);
166597
+ } finally {
166598
+ stopRenewal();
166586
166599
  }
166587
166600
  }
166588
166601
 
166589
166602
  // ../plugin/src/plugin/embedding-bootstrap-helpers.ts
166590
- import { createHash as createHash9 } from "node:crypto";
166603
+ import { createHash as createHash8 } from "node:crypto";
166591
166604
  init_logger();
166592
166605
  var EMBEDDING_AFFECTING_KEYS = new Set([
166593
166606
  "embedding.api_key",
@@ -166599,7 +166612,7 @@ var EMBEDDING_AFFECTING_TOP_LEVEL_KEYS = new Set(["embedding", "memory", "experi
166599
166612
  var EMBEDDING_WARNING_TERMS = ["api_key", "endpoint", "model", "provider", "embedding"];
166600
166613
  var loggedFailureSignatures = new Map;
166601
166614
  function sha256Prefix2(value, length = 16) {
166602
- return createHash9("sha256").update(value).digest("hex").slice(0, length);
166615
+ return createHash8("sha256").update(value).digest("hex").slice(0, length);
166603
166616
  }
166604
166617
  function warningLooksEmbeddingRelated(message) {
166605
166618
  const lower = message.toLowerCase();
@@ -166663,8 +166676,8 @@ function handleUntrustedLoad(db, projectIdentity, directory, detailed) {
166663
166676
  }
166664
166677
 
166665
166678
  // src/config/index.ts
166666
- import { existsSync as existsSync11, readFileSync as readFileSync8 } from "node:fs";
166667
- import { homedir as homedir5 } from "node:os";
166679
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "node:fs";
166680
+ import { homedir as homedir4 } from "node:os";
166668
166681
  import { join as join13 } from "node:path";
166669
166682
 
166670
166683
  // ../plugin/src/config/migrate-experimental.ts
@@ -166754,9 +166767,67 @@ function migrateLegacyExperimental(rawConfig, warnings) {
166754
166767
  }
166755
166768
 
166756
166769
  // ../plugin/src/config/variable.ts
166757
- import { existsSync as existsSync10, readFileSync as readFileSync7 } from "node:fs";
166758
- import { homedir as homedir4 } from "node:os";
166770
+ import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
166771
+ import { homedir as homedir3 } from "node:os";
166759
166772
  import { dirname as dirname5, isAbsolute as isAbsolute2, resolve as resolve3 } from "node:path";
166773
+
166774
+ // ../plugin/src/shared/jsonc-parser.ts
166775
+ function stripJsonComments(content) {
166776
+ let result = "";
166777
+ let inString = false;
166778
+ let escaped = false;
166779
+ let inLineComment = false;
166780
+ let inBlockComment = false;
166781
+ for (let index = 0;index < content.length; index += 1) {
166782
+ const char = content[index];
166783
+ const next = content[index + 1];
166784
+ if (inLineComment) {
166785
+ if (char === `
166786
+ `) {
166787
+ inLineComment = false;
166788
+ result += char;
166789
+ }
166790
+ continue;
166791
+ }
166792
+ if (inBlockComment) {
166793
+ if (char === "*" && next === "/") {
166794
+ inBlockComment = false;
166795
+ index += 1;
166796
+ }
166797
+ continue;
166798
+ }
166799
+ if (inString) {
166800
+ result += char;
166801
+ if (escaped) {
166802
+ escaped = false;
166803
+ } else if (char === "\\") {
166804
+ escaped = true;
166805
+ } else if (char === '"') {
166806
+ inString = false;
166807
+ }
166808
+ continue;
166809
+ }
166810
+ if (char === '"') {
166811
+ inString = true;
166812
+ result += char;
166813
+ continue;
166814
+ }
166815
+ if (char === "/" && next === "/") {
166816
+ inLineComment = true;
166817
+ index += 1;
166818
+ continue;
166819
+ }
166820
+ if (char === "/" && next === "*") {
166821
+ inBlockComment = true;
166822
+ index += 1;
166823
+ continue;
166824
+ }
166825
+ result += char;
166826
+ }
166827
+ return result;
166828
+ }
166829
+
166830
+ // ../plugin/src/config/variable.ts
166760
166831
  var ENV_PATTERN = /\{env:([^}]+)\}/g;
166761
166832
  var FILE_PATTERN = /\{file:([^}]+)\}/g;
166762
166833
  function substituteConfigVariables(input) {
@@ -166808,11 +166879,11 @@ function substituteConfigVariables(input) {
166808
166879
  }
166809
166880
  let filePath = rawPath.trim();
166810
166881
  if (filePath.startsWith("~/")) {
166811
- filePath = resolve3(homedir4(), filePath.slice(2));
166882
+ filePath = resolve3(homedir3(), filePath.slice(2));
166812
166883
  } else if (!isAbsolute2(filePath)) {
166813
166884
  filePath = resolve3(configDir, filePath);
166814
166885
  }
166815
- if (!existsSync10(filePath)) {
166886
+ if (!existsSync9(filePath)) {
166816
166887
  warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
166817
166888
  continue;
166818
166889
  }
@@ -166838,12 +166909,12 @@ function getProjectConfigPaths(cwd) {
166838
166909
  return [`${basePath}.jsonc`, `${basePath}.json`];
166839
166910
  }
166840
166911
  function getUserConfigPaths() {
166841
- const home = process.env.HOME ?? homedir5();
166912
+ const home = process.env.HOME ?? homedir4();
166842
166913
  const basePath = join13(home, ".pi", "agent", CONFIG_FILE_NAME);
166843
166914
  return [`${basePath}.jsonc`, `${basePath}.json`];
166844
166915
  }
166845
166916
  function resolveFirstExisting(paths) {
166846
- return paths.find((path7) => existsSync11(path7));
166917
+ return paths.find((path7) => existsSync10(path7));
166847
166918
  }
166848
166919
  function loadConfigFile(path7, scope) {
166849
166920
  try {
@@ -169447,6 +169518,62 @@ function buildToolTarget(part, message) {
169447
169518
 
169448
169519
  // ../plugin/src/features/magic-context/search.ts
169449
169520
  init_logger();
169521
+
169522
+ // ../plugin/src/features/magic-context/literal-probes.ts
169523
+ var MAX_PROBES = 5;
169524
+ var MIN_PROBE_LENGTH = 3;
169525
+ var SLASH_COMMAND_RE = /\/[a-z][a-z0-9]*(?:-[a-z0-9]+)+/gi;
169526
+ var KEBAB_SNAKE_RE = /[a-z][a-z0-9]*(?:[-_][a-z0-9]+)+/gi;
169527
+ var DOTTED_RE = /[a-z0-9][a-z0-9_-]*(?:\.[a-z0-9_-]+)+/gi;
169528
+ var CAMEL_RE = /\b[a-zA-Z][a-z0-9]*(?:[A-Z][a-z0-9]*)+\b/g;
169529
+ var SHA_RE = /\b[0-9a-f]{7,40}\b/gi;
169530
+ var ERROR_CODE_RE = /\b(?:TS\d{4,}|ERR_[A-Z][A-Z0-9_]*)\b/g;
169531
+ var QUOTED_RE = /["`]([^"`]{3,80})["`]/g;
169532
+ function looksLikeSha(token) {
169533
+ return /[0-9]/.test(token) && /^[0-9a-f]{7,40}$/i.test(token);
169534
+ }
169535
+ function extractLiteralProbes(query) {
169536
+ const trimmed = query.trim();
169537
+ if (trimmed.length === 0)
169538
+ return [];
169539
+ const ordered = [];
169540
+ const seen = new Set;
169541
+ const add = (raw) => {
169542
+ if (!raw)
169543
+ return;
169544
+ const probe = raw.trim();
169545
+ if (probe.length < MIN_PROBE_LENGTH)
169546
+ return;
169547
+ const key = probe.toLowerCase();
169548
+ if (seen.has(key))
169549
+ return;
169550
+ seen.add(key);
169551
+ ordered.push(probe);
169552
+ };
169553
+ for (const m of trimmed.matchAll(QUOTED_RE))
169554
+ add(m[1]);
169555
+ for (const m of trimmed.matchAll(SLASH_COMMAND_RE))
169556
+ add(m[0]);
169557
+ for (const m of trimmed.matchAll(ERROR_CODE_RE))
169558
+ add(m[0]);
169559
+ for (const m of trimmed.matchAll(DOTTED_RE))
169560
+ add(m[0]);
169561
+ for (const m of trimmed.matchAll(KEBAB_SNAKE_RE))
169562
+ add(m[0]);
169563
+ for (const m of trimmed.matchAll(CAMEL_RE))
169564
+ add(m[0]);
169565
+ for (const m of trimmed.matchAll(SHA_RE)) {
169566
+ if (looksLikeSha(m[0]))
169567
+ add(m[0]);
169568
+ }
169569
+ return ordered.slice(0, MAX_PROBES);
169570
+ }
169571
+ function containsProbeVerbatim(text, probes) {
169572
+ if (probes.length === 0)
169573
+ return false;
169574
+ const haystack = text.toLowerCase();
169575
+ return probes.some((probe) => haystack.includes(probe.toLowerCase()));
169576
+ }
169450
169577
  // ../plugin/src/features/magic-context/memory/embedding-backfill.ts
169451
169578
  init_logger();
169452
169579
  async function ensureMemoryEmbeddings(args) {
@@ -169709,36 +169836,82 @@ function linearDecayScore(rank, total) {
169709
169836
  return 0;
169710
169837
  return Math.max(0, 1 - rank / total);
169711
169838
  }
169712
- function searchMessages(args) {
169713
- const sanitizedQuery = sanitizeFtsQuery(args.query.trim());
169714
- if (sanitizedQuery.length === 0) {
169839
+ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
169840
+ if (ftsQuery.length === 0)
169715
169841
  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) => {
169842
+ const rows = getMessageSearchStatement(db).all(sessionId, ftsQuery, fetchLimit).map((row) => row);
169843
+ const result = [];
169844
+ for (const row of rows) {
169721
169845
  const messageOrdinal = getMessageOrdinal(row.messageOrdinal);
169722
169846
  if (messageOrdinal === null || typeof row.messageId !== "string" || typeof row.role !== "string" || typeof row.content !== "string") {
169723
- return null;
169847
+ continue;
169724
169848
  }
169725
169849
  if (cutoff !== null && messageOrdinal > cutoff) {
169726
- return null;
169850
+ continue;
169727
169851
  }
169728
- return {
169852
+ result.push({
169729
169853
  messageOrdinal,
169730
169854
  messageId: row.messageId,
169731
169855
  role: row.role,
169732
169856
  content: row.content
169733
- };
169734
- }).filter((result) => result !== null).slice(0, args.limit);
169735
- return filtered.map((row, rank) => ({
169857
+ });
169858
+ }
169859
+ return result;
169860
+ }
169861
+ var RRF_K = 60;
169862
+ var VERBATIM_PROBE_BONUS = 0.5;
169863
+ function searchMessages(args) {
169864
+ const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
169865
+ const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
169866
+ const baseQuery = sanitizeFtsQuery(args.query.trim());
169867
+ const probes = args.probes ?? [];
169868
+ if (probes.length === 0) {
169869
+ const filtered = runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff).slice(0, args.limit);
169870
+ return filtered.map((row, rank) => ({
169871
+ source: "message",
169872
+ content: previewText(row.content),
169873
+ score: linearDecayScore(rank, filtered.length),
169874
+ messageOrdinal: row.messageOrdinal,
169875
+ messageId: row.messageId,
169876
+ role: row.role
169877
+ }));
169878
+ }
169879
+ const queryLists = [];
169880
+ if (baseQuery.length > 0) {
169881
+ queryLists.push(runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff));
169882
+ }
169883
+ for (const probe of probes) {
169884
+ const probeQuery = sanitizeFtsQuery(probe);
169885
+ if (probeQuery.length === 0)
169886
+ continue;
169887
+ queryLists.push(runMessageFtsQuery(args.db, args.sessionId, probeQuery, fetchLimit, cutoff));
169888
+ }
169889
+ const fused = new Map;
169890
+ for (const list of queryLists) {
169891
+ list.forEach((row, rank) => {
169892
+ const rrf = 1 / (RRF_K + rank);
169893
+ const existing = fused.get(row.messageId);
169894
+ if (existing) {
169895
+ existing.score += rrf;
169896
+ } else {
169897
+ fused.set(row.messageId, { row, score: rrf });
169898
+ }
169899
+ });
169900
+ }
169901
+ for (const entry of fused.values()) {
169902
+ if (containsProbeVerbatim(entry.row.content, probes)) {
169903
+ entry.score += VERBATIM_PROBE_BONUS;
169904
+ }
169905
+ }
169906
+ 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);
169907
+ const maxScore = ranked.length > 0 ? ranked[0].score : 1;
169908
+ return ranked.map((entry) => ({
169736
169909
  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
169910
+ content: previewText(entry.row.content),
169911
+ score: maxScore > 0 ? entry.score / maxScore : 0,
169912
+ messageOrdinal: entry.row.messageOrdinal,
169913
+ messageId: entry.row.messageId,
169914
+ role: entry.row.role
169742
169915
  }));
169743
169916
  }
169744
169917
  function getSourceBoost(result) {
@@ -169822,12 +169995,14 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
169822
169995
  return null;
169823
169996
  }) : Promise.resolve(null);
169824
169997
  await Promise.resolve();
169998
+ const messageProbes = options.explicitSearch ? extractLiteralProbes(trimmedQuery) : [];
169825
169999
  const messageResults = runMessages ? searchMessages({
169826
170000
  db,
169827
170001
  sessionId,
169828
170002
  query: trimmedQuery,
169829
170003
  limit: tierLimit,
169830
- maxOrdinal: options.maxMessageOrdinal
170004
+ maxOrdinal: options.maxMessageOrdinal,
170005
+ probes: messageProbes
169831
170006
  }) : [];
169832
170007
  const queryEmbedding = await queryEmbeddingPromise;
169833
170008
  const [memoryResults, gitCommitResults] = await Promise.all([
@@ -175690,7 +175865,7 @@ function stripPiDroppedPlaceholderMessages(args) {
175690
175865
  }
175691
175866
 
175692
175867
  // src/system-prompt.ts
175693
- import { createHash as createHash10 } from "node:crypto";
175868
+ import { createHash as createHash9 } from "node:crypto";
175694
175869
 
175695
175870
  // ../plugin/src/agents/magic-context-prompt.ts
175696
175871
  var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
@@ -175835,7 +176010,7 @@ function processSystemPromptForCache(args) {
175835
176010
  sessionLog(sessionId, `system prompt date frozen: real=${liveDate}, using=${stickyDate} (cache-stable pass)`);
175836
176011
  }
175837
176012
  }
175838
- const currentHash = createHash10("md5").update(frozenPrompt).digest("hex");
176013
+ const currentHash = createHash9("md5").update(frozenPrompt).digest("hex");
175839
176014
  const hashChanged = !isFirstHash && currentHash !== previousHash;
175840
176015
  if (hashChanged) {
175841
176016
  sessionLog(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${frozenPrompt.length})`);
@@ -175880,10 +176055,8 @@ function injectPiTemporalMarkers(messages) {
175880
176055
  if (prefix !== null) {
175881
176056
  const userMsg = msg;
175882
176057
  if (typeof userMsg.content === "string") {
175883
- if (!TEMPORAL_MARKER_PATTERN.test(stripTagPrefix2(userMsg.content))) {
175884
- const tagMatch = userMsg.content.match(/^(?:§\d+§\s*)+/);
175885
- const tagPrefix = tagMatch ? tagMatch[0] : "";
175886
- const body = userMsg.content.slice(tagPrefix.length);
176058
+ if (!TEMPORAL_MARKER_PATTERN.test(stripTagPrefix(userMsg.content))) {
176059
+ const { tagPrefix, body } = peelLeadingMcTagNotation(userMsg.content);
175887
176060
  messages[i] = {
175888
176061
  ...userMsg,
175889
176062
  content: tagPrefix + prefix + body
@@ -175894,9 +176067,7 @@ function injectPiTemporalMarkers(messages) {
175894
176067
  const firstTextIndex = userMsg.content.findIndex((p) => p && typeof p === "object" && p.type === "text");
175895
176068
  if (firstTextIndex >= 0) {
175896
176069
  const existing = userMsg.content[firstTextIndex];
175897
- const tagMatch = existing.text.match(/^(?:§\d+§\s*)+/);
175898
- const tagPrefix = tagMatch ? tagMatch[0] : "";
175899
- const body = existing.text.slice(tagPrefix.length);
176070
+ const { tagPrefix, body } = peelLeadingMcTagNotation(existing.text);
175900
176071
  if (!TEMPORAL_MARKER_PATTERN.test(body)) {
175901
176072
  const newContent = userMsg.content.slice();
175902
176073
  newContent[firstTextIndex] = {
@@ -175919,12 +176090,6 @@ function injectPiTemporalMarkers(messages) {
175919
176090
  }
175920
176091
  return injected;
175921
176092
  }
175922
- function stripTagPrefix2(text) {
175923
- const match = text.match(/^(?:§\d+§\s*)+/);
175924
- if (!match)
175925
- return text;
175926
- return text.slice(match[0].length);
175927
- }
175928
176093
 
175929
176094
  // src/timeout.ts
175930
176095
  function withTimeout(p, ms) {
@@ -176951,14 +177116,10 @@ function registerPiContextHandler(pi, options) {
176951
177116
  }
176952
177117
  const sessionMeta = sessionMetaForUsage;
176953
177118
  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;
177119
+ if (usageContextLimit === undefined) {
177120
+ const modelWindow = ctx.model?.contextWindow;
177121
+ if (isSaneLimit(modelWindow)) {
177122
+ usageContextLimit = modelWindow;
176962
177123
  }
176963
177124
  }
176964
177125
  let schedulerDecision;
@@ -177211,27 +177372,8 @@ async function awaitInFlightHistorians() {
177211
177372
  return;
177212
177373
  await Promise.allSettled(Array.from(inFlightHistorian.values()));
177213
177374
  }
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
177375
  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
- }
177376
+ const contextLimit = typeof args.usageContextLimit === "number" && Number.isFinite(args.usageContextLimit) && args.usageContextLimit > 0 ? args.usageContextLimit : DEFAULT_CONTEXT_LIMIT;
177235
177377
  const executeThresholdPercentage = resolveExecuteThreshold(args.historian.executeThresholdPercentage ?? 65, args.modelKey, 65, {
177236
177378
  tokensConfig: args.historian.executeThresholdTokens,
177237
177379
  contextLimit,
@@ -178053,7 +178195,7 @@ ${result}`;
178053
178195
  init_logger();
178054
178196
 
178055
178197
  // ../plugin/src/hooks/magic-context/historian-state-file.ts
178056
- import { mkdirSync as mkdirSync5, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
178198
+ import { mkdirSync as mkdirSync6, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
178057
178199
  init_data_path();
178058
178200
  function cleanupHistorianStateFile(path7) {
178059
178201
  if (!path7)
@@ -178257,7 +178399,7 @@ function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEn
178257
178399
  }
178258
178400
 
178259
178401
  // ../plugin/src/hooks/magic-context/compartment-runner-historian.ts
178260
- import { mkdirSync as mkdirSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
178402
+ import { mkdirSync as mkdirSync7, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
178261
178403
  import { join as join16 } from "node:path";
178262
178404
  init_data_path();
178263
178405
  function historianResponseDumpDir(directory) {
@@ -178562,11 +178704,11 @@ function cleanupHistorianDump(sessionId, dumpPath) {
178562
178704
  function dumpHistorianResponse(sessionId, directory, label, text) {
178563
178705
  try {
178564
178706
  const dumpDir = historianResponseDumpDir(directory);
178565
- mkdirSync6(dumpDir, { recursive: true });
178707
+ mkdirSync7(dumpDir, { recursive: true });
178566
178708
  const safeSessionId = sanitizeDumpName(sessionId);
178567
178709
  const safeLabel = sanitizeDumpName(label);
178568
178710
  const dumpPath = join16(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
178569
- writeFileSync3(dumpPath, text, "utf8");
178711
+ writeFileSync4(dumpPath, text, "utf8");
178570
178712
  sessionLog(sessionId, "compartment agent: historian response dumped", {
178571
178713
  label,
178572
178714
  dumpPath
@@ -180478,7 +180620,7 @@ function formatThresholdPercent(value) {
180478
180620
  // package.json
180479
180621
  var package_default = {
180480
180622
  name: "@cortexkit/pi-magic-context",
180481
- version: "0.22.1",
180623
+ version: "0.22.3",
180482
180624
  type: "module",
180483
180625
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
180484
180626
  main: "dist/index.js",
@@ -181063,8 +181205,6 @@ function computePiPressure(usage, contextLimit) {
181063
181205
  }
181064
181206
 
181065
181207
  // src/strip-tag-prefix.ts
181066
- var LEADING_TAG_PREFIX_REGEX = /^(\u00a7\d+\u00a7\s*)+/;
181067
- var SECTION_CHAR_REGEX = /\u00a7/g;
181068
181208
  function stripTagPrefixFromAssistantMessage(message) {
181069
181209
  if (message.role !== "assistant")
181070
181210
  return false;
@@ -181078,7 +181218,7 @@ function stripTagPrefixFromAssistantMessage(message) {
181078
181218
  const textPart = part;
181079
181219
  if (typeof textPart.text !== "string")
181080
181220
  continue;
181081
- const stripped = textPart.text.replace(LEADING_TAG_PREFIX_REGEX, "").replace(SECTION_CHAR_REGEX, "");
181221
+ const stripped = stripPersistedAssistantText(textPart.text);
181082
181222
  if (stripped !== textPart.text) {
181083
181223
  textPart.text = stripped;
181084
181224
  mutated = true;
@@ -185582,15 +185722,26 @@ function err3(text) {
185582
185722
  isError: true
185583
185723
  };
185584
185724
  }
185725
+ function captureAnchorOrdinal(db, sessionId) {
185726
+ try {
185727
+ const ordinal = getLastIndexedOrdinal(db, sessionId);
185728
+ return ordinal > 0 ? ordinal : null;
185729
+ } catch {
185730
+ return null;
185731
+ }
185732
+ }
185733
+ function anchorSuffix(note) {
185734
+ return note.anchorOrdinal !== null ? ` ↳ @msg ${note.anchorOrdinal}` : "";
185735
+ }
185585
185736
  function formatNoteLine(note) {
185586
185737
  if (note.type === "smart") {
185587
185738
  const conditionLine = note.status === "ready" ? note.readyReason ?? note.surfaceCondition ?? "Condition satisfied" : note.surfaceCondition ?? "No condition recorded";
185588
185739
  const statusSuffix2 = note.status === "active" ? "" : ` (${note.status})`;
185589
- return `- **#${note.id}**${statusSuffix2}: ${note.content}
185740
+ return `- **#${note.id}**${statusSuffix2}: ${note.content}${anchorSuffix(note)}
185590
185741
  *Condition*: ${conditionLine}`;
185591
185742
  }
185592
185743
  const statusSuffix = note.status === "active" ? "" : ` (${note.status})`;
185593
- return `- **#${note.id}**${statusSuffix}: ${note.content}`;
185744
+ return `- **#${note.id}**${statusSuffix}: ${note.content}${anchorSuffix(note)}`;
185594
185745
  }
185595
185746
  var DISMISS_FOOTER = `
185596
185747
 
@@ -185612,6 +185763,7 @@ function createCtxNoteTool(deps) {
185612
185763
  const content = params.content?.trim();
185613
185764
  if (!content)
185614
185765
  return err3("Error: 'content' is required when action is 'write'.");
185766
+ const anchorOrdinal = captureAnchorOrdinal(deps.db, sessionId);
185615
185767
  const surfaceCondition = params.surface_condition?.trim();
185616
185768
  if (surfaceCondition) {
185617
185769
  if (deps.dreamerEnabled !== true) {
@@ -185624,13 +185776,18 @@ function createCtxNoteTool(deps) {
185624
185776
  const note2 = addNote(deps.db, "smart", {
185625
185777
  content,
185626
185778
  projectPath: projectIdentity,
185627
- surfaceCondition
185779
+ surfaceCondition,
185780
+ anchorOrdinal
185628
185781
  });
185629
185782
  return ok3(`Created smart note #${note2.id}. Dreamer will evaluate the condition during nightly runs:
185630
185783
  - Content: ${content}
185631
185784
  - Condition: ${surfaceCondition}`);
185632
185785
  }
185633
- const note = addNote(deps.db, "session", { sessionId, content });
185786
+ const note = addNote(deps.db, "session", {
185787
+ sessionId,
185788
+ content,
185789
+ anchorOrdinal
185790
+ });
185634
185791
  return ok3(`Saved session note #${note.id}.`);
185635
185792
  }
185636
185793
  if (action2 === "dismiss") {
@@ -185693,9 +185850,13 @@ function createCtxNoteTool(deps) {
185693
185850
 
185694
185851
  No notes for the current filter.`);
185695
185852
  }
185696
- return ok3(`${sections.join(`
185853
+ const body = sections.join(`
185854
+
185855
+ `);
185856
+ const anchorHint = body.includes("↳ @msg ") ? `
185697
185857
 
185698
- `)}${DISMISS_FOOTER}`);
185858
+ ↳ @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).` : "";
185859
+ return ok3(`${body}${anchorHint}${DISMISS_FOOTER}`);
185699
185860
  }
185700
185861
  };
185701
185862
  }
@@ -186040,7 +186201,8 @@ function createCtxSearchTool(deps) {
186040
186201
  maxMessageOrdinal: lastCompartmentEnd >= 0 ? lastCompartmentEnd : undefined,
186041
186202
  gitCommitsEnabled,
186042
186203
  sources: params.sources,
186043
- visibleMemoryIds
186204
+ visibleMemoryIds,
186205
+ explicitSearch: true
186044
186206
  });
186045
186207
  return {
186046
186208
  content: [{ type: "text", text: formatSearchResults(query, results) }],
@@ -186188,8 +186350,7 @@ function getPiMessageModel(message) {
186188
186350
  };
186189
186351
  }
186190
186352
  function resolvePiPressureContextLimit(args) {
186191
- const cachedLimit = args.provider && args.model ? getModelsDevContextLimit(args.provider, args.model) : undefined;
186192
- let effectiveContextLimit = cachedLimit ?? args.piContextWindow;
186353
+ let effectiveContextLimit = isSaneLimit(args.piContextWindow) ? args.piContextWindow : 0;
186193
186354
  try {
186194
186355
  const overflowState = getOverflowState(args.db, args.sessionId);
186195
186356
  if (overflowState.detectedContextLimit > 0) {
@@ -186205,8 +186366,6 @@ async function persistPiPressureFromMessageEnd(args) {
186205
186366
  const effectiveContextLimit = resolvePiPressureContextLimit({
186206
186367
  db: args.db,
186207
186368
  sessionId: args.sessionId,
186208
- provider: provider2,
186209
- model,
186210
186369
  piContextWindow: args.piContextWindow
186211
186370
  });
186212
186371
  const usage = extractAssistantUsage(args.message);
@@ -186215,28 +186374,16 @@ async function persistPiPressureFromMessageEnd(args) {
186215
186374
  const messageHadOverflowError = typeof msg?.errorMessage === "string" && detectOverflow(msg.errorMessage).isOverflow;
186216
186375
  const updates = { lastResponseTime: Date.now() };
186217
186376
  if (pressure) {
186218
- let percentage = pressure.percentage;
186219
- let contextLimit = effectiveContextLimit;
186377
+ const percentage = pressure.percentage;
186378
+ const contextLimit = effectiveContextLimit;
186220
186379
  const meta3 = getOrCreateSessionMeta(args.db, args.sessionId);
186221
186380
  const observedSafeInputTokens = meta3.observedSafeInputTokens ?? 0;
186222
186381
  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) {
186382
+ if (!meta3.cacheAlertSent) {
186236
186383
  updates.cacheAlertSent = true;
186237
186384
  const safeTokens = Math.max(observedSafeInputTokens, pressure.inputTokens);
186238
186385
  const modelLabel = provider2 && model ? `${provider2}/${model}` : "the active model";
186239
- await args.notifyIssue?.(`⚠️ Magic Context: Pi reports a context limit of ${formatTokens(contextLimit)} tokens for ${modelLabel} but you've successfully sent ${formatTokens(safeTokens)} tokens in this session — the cached limit looks wrong. Restart Pi if you suspect this is incorrect.`);
186386
+ await args.notifyIssue?.(`⚠️ Magic Context: Pi reports a context limit of ${formatTokens(contextLimit)} tokens for ${modelLabel} but you've successfully sent ${formatTokens(safeTokens)} tokens in this session — the reported limit looks wrong. Restart Pi if you suspect this is incorrect.`);
186240
186387
  }
186241
186388
  }
186242
186389
  updates.lastContextPercentage = percentage;
@@ -186703,7 +186850,7 @@ ${block}` : event.systemPrompt;
186703
186850
  cacheTtlConfig: config2.cache_ttl
186704
186851
  });
186705
186852
  const piUsage = ctx.getContextUsage?.();
186706
- const piContextWindow = piUsage && typeof piUsage.contextWindow === "number" ? piUsage.contextWindow : 0;
186853
+ const piContextWindow = piUsage && typeof piUsage.contextWindow === "number" && piUsage.contextWindow > 0 ? piUsage.contextWindow : ctx.model?.contextWindow ?? 0;
186707
186854
  await persistPiPressureFromMessageEnd({
186708
186855
  db,
186709
186856
  sessionId,