@cortexkit/magic-context 0.18.0 → 0.19.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 +996 -543
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7805,26 +7805,70 @@ var require_src2 = __commonJS((exports, module) => {
7805
7805
  };
7806
7806
  });
7807
7807
 
7808
+ // ../plugin/src/shared/harness.ts
7809
+ function getHarness() {
7810
+ return currentHarness;
7811
+ }
7812
+ var currentHarness = "opencode";
7813
+
7814
+ // ../plugin/src/shared/data-path.ts
7815
+ import * as os from "node:os";
7816
+ import * as path from "node:path";
7817
+ function getDataDir() {
7818
+ return process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share");
7819
+ }
7820
+ function getMagicContextTempDir(harness = getHarness()) {
7821
+ return path.join(os.tmpdir(), harness, "magic-context");
7822
+ }
7823
+ function getMagicContextLogPath(harness = getHarness()) {
7824
+ return path.join(getMagicContextTempDir(harness), "magic-context.log");
7825
+ }
7826
+ function getMagicContextHistorianDir(harness = getHarness()) {
7827
+ return path.join(getMagicContextTempDir(harness), "historian");
7828
+ }
7829
+ function getProjectMagicContextDir(directory) {
7830
+ return path.join(directory, ".opencode", "magic-context");
7831
+ }
7832
+ function getProjectMagicContextHistorianDir(directory) {
7833
+ return path.join(getProjectMagicContextDir(directory), "historian");
7834
+ }
7835
+ function getOpenCodeStorageDir() {
7836
+ return path.join(getDataDir(), "opencode", "storage");
7837
+ }
7838
+ function getMagicContextStorageDir() {
7839
+ return path.join(getDataDir(), "cortexkit", "magic-context");
7840
+ }
7841
+ function getLegacyOpenCodeMagicContextStorageDir() {
7842
+ return path.join(getOpenCodeStorageDir(), "plugin", "magic-context");
7843
+ }
7844
+ function getCacheDir() {
7845
+ return process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), ".cache");
7846
+ }
7847
+ function getOpenCodeCacheDir() {
7848
+ return path.join(getCacheDir(), "opencode");
7849
+ }
7850
+ var init_data_path = () => {};
7851
+
7808
7852
  // src/lib/paths.ts
7809
7853
  import { existsSync, readdirSync, statSync } from "node:fs";
7810
- import { homedir, tmpdir } from "node:os";
7811
- import { join } from "node:path";
7854
+ import { homedir as homedir2 } from "node:os";
7855
+ import { join as join2 } from "node:path";
7812
7856
  function getOpenCodeConfigDir() {
7813
7857
  const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
7814
7858
  if (envDir)
7815
7859
  return envDir;
7816
7860
  if (process.platform === "win32") {
7817
- return join(homedir(), ".config", "opencode");
7861
+ return join2(homedir2(), ".config", "opencode");
7818
7862
  }
7819
- const xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
7820
- return join(xdgConfig, "opencode");
7863
+ const xdgConfig = process.env.XDG_CONFIG_HOME || join2(homedir2(), ".config");
7864
+ return join2(xdgConfig, "opencode");
7821
7865
  }
7822
7866
  function findOmoConfig(configDir) {
7823
7867
  const locations = [
7824
- join(configDir, "oh-my-openagent.jsonc"),
7825
- join(configDir, "oh-my-openagent.json"),
7826
- join(configDir, "oh-my-opencode.jsonc"),
7827
- join(configDir, "oh-my-opencode.json")
7868
+ join2(configDir, "oh-my-openagent.jsonc"),
7869
+ join2(configDir, "oh-my-openagent.json"),
7870
+ join2(configDir, "oh-my-opencode.jsonc"),
7871
+ join2(configDir, "oh-my-opencode.json")
7828
7872
  ];
7829
7873
  for (const loc of locations) {
7830
7874
  if (existsSync(loc))
@@ -7838,8 +7882,8 @@ function detectConfigPaths() {
7838
7882
  let opencodeConfigFormat;
7839
7883
  let tuiConfig;
7840
7884
  let tuiConfigFormat;
7841
- const jsoncPath = join(configDir, "opencode.jsonc");
7842
- const jsonPath = join(configDir, "opencode.json");
7885
+ const jsoncPath = join2(configDir, "opencode.jsonc");
7886
+ const jsonPath = join2(configDir, "opencode.json");
7843
7887
  if (existsSync(jsoncPath)) {
7844
7888
  opencodeConfig = jsoncPath;
7845
7889
  opencodeConfigFormat = "jsonc";
@@ -7850,8 +7894,8 @@ function detectConfigPaths() {
7850
7894
  opencodeConfig = jsonPath;
7851
7895
  opencodeConfigFormat = "none";
7852
7896
  }
7853
- const tuiJsoncPath = join(configDir, "tui.jsonc");
7854
- const tuiJsonPath = join(configDir, "tui.json");
7897
+ const tuiJsoncPath = join2(configDir, "tui.jsonc");
7898
+ const tuiJsonPath = join2(configDir, "tui.json");
7855
7899
  if (existsSync(tuiJsoncPath)) {
7856
7900
  tuiConfig = tuiJsoncPath;
7857
7901
  tuiConfigFormat = "jsonc";
@@ -7866,7 +7910,7 @@ function detectConfigPaths() {
7866
7910
  configDir,
7867
7911
  opencodeConfig,
7868
7912
  opencodeConfigFormat,
7869
- magicContextConfig: join(configDir, "magic-context.jsonc"),
7913
+ magicContextConfig: join2(configDir, "magic-context.jsonc"),
7870
7914
  omoConfig: findOmoConfig(configDir),
7871
7915
  tuiConfig,
7872
7916
  tuiConfigFormat
@@ -7876,33 +7920,36 @@ function getPiAgentConfigDir() {
7876
7920
  const envDir = process.env.PI_CODING_AGENT_DIR?.trim();
7877
7921
  if (envDir)
7878
7922
  return envDir;
7879
- return join(homedir(), ".pi", "agent");
7923
+ return join2(homedir2(), ".pi", "agent");
7880
7924
  }
7881
7925
  function getPiUserConfigPath() {
7882
- return join(getPiAgentConfigDir(), "magic-context.jsonc");
7926
+ return join2(getPiAgentConfigDir(), "magic-context.jsonc");
7883
7927
  }
7884
7928
  function getPiUserExtensionsPath() {
7885
- return join(getPiAgentConfigDir(), "settings.json");
7929
+ return join2(getPiAgentConfigDir(), "settings.json");
7930
+ }
7931
+ function getMagicContextLogPath2(harness) {
7932
+ return getMagicContextLogPath(harness);
7886
7933
  }
7887
- function getMagicContextLogPath() {
7888
- return join(tmpdir(), "magic-context.log");
7934
+ function getMagicContextHistorianDir2(harness) {
7935
+ return getMagicContextHistorianDir(harness);
7889
7936
  }
7890
7937
  function getOpenCodePluginCacheDir() {
7891
- const xdg = process.env.XDG_CACHE_HOME || join(homedir(), ".cache");
7892
- return join(xdg, "opencode", "packages");
7938
+ const xdg = process.env.XDG_CACHE_HOME || join2(homedir2(), ".cache");
7939
+ return join2(xdg, "opencode", "packages");
7893
7940
  }
7894
- function isDir(path) {
7941
+ function isDir(path2) {
7895
7942
  try {
7896
- return statSync(path).isDirectory();
7943
+ return statSync(path2).isDirectory();
7897
7944
  } catch {
7898
7945
  return false;
7899
7946
  }
7900
7947
  }
7901
- function dirSizeBytes(path) {
7902
- if (!isDir(path))
7948
+ function dirSizeBytes(path2) {
7949
+ if (!isDir(path2))
7903
7950
  return 0;
7904
7951
  let total = 0;
7905
- const stack = [path];
7952
+ const stack = [path2];
7906
7953
  while (stack.length > 0) {
7907
7954
  const cur = stack.pop();
7908
7955
  if (cur === undefined)
@@ -7910,7 +7957,7 @@ function dirSizeBytes(path) {
7910
7957
  try {
7911
7958
  const entries = readdirSync(cur, { withFileTypes: true });
7912
7959
  for (const entry of entries) {
7913
- const child = join(cur, entry.name);
7960
+ const child = join2(cur, entry.name);
7914
7961
  if (entry.isDirectory()) {
7915
7962
  stack.push(child);
7916
7963
  } else if (entry.isFile()) {
@@ -7923,13 +7970,15 @@ function dirSizeBytes(path) {
7923
7970
  }
7924
7971
  return total;
7925
7972
  }
7926
- var init_paths = () => {};
7973
+ var init_paths = __esm(() => {
7974
+ init_data_path();
7975
+ });
7927
7976
 
7928
7977
  // src/adapters/opencode.ts
7929
7978
  import { execFileSync } from "node:child_process";
7930
7979
  import { existsSync as existsSync2, readFileSync, writeFileSync } from "node:fs";
7931
- import { homedir as homedir2 } from "node:os";
7932
- import { dirname, join as join2 } from "node:path";
7980
+ import { homedir as homedir3 } from "node:os";
7981
+ import { dirname, join as join3 } from "node:path";
7933
7982
 
7934
7983
  class OpenCodeAdapter {
7935
7984
  kind = "opencode";
@@ -7937,7 +7986,7 @@ class OpenCodeAdapter {
7937
7986
  pluginPackageName = PLUGIN_NAME;
7938
7987
  isInstalled() {
7939
7988
  const isWindows = process.platform === "win32";
7940
- const stockBin = isWindows ? join2(homedir2(), ".opencode", "bin", "opencode.exe") : join2(homedir2(), ".opencode", "bin", "opencode");
7989
+ const stockBin = isWindows ? join3(homedir3(), ".opencode", "bin", "opencode.exe") : join3(homedir3(), ".opencode", "bin", "opencode");
7941
7990
  if (existsSync2(stockBin))
7942
7991
  return true;
7943
7992
  const probe = isWindows ? { cmd: "where", args: ["opencode"] } : { cmd: "command", args: ["-v", "opencode"] };
@@ -8112,15 +8161,15 @@ class OpenCodeAdapter {
8112
8161
  return "Install OpenCode: curl -fsSL https://opencode.ai/install | bash";
8113
8162
  }
8114
8163
  getPluginCacheInfo() {
8115
- const path = getOpenCodePluginCacheDir();
8164
+ const path2 = getOpenCodePluginCacheDir();
8116
8165
  return {
8117
- path,
8118
- exists: existsSync2(path),
8119
- sizeBytes: dirSizeBytes(path)
8166
+ path: path2,
8167
+ exists: existsSync2(path2),
8168
+ sizeBytes: dirSizeBytes(path2)
8120
8169
  };
8121
8170
  }
8122
8171
  getLogPath() {
8123
- return getMagicContextLogPath();
8172
+ return getMagicContextLogPath2("opencode");
8124
8173
  }
8125
8174
  getInstalledPluginVersion() {
8126
8175
  const cacheDir = getOpenCodePluginCacheDir();
@@ -8185,8 +8234,8 @@ var init_opencode = __esm(() => {
8185
8234
  // src/lib/pi-helpers.ts
8186
8235
  import { execFileSync as execFileSync2, spawnSync } from "node:child_process";
8187
8236
  import { existsSync as existsSync3 } from "node:fs";
8188
- import { homedir as homedir3 } from "node:os";
8189
- import { join as join3 } from "node:path";
8237
+ import { homedir as homedir4 } from "node:os";
8238
+ import { join as join4 } from "node:path";
8190
8239
  function getStaticModels() {
8191
8240
  return [...STATIC_MODELS];
8192
8241
  }
@@ -8208,7 +8257,7 @@ function detectPiBinary() {
8208
8257
  if (first)
8209
8258
  return { path: first, source: "path" };
8210
8259
  }
8211
- const homeCandidate = process.platform === "win32" ? join3(homedir3(), ".pi", "bin", "pi.cmd") : join3(homedir3(), ".pi", "bin", "pi");
8260
+ const homeCandidate = process.platform === "win32" ? join4(homedir4(), ".pi", "bin", "pi.cmd") : join4(homedir4(), ".pi", "bin", "pi");
8212
8261
  if (existsSync3(homeCandidate))
8213
8262
  return { path: homeCandidate, source: "home" };
8214
8263
  return null;
@@ -8463,7 +8512,7 @@ class PiAdapter {
8463
8512
  return { path: null, exists: false, sizeBytes: 0 };
8464
8513
  }
8465
8514
  getLogPath() {
8466
- return getMagicContextLogPath();
8515
+ return getMagicContextLogPath2("pi");
8467
8516
  }
8468
8517
  getInstalledPluginVersion() {
8469
8518
  const piBin = detectPiBinary();
@@ -10327,17 +10376,17 @@ function detectConfigFile(basePath) {
10327
10376
  var init_jsonc_parser = () => {};
10328
10377
 
10329
10378
  // ../plugin/src/shared/opencode-config-dir.ts
10330
- import { homedir as homedir4 } from "node:os";
10331
- import { join as join4, resolve } from "node:path";
10379
+ import { homedir as homedir5 } from "node:os";
10380
+ import { join as join5, resolve } from "node:path";
10332
10381
  function getCliConfigDir() {
10333
10382
  const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
10334
10383
  if (envConfigDir) {
10335
10384
  return resolve(envConfigDir);
10336
10385
  }
10337
10386
  if (process.platform === "win32") {
10338
- return join4(homedir4(), ".config", "opencode");
10387
+ return join5(homedir5(), ".config", "opencode");
10339
10388
  }
10340
- return join4(process.env.XDG_CONFIG_HOME || join4(homedir4(), ".config"), "opencode");
10389
+ return join5(process.env.XDG_CONFIG_HOME || join5(homedir5(), ".config"), "opencode");
10341
10390
  }
10342
10391
  function getOpenCodeConfigDir2(_options) {
10343
10392
  return getCliConfigDir();
@@ -10346,16 +10395,16 @@ function getOpenCodeConfigPaths(options) {
10346
10395
  const configDir = getOpenCodeConfigDir2(options);
10347
10396
  return {
10348
10397
  configDir,
10349
- configJson: join4(configDir, "opencode.json"),
10350
- configJsonc: join4(configDir, "opencode.jsonc"),
10351
- packageJson: join4(configDir, "package.json"),
10352
- omoConfig: join4(configDir, "magic-context.jsonc")
10398
+ configJson: join5(configDir, "opencode.json"),
10399
+ configJsonc: join5(configDir, "opencode.jsonc"),
10400
+ packageJson: join5(configDir, "package.json"),
10401
+ omoConfig: join5(configDir, "magic-context.jsonc")
10353
10402
  };
10354
10403
  }
10355
10404
  var init_opencode_config_dir = () => {};
10356
10405
 
10357
10406
  // ../plugin/src/shared/conflict-detector.ts
10358
- import { join as join5 } from "node:path";
10407
+ import { join as join6 } from "node:path";
10359
10408
  function detectConflicts(directory) {
10360
10409
  const conflicts = {
10361
10410
  compactionAuto: false,
@@ -10412,8 +10461,8 @@ function checkCompaction(directory) {
10412
10461
  return { auto: true, prune: false };
10413
10462
  }
10414
10463
  function readProjectCompaction(directory) {
10415
- const dotOcJsonc = join5(directory, ".opencode", "opencode.jsonc");
10416
- const dotOcJson = join5(directory, ".opencode", "opencode.json");
10464
+ const dotOcJsonc = join6(directory, ".opencode", "opencode.jsonc");
10465
+ const dotOcJson = join6(directory, ".opencode", "opencode.json");
10417
10466
  const dotOcConfig = readJsoncFile(dotOcJsonc) ?? readJsoncFile(dotOcJson);
10418
10467
  if (dotOcConfig?.compaction) {
10419
10468
  const c2 = dotOcConfig.compaction;
@@ -10421,8 +10470,8 @@ function readProjectCompaction(directory) {
10421
10470
  return { auto: c2.auto === true, prune: c2.prune === true, resolved: true };
10422
10471
  }
10423
10472
  }
10424
- const rootJsonc = join5(directory, "opencode.jsonc");
10425
- const rootJson = join5(directory, "opencode.json");
10473
+ const rootJsonc = join6(directory, "opencode.jsonc");
10474
+ const rootJson = join6(directory, "opencode.json");
10426
10475
  const rootConfig = readJsoncFile(rootJsonc) ?? readJsoncFile(rootJson);
10427
10476
  if (rootConfig?.compaction) {
10428
10477
  const c2 = rootConfig.compaction;
@@ -10476,10 +10525,10 @@ function collectPluginEntries(directory) {
10476
10525
  }
10477
10526
  };
10478
10527
  for (const configPath of [
10479
- join5(directory, ".opencode", "opencode.jsonc"),
10480
- join5(directory, ".opencode", "opencode.json"),
10481
- join5(directory, "opencode.jsonc"),
10482
- join5(directory, "opencode.json")
10528
+ join6(directory, ".opencode", "opencode.jsonc"),
10529
+ join6(directory, ".opencode", "opencode.json"),
10530
+ join6(directory, "opencode.jsonc"),
10531
+ join6(directory, "opencode.json")
10483
10532
  ]) {
10484
10533
  const config = readJsoncFile(configPath);
10485
10534
  pushFrom(config?.plugin);
@@ -10520,7 +10569,7 @@ function readOmoDisabledHooks(directory) {
10520
10569
  try {
10521
10570
  const paths = getOpenCodeConfigPaths({ binary: "opencode" });
10522
10571
  for (const name of configNames) {
10523
- const configPath = join5(paths.configDir, name);
10572
+ const configPath = join6(paths.configDir, name);
10524
10573
  const config = readJsoncFile(configPath);
10525
10574
  if (config?.disabled_hooks) {
10526
10575
  for (const hook of config.disabled_hooks) {
@@ -10530,7 +10579,7 @@ function readOmoDisabledHooks(directory) {
10530
10579
  }
10531
10580
  } catch {}
10532
10581
  for (const name of configNames) {
10533
- const config = readJsoncFile(join5(directory, name));
10582
+ const config = readJsoncFile(join6(directory, name));
10534
10583
  if (config?.disabled_hooks) {
10535
10584
  for (const hook of config.disabled_hooks) {
10536
10585
  disabled.add(hook);
@@ -10548,11 +10597,8 @@ var init_conflict_detector = __esm(() => {
10548
10597
  });
10549
10598
 
10550
10599
  // ../plugin/src/shared/conflict-fixer.ts
10551
- import { existsSync as existsSync6, mkdirSync, writeFileSync as writeFileSync3 } from "node:fs";
10552
- import { dirname as dirname3, join as join6 } from "node:path";
10553
- function ensureParentDir(filePath) {
10554
- mkdirSync(dirname3(filePath), { recursive: true });
10555
- }
10600
+ import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
10601
+ import { join as join7 } from "node:path";
10556
10602
  function isRecord(value) {
10557
10603
  return typeof value === "object" && value !== null && !Array.isArray(value);
10558
10604
  }
@@ -10561,13 +10607,17 @@ function asStringArray(value) {
10561
10607
  }
10562
10608
  function readConfig(filePath) {
10563
10609
  if (!existsSync6(filePath)) {
10564
- return {};
10610
+ return null;
10611
+ }
10612
+ try {
10613
+ const parsed = import_comment_json3.parse(readFileSync4(filePath, "utf-8"));
10614
+ return isRecord(parsed) ? parsed : null;
10615
+ } catch {
10616
+ return null;
10565
10617
  }
10566
- return readJsoncFile(filePath);
10567
10618
  }
10568
10619
  function writeConfig(filePath, config) {
10569
- ensureParentDir(filePath);
10570
- writeFileSync3(filePath, `${JSON.stringify(config, null, 2)}
10620
+ writeFileSync3(filePath, `${import_comment_json3.stringify(config, null, 2)}
10571
10621
  `);
10572
10622
  }
10573
10623
  function resolveUserOpenCodeConfigPath() {
@@ -10579,12 +10629,14 @@ function resolveUserOpenCodeConfigPath() {
10579
10629
  function collectOpenCodeConfigPaths(directory) {
10580
10630
  const paths = new Set;
10581
10631
  const userConfig = resolveUserOpenCodeConfigPath();
10582
- paths.add(userConfig);
10632
+ if (existsSync6(userConfig)) {
10633
+ paths.add(userConfig);
10634
+ }
10583
10635
  for (const filePath of [
10584
- join6(directory, ".opencode", "opencode.jsonc"),
10585
- join6(directory, ".opencode", "opencode.json"),
10586
- join6(directory, "opencode.jsonc"),
10587
- join6(directory, "opencode.json")
10636
+ join7(directory, ".opencode", "opencode.jsonc"),
10637
+ join7(directory, ".opencode", "opencode.json"),
10638
+ join7(directory, "opencode.jsonc"),
10639
+ join7(directory, "opencode.json")
10588
10640
  ]) {
10589
10641
  if (existsSync6(filePath)) {
10590
10642
  paths.add(filePath);
@@ -10596,8 +10648,8 @@ function collectOmoConfigPaths(directory) {
10596
10648
  const paths = new Set;
10597
10649
  const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
10598
10650
  for (const fileName of OMO_CONFIG_NAMES) {
10599
- const userPath = join6(configDir, fileName);
10600
- const projectPath = join6(directory, fileName);
10651
+ const userPath = join7(configDir, fileName);
10652
+ const projectPath = join7(directory, fileName);
10601
10653
  if (existsSync6(userPath)) {
10602
10654
  paths.add(userPath);
10603
10655
  }
@@ -10605,11 +10657,15 @@ function collectOmoConfigPaths(directory) {
10605
10657
  paths.add(projectPath);
10606
10658
  }
10607
10659
  }
10608
- if (paths.size === 0) {
10609
- paths.add(join6(configDir, "oh-my-openagent.json"));
10610
- }
10611
10660
  return [...paths];
10612
10661
  }
10662
+ function filterDcpPluginEntries(entries) {
10663
+ const plugins = entries.filter((entry) => {
10664
+ const name = extractPluginName(entry);
10665
+ return name ? !matchesPackageName(name, DCP_PACKAGE_NAMES) : true;
10666
+ });
10667
+ return { plugins, removed: plugins.length !== entries.length };
10668
+ }
10613
10669
  function fixConflicts(directory, conflicts) {
10614
10670
  const actions = [];
10615
10671
  let updatedCompaction = false;
@@ -10623,7 +10679,7 @@ function fixConflicts(directory, conflicts) {
10623
10679
  }
10624
10680
  let changed = false;
10625
10681
  if (conflicts.compactionAuto || conflicts.compactionPrune) {
10626
- const compaction = isRecord(config.compaction) ? { ...config.compaction } : {};
10682
+ const compaction = isRecord(config.compaction) ? config.compaction : {};
10627
10683
  if (compaction.auto !== false) {
10628
10684
  compaction.auto = false;
10629
10685
  changed = true;
@@ -10637,10 +10693,10 @@ function fixConflicts(directory, conflicts) {
10637
10693
  config.compaction = compaction;
10638
10694
  }
10639
10695
  if (conflicts.dcpPlugin) {
10640
- const plugins = asStringArray(config.plugin);
10641
- const filteredPlugins = plugins.filter((plugin) => !plugin.includes("opencode-dcp"));
10642
- if (filteredPlugins.length !== plugins.length) {
10643
- config.plugin = filteredPlugins;
10696
+ const plugins = Array.isArray(config.plugin) ? config.plugin : [];
10697
+ const filtered = filterDcpPluginEntries(plugins);
10698
+ if (filtered.removed) {
10699
+ config.plugin = filtered.plugins;
10644
10700
  changed = true;
10645
10701
  removedDcpPlugin = true;
10646
10702
  }
@@ -10695,10 +10751,11 @@ function fixConflicts(directory, conflicts) {
10695
10751
  }
10696
10752
  return actions;
10697
10753
  }
10698
- var CONFLICTING_OMO_HOOKS, OMO_CONFIG_NAMES;
10754
+ var import_comment_json3, CONFLICTING_OMO_HOOKS, OMO_CONFIG_NAMES;
10699
10755
  var init_conflict_fixer = __esm(() => {
10700
- init_jsonc_parser();
10756
+ init_conflict_detector();
10701
10757
  init_opencode_config_dir();
10758
+ import_comment_json3 = __toESM(require_src2(), 1);
10702
10759
  CONFLICTING_OMO_HOOKS = [
10703
10760
  "context-window-monitor",
10704
10761
  "preemptive-compaction",
@@ -10790,30 +10847,30 @@ function buildModelSelection2(allModels, role) {
10790
10847
  var init_opencode_helpers = () => {};
10791
10848
 
10792
10849
  // src/commands/setup-opencode.ts
10793
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "node:fs";
10794
- import { dirname as dirname4 } from "node:path";
10850
+ import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
10851
+ import { dirname as dirname3 } from "node:path";
10795
10852
  function ensureDir3(dir) {
10796
10853
  if (!existsSync7(dir)) {
10797
- mkdirSync2(dir, { recursive: true });
10854
+ mkdirSync(dir, { recursive: true });
10798
10855
  }
10799
10856
  }
10800
- function readJsonc(path) {
10801
- const content = readFileSync4(path, "utf-8");
10857
+ function readJsonc(path2) {
10858
+ const content = readFileSync5(path2, "utf-8");
10802
10859
  try {
10803
- return import_comment_json3.parse(content);
10860
+ return import_comment_json4.parse(content);
10804
10861
  } catch (err) {
10805
- console.error(` ⚠ Failed to parse ${path}: ${err instanceof Error ? err.message : err}`);
10862
+ console.error(` ⚠ Failed to parse ${path2}: ${err instanceof Error ? err.message : err}`);
10806
10863
  return null;
10807
10864
  }
10808
10865
  }
10809
10866
  function addPluginToOpenCodeConfig(configPath, format) {
10810
- ensureDir3(dirname4(configPath));
10867
+ ensureDir3(dirname3(configPath));
10811
10868
  if (format === "none") {
10812
10869
  const config = {
10813
10870
  plugin: [PLUGIN_ENTRY2],
10814
10871
  compaction: { auto: false, prune: false }
10815
10872
  };
10816
- writeFileSync4(configPath, `${import_comment_json3.stringify(config, null, 2)}
10873
+ writeFileSync4(configPath, `${import_comment_json4.stringify(config, null, 2)}
10817
10874
  `);
10818
10875
  return;
10819
10876
  }
@@ -10833,13 +10890,13 @@ function addPluginToOpenCodeConfig(configPath, format) {
10833
10890
  compaction.auto = false;
10834
10891
  compaction.prune = false;
10835
10892
  existing.compaction = compaction;
10836
- writeFileSync4(configPath, `${import_comment_json3.stringify(existing, null, 2)}
10893
+ writeFileSync4(configPath, `${import_comment_json4.stringify(existing, null, 2)}
10837
10894
  `);
10838
10895
  }
10839
10896
  function addPluginToTuiConfig(configPath, format) {
10840
- ensureDir3(dirname4(configPath));
10897
+ ensureDir3(dirname3(configPath));
10841
10898
  if (format === "none") {
10842
- writeFileSync4(configPath, `${import_comment_json3.stringify({ plugin: [PLUGIN_ENTRY2] }, null, 2)}
10899
+ writeFileSync4(configPath, `${import_comment_json4.stringify({ plugin: [PLUGIN_ENTRY2] }, null, 2)}
10843
10900
  `);
10844
10901
  return;
10845
10902
  }
@@ -10855,9 +10912,42 @@ function addPluginToTuiConfig(configPath, format) {
10855
10912
  rawPlugins.push(PLUGIN_ENTRY2);
10856
10913
  }
10857
10914
  existing.plugin = rawPlugins;
10858
- writeFileSync4(configPath, `${import_comment_json3.stringify(existing, null, 2)}
10915
+ writeFileSync4(configPath, `${import_comment_json4.stringify(existing, null, 2)}
10859
10916
  `);
10860
10917
  }
10918
+ function findDcpPluginIndexes(plugins) {
10919
+ return plugins.map((plugin, index) => matchesPluginEntry(plugin, DCP_PLUGIN_NAME) ? index : -1).filter((index) => index >= 0);
10920
+ }
10921
+ function pluginEntryName(entry) {
10922
+ if (typeof entry === "string")
10923
+ return entry;
10924
+ if (Array.isArray(entry) && typeof entry[0] === "string")
10925
+ return entry[0];
10926
+ return String(entry);
10927
+ }
10928
+ async function resolveDcpConflictBeforeSetup(configPath, format) {
10929
+ if (format === "none")
10930
+ return;
10931
+ const ocConfig = readJsonc(configPath);
10932
+ if (!ocConfig)
10933
+ return;
10934
+ const plugins = Array.isArray(ocConfig.plugin) ? ocConfig.plugin : [];
10935
+ const dcpIndexes = findDcpPluginIndexes(plugins);
10936
+ if (dcpIndexes.length === 0)
10937
+ return;
10938
+ log.warn(`Found conflicting plugin: ${pluginEntryName(plugins[dcpIndexes[0]])}`);
10939
+ log.message(`opencode-dcp (Dynamic Context Pruning) and Magic Context both manage context.
10940
+ ` + "Running both simultaneously will cause unpredictable behavior.");
10941
+ const shouldRemove = await confirm("Remove opencode-dcp from your config?", true);
10942
+ if (shouldRemove) {
10943
+ ocConfig.plugin = plugins.filter((_plugin, index) => !dcpIndexes.includes(index));
10944
+ writeFileSync4(configPath, `${import_comment_json4.stringify(ocConfig, null, 2)}
10945
+ `);
10946
+ log.success("Removed opencode-dcp from plugin list");
10947
+ } else {
10948
+ log.warn("Skipped — you may experience context management conflicts");
10949
+ }
10950
+ }
10861
10951
  function writeMagicContextConfig(configPath, options) {
10862
10952
  const config = (existsSync7(configPath) ? readJsonc(configPath) : null) ?? {};
10863
10953
  if (!config.$schema) {
@@ -10896,7 +10986,7 @@ function writeMagicContextConfig(configPath, options) {
10896
10986
  cacheTtl["anthropic/claude-opus-4-6"] = "59m";
10897
10987
  config.cache_ttl = cacheTtl;
10898
10988
  }
10899
- writeFileSync4(configPath, `${import_comment_json3.stringify(config, null, 2)}
10989
+ writeFileSync4(configPath, `${import_comment_json4.stringify(config, null, 2)}
10900
10990
  `);
10901
10991
  }
10902
10992
  async function runSetup() {
@@ -10926,32 +11016,11 @@ async function runSetup() {
10926
11016
  }
10927
11017
  const paths = detectConfigPaths();
10928
11018
  const hadExistingSetup = paths.opencodeConfigFormat !== "none" || existsSync7(paths.magicContextConfig) || paths.tuiConfigFormat !== "none";
11019
+ await resolveDcpConflictBeforeSetup(paths.opencodeConfig, paths.opencodeConfigFormat);
10929
11020
  addPluginToOpenCodeConfig(paths.opencodeConfig, paths.opencodeConfigFormat);
10930
11021
  log.success(`Plugin added to ${paths.opencodeConfig}`);
10931
11022
  log.info("Disabled built-in compaction (auto=false, prune=false)");
10932
11023
  log.message("Magic Context handles context management — built-in compaction would interfere");
10933
- if (paths.opencodeConfigFormat !== "none") {
10934
- const ocConfig = readJsonc(paths.opencodeConfig);
10935
- if (ocConfig) {
10936
- const plugins = ocConfig.plugin ?? [];
10937
- const dcpIndex = plugins.findIndex((p2) => p2.startsWith("@tarquinen/opencode-dcp"));
10938
- if (dcpIndex !== -1) {
10939
- log.warn(`Found conflicting plugin: ${plugins[dcpIndex]}`);
10940
- log.message(`opencode-dcp (Dynamic Context Pruning) and Magic Context both manage context.
10941
- ` + "Running both simultaneously will cause unpredictable behavior.");
10942
- const shouldRemove = await confirm("Remove opencode-dcp from your config?", true);
10943
- if (shouldRemove) {
10944
- plugins.splice(dcpIndex, 1);
10945
- ocConfig.plugin = plugins;
10946
- writeFileSync4(paths.opencodeConfig, `${import_comment_json3.stringify(ocConfig, null, 2)}
10947
- `);
10948
- log.success("Removed opencode-dcp from plugin list");
10949
- } else {
10950
- log.warn("Skipped — you may experience context management conflicts");
10951
- }
10952
- }
10953
- }
10954
- }
10955
11024
  if (hadExistingSetup) {
10956
11025
  const conflicts = detectConflicts(process.cwd());
10957
11026
  if (conflicts.hasConflict) {
@@ -11084,7 +11153,7 @@ async function runSetup() {
11084
11153
  outro("Run 'opencode' to start!");
11085
11154
  return 0;
11086
11155
  }
11087
- var import_comment_json3, PLUGIN_NAME3 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY2 = "@cortexkit/opencode-magic-context@latest";
11156
+ var import_comment_json4, PLUGIN_NAME3 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY2 = "@cortexkit/opencode-magic-context@latest", DCP_PLUGIN_NAME = "@tarquinen/opencode-dcp";
11088
11157
  var init_setup_opencode = __esm(() => {
11089
11158
  init_conflict_detector();
11090
11159
  init_conflict_fixer();
@@ -11092,26 +11161,77 @@ var init_setup_opencode = __esm(() => {
11092
11161
  init_opencode_helpers();
11093
11162
  init_paths();
11094
11163
  init_prompts();
11095
- import_comment_json3 = __toESM(require_src2(), 1);
11164
+ import_comment_json4 = __toESM(require_src2(), 1);
11165
+ });
11166
+
11167
+ // src/lib/pi-package-entry.ts
11168
+ function stripNpmPrefix(value) {
11169
+ return value.startsWith("npm:") ? value.slice("npm:".length) : value;
11170
+ }
11171
+ function packageNameFromSpecifier(value) {
11172
+ const normalized = stripNpmPrefix(value.trim());
11173
+ if (!normalized)
11174
+ return normalized;
11175
+ if (normalized.startsWith("@")) {
11176
+ const slash = normalized.indexOf("/");
11177
+ if (slash < 0)
11178
+ return normalized;
11179
+ const versionAt2 = normalized.indexOf("@", slash + 1);
11180
+ return versionAt2 > 0 ? normalized.slice(0, versionAt2) : normalized;
11181
+ }
11182
+ const versionAt = normalized.indexOf("@");
11183
+ return versionAt > 0 ? normalized.slice(0, versionAt) : normalized;
11184
+ }
11185
+ function getPiPackageEntryName(entry) {
11186
+ if (typeof entry === "string")
11187
+ return packageNameFromSpecifier(entry);
11188
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
11189
+ const name = entry.name;
11190
+ if (typeof name === "string")
11191
+ return packageNameFromSpecifier(name);
11192
+ }
11193
+ return null;
11194
+ }
11195
+ function isPiMagicContextPackageEntry(entry) {
11196
+ return getPiPackageEntryName(entry) === PI_MAGIC_CONTEXT_PACKAGE_NAME;
11197
+ }
11198
+ function hasPiMagicContextPackage(entries) {
11199
+ return entries.some(isPiMagicContextPackageEntry);
11200
+ }
11201
+ function describePiPackageEntry(entry) {
11202
+ if (typeof entry === "string")
11203
+ return entry;
11204
+ const name = getPiPackageEntryName(entry);
11205
+ if (name)
11206
+ return name;
11207
+ try {
11208
+ return JSON.stringify(entry);
11209
+ } catch {
11210
+ return String(entry);
11211
+ }
11212
+ }
11213
+ var PI_MAGIC_CONTEXT_PACKAGE_NAME = "@cortexkit/pi-magic-context";
11214
+ var init_pi_package_entry = __esm(() => {
11215
+ init_pi_helpers();
11096
11216
  });
11097
11217
 
11098
11218
  // src/commands/setup-pi.ts
11099
- import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
11100
- import { dirname as dirname5 } from "node:path";
11101
- function ensureDir4(path) {
11102
- if (!existsSync8(path))
11103
- mkdirSync3(path, { recursive: true });
11219
+ import { existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
11220
+ import { dirname as dirname4 } from "node:path";
11221
+ function ensureDir4(path2) {
11222
+ if (!existsSync8(path2))
11223
+ mkdirSync2(path2, { recursive: true });
11104
11224
  }
11105
11225
  async function getDefaultPrompts() {
11106
11226
  const { promptIO: promptIO2 } = await Promise.resolve().then(() => (init_prompts(), exports_prompts));
11107
11227
  return promptIO2;
11108
11228
  }
11109
- function readJsonc2(path) {
11229
+ function readJsonc2(path2) {
11110
11230
  try {
11111
- return import_comment_json4.parse(readFileSync5(path, "utf-8"));
11231
+ return import_comment_json5.parse(readFileSync6(path2, "utf-8"));
11112
11232
  } catch (error) {
11113
11233
  const message = error instanceof Error ? error.message : String(error);
11114
- console.warn(`Could not parse ${path}: ${message}`);
11234
+ console.warn(`Could not parse ${path2}: ${message}`);
11115
11235
  return null;
11116
11236
  }
11117
11237
  }
@@ -11123,12 +11243,12 @@ function compactObject(obj) {
11123
11243
  return obj;
11124
11244
  }
11125
11245
  function comparePiVersion(a, b2) {
11126
- const parse = (v2) => {
11246
+ const parse2 = (v2) => {
11127
11247
  const match = v2.match(/(\d+)\.(\d+)\.(\d+)/);
11128
11248
  return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
11129
11249
  };
11130
- const left = parse(a);
11131
- const right = parse(b2);
11250
+ const left = parse2(a);
11251
+ const right = parse2(b2);
11132
11252
  if (!left || !right)
11133
11253
  return 0;
11134
11254
  for (let i = 0;i < 3; i += 1) {
@@ -11140,19 +11260,19 @@ function comparePiVersion(a, b2) {
11140
11260
  return 0;
11141
11261
  }
11142
11262
  function writePiSettingsPackage(settingsPath, packageSource = PI_PACKAGE_SOURCE) {
11143
- ensureDir4(dirname5(settingsPath));
11263
+ ensureDir4(dirname4(settingsPath));
11144
11264
  const settings = existsSync8(settingsPath) ? readJsonc2(settingsPath) ?? {} : {};
11145
- const packages = Array.isArray(settings.packages) ? settings.packages.filter((value) => typeof value === "string") : [];
11146
- const hasPackage = packages.some((source) => source === packageSource || source === packageSource.replace(/^npm:/, "") || source.includes("pi-magic-context"));
11265
+ const packages = Array.isArray(settings.packages) ? settings.packages : [];
11266
+ const hasPackage = hasPiMagicContextPackage(packages);
11147
11267
  if (!hasPackage)
11148
11268
  packages.push(packageSource);
11149
11269
  settings.packages = packages;
11150
- writeFileSync5(settingsPath, `${import_comment_json4.stringify(settings, null, 2)}
11270
+ writeFileSync5(settingsPath, `${import_comment_json5.stringify(settings, null, 2)}
11151
11271
  `);
11152
11272
  return !hasPackage;
11153
11273
  }
11154
11274
  function writeMagicContextConfig2(configPath, options) {
11155
- ensureDir4(dirname5(configPath));
11275
+ ensureDir4(dirname4(configPath));
11156
11276
  const config = existsSync8(configPath) ? readJsonc2(configPath) ?? {} : {};
11157
11277
  if (!config.$schema) {
11158
11278
  config.$schema = "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json";
@@ -11180,7 +11300,7 @@ function writeMagicContextConfig2(configPath, options) {
11180
11300
  };
11181
11301
  }
11182
11302
  config.embedding = options.embedding;
11183
- writeFileSync5(configPath, `${import_comment_json4.stringify(config, null, 2)}
11303
+ writeFileSync5(configPath, `${import_comment_json5.stringify(config, null, 2)}
11184
11304
  `);
11185
11305
  }
11186
11306
  async function chooseModel(prompts, allModels, role, message) {
@@ -11306,11 +11426,12 @@ Run \`pi update\` (or \`npm install -g @mariozechner/pi-coding-agent@latest\`) b
11306
11426
  prompts.outro("Start a Pi session and try /ctx-aug");
11307
11427
  return 0;
11308
11428
  }
11309
- var import_comment_json4, DEFAULT_ENV;
11429
+ var import_comment_json5, DEFAULT_ENV;
11310
11430
  var init_setup_pi = __esm(() => {
11311
11431
  init_paths();
11312
11432
  init_pi_helpers();
11313
- import_comment_json4 = __toESM(require_src2(), 1);
11433
+ init_pi_package_entry();
11434
+ import_comment_json5 = __toESM(require_src2(), 1);
11314
11435
  DEFAULT_ENV = {
11315
11436
  detectPiBinary,
11316
11437
  getPiVersion,
@@ -11390,29 +11511,6 @@ var init_setup = __esm(() => {
11390
11511
  init_setup_pi();
11391
11512
  });
11392
11513
 
11393
- // ../plugin/src/shared/data-path.ts
11394
- import * as os from "node:os";
11395
- import * as path from "node:path";
11396
- function getDataDir() {
11397
- return process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share");
11398
- }
11399
- function getOpenCodeStorageDir() {
11400
- return path.join(getDataDir(), "opencode", "storage");
11401
- }
11402
- function getMagicContextStorageDir() {
11403
- return path.join(getDataDir(), "cortexkit", "magic-context");
11404
- }
11405
- function getLegacyOpenCodeMagicContextStorageDir() {
11406
- return path.join(getOpenCodeStorageDir(), "plugin", "magic-context");
11407
- }
11408
- function getCacheDir() {
11409
- return process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), ".cache");
11410
- }
11411
- function getOpenCodeCacheDir() {
11412
- return path.join(getCacheDir(), "opencode");
11413
- }
11414
- var init_data_path = () => {};
11415
-
11416
11514
  // ../../node_modules/.bun/nanotar@0.3.0/node_modules/nanotar/dist/index.mjs
11417
11515
  function parseTar(data, opts) {
11418
11516
  const buffer = data.buffer || data;
@@ -11591,8 +11689,16 @@ var init_dist5 = __esm(() => {
11591
11689
 
11592
11690
  // ../plugin/src/shared/logger.ts
11593
11691
  import * as fs from "node:fs";
11594
- import * as os2 from "node:os";
11595
11692
  import * as path2 from "node:path";
11693
+ function ensureDir5(filePath) {
11694
+ const dir = path2.dirname(filePath);
11695
+ if (dir === lastEnsuredDir)
11696
+ return;
11697
+ try {
11698
+ fs.mkdirSync(dir, { recursive: true });
11699
+ lastEnsuredDir = dir;
11700
+ } catch {}
11701
+ }
11596
11702
  function flush() {
11597
11703
  if (flushTimer) {
11598
11704
  clearTimeout(flushTimer);
@@ -11603,6 +11709,8 @@ function flush() {
11603
11709
  const data = buffer.join("");
11604
11710
  buffer = [];
11605
11711
  try {
11712
+ const logFile = getMagicContextLogPath();
11713
+ ensureDir5(logFile);
11606
11714
  fs.appendFileSync(logFile, data);
11607
11715
  } catch {}
11608
11716
  }
@@ -11630,9 +11738,9 @@ ${data.stack}` : ""}` : ` ${JSON.stringify(data)}`;
11630
11738
  }
11631
11739
  } catch {}
11632
11740
  }
11633
- var logFile, isTestEnv = false, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50;
11741
+ var isTestEnv = false, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50, lastEnsuredDir = null;
11634
11742
  var init_logger = __esm(() => {
11635
- logFile = path2.join(os2.tmpdir(), "magic-context.log");
11743
+ init_data_path();
11636
11744
  buffer = [];
11637
11745
  if (!isTestEnv) {
11638
11746
  process.on("exit", flush);
@@ -11808,15 +11916,15 @@ __export(exports_migrate, {
11808
11916
  import { randomBytes } from "node:crypto";
11809
11917
  import { existsSync as existsSync10, mkdirSync as mkdirSync5, writeFileSync as writeFileSync7 } from "node:fs";
11810
11918
  import { homedir as homedir6 } from "node:os";
11811
- import { join as join10 } from "node:path";
11919
+ import { join as join9 } from "node:path";
11812
11920
  function defaultOpenCodeDbPath() {
11813
- return join10(homedir6(), ".local", "share", "opencode", "opencode.db");
11921
+ return join9(homedir6(), ".local", "share", "opencode", "opencode.db");
11814
11922
  }
11815
11923
  function defaultCortexkitDbPath() {
11816
- return join10(getMagicContextStorageDir(), "context.db");
11924
+ return join9(getMagicContextStorageDir(), "context.db");
11817
11925
  }
11818
11926
  function defaultPiSessionsRoot() {
11819
- return join10(homedir6(), ".pi", "agent", "sessions");
11927
+ return join9(homedir6(), ".pi", "agent", "sessions");
11820
11928
  }
11821
11929
  function defaultFs() {
11822
11930
  return { existsSync: existsSync10, mkdirSync: mkdirSync5, writeFileSync: writeFileSync7 };
@@ -12242,7 +12350,7 @@ function migrateOpenCodeSessionToPi(opts) {
12242
12350
  const provider = opts.provider ?? model.provider;
12243
12351
  const modelId = opts.modelId ?? model.modelId;
12244
12352
  const cwd = session.directory ?? session.path ?? process.cwd();
12245
- const outputDir = join10(piSessionsRoot, projectPathToPiDirSlug(cwd));
12353
+ const outputDir = join9(piSessionsRoot, projectPathToPiDirSlug(cwd));
12246
12354
  const buildResult = buildPiEntries({
12247
12355
  session,
12248
12356
  messages,
@@ -12268,7 +12376,7 @@ function migrateOpenCodeSessionToPi(opts) {
12268
12376
  });
12269
12377
  }
12270
12378
  const compactionMarker = insertCompactionMarker(buildResult.entries, copyResult.lastCompartmentEndPiEntryId);
12271
- const outputPath = join10(outputDir, `${formatPiFilenameTimestamp(now)}_${buildResult.piSessionId}.jsonl`);
12379
+ const outputPath = join9(outputDir, `${formatPiFilenameTimestamp(now)}_${buildResult.piSessionId}.jsonl`);
12272
12380
  const jsonl = `${buildResult.entries.map((entry) => JSON.stringify(entry)).join(`
12273
12381
  `)}
12274
12382
  `;
@@ -13326,7 +13434,7 @@ var _parse = (_Err) => (schema, value, _ctx, _params) => {
13326
13434
  throw e2;
13327
13435
  }
13328
13436
  return result.value;
13329
- }, parse, _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
13437
+ }, parse2, _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
13330
13438
  const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
13331
13439
  let result = schema._zod.run({ value, issues: [] }, ctx);
13332
13440
  if (result instanceof Promise)
@@ -13381,7 +13489,7 @@ var init_parse = __esm(() => {
13381
13489
  init_core();
13382
13490
  init_errors();
13383
13491
  init_util();
13384
- parse = /* @__PURE__ */ _parse($ZodRealError);
13492
+ parse2 = /* @__PURE__ */ _parse($ZodRealError);
13385
13493
  parseAsync = /* @__PURE__ */ _parseAsync($ZodRealError);
13386
13494
  safeParse = /* @__PURE__ */ _safeParse($ZodRealError);
13387
13495
  safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError);
@@ -16140,10 +16248,10 @@ var init_schemas = __esm(() => {
16140
16248
  throw new Error("implement() must be called with a function");
16141
16249
  }
16142
16250
  return function(...args) {
16143
- const parsedArgs = inst._def.input ? parse(inst._def.input, args) : args;
16251
+ const parsedArgs = inst._def.input ? parse2(inst._def.input, args) : args;
16144
16252
  const result = Reflect.apply(func, this, parsedArgs);
16145
16253
  if (inst._def.output) {
16146
- return parse(inst._def.output, result);
16254
+ return parse2(inst._def.output, result);
16147
16255
  }
16148
16256
  return result;
16149
16257
  };
@@ -23628,7 +23736,7 @@ function finalize(ctx, schema) {
23628
23736
  result.$schema = "http://json-schema.org/draft-07/schema#";
23629
23737
  } else if (ctx.target === "draft-04") {
23630
23738
  result.$schema = "http://json-schema.org/draft-04/schema#";
23631
- } else if (ctx.target === "openapi-3.0") {} else {}
23739
+ } else if (ctx.target === "openapi-3.0") {}
23632
23740
  if (ctx.external?.uri) {
23633
23741
  const id = ctx.external.registry.get(schema)?.id;
23634
23742
  if (!id)
@@ -23889,7 +23997,7 @@ var formatMap, stringProcessor = (schema, ctx, _json, _params) => {
23889
23997
  if (val === undefined) {
23890
23998
  if (ctx.unrepresentable === "throw") {
23891
23999
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
23892
- } else {}
24000
+ }
23893
24001
  } else if (typeof val === "bigint") {
23894
24002
  if (ctx.unrepresentable === "throw") {
23895
24003
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -24336,7 +24444,7 @@ __export(exports_core2, {
24336
24444
  process: () => process2,
24337
24445
  prettifyError: () => prettifyError,
24338
24446
  parseAsync: () => parseAsync,
24339
- parse: () => parse,
24447
+ parse: () => parse2,
24340
24448
  meta: () => meta,
24341
24449
  locales: () => exports_locales,
24342
24450
  isValidJWT: () => isValidJWT,
@@ -24737,11 +24845,11 @@ var init_errors2 = __esm(() => {
24737
24845
  });
24738
24846
 
24739
24847
  // ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/parse.js
24740
- var parse3, parseAsync2, safeParse2, safeParseAsync2, encode2, decode2, encodeAsync2, decodeAsync2, safeEncode2, safeDecode2, safeEncodeAsync2, safeDecodeAsync2;
24848
+ var parse4, parseAsync2, safeParse2, safeParseAsync2, encode2, decode2, encodeAsync2, decodeAsync2, safeEncode2, safeDecode2, safeEncodeAsync2, safeDecodeAsync2;
24741
24849
  var init_parse2 = __esm(() => {
24742
24850
  init_core2();
24743
24851
  init_errors2();
24744
- parse3 = /* @__PURE__ */ _parse(ZodRealError);
24852
+ parse4 = /* @__PURE__ */ _parse(ZodRealError);
24745
24853
  parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
24746
24854
  safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
24747
24855
  safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
@@ -25461,7 +25569,7 @@ var init_schemas2 = __esm(() => {
25461
25569
  inst.def = def;
25462
25570
  inst.type = def.type;
25463
25571
  Object.defineProperty(inst, "_def", { value: def });
25464
- inst.parse = (data, params) => parse3(inst, data, params, { callee: inst.parse });
25572
+ inst.parse = (data, params) => parse4(inst, data, params, { callee: inst.parse });
25465
25573
  inst.safeParse = (data, params) => safeParse2(inst, data, params);
25466
25574
  inst.parseAsync = async (data, params) => parseAsync2(inst, data, params, { callee: inst.parseAsync });
25467
25575
  inst.safeParseAsync = async (data, params) => safeParseAsync2(inst, data, params);
@@ -26813,7 +26921,7 @@ __export(exports_external, {
26813
26921
  pipe: () => pipe,
26814
26922
  partialRecord: () => partialRecord,
26815
26923
  parseAsync: () => parseAsync2,
26816
- parse: () => parse3,
26924
+ parse: () => parse4,
26817
26925
  overwrite: () => _overwrite,
26818
26926
  optional: () => optional,
26819
26927
  object: () => object,
@@ -27236,7 +27344,7 @@ var init_magic_context = __esm(() => {
27236
27344
  });
27237
27345
 
27238
27346
  // ../plugin/src/config/variable.ts
27239
- import { existsSync as existsSync11, readFileSync as readFileSync6 } from "node:fs";
27347
+ import { existsSync as existsSync11, readFileSync as readFileSync7 } from "node:fs";
27240
27348
  import { homedir as homedir7 } from "node:os";
27241
27349
  import { dirname as dirname7, isAbsolute, resolve as resolve2 } from "node:path";
27242
27350
  function substituteConfigVariables(input) {
@@ -27283,7 +27391,7 @@ function substituteConfigVariables(input) {
27283
27391
  }
27284
27392
  let contents;
27285
27393
  try {
27286
- contents = readFileSync6(filePath, "utf-8").trim();
27394
+ contents = readFileSync7(filePath, "utf-8").trim();
27287
27395
  } catch (error51) {
27288
27396
  const message = error51 instanceof Error ? error51.message : String(error51);
27289
27397
  warnings.push(`Failed to read file for ${token} (${filePath}): ${message}; using empty string`);
@@ -27301,22 +27409,22 @@ var init_variable = __esm(() => {
27301
27409
  });
27302
27410
 
27303
27411
  // ../plugin/src/config/index.ts
27304
- import { existsSync as existsSync12, readFileSync as readFileSync7 } from "node:fs";
27412
+ import { existsSync as existsSync12, readFileSync as readFileSync8 } from "node:fs";
27305
27413
  import { homedir as homedir8 } from "node:os";
27306
- import { join as join11 } from "node:path";
27414
+ import { join as join10 } from "node:path";
27307
27415
  function getUserConfigBasePath() {
27308
- const configRoot = process.env.XDG_CONFIG_HOME ?? join11(homedir8(), ".config");
27309
- return join11(configRoot, "opencode", CONFIG_FILE_BASENAME);
27416
+ const configRoot = process.env.XDG_CONFIG_HOME ?? join10(homedir8(), ".config");
27417
+ return join10(configRoot, "opencode", CONFIG_FILE_BASENAME);
27310
27418
  }
27311
27419
  function getProjectConfigBasePath(directory) {
27312
- return join11(directory, ".opencode", CONFIG_FILE_BASENAME);
27420
+ return join10(directory, ".opencode", CONFIG_FILE_BASENAME);
27313
27421
  }
27314
27422
  function loadConfigFile(configPath) {
27315
27423
  try {
27316
27424
  if (!existsSync12(configPath)) {
27317
27425
  return null;
27318
27426
  }
27319
- const rawText = readFileSync7(configPath, "utf-8");
27427
+ const rawText = readFileSync8(configPath, "utf-8");
27320
27428
  const substituted = substituteConfigVariables({ text: rawText, configPath });
27321
27429
  return {
27322
27430
  config: parseJsonc3(substituted.text),
@@ -27327,34 +27435,20 @@ function loadConfigFile(configPath) {
27327
27435
  return null;
27328
27436
  }
27329
27437
  }
27330
- function mergeConfigs(base, override, options = {}) {
27331
- const config2 = {
27332
- ...base,
27333
- ...override,
27334
- auto_update: options.allowUserOnlyFields ? override.auto_update : base.auto_update,
27335
- memory: {
27336
- ...base.memory ?? {},
27337
- ...override.memory ?? {}
27338
- },
27339
- embedding: override.embedding ?? base.embedding,
27340
- historian: override.historian ?? base.historian,
27341
- dreamer: override.dreamer ? {
27342
- ...base.dreamer ?? {},
27343
- ...override.dreamer
27344
- } : base.dreamer,
27345
- sidekick: override.sidekick ? {
27346
- ...base.sidekick ?? {},
27347
- ...override.sidekick
27348
- } : base.sidekick,
27349
- disabled_hooks: [
27350
- ...new Set([...base.disabled_hooks ?? [], ...override.disabled_hooks ?? []])
27351
- ],
27352
- command: {
27353
- ...base.command ?? {},
27354
- ...override.command ?? {}
27438
+ function deepMergeRawConfig(base, override) {
27439
+ const result = { ...base };
27440
+ for (const key of Object.keys(override)) {
27441
+ const baseVal = base[key];
27442
+ const overrideVal = override[key];
27443
+ if (baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal) && overrideVal !== null && typeof overrideVal === "object" && !Array.isArray(overrideVal)) {
27444
+ result[key] = deepMergeRawConfig(baseVal, overrideVal);
27445
+ } else if (key === "disabled_hooks" && Array.isArray(baseVal) && Array.isArray(overrideVal)) {
27446
+ result[key] = [...new Set([...baseVal, ...overrideVal])];
27447
+ } else {
27448
+ result[key] = overrideVal;
27355
27449
  }
27356
- };
27357
- return config2;
27450
+ }
27451
+ return result;
27358
27452
  }
27359
27453
  function getProjectUserOnlyFields(config2) {
27360
27454
  return "auto_update" in config2 ? ["auto_update"] : [];
@@ -27490,35 +27584,43 @@ function parsePluginConfig(rawConfig) {
27490
27584
  }
27491
27585
  function loadPluginConfig(directory) {
27492
27586
  const userDetected = detectConfigFile(getUserConfigBasePath());
27493
- const rootDetected = detectConfigFile(join11(directory, CONFIG_FILE_BASENAME));
27587
+ const rootDetected = detectConfigFile(join10(directory, CONFIG_FILE_BASENAME));
27494
27588
  const dotOpenCodeDetected = detectConfigFile(getProjectConfigBasePath(directory));
27495
27589
  const projectDetected = rootDetected.format !== "none" ? rootDetected : dotOpenCodeDetected;
27496
27590
  const userLoaded = userDetected.format === "none" ? null : loadConfigFile(userDetected.path);
27497
27591
  const projectLoaded = projectDetected.format === "none" ? null : loadConfigFile(projectDetected.path);
27498
- let config2 = parsePluginConfig({});
27499
27592
  const allWarnings = [];
27593
+ let mergedRaw = {};
27500
27594
  if (userLoaded) {
27501
27595
  allWarnings.push(...userLoaded.warnings.map((w3) => `[user config] ${w3}`));
27502
- const parsed = parsePluginConfig(userLoaded.config);
27503
- if (parsed.configWarnings?.length) {
27504
- allWarnings.push(...parsed.configWarnings.map((w3) => `[user config] ${w3}`));
27505
- }
27506
- config2 = mergeConfigs(config2, parsed, { allowUserOnlyFields: true });
27596
+ mergedRaw = deepMergeRawConfig(mergedRaw, userLoaded.config);
27507
27597
  }
27508
27598
  if (projectLoaded) {
27509
27599
  allWarnings.push(...projectLoaded.warnings.map((w3) => `[project config] ${w3}`));
27510
- const parsed = parsePluginConfig(projectLoaded.config);
27511
- if (parsed.configWarnings?.length) {
27512
- allWarnings.push(...parsed.configWarnings.map((w3) => `[project config] ${w3}`));
27513
- }
27514
- const strippedUserOnlyFields = getProjectUserOnlyFields(projectLoaded.config);
27600
+ const projectRaw = { ...projectLoaded.config };
27601
+ const strippedUserOnlyFields = getProjectUserOnlyFields(projectRaw);
27515
27602
  if (strippedUserOnlyFields.length > 0) {
27603
+ for (const key of strippedUserOnlyFields) {
27604
+ delete projectRaw[key];
27605
+ }
27516
27606
  allWarnings.push(`[project config] Ignoring ${strippedUserOnlyFields.join(", ")} from project config (security: these settings only honor user-level config)`);
27517
27607
  }
27518
- config2 = mergeConfigs(config2, parsed);
27608
+ mergedRaw = deepMergeRawConfig(mergedRaw, projectRaw);
27609
+ }
27610
+ const config2 = parsePluginConfig(mergedRaw);
27611
+ if (config2.configWarnings?.length) {
27612
+ allWarnings.push(...config2.configWarnings.map((w3) => {
27613
+ if (userLoaded && projectLoaded)
27614
+ return `[config] ${w3}`;
27615
+ if (userLoaded)
27616
+ return `[user config] ${w3}`;
27617
+ return `[project config] ${w3}`;
27618
+ }));
27519
27619
  }
27520
27620
  if (allWarnings.length > 0) {
27521
27621
  config2.configWarnings = allWarnings;
27622
+ } else if ("configWarnings" in config2) {
27623
+ config2.configWarnings = undefined;
27522
27624
  }
27523
27625
  return config2;
27524
27626
  }
@@ -27634,8 +27736,8 @@ function truncate(text2) {
27634
27736
  var DEFAULT_TIMEOUT_MS = 1e4, MAX_PREVIEW_CHARS = 240;
27635
27737
 
27636
27738
  // ../plugin/src/shared/tui-config.ts
27637
- import { existsSync as existsSync13, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "node:fs";
27638
- import { dirname as dirname8, join as join12 } from "node:path";
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";
27639
27741
  function isMagicContextEntry(entry) {
27640
27742
  if (!entry)
27641
27743
  return false;
@@ -27649,8 +27751,8 @@ function isMagicContextEntry(entry) {
27649
27751
  }
27650
27752
  function resolveTuiConfigPath() {
27651
27753
  const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
27652
- const jsoncPath = join12(configDir, "tui.jsonc");
27653
- const jsonPath = join12(configDir, "tui.json");
27754
+ const jsoncPath = join11(configDir, "tui.jsonc");
27755
+ const jsonPath = join11(configDir, "tui.json");
27654
27756
  if (existsSync13(jsoncPath))
27655
27757
  return jsoncPath;
27656
27758
  if (existsSync13(jsonPath))
@@ -27662,8 +27764,8 @@ function ensureTuiPluginEntry() {
27662
27764
  const configPath = resolveTuiConfigPath();
27663
27765
  let config2 = {};
27664
27766
  if (existsSync13(configPath)) {
27665
- const raw = readFileSync8(configPath, "utf-8");
27666
- config2 = import_comment_json5.parse(raw) ?? {};
27767
+ const raw = readFileSync9(configPath, "utf-8");
27768
+ config2 = import_comment_json6.parse(raw) ?? {};
27667
27769
  }
27668
27770
  const plugins = Array.isArray(config2.plugin) ? config2.plugin.filter((p2) => typeof p2 === "string") : [];
27669
27771
  const existingIdx = plugins.findIndex(isMagicContextEntry);
@@ -27682,7 +27784,7 @@ function ensureTuiPluginEntry() {
27682
27784
  }
27683
27785
  config2.plugin = plugins;
27684
27786
  mkdirSync6(dirname8(configPath), { recursive: true });
27685
- writeFileSync8(configPath, `${import_comment_json5.stringify(config2, null, 2)}
27787
+ writeFileSync8(configPath, `${import_comment_json6.stringify(config2, null, 2)}
27686
27788
  `);
27687
27789
  log2(`[magic-context] updated TUI plugin entry in ${configPath}`);
27688
27790
  return true;
@@ -27691,11 +27793,11 @@ function ensureTuiPluginEntry() {
27691
27793
  return false;
27692
27794
  }
27693
27795
  }
27694
- var import_comment_json5, PLUGIN_NAME4 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY3;
27796
+ var import_comment_json6, PLUGIN_NAME4 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY3;
27695
27797
  var init_tui_config = __esm(() => {
27696
27798
  init_logger();
27697
27799
  init_opencode_config_dir();
27698
- import_comment_json5 = __toESM(require_src2(), 1);
27800
+ import_comment_json6 = __toESM(require_src2(), 1);
27699
27801
  PLUGIN_ENTRY3 = `${PLUGIN_NAME4}@latest`;
27700
27802
  });
27701
27803
 
@@ -27749,11 +27851,126 @@ var init_compartment_parser = __esm(() => {
27749
27851
  USER_OBS_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
27750
27852
  });
27751
27853
 
27854
+ // src/lib/redaction.ts
27855
+ import { homedir as homedir9, userInfo } from "node:os";
27856
+ function escapeRegex2(value) {
27857
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
27858
+ }
27859
+ function redactionTypeForKey(key) {
27860
+ const normalized = key.trim().toLowerCase().replace(/[^a-z0-9_.-]+/g, "_");
27861
+ const suffix = normalized.split(".").filter(Boolean).at(-1) ?? normalized;
27862
+ return suffix || "secret";
27863
+ }
27864
+ function isSecretKey(key) {
27865
+ return SECRET_KEY_PATTERN.test(key);
27866
+ }
27867
+ function sanitizePathString(value) {
27868
+ const home = homedir9();
27869
+ const username = userInfo().username;
27870
+ let sanitized = value;
27871
+ if (home) {
27872
+ sanitized = sanitized.replace(new RegExp(escapeRegex2(home), "g"), "~");
27873
+ }
27874
+ sanitized = sanitized.replace(/\/Users\/[^/]+\//g, "/Users/<USER>/");
27875
+ sanitized = sanitized.replace(/\/home\/[^/]+\//g, "/home/<USER>/");
27876
+ sanitized = sanitized.replace(/C:\\Users\\[^\\]+\\/g, "C:\\Users\\<USER>\\");
27877
+ if (username) {
27878
+ sanitized = sanitized.replace(new RegExp(escapeRegex2(username), "g"), "<USER>");
27879
+ }
27880
+ return sanitized;
27881
+ }
27882
+ function redactSecretText(value) {
27883
+ let redacted = value;
27884
+ for (const { pattern, replacement } of SECRET_TEXT_PATTERNS) {
27885
+ if (typeof replacement === "string") {
27886
+ redacted = redacted.replace(pattern, replacement);
27887
+ } else {
27888
+ redacted = redacted.replace(pattern, replacement);
27889
+ }
27890
+ }
27891
+ return redacted;
27892
+ }
27893
+ function sanitizeDiagnosticText(value) {
27894
+ return redactSecretText(sanitizePathString(value));
27895
+ }
27896
+ function sanitizeConfigValue(value, keyPath = []) {
27897
+ const key = keyPath.at(-1) ?? "";
27898
+ if (key && isSecretKey(key)) {
27899
+ return `<REDACTED:${redactionTypeForKey(key)}>`;
27900
+ }
27901
+ if (typeof value === "string")
27902
+ return sanitizeDiagnosticText(value);
27903
+ if (Array.isArray(value)) {
27904
+ return value.map((entry, index) => sanitizeConfigValue(entry, [...keyPath, String(index)]));
27905
+ }
27906
+ if (value && typeof value === "object") {
27907
+ return Object.fromEntries(Object.entries(value).map(([entryKey, entry]) => [
27908
+ entryKey,
27909
+ sanitizeConfigValue(entry, [...keyPath, entryKey])
27910
+ ]));
27911
+ }
27912
+ return value;
27913
+ }
27914
+ var SECRET_KEY_PATTERN, SECRET_TEXT_PATTERNS;
27915
+ var init_redaction = __esm(() => {
27916
+ SECRET_KEY_PATTERN = /(?:key|token|secret|password|auth|bearer|credential)/i;
27917
+ SECRET_TEXT_PATTERNS = [
27918
+ {
27919
+ pattern: /\bsk-ant-(?:api03-)?[A-Za-z0-9_-]{32,}/g,
27920
+ replacement: "<ANTHROPIC_API_KEY_REDACTED>"
27921
+ },
27922
+ {
27923
+ pattern: /\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/g,
27924
+ replacement: "<OPENAI_API_KEY_REDACTED>"
27925
+ },
27926
+ {
27927
+ pattern: /\bgithub_pat_[A-Za-z0-9_]{20,}/g,
27928
+ replacement: "<GITHUB_PAT_REDACTED>"
27929
+ },
27930
+ {
27931
+ pattern: /\b(?:gh[opsu]|ghr)_[A-Za-z0-9]{30,}/g,
27932
+ replacement: "<GITHUB_TOKEN_REDACTED>"
27933
+ },
27934
+ {
27935
+ pattern: /\bhf_[A-Za-z0-9]{30,}/g,
27936
+ replacement: "<HUGGINGFACE_TOKEN_REDACTED>"
27937
+ },
27938
+ {
27939
+ pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
27940
+ replacement: "<AWS_ACCESS_KEY_ID_REDACTED>"
27941
+ },
27942
+ {
27943
+ pattern: /\bxox[abprsuvc]-[A-Za-z0-9-]{10,}/g,
27944
+ replacement: "<SLACK_TOKEN_REDACTED>"
27945
+ },
27946
+ {
27947
+ pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g,
27948
+ replacement: "<GOOGLE_API_KEY_REDACTED>"
27949
+ },
27950
+ {
27951
+ pattern: /\b(Authorization\s*:\s*Bearer\s+)([A-Za-z0-9._~+/=-]{8,})/gi,
27952
+ replacement: (_full, prefix) => `${prefix}<REDACTED:bearer>`
27953
+ },
27954
+ {
27955
+ pattern: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
27956
+ replacement: "<JWT_REDACTED>"
27957
+ },
27958
+ {
27959
+ pattern: /(["'])([^"']*(?:key|token|secret|password|auth|bearer|credential)[^"']*)\1(\s*:\s*)(["'])([^"']*)\4/gi,
27960
+ replacement: (_full, quote, key, separator, valueQuote) => `${quote}${key}${quote}${separator}${valueQuote}<REDACTED:${redactionTypeForKey(key)}>${valueQuote}`
27961
+ },
27962
+ {
27963
+ pattern: /\b([A-Za-z0-9_.-]*(?:key|token|secret|password|auth|bearer|credential)[A-Za-z0-9_.-]*)\s*=\s*([^\s'"`]+)/gi,
27964
+ replacement: (_full, key) => `${key}=<REDACTED:${redactionTypeForKey(key)}>`
27965
+ }
27966
+ ];
27967
+ });
27968
+
27752
27969
  // src/lib/diagnostics-opencode.ts
27753
- import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync9, statSync as statSync2 } from "node:fs";
27970
+ import { existsSync as existsSync14, readdirSync as readdirSync2, readFileSync as readFileSync10, statSync as statSync2 } from "node:fs";
27754
27971
  import { createRequire as createRequire3 } from "node:module";
27755
- import { homedir as homedir9, tmpdir as tmpdir3, userInfo } from "node:os";
27756
- import { join as join13 } from "node:path";
27972
+ import { homedir as homedir10 } from "node:os";
27973
+ import { join as join12 } from "node:path";
27757
27974
  function getSelfVersion() {
27758
27975
  const require2 = createRequire3(import.meta.url);
27759
27976
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -27767,12 +27984,12 @@ function getSelfVersion() {
27767
27984
  return "unknown";
27768
27985
  }
27769
27986
  function getPluginCacheInfo() {
27770
- const path4 = join13(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY_WITH_VERSION);
27987
+ const path4 = join12(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY_WITH_VERSION);
27771
27988
  let cached2;
27772
27989
  try {
27773
- const installedPkgPath = join13(path4, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
27990
+ const installedPkgPath = join12(path4, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
27774
27991
  if (existsSync14(installedPkgPath)) {
27775
- const pkg = JSON.parse(readFileSync9(installedPkgPath, "utf-8"));
27992
+ const pkg = JSON.parse(readFileSync10(installedPkgPath, "utf-8"));
27776
27993
  cached2 = typeof pkg.version === "string" ? pkg.version : undefined;
27777
27994
  }
27778
27995
  } catch {
@@ -27781,8 +27998,8 @@ function getPluginCacheInfo() {
27781
27998
  return { path: path4, cached: cached2, latest: getSelfVersion() };
27782
27999
  }
27783
28000
  function getStorageDir() {
27784
- const dataHome = process.env.XDG_DATA_HOME || join13(homedir9(), ".local", "share");
27785
- return join13(dataHome, "cortexkit", "magic-context");
28001
+ const dataHome = process.env.XDG_DATA_HOME || join12(homedir10(), ".local", "share");
28002
+ return join12(dataHome, "cortexkit", "magic-context");
27786
28003
  }
27787
28004
  function fileSize(path4) {
27788
28005
  try {
@@ -27791,40 +28008,18 @@ function fileSize(path4) {
27791
28008
  return 0;
27792
28009
  }
27793
28010
  }
27794
- function escapeRegex2(value) {
27795
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
27796
- }
27797
28011
  function sanitizeString(value) {
27798
- const home = homedir9();
27799
- const username = userInfo().username;
27800
- let sanitized = value;
27801
- if (home) {
27802
- sanitized = sanitized.replace(new RegExp(escapeRegex2(home), "g"), "~");
27803
- }
27804
- sanitized = sanitized.replace(/\/Users\/[^/]+\//g, "/Users/<USER>/");
27805
- sanitized = sanitized.replace(/\/home\/[^/]+\//g, "/home/<USER>/");
27806
- sanitized = sanitized.replace(/C:\\Users\\[^\\]+\\/g, "C:\\Users\\<USER>\\");
27807
- if (username) {
27808
- sanitized = sanitized.replace(new RegExp(escapeRegex2(username), "g"), "<USER>");
27809
- }
27810
- return sanitized;
28012
+ return sanitizePathString(value);
27811
28013
  }
27812
28014
  function sanitizeValue(value) {
27813
- if (typeof value === "string")
27814
- return sanitizeString(value);
27815
- if (Array.isArray(value))
27816
- return value.map(sanitizeValue);
27817
- if (value && typeof value === "object") {
27818
- return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, sanitizeValue(entry)]));
27819
- }
27820
- return value;
28015
+ return sanitizeConfigValue(value);
27821
28016
  }
27822
28017
  function readConfig2(path4) {
27823
28018
  if (!existsSync14(path4))
27824
28019
  return { value: null };
27825
28020
  try {
27826
- const raw = readFileSync9(path4, "utf-8");
27827
- const value = import_comment_json6.parse(raw);
28021
+ const raw = readFileSync10(path4, "utf-8");
28022
+ const value = import_comment_json7.parse(raw);
27828
28023
  return { value };
27829
28024
  } catch (error51) {
27830
28025
  return { value: null, error: error51 instanceof Error ? error51.message : String(error51) };
@@ -27846,7 +28041,7 @@ function configHasPluginEntry(config2) {
27846
28041
  }
27847
28042
  function parseHistorianDumpMeta(path4) {
27848
28043
  try {
27849
- const xml = readFileSync9(path4, "utf-8");
28044
+ const xml = readFileSync10(path4, "utf-8");
27850
28045
  const parsed = parseCompartmentOutput(xml);
27851
28046
  const factCountByCategory = {};
27852
28047
  for (const fact of parsed.facts) {
@@ -27878,14 +28073,12 @@ function parseHistorianDumpMeta(path4) {
27878
28073
  return { error: error51 instanceof Error ? error51.message : String(error51) };
27879
28074
  }
27880
28075
  }
27881
- function collectHistorianDumps() {
27882
- const dir = join13(tmpdir3(), "magic-context-historian");
27883
- if (!existsSync14(dir)) {
27884
- return { dir, count: 0, recent: [] };
27885
- }
28076
+ function listDumpsInDir(dir, limit) {
28077
+ if (!existsSync14(dir))
28078
+ return { count: 0, recent: [] };
27886
28079
  try {
27887
28080
  const entries = readdirSync2(dir).filter((name) => name.endsWith(".xml")).map((name) => {
27888
- const stat = statSync2(join13(dir, name));
28081
+ const stat = statSync2(join12(dir, name));
27889
28082
  return {
27890
28083
  name,
27891
28084
  mtime: stat.mtimeMs,
@@ -27893,8 +28086,8 @@ function collectHistorianDumps() {
27893
28086
  };
27894
28087
  }).sort((a, b2) => b2.mtime - a.mtime);
27895
28088
  const now = Date.now();
27896
- const recent = entries.slice(0, 5).map((entry) => {
27897
- const meta3 = parseHistorianDumpMeta(join13(dir, entry.name));
28089
+ const recent = entries.slice(0, limit).map((entry) => {
28090
+ const meta3 = parseHistorianDumpMeta(join12(dir, entry.name));
27898
28091
  const summary = {
27899
28092
  name: entry.name,
27900
28093
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -27907,13 +28100,84 @@ function collectHistorianDumps() {
27907
28100
  }
27908
28101
  return summary;
27909
28102
  });
27910
- return { dir, count: entries.length, recent };
28103
+ return { count: entries.length, recent };
27911
28104
  } catch {
27912
- return { dir, count: 0, recent: [] };
28105
+ return { count: 0, recent: [] };
28106
+ }
28107
+ }
28108
+ function collectHistorianDumps(recentSessions) {
28109
+ const buckets = new Map;
28110
+ for (const session of recentSessions) {
28111
+ const dir = session.directory;
28112
+ if (!dir)
28113
+ continue;
28114
+ const projectHistorianDir = getProjectMagicContextHistorianDir(dir);
28115
+ const listing = listDumpsInDir(projectHistorianDir, 5);
28116
+ const existing = buckets.get(dir);
28117
+ if (existing) {
28118
+ if (!existing.sessionIds.includes(session.sessionId)) {
28119
+ existing.sessionIds.push(session.sessionId);
28120
+ }
28121
+ continue;
28122
+ }
28123
+ if (listing.count === 0)
28124
+ continue;
28125
+ buckets.set(dir, {
28126
+ directory: dir,
28127
+ primarySessionId: session.sessionId,
28128
+ sessionIds: [session.sessionId],
28129
+ count: listing.count,
28130
+ recent: listing.recent
28131
+ });
28132
+ }
28133
+ const legacyDir = getMagicContextHistorianDir2("opencode");
28134
+ const legacyListing = listDumpsInDir(legacyDir, 5);
28135
+ return {
28136
+ byProject: [...buckets.values()],
28137
+ legacyDumps: {
28138
+ dir: legacyDir,
28139
+ count: legacyListing.count,
28140
+ recent: legacyListing.recent
28141
+ }
28142
+ };
28143
+ }
28144
+ async function collectRecentSessions() {
28145
+ const opencodeDbPath = join12(homedir10(), ".local", "share", "opencode", "opencode.db");
28146
+ if (!existsSync14(opencodeDbPath))
28147
+ return [];
28148
+ if (typeof globalThis.Bun === "undefined") {
28149
+ return [];
28150
+ }
28151
+ let DatabaseClass;
28152
+ try {
28153
+ const mod = await new Function("p", "return import(p)")("bun:sqlite");
28154
+ DatabaseClass = mod.Database;
28155
+ } catch {
28156
+ return [];
28157
+ }
28158
+ let db = null;
28159
+ try {
28160
+ db = new DatabaseClass(opencodeDbPath, { readonly: true });
28161
+ const rows = db.prepare("SELECT id, directory, title, time_updated FROM session " + "WHERE time_archived IS NULL AND parent_id IS NULL " + "ORDER BY time_updated DESC LIMIT 5").all();
28162
+ return rows.flatMap((row) => {
28163
+ const sessionId = typeof row.id === "string" ? row.id : null;
28164
+ const directory = typeof row.directory === "string" ? row.directory : null;
28165
+ if (!sessionId || !directory)
28166
+ return [];
28167
+ const title = typeof row.title === "string" ? row.title : "";
28168
+ const lastActiveAt = typeof row.time_updated === "number" ? new Date(row.time_updated).toISOString() : "";
28169
+ return [{ sessionId, title, directory, lastActiveAt }];
28170
+ });
28171
+ } catch {
28172
+ return [];
28173
+ } finally {
28174
+ try {
28175
+ db?.close();
28176
+ } catch {}
27913
28177
  }
27914
28178
  }
27915
28179
  async function collectHistorianFailures(storageDirPath) {
27916
- const contextDbPath = join13(storageDirPath, "context.db");
28180
+ const contextDbPath = join12(storageDirPath, "context.db");
27917
28181
  if (!existsSync14(contextDbPath))
27918
28182
  return [];
27919
28183
  if (typeof globalThis.Bun === "undefined") {
@@ -27935,7 +28199,7 @@ async function collectHistorianFailures(storageDirPath) {
27935
28199
  const failureCount = typeof row.historian_failure_count === "number" ? row.historian_failure_count : 0;
27936
28200
  const rawError = typeof row.historian_last_error === "string" ? row.historian_last_error : "";
27937
28201
  const lastAt = typeof row.historian_last_failure_at === "number" ? new Date(row.historian_last_failure_at).toISOString() : "";
27938
- const lastError = sanitizeString(rawError.replace(/\s+/g, " ").trim().slice(0, 400));
28202
+ const lastError = sanitizeDiagnosticText(rawError.replace(/\s+/g, " ").trim().slice(0, 400));
27939
28203
  return { sessionId, failureCount, lastError, lastFailureAt: lastAt };
27940
28204
  });
27941
28205
  } catch {
@@ -27953,10 +28217,11 @@ async function collectDiagnostics() {
27953
28217
  const tuiConfig = readConfig2(configPaths.tuiConfig);
27954
28218
  const magicContextConfig = readConfig2(configPaths.magicContextConfig);
27955
28219
  const storageDirPath = getStorageDir();
27956
- const contextDbPath = join13(storageDirPath, "context.db");
27957
- const logPath = join13(tmpdir3(), "magic-context.log");
28220
+ const contextDbPath = join12(storageDirPath, "context.db");
28221
+ const logPath = getMagicContextLogPath2("opencode");
27958
28222
  const logFileSize = existsSync14(logPath) ? statSync2(logPath).size : 0;
27959
28223
  const conflictResult = detectConflicts(process.cwd());
28224
+ const recentSessions = await collectRecentSessions();
27960
28225
  return {
27961
28226
  timestamp: new Date().toISOString(),
27962
28227
  platform: process.platform,
@@ -27988,7 +28253,8 @@ async function collectDiagnostics() {
27988
28253
  exists: existsSync14(logPath),
27989
28254
  sizeKb: Math.round(logFileSize / 1024)
27990
28255
  },
27991
- historianDumps: collectHistorianDumps(),
28256
+ recentSessions,
28257
+ historianDumps: collectHistorianDumps(recentSessions),
27992
28258
  historianFailures: await collectHistorianFailures(storageDirPath)
27993
28259
  };
27994
28260
  }
@@ -28022,10 +28288,25 @@ function renderDiagnosticsMarkdown(report) {
28022
28288
  context_db_size: formatBytes(report.storageDir.contextDbSizeBytes)
28023
28289
  };
28024
28290
  const historianDumps = {
28025
- dir: sanitizeString(report.historianDumps.dir),
28026
- count: report.historianDumps.count,
28027
- recent: report.historianDumps.recent
28291
+ byProject: report.historianDumps.byProject.map((bucket) => ({
28292
+ directory: sanitizeString(bucket.directory),
28293
+ primarySessionId: bucket.primarySessionId,
28294
+ sessionIds: bucket.sessionIds,
28295
+ count: bucket.count,
28296
+ recent: bucket.recent
28297
+ })),
28298
+ legacyDumps: {
28299
+ dir: sanitizeString(report.historianDumps.legacyDumps.dir),
28300
+ count: report.historianDumps.legacyDumps.count,
28301
+ recent: report.historianDumps.legacyDumps.recent
28302
+ }
28028
28303
  };
28304
+ const recentSessions = report.recentSessions.map((session) => ({
28305
+ sessionId: session.sessionId,
28306
+ title: session.title,
28307
+ directory: sanitizeString(session.directory),
28308
+ lastActiveAt: session.lastActiveAt
28309
+ }));
28029
28310
  return [
28030
28311
  `- Timestamp: ${report.timestamp}`,
28031
28312
  `- Plugin: v${report.pluginVersion}`,
@@ -28044,7 +28325,7 @@ function renderDiagnosticsMarkdown(report) {
28044
28325
  "",
28045
28326
  "### magic-context.jsonc flags",
28046
28327
  "```jsonc",
28047
- JSON.stringify(report.magicContextConfig.flags, null, 2),
28328
+ JSON.stringify(sanitizeConfigValue(report.magicContextConfig.flags), null, 2),
28048
28329
  "```",
28049
28330
  "",
28050
28331
  "### Plugin cache",
@@ -28056,15 +28337,24 @@ function renderDiagnosticsMarkdown(report) {
28056
28337
  "```json",
28057
28338
  JSON.stringify(storage, null, 2),
28058
28339
  "```",
28340
+ "",
28341
+ "### Recent sessions",
28342
+ recentSessions.length === 0 ? "_No recent OpenCode sessions found (or OpenCode DB unavailable on this runtime)._" : ["```json", JSON.stringify(recentSessions, null, 2), "```"].join(`
28343
+ `),
28059
28344
  "",
28060
28345
  "### Historian dumps",
28061
28346
  "(Metadata only — XML content is not included in this report.)",
28347
+ "Dumps are stored per-project under `<project>/.opencode/magic-context/historian/`.",
28062
28348
  "```json",
28063
28349
  JSON.stringify(historianDumps, null, 2),
28064
28350
  "```",
28065
28351
  "",
28066
28352
  "### Historian failures (session_meta)",
28067
- report.historianFailures.length === 0 ? "_No sessions with historian failures._" : ["```json", JSON.stringify(report.historianFailures, null, 2), "```"].join(`
28353
+ report.historianFailures.length === 0 ? "_No sessions with historian failures._" : [
28354
+ "```json",
28355
+ JSON.stringify(sanitizeConfigValue(report.historianFailures), null, 2),
28356
+ "```"
28357
+ ].join(`
28068
28358
  `),
28069
28359
  "",
28070
28360
  "### Log file",
@@ -28074,45 +28364,24 @@ function renderDiagnosticsMarkdown(report) {
28074
28364
  ].join(`
28075
28365
  `);
28076
28366
  }
28077
- var import_comment_json6, PLUGIN_NAME5 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY_WITH_VERSION;
28367
+ var import_comment_json7, PLUGIN_NAME5 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY_WITH_VERSION;
28078
28368
  var init_diagnostics_opencode = __esm(() => {
28079
28369
  init_compartment_parser();
28080
28370
  init_conflict_detector();
28081
28371
  init_data_path();
28082
28372
  init_opencode_helpers();
28083
28373
  init_paths();
28084
- import_comment_json6 = __toESM(require_src2(), 1);
28374
+ init_redaction();
28375
+ import_comment_json7 = __toESM(require_src2(), 1);
28085
28376
  PLUGIN_ENTRY_WITH_VERSION = `${PLUGIN_NAME5}@latest`;
28086
28377
  });
28087
28378
 
28088
28379
  // src/lib/logs-opencode.ts
28089
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync9 } from "node:fs";
28090
- import { homedir as homedir10, userInfo as userInfo2 } from "node:os";
28091
- import { join as join14 } from "node:path";
28092
- function escapeRegex3(value) {
28093
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
28094
- }
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";
28095
28383
  function sanitizeLogContent(content) {
28096
- const home = homedir10();
28097
- const username = userInfo2().username;
28098
- let sanitized = content;
28099
- if (home) {
28100
- sanitized = sanitized.replace(new RegExp(escapeRegex3(home), "g"), "~");
28101
- }
28102
- sanitized = sanitized.replace(/\/Users\/[^/]+\//g, "/Users/<USER>/");
28103
- sanitized = sanitized.replace(/\/home\/[^/]+\//g, "/home/<USER>/");
28104
- sanitized = sanitized.replace(/C:\\Users\\[^\\]+\\/g, "C:\\Users\\<USER>\\");
28105
- if (username) {
28106
- sanitized = sanitized.replace(new RegExp(escapeRegex3(username), "g"), "<USER>");
28107
- }
28108
- for (const { pattern, replacement } of SECRET_PATTERNS) {
28109
- if (typeof replacement === "string") {
28110
- sanitized = sanitized.replace(pattern, replacement);
28111
- } else {
28112
- sanitized = sanitized.replace(pattern, replacement);
28113
- }
28114
- }
28115
- return sanitized;
28384
+ return sanitizeDiagnosticText(content);
28116
28385
  }
28117
28386
  function formatTimestamp(date5) {
28118
28387
  const pad = (value) => String(value).padStart(2, "0");
@@ -28139,16 +28408,28 @@ function extractHistorianFailureLines(sanitized, limit = 30) {
28139
28408
  }
28140
28409
  return matches.reverse();
28141
28410
  }
28142
- async function bundleIssueReport(report, description, _title) {
28411
+ function filterLogLinesBySession(lines, sessionId) {
28412
+ if (!sessionId)
28413
+ return lines;
28414
+ const otherSessionPattern = /\bses_[A-Za-z0-9]{8,32}\b/g;
28415
+ return lines.filter((line) => {
28416
+ const matches = line.match(otherSessionPattern);
28417
+ if (!matches)
28418
+ return true;
28419
+ return matches.every((id) => id === sessionId);
28420
+ });
28421
+ }
28422
+ async function bundleIssueReport(report, description, _title, sessionFilter = null) {
28143
28423
  const LOG_TAIL_LINES = 400;
28144
- const logLines = report.logFile.exists ? readFileSync10(report.logFile.path, "utf-8").split(/\r?\n/) : [];
28424
+ const allLogLines = report.logFile.exists ? readFileSync11(report.logFile.path, "utf-8").split(/\r?\n/) : [];
28425
+ const logLines = filterLogLinesBySession(allLogLines, sessionFilter);
28145
28426
  const recentLog = sanitizeLogContent(logLines.slice(-LOG_TAIL_LINES).join(`
28146
28427
  `)).trim();
28147
28428
  const historianScanWindow = sanitizeLogContent(logLines.slice(-4000).join(`
28148
28429
  `));
28149
28430
  const historianFailureLines = extractHistorianFailureLines(historianScanWindow, 30);
28150
- const configBody = JSON.stringify(report.magicContextConfig.flags, null, 2);
28151
- const sanitizedConfigPath = report.configPaths.magicContextConfig.replace(homedir10(), "~");
28431
+ const configBody = JSON.stringify(sanitizeConfigValue(report.magicContextConfig.flags), null, 2);
28432
+ const sanitizedConfigPath = report.configPaths.magicContextConfig.replace(homedir11(), "~");
28152
28433
  const bodyMarkdown = [
28153
28434
  "## Description",
28154
28435
  description,
@@ -28179,81 +28460,15 @@ async function bundleIssueReport(report, description, _title) {
28179
28460
  "```"
28180
28461
  ].join(`
28181
28462
  `);
28182
- const path4 = join14(process.cwd(), `magic-context-issue-${formatTimestamp(new Date)}.md`);
28463
+ const path4 = join13(process.cwd(), `magic-context-issue-${formatTimestamp(new Date)}.md`);
28183
28464
  writeFileSync9(path4, `${bodyMarkdown}
28184
28465
  `);
28185
28466
  return { path: path4, bodyMarkdown };
28186
28467
  }
28187
- var SECRET_PATTERNS, HISTORIAN_LOG_PATTERNS;
28468
+ var HISTORIAN_LOG_PATTERNS;
28188
28469
  var init_logs_opencode = __esm(() => {
28189
28470
  init_diagnostics_opencode();
28190
- SECRET_PATTERNS = [
28191
- {
28192
- name: "anthropic_api_key",
28193
- pattern: /\bsk-ant-(?:api03-)?[A-Za-z0-9_-]{32,}/g,
28194
- replacement: "<ANTHROPIC_API_KEY_REDACTED>"
28195
- },
28196
- {
28197
- name: "openai_api_key",
28198
- pattern: /\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/g,
28199
- replacement: "<OPENAI_API_KEY_REDACTED>"
28200
- },
28201
- {
28202
- name: "github_pat_fine_grained",
28203
- pattern: /\bgithub_pat_[A-Za-z0-9_]{20,}/g,
28204
- replacement: "<GITHUB_PAT_REDACTED>"
28205
- },
28206
- {
28207
- name: "github_token_classic",
28208
- pattern: /\b(?:gh[opsu]|ghr)_[A-Za-z0-9]{30,}/g,
28209
- replacement: "<GITHUB_TOKEN_REDACTED>"
28210
- },
28211
- {
28212
- name: "huggingface_token",
28213
- pattern: /\bhf_[A-Za-z0-9]{30,}/g,
28214
- replacement: "<HUGGINGFACE_TOKEN_REDACTED>"
28215
- },
28216
- {
28217
- name: "aws_access_key_id",
28218
- pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
28219
- replacement: "<AWS_ACCESS_KEY_ID_REDACTED>"
28220
- },
28221
- {
28222
- name: "aws_secret_access_key",
28223
- pattern: /\b(aws[_-]?secret[_-]?access[_-]?key\s*[=:]\s*)([A-Za-z0-9/+=]{40})\b/gi,
28224
- replacement: (_full, prefix) => `${prefix}<AWS_SECRET_REDACTED>`
28225
- },
28226
- {
28227
- name: "slack_token",
28228
- pattern: /\bxox[abprsuvc]-[A-Za-z0-9-]{10,}/g,
28229
- replacement: "<SLACK_TOKEN_REDACTED>"
28230
- },
28231
- {
28232
- name: "google_api_key",
28233
- pattern: /\bAIza[A-Za-z0-9_-]{35}\b/g,
28234
- replacement: "<GOOGLE_API_KEY_REDACTED>"
28235
- },
28236
- {
28237
- name: "secret_env_assignment",
28238
- pattern: /\b([A-Z][A-Z0-9_]*(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|PRIVATE[_-]?KEY))\s*=\s*([^\s'"]+)/g,
28239
- replacement: (_full, key) => `${key}=<REDACTED>`
28240
- },
28241
- {
28242
- name: "secret_json_assignment",
28243
- pattern: /("(?:api[_-]?key|access[_-]?token|auth[_-]?token|bearer[_-]?token|client[_-]?secret|password|private[_-]?key|secret[_-]?key)"\s*:\s*)"([^"]+)"/gi,
28244
- replacement: (_full, prefix) => `${prefix}"<REDACTED>"`
28245
- },
28246
- {
28247
- name: "bearer_token",
28248
- pattern: /\b(Authorization\s*:\s*Bearer\s+)([A-Za-z0-9._~+/=-]{16,})/gi,
28249
- replacement: (_full, prefix) => `${prefix}<BEARER_TOKEN_REDACTED>`
28250
- },
28251
- {
28252
- name: "jwt_token",
28253
- pattern: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
28254
- replacement: "<JWT_REDACTED>"
28255
- }
28256
- ];
28471
+ init_redaction();
28257
28472
  HISTORIAN_LOG_PATTERNS = [
28258
28473
  /historian failure:/,
28259
28474
  /historian failure recorded:/,
@@ -28267,10 +28482,10 @@ var init_logs_opencode = __esm(() => {
28267
28482
 
28268
28483
  // src/commands/doctor-opencode.ts
28269
28484
  import { execSync as execSync2, spawnSync as spawnSync2 } from "node:child_process";
28270
- import { existsSync as existsSync15, readdirSync as readdirSync3, readFileSync as readFileSync11, rmSync, statSync as statSync3, writeFileSync as writeFileSync10 } from "node:fs";
28485
+ import { existsSync as existsSync15, readFileSync as readFileSync12, rmSync, statSync as statSync3, writeFileSync as writeFileSync10 } from "node:fs";
28271
28486
  import { createRequire as createRequire4 } from "node:module";
28272
- import { homedir as homedir11, tmpdir as tmpdir4 } from "node:os";
28273
- import { join as join15 } from "node:path";
28487
+ import { homedir as homedir12 } from "node:os";
28488
+ import { join as join14 } from "node:path";
28274
28489
  async function fetchNpmLatest(pkg, timeoutMs = 5000) {
28275
28490
  try {
28276
28491
  const controller = new AbortController;
@@ -28320,15 +28535,15 @@ function compareVersions(a, b2) {
28320
28535
  }
28321
28536
  async function clearPluginCache(force = false) {
28322
28537
  const cacheDir = getOpenCodeCacheDir();
28323
- const pluginCacheDir = join15(cacheDir, "packages", PLUGIN_ENTRY_WITH_VERSION2);
28538
+ const pluginCacheDir = join14(cacheDir, "packages", PLUGIN_ENTRY_WITH_VERSION2);
28324
28539
  if (!existsSync15(pluginCacheDir)) {
28325
28540
  return { action: "not_found", path: pluginCacheDir };
28326
28541
  }
28327
28542
  let cachedVersion;
28328
28543
  try {
28329
- const installedPkgPath = join15(pluginCacheDir, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
28544
+ const installedPkgPath = join14(pluginCacheDir, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
28330
28545
  if (existsSync15(installedPkgPath)) {
28331
- const pkg = JSON.parse(readFileSync11(installedPkgPath, "utf-8"));
28546
+ const pkg = JSON.parse(readFileSync12(installedPkgPath, "utf-8"));
28332
28547
  if (typeof pkg?.version === "string") {
28333
28548
  cachedVersion = pkg.version;
28334
28549
  }
@@ -28403,7 +28618,27 @@ async function runIssueFlow() {
28403
28618
  s.start("Collecting diagnostics");
28404
28619
  try {
28405
28620
  const report = await collectDiagnostics();
28406
- const bundled = await bundleIssueReport(report, description, title);
28621
+ s.stop("Diagnostics collected");
28622
+ let sessionFilter = null;
28623
+ if (report.recentSessions.length > 1) {
28624
+ const choice = await selectOne("Which session is this issue about? (filters log lines from other sessions)", [
28625
+ ...report.recentSessions.map((session, index) => {
28626
+ const displayTitle = session.title.trim() || "(no title)";
28627
+ const truncatedTitle = displayTitle.length > 50 ? `${displayTitle.slice(0, 47)}...` : displayTitle;
28628
+ return {
28629
+ label: `${truncatedTitle} — ${session.sessionId}${index === 0 ? " (most recent)" : ""}`,
28630
+ value: session.sessionId
28631
+ };
28632
+ }),
28633
+ {
28634
+ label: "All sessions (no filtering)",
28635
+ value: "__all__"
28636
+ }
28637
+ ]);
28638
+ sessionFilter = choice === "__all__" ? null : choice;
28639
+ }
28640
+ s.start("Bundling issue report");
28641
+ const bundled = await bundleIssueReport(report, description, title, sessionFilter);
28407
28642
  s.stop(`Report written to ${bundled.path}`);
28408
28643
  const shouldSubmit = await confirm("Submit this issue on GitHub now?", true);
28409
28644
  if (shouldSubmit && isGhInstalled()) {
@@ -28445,7 +28680,7 @@ async function checkEmbeddingConfig(magicContextConfigPath) {
28445
28680
  }
28446
28681
  let rawText;
28447
28682
  try {
28448
- rawText = readFileSync11(magicContextConfigPath, "utf-8");
28683
+ rawText = readFileSync12(magicContextConfigPath, "utf-8");
28449
28684
  } catch {
28450
28685
  log.warn("Could not read magic-context.jsonc for embedding check");
28451
28686
  return { issues: 1 };
@@ -28456,7 +28691,7 @@ async function checkEmbeddingConfig(magicContextConfigPath) {
28456
28691
  });
28457
28692
  let parsedConfig;
28458
28693
  try {
28459
- parsedConfig = import_comment_json7.parse(substituted.text);
28694
+ parsedConfig = import_comment_json8.parse(substituted.text);
28460
28695
  } catch (error51) {
28461
28696
  log.warn(`Embedding check skipped — could not parse magic-context.jsonc: ${error51 instanceof Error ? error51.message : String(error51)}`);
28462
28697
  return { issues: 1 };
@@ -28596,12 +28831,12 @@ async function runDoctor(options = {}) {
28596
28831
  if (existsSync15(paths.magicContextConfig)) {
28597
28832
  pass(`Magic Context config: ${paths.magicContextConfig}`);
28598
28833
  try {
28599
- const raw = readFileSync11(paths.magicContextConfig, "utf-8");
28834
+ const raw = readFileSync12(paths.magicContextConfig, "utf-8");
28600
28835
  const substituted = substituteConfigVariables({
28601
28836
  text: raw,
28602
28837
  configPath: paths.magicContextConfig
28603
28838
  }).text;
28604
- import_comment_json7.parse(substituted);
28839
+ import_comment_json8.parse(substituted);
28605
28840
  pass("magic-context.jsonc parses as valid JSONC");
28606
28841
  } catch (err) {
28607
28842
  fail(`magic-context.jsonc parse failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -28623,8 +28858,8 @@ async function runDoctor(options = {}) {
28623
28858
  }
28624
28859
  if (existsSync15(paths.magicContextConfig)) {
28625
28860
  try {
28626
- const mcRaw = readFileSync11(paths.magicContextConfig, "utf-8");
28627
- const mcConfig = import_comment_json7.parse(mcRaw);
28861
+ const mcRaw = readFileSync12(paths.magicContextConfig, "utf-8");
28862
+ const mcConfig = import_comment_json8.parse(mcRaw);
28628
28863
  let mcChanged = false;
28629
28864
  const experimental = mcConfig.experimental;
28630
28865
  if (experimental && "compaction_markers" in experimental) {
@@ -28699,7 +28934,7 @@ async function runDoctor(options = {}) {
28699
28934
  fixed++;
28700
28935
  }
28701
28936
  if (mcChanged) {
28702
- writeFileSync10(paths.magicContextConfig, `${import_comment_json7.stringify(mcConfig, null, 2)}
28937
+ writeFileSync10(paths.magicContextConfig, `${import_comment_json8.stringify(mcConfig, null, 2)}
28703
28938
  `);
28704
28939
  }
28705
28940
  } catch {
@@ -28708,8 +28943,8 @@ async function runDoctor(options = {}) {
28708
28943
  }
28709
28944
  if (paths.opencodeConfigFormat !== "none") {
28710
28945
  try {
28711
- const raw = readFileSync11(paths.opencodeConfig, "utf-8");
28712
- const config2 = import_comment_json7.parse(raw);
28946
+ const raw = readFileSync12(paths.opencodeConfig, "utf-8");
28947
+ const config2 = import_comment_json8.parse(raw);
28713
28948
  const rawPlugins = Array.isArray(config2?.plugin) ? config2.plugin : [];
28714
28949
  const existingIdx = rawPlugins.findIndex((entry) => matchesPluginEntry(entry, PLUGIN_NAME6) || isDevPathPluginEntry(entry));
28715
28950
  const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
@@ -28740,7 +28975,7 @@ async function runDoctor(options = {}) {
28740
28975
  rawPlugins[existingIdx] = PLUGIN_ENTRY_WITH_VERSION2;
28741
28976
  }
28742
28977
  config2.plugin = rawPlugins;
28743
- writeFileSync10(paths.opencodeConfig, `${import_comment_json7.stringify(config2, null, 2)}
28978
+ writeFileSync10(paths.opencodeConfig, `${import_comment_json8.stringify(config2, null, 2)}
28744
28979
  `);
28745
28980
  pass(`Upgraded plugin entry in ${configName}: ${oldEntryStr} → ${PLUGIN_ENTRY_WITH_VERSION2}`);
28746
28981
  fixed++;
@@ -28749,7 +28984,7 @@ async function runDoctor(options = {}) {
28749
28984
  } else {
28750
28985
  rawPlugins.push(PLUGIN_ENTRY_WITH_VERSION2);
28751
28986
  config2.plugin = rawPlugins;
28752
- writeFileSync10(paths.opencodeConfig, `${import_comment_json7.stringify(config2, null, 2)}
28987
+ writeFileSync10(paths.opencodeConfig, `${import_comment_json8.stringify(config2, null, 2)}
28753
28988
  `);
28754
28989
  pass(`Added plugin to ${configName}`);
28755
28990
  fixed++;
@@ -28782,8 +29017,8 @@ async function runDoctor(options = {}) {
28782
29017
  fixed++;
28783
29018
  } else if (existsSync15(paths.tuiConfig)) {
28784
29019
  try {
28785
- const tuiRaw = readFileSync11(paths.tuiConfig, "utf-8");
28786
- const tuiConfig = import_comment_json7.parse(tuiRaw);
29020
+ const tuiRaw = readFileSync12(paths.tuiConfig, "utf-8");
29021
+ const tuiConfig = import_comment_json8.parse(tuiRaw);
28787
29022
  const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
28788
29023
  const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, PLUGIN_NAME6) || isDevPathPluginEntry(entry));
28789
29024
  const tuiEntryAsString = (entry) => {
@@ -28811,7 +29046,7 @@ async function runDoctor(options = {}) {
28811
29046
  tuiRawPlugins[tuiIdx] = PLUGIN_ENTRY_WITH_VERSION2;
28812
29047
  }
28813
29048
  tuiConfig.plugin = tuiRawPlugins;
28814
- writeFileSync10(paths.tuiConfig, `${import_comment_json7.stringify(tuiConfig, null, 2)}
29049
+ writeFileSync10(paths.tuiConfig, `${import_comment_json8.stringify(tuiConfig, null, 2)}
28815
29050
  `);
28816
29051
  pass(`Upgraded TUI plugin: ${tuiEntryStr} → ${PLUGIN_ENTRY_WITH_VERSION2}`);
28817
29052
  fixed++;
@@ -28830,8 +29065,8 @@ async function runDoctor(options = {}) {
28830
29065
  }
28831
29066
  if (existsSync15(paths.magicContextConfig)) {
28832
29067
  try {
28833
- const mcRaw = readFileSync11(paths.magicContextConfig, "utf-8");
28834
- const mcConfig = import_comment_json7.parse(mcRaw);
29068
+ const mcRaw = readFileSync12(paths.magicContextConfig, "utf-8");
29069
+ const mcConfig = import_comment_json8.parse(mcRaw);
28835
29070
  const dreamerObj = mcConfig?.dreamer;
28836
29071
  const dreamerEnabled = dreamerObj?.enabled === true;
28837
29072
  const userMemObj = dreamerObj?.user_memories;
@@ -28848,7 +29083,7 @@ async function runDoctor(options = {}) {
28848
29083
  failCount += embeddingCheck.issues;
28849
29084
  else
28850
29085
  passCount++;
28851
- const dbPath = join15(getMagicContextStorageDir(), "context.db");
29086
+ const dbPath = join14(getMagicContextStorageDir(), "context.db");
28852
29087
  if (!existsSync15(dbPath)) {
28853
29088
  log.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
28854
29089
  } else {
@@ -28910,10 +29145,10 @@ async function runDoctor(options = {}) {
28910
29145
  }
28911
29146
  {
28912
29147
  const ageWarnings = [];
28913
- const npmrcPath = join15(homedir11(), ".npmrc");
29148
+ const npmrcPath = join14(homedir12(), ".npmrc");
28914
29149
  if (existsSync15(npmrcPath)) {
28915
29150
  try {
28916
- const npmrc = readFileSync11(npmrcPath, "utf-8");
29151
+ const npmrc = readFileSync12(npmrcPath, "utf-8");
28917
29152
  for (const line of npmrc.split(`
28918
29153
  `)) {
28919
29154
  const trimmed = line.trim();
@@ -28936,7 +29171,7 @@ async function runDoctor(options = {}) {
28936
29171
  issues++;
28937
29172
  }
28938
29173
  }
28939
- const logPath = join15(tmpdir4(), "magic-context.log");
29174
+ const logPath = getMagicContextLogPath2("opencode");
28940
29175
  if (existsSync15(logPath)) {
28941
29176
  const logStat = statSync3(logPath);
28942
29177
  const sizeKb = (logStat.size / 1024).toFixed(0);
@@ -28944,25 +29179,27 @@ async function runDoctor(options = {}) {
28944
29179
  } else {
28945
29180
  log.info(`Log file: ${logPath} (not yet created)`);
28946
29181
  }
28947
- const historianDumpDir = join15(tmpdir4(), "magic-context-historian");
28948
- if (existsSync15(historianDumpDir)) {
28949
- try {
28950
- const dumps = readdirSync3(historianDumpDir).filter((f) => f.endsWith(".xml")).map((f) => ({
28951
- name: f,
28952
- mtime: statSync3(join15(historianDumpDir, f)).mtimeMs
28953
- })).sort((a, b2) => b2.mtime - a.mtime);
28954
- if (dumps.length > 0) {
28955
- warn(`Historian debug dumps: ${dumps.length} file(s) in ${historianDumpDir}`);
28956
- for (const dump of dumps.slice(0, 3)) {
28957
- const age = Math.round((Date.now() - dump.mtime) / 60000);
28958
- const ageStr = age < 60 ? `${age}m ago` : `${Math.round(age / 60)}h ago`;
28959
- log.info(` ${dump.name} (${ageStr})`);
28960
- }
28961
- if (dumps.length > 3) {
28962
- log.info(` ... and ${dumps.length - 3} more`);
28963
- }
29182
+ const diagnostics = await collectDiagnostics();
29183
+ const dumpBuckets = diagnostics.historianDumps.byProject;
29184
+ if (dumpBuckets.length > 0) {
29185
+ const totalCount = dumpBuckets.reduce((sum, b2) => sum + b2.count, 0);
29186
+ const sessionCount = dumpBuckets.length;
29187
+ warn(`Historian debug dumps: ${totalCount} file(s) across ${sessionCount} project(s)`);
29188
+ for (const bucket of dumpBuckets) {
29189
+ log.info(` [${bucket.directory}] ${bucket.count} file(s)`);
29190
+ for (const dump of bucket.recent.slice(0, 3)) {
29191
+ const age = dump.ageMinutes;
29192
+ const ageStr = age < 60 ? `${age}m ago` : `${Math.round(age / 60)}h ago`;
29193
+ log.info(` ${dump.name} (${ageStr})`);
28964
29194
  }
28965
- } catch {}
29195
+ if (bucket.count > 3) {
29196
+ log.info(` ... and ${bucket.count - 3} more`);
29197
+ }
29198
+ }
29199
+ }
29200
+ const legacy = diagnostics.historianDumps.legacyDumps;
29201
+ if (legacy.count > 0) {
29202
+ log.info(`Legacy historian dumps (pre-v0.18.x): ${legacy.count} file(s) in ${legacy.dir}`);
28966
29203
  }
28967
29204
  if (paths.omoConfig) {
28968
29205
  log.info(`OMO config found: ${paths.omoConfig}`);
@@ -28981,7 +29218,7 @@ async function runDoctor(options = {}) {
28981
29218
  }
28982
29219
  return 0;
28983
29220
  }
28984
- var import_comment_json7, PLUGIN_NAME6 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY_WITH_VERSION2, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
29221
+ var import_comment_json8, PLUGIN_NAME6 = "@cortexkit/opencode-magic-context", PLUGIN_ENTRY_WITH_VERSION2, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
28985
29222
  var init_doctor_opencode = __esm(async () => {
28986
29223
  init_config();
28987
29224
  init_variable();
@@ -28996,9 +29233,10 @@ var init_doctor_opencode = __esm(async () => {
28996
29233
  init_paths();
28997
29234
  init_prompts();
28998
29235
  await init_sqlite();
28999
- import_comment_json7 = __toESM(require_src2(), 1);
29236
+ import_comment_json8 = __toESM(require_src2(), 1);
29000
29237
  PLUGIN_ENTRY_WITH_VERSION2 = `${PLUGIN_NAME6}@latest`;
29001
29238
  });
29239
+
29002
29240
  // ../plugin/src/features/magic-context/compartment-storage.ts
29003
29241
  var insertCompartmentStatements, insertFactStatements;
29004
29242
  var init_compartment_storage = __esm(() => {
@@ -29138,7 +29376,7 @@ function binarySearchBytes(sortedArray, key) {
29138
29376
  }
29139
29377
  return -1;
29140
29378
  }
29141
- function escapeRegex4(str) {
29379
+ function escapeRegex3(str) {
29142
29380
  return str.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
29143
29381
  }
29144
29382
  function bytePairMerge(piece, stringRanks, binaryFirstByteIndex) {
@@ -29248,7 +29486,7 @@ var Tokenizer = class {
29248
29486
  };
29249
29487
  this.specialTokenKeys = Object.keys(this.specialTokens);
29250
29488
  this.hasSpecialTokens = this.specialTokenKeys.length > 0;
29251
- this.specialTokensRegex = this.hasSpecialTokens ? new RegExp(this.specialTokenKeys.map(escapeRegex4).join("|"), "g") : null;
29489
+ this.specialTokensRegex = this.hasSpecialTokens ? new RegExp(this.specialTokenKeys.map(escapeRegex3).join("|"), "g") : null;
29252
29490
  this.inverseSpecialTokens = {};
29253
29491
  for (const [text2, rank] of Object.entries(this.specialTokens))
29254
29492
  this.inverseSpecialTokens[rank] = textEncoder.encode(text2);
@@ -29278,7 +29516,7 @@ var Tokenizer = class {
29278
29516
  const allowedSet = new Set(allowedSpecial === "all" ? this.specialTokenKeys : allowedSpecial);
29279
29517
  const disallowedSet = new Set(disallowedSpecial === "all" ? this.specialTokenKeys.filter((x2) => !allowedSet.has(x2)) : disallowedSpecial);
29280
29518
  if (disallowedSet.size > 0) {
29281
- const disallowedRegex = new RegExp([...disallowedSet].map(escapeRegex4).join("|"), "g");
29519
+ const disallowedRegex = new RegExp([...disallowedSet].map(escapeRegex3).join("|"), "g");
29282
29520
  const match = text2.match(disallowedRegex);
29283
29521
  if (match)
29284
29522
  throw new Error(`Text contains disallowed special token: ${match[0]}`);
@@ -161784,6 +162022,9 @@ var init_migrations = __esm(async () => {
161784
162022
  embedding BLOB NOT NULL,
161785
162023
  model_id TEXT NOT NULL,
161786
162024
  created_at INTEGER NOT NULL,
162025
+ -- FK-cascade audit (v12): git_commit_embeddings.sha -> git_commits.sha
162026
+ -- uses ON DELETE CASCADE, so SQLite PRAGMA foreign_keys must be ON on
162027
+ -- every connection and v12 cleans historical orphan rows.
161787
162028
  FOREIGN KEY(sha) REFERENCES git_commits(sha) ON DELETE CASCADE
161788
162029
  );
161789
162030
 
@@ -161923,10 +162164,32 @@ var init_migrations = __esm(async () => {
161923
162164
  db.exec("ALTER TABLE session_meta ADD COLUMN todo_synthetic_state_json TEXT DEFAULT ''");
161924
162165
  }
161925
162166
  }
162167
+ },
162168
+ {
162169
+ version: 12,
162170
+ description: "Clean orphan rows from FK-cascade embedding tables",
162171
+ up: (db) => {
162172
+ const hasTable = (name2) => Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name2));
162173
+ const memoryEmbeddings = hasTable("memory_embeddings") ? db.prepare(`DELETE FROM memory_embeddings
162174
+ WHERE memory_id NOT IN (SELECT id FROM memories)`).run().changes : 0;
162175
+ log2(`[migrations] v12 cleaned ${memoryEmbeddings} orphan memory_embeddings row(s)`);
162176
+ const gitCommitEmbeddings = hasTable("git_commit_embeddings") ? db.prepare(`DELETE FROM git_commit_embeddings
162177
+ WHERE sha NOT IN (SELECT sha FROM git_commits)`).run().changes : 0;
162178
+ log2(`[migrations] v12 cleaned ${gitCommitEmbeddings} orphan git_commit_embeddings row(s)`);
162179
+ }
162180
+ },
162181
+ {
162182
+ version: 13,
162183
+ description: "Add pending_compaction_marker_state column for deferred marker drain",
162184
+ up: (db) => {
162185
+ const cols = db.prepare("PRAGMA table_info(session_meta)").all();
162186
+ if (!cols.some((c2) => c2.name === "pending_compaction_marker_state")) {
162187
+ db.exec("ALTER TABLE session_meta ADD COLUMN pending_compaction_marker_state TEXT");
162188
+ }
162189
+ }
161926
162190
  }
161927
162191
  ];
161928
162192
  });
161929
-
161930
162193
  // ../plugin/src/features/magic-context/tool-definition-tokens.ts
161931
162194
  function keyFor(providerID, modelID, agentName) {
161932
162195
  const agent = agentName && agentName.length > 0 ? agentName : "default";
@@ -161962,9 +162225,9 @@ var init_tool_definition_tokens = __esm(() => {
161962
162225
 
161963
162226
  // ../plugin/src/features/magic-context/tool-owner-backfill.ts
161964
162227
  import { existsSync as existsSync16 } from "node:fs";
161965
- import { join as join16 } from "node:path";
162228
+ import { join as join15 } from "node:path";
161966
162229
  function resolveOpencodeDbPath() {
161967
- return join16(getDataDir(), "opencode", "opencode.db");
162230
+ return join15(getDataDir(), "opencode", "opencode.db");
161968
162231
  }
161969
162232
  function ensureBackfillStateTable(db) {
161970
162233
  db.exec(`
@@ -162210,23 +162473,23 @@ var init_tool_owner_backfill = __esm(() => {
162210
162473
 
162211
162474
  // ../plugin/src/features/magic-context/storage-db.ts
162212
162475
  import { copyFileSync, cpSync, existsSync as existsSync17, mkdirSync as mkdirSync7 } from "node:fs";
162213
- import { join as join17 } from "node:path";
162476
+ import { join as join16 } from "node:path";
162214
162477
  function resolveDatabasePath() {
162215
162478
  const dbDir = getMagicContextStorageDir();
162216
- return { dbDir, dbPath: join17(dbDir, "context.db") };
162479
+ return { dbDir, dbPath: join16(dbDir, "context.db") };
162217
162480
  }
162218
162481
  function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
162219
162482
  if (existsSync17(targetDbPath))
162220
162483
  return;
162221
162484
  const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
162222
- const legacyDbPath = join17(legacyDir, "context.db");
162485
+ const legacyDbPath = join16(legacyDir, "context.db");
162223
162486
  if (!existsSync17(legacyDbPath))
162224
162487
  return;
162225
162488
  log2(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
162226
162489
  mkdirSync7(targetDbDir, { recursive: true });
162227
162490
  for (const suffix of ["", "-wal", "-shm"]) {
162228
162491
  const src = `${legacyDbPath}${suffix}`;
162229
- const dst = join17(targetDbDir, `context.db${suffix}`);
162492
+ const dst = join16(targetDbDir, `context.db${suffix}`);
162230
162493
  if (existsSync17(src)) {
162231
162494
  try {
162232
162495
  copyFileSync(src, dst);
@@ -162235,8 +162498,8 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
162235
162498
  }
162236
162499
  }
162237
162500
  }
162238
- const legacyModelsDir = join17(legacyDir, "models");
162239
- const targetModelsDir = join17(targetDbDir, "models");
162501
+ const legacyModelsDir = join16(legacyDir, "models");
162502
+ const targetModelsDir = join16(targetDbDir, "models");
162240
162503
  if (existsSync17(legacyModelsDir) && !existsSync17(targetModelsDir)) {
162241
162504
  try {
162242
162505
  cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
@@ -162246,9 +162509,9 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
162246
162509
  }
162247
162510
  }
162248
162511
  function initializeDatabase(db) {
162512
+ db.exec("PRAGMA foreign_keys=ON");
162249
162513
  db.exec("PRAGMA journal_mode=WAL");
162250
162514
  db.exec("PRAGMA busy_timeout=5000");
162251
- db.exec("PRAGMA foreign_keys=ON");
162252
162515
  db.exec(`
162253
162516
  CREATE TABLE IF NOT EXISTS tags (
162254
162517
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -162346,6 +162609,9 @@ function initializeDatabase(db) {
162346
162609
  );
162347
162610
 
162348
162611
  CREATE TABLE IF NOT EXISTS memory_embeddings (
162612
+ -- FK-cascade audit (v12): memory_embeddings.memory_id -> memories.id
162613
+ -- uses ON DELETE CASCADE, so SQLite PRAGMA foreign_keys must be ON on
162614
+ -- every connection and v12 cleans historical orphan rows.
162349
162615
  memory_id INTEGER PRIMARY KEY REFERENCES memories(id) ON DELETE CASCADE,
162350
162616
  embedding BLOB NOT NULL,
162351
162617
  model_id TEXT
@@ -162453,7 +162719,13 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
162453
162719
  system_prompt_hash TEXT DEFAULT '',
162454
162720
  memory_block_cache TEXT DEFAULT '',
162455
162721
  memory_block_count INTEGER DEFAULT 0,
162456
- memory_block_ids TEXT DEFAULT ''
162722
+ memory_block_ids TEXT DEFAULT '',
162723
+ -- pending_compaction_marker_state: intentionally NULLABLE without a
162724
+ -- default. Absence of a deferred marker is SQL NULL; presence is a
162725
+ -- valid JSON blob written via setPendingCompactionMarkerState.
162726
+ -- Excluded from healNullTextColumns. Readers filter IS NOT NULL AND
162727
+ -- != empty-string defensively. Plan v6 section 3.
162728
+ pending_compaction_marker_state TEXT
162457
162729
  );
162458
162730
 
162459
162731
  CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
@@ -162541,6 +162813,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
162541
162813
  ensureColumn(db, "session_meta", "recomp_partial_range_end", "INTEGER DEFAULT 0");
162542
162814
  ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
162543
162815
  ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
162816
+ ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
162544
162817
  ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
162545
162818
  ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
162546
162819
  ensureColumn(db, "source_contents", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
@@ -162772,16 +163045,16 @@ var init_storage = __esm(async () => {
162772
163045
  });
162773
163046
 
162774
163047
  // ../pi-plugin/src/config/index.ts
162775
- import { existsSync as existsSync18, readFileSync as readFileSync12 } from "node:fs";
162776
- import { homedir as homedir12 } from "node:os";
162777
- import { join as join18 } from "node:path";
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";
162778
163051
  function getProjectConfigPaths(cwd) {
162779
- const basePath = join18(cwd, ".pi", CONFIG_FILE_NAME);
163052
+ const basePath = join17(cwd, ".pi", CONFIG_FILE_NAME);
162780
163053
  return [`${basePath}.jsonc`, `${basePath}.json`];
162781
163054
  }
162782
163055
  function getUserConfigPaths() {
162783
- const home = process.env.HOME ?? homedir12();
162784
- const basePath = join18(home, ".pi", "agent", CONFIG_FILE_NAME);
163056
+ const home = process.env.HOME ?? homedir13();
163057
+ const basePath = join17(home, ".pi", "agent", CONFIG_FILE_NAME);
162785
163058
  return [`${basePath}.jsonc`, `${basePath}.json`];
162786
163059
  }
162787
163060
  function resolveFirstExisting(paths) {
@@ -162789,7 +163062,7 @@ function resolveFirstExisting(paths) {
162789
163062
  }
162790
163063
  function loadConfigFile2(path4, scope) {
162791
163064
  try {
162792
- const rawText = readFileSync12(path4, "utf-8");
163065
+ const rawText = readFileSync13(path4, "utf-8");
162793
163066
  const substituted = substituteConfigVariables({
162794
163067
  text: rawText,
162795
163068
  configPath: path4
@@ -162797,7 +163070,7 @@ function loadConfigFile2(path4, scope) {
162797
163070
  return {
162798
163071
  path: path4,
162799
163072
  scope,
162800
- config: import_comment_json8.parse(substituted.text),
163073
+ config: import_comment_json9.parse(substituted.text),
162801
163074
  warnings: substituted.warnings.map((warning) => `${path4}: ${warning}`)
162802
163075
  };
162803
163076
  } catch (error51) {
@@ -162910,19 +163183,19 @@ function loadPiConfig(opts = {}) {
162910
163183
  loadedFromPaths: loadedFiles.map((loaded) => loaded.path)
162911
163184
  };
162912
163185
  }
162913
- var import_comment_json8, CONFIG_FILE_NAME = "magic-context";
163186
+ var import_comment_json9, CONFIG_FILE_NAME = "magic-context";
162914
163187
  var init_config2 = __esm(() => {
162915
163188
  init_magic_context();
162916
163189
  init_variable();
162917
- import_comment_json8 = __toESM(require_src2(), 1);
163190
+ import_comment_json9 = __toESM(require_src2(), 1);
162918
163191
  });
162919
163192
 
162920
163193
  // src/lib/diagnostics-pi.ts
162921
163194
  import { createHash } from "node:crypto";
162922
- import { existsSync as existsSync19, readFileSync as readFileSync13, statSync as statSync4 } from "node:fs";
163195
+ import { existsSync as existsSync19, readdirSync as readdirSync3, readFileSync as readFileSync14, statSync as statSync4 } from "node:fs";
162923
163196
  import { createRequire as createRequire5 } from "node:module";
162924
- import { homedir as homedir13, tmpdir as tmpdir5, userInfo as userInfo3 } from "node:os";
162925
- import { join as join19 } from "node:path";
163197
+ import { homedir as homedir14, userInfo as userInfo2 } from "node:os";
163198
+ import { join as join18 } from "node:path";
162926
163199
  function getSelfVersion3() {
162927
163200
  const req = createRequire5(import.meta.url);
162928
163201
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -162942,29 +163215,29 @@ function fileSize2(path4) {
162942
163215
  return 0;
162943
163216
  }
162944
163217
  }
162945
- function escapeRegex5(value) {
163218
+ function escapeRegex4(value) {
162946
163219
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
162947
163220
  }
162948
163221
  function currentUserHash() {
162949
- const username = userInfo3().username || "unknown";
163222
+ const username = userInfo2().username || "unknown";
162950
163223
  return createHash("sha256").update(username).digest("hex").slice(0, 12);
162951
163224
  }
162952
163225
  function redactSecretString(value) {
162953
163226
  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>");
162954
163227
  }
162955
163228
  function sanitizeString2(value) {
162956
- const home = process.env.HOME || homedir13();
162957
- const username = userInfo3().username;
163229
+ const home = process.env.HOME || homedir14();
163230
+ const username = userInfo2().username;
162958
163231
  const userHash = `<USER:${currentUserHash()}>`;
162959
163232
  let sanitized = redactSecretString(value);
162960
163233
  if (home) {
162961
- sanitized = sanitized.replace(new RegExp(escapeRegex5(home), "g"), "<HOME>");
163234
+ sanitized = sanitized.replace(new RegExp(escapeRegex4(home), "g"), "<HOME>");
162962
163235
  }
162963
163236
  sanitized = sanitized.replace(/\/Users\/[^/]+\//g, `/Users/${userHash}/`);
162964
163237
  sanitized = sanitized.replace(/\/home\/[^/]+\//g, `/home/${userHash}/`);
162965
163238
  sanitized = sanitized.replace(/C:\\Users\\[^\\]+\\/g, `C:\\Users\\${userHash}\\`);
162966
163239
  if (username) {
162967
- sanitized = sanitized.replace(new RegExp(escapeRegex5(username), "g"), userHash);
163240
+ sanitized = sanitized.replace(new RegExp(escapeRegex4(username), "g"), userHash);
162968
163241
  }
162969
163242
  return sanitized;
162970
163243
  }
@@ -162991,7 +163264,7 @@ function readJsonc3(path4) {
162991
163264
  return { value: {} };
162992
163265
  try {
162993
163266
  return {
162994
- value: import_comment_json9.parse(readFileSync13(path4, "utf-8"))
163267
+ value: import_comment_json10.parse(readFileSync14(path4, "utf-8"))
162995
163268
  };
162996
163269
  } catch (error51) {
162997
163270
  return {
@@ -163001,7 +163274,7 @@ function readJsonc3(path4) {
163001
163274
  }
163002
163275
  }
163003
163276
  function getProjectConfigPath(cwd) {
163004
- return join19(cwd, ".pi", "magic-context.jsonc");
163277
+ return join18(cwd, ".pi", "magic-context.jsonc");
163005
163278
  }
163006
163279
  function readConfigDiagnostic(path4) {
163007
163280
  const parsed = readJsonc3(path4);
@@ -163013,10 +163286,153 @@ function readConfigDiagnostic(path4) {
163013
163286
  };
163014
163287
  }
163015
163288
  function packageEntries(settings) {
163016
- return Array.isArray(settings.packages) ? settings.packages.filter((entry) => typeof entry === "string") : [];
163289
+ return Array.isArray(settings.packages) ? settings.packages : [];
163290
+ }
163291
+ function reverseSlugToDirectory(slug) {
163292
+ if (!slug.startsWith("--") || !slug.endsWith("--"))
163293
+ return null;
163294
+ const inner = slug.slice(2, -2);
163295
+ if (!inner)
163296
+ return null;
163297
+ return `/${inner.replace(/-/g, "/")}`;
163298
+ }
163299
+ function collectPiRecentSessions() {
163300
+ const sessionsRoot = join18(homedir14(), ".pi", "agent", "sessions");
163301
+ if (!existsSync19(sessionsRoot))
163302
+ return [];
163303
+ try {
163304
+ const slugs = readdirSync3(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
163305
+ const candidates = [];
163306
+ for (const slug of slugs) {
163307
+ const directory = reverseSlugToDirectory(slug);
163308
+ if (!directory)
163309
+ continue;
163310
+ const slugDir = join18(sessionsRoot, slug);
163311
+ let files;
163312
+ try {
163313
+ files = readdirSync3(slugDir).filter((name2) => name2.endsWith(".jsonl"));
163314
+ } catch {
163315
+ continue;
163316
+ }
163317
+ for (const file2 of files) {
163318
+ try {
163319
+ const mtime = statSync4(join18(slugDir, file2)).mtimeMs;
163320
+ const sessionId = file2.replace(/\.jsonl$/, "");
163321
+ candidates.push({ sessionId, directory, mtime });
163322
+ } catch {}
163323
+ }
163324
+ }
163325
+ candidates.sort((a, b2) => b2.mtime - a.mtime);
163326
+ return candidates.slice(0, 5).map((entry) => ({
163327
+ sessionId: entry.sessionId,
163328
+ directory: entry.directory,
163329
+ lastActiveAt: new Date(entry.mtime).toISOString()
163330
+ }));
163331
+ } catch {
163332
+ return [];
163333
+ }
163334
+ }
163335
+ function parseHistorianDumpMeta2(path4) {
163336
+ try {
163337
+ const xml = readFileSync14(path4, "utf-8");
163338
+ const parsed = parseCompartmentOutput(xml);
163339
+ const factCountByCategory = {};
163340
+ for (const fact of parsed.facts) {
163341
+ factCountByCategory[fact.category] = (factCountByCategory[fact.category] ?? 0) + 1;
163342
+ }
163343
+ const starts = parsed.compartments.map((c2) => c2.startMessage);
163344
+ const ends = parsed.compartments.map((c2) => c2.endMessage);
163345
+ let gaps = 0;
163346
+ let overlaps = 0;
163347
+ for (let i = 1;i < parsed.compartments.length; i++) {
163348
+ const prev = parsed.compartments[i - 1];
163349
+ const curr = parsed.compartments[i];
163350
+ if (curr.startMessage > prev.endMessage + 1)
163351
+ gaps += 1;
163352
+ else if (curr.startMessage <= prev.endMessage)
163353
+ overlaps += 1;
163354
+ }
163355
+ return {
163356
+ compartmentCount: parsed.compartments.length,
163357
+ minStart: starts.length > 0 ? Math.min(...starts) : null,
163358
+ maxEnd: ends.length > 0 ? Math.max(...ends) : null,
163359
+ unprocessedFrom: parsed.unprocessedFrom,
163360
+ factCountByCategory,
163361
+ userObservationCount: parsed.userObservations.length,
163362
+ ordinalGapCount: gaps,
163363
+ ordinalOverlapCount: overlaps
163364
+ };
163365
+ } catch (error51) {
163366
+ return { error: error51 instanceof Error ? error51.message : String(error51) };
163367
+ }
163017
163368
  }
163018
- function hasMagicContextPackage(packages) {
163019
- return packages.some((entry) => entry === PI_PACKAGE_SOURCE || entry === PACKAGE_NAME || entry.includes("pi-magic-context"));
163369
+ function listDumpsInDir2(dir, limit) {
163370
+ if (!existsSync19(dir))
163371
+ return { count: 0, recent: [] };
163372
+ try {
163373
+ const entries = readdirSync3(dir).filter((name2) => name2.endsWith(".xml")).map((name2) => {
163374
+ const stat = statSync4(join18(dir, name2));
163375
+ return {
163376
+ name: name2,
163377
+ mtime: stat.mtimeMs,
163378
+ sizeKb: Math.round(stat.size / 1024)
163379
+ };
163380
+ }).sort((a, b2) => b2.mtime - a.mtime);
163381
+ const now = Date.now();
163382
+ const recent = entries.slice(0, limit).map((entry) => {
163383
+ const meta3 = parseHistorianDumpMeta2(join18(dir, entry.name));
163384
+ const summary = {
163385
+ name: entry.name,
163386
+ ageMinutes: Math.round((now - entry.mtime) / 60000),
163387
+ sizeKb: entry.sizeKb
163388
+ };
163389
+ if ("error" in meta3) {
163390
+ summary.parseError = meta3.error;
163391
+ } else {
163392
+ summary.meta = meta3;
163393
+ }
163394
+ return summary;
163395
+ });
163396
+ return { count: entries.length, recent };
163397
+ } catch {
163398
+ return { count: 0, recent: [] };
163399
+ }
163400
+ }
163401
+ function collectPiHistorianDumps(recentSessions) {
163402
+ const buckets = new Map;
163403
+ for (const session of recentSessions) {
163404
+ const dir = session.directory;
163405
+ if (!dir)
163406
+ continue;
163407
+ const projectHistorianDir = getProjectMagicContextHistorianDir(dir);
163408
+ const listing = listDumpsInDir2(projectHistorianDir, 5);
163409
+ const existing = buckets.get(dir);
163410
+ if (existing) {
163411
+ if (!existing.sessionIds.includes(session.sessionId)) {
163412
+ existing.sessionIds.push(session.sessionId);
163413
+ }
163414
+ continue;
163415
+ }
163416
+ if (listing.count === 0)
163417
+ continue;
163418
+ buckets.set(dir, {
163419
+ directory: dir,
163420
+ primarySessionId: session.sessionId,
163421
+ sessionIds: [session.sessionId],
163422
+ count: listing.count,
163423
+ recent: listing.recent
163424
+ });
163425
+ }
163426
+ const legacyDir = getMagicContextHistorianDir2("pi");
163427
+ const legacyListing = listDumpsInDir2(legacyDir, 5);
163428
+ return {
163429
+ byProject: [...buckets.values()],
163430
+ legacyDumps: {
163431
+ dir: legacyDir,
163432
+ count: legacyListing.count,
163433
+ recent: legacyListing.recent
163434
+ }
163435
+ };
163020
163436
  }
163021
163437
  async function collectDiagnostics2(cwd = process.cwd()) {
163022
163438
  const pi = detectPiBinary();
@@ -163027,10 +163443,12 @@ async function collectDiagnostics2(cwd = process.cwd()) {
163027
163443
  const projectConfigPath = getProjectConfigPath(cwd);
163028
163444
  const loaded = loadPiConfig({ cwd });
163029
163445
  const storageDirPath = getMagicContextStorageDir();
163030
- const dbPath = join19(storageDirPath, "context.db");
163031
- const logPath = join19(tmpdir5(), "magic-context.log");
163446
+ const dbPath = join18(storageDirPath, "context.db");
163447
+ const logPath = getMagicContextLogPath2("pi");
163032
163448
  const logFileSize = existsSync19(logPath) ? statSync4(logPath).size : 0;
163033
- const otherPiExtensions = packages.filter((entry) => !hasMagicContextPackage([entry]));
163449
+ const otherPiExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
163450
+ const recentSessions = collectPiRecentSessions();
163451
+ const historianDumps = collectPiHistorianDumps(recentSessions);
163034
163452
  return {
163035
163453
  timestamp: new Date().toISOString(),
163036
163454
  platform: process.platform,
@@ -163044,8 +163462,8 @@ async function collectDiagnostics2(cwd = process.cwd()) {
163044
163462
  path: settingsPath,
163045
163463
  exists: existsSync19(settingsPath),
163046
163464
  ...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
163047
- hasMagicContextPackage: hasMagicContextPackage(packages),
163048
- packages: packages.map(sanitizeString2)
163465
+ hasMagicContextPackage: hasPiMagicContextPackage(packages),
163466
+ packages: sanitizeValue2(packages)
163049
163467
  },
163050
163468
  configPaths: {
163051
163469
  agentDir: getPiAgentConfigDir(),
@@ -163069,7 +163487,9 @@ async function collectDiagnostics2(cwd = process.cwd()) {
163069
163487
  path: logPath,
163070
163488
  exists: existsSync19(logPath),
163071
163489
  sizeKb: Math.round(logFileSize / 1024)
163072
- }
163490
+ },
163491
+ recentSessions,
163492
+ historianDumps
163073
163493
  };
163074
163494
  }
163075
163495
  function formatBytes2(bytes) {
@@ -163146,18 +163566,20 @@ function renderDiagnosticsMarkdown2(report) {
163146
163566
  ].join(`
163147
163567
  `);
163148
163568
  }
163149
- var import_comment_json9, PACKAGE_NAME = "@cortexkit/pi-magic-context";
163569
+ var import_comment_json10;
163150
163570
  var init_diagnostics_pi = __esm(() => {
163571
+ init_compartment_parser();
163151
163572
  init_data_path();
163152
163573
  init_config2();
163153
163574
  init_paths();
163154
163575
  init_pi_helpers();
163155
- import_comment_json9 = __toESM(require_src2(), 1);
163576
+ init_pi_package_entry();
163577
+ import_comment_json10 = __toESM(require_src2(), 1);
163156
163578
  });
163157
163579
 
163158
163580
  // src/lib/logs-pi.ts
163159
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync11 } from "node:fs";
163160
- import { join as join20 } from "node:path";
163581
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync11 } from "node:fs";
163582
+ import { join as join19 } from "node:path";
163161
163583
  function sanitizeLogContent2(content) {
163162
163584
  return sanitizeString2(content);
163163
163585
  }
@@ -163173,9 +163595,21 @@ function formatTimestamp2(date5) {
163173
163595
  pad(date5.getSeconds())
163174
163596
  ].join("");
163175
163597
  }
163598
+ function filterLogLinesBySession2(lines, sessionId) {
163599
+ if (!sessionId)
163600
+ return lines;
163601
+ const otherSessionPattern = /\bses_[A-Za-z0-9]{8,32}\b/g;
163602
+ return lines.filter((line) => {
163603
+ const matches = line.match(otherSessionPattern);
163604
+ if (!matches)
163605
+ return true;
163606
+ return matches.every((id) => id === sessionId);
163607
+ });
163608
+ }
163176
163609
  async function bundleIssueReport2(report, description, title, options = {}) {
163177
163610
  const LOG_TAIL_LINES = 400;
163178
- const logLines = report.logFile.exists ? readFileSync14(report.logFile.path, "utf-8").split(/\r?\n/) : [];
163611
+ const allLogLines = report.logFile.exists ? readFileSync15(report.logFile.path, "utf-8").split(/\r?\n/) : [];
163612
+ const logLines = filterLogLinesBySession2(allLogLines, options.sessionFilter ?? null);
163179
163613
  const recentLog = sanitizeLogContent2(logLines.slice(-LOG_TAIL_LINES).join(`
163180
163614
  `)).trim();
163181
163615
  const bodyMarkdown = [
@@ -163201,7 +163635,7 @@ async function bundleIssueReport2(report, description, title, options = {}) {
163201
163635
  ].join(`
163202
163636
  `);
163203
163637
  const cwd = options.cwd ?? process.cwd();
163204
- const path4 = join20(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
163638
+ const path4 = join19(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
163205
163639
  writeFileSync11(path4, `${bodyMarkdown}
163206
163640
  `);
163207
163641
  return { path: path4, bodyMarkdown };
@@ -163216,14 +163650,14 @@ import {
163216
163650
  existsSync as existsSync20,
163217
163651
  mkdirSync as mkdirSync8,
163218
163652
  readdirSync as readdirSync4,
163219
- readFileSync as readFileSync15,
163653
+ readFileSync as readFileSync16,
163220
163654
  rmSync as rmSync2,
163221
163655
  statSync as statSync5,
163222
163656
  writeFileSync as writeFileSync12
163223
163657
  } from "node:fs";
163224
163658
  import { createRequire as createRequire6 } from "node:module";
163225
- import { homedir as homedir14, tmpdir as tmpdir6 } from "node:os";
163226
- import { dirname as dirname9, join as join21 } from "node:path";
163659
+ import { homedir as homedir15 } from "node:os";
163660
+ import { dirname as dirname9, join as join20 } from "node:path";
163227
163661
  function depsFrom(options) {
163228
163662
  return {
163229
163663
  ...DEFAULT_DEPS,
@@ -163310,7 +163744,7 @@ function summarize(results) {
163310
163744
  function readJsonc4(path4) {
163311
163745
  try {
163312
163746
  return {
163313
- value: import_comment_json10.parse(readFileSync15(path4, "utf-8"))
163747
+ value: import_comment_json11.parse(readFileSync16(path4, "utf-8"))
163314
163748
  };
163315
163749
  } catch (error51) {
163316
163750
  return {
@@ -163320,24 +163754,21 @@ function readJsonc4(path4) {
163320
163754
  }
163321
163755
  }
163322
163756
  function packagesFrom(settings) {
163323
- return Array.isArray(settings.packages) ? settings.packages.filter((entry) => typeof entry === "string") : [];
163324
- }
163325
- function hasPiPackage(packages) {
163326
- return packages.some((entry) => entry === PI_PACKAGE_SOURCE || entry === PACKAGE_NAME2 || entry.includes("pi-magic-context"));
163757
+ return Array.isArray(settings.packages) ? settings.packages : [];
163327
163758
  }
163328
163759
  function projectConfigPath(cwd) {
163329
- return join21(cwd, ".pi", "magic-context.jsonc");
163760
+ return join20(cwd, ".pi", "magic-context.jsonc");
163330
163761
  }
163331
163762
  function readConfigForEmbedding(path4) {
163332
163763
  if (!existsSync20(path4))
163333
163764
  return null;
163334
163765
  try {
163335
- const rawText = readFileSync15(path4, "utf-8");
163766
+ const rawText = readFileSync16(path4, "utf-8");
163336
163767
  const substituted = substituteConfigVariables({
163337
163768
  text: rawText,
163338
163769
  configPath: path4
163339
163770
  });
163340
- return import_comment_json10.parse(substituted.text);
163771
+ return import_comment_json11.parse(substituted.text);
163341
163772
  } catch {
163342
163773
  return null;
163343
163774
  }
@@ -163390,14 +163821,14 @@ function countTable(db, table) {
163390
163821
  }
163391
163822
  }
163392
163823
  function cacheRoots() {
163393
- const home = homedir14();
163394
- const cacheHome = process.env.XDG_CACHE_HOME || join21(home, ".cache");
163824
+ const home = homedir15();
163825
+ const cacheHome = process.env.XDG_CACHE_HOME || join20(home, ".cache");
163395
163826
  return [
163396
- join21(home, ".pi", "cache", "extensions"),
163397
- join21(home, ".pi", "cache", "packages"),
163398
- join21(cacheHome, "pi", "extensions"),
163399
- join21(cacheHome, "pi", "packages"),
163400
- join21(getPiAgentConfigDir(), "cache", "extensions")
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")
163401
163832
  ];
163402
163833
  }
163403
163834
  function findPiMagicContextCacheDirs(self, force = false) {
@@ -163413,13 +163844,13 @@ function findPiMagicContextCacheDirs(self, force = false) {
163413
163844
  }
163414
163845
  if (!stat.isDirectory())
163415
163846
  return;
163416
- const packageJson = join21(path4, "package.json");
163847
+ const packageJson = join20(path4, "package.json");
163417
163848
  if (existsSync20(packageJson)) {
163418
163849
  try {
163419
- const pkg = JSON.parse(readFileSync15(packageJson, "utf-8"));
163850
+ const pkg = JSON.parse(readFileSync16(packageJson, "utf-8"));
163420
163851
  const name2 = typeof pkg.name === "string" ? pkg.name : "";
163421
163852
  const version2 = typeof pkg.version === "string" ? pkg.version : undefined;
163422
- if (name2 === PACKAGE_NAME2 || path4.includes("pi-magic-context")) {
163853
+ if (name2 === PACKAGE_NAME || path4.includes("pi-magic-context")) {
163423
163854
  if (force || !version2 || version2 !== self)
163424
163855
  found.set(path4, { path: path4, version: version2 });
163425
163856
  }
@@ -163435,7 +163866,7 @@ function findPiMagicContextCacheDirs(self, force = false) {
163435
163866
  return;
163436
163867
  }
163437
163868
  for (const entry of entries)
163438
- visit(join21(path4, entry), depth - 1);
163869
+ visit(join20(path4, entry), depth - 1);
163439
163870
  };
163440
163871
  for (const root of cacheRoots())
163441
163872
  visit(root, 5);
@@ -163482,7 +163913,7 @@ async function runHealthChecks(options) {
163482
163913
  } else {
163483
163914
  packages = packagesFrom(parsed.value);
163484
163915
  add(results, "pass", `Pi settings found at ${settingsPath}`);
163485
- if (hasPiPackage(packages)) {
163916
+ if (hasPiMagicContextPackage(packages)) {
163486
163917
  add(results, "pass", `${PI_PACKAGE_SOURCE} is registered in packages[]`);
163487
163918
  } else {
163488
163919
  add(results, "warn", `${PI_PACKAGE_SOURCE} is missing from packages[]`);
@@ -163529,7 +163960,7 @@ async function runHealthChecks(options) {
163529
163960
  add(results, "pass", `historian.model "${historianModel}" has thinking_level "${historianThinkingLevel}" configured`);
163530
163961
  }
163531
163962
  const storageDir = getMagicContextStorageDir();
163532
- const dbPath = join21(storageDir, "context.db");
163963
+ const dbPath = join20(storageDir, "context.db");
163533
163964
  const existedBeforeOpen = existsSync20(dbPath);
163534
163965
  if (existedBeforeOpen)
163535
163966
  add(results, "pass", `Shared context DB exists at ${dbPath}`);
@@ -163587,13 +164018,13 @@ async function runHealthChecks(options) {
163587
164018
  } else {
163588
164019
  add(results, "pass", `Embedding provider: ${loadedConfig.config.embedding.provider}`);
163589
164020
  }
163590
- const piEntries = packages.filter((entry) => hasPiPackage([entry]));
164021
+ const piEntries = packages.filter(isPiMagicContextPackageEntry).map(describePiPackageEntry);
163591
164022
  if (piEntries.length > 1) {
163592
164023
  add(results, "fail", `Multiple magic-context entries in Pi packages[] — this loads the plugin twice: ${piEntries.join(", ")}`);
163593
164024
  } else {
163594
164025
  add(results, "pass", "No conflicting magic-context entries in Pi packages[]");
163595
164026
  }
163596
- const otherExtensions = packages.filter((entry) => !hasPiPackage([entry]));
164027
+ const otherExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
163597
164028
  if (otherExtensions.length > 0) {
163598
164029
  add(results, "info", `Other Pi extensions registered: ${otherExtensions.join(", ")}`);
163599
164030
  } else {
@@ -163606,32 +164037,36 @@ async function runHealthChecks(options) {
163606
164037
  } else {
163607
164038
  add(results, "pass", "Pi extension cache clean (no stale cached package found)");
163608
164039
  }
163609
- const logPath = join21(tmpdir6(), "magic-context.log");
164040
+ const logPath = getMagicContextLogPath2("pi");
163610
164041
  if (existsSync20(logPath)) {
163611
164042
  const stat = statSync5(logPath);
163612
164043
  const sizeKb = (stat.size / 1024).toFixed(0);
163613
- const lines = readFileSync15(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
164044
+ const lines = readFileSync16(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
163614
164045
  add(results, "info", `Log file: ${logPath} (${sizeKb} KB)`);
163615
164046
  add(results, "info", `Last plugin log line: ${lines.at(-1) ?? "<empty log>"}`);
163616
164047
  } else {
163617
164048
  add(results, "info", `No plugin log file yet at ${logPath}`);
163618
164049
  }
163619
- const historianDumpDir = join21(tmpdir6(), "magic-context-historian");
163620
- if (existsSync20(historianDumpDir)) {
163621
- try {
163622
- const dumps = readdirSync4(historianDumpDir).filter((f) => f.endsWith(".xml")).map((f) => ({ name: f, mtime: statSync5(join21(historianDumpDir, f)).mtimeMs })).sort((a, b2) => b2.mtime - a.mtime);
163623
- if (dumps.length > 0) {
163624
- add(results, "warn", `Historian debug dumps: ${dumps.length} file(s) in ${historianDumpDir}`);
163625
- for (const dump of dumps.slice(0, 3)) {
163626
- const age = Math.round((Date.now() - dump.mtime) / 60000);
163627
- const ageStr = age < 60 ? `${age}m ago` : `${Math.round(age / 60)}h ago`;
163628
- add(results, "info", ` ${dump.name} (${ageStr})`);
163629
- }
163630
- if (dumps.length > 3) {
163631
- add(results, "info", ` ... and ${dumps.length - 3} more`);
163632
- }
164050
+ const diagnosticsForDumps = await collectDiagnostics2(options.cwd);
164051
+ const dumpBuckets = diagnosticsForDumps.historianDumps.byProject;
164052
+ if (dumpBuckets.length > 0) {
164053
+ const totalCount = dumpBuckets.reduce((sum, b2) => sum + b2.count, 0);
164054
+ add(results, "warn", `Historian debug dumps: ${totalCount} file(s) across ${dumpBuckets.length} project(s)`);
164055
+ for (const bucket of dumpBuckets) {
164056
+ add(results, "info", ` [${bucket.directory}] ${bucket.count} file(s)`);
164057
+ for (const dump of bucket.recent.slice(0, 3)) {
164058
+ const age = dump.ageMinutes;
164059
+ const ageStr = age < 60 ? `${age}m ago` : `${Math.round(age / 60)}h ago`;
164060
+ add(results, "info", ` ${dump.name} (${ageStr})`);
163633
164061
  }
163634
- } catch {}
164062
+ if (bucket.count > 3) {
164063
+ add(results, "info", ` ... and ${bucket.count - 3} more`);
164064
+ }
164065
+ }
164066
+ }
164067
+ const legacyDumps = diagnosticsForDumps.historianDumps.legacyDumps;
164068
+ if (legacyDumps.count > 0) {
164069
+ add(results, "info", `Legacy historian dumps (pre-v0.18.x): ${legacyDumps.count} file(s) in ${legacyDumps.dir}`);
163635
164070
  }
163636
164071
  if (!options.quiet) {
163637
164072
  for (const result of results)
@@ -163645,7 +164080,7 @@ function writeDefaultMagicContextConfig(path4) {
163645
164080
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
163646
164081
  ...MagicContextConfigSchema.parse({})
163647
164082
  };
163648
- writeFileSync12(path4, `${import_comment_json10.stringify(config2, null, 2)}
164083
+ writeFileSync12(path4, `${import_comment_json11.stringify(config2, null, 2)}
163649
164084
  `);
163650
164085
  }
163651
164086
  function repair(plan, prompts) {
@@ -163710,9 +164145,26 @@ async function runIssueFlow2(options) {
163710
164145
  spinner2.start("Collecting sanitized Pi diagnostics");
163711
164146
  try {
163712
164147
  const report = await options.deps.collectDiagnostics(options.cwd);
164148
+ spinner2.stop("Diagnostics collected");
164149
+ let sessionFilter = null;
164150
+ if (report.recentSessions.length > 1) {
164151
+ const choice = await options.prompts.selectOne("Which Pi session is this issue about? (filters log lines from other sessions)", [
164152
+ ...report.recentSessions.map((session, index) => ({
164153
+ label: `${session.directory} — ${session.sessionId}${index === 0 ? " (most recent)" : ""}`,
164154
+ value: session.sessionId
164155
+ })),
164156
+ {
164157
+ label: "All sessions (no filtering)",
164158
+ value: "__all__"
164159
+ }
164160
+ ]);
164161
+ sessionFilter = choice === "__all__" ? null : choice;
164162
+ }
164163
+ spinner2.start("Bundling Pi issue report");
163713
164164
  const bundled = await bundleIssueReport2(report, description, title, {
163714
164165
  cwd: options.cwd,
163715
- now: options.deps.now()
164166
+ now: options.deps.now(),
164167
+ sessionFilter
163716
164168
  });
163717
164169
  spinner2.stop(`Report written to ${bundled.path}`);
163718
164170
  if (ghAvailableAndAuthed(options.deps)) {
@@ -163787,7 +164239,7 @@ function parseDoctorArgs(args) {
163787
164239
  function doctor(args = []) {
163788
164240
  return runDoctor2(parseDoctorArgs(args));
163789
164241
  }
163790
- var import_comment_json10, PACKAGE_NAME2 = "@cortexkit/pi-magic-context", MIN_PI_VERSION = "0.71.0", ROW_COUNT_TABLES, DEFAULT_DEPS;
164242
+ var import_comment_json11, PACKAGE_NAME = "@cortexkit/pi-magic-context", MIN_PI_VERSION = "0.71.0", ROW_COUNT_TABLES, DEFAULT_DEPS;
163791
164243
  var init_doctor_pi = __esm(async () => {
163792
164244
  init_magic_context();
163793
164245
  init_variable();
@@ -163797,17 +164249,18 @@ var init_doctor_pi = __esm(async () => {
163797
164249
  init_logs_pi();
163798
164250
  init_paths();
163799
164251
  init_pi_helpers();
164252
+ init_pi_package_entry();
163800
164253
  init_prompts();
163801
164254
  init_setup_pi();
163802
164255
  await init_storage();
163803
- import_comment_json10 = __toESM(require_src2(), 1);
164256
+ import_comment_json11 = __toESM(require_src2(), 1);
163804
164257
  ROW_COUNT_TABLES = ["tags", "compartments", "memories", "notes", "dream_runs"];
163805
164258
  DEFAULT_DEPS = {
163806
164259
  prompts: promptIO,
163807
164260
  collectDiagnostics: collectDiagnostics2,
163808
164261
  detectPiBinary,
163809
164262
  getPiVersion,
163810
- getLatestNpmVersion: () => getLatestNpmVersion(PACKAGE_NAME2),
164263
+ getLatestNpmVersion: () => getLatestNpmVersion(PACKAGE_NAME),
163811
164264
  probeEmbeddingEndpoint,
163812
164265
  openDatabase,
163813
164266
  isDatabasePersisted,