@cortexkit/magic-context 0.19.0 → 0.21.0

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.
Files changed (2) hide show
  1. package/dist/index.js +448 -187
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -8300,7 +8300,7 @@ function parseModelListOutput(output) {
8300
8300
  if (!line || line.toLowerCase().includes("usage:"))
8301
8301
  continue;
8302
8302
  const token = line.split(/\s+/)[0]?.trim().replace(/,$/, "");
8303
- if (!token || !token.includes("/"))
8303
+ if (!token?.includes("/"))
8304
8304
  continue;
8305
8305
  if (/^https?:\/\//.test(token))
8306
8306
  continue;
@@ -8506,7 +8506,7 @@ class PiAdapter {
8506
8506
  }
8507
8507
  }
8508
8508
  getInstallHint() {
8509
- return "Install Pi: https://pi.coding/install (npm: @mariozechner/pi-coding-agent)";
8509
+ return "Install Pi: https://pi.coding/install (npm: @earendil-works/pi-coding-agent)";
8510
8510
  }
8511
8511
  getPluginCacheInfo() {
8512
8512
  return { path: null, exists: false, sizeBytes: 0 };
@@ -11353,11 +11353,11 @@ async function runSetup2(options = {}) {
11353
11353
  }
11354
11354
  const version = env.getPiVersion(pi.path);
11355
11355
  spinner2.stop(version ? `Pi ${version} detected at ${pi.path}` : `Pi detected at ${pi.path}`);
11356
- const MIN_PI_VERSION = "0.71.0";
11356
+ const MIN_PI_VERSION = "0.74.0";
11357
11357
  if (version && comparePiVersion(version, MIN_PI_VERSION) < 0) {
11358
11358
  prompts.log.warn(`Pi ${version} is older than the required ${MIN_PI_VERSION}.
11359
- Magic Context spawns subagents with \`--extension <path>\` (long form), which Pi 0.71.0 introduced. Older Pi versions hard-fail with "Unknown option" when historian/dreamer/sidekick tries to run.
11360
- Run \`pi update\` (or \`npm install -g @mariozechner/pi-coding-agent@latest\`) before continuing.`);
11359
+ Pi 0.74.0 renamed the npm package from \`@mariozechner/pi-coding-agent\` to \`@earendil-works/pi-coding-agent\`. Magic Context's peer dependency targets the new scope, so older Pi installs cannot load this extension.
11360
+ Run \`pi update --self\` (or \`npm install -g @earendil-works/pi-coding-agent@latest\`) before continuing.`);
11361
11361
  const proceed = await prompts.confirm("Continue with setup anyway? (subagents will fail at runtime)", false);
11362
11362
  if (!proceed) {
11363
11363
  prompts.outro("Setup cancelled — upgrade Pi and try again.");
@@ -27529,7 +27529,7 @@ function migrateLegacyExperimental(rawConfig, warnings) {
27529
27529
  patched.dreamer = dreamer;
27530
27530
  return patched;
27531
27531
  }
27532
- function parsePluginConfig(rawConfig) {
27532
+ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
27533
27533
  const preMigrationWarnings = [];
27534
27534
  const migrated = migrateLegacyExperimental(rawConfig, preMigrationWarnings);
27535
27535
  const parsed = MagicContextConfigSchema.safeParse(migrated);
@@ -27554,6 +27554,7 @@ function parsePluginConfig(rawConfig) {
27554
27554
  }
27555
27555
  const patched = { ...rawConfig };
27556
27556
  for (const key of errorPaths) {
27557
+ recoveredTopLevelKeys.push(key);
27557
27558
  const isAgentConfig = key === "historian" || key === "dreamer" || key === "sidekick";
27558
27559
  if (isAgentConfig) {
27559
27560
  delete patched[key];
@@ -27631,6 +27632,78 @@ var init_config = __esm(() => {
27631
27632
  init_variable();
27632
27633
  });
27633
27634
 
27635
+ // ../plugin/src/features/magic-context/key-files/aft-availability.ts
27636
+ import { existsSync as existsSync13, readFileSync as readFileSync9 } from "node:fs";
27637
+ import { homedir as homedir9 } from "node:os";
27638
+ import { join as join11 } from "node:path";
27639
+ function parseConfig(path4) {
27640
+ if (!existsSync13(path4))
27641
+ return null;
27642
+ return import_comment_json6.parse(readFileSync9(path4, "utf-8"));
27643
+ }
27644
+ function entryMatchesAft(entry) {
27645
+ const value = Array.isArray(entry) ? entry[0] : entry;
27646
+ return typeof value === "string" && (value.includes("@cortexkit/aft") || value.includes("aft-opencode") || value.includes("aft-pi"));
27647
+ }
27648
+ function hasAftInArray(value) {
27649
+ return Array.isArray(value) && value.some(entryMatchesAft);
27650
+ }
27651
+ function hasAftAtKeys(value, keys) {
27652
+ if (!value || typeof value !== "object")
27653
+ return false;
27654
+ const record2 = value;
27655
+ for (const key of keys) {
27656
+ if (hasAftInArray(record2[key]))
27657
+ return true;
27658
+ }
27659
+ return false;
27660
+ }
27661
+ function getAftAvailability() {
27662
+ const home = process.env.HOME || homedir9();
27663
+ const opencodePaths = [
27664
+ join11(home, ".config", "opencode", "opencode.jsonc"),
27665
+ join11(home, ".config", "opencode", "opencode.json")
27666
+ ];
27667
+ const piPaths = [join11(home, ".pi", "agent", "settings.json")];
27668
+ const checkedPaths = [...opencodePaths, ...piPaths];
27669
+ let opencode = false;
27670
+ for (const path4 of opencodePaths) {
27671
+ try {
27672
+ const config2 = parseConfig(path4);
27673
+ if (hasAftAtKeys(config2, ["plugin", "plugins", "mcp", "mcp_servers"])) {
27674
+ opencode = true;
27675
+ break;
27676
+ }
27677
+ } catch {}
27678
+ }
27679
+ let pi = false;
27680
+ for (const path4 of piPaths) {
27681
+ try {
27682
+ const config2 = parseConfig(path4);
27683
+ if (hasAftAtKeys(config2, ["packages", "extensions"])) {
27684
+ pi = true;
27685
+ break;
27686
+ }
27687
+ const agent = config2?.agent;
27688
+ if (hasAftAtKeys(agent, ["packages", "extensions"])) {
27689
+ pi = true;
27690
+ break;
27691
+ }
27692
+ } catch {}
27693
+ }
27694
+ const detected = opencode || pi;
27695
+ return {
27696
+ available: overrideAvailability ?? detected,
27697
+ opencode,
27698
+ pi,
27699
+ checkedPaths
27700
+ };
27701
+ }
27702
+ var import_comment_json6, overrideAvailability = null;
27703
+ var init_aft_availability = __esm(() => {
27704
+ import_comment_json6 = __toESM(require_src2(), 1);
27705
+ });
27706
+
27634
27707
  // ../plugin/src/features/magic-context/memory/embedding-probe.ts
27635
27708
  async function probeEmbeddingEndpoint(options) {
27636
27709
  const endpoint = options.endpoint.trim().replace(/\/+$/, "");
@@ -27736,8 +27809,8 @@ function truncate(text2) {
27736
27809
  var DEFAULT_TIMEOUT_MS = 1e4, MAX_PREVIEW_CHARS = 240;
27737
27810
 
27738
27811
  // ../plugin/src/shared/tui-config.ts
27739
- import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "node:fs";
27740
- import { dirname as dirname8, join as join11 } from "node:path";
27812
+ import { existsSync as existsSync14, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "node:fs";
27813
+ import { dirname as dirname8, join as join12 } from "node:path";
27741
27814
  function isMagicContextEntry(entry) {
27742
27815
  if (!entry)
27743
27816
  return false;
@@ -27751,11 +27824,11 @@ function isMagicContextEntry(entry) {
27751
27824
  }
27752
27825
  function resolveTuiConfigPath() {
27753
27826
  const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
27754
- const jsoncPath = join11(configDir, "tui.jsonc");
27755
- const jsonPath = join11(configDir, "tui.json");
27756
- if (existsSync13(jsoncPath))
27827
+ const jsoncPath = join12(configDir, "tui.jsonc");
27828
+ const jsonPath = join12(configDir, "tui.json");
27829
+ if (existsSync14(jsoncPath))
27757
27830
  return jsoncPath;
27758
- if (existsSync13(jsonPath))
27831
+ if (existsSync14(jsonPath))
27759
27832
  return jsonPath;
27760
27833
  return jsonPath;
27761
27834
  }
@@ -27763,9 +27836,9 @@ function ensureTuiPluginEntry() {
27763
27836
  try {
27764
27837
  const configPath = resolveTuiConfigPath();
27765
27838
  let config2 = {};
27766
- if (existsSync13(configPath)) {
27767
- const raw = readFileSync9(configPath, "utf-8");
27768
- config2 = import_comment_json6.parse(raw) ?? {};
27839
+ if (existsSync14(configPath)) {
27840
+ const raw = readFileSync10(configPath, "utf-8");
27841
+ config2 = import_comment_json7.parse(raw) ?? {};
27769
27842
  }
27770
27843
  const plugins = Array.isArray(config2.plugin) ? config2.plugin.filter((p2) => typeof p2 === "string") : [];
27771
27844
  const existingIdx = plugins.findIndex(isMagicContextEntry);
@@ -27784,7 +27857,7 @@ function ensureTuiPluginEntry() {
27784
27857
  }
27785
27858
  config2.plugin = plugins;
27786
27859
  mkdirSync6(dirname8(configPath), { recursive: true });
27787
- writeFileSync8(configPath, `${import_comment_json6.stringify(config2, null, 2)}
27860
+ writeFileSync8(configPath, `${import_comment_json7.stringify(config2, null, 2)}
27788
27861
  `);
27789
27862
  log2(`[magic-context] updated TUI plugin entry in ${configPath}`);
27790
27863
  return true;
@@ -27793,11 +27866,11 @@ function ensureTuiPluginEntry() {
27793
27866
  return false;
27794
27867
  }
27795
27868
  }
27796
- var import_comment_json6, PLUGIN_NAME4 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY3;
27869
+ var import_comment_json7, PLUGIN_NAME4 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY3;
27797
27870
  var init_tui_config = __esm(() => {
27798
27871
  init_logger();
27799
27872
  init_opencode_config_dir();
27800
- import_comment_json6 = __toESM(require_src2(), 1);
27873
+ import_comment_json7 = __toESM(require_src2(), 1);
27801
27874
  PLUGIN_ENTRY3 = `${PLUGIN_NAME4}@latest`;
27802
27875
  });
27803
27876
 
@@ -27852,7 +27925,7 @@ var init_compartment_parser = __esm(() => {
27852
27925
  });
27853
27926
 
27854
27927
  // src/lib/redaction.ts
27855
- import { homedir as homedir9, userInfo } from "node:os";
27928
+ import { homedir as homedir10, userInfo } from "node:os";
27856
27929
  function escapeRegex2(value) {
27857
27930
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
27858
27931
  }
@@ -27865,7 +27938,7 @@ function isSecretKey(key) {
27865
27938
  return SECRET_KEY_PATTERN.test(key);
27866
27939
  }
27867
27940
  function sanitizePathString(value) {
27868
- const home = homedir9();
27941
+ const home = homedir10();
27869
27942
  const username = userInfo().username;
27870
27943
  let sanitized = value;
27871
27944
  if (home) {
@@ -27967,10 +28040,10 @@ var init_redaction = __esm(() => {
27967
28040
  });
27968
28041
 
27969
28042
  // src/lib/diagnostics-opencode.ts
27970
- import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync10, statSync as statSync2 } from "node:fs";
28043
+ import { existsSync as existsSync15, readdirSync as readdirSync2, readFileSync as readFileSync11, statSync as statSync2 } from "node:fs";
27971
28044
  import { createRequire as createRequire3 } from "node:module";
27972
- import { homedir as homedir10 } from "node:os";
27973
- import { join as join12 } from "node:path";
28045
+ import { homedir as homedir11 } from "node:os";
28046
+ import { join as join13 } from "node:path";
27974
28047
  function getSelfVersion() {
27975
28048
  const require2 = createRequire3(import.meta.url);
27976
28049
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -27984,12 +28057,12 @@ function getSelfVersion() {
27984
28057
  return "unknown";
27985
28058
  }
27986
28059
  function getPluginCacheInfo() {
27987
- const path4 = join12(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY_WITH_VERSION);
28060
+ const path4 = join13(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY_WITH_VERSION);
27988
28061
  let cached2;
27989
28062
  try {
27990
- const installedPkgPath = join12(path4, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
27991
- if (existsSync14(installedPkgPath)) {
27992
- const pkg = JSON.parse(readFileSync10(installedPkgPath, "utf-8"));
28063
+ const installedPkgPath = join13(path4, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
28064
+ if (existsSync15(installedPkgPath)) {
28065
+ const pkg = JSON.parse(readFileSync11(installedPkgPath, "utf-8"));
27993
28066
  cached2 = typeof pkg.version === "string" ? pkg.version : undefined;
27994
28067
  }
27995
28068
  } catch {
@@ -27998,12 +28071,12 @@ function getPluginCacheInfo() {
27998
28071
  return { path: path4, cached: cached2, latest: getSelfVersion() };
27999
28072
  }
28000
28073
  function getStorageDir() {
28001
- const dataHome = process.env.XDG_DATA_HOME || join12(homedir10(), ".local", "share");
28002
- return join12(dataHome, "cortexkit", "magic-context");
28074
+ const dataHome = process.env.XDG_DATA_HOME || join13(homedir11(), ".local", "share");
28075
+ return join13(dataHome, "cortexkit", "magic-context");
28003
28076
  }
28004
28077
  function fileSize(path4) {
28005
28078
  try {
28006
- return existsSync14(path4) ? statSync2(path4).size : 0;
28079
+ return existsSync15(path4) ? statSync2(path4).size : 0;
28007
28080
  } catch {
28008
28081
  return 0;
28009
28082
  }
@@ -28015,11 +28088,11 @@ function sanitizeValue(value) {
28015
28088
  return sanitizeConfigValue(value);
28016
28089
  }
28017
28090
  function readConfig2(path4) {
28018
- if (!existsSync14(path4))
28091
+ if (!existsSync15(path4))
28019
28092
  return { value: null };
28020
28093
  try {
28021
- const raw = readFileSync10(path4, "utf-8");
28022
- const value = import_comment_json7.parse(raw);
28094
+ const raw = readFileSync11(path4, "utf-8");
28095
+ const value = import_comment_json8.parse(raw);
28023
28096
  return { value };
28024
28097
  } catch (error51) {
28025
28098
  return { value: null, error: error51 instanceof Error ? error51.message : String(error51) };
@@ -28041,7 +28114,7 @@ function configHasPluginEntry(config2) {
28041
28114
  }
28042
28115
  function parseHistorianDumpMeta(path4) {
28043
28116
  try {
28044
- const xml = readFileSync10(path4, "utf-8");
28117
+ const xml = readFileSync11(path4, "utf-8");
28045
28118
  const parsed = parseCompartmentOutput(xml);
28046
28119
  const factCountByCategory = {};
28047
28120
  for (const fact of parsed.facts) {
@@ -28074,11 +28147,11 @@ function parseHistorianDumpMeta(path4) {
28074
28147
  }
28075
28148
  }
28076
28149
  function listDumpsInDir(dir, limit) {
28077
- if (!existsSync14(dir))
28150
+ if (!existsSync15(dir))
28078
28151
  return { count: 0, recent: [] };
28079
28152
  try {
28080
28153
  const entries = readdirSync2(dir).filter((name) => name.endsWith(".xml")).map((name) => {
28081
- const stat = statSync2(join12(dir, name));
28154
+ const stat = statSync2(join13(dir, name));
28082
28155
  return {
28083
28156
  name,
28084
28157
  mtime: stat.mtimeMs,
@@ -28087,7 +28160,7 @@ function listDumpsInDir(dir, limit) {
28087
28160
  }).sort((a, b2) => b2.mtime - a.mtime);
28088
28161
  const now = Date.now();
28089
28162
  const recent = entries.slice(0, limit).map((entry) => {
28090
- const meta3 = parseHistorianDumpMeta(join12(dir, entry.name));
28163
+ const meta3 = parseHistorianDumpMeta(join13(dir, entry.name));
28091
28164
  const summary = {
28092
28165
  name: entry.name,
28093
28166
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -28142,8 +28215,8 @@ function collectHistorianDumps(recentSessions) {
28142
28215
  };
28143
28216
  }
28144
28217
  async function collectRecentSessions() {
28145
- const opencodeDbPath = join12(homedir10(), ".local", "share", "opencode", "opencode.db");
28146
- if (!existsSync14(opencodeDbPath))
28218
+ const opencodeDbPath = join13(homedir11(), ".local", "share", "opencode", "opencode.db");
28219
+ if (!existsSync15(opencodeDbPath))
28147
28220
  return [];
28148
28221
  if (typeof globalThis.Bun === "undefined") {
28149
28222
  return [];
@@ -28177,8 +28250,8 @@ async function collectRecentSessions() {
28177
28250
  }
28178
28251
  }
28179
28252
  async function collectHistorianFailures(storageDirPath) {
28180
- const contextDbPath = join12(storageDirPath, "context.db");
28181
- if (!existsSync14(contextDbPath))
28253
+ const contextDbPath = join13(storageDirPath, "context.db");
28254
+ if (!existsSync15(contextDbPath))
28182
28255
  return [];
28183
28256
  if (typeof globalThis.Bun === "undefined") {
28184
28257
  return [];
@@ -28217,9 +28290,9 @@ async function collectDiagnostics() {
28217
28290
  const tuiConfig = readConfig2(configPaths.tuiConfig);
28218
28291
  const magicContextConfig = readConfig2(configPaths.magicContextConfig);
28219
28292
  const storageDirPath = getStorageDir();
28220
- const contextDbPath = join12(storageDirPath, "context.db");
28293
+ const contextDbPath = join13(storageDirPath, "context.db");
28221
28294
  const logPath = getMagicContextLogPath2("opencode");
28222
- const logFileSize = existsSync14(logPath) ? statSync2(logPath).size : 0;
28295
+ const logFileSize = existsSync15(logPath) ? statSync2(logPath).size : 0;
28223
28296
  const conflictResult = detectConflicts(process.cwd());
28224
28297
  const recentSessions = await collectRecentSessions();
28225
28298
  return {
@@ -28234,14 +28307,15 @@ async function collectDiagnostics() {
28234
28307
  opencodeConfigHasPlugin: configHasPluginEntry(opencodeConfig.value),
28235
28308
  tuiConfigHasPlugin: configHasPluginEntry(tuiConfig.value),
28236
28309
  magicContextConfig: {
28237
- exists: existsSync14(configPaths.magicContextConfig),
28310
+ exists: existsSync15(configPaths.magicContextConfig),
28238
28311
  ...magicContextConfig.error ? { parseError: magicContextConfig.error } : {},
28239
28312
  flags: sanitizeValue(magicContextConfig.value ?? {}) ?? {}
28240
28313
  },
28314
+ aft: getAftAvailability(),
28241
28315
  pluginCache: getPluginCacheInfo(),
28242
28316
  storageDir: {
28243
28317
  path: storageDirPath,
28244
- exists: existsSync14(storageDirPath),
28318
+ exists: existsSync15(storageDirPath),
28245
28319
  contextDbSizeBytes: fileSize(contextDbPath)
28246
28320
  },
28247
28321
  conflicts: {
@@ -28250,7 +28324,7 @@ async function collectDiagnostics() {
28250
28324
  },
28251
28325
  logFile: {
28252
28326
  path: logPath,
28253
- exists: existsSync14(logPath),
28327
+ exists: existsSync15(logPath),
28254
28328
  sizeKb: Math.round(logFileSize / 1024)
28255
28329
  },
28256
28330
  recentSessions,
@@ -28316,6 +28390,7 @@ function renderDiagnosticsMarkdown(report) {
28316
28390
  `- Plugin registered in opencode config: ${report.opencodeConfigHasPlugin}`,
28317
28391
  `- Plugin registered in tui config: ${report.tuiConfigHasPlugin}`,
28318
28392
  `- magic-context.jsonc parse error: ${report.magicContextConfig.parseError ?? "none"}`,
28393
+ `- AFT available: ${report.aft?.available ?? false} (opencode=${report.aft?.opencode ?? false}, pi=${report.aft?.pi ?? false})`,
28319
28394
  `- Conflicts detected: ${report.conflicts.hasConflict ? report.conflicts.reasons.join("; ") : "none"}`,
28320
28395
  "",
28321
28396
  "### Config paths",
@@ -28364,22 +28439,23 @@ function renderDiagnosticsMarkdown(report) {
28364
28439
  ].join(`
28365
28440
  `);
28366
28441
  }
28367
- var import_comment_json7, PLUGIN_NAME5 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY_WITH_VERSION;
28442
+ var import_comment_json8, PLUGIN_NAME5 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY_WITH_VERSION;
28368
28443
  var init_diagnostics_opencode = __esm(() => {
28444
+ init_aft_availability();
28369
28445
  init_compartment_parser();
28370
28446
  init_conflict_detector();
28371
28447
  init_data_path();
28372
28448
  init_opencode_helpers();
28373
28449
  init_paths();
28374
28450
  init_redaction();
28375
- import_comment_json7 = __toESM(require_src2(), 1);
28451
+ import_comment_json8 = __toESM(require_src2(), 1);
28376
28452
  PLUGIN_ENTRY_WITH_VERSION = `${PLUGIN_NAME5}@latest`;
28377
28453
  });
28378
28454
 
28379
28455
  // src/lib/logs-opencode.ts
28380
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "node:fs";
28381
- import { homedir as homedir11 } from "node:os";
28382
- import { join as join13 } from "node:path";
28456
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "node:fs";
28457
+ import { homedir as homedir12 } from "node:os";
28458
+ import { join as join14 } from "node:path";
28383
28459
  function sanitizeLogContent(content) {
28384
28460
  return sanitizeDiagnosticText(content);
28385
28461
  }
@@ -28421,7 +28497,7 @@ function filterLogLinesBySession(lines, sessionId) {
28421
28497
  }
28422
28498
  async function bundleIssueReport(report, description, _title, sessionFilter = null) {
28423
28499
  const LOG_TAIL_LINES = 400;
28424
- const allLogLines = report.logFile.exists ? readFileSync11(report.logFile.path, "utf-8").split(/\r?\n/) : [];
28500
+ const allLogLines = report.logFile.exists ? readFileSync12(report.logFile.path, "utf-8").split(/\r?\n/) : [];
28425
28501
  const logLines = filterLogLinesBySession(allLogLines, sessionFilter);
28426
28502
  const recentLog = sanitizeLogContent(logLines.slice(-LOG_TAIL_LINES).join(`
28427
28503
  `)).trim();
@@ -28429,7 +28505,7 @@ async function bundleIssueReport(report, description, _title, sessionFilter = nu
28429
28505
  `));
28430
28506
  const historianFailureLines = extractHistorianFailureLines(historianScanWindow, 30);
28431
28507
  const configBody = JSON.stringify(sanitizeConfigValue(report.magicContextConfig.flags), null, 2);
28432
- const sanitizedConfigPath = report.configPaths.magicContextConfig.replace(homedir11(), "~");
28508
+ const sanitizedConfigPath = report.configPaths.magicContextConfig.replace(homedir12(), "~");
28433
28509
  const bodyMarkdown = [
28434
28510
  "## Description",
28435
28511
  description,
@@ -28460,7 +28536,7 @@ async function bundleIssueReport(report, description, _title, sessionFilter = nu
28460
28536
  "```"
28461
28537
  ].join(`
28462
28538
  `);
28463
- const path4 = join13(process.cwd(), `magic-context-issue-${formatTimestamp(new Date)}.md`);
28539
+ const path4 = join14(process.cwd(), `magic-context-issue-${formatTimestamp(new Date)}.md`);
28464
28540
  writeFileSync9(path4, `${bodyMarkdown}
28465
28541
  `);
28466
28542
  return { path: path4, bodyMarkdown };
@@ -28482,10 +28558,10 @@ var init_logs_opencode = __esm(() => {
28482
28558
 
28483
28559
  // src/commands/doctor-opencode.ts
28484
28560
  import { execSync as execSync2, spawnSync as spawnSync2 } from "node:child_process";
28485
- import { existsSync as existsSync15, readFileSync as readFileSync12, rmSync, statSync as statSync3, writeFileSync as writeFileSync10 } from "node:fs";
28561
+ import { existsSync as existsSync16, readFileSync as readFileSync13, rmSync, statSync as statSync3, writeFileSync as writeFileSync10 } from "node:fs";
28486
28562
  import { createRequire as createRequire4 } from "node:module";
28487
- import { homedir as homedir12 } from "node:os";
28488
- import { join as join14 } from "node:path";
28563
+ import { homedir as homedir13 } from "node:os";
28564
+ import { join as join15 } from "node:path";
28489
28565
  async function fetchNpmLatest(pkg, timeoutMs = 5000) {
28490
28566
  try {
28491
28567
  const controller = new AbortController;
@@ -28535,15 +28611,15 @@ function compareVersions(a, b2) {
28535
28611
  }
28536
28612
  async function clearPluginCache(force = false) {
28537
28613
  const cacheDir = getOpenCodeCacheDir();
28538
- const pluginCacheDir = join14(cacheDir, "packages", PLUGIN_ENTRY_WITH_VERSION2);
28539
- if (!existsSync15(pluginCacheDir)) {
28614
+ const pluginCacheDir = join15(cacheDir, "packages", PLUGIN_ENTRY_WITH_VERSION2);
28615
+ if (!existsSync16(pluginCacheDir)) {
28540
28616
  return { action: "not_found", path: pluginCacheDir };
28541
28617
  }
28542
28618
  let cachedVersion;
28543
28619
  try {
28544
- const installedPkgPath = join14(pluginCacheDir, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
28545
- if (existsSync15(installedPkgPath)) {
28546
- const pkg = JSON.parse(readFileSync12(installedPkgPath, "utf-8"));
28620
+ const installedPkgPath = join15(pluginCacheDir, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
28621
+ if (existsSync16(installedPkgPath)) {
28622
+ const pkg = JSON.parse(readFileSync13(installedPkgPath, "utf-8"));
28547
28623
  if (typeof pkg?.version === "string") {
28548
28624
  cachedVersion = pkg.version;
28549
28625
  }
@@ -28675,12 +28751,12 @@ async function runIssueFlow() {
28675
28751
  }
28676
28752
  }
28677
28753
  async function checkEmbeddingConfig(magicContextConfigPath) {
28678
- if (!existsSync15(magicContextConfigPath)) {
28754
+ if (!existsSync16(magicContextConfigPath)) {
28679
28755
  return { issues: 0 };
28680
28756
  }
28681
28757
  let rawText;
28682
28758
  try {
28683
- rawText = readFileSync12(magicContextConfigPath, "utf-8");
28759
+ rawText = readFileSync13(magicContextConfigPath, "utf-8");
28684
28760
  } catch {
28685
28761
  log.warn("Could not read magic-context.jsonc for embedding check");
28686
28762
  return { issues: 1 };
@@ -28691,7 +28767,7 @@ async function checkEmbeddingConfig(magicContextConfigPath) {
28691
28767
  });
28692
28768
  let parsedConfig;
28693
28769
  try {
28694
- parsedConfig = import_comment_json8.parse(substituted.text);
28770
+ parsedConfig = import_comment_json9.parse(substituted.text);
28695
28771
  } catch (error51) {
28696
28772
  log.warn(`Embedding check skipped — could not parse magic-context.jsonc: ${error51 instanceof Error ? error51.message : String(error51)}`);
28697
28773
  return { issues: 1 };
@@ -28828,15 +28904,15 @@ async function runDoctor(options = {}) {
28828
28904
  } else {
28829
28905
  pass(`OpenCode config: ${paths.opencodeConfig}`);
28830
28906
  }
28831
- if (existsSync15(paths.magicContextConfig)) {
28907
+ if (existsSync16(paths.magicContextConfig)) {
28832
28908
  pass(`Magic Context config: ${paths.magicContextConfig}`);
28833
28909
  try {
28834
- const raw = readFileSync12(paths.magicContextConfig, "utf-8");
28910
+ const raw = readFileSync13(paths.magicContextConfig, "utf-8");
28835
28911
  const substituted = substituteConfigVariables({
28836
28912
  text: raw,
28837
28913
  configPath: paths.magicContextConfig
28838
28914
  }).text;
28839
- import_comment_json8.parse(substituted);
28915
+ import_comment_json9.parse(substituted);
28840
28916
  pass("magic-context.jsonc parses as valid JSONC");
28841
28917
  } catch (err) {
28842
28918
  fail(`magic-context.jsonc parse failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -28856,10 +28932,10 @@ async function runDoctor(options = {}) {
28856
28932
  warn(`No magic-context.jsonc found — using defaults`);
28857
28933
  log.info(" Run 'setup' to create one with model recommendations");
28858
28934
  }
28859
- if (existsSync15(paths.magicContextConfig)) {
28935
+ if (existsSync16(paths.magicContextConfig)) {
28860
28936
  try {
28861
- const mcRaw = readFileSync12(paths.magicContextConfig, "utf-8");
28862
- const mcConfig = import_comment_json8.parse(mcRaw);
28937
+ const mcRaw = readFileSync13(paths.magicContextConfig, "utf-8");
28938
+ const mcConfig = import_comment_json9.parse(mcRaw);
28863
28939
  let mcChanged = false;
28864
28940
  const experimental = mcConfig.experimental;
28865
28941
  if (experimental && "compaction_markers" in experimental) {
@@ -28934,7 +29010,7 @@ async function runDoctor(options = {}) {
28934
29010
  fixed++;
28935
29011
  }
28936
29012
  if (mcChanged) {
28937
- writeFileSync10(paths.magicContextConfig, `${import_comment_json8.stringify(mcConfig, null, 2)}
29013
+ writeFileSync10(paths.magicContextConfig, `${import_comment_json9.stringify(mcConfig, null, 2)}
28938
29014
  `);
28939
29015
  }
28940
29016
  } catch {
@@ -28943,8 +29019,8 @@ async function runDoctor(options = {}) {
28943
29019
  }
28944
29020
  if (paths.opencodeConfigFormat !== "none") {
28945
29021
  try {
28946
- const raw = readFileSync12(paths.opencodeConfig, "utf-8");
28947
- const config2 = import_comment_json8.parse(raw);
29022
+ const raw = readFileSync13(paths.opencodeConfig, "utf-8");
29023
+ const config2 = import_comment_json9.parse(raw);
28948
29024
  const rawPlugins = Array.isArray(config2?.plugin) ? config2.plugin : [];
28949
29025
  const existingIdx = rawPlugins.findIndex((entry) => matchesPluginEntry(entry, PLUGIN_NAME6) || isDevPathPluginEntry(entry));
28950
29026
  const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
@@ -28975,7 +29051,7 @@ async function runDoctor(options = {}) {
28975
29051
  rawPlugins[existingIdx] = PLUGIN_ENTRY_WITH_VERSION2;
28976
29052
  }
28977
29053
  config2.plugin = rawPlugins;
28978
- writeFileSync10(paths.opencodeConfig, `${import_comment_json8.stringify(config2, null, 2)}
29054
+ writeFileSync10(paths.opencodeConfig, `${import_comment_json9.stringify(config2, null, 2)}
28979
29055
  `);
28980
29056
  pass(`Upgraded plugin entry in ${configName}: ${oldEntryStr} → ${PLUGIN_ENTRY_WITH_VERSION2}`);
28981
29057
  fixed++;
@@ -28984,7 +29060,7 @@ async function runDoctor(options = {}) {
28984
29060
  } else {
28985
29061
  rawPlugins.push(PLUGIN_ENTRY_WITH_VERSION2);
28986
29062
  config2.plugin = rawPlugins;
28987
- writeFileSync10(paths.opencodeConfig, `${import_comment_json8.stringify(config2, null, 2)}
29063
+ writeFileSync10(paths.opencodeConfig, `${import_comment_json9.stringify(config2, null, 2)}
28988
29064
  `);
28989
29065
  pass(`Added plugin to ${configName}`);
28990
29066
  fixed++;
@@ -29015,10 +29091,10 @@ async function runDoctor(options = {}) {
29015
29091
  pass("Added TUI sidebar plugin to tui.json");
29016
29092
  warn("Restart OpenCode to see the sidebar");
29017
29093
  fixed++;
29018
- } else if (existsSync15(paths.tuiConfig)) {
29094
+ } else if (existsSync16(paths.tuiConfig)) {
29019
29095
  try {
29020
- const tuiRaw = readFileSync12(paths.tuiConfig, "utf-8");
29021
- const tuiConfig = import_comment_json8.parse(tuiRaw);
29096
+ const tuiRaw = readFileSync13(paths.tuiConfig, "utf-8");
29097
+ const tuiConfig = import_comment_json9.parse(tuiRaw);
29022
29098
  const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
29023
29099
  const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, PLUGIN_NAME6) || isDevPathPluginEntry(entry));
29024
29100
  const tuiEntryAsString = (entry) => {
@@ -29046,7 +29122,7 @@ async function runDoctor(options = {}) {
29046
29122
  tuiRawPlugins[tuiIdx] = PLUGIN_ENTRY_WITH_VERSION2;
29047
29123
  }
29048
29124
  tuiConfig.plugin = tuiRawPlugins;
29049
- writeFileSync10(paths.tuiConfig, `${import_comment_json8.stringify(tuiConfig, null, 2)}
29125
+ writeFileSync10(paths.tuiConfig, `${import_comment_json9.stringify(tuiConfig, null, 2)}
29050
29126
  `);
29051
29127
  pass(`Upgraded TUI plugin: ${tuiEntryStr} → ${PLUGIN_ENTRY_WITH_VERSION2}`);
29052
29128
  fixed++;
@@ -29063,10 +29139,10 @@ async function runDoctor(options = {}) {
29063
29139
  } else {
29064
29140
  pass("TUI sidebar plugin configured (tui.json created)");
29065
29141
  }
29066
- if (existsSync15(paths.magicContextConfig)) {
29142
+ if (existsSync16(paths.magicContextConfig)) {
29067
29143
  try {
29068
- const mcRaw = readFileSync12(paths.magicContextConfig, "utf-8");
29069
- const mcConfig = import_comment_json8.parse(mcRaw);
29144
+ const mcRaw = readFileSync13(paths.magicContextConfig, "utf-8");
29145
+ const mcConfig = import_comment_json9.parse(mcRaw);
29070
29146
  const dreamerObj = mcConfig?.dreamer;
29071
29147
  const dreamerEnabled = dreamerObj?.enabled === true;
29072
29148
  const userMemObj = dreamerObj?.user_memories;
@@ -29075,6 +29151,15 @@ async function runDoctor(options = {}) {
29075
29151
  log.warn("dreamer.user_memories is enabled (default) but dreamer itself is disabled — user memory candidates will be collected but never promoted to stable memories. Enable `dreamer.enabled: true` or set `dreamer.user_memories.enabled: false` to silence this.");
29076
29152
  issues++;
29077
29153
  }
29154
+ const pinKeyFilesObj = dreamerObj?.pin_key_files;
29155
+ if (pinKeyFilesObj?.enabled === true) {
29156
+ const aft = getAftAvailability();
29157
+ if (aft.available) {
29158
+ pass("AFT detected for dreamer.pin_key_files");
29159
+ } else {
29160
+ fail(`dreamer.pin_key_files is enabled but AFT is not configured. Install/register AFT (checked: ${aft.checkedPaths.join(", ")})`);
29161
+ }
29162
+ }
29078
29163
  } catch {}
29079
29164
  }
29080
29165
  const embeddingCheck = await checkEmbeddingConfig(paths.magicContextConfig);
@@ -29083,8 +29168,8 @@ async function runDoctor(options = {}) {
29083
29168
  failCount += embeddingCheck.issues;
29084
29169
  else
29085
29170
  passCount++;
29086
- const dbPath = join14(getMagicContextStorageDir(), "context.db");
29087
- if (!existsSync15(dbPath)) {
29171
+ const dbPath = join15(getMagicContextStorageDir(), "context.db");
29172
+ if (!existsSync16(dbPath)) {
29088
29173
  log.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
29089
29174
  } else {
29090
29175
  pass(`Shared context DB exists at ${dbPath}`);
@@ -29145,10 +29230,10 @@ async function runDoctor(options = {}) {
29145
29230
  }
29146
29231
  {
29147
29232
  const ageWarnings = [];
29148
- const npmrcPath = join14(homedir12(), ".npmrc");
29149
- if (existsSync15(npmrcPath)) {
29233
+ const npmrcPath = join15(homedir13(), ".npmrc");
29234
+ if (existsSync16(npmrcPath)) {
29150
29235
  try {
29151
- const npmrc = readFileSync12(npmrcPath, "utf-8");
29236
+ const npmrc = readFileSync13(npmrcPath, "utf-8");
29152
29237
  for (const line of npmrc.split(`
29153
29238
  `)) {
29154
29239
  const trimmed = line.trim();
@@ -29172,7 +29257,7 @@ async function runDoctor(options = {}) {
29172
29257
  }
29173
29258
  }
29174
29259
  const logPath = getMagicContextLogPath2("opencode");
29175
- if (existsSync15(logPath)) {
29260
+ if (existsSync16(logPath)) {
29176
29261
  const logStat = statSync3(logPath);
29177
29262
  const sizeKb = (logStat.size / 1024).toFixed(0);
29178
29263
  log.info(`Log file: ${logPath} (${sizeKb} KB)`);
@@ -29218,10 +29303,11 @@ async function runDoctor(options = {}) {
29218
29303
  }
29219
29304
  return 0;
29220
29305
  }
29221
- var import_comment_json8, PLUGIN_NAME6 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY_WITH_VERSION2, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
29306
+ var import_comment_json9, PLUGIN_NAME6 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY_WITH_VERSION2, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
29222
29307
  var init_doctor_opencode = __esm(async () => {
29223
29308
  init_config();
29224
29309
  init_variable();
29310
+ init_aft_availability();
29225
29311
  init_conflict_detector();
29226
29312
  init_conflict_fixer();
29227
29313
  init_data_path();
@@ -29233,7 +29319,7 @@ var init_doctor_opencode = __esm(async () => {
29233
29319
  init_paths();
29234
29320
  init_prompts();
29235
29321
  await init_sqlite();
29236
- import_comment_json8 = __toESM(require_src2(), 1);
29322
+ import_comment_json9 = __toESM(require_src2(), 1);
29237
29323
  PLUGIN_ENTRY_WITH_VERSION2 = `${PLUGIN_NAME6}@latest`;
29238
29324
  });
29239
29325
 
@@ -161820,6 +161906,34 @@ function getErrorMessage(error51) {
161820
161906
  return error51 instanceof Error ? error51.message : String(error51);
161821
161907
  }
161822
161908
 
161909
+ // ../plugin/src/features/magic-context/key-files/project-key-files.ts
161910
+ import { existsSync as existsSync17, readFileSync as readFileSync14, realpathSync } from "node:fs";
161911
+ function deleteOrphanProjectKeyFiles(db, now = Date.now()) {
161912
+ const cutoff = now - ORPHAN_GRACE_MS;
161913
+ const rows = db.prepare(`SELECT project_path AS projectPath, MAX(generated_at) AS lastGen
161914
+ FROM project_key_files
161915
+ GROUP BY project_path
161916
+ HAVING lastGen < ?`).all(cutoff);
161917
+ let deletedProjects = 0;
161918
+ for (const row of rows) {
161919
+ if (existsSync17(row.projectPath))
161920
+ continue;
161921
+ try {
161922
+ db.prepare("DELETE FROM project_key_files WHERE project_path = ?").run(row.projectPath);
161923
+ db.prepare("DELETE FROM project_key_files_version WHERE project_path = ?").run(row.projectPath);
161924
+ deletedProjects++;
161925
+ } catch (error51) {
161926
+ log2(`[key-files] orphan GC failed for ${row.projectPath}:`, error51);
161927
+ }
161928
+ }
161929
+ return deletedProjects;
161930
+ }
161931
+ var ORPHAN_GRACE_MS;
161932
+ var init_project_key_files = __esm(() => {
161933
+ init_logger();
161934
+ ORPHAN_GRACE_MS = 7 * 24 * 60 * 60 * 1000;
161935
+ });
161936
+
161823
161937
  // ../plugin/src/features/magic-context/migrations.ts
161824
161938
  function ensureMigrationsTable(db) {
161825
161939
  db.exec(`
@@ -162187,6 +162301,92 @@ var init_migrations = __esm(async () => {
162187
162301
  db.exec("ALTER TABLE session_meta ADD COLUMN pending_compaction_marker_state TEXT");
162188
162302
  }
162189
162303
  }
162304
+ },
162305
+ {
162306
+ version: 14,
162307
+ description: "Add project-scoped key files and version counter",
162308
+ up: (db) => {
162309
+ db.exec(`
162310
+ CREATE TABLE IF NOT EXISTS project_key_files (
162311
+ project_path TEXT NOT NULL,
162312
+ path TEXT NOT NULL,
162313
+ content TEXT NOT NULL,
162314
+ content_hash TEXT NOT NULL,
162315
+ local_token_estimate INTEGER NOT NULL,
162316
+ generated_at INTEGER NOT NULL,
162317
+ generated_by_model TEXT,
162318
+ generation_config_hash TEXT NOT NULL,
162319
+ stale_reason TEXT,
162320
+ PRIMARY KEY (project_path, path)
162321
+ );
162322
+
162323
+ CREATE INDEX IF NOT EXISTS idx_project_key_files_project
162324
+ ON project_key_files(project_path);
162325
+ CREATE INDEX IF NOT EXISTS idx_project_key_files_generated_at
162326
+ ON project_key_files(project_path, generated_at);
162327
+
162328
+ CREATE TABLE IF NOT EXISTS project_key_files_version (
162329
+ project_path TEXT PRIMARY KEY,
162330
+ version INTEGER NOT NULL DEFAULT 0
162331
+ );
162332
+ `);
162333
+ }
162334
+ },
162335
+ {
162336
+ version: 15,
162337
+ description: "Add deferred_execute_state column for boundary execution drain",
162338
+ up: (db) => {
162339
+ const cols = db.prepare("PRAGMA table_info(session_meta)").all();
162340
+ if (!cols.some((c2) => c2.name === "deferred_execute_state")) {
162341
+ db.exec("ALTER TABLE session_meta ADD COLUMN deferred_execute_state TEXT");
162342
+ }
162343
+ }
162344
+ },
162345
+ {
162346
+ version: 16,
162347
+ description: "Add context-limit cache regression sentinels",
162348
+ up: (db) => {
162349
+ const cols = db.prepare("PRAGMA table_info(session_meta)").all();
162350
+ if (!cols.some((c2) => c2.name === "observed_safe_input_tokens")) {
162351
+ db.exec("ALTER TABLE session_meta ADD COLUMN observed_safe_input_tokens INTEGER NOT NULL DEFAULT 0");
162352
+ }
162353
+ if (!cols.some((c2) => c2.name === "cache_alert_sent")) {
162354
+ db.exec("ALTER TABLE session_meta ADD COLUMN cache_alert_sent INTEGER NOT NULL DEFAULT 0");
162355
+ }
162356
+ }
162357
+ },
162358
+ {
162359
+ version: 17,
162360
+ description: "Multi-anchor JSON storage for note-nudge and auto-search-hint persistence",
162361
+ up: (db) => {
162362
+ const cols = db.prepare("PRAGMA table_info(session_meta)").all();
162363
+ if (!cols.some((c2) => c2.name === "note_nudge_anchors")) {
162364
+ db.exec("ALTER TABLE session_meta ADD COLUMN note_nudge_anchors TEXT NOT NULL DEFAULT '[]'");
162365
+ }
162366
+ if (!cols.some((c2) => c2.name === "auto_search_hint_decisions")) {
162367
+ db.exec("ALTER TABLE session_meta ADD COLUMN auto_search_hint_decisions TEXT NOT NULL DEFAULT '[]'");
162368
+ }
162369
+ db.exec(`
162370
+ UPDATE session_meta
162371
+ SET note_nudge_anchors = json_array(
162372
+ json_object(
162373
+ 'messageId', note_nudge_sticky_message_id,
162374
+ 'text', note_nudge_sticky_text
162375
+ )
162376
+ )
162377
+ WHERE COALESCE(note_nudge_sticky_text, '') != ''
162378
+ AND COALESCE(note_nudge_sticky_message_id, '') != ''
162379
+ AND (note_nudge_anchors IS NULL OR note_nudge_anchors = '[]')
162380
+ `);
162381
+ db.exec(`
162382
+ UPDATE session_meta SET note_nudge_anchors = '[]'
162383
+ WHERE note_nudge_anchors IS NULL
162384
+ `);
162385
+ db.exec(`
162386
+ UPDATE session_meta SET auto_search_hint_decisions = '[]'
162387
+ WHERE auto_search_hint_decisions IS NULL
162388
+ `);
162389
+ }
162190
162390
  }
162191
162391
  ];
162192
162392
  });
@@ -162224,10 +162424,10 @@ var init_tool_definition_tokens = __esm(() => {
162224
162424
  });
162225
162425
 
162226
162426
  // ../plugin/src/features/magic-context/tool-owner-backfill.ts
162227
- import { existsSync as existsSync16 } from "node:fs";
162228
- import { join as join15 } from "node:path";
162427
+ import { existsSync as existsSync18 } from "node:fs";
162428
+ import { join as join16 } from "node:path";
162229
162429
  function resolveOpencodeDbPath() {
162230
- return join15(getDataDir(), "opencode", "opencode.db");
162430
+ return join16(getDataDir(), "opencode", "opencode.db");
162231
162431
  }
162232
162432
  function ensureBackfillStateTable(db) {
162233
162433
  db.exec(`
@@ -162262,7 +162462,7 @@ function runToolOwnerBackfill(db) {
162262
162462
  return result;
162263
162463
  }
162264
162464
  const opencodeDbPath = resolveOpencodeDbPath();
162265
- if (!existsSync16(opencodeDbPath)) {
162465
+ if (!existsSync18(opencodeDbPath)) {
162266
162466
  log2(`[backfill] OpenCode DB not found at ${opencodeDbPath} — marking all unbackfilled sessions as skipped. Lazy adoption (defense-in-depth) handles legacy rows at runtime.`);
162267
162467
  markAllUnbackfilledSessionsSkipped(db);
162268
162468
  result.sessionsSkippedNoOcDb = countSessionsByStatus(db, "skipped");
@@ -162472,25 +162672,25 @@ var init_tool_owner_backfill = __esm(() => {
162472
162672
  });
162473
162673
 
162474
162674
  // ../plugin/src/features/magic-context/storage-db.ts
162475
- import { copyFileSync, cpSync, existsSync as existsSync17, mkdirSync as mkdirSync7 } from "node:fs";
162476
- import { join as join16 } from "node:path";
162675
+ import { copyFileSync, cpSync, existsSync as existsSync19, mkdirSync as mkdirSync7 } from "node:fs";
162676
+ import { join as join17 } from "node:path";
162477
162677
  function resolveDatabasePath() {
162478
162678
  const dbDir = getMagicContextStorageDir();
162479
- return { dbDir, dbPath: join16(dbDir, "context.db") };
162679
+ return { dbDir, dbPath: join17(dbDir, "context.db") };
162480
162680
  }
162481
162681
  function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
162482
- if (existsSync17(targetDbPath))
162682
+ if (existsSync19(targetDbPath))
162483
162683
  return;
162484
162684
  const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
162485
- const legacyDbPath = join16(legacyDir, "context.db");
162486
- if (!existsSync17(legacyDbPath))
162685
+ const legacyDbPath = join17(legacyDir, "context.db");
162686
+ if (!existsSync19(legacyDbPath))
162487
162687
  return;
162488
162688
  log2(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
162489
162689
  mkdirSync7(targetDbDir, { recursive: true });
162490
162690
  for (const suffix of ["", "-wal", "-shm"]) {
162491
162691
  const src = `${legacyDbPath}${suffix}`;
162492
- const dst = join16(targetDbDir, `context.db${suffix}`);
162493
- if (existsSync17(src)) {
162692
+ const dst = join17(targetDbDir, `context.db${suffix}`);
162693
+ if (existsSync19(src)) {
162494
162694
  try {
162495
162695
  copyFileSync(src, dst);
162496
162696
  } catch (error51) {
@@ -162498,9 +162698,9 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
162498
162698
  }
162499
162699
  }
162500
162700
  }
162501
- const legacyModelsDir = join16(legacyDir, "models");
162502
- const targetModelsDir = join16(targetDbDir, "models");
162503
- if (existsSync17(legacyModelsDir) && !existsSync17(targetModelsDir)) {
162701
+ const legacyModelsDir = join17(legacyDir, "models");
162702
+ const targetModelsDir = join17(targetDbDir, "models");
162703
+ if (existsSync19(legacyModelsDir) && !existsSync19(targetModelsDir)) {
162504
162704
  try {
162505
162705
  cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
162506
162706
  } catch (error51) {
@@ -162648,6 +162848,26 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
162648
162848
  );
162649
162849
  CREATE INDEX IF NOT EXISTS idx_dream_runs_project ON dream_runs(project_path, finished_at DESC);
162650
162850
 
162851
+ CREATE TABLE IF NOT EXISTS project_key_files (
162852
+ project_path TEXT NOT NULL,
162853
+ path TEXT NOT NULL,
162854
+ content TEXT NOT NULL,
162855
+ content_hash TEXT NOT NULL,
162856
+ local_token_estimate INTEGER NOT NULL,
162857
+ generated_at INTEGER NOT NULL,
162858
+ generated_by_model TEXT,
162859
+ generation_config_hash TEXT NOT NULL,
162860
+ stale_reason TEXT,
162861
+ PRIMARY KEY (project_path, path)
162862
+ );
162863
+ CREATE INDEX IF NOT EXISTS idx_project_key_files_project ON project_key_files(project_path);
162864
+ CREATE INDEX IF NOT EXISTS idx_project_key_files_generated_at ON project_key_files(project_path, generated_at);
162865
+
162866
+ CREATE TABLE IF NOT EXISTS project_key_files_version (
162867
+ project_path TEXT PRIMARY KEY,
162868
+ version INTEGER NOT NULL DEFAULT 0
162869
+ );
162870
+
162651
162871
  -- (smart_notes: see note above; merged into unified notes table by migration v1)
162652
162872
 
162653
162873
  CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
@@ -162704,6 +162924,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
162704
162924
  note_nudge_trigger_message_id TEXT DEFAULT '',
162705
162925
  note_nudge_sticky_text TEXT DEFAULT '',
162706
162926
  note_nudge_sticky_message_id TEXT DEFAULT '',
162927
+ note_nudge_anchors TEXT NOT NULL DEFAULT '[]',
162928
+ auto_search_hint_decisions TEXT NOT NULL DEFAULT '[]',
162707
162929
  last_todo_state TEXT DEFAULT '',
162708
162930
  todo_synthetic_call_id TEXT DEFAULT '',
162709
162931
  todo_synthetic_anchor_message_id TEXT DEFAULT '',
@@ -162711,6 +162933,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
162711
162933
  is_subagent INTEGER DEFAULT 0,
162712
162934
  last_context_percentage REAL DEFAULT 0,
162713
162935
  last_input_tokens INTEGER DEFAULT 0,
162936
+ observed_safe_input_tokens INTEGER NOT NULL DEFAULT 0,
162937
+ cache_alert_sent INTEGER NOT NULL DEFAULT 0,
162714
162938
  times_execute_threshold_reached INTEGER DEFAULT 0,
162715
162939
  compartment_in_progress INTEGER DEFAULT 0,
162716
162940
  historian_failure_count INTEGER DEFAULT 0,
@@ -162725,7 +162949,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
162725
162949
  -- valid JSON blob written via setPendingCompactionMarkerState.
162726
162950
  -- Excluded from healNullTextColumns. Readers filter IS NOT NULL AND
162727
162951
  -- != empty-string defensively. Plan v6 section 3.
162728
- pending_compaction_marker_state TEXT
162952
+ pending_compaction_marker_state TEXT,
162953
+ -- deferred_execute_state: intentionally NULLABLE without a default.
162954
+ -- Absence is SQL NULL; presence is a JSON blob written via
162955
+ -- setDeferredExecutePendingIfAbsent. Excluded from healNullTextColumns.
162956
+ deferred_execute_state TEXT
162729
162957
  );
162730
162958
 
162731
162959
  CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
@@ -162778,12 +163006,16 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
162778
163006
  ensureColumn(db, "session_meta", "note_nudge_trigger_message_id", "TEXT DEFAULT ''");
162779
163007
  ensureColumn(db, "session_meta", "note_nudge_sticky_text", "TEXT DEFAULT ''");
162780
163008
  ensureColumn(db, "session_meta", "note_nudge_sticky_message_id", "TEXT DEFAULT ''");
163009
+ ensureColumn(db, "session_meta", "note_nudge_anchors", "TEXT NOT NULL DEFAULT '[]'");
163010
+ ensureColumn(db, "session_meta", "auto_search_hint_decisions", "TEXT NOT NULL DEFAULT '[]'");
162781
163011
  ensureColumn(db, "session_meta", "last_todo_state", "TEXT DEFAULT ''");
162782
163012
  ensureColumn(db, "session_meta", "todo_synthetic_call_id", "TEXT DEFAULT ''");
162783
163013
  ensureColumn(db, "session_meta", "todo_synthetic_anchor_message_id", "TEXT DEFAULT ''");
162784
163014
  ensureColumn(db, "session_meta", "todo_synthetic_state_json", "TEXT DEFAULT ''");
162785
163015
  ensureColumn(db, "session_meta", "note_last_read_at", "INTEGER DEFAULT 0");
162786
163016
  ensureColumn(db, "session_meta", "times_execute_threshold_reached", "INTEGER DEFAULT 0");
163017
+ ensureColumn(db, "session_meta", "observed_safe_input_tokens", "INTEGER NOT NULL DEFAULT 0");
163018
+ ensureColumn(db, "session_meta", "cache_alert_sent", "INTEGER NOT NULL DEFAULT 0");
162787
163019
  ensureColumn(db, "session_meta", "compartment_in_progress", "INTEGER DEFAULT 0");
162788
163020
  ensureColumn(db, "session_meta", "historian_failure_count", "INTEGER DEFAULT 0");
162789
163021
  ensureColumn(db, "session_meta", "historian_last_error", "TEXT DEFAULT NULL");
@@ -162814,6 +163046,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
162814
163046
  ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
162815
163047
  ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
162816
163048
  ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
163049
+ ensureColumn(db, "session_meta", "deferred_execute_state", "TEXT");
162817
163050
  ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
162818
163051
  ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
162819
163052
  ensureColumn(db, "source_contents", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
@@ -162874,7 +163107,9 @@ function healNullIntegerColumns(db) {
162874
163107
  ["system_prompt_tokens", 0],
162875
163108
  ["conversation_tokens", 0],
162876
163109
  ["tool_call_tokens", 0],
162877
- ["note_nudge_trigger_pending", 0]
163110
+ ["note_nudge_trigger_pending", 0],
163111
+ ["observed_safe_input_tokens", 0],
163112
+ ["cache_alert_sent", 0]
162878
163113
  ];
162879
163114
  for (const [column, fallback] of columns) {
162880
163115
  try {
@@ -162883,14 +163118,22 @@ function healNullIntegerColumns(db) {
162883
163118
  }
162884
163119
  }
162885
163120
  function ensureColumn(db, table, column, definition) {
162886
- if (!/^[a-z_]+$/.test(table) || !/^[a-z_]+$/.test(column) || !/^[A-Z0-9_'(),\s]+$/i.test(definition)) {
163121
+ if (!/^[a-z_]+$/.test(table) || !/^[a-z_]+$/.test(column) || !/^[A-Z0-9_'(),[\]\s]+$/i.test(definition)) {
162887
163122
  throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
162888
163123
  }
162889
163124
  const rows = db.prepare(`PRAGMA table_info(${table})`).all();
162890
163125
  if (rows.some((row) => row.name === column)) {
162891
163126
  return;
162892
163127
  }
162893
- db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
163128
+ try {
163129
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
163130
+ } catch (err) {
163131
+ const recheck = db.prepare(`PRAGMA table_info(${table})`).all();
163132
+ if (recheck.some((row) => row.name === column)) {
163133
+ return;
163134
+ }
163135
+ throw err;
163136
+ }
162894
163137
  }
162895
163138
  function openDatabase() {
162896
163139
  const { dbDir, dbPath } = resolveDatabasePath();
@@ -162907,6 +163150,11 @@ function openDatabase() {
162907
163150
  const db = new Database(dbPath);
162908
163151
  initializeDatabase(db);
162909
163152
  runMigrations(db);
163153
+ try {
163154
+ deleteOrphanProjectKeyFiles(db);
163155
+ } catch (error51) {
163156
+ log2(`[magic-context] key-files orphan GC failed: ${getErrorMessage(error51)}`);
163157
+ }
162910
163158
  try {
162911
163159
  runToolOwnerBackfill(db);
162912
163160
  } catch (error51) {
@@ -162942,6 +163190,7 @@ var databases, persistenceByDatabase, persistenceErrorByDatabase;
162942
163190
  var init_storage_db = __esm(async () => {
162943
163191
  init_data_path();
162944
163192
  init_logger();
163193
+ init_project_key_files();
162945
163194
  init_tool_definition_tokens();
162946
163195
  init_tool_owner_backfill();
162947
163196
  await __promiseAll([
@@ -162956,13 +163205,22 @@ var init_storage_db = __esm(async () => {
162956
163205
  // ../plugin/src/features/magic-context/storage-meta-shared.ts
162957
163206
  var BOOLEAN_META_KEYS;
162958
163207
  var init_storage_meta_shared = __esm(() => {
162959
- BOOLEAN_META_KEYS = new Set(["isSubagent", "compartmentInProgress"]);
163208
+ BOOLEAN_META_KEYS = new Set(["isSubagent", "compartmentInProgress", "cacheAlertSent"]);
162960
163209
  });
162961
163210
 
162962
163211
  // ../plugin/src/features/magic-context/storage-meta-persisted.ts
163212
+ var AUTO_SEARCH_NO_HINT_REASONS;
162963
163213
  var init_storage_meta_persisted = __esm(() => {
162964
163214
  init_logger();
162965
163215
  init_storage_meta_shared();
163216
+ AUTO_SEARCH_NO_HINT_REASONS = new Set([
163217
+ "below-threshold",
163218
+ "timeout",
163219
+ "empty",
163220
+ "error",
163221
+ "stacked",
163222
+ "too-short"
163223
+ ]);
162966
163224
  });
162967
163225
 
162968
163226
  // ../plugin/src/features/magic-context/resolve-subagent-fallback.ts
@@ -163045,24 +163303,24 @@ var init_storage = __esm(async () => {
163045
163303
  });
163046
163304
 
163047
163305
  // ../pi-plugin/src/config/index.ts
163048
- import { existsSync as existsSync18, readFileSync as readFileSync13 } from "node:fs";
163049
- import { homedir as homedir13 } from "node:os";
163050
- import { join as join17 } from "node:path";
163306
+ import { existsSync as existsSync20, readFileSync as readFileSync15 } from "node:fs";
163307
+ import { homedir as homedir14 } from "node:os";
163308
+ import { join as join18 } from "node:path";
163051
163309
  function getProjectConfigPaths(cwd) {
163052
- const basePath = join17(cwd, ".pi", CONFIG_FILE_NAME);
163310
+ const basePath = join18(cwd, ".pi", CONFIG_FILE_NAME);
163053
163311
  return [`${basePath}.jsonc`, `${basePath}.json`];
163054
163312
  }
163055
163313
  function getUserConfigPaths() {
163056
- const home = process.env.HOME ?? homedir13();
163057
- const basePath = join17(home, ".pi", "agent", CONFIG_FILE_NAME);
163314
+ const home = process.env.HOME ?? homedir14();
163315
+ const basePath = join18(home, ".pi", "agent", CONFIG_FILE_NAME);
163058
163316
  return [`${basePath}.jsonc`, `${basePath}.json`];
163059
163317
  }
163060
163318
  function resolveFirstExisting(paths) {
163061
- return paths.find((path4) => existsSync18(path4));
163319
+ return paths.find((path4) => existsSync20(path4));
163062
163320
  }
163063
163321
  function loadConfigFile2(path4, scope) {
163064
163322
  try {
163065
- const rawText = readFileSync13(path4, "utf-8");
163323
+ const rawText = readFileSync15(path4, "utf-8");
163066
163324
  const substituted = substituteConfigVariables({
163067
163325
  text: rawText,
163068
163326
  configPath: path4
@@ -163070,8 +163328,9 @@ function loadConfigFile2(path4, scope) {
163070
163328
  return {
163071
163329
  path: path4,
163072
163330
  scope,
163073
- config: import_comment_json9.parse(substituted.text),
163074
- warnings: substituted.warnings.map((warning) => `${path4}: ${warning}`)
163331
+ config: import_comment_json10.parse(substituted.text),
163332
+ warnings: substituted.warnings.map((warning) => `${path4}: ${warning}`),
163333
+ loadOutcome: substituted.warnings.length > 0 ? "substitution-failure" : "ok"
163075
163334
  };
163076
163335
  } catch (error51) {
163077
163336
  const message = error51 instanceof Error ? error51.message : String(error51);
@@ -163081,7 +163340,8 @@ function loadConfigFile2(path4, scope) {
163081
163340
  config: {},
163082
163341
  warnings: [
163083
163342
  `${path4}: failed to load config: ${message}; using defaults for this file.`
163084
- ]
163343
+ ],
163344
+ loadOutcome: typeof error51.code === "string" ? "project-file-io-error" : "project-file-parse-error"
163085
163345
  };
163086
163346
  }
163087
163347
  }
@@ -163116,7 +163376,7 @@ function mergeRawConfigs(base, override) {
163116
163376
  }
163117
163377
  return merged;
163118
163378
  }
163119
- function parsePiConfig(rawConfig) {
163379
+ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
163120
163380
  const parsed = MagicContextConfigSchema.safeParse(rawConfig);
163121
163381
  if (parsed.success) {
163122
163382
  return { config: parsed.data, warnings: [] };
@@ -163132,6 +163392,7 @@ function parsePiConfig(rawConfig) {
163132
163392
  const patched = { ...rawConfig };
163133
163393
  const warnings = [];
163134
163394
  for (const key of errorPaths) {
163395
+ recoveredTopLevelKeys.push(key);
163135
163396
  const isAgentConfig = key === "historian" || key === "dreamer" || key === "sidekick";
163136
163397
  delete patched[key];
163137
163398
  if (isAgentConfig) {
@@ -163183,19 +163444,19 @@ function loadPiConfig(opts = {}) {
163183
163444
  loadedFromPaths: loadedFiles.map((loaded) => loaded.path)
163184
163445
  };
163185
163446
  }
163186
- var import_comment_json9, CONFIG_FILE_NAME = "magic-context";
163447
+ var import_comment_json10, CONFIG_FILE_NAME = "magic-context";
163187
163448
  var init_config2 = __esm(() => {
163188
163449
  init_magic_context();
163189
163450
  init_variable();
163190
- import_comment_json9 = __toESM(require_src2(), 1);
163451
+ import_comment_json10 = __toESM(require_src2(), 1);
163191
163452
  });
163192
163453
 
163193
163454
  // src/lib/diagnostics-pi.ts
163194
163455
  import { createHash } from "node:crypto";
163195
- import { existsSync as existsSync19, readdirSync as readdirSync3, readFileSync as readFileSync14, statSync as statSync4 } from "node:fs";
163456
+ import { existsSync as existsSync21, readdirSync as readdirSync3, readFileSync as readFileSync16, statSync as statSync4 } from "node:fs";
163196
163457
  import { createRequire as createRequire5 } from "node:module";
163197
- import { homedir as homedir14, userInfo as userInfo2 } from "node:os";
163198
- import { join as join18 } from "node:path";
163458
+ import { homedir as homedir15, userInfo as userInfo2 } from "node:os";
163459
+ import { join as join19 } from "node:path";
163199
163460
  function getSelfVersion3() {
163200
163461
  const req = createRequire5(import.meta.url);
163201
163462
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -163210,7 +163471,7 @@ function getSelfVersion3() {
163210
163471
  }
163211
163472
  function fileSize2(path4) {
163212
163473
  try {
163213
- return existsSync19(path4) ? statSync4(path4).size : 0;
163474
+ return existsSync21(path4) ? statSync4(path4).size : 0;
163214
163475
  } catch {
163215
163476
  return 0;
163216
163477
  }
@@ -163226,7 +163487,7 @@ function redactSecretString(value) {
163226
163487
  return value.replace(/Bearer\s+[A-Za-z0-9._~+\-/=]+/g, "Bearer <REDACTED>").replace(/sk-[A-Za-z0-9_-]{12,}/g, "sk-<REDACTED>").replace(/api[_-]?key=([^\s&]+)/gi, "api_key=<REDACTED>").replace(/token=([^\s&]+)/gi, "token=<REDACTED>");
163227
163488
  }
163228
163489
  function sanitizeString2(value) {
163229
- const home = process.env.HOME || homedir14();
163490
+ const home = process.env.HOME || homedir15();
163230
163491
  const username = userInfo2().username;
163231
163492
  const userHash = `<USER:${currentUserHash()}>`;
163232
163493
  let sanitized = redactSecretString(value);
@@ -163260,11 +163521,11 @@ function sanitizeValue2(value, key = "") {
163260
163521
  return value;
163261
163522
  }
163262
163523
  function readJsonc3(path4) {
163263
- if (!existsSync19(path4))
163524
+ if (!existsSync21(path4))
163264
163525
  return { value: {} };
163265
163526
  try {
163266
163527
  return {
163267
- value: import_comment_json10.parse(readFileSync14(path4, "utf-8"))
163528
+ value: import_comment_json11.parse(readFileSync16(path4, "utf-8"))
163268
163529
  };
163269
163530
  } catch (error51) {
163270
163531
  return {
@@ -163274,13 +163535,13 @@ function readJsonc3(path4) {
163274
163535
  }
163275
163536
  }
163276
163537
  function getProjectConfigPath(cwd) {
163277
- return join18(cwd, ".pi", "magic-context.jsonc");
163538
+ return join19(cwd, ".pi", "magic-context.jsonc");
163278
163539
  }
163279
163540
  function readConfigDiagnostic(path4) {
163280
163541
  const parsed = readJsonc3(path4);
163281
163542
  return {
163282
163543
  path: path4,
163283
- exists: existsSync19(path4),
163544
+ exists: existsSync21(path4),
163284
163545
  ...parsed.parseError ? { parseError: parsed.parseError } : {},
163285
163546
  flags: sanitizeValue2(parsed.value)
163286
163547
  };
@@ -163297,8 +163558,8 @@ function reverseSlugToDirectory(slug) {
163297
163558
  return `/${inner.replace(/-/g, "/")}`;
163298
163559
  }
163299
163560
  function collectPiRecentSessions() {
163300
- const sessionsRoot = join18(homedir14(), ".pi", "agent", "sessions");
163301
- if (!existsSync19(sessionsRoot))
163561
+ const sessionsRoot = join19(homedir15(), ".pi", "agent", "sessions");
163562
+ if (!existsSync21(sessionsRoot))
163302
163563
  return [];
163303
163564
  try {
163304
163565
  const slugs = readdirSync3(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
@@ -163307,7 +163568,7 @@ function collectPiRecentSessions() {
163307
163568
  const directory = reverseSlugToDirectory(slug);
163308
163569
  if (!directory)
163309
163570
  continue;
163310
- const slugDir = join18(sessionsRoot, slug);
163571
+ const slugDir = join19(sessionsRoot, slug);
163311
163572
  let files;
163312
163573
  try {
163313
163574
  files = readdirSync3(slugDir).filter((name2) => name2.endsWith(".jsonl"));
@@ -163316,7 +163577,7 @@ function collectPiRecentSessions() {
163316
163577
  }
163317
163578
  for (const file2 of files) {
163318
163579
  try {
163319
- const mtime = statSync4(join18(slugDir, file2)).mtimeMs;
163580
+ const mtime = statSync4(join19(slugDir, file2)).mtimeMs;
163320
163581
  const sessionId = file2.replace(/\.jsonl$/, "");
163321
163582
  candidates.push({ sessionId, directory, mtime });
163322
163583
  } catch {}
@@ -163334,7 +163595,7 @@ function collectPiRecentSessions() {
163334
163595
  }
163335
163596
  function parseHistorianDumpMeta2(path4) {
163336
163597
  try {
163337
- const xml = readFileSync14(path4, "utf-8");
163598
+ const xml = readFileSync16(path4, "utf-8");
163338
163599
  const parsed = parseCompartmentOutput(xml);
163339
163600
  const factCountByCategory = {};
163340
163601
  for (const fact of parsed.facts) {
@@ -163367,11 +163628,11 @@ function parseHistorianDumpMeta2(path4) {
163367
163628
  }
163368
163629
  }
163369
163630
  function listDumpsInDir2(dir, limit) {
163370
- if (!existsSync19(dir))
163631
+ if (!existsSync21(dir))
163371
163632
  return { count: 0, recent: [] };
163372
163633
  try {
163373
163634
  const entries = readdirSync3(dir).filter((name2) => name2.endsWith(".xml")).map((name2) => {
163374
- const stat = statSync4(join18(dir, name2));
163635
+ const stat = statSync4(join19(dir, name2));
163375
163636
  return {
163376
163637
  name: name2,
163377
163638
  mtime: stat.mtimeMs,
@@ -163380,7 +163641,7 @@ function listDumpsInDir2(dir, limit) {
163380
163641
  }).sort((a, b2) => b2.mtime - a.mtime);
163381
163642
  const now = Date.now();
163382
163643
  const recent = entries.slice(0, limit).map((entry) => {
163383
- const meta3 = parseHistorianDumpMeta2(join18(dir, entry.name));
163644
+ const meta3 = parseHistorianDumpMeta2(join19(dir, entry.name));
163384
163645
  const summary = {
163385
163646
  name: entry.name,
163386
163647
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -163443,9 +163704,9 @@ async function collectDiagnostics2(cwd = process.cwd()) {
163443
163704
  const projectConfigPath = getProjectConfigPath(cwd);
163444
163705
  const loaded = loadPiConfig({ cwd });
163445
163706
  const storageDirPath = getMagicContextStorageDir();
163446
- const dbPath = join18(storageDirPath, "context.db");
163707
+ const dbPath = join19(storageDirPath, "context.db");
163447
163708
  const logPath = getMagicContextLogPath2("pi");
163448
- const logFileSize = existsSync19(logPath) ? statSync4(logPath).size : 0;
163709
+ const logFileSize = existsSync21(logPath) ? statSync4(logPath).size : 0;
163449
163710
  const otherPiExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
163450
163711
  const recentSessions = collectPiRecentSessions();
163451
163712
  const historianDumps = collectPiHistorianDumps(recentSessions);
@@ -163460,7 +163721,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
163460
163721
  piVersion: pi ? getPiVersion(pi.path) : null,
163461
163722
  settings: {
163462
163723
  path: settingsPath,
163463
- exists: existsSync19(settingsPath),
163724
+ exists: existsSync21(settingsPath),
163464
163725
  ...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
163465
163726
  hasMagicContextPackage: hasPiMagicContextPackage(packages),
163466
163727
  packages: sanitizeValue2(packages)
@@ -163476,7 +163737,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
163476
163737
  loadWarnings: loaded.warnings.map(sanitizeString2),
163477
163738
  storageDir: {
163478
163739
  path: storageDirPath,
163479
- exists: existsSync19(storageDirPath),
163740
+ exists: existsSync21(storageDirPath),
163480
163741
  contextDbSizeBytes: fileSize2(dbPath)
163481
163742
  },
163482
163743
  conflicts: {
@@ -163485,7 +163746,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
163485
163746
  },
163486
163747
  logFile: {
163487
163748
  path: logPath,
163488
- exists: existsSync19(logPath),
163749
+ exists: existsSync21(logPath),
163489
163750
  sizeKb: Math.round(logFileSize / 1024)
163490
163751
  },
163491
163752
  recentSessions,
@@ -163566,7 +163827,7 @@ function renderDiagnosticsMarkdown2(report) {
163566
163827
  ].join(`
163567
163828
  `);
163568
163829
  }
163569
- var import_comment_json10;
163830
+ var import_comment_json11;
163570
163831
  var init_diagnostics_pi = __esm(() => {
163571
163832
  init_compartment_parser();
163572
163833
  init_data_path();
@@ -163574,12 +163835,12 @@ var init_diagnostics_pi = __esm(() => {
163574
163835
  init_paths();
163575
163836
  init_pi_helpers();
163576
163837
  init_pi_package_entry();
163577
- import_comment_json10 = __toESM(require_src2(), 1);
163838
+ import_comment_json11 = __toESM(require_src2(), 1);
163578
163839
  });
163579
163840
 
163580
163841
  // src/lib/logs-pi.ts
163581
- import { readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "node:fs";
163582
- import { join as join19 } from "node:path";
163842
+ import { readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "node:fs";
163843
+ import { join as join20 } from "node:path";
163583
163844
  function sanitizeLogContent2(content) {
163584
163845
  return sanitizeString2(content);
163585
163846
  }
@@ -163608,7 +163869,7 @@ function filterLogLinesBySession2(lines, sessionId) {
163608
163869
  }
163609
163870
  async function bundleIssueReport2(report, description, title, options = {}) {
163610
163871
  const LOG_TAIL_LINES = 400;
163611
- const allLogLines = report.logFile.exists ? readFileSync15(report.logFile.path, "utf-8").split(/\r?\n/) : [];
163872
+ const allLogLines = report.logFile.exists ? readFileSync17(report.logFile.path, "utf-8").split(/\r?\n/) : [];
163612
163873
  const logLines = filterLogLinesBySession2(allLogLines, options.sessionFilter ?? null);
163613
163874
  const recentLog = sanitizeLogContent2(logLines.slice(-LOG_TAIL_LINES).join(`
163614
163875
  `)).trim();
@@ -163635,7 +163896,7 @@ async function bundleIssueReport2(report, description, title, options = {}) {
163635
163896
  ].join(`
163636
163897
  `);
163637
163898
  const cwd = options.cwd ?? process.cwd();
163638
- const path4 = join19(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
163899
+ const path4 = join20(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
163639
163900
  writeFileSync11(path4, `${bodyMarkdown}
163640
163901
  `);
163641
163902
  return { path: path4, bodyMarkdown };
@@ -163647,17 +163908,17 @@ var init_logs_pi = __esm(() => {
163647
163908
  // src/commands/doctor-pi.ts
163648
163909
  import { execFileSync as execFileSync4, spawnSync as spawnSync3 } from "node:child_process";
163649
163910
  import {
163650
- existsSync as existsSync20,
163911
+ existsSync as existsSync22,
163651
163912
  mkdirSync as mkdirSync8,
163652
163913
  readdirSync as readdirSync4,
163653
- readFileSync as readFileSync16,
163914
+ readFileSync as readFileSync18,
163654
163915
  rmSync as rmSync2,
163655
163916
  statSync as statSync5,
163656
163917
  writeFileSync as writeFileSync12
163657
163918
  } from "node:fs";
163658
163919
  import { createRequire as createRequire6 } from "node:module";
163659
- import { homedir as homedir15 } from "node:os";
163660
- import { dirname as dirname9, join as join20 } from "node:path";
163920
+ import { homedir as homedir16 } from "node:os";
163921
+ import { dirname as dirname9, join as join21 } from "node:path";
163661
163922
  function depsFrom(options) {
163662
163923
  return {
163663
163924
  ...DEFAULT_DEPS,
@@ -163744,7 +164005,7 @@ function summarize(results) {
163744
164005
  function readJsonc4(path4) {
163745
164006
  try {
163746
164007
  return {
163747
- value: import_comment_json11.parse(readFileSync16(path4, "utf-8"))
164008
+ value: import_comment_json12.parse(readFileSync18(path4, "utf-8"))
163748
164009
  };
163749
164010
  } catch (error51) {
163750
164011
  return {
@@ -163757,18 +164018,18 @@ function packagesFrom(settings) {
163757
164018
  return Array.isArray(settings.packages) ? settings.packages : [];
163758
164019
  }
163759
164020
  function projectConfigPath(cwd) {
163760
- return join20(cwd, ".pi", "magic-context.jsonc");
164021
+ return join21(cwd, ".pi", "magic-context.jsonc");
163761
164022
  }
163762
164023
  function readConfigForEmbedding(path4) {
163763
- if (!existsSync20(path4))
164024
+ if (!existsSync22(path4))
163764
164025
  return null;
163765
164026
  try {
163766
- const rawText = readFileSync16(path4, "utf-8");
164027
+ const rawText = readFileSync18(path4, "utf-8");
163767
164028
  const substituted = substituteConfigVariables({
163768
164029
  text: rawText,
163769
164030
  configPath: path4
163770
164031
  });
163771
- return import_comment_json11.parse(substituted.text);
164032
+ return import_comment_json12.parse(substituted.text);
163772
164033
  } catch {
163773
164034
  return null;
163774
164035
  }
@@ -163821,20 +164082,20 @@ function countTable(db, table) {
163821
164082
  }
163822
164083
  }
163823
164084
  function cacheRoots() {
163824
- const home = homedir15();
163825
- const cacheHome = process.env.XDG_CACHE_HOME || join20(home, ".cache");
164085
+ const home = homedir16();
164086
+ const cacheHome = process.env.XDG_CACHE_HOME || join21(home, ".cache");
163826
164087
  return [
163827
- join20(home, ".pi", "cache", "extensions"),
163828
- join20(home, ".pi", "cache", "packages"),
163829
- join20(cacheHome, "pi", "extensions"),
163830
- join20(cacheHome, "pi", "packages"),
163831
- join20(getPiAgentConfigDir(), "cache", "extensions")
164088
+ join21(home, ".pi", "cache", "extensions"),
164089
+ join21(home, ".pi", "cache", "packages"),
164090
+ join21(cacheHome, "pi", "extensions"),
164091
+ join21(cacheHome, "pi", "packages"),
164092
+ join21(getPiAgentConfigDir(), "cache", "extensions")
163832
164093
  ];
163833
164094
  }
163834
164095
  function findPiMagicContextCacheDirs(self, force = false) {
163835
164096
  const found = new Map;
163836
164097
  const visit = (path4, depth) => {
163837
- if (depth < 0 || !existsSync20(path4))
164098
+ if (depth < 0 || !existsSync22(path4))
163838
164099
  return;
163839
164100
  let stat;
163840
164101
  try {
@@ -163844,10 +164105,10 @@ function findPiMagicContextCacheDirs(self, force = false) {
163844
164105
  }
163845
164106
  if (!stat.isDirectory())
163846
164107
  return;
163847
- const packageJson = join20(path4, "package.json");
163848
- if (existsSync20(packageJson)) {
164108
+ const packageJson = join21(path4, "package.json");
164109
+ if (existsSync22(packageJson)) {
163849
164110
  try {
163850
- const pkg = JSON.parse(readFileSync16(packageJson, "utf-8"));
164111
+ const pkg = JSON.parse(readFileSync18(packageJson, "utf-8"));
163851
164112
  const name2 = typeof pkg.name === "string" ? pkg.name : "";
163852
164113
  const version2 = typeof pkg.version === "string" ? pkg.version : undefined;
163853
164114
  if (name2 === PACKAGE_NAME || path4.includes("pi-magic-context")) {
@@ -163866,7 +164127,7 @@ function findPiMagicContextCacheDirs(self, force = false) {
163866
164127
  return;
163867
164128
  }
163868
164129
  for (const entry of entries)
163869
- visit(join20(path4, entry), depth - 1);
164130
+ visit(join21(path4, entry), depth - 1);
163870
164131
  };
163871
164132
  for (const root of cacheRoots())
163872
164133
  visit(root, 5);
@@ -163888,7 +164149,7 @@ async function runHealthChecks(options) {
163888
164149
  add(results, "pass", version2 ? `Pi ${version2} detected at ${pi.path}` : `Pi detected at ${pi.path}`);
163889
164150
  const compare = compareSemver(version2, MIN_PI_VERSION);
163890
164151
  if (compare !== null && compare < 0) {
163891
- add(results, "fail", `Pi ${version2} is older than required ${MIN_PI_VERSION}. Subagents (historian/dreamer/sidekick) use the long-form \`--extension\` flag introduced in Pi 0.71.0; older versions hard-fail with "Unknown option". Run \`pi update\` (or \`npm install -g @mariozechner/pi-coding-agent@latest\`).`);
164152
+ add(results, "fail", `Pi ${version2} is older than required ${MIN_PI_VERSION}. Subagents (historian/dreamer/sidekick) use the long-form \`--extension\` flag introduced in Pi 0.71.0; older versions hard-fail with "Unknown option". Run \`pi update\` (or \`npm install -g @earendil-works/pi-coding-agent@latest\`).`);
163892
164153
  } else if (version2) {
163893
164154
  add(results, "pass", `Pi version meets minimum ${MIN_PI_VERSION} requirement`);
163894
164155
  }
@@ -163903,7 +164164,7 @@ async function runHealthChecks(options) {
163903
164164
  }
163904
164165
  const settingsPath = getPiUserExtensionsPath();
163905
164166
  let packages = [];
163906
- if (!existsSync20(settingsPath)) {
164167
+ if (!existsSync22(settingsPath)) {
163907
164168
  add(results, "warn", `Pi settings not found at ${settingsPath}`);
163908
164169
  repairPlan.addPackageEntry = true;
163909
164170
  } else {
@@ -163927,7 +164188,7 @@ async function runHealthChecks(options) {
163927
164188
  ["user", userConfigPath, true],
163928
164189
  ["project", projectPath, false]
163929
164190
  ]) {
163930
- if (!existsSync20(path4)) {
164191
+ if (!existsSync22(path4)) {
163931
164192
  if (required2) {
163932
164193
  add(results, "warn", `No ${label} magic-context.jsonc found at ${path4}`);
163933
164194
  repairPlan.writeUserConfig = true;
@@ -163960,8 +164221,8 @@ async function runHealthChecks(options) {
163960
164221
  add(results, "pass", `historian.model "${historianModel}" has thinking_level "${historianThinkingLevel}" configured`);
163961
164222
  }
163962
164223
  const storageDir = getMagicContextStorageDir();
163963
- const dbPath = join20(storageDir, "context.db");
163964
- const existedBeforeOpen = existsSync20(dbPath);
164224
+ const dbPath = join21(storageDir, "context.db");
164225
+ const existedBeforeOpen = existsSync22(dbPath);
163965
164226
  if (existedBeforeOpen)
163966
164227
  add(results, "pass", `Shared context DB exists at ${dbPath}`);
163967
164228
  else
@@ -164038,10 +164299,10 @@ async function runHealthChecks(options) {
164038
164299
  add(results, "pass", "Pi extension cache clean (no stale cached package found)");
164039
164300
  }
164040
164301
  const logPath = getMagicContextLogPath2("pi");
164041
- if (existsSync20(logPath)) {
164302
+ if (existsSync22(logPath)) {
164042
164303
  const stat = statSync5(logPath);
164043
164304
  const sizeKb = (stat.size / 1024).toFixed(0);
164044
- const lines = readFileSync16(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
164305
+ const lines = readFileSync18(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
164045
164306
  add(results, "info", `Log file: ${logPath} (${sizeKb} KB)`);
164046
164307
  add(results, "info", `Last plugin log line: ${lines.at(-1) ?? "<empty log>"}`);
164047
164308
  } else {
@@ -164080,7 +164341,7 @@ function writeDefaultMagicContextConfig(path4) {
164080
164341
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
164081
164342
  ...MagicContextConfigSchema.parse({})
164082
164343
  };
164083
- writeFileSync12(path4, `${import_comment_json11.stringify(config2, null, 2)}
164344
+ writeFileSync12(path4, `${import_comment_json12.stringify(config2, null, 2)}
164084
164345
  `);
164085
164346
  }
164086
164347
  function repair(plan, prompts) {
@@ -164097,7 +164358,7 @@ function repair(plan, prompts) {
164097
164358
  }
164098
164359
  if (plan.writeUserConfig) {
164099
164360
  const configPath = getPiUserConfigPath();
164100
- if (!existsSync20(configPath)) {
164361
+ if (!existsSync22(configPath)) {
164101
164362
  try {
164102
164363
  writeDefaultMagicContextConfig(configPath);
164103
164364
  prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
@@ -164239,7 +164500,7 @@ function parseDoctorArgs(args) {
164239
164500
  function doctor(args = []) {
164240
164501
  return runDoctor2(parseDoctorArgs(args));
164241
164502
  }
164242
- var import_comment_json11, PACKAGE_NAME = "@cortexkit/pi-magic-context", MIN_PI_VERSION = "0.71.0", ROW_COUNT_TABLES, DEFAULT_DEPS;
164503
+ var import_comment_json12, PACKAGE_NAME = "@cortexkit/pi-magic-context", MIN_PI_VERSION = "0.74.0", ROW_COUNT_TABLES, DEFAULT_DEPS;
164243
164504
  var init_doctor_pi = __esm(async () => {
164244
164505
  init_magic_context();
164245
164506
  init_variable();
@@ -164253,7 +164514,7 @@ var init_doctor_pi = __esm(async () => {
164253
164514
  init_prompts();
164254
164515
  init_setup_pi();
164255
164516
  await init_storage();
164256
- import_comment_json11 = __toESM(require_src2(), 1);
164517
+ import_comment_json12 = __toESM(require_src2(), 1);
164257
164518
  ROW_COUNT_TABLES = ["tags", "compartments", "memories", "notes", "dream_runs"];
164258
164519
  DEFAULT_DEPS = {
164259
164520
  prompts: promptIO,
@@ -164276,7 +164537,7 @@ var exports_doctor = {};
164276
164537
  __export(exports_doctor, {
164277
164538
  runDoctor: () => runDoctor3
164278
164539
  });
164279
- import { existsSync as existsSync21, rmSync as rmSync3 } from "node:fs";
164540
+ import { existsSync as existsSync23, rmSync as rmSync3 } from "node:fs";
164280
164541
  async function runDoctor3(options) {
164281
164542
  if (options.clear)
164282
164543
  return runClear();
@@ -164360,7 +164621,7 @@ async function runClear() {
164360
164621
  const s = spinner();
164361
164622
  s.start(`Clearing ${item.path}`);
164362
164623
  try {
164363
- if (existsSync21(item.path)) {
164624
+ if (existsSync23(item.path)) {
164364
164625
  rmSync3(item.path, { recursive: true, force: true });
164365
164626
  }
164366
164627
  s.stop(`Cleared ${item.path}`);