@cortexkit/magic-context 0.37.0 → 0.38.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 +728 -220
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -3067,10 +3067,11 @@ function detectOmpBinary() {
3067
3067
  const candidate = candidates.find((path2) => isExecutableFile(path2));
3068
3068
  return candidate ? { path: candidate, source: "home" } : null;
3069
3069
  }
3070
- function runOmpCommand(ompPath, args, timeout = 30000) {
3070
+ function runOmpCommand(ompPath, args, timeout = 30000, overrides = {}) {
3071
+ const deps = { ...DEFAULT_COMMAND_EXECUTION_DEPS, ...overrides };
3071
3072
  try {
3072
- const invocation = getOmpCommandInvocation(ompPath, args);
3073
- const result = spawnSync2(invocation.command, invocation.args, {
3073
+ const invocation = deps.getInvocation(ompPath, args);
3074
+ const result = deps.spawnSync(invocation.command, invocation.args, {
3074
3075
  encoding: "utf-8",
3075
3076
  timeout,
3076
3077
  maxBuffer: 10 * 1024 * 1024,
@@ -3161,11 +3162,15 @@ function getOmpSetting(ompPath, key) {
3161
3162
  return null;
3162
3163
  }
3163
3164
  }
3164
- var OMP_PLUGIN_PACKAGE = "@cortexkit/pi-magic-context";
3165
+ var OMP_PLUGIN_PACKAGE = "@cortexkit/pi-magic-context", DEFAULT_COMMAND_EXECUTION_DEPS;
3165
3166
  var init_omp_helpers = __esm(() => {
3166
3167
  init_find_on_path();
3167
3168
  init_paths();
3168
3169
  init_pi_helpers();
3170
+ DEFAULT_COMMAND_EXECUTION_DEPS = {
3171
+ getInvocation: getOmpCommandInvocation,
3172
+ spawnSync: spawnSync2
3173
+ };
3169
3174
  });
3170
3175
 
3171
3176
  // src/adapters/omp.ts
@@ -3176,14 +3181,18 @@ class OmpAdapter {
3176
3181
  kind = "omp";
3177
3182
  displayName = "Oh My Pi (OMP)";
3178
3183
  pluginPackageName = OMP_PLUGIN_PACKAGE;
3184
+ deps;
3185
+ constructor(deps = {}) {
3186
+ this.deps = { ...DEFAULT_DEPS, ...deps };
3187
+ }
3179
3188
  isInstalled() {
3180
- return detectOmpBinary() !== null;
3189
+ return this.deps.detectOmpBinary() !== null;
3181
3190
  }
3182
3191
  hasPluginEntry() {
3183
- const omp = detectOmpBinary();
3192
+ const omp = this.deps.detectOmpBinary();
3184
3193
  if (!omp)
3185
3194
  return false;
3186
- return listOmpPlugins(omp.path)?.some((plugin) => plugin.name === OMP_PLUGIN_PACKAGE && plugin.enabled) ?? false;
3195
+ return this.deps.listOmpPlugins(omp.path)?.some((plugin) => plugin.name === OMP_PLUGIN_PACKAGE && plugin.enabled) ?? false;
3187
3196
  }
3188
3197
  getConfigPaths() {
3189
3198
  return {
@@ -3195,10 +3204,10 @@ class OmpAdapter {
3195
3204
  }
3196
3205
  async ensurePluginEntry() {
3197
3206
  const configPath = getOmpPluginsLockPath();
3198
- const omp = detectOmpBinary();
3207
+ const omp = this.deps.detectOmpBinary();
3199
3208
  if (!omp)
3200
3209
  return this.errorResult(configPath, "OMP binary not found");
3201
- const plugins = listOmpPlugins(omp.path);
3210
+ const plugins = this.deps.listOmpPlugins(omp.path);
3202
3211
  if (plugins === null) {
3203
3212
  return this.errorResult(configPath, "`omp plugin list --json` failed");
3204
3213
  }
@@ -3213,16 +3222,16 @@ class OmpAdapter {
3213
3222
  }
3214
3223
  const originalRuntimeEnabled = this.readRuntimeEnabled(configPath);
3215
3224
  const args = installed ? ["plugin", "enable", OMP_PLUGIN_PACKAGE] : ["plugin", "install", OMP_PLUGIN_PACKAGE];
3216
- const result = runOmpCommand(omp.path, args, 120000);
3225
+ const result = this.deps.runOmpCommand(omp.path, args, 120000);
3217
3226
  if (!result.ok) {
3218
3227
  return this.errorResult(configPath, result.stderr || result.stdout || `omp ${args.join(" ")} failed`);
3219
3228
  }
3220
- const enabledAfter = listOmpPlugins(omp.path)?.some((plugin) => plugin.name === OMP_PLUGIN_PACKAGE && plugin.enabled);
3229
+ const enabledAfter = this.deps.listOmpPlugins(omp.path)?.some((plugin) => plugin.name === OMP_PLUGIN_PACKAGE && plugin.enabled);
3221
3230
  if (!enabledAfter) {
3222
3231
  if (!installed) {
3223
- runOmpCommand(omp.path, ["plugin", "uninstall", OMP_PLUGIN_PACKAGE], 120000);
3232
+ this.deps.runOmpCommand(omp.path, ["plugin", "uninstall", OMP_PLUGIN_PACKAGE], 120000);
3224
3233
  } else if (originalRuntimeEnabled !== undefined) {
3225
- runOmpCommand(omp.path, ["plugin", originalRuntimeEnabled ? "enable" : "disable", OMP_PLUGIN_PACKAGE], 120000);
3234
+ this.deps.runOmpCommand(omp.path, ["plugin", originalRuntimeEnabled ? "enable" : "disable", OMP_PLUGIN_PACKAGE], 120000);
3226
3235
  }
3227
3236
  return this.errorResult(configPath, `${OMP_PLUGIN_PACKAGE} is still disabled in the current project after \`omp ${args.join(" ")}\``);
3228
3237
  }
@@ -3235,10 +3244,10 @@ class OmpAdapter {
3235
3244
  }
3236
3245
  async removePluginEntry() {
3237
3246
  const configPath = getOmpPluginsLockPath();
3238
- const omp = detectOmpBinary();
3247
+ const omp = this.deps.detectOmpBinary();
3239
3248
  if (!omp)
3240
3249
  return this.errorResult(configPath, "OMP binary not found");
3241
- const plugins = listOmpPlugins(omp.path);
3250
+ const plugins = this.deps.listOmpPlugins(omp.path);
3242
3251
  if (plugins === null) {
3243
3252
  return this.errorResult(configPath, "`omp plugin list --json` failed");
3244
3253
  }
@@ -3251,7 +3260,7 @@ class OmpAdapter {
3251
3260
  configPath
3252
3261
  };
3253
3262
  }
3254
- const result = runOmpCommand(omp.path, ["plugin", "uninstall", OMP_PLUGIN_PACKAGE], 120000);
3263
+ const result = this.deps.runOmpCommand(omp.path, ["plugin", "uninstall", OMP_PLUGIN_PACKAGE], 120000);
3255
3264
  if (!result.ok) {
3256
3265
  return this.errorResult(configPath, result.stderr || result.stdout || "OMP plugin uninstall failed");
3257
3266
  }
@@ -3273,10 +3282,10 @@ class OmpAdapter {
3273
3282
  return getMagicContextLogPath2("pi");
3274
3283
  }
3275
3284
  getInstalledPluginVersion() {
3276
- const omp = detectOmpBinary();
3285
+ const omp = this.deps.detectOmpBinary();
3277
3286
  if (!omp)
3278
3287
  return null;
3279
- return listOmpPlugins(omp.path)?.find((plugin) => plugin.name === OMP_PLUGIN_PACKAGE)?.version ?? null;
3288
+ return this.deps.listOmpPlugins(omp.path)?.find((plugin) => plugin.name === OMP_PLUGIN_PACKAGE)?.version ?? null;
3280
3289
  }
3281
3290
  readRuntimeEnabled(configPath) {
3282
3291
  try {
@@ -3296,9 +3305,15 @@ class OmpAdapter {
3296
3305
  };
3297
3306
  }
3298
3307
  }
3308
+ var DEFAULT_DEPS;
3299
3309
  var init_omp = __esm(() => {
3300
3310
  init_omp_helpers();
3301
3311
  init_paths();
3312
+ DEFAULT_DEPS = {
3313
+ detectOmpBinary,
3314
+ listOmpPlugins,
3315
+ runOmpCommand
3316
+ };
3302
3317
  });
3303
3318
 
3304
3319
  // ../../node_modules/.bun/esprima@4.0.1/node_modules/esprima/dist/esprima.js
@@ -11160,14 +11175,16 @@ var init_atomic_write = () => {};
11160
11175
  import { existsSync as existsSync7, realpathSync } from "node:fs";
11161
11176
  import { homedir as homedir6 } from "node:os";
11162
11177
  import { join as join8 } from "node:path";
11163
- function defaultDeps() {
11178
+ function defaultDeps(overrides = {}) {
11179
+ const env = overrides.env ?? process.env;
11164
11180
  return {
11165
- exists: existsSync7,
11166
- isExecutable: isExecutableFile,
11167
- home: process.env.HOME?.trim() || homedir6(),
11168
- platform: process.platform,
11169
- env: process.env,
11170
- onPath: findOnPath
11181
+ exists: overrides.exists ?? existsSync7,
11182
+ isExecutable: overrides.isExecutable ?? isExecutableFile,
11183
+ home: overrides.home ?? (env.HOME?.trim() || homedir6()),
11184
+ platform: overrides.platform ?? process.platform,
11185
+ env,
11186
+ onPath: overrides.onPath ?? findOnPath,
11187
+ realpath: overrides.realpath
11171
11188
  };
11172
11189
  }
11173
11190
  function stockCliBinary(d) {
@@ -11246,7 +11263,7 @@ function desktopAppPaths(d) {
11246
11263
  }
11247
11264
  }
11248
11265
  function detectOpenCodeInstallations(deps) {
11249
- const d = { ...defaultDeps(), ...deps };
11266
+ const d = defaultDeps(deps);
11250
11267
  const installations = [];
11251
11268
  const seenRealpaths = new Set;
11252
11269
  const onPath = d.onPath("opencode");
@@ -12736,31 +12753,28 @@ var init_setup_pi = __esm(() => {
12736
12753
  });
12737
12754
 
12738
12755
  // src/commands/setup-omp.ts
12739
- async function runSetup2(options = {}) {
12740
- return runSetup({
12741
- ...options,
12742
- env: options.env ?? OMP_ENV,
12743
- host: options.host ?? OMP_HOST
12744
- });
12756
+ function resolveDeps(overrides = {}) {
12757
+ return { ...DEFAULT_DEPS2, ...overrides };
12745
12758
  }
12746
- var OMP_ENV, OMP_HOST;
12747
- var init_setup_omp = __esm(() => {
12748
- init_harness_provider_map();
12749
- init_omp();
12750
- init_omp_helpers();
12751
- init_paths();
12752
- init_setup_pi();
12753
- OMP_ENV = {
12754
- detectPiBinary: detectOmpBinary,
12755
- getPiVersion: getOmpVersion,
12756
- getAvailableModels: getOmpAvailableModels,
12759
+ function createOmpEnvironment(deps) {
12760
+ return {
12761
+ detectPiBinary: deps.detectOmpBinary,
12762
+ getPiVersion: deps.getOmpVersion,
12763
+ getAvailableModels: deps.getOmpAvailableModels,
12757
12764
  paths: {
12758
12765
  getPiAgentConfigDir: getOmpAgentDir,
12759
12766
  getPiUserConfigPath: getOmpUserConfigPath,
12760
12767
  getPiUserExtensionsPath: getOmpPluginsLockPath
12761
12768
  }
12762
12769
  };
12763
- OMP_HOST = {
12770
+ }
12771
+ function createOmpHost(deps) {
12772
+ const adapterDeps = {
12773
+ detectOmpBinary: deps.detectOmpBinary,
12774
+ listOmpPlugins: deps.listOmpPlugins,
12775
+ runOmpCommand: deps.runOmpCommand
12776
+ };
12777
+ return {
12764
12778
  displayName: "Oh My Pi (OMP)",
12765
12779
  cliName: "omp",
12766
12780
  packageSource: OMP_PLUGIN_PACKAGE,
@@ -12768,13 +12782,13 @@ var init_setup_omp = __esm(() => {
12768
12782
  minimumVersion: "17.1.7",
12769
12783
  versionWarning: (version, minimum) => `OMP ${version} is older than the tested minimum ${minimum}. ` + "Upgrade with `omp update` before enabling Magic Context.",
12770
12784
  modelRefToCanonical: ompModelRefToCanonical,
12771
- ensurePluginEntry: async () => new OmpAdapter().ensurePluginEntry(),
12785
+ ensurePluginEntry: async () => new OmpAdapter(adapterDeps).ensurePluginEntry(),
12772
12786
  beforeWrite: async ({ binaryPath, cwd, prompts, dryRun, configureHost }) => {
12773
- if (!configureHost && !new OmpAdapter().hasPluginEntry()) {
12787
+ if (!configureHost && !new OmpAdapter(adapterDeps).hasPluginEntry()) {
12774
12788
  return async () => {};
12775
12789
  }
12776
- const compaction = getOmpSetting(binaryPath, "compaction.enabled");
12777
- const memoryBackend = getOmpSetting(binaryPath, "memory.backend");
12790
+ const compaction = deps.getOmpSetting(binaryPath, "compaction.enabled");
12791
+ const memoryBackend = deps.getOmpSetting(binaryPath, "memory.backend");
12778
12792
  if (compaction === null || memoryBackend === null) {
12779
12793
  prompts.log.error("Could not read OMP compaction/memory settings; refusing to install two context managers blindly.");
12780
12794
  return false;
@@ -12813,7 +12827,7 @@ Edit those files directly, then rerun setup.`);
12813
12827
  const applied = [];
12814
12828
  const rollback = async () => {
12815
12829
  for (const change of [...applied].reverse()) {
12816
- const result = runOmpCommand(binaryPath, ["config", "set", change.key, change.from], 1e4);
12830
+ const result = deps.runOmpCommand(binaryPath, ["config", "set", change.key, change.from], 1e4);
12817
12831
  if (result.ok)
12818
12832
  prompts.log.info(`Restored OMP ${change.key}=${change.from}`);
12819
12833
  else
@@ -12821,7 +12835,7 @@ Edit those files directly, then rerun setup.`);
12821
12835
  }
12822
12836
  };
12823
12837
  for (const change of changes) {
12824
- const result = runOmpCommand(binaryPath, ["config", "set", change.key, change.to], 1e4);
12838
+ const result = deps.runOmpCommand(binaryPath, ["config", "set", change.key, change.to], 1e4);
12825
12839
  if (!result.ok) {
12826
12840
  prompts.log.error(result.stderr || `Could not set OMP ${change.key}`);
12827
12841
  await rollback();
@@ -12835,13 +12849,40 @@ Edit those files directly, then rerun setup.`);
12835
12849
  rollbackPluginEntry: async (registration) => {
12836
12850
  if (registration.action === "already_present")
12837
12851
  return;
12838
- const omp = detectOmpBinary();
12852
+ const omp = deps.detectOmpBinary();
12839
12853
  if (!omp)
12840
12854
  return;
12841
12855
  const action = registration.action === "added" ? "uninstall" : "disable";
12842
- runOmpCommand(omp.path, ["plugin", action, OMP_PLUGIN_PACKAGE], 120000);
12856
+ deps.runOmpCommand(omp.path, ["plugin", action, OMP_PLUGIN_PACKAGE], 120000);
12843
12857
  }
12844
12858
  };
12859
+ }
12860
+ async function runSetup2(options = {}) {
12861
+ const { deps: overrides, ...setupOptions } = options;
12862
+ const deps = overrides ? resolveDeps(overrides) : DEFAULT_DEPS2;
12863
+ return runSetup({
12864
+ ...setupOptions,
12865
+ env: setupOptions.env ?? (overrides ? createOmpEnvironment(deps) : OMP_ENV),
12866
+ host: setupOptions.host ?? (overrides ? createOmpHost(deps) : OMP_HOST)
12867
+ });
12868
+ }
12869
+ var DEFAULT_DEPS2, OMP_ENV, OMP_HOST;
12870
+ var init_setup_omp = __esm(() => {
12871
+ init_harness_provider_map();
12872
+ init_omp();
12873
+ init_omp_helpers();
12874
+ init_paths();
12875
+ init_setup_pi();
12876
+ DEFAULT_DEPS2 = {
12877
+ detectOmpBinary,
12878
+ getOmpVersion,
12879
+ getOmpAvailableModels,
12880
+ getOmpSetting,
12881
+ listOmpPlugins,
12882
+ runOmpCommand
12883
+ };
12884
+ OMP_ENV = createOmpEnvironment(DEFAULT_DEPS2);
12885
+ OMP_HOST = createOmpHost(DEFAULT_DEPS2);
12845
12886
  });
12846
12887
 
12847
12888
  // ../plugin/src/shared/logger.ts
@@ -28245,7 +28286,7 @@ var init_magic_context = __esm(() => {
28245
28286
  output_reserve: exports_external.union([
28246
28287
  exports_external.number().min(0),
28247
28288
  exports_external.object({ default: exports_external.number().min(0) }).catchall(exports_external.number().min(0))
28248
- ]).optional().describe('User-only output-token reservation override. Number or per-model object ({ default: 16384, "provider/model": 8192 }); 0 disables reservation. When unset, Magic Context reserves the catalog output limit (capped at 25% of context) for shared-window providers and keeps proven separate-quota Google/Gemini windows unchanged.'),
28289
+ ]).optional().describe('User-only output-token reservation override. Number or per-model object ({ default: 16384, "provider/model": 8192 }); 0 disables reservation. Takes precedence over every derived source: an explicit value here always wins against catalog output limits, provider window-geometry facts, and the 25%-of-context fallback (usable window = context window minus this reserve). When unset, Magic Context reserves the catalog output limit (capped at 25% of context) for shared-window providers and keeps proven separate-quota Google/Gemini windows unchanged.'),
28249
28290
  models: exports_external.object({
28250
28291
  window_overlay_path: exports_external.string().trim().min(1).optional()
28251
28292
  }).optional().describe("User-only Fusiform window-overlay settings. The path defaults to <dataDir>/fusiform/window-overlay.json."),
@@ -28300,7 +28341,7 @@ var init_magic_context = __esm(() => {
28300
28341
  overlay: exports_external.boolean().default(true).describe("Pi only: show the persistent todo overlay above the editor while tasks are active.")
28301
28342
  }).default({ enabled: true, overlay: true }).describe("Pi-only todowrite tool and overlay controls. Pi registers tools and widgets at extension boot, so changing this after /cd requires /reload or restart."),
28302
28343
  pi: PiConfigSchema.describe("Pi-only child-process extension controls. This setting is user-level only; project configuration cannot choose which extensions a user's subagent children load."),
28303
- smart_drops: exports_external.boolean().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 5), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
28344
+ smart_drops: exports_external.boolean().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 3), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
28304
28345
  caveman_text_compression: exports_external.object({
28305
28346
  enabled: exports_external.boolean().default(false).describe("Apply deterministic caveman-style text compression to old conversation text. Active for primary sessions when enabled; never for subagents. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%)."),
28306
28347
  min_chars: exports_external.number().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
@@ -29882,10 +29923,11 @@ function runOpenCode(args, binary, timeoutMs) {
29882
29923
  function getOpenCodeVersion(binary) {
29883
29924
  return runOpenCode(["--version"], binary, OPENCODE_VERSION_PROBE_TIMEOUT_MS);
29884
29925
  }
29885
- function describeOpenCodeInstallations(installations) {
29926
+ function describeOpenCodeInstallations(installations, deps = {}) {
29927
+ const getVersion = deps.getVersion ?? getOpenCodeVersion;
29886
29928
  return installations.map((installation, index) => ({
29887
29929
  ...installation,
29888
- version: installation.kind === "cli" ? getOpenCodeVersion(installation.path) ?? "unknown" : "unknown",
29930
+ version: installation.kind === "cli" ? getVersion(installation.path) ?? "unknown" : "unknown",
29889
29931
  active: index === 0
29890
29932
  }));
29891
29933
  }
@@ -34338,6 +34380,51 @@ function readPsProcessCommand(pid) {
34338
34380
  return null;
34339
34381
  }
34340
34382
  }
34383
+ function readProcessCommand(pid) {
34384
+ if (!Number.isInteger(pid) || pid <= 0)
34385
+ return null;
34386
+ return rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(pid) : rpcIdentityPlatform === "win32" ? readWindowsProcess(pid).command ?? null : readPsProcessCommand(pid);
34387
+ }
34388
+ function executableName(token) {
34389
+ return (token ?? "").replace(/^['"]|['"]$/g, "").split("/").at(-1) ?? "";
34390
+ }
34391
+ function commandTokens(command) {
34392
+ return command.toLowerCase().replaceAll("\\", "/").replaceAll("\x00", " ").split(/\s+/).map((token) => token.replace(/^['"]|['"]$/g, "")).filter(Boolean);
34393
+ }
34394
+ function commandHasOpenCodeExecutable(tokens) {
34395
+ return tokens.findIndex((token) => {
34396
+ const executable = executableName(token).replace(/\.(?:exe|cmd)$/, "");
34397
+ return executable === "opencode" || executable.endsWith("/opencode");
34398
+ });
34399
+ }
34400
+ function commandHasPiExecutable(tokens) {
34401
+ for (let index = 0;index < tokens.length; index += 1) {
34402
+ const executable = executableName(tokens[index]).replace(/\.(?:exe|cmd)$/, "");
34403
+ if (["pi", "omp", "oh-my-pi"].includes(executable))
34404
+ return true;
34405
+ if (["node", "bun", "deno"].includes(executable)) {
34406
+ const script = executableName(tokens[index + 1]).replace(/\.(?:exe|cmd)$/, "");
34407
+ if (["pi", "pi.js", "pi.mjs", "pi.cjs"].includes(script) || tokens[index + 1]?.includes("pi-coding-agent")) {
34408
+ return true;
34409
+ }
34410
+ }
34411
+ }
34412
+ return false;
34413
+ }
34414
+ function classifyProcessKind(command) {
34415
+ if (!command)
34416
+ return "process";
34417
+ const tokens = commandTokens(command);
34418
+ const openCodeIndex = commandHasOpenCodeExecutable(tokens);
34419
+ if (openCodeIndex >= 0) {
34420
+ const args = tokens.slice(openCodeIndex + 1);
34421
+ if (args.some((token) => token === "serve" || token === "--serve" || token.startsWith("--serve="))) {
34422
+ return "OpenCode server";
34423
+ }
34424
+ return "OpenCode instance (TUI/CLI)";
34425
+ }
34426
+ return commandHasPiExecutable(tokens) ? "Pi" : "process";
34427
+ }
34341
34428
  function commandLooksLikeOpenCode(command) {
34342
34429
  const normalized = command.toLowerCase();
34343
34430
  return OPEN_CODE_COMMAND_MARKERS.some((marker) => normalized.includes(marker));
@@ -34359,12 +34446,12 @@ function isPidIdentityPlausible(record2) {
34359
34446
  function commandLooksLikePi(command) {
34360
34447
  const normalized = command.trim().toLowerCase().replaceAll("\\", "/");
34361
34448
  const tokens = normalized.split(/\s+/).filter(Boolean);
34362
- const executableName = (token) => (token ?? "").split("/").at(-1) ?? "";
34363
- const first = executableName(tokens[0]).replace(/\.exe$/, "");
34449
+ const executableName2 = (token) => (token ?? "").split("/").at(-1) ?? "";
34450
+ const first = executableName2(tokens[0]).replace(/\.exe$/, "");
34364
34451
  if (["pi", "pi.cmd", "omp", "oh-my-pi"].includes(first))
34365
34452
  return true;
34366
34453
  if (["node", "bun", "deno"].includes(first)) {
34367
- const script = executableName(tokens[1]);
34454
+ const script = executableName2(tokens[1]);
34368
34455
  return ["pi", "pi.js", "pi.mjs", "pi.cjs"].includes(script) || normalized.includes("pi-coding-agent");
34369
34456
  }
34370
34457
  return false;
@@ -34434,6 +34521,8 @@ function parseRpcPortFile(content, fallbackPid = 0) {
34434
34521
  port: port2,
34435
34522
  pid,
34436
34523
  started_at: Number.isFinite(startedAt) ? startedAt : 0,
34524
+ kind: typeof parsed.kind === "string" ? parsed.kind : undefined,
34525
+ harness: typeof parsed.harness === "string" ? parsed.harness : undefined,
34437
34526
  token: typeof parsed.token === "string" ? parsed.token : undefined,
34438
34527
  instance_id: typeof parsed.instance_id === "string" ? parsed.instance_id : undefined
34439
34528
  };
@@ -37048,7 +37137,7 @@ import {
37048
37137
  statSync as statSync7,
37049
37138
  unlinkSync as unlinkSync2
37050
37139
  } from "node:fs";
37051
- import { basename as basename3, dirname as dirname10, join as join14 } from "node:path";
37140
+ import { basename as basename3, dirname as dirname10, join as join14, resolve as resolve5 } from "node:path";
37052
37141
  function getPersistedSchemaVersion(db) {
37053
37142
  const hasMigrationsTable = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'schema_migrations'").get();
37054
37143
  if (!hasMigrationsTable) {
@@ -37080,6 +37169,28 @@ function invalidDiscoveryReason(raw) {
37080
37169
  }
37081
37170
  return "parse-invalid";
37082
37171
  }
37172
+ function classifyDiscoveryRecordKind(record2) {
37173
+ for (const value of [record2.kind, record2.harness]) {
37174
+ const normalized = value?.trim().toLowerCase();
37175
+ if (!normalized)
37176
+ continue;
37177
+ if (normalized === "process")
37178
+ return "process";
37179
+ if (normalized === "opencode server" || normalized === "server") {
37180
+ return "OpenCode server";
37181
+ }
37182
+ if (normalized === "opencode instance" || normalized === "opencode instance (tui/cli)" || normalized === "opencode" || normalized === "tui" || normalized === "cli") {
37183
+ return "OpenCode instance (TUI/CLI)";
37184
+ }
37185
+ if (normalized === "pi" || normalized === "pi harness" || normalized === "omp" || normalized === "oh-my-pi") {
37186
+ return "Pi";
37187
+ }
37188
+ }
37189
+ return null;
37190
+ }
37191
+ function classifyRpcProcess(record2) {
37192
+ return classifyDiscoveryRecordKind(record2) ?? classifyProcessKind(readProcessCommand(record2.pid));
37193
+ }
37083
37194
  function classifyJunkDiscovery(portFile, raw, staleFiles) {
37084
37195
  let mtimeMs;
37085
37196
  try {
@@ -37132,6 +37243,7 @@ function inspectRpcServerDiscovery(storageDir) {
37132
37243
  return { state: "absent", serverPids: [], staleFiles: [] };
37133
37244
  }
37134
37245
  const pids = new Set;
37246
+ const processByPid = new Map;
37135
37247
  const staleFiles = [];
37136
37248
  const inconclusivePids = new Set;
37137
37249
  for (const portFile of portFiles) {
@@ -37157,6 +37269,14 @@ function inspectRpcServerDiscovery(storageDir) {
37157
37269
  const identity = liveness === "dead" ? "implausible" : isPidIdentityPlausible(record2);
37158
37270
  if (liveness === "alive" && identity === "plausible") {
37159
37271
  pids.add(record2.pid);
37272
+ const detected = {
37273
+ kind: classifyRpcProcess(record2),
37274
+ pid: record2.pid
37275
+ };
37276
+ const previous = processByPid.get(record2.pid);
37277
+ if (!previous || previous.kind === "process" && detected.kind !== "process") {
37278
+ processByPid.set(record2.pid, detected);
37279
+ }
37160
37280
  } else if (liveness === "dead" || identity === "implausible") {
37161
37281
  staleFiles.push(portFile);
37162
37282
  } else {
@@ -37172,7 +37292,12 @@ function inspectRpcServerDiscovery(storageDir) {
37172
37292
  }
37173
37293
  const serverPids = [...pids].sort((a3, b2) => a3 - b2);
37174
37294
  if (serverPids.length > 0) {
37175
- return { state: "live", serverPids, staleFiles };
37295
+ return {
37296
+ state: "live",
37297
+ serverPids,
37298
+ serverProcesses: serverPids.map((pid) => processByPid.get(pid) ?? { kind: "process", pid }),
37299
+ staleFiles
37300
+ };
37176
37301
  }
37177
37302
  const uncertainPids = [...inconclusivePids].sort((a3, b2) => a3 - b2);
37178
37303
  if (uncertainPids.length > 0) {
@@ -37187,8 +37312,8 @@ function inspectRpcServerDiscovery(storageDir) {
37187
37312
  }
37188
37313
  function getLiveMigrationBlockingProcesses(storageDir) {
37189
37314
  const discovery = inspectRpcServerDiscovery(storageDir);
37190
- const openCode = discovery.state === "live" ? discovery.serverPids.map((pid) => ({ harness: "OpenCode server", pid })) : [];
37191
- const pi = discoverLivePiProcessIds().map((pid) => ({ harness: "Pi harness", pid }));
37315
+ const openCode = discovery.state === "live" ? discovery.serverProcesses ?? [] : [];
37316
+ const pi = discoverLivePiProcessIds().map((pid) => ({ kind: "Pi", pid }));
37192
37317
  return [...openCode, ...pi];
37193
37318
  }
37194
37319
  function applySqliteTuningPragmas(db) {
@@ -38301,7 +38426,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
38301
38426
  ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
38302
38427
  ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
38303
38428
  }
38304
- var databases, pendingAsyncOpens, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, LATEST_SUPPORTED_VERSION = 78, PERMISSIONS_ENFORCEABLE, RPC_DISCOVERY_PARSE_GRACE_MS, defaultRpcDiscoveryFs, rpcDiscoveryFs, sqlitePragmaConfig;
38429
+ var databases, pendingAsyncOpens, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, LATEST_SUPPORTED_VERSION = 78, PERMISSIONS_ENFORCEABLE, RPC_DISCOVERY_PARSE_GRACE_MS, defaultRpcDiscoveryFs, rpcDiscoveryFs, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS;
38305
38430
  var init_storage_db = __esm(async () => {
38306
38431
  init_data_path();
38307
38432
  init_logger();
@@ -38331,6 +38456,7 @@ var init_storage_db = __esm(async () => {
38331
38456
  cacheSizeMb: 64,
38332
38457
  mmapSizeMb: 0
38333
38458
  };
38459
+ CHANNEL2_CLAIM_TTL_MS = 10 * 60000;
38334
38460
  });
38335
38461
 
38336
38462
  // src/lib/database-access.ts
@@ -39251,7 +39377,7 @@ function printHelp() {
39251
39377
  }
39252
39378
  async function runRepairDb(options = {}) {
39253
39379
  const prompts = options.prompts ?? promptIO;
39254
- const deps = { ...DEFAULT_DEPS, ...options.deps };
39380
+ const deps = { ...DEFAULT_DEPS3, ...options.deps };
39255
39381
  const storageDir = options.storageDir ?? dirname11(options.dbPath ?? join16(getMagicContextStorageDir(), "context.db"));
39256
39382
  const dbPath = options.dbPath ?? join16(storageDir, "context.db");
39257
39383
  const stamp = timestamp(deps.now());
@@ -39421,7 +39547,7 @@ async function runRepairDbCli(args, options = {}) {
39421
39547
  }
39422
39548
  return runRepairDb(options);
39423
39549
  }
39424
- var ROW_COUNT_TABLES, DATABASE_SUFFIXES, RECOGNIZABLE_TABLES, REPAIR_DB_EXIT, DEFAULT_DEPS, RECOVER_UNAVAILABLE_PATTERNS;
39550
+ var ROW_COUNT_TABLES, DATABASE_SUFFIXES, RECOGNIZABLE_TABLES, REPAIR_DB_EXIT, DEFAULT_DEPS3, RECOVER_UNAVAILABLE_PATTERNS;
39425
39551
  var init_doctor_repair_db = __esm(async () => {
39426
39552
  init_migrations();
39427
39553
  init_data_path();
@@ -39441,7 +39567,7 @@ var init_doctor_repair_db = __esm(async () => {
39441
39567
  unsalvageable: 2,
39442
39568
  refused: 3
39443
39569
  };
39444
- DEFAULT_DEPS = {
39570
+ DEFAULT_DEPS3 = {
39445
39571
  now: () => new Date,
39446
39572
  sqliteExecutable: defaultSqliteExecutable(),
39447
39573
  inspectHolders: defaultInspectHolders
@@ -41576,7 +41702,7 @@ var init_redaction2 = __esm(() => {
41576
41702
  import { execFileSync as execFileSync5, spawnSync as spawnSync4 } from "node:child_process";
41577
41703
  import { existsSync as existsSync24, mkdirSync as mkdirSync9, readFileSync as readFileSync15 } from "node:fs";
41578
41704
  import { createRequire as createRequire2 } from "node:module";
41579
- import { dirname as dirname13, join as join20, resolve as resolve5 } from "node:path";
41705
+ import { dirname as dirname13, join as join20, resolve as resolve6 } from "node:path";
41580
41706
  function parseSemver(value) {
41581
41707
  const match = value?.match(/(\d+)\.(\d+)\.(\d+)/);
41582
41708
  return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
@@ -41702,8 +41828,8 @@ async function runHealthChecks(options) {
41702
41828
  if (!reportedAgentDir.ok) {
41703
41829
  add(results, "warn", "Could not verify OMP active agent directory");
41704
41830
  } else {
41705
- const reportedPath = resolve5(reportedAgentDir.stdout);
41706
- const expectedPath = resolve5(getOmpAgentDir());
41831
+ const reportedPath = resolve6(reportedAgentDir.stdout);
41832
+ const expectedPath = resolve6(getOmpAgentDir());
41707
41833
  if (reportedPath === expectedPath) {
41708
41834
  add(results, "pass", `OMP agent directory resolved to ${getOmpAgentDir()}`);
41709
41835
  } else {
@@ -41875,8 +42001,8 @@ async function runIssueFlow(options) {
41875
42001
  }
41876
42002
  async function runDoctor(options = {}) {
41877
42003
  const deps = {
41878
- ...DEFAULT_DEPS2,
41879
- prompts: options.prompts ?? DEFAULT_DEPS2.prompts,
42004
+ ...DEFAULT_DEPS4,
42005
+ prompts: options.prompts ?? DEFAULT_DEPS4.prompts,
41880
42006
  ...options.deps
41881
42007
  };
41882
42008
  const prompts = options.prompts ?? deps.prompts;
@@ -41902,7 +42028,7 @@ async function runDoctor(options = {}) {
41902
42028
  prompts.log.message(`Summary: PASS ${second.pass} / WARN ${second.warn} / FAIL ${second.fail}`);
41903
42029
  return second.fail === 0 ? 0 : 1;
41904
42030
  }
41905
- var import_comment_json8, MIN_OMP_VERSION = "17.1.7", DEFAULT_DEPS2;
42031
+ var import_comment_json8, MIN_OMP_VERSION = "17.1.7", DEFAULT_DEPS4;
41906
42032
  var init_doctor_omp = __esm(async () => {
41907
42033
  init_magic_context();
41908
42034
  init_data_path();
@@ -41916,7 +42042,7 @@ var init_doctor_omp = __esm(async () => {
41916
42042
  init_redaction2();
41917
42043
  await init_database_access();
41918
42044
  import_comment_json8 = __toESM(require_src3(), 1);
41919
- DEFAULT_DEPS2 = {
42045
+ DEFAULT_DEPS4 = {
41920
42046
  prompts: promptIO,
41921
42047
  detectOmpBinary,
41922
42048
  getOmpVersion,
@@ -43352,25 +43478,391 @@ function migrateExperimentalPinKeyFilesForDoctor(mcConfig) {
43352
43478
  return true;
43353
43479
  }
43354
43480
 
43481
+ // ../plugin/src/hooks/auto-update-checker/constants.ts
43482
+ import { homedir as homedir16, platform } from "node:os";
43483
+ import { join as join25 } from "node:path";
43484
+ function getOpenCodeCacheRoot() {
43485
+ if (platform() === "win32") {
43486
+ return join25(process.env.LOCALAPPDATA ?? homedir16(), "opencode");
43487
+ }
43488
+ return join25(homedir16(), ".cache", "opencode");
43489
+ }
43490
+ function getOpenCodeConfigRoot() {
43491
+ if (platform() === "win32") {
43492
+ return join25(process.env.APPDATA ?? join25(homedir16(), "AppData", "Roaming"), "opencode");
43493
+ }
43494
+ return join25(process.env.XDG_CONFIG_HOME ?? join25(homedir16(), ".config"), "opencode");
43495
+ }
43496
+ var PACKAGE_NAME = "@cortexkit/opencode-magic-context", CACHE_DIR, USER_OPENCODE_CONFIG, USER_OPENCODE_CONFIG_JSONC;
43497
+ var init_constants2 = __esm(() => {
43498
+ CACHE_DIR = join25(getOpenCodeCacheRoot(), "packages");
43499
+ USER_OPENCODE_CONFIG = join25(getOpenCodeConfigRoot(), "opencode.json");
43500
+ USER_OPENCODE_CONFIG_JSONC = join25(getOpenCodeConfigRoot(), "opencode.jsonc");
43501
+ });
43502
+ // ../plugin/src/hooks/auto-update-checker/types.ts
43503
+ var NpmPackageEnvelopeSchema, OpencodePluginTupleSchema, OpencodeConfigSchema, PackageJsonSchema;
43504
+ var init_types = __esm(() => {
43505
+ init_zod();
43506
+ NpmPackageEnvelopeSchema = exports_external.object({
43507
+ "dist-tags": exports_external.record(exports_external.string(), exports_external.string()).optional().default({})
43508
+ });
43509
+ OpencodePluginTupleSchema = exports_external.tuple([exports_external.string(), exports_external.record(exports_external.string(), exports_external.unknown())]);
43510
+ OpencodeConfigSchema = exports_external.object({
43511
+ plugin: exports_external.array(exports_external.union([exports_external.string(), OpencodePluginTupleSchema])).optional()
43512
+ });
43513
+ PackageJsonSchema = exports_external.object({
43514
+ name: exports_external.string().optional(),
43515
+ version: exports_external.string().optional(),
43516
+ dependencies: exports_external.record(exports_external.string(), exports_external.string()).optional()
43517
+ }).passthrough();
43518
+ });
43519
+
43520
+ // ../plugin/src/hooks/auto-update-checker/checker.ts
43521
+ import {
43522
+ accessSync as accessSync2,
43523
+ existsSync as existsSync28,
43524
+ constants as fsConstants,
43525
+ readFileSync as readFileSync19,
43526
+ renameSync as renameSync6,
43527
+ statSync as statSync11,
43528
+ writeFileSync as writeFileSync8
43529
+ } from "node:fs";
43530
+ import { dirname as dirname16, isAbsolute as isAbsolute4, join as join26, resolve as resolve7 } from "node:path";
43531
+ function warn(message) {
43532
+ log3(`WARN: ${message}`);
43533
+ }
43534
+ function isString(value) {
43535
+ return typeof value === "string";
43536
+ }
43537
+ function pluginSpecifier(entry) {
43538
+ return typeof entry === "string" ? entry : entry[0];
43539
+ }
43540
+ function getPluginEntries(config2) {
43541
+ const parsed = OpencodeConfigSchema.safeParse(config2);
43542
+ if (!parsed.success)
43543
+ return [];
43544
+ return (parsed.data.plugin ?? []).map(pluginSpecifier).filter(isString);
43545
+ }
43546
+ function parseJsonConfig(content) {
43547
+ try {
43548
+ return import_comment_json11.parse(content);
43549
+ } catch (err) {
43550
+ warn(`[auto-update-checker] Failed to parse OpenCode config: ${String(err)}`);
43551
+ return null;
43552
+ }
43553
+ }
43554
+ function getSurfaceConfigPaths(directory, surface) {
43555
+ const name = surface === "server" ? "opencode" : "tui";
43556
+ const globalDir = dirname16(USER_OPENCODE_CONFIG);
43557
+ const dirs = [
43558
+ globalDir,
43559
+ directory,
43560
+ join26(directory, ".opencode"),
43561
+ process.env.OPENCODE_CONFIG_DIR
43562
+ ].filter((value) => Boolean(value));
43563
+ const paths = [];
43564
+ for (const dir of dirs) {
43565
+ for (const extension of ["json", "jsonc"]) {
43566
+ const path6 = join26(dir, `${name}.${extension}`);
43567
+ if (!paths.includes(path6))
43568
+ paths.push(path6);
43569
+ }
43570
+ }
43571
+ return paths;
43572
+ }
43573
+ function getWinningConfig(directory, surface) {
43574
+ let winner = null;
43575
+ for (const path6 of getSurfaceConfigPaths(directory, surface)) {
43576
+ try {
43577
+ if (!existsSync28(path6))
43578
+ continue;
43579
+ const parsed = parseJsonConfig(readFileSync19(path6, "utf-8"));
43580
+ const entries = getPluginEntries(parsed);
43581
+ if (entries.some((entry) => entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))) {
43582
+ if (winner) {
43583
+ log3(`[auto-update-checker] ${surface} config ${winner.path} is shadowed by ${path6}`);
43584
+ }
43585
+ winner = { path: path6, entries };
43586
+ }
43587
+ } catch {}
43588
+ }
43589
+ return winner;
43590
+ }
43591
+ function findPluginEntry(directory, surface = "server") {
43592
+ const winner = getWinningConfig(directory, surface);
43593
+ if (!winner)
43594
+ return null;
43595
+ const entry = winner.entries.find((value) => value === PACKAGE_NAME || value.startsWith(`${PACKAGE_NAME}@`));
43596
+ if (!entry)
43597
+ return null;
43598
+ const pinnedVersion = entry.startsWith(`${PACKAGE_NAME}@`) ? entry.slice(PACKAGE_NAME.length + 1) : null;
43599
+ return {
43600
+ entry,
43601
+ isPinned: pinnedVersion !== null && pinnedVersion !== "latest",
43602
+ pinnedVersion: pinnedVersion && pinnedVersion !== "latest" ? pinnedVersion : null,
43603
+ configPath: winner.path
43604
+ };
43605
+ }
43606
+ var import_comment_json11;
43607
+ var init_checker = __esm(() => {
43608
+ init_logger();
43609
+ init_constants2();
43610
+ init_types();
43611
+ import_comment_json11 = __toESM(require_src3(), 1);
43612
+ });
43613
+
43614
+ // src/lib/opencode-plugin-schema-fence.ts
43615
+ import { existsSync as existsSync29, readdirSync as readdirSync4, readFileSync as readFileSync20 } from "node:fs";
43616
+ import { join as join27 } from "node:path";
43617
+ import { gunzipSync } from "node:zlib";
43618
+ function readPackageVersion(packageJsonPath) {
43619
+ try {
43620
+ if (!existsSync29(packageJsonPath))
43621
+ return null;
43622
+ const packageJson = JSON.parse(readFileSync20(packageJsonPath, "utf-8"));
43623
+ if (packageJson.name !== OPENCODE_PLUGIN_NAME || typeof packageJson.version !== "string") {
43624
+ return null;
43625
+ }
43626
+ return packageJson.version;
43627
+ } catch {
43628
+ return null;
43629
+ }
43630
+ }
43631
+ function readFenceValue(text3) {
43632
+ const values = new Set;
43633
+ for (const match of text3.matchAll(FENCE_PATTERN)) {
43634
+ const version2 = Number.parseInt(match[1] ?? "", 10);
43635
+ if (Number.isFinite(version2))
43636
+ values.add(version2);
43637
+ }
43638
+ return values.size === 1 ? [...values][0] ?? null : null;
43639
+ }
43640
+ function readFenceFromDist(packageDirectory) {
43641
+ const distDirectory = join27(packageDirectory, "dist");
43642
+ if (!existsSync29(distDirectory))
43643
+ return null;
43644
+ const pending = [distDirectory];
43645
+ const fenceValues = new Set;
43646
+ while (pending.length > 0) {
43647
+ const directory = pending.pop();
43648
+ if (!directory)
43649
+ continue;
43650
+ try {
43651
+ for (const entry of readdirSync4(directory, { withFileTypes: true })) {
43652
+ const path6 = join27(directory, entry.name);
43653
+ if (entry.isDirectory()) {
43654
+ pending.push(path6);
43655
+ continue;
43656
+ }
43657
+ if (!entry.isFile() || !/\.(?:[cm]?js|ts)$/.test(entry.name))
43658
+ continue;
43659
+ const fence = readFenceValue(readFileSync20(path6, "utf-8"));
43660
+ if (fence !== null)
43661
+ fenceValues.add(fence);
43662
+ }
43663
+ } catch {
43664
+ return null;
43665
+ }
43666
+ }
43667
+ return fenceValues.size === 1 ? [...fenceValues][0] ?? null : null;
43668
+ }
43669
+ function findInstalledPluginPackage(cacheDirectory, specifier, requestedVersion) {
43670
+ const directCacheRoot = join27(cacheDirectory, specifier);
43671
+ const candidates = [directCacheRoot];
43672
+ try {
43673
+ for (const entry of readdirSync4(cacheDirectory, { withFileTypes: true })) {
43674
+ if (!entry.isDirectory())
43675
+ continue;
43676
+ const candidate = join27(cacheDirectory, entry.name);
43677
+ if (!candidates.includes(candidate))
43678
+ candidates.push(candidate);
43679
+ }
43680
+ } catch {}
43681
+ for (const cacheRoot of candidates) {
43682
+ const directory = join27(cacheRoot, "node_modules", ...PACKAGE_PATH_SEGMENTS);
43683
+ const version2 = readPackageVersion(join27(directory, "package.json"));
43684
+ if (!version2)
43685
+ continue;
43686
+ if (cacheRoot === directCacheRoot || EXACT_VERSION_PATTERN.test(requestedVersion) && version2 === requestedVersion) {
43687
+ return { directory, version: version2 };
43688
+ }
43689
+ }
43690
+ return null;
43691
+ }
43692
+ function readTarText(bytes, offset, length) {
43693
+ const end = Math.min(offset + length, bytes.length);
43694
+ let nul = offset;
43695
+ while (nul < end && bytes[nul] !== 0)
43696
+ nul++;
43697
+ return new TextDecoder().decode(bytes.subarray(offset, nul));
43698
+ }
43699
+ function readTarOctal(bytes, offset, length) {
43700
+ const value = readTarText(bytes, offset, length).trim();
43701
+ if (!/^[0-7]+$/.test(value))
43702
+ return null;
43703
+ const parsed = Number.parseInt(value, 8);
43704
+ return Number.isFinite(parsed) ? parsed : null;
43705
+ }
43706
+ function readFenceFromNpmTarball(tarball) {
43707
+ let archive;
43708
+ try {
43709
+ archive = gunzipSync(tarball);
43710
+ } catch {
43711
+ return null;
43712
+ }
43713
+ const fenceValues = new Set;
43714
+ for (let offset = 0;offset + 512 <= archive.length; ) {
43715
+ const name = readTarText(archive, offset, 100);
43716
+ if (!name)
43717
+ break;
43718
+ const prefix = readTarText(archive, offset + 345, 155);
43719
+ const path6 = prefix ? `${prefix}/${name}` : name;
43720
+ const size = readTarOctal(archive, offset + 124, 12);
43721
+ if (size === null)
43722
+ return null;
43723
+ const contentStart = offset + 512;
43724
+ const contentEnd = contentStart + size;
43725
+ if (contentEnd > archive.length)
43726
+ return null;
43727
+ if (/^package\/dist\/.+\.(?:[cm]?js|ts)$/.test(path6)) {
43728
+ const fence = readFenceValue(new TextDecoder().decode(archive.subarray(contentStart, contentEnd)));
43729
+ if (fence !== null)
43730
+ fenceValues.add(fence);
43731
+ }
43732
+ offset = contentStart + Math.ceil(size / 512) * 512;
43733
+ }
43734
+ return fenceValues.size === 1 ? [...fenceValues][0] ?? null : null;
43735
+ }
43736
+ function npmPackageVersionUrl(version2) {
43737
+ const packagePath = encodeURIComponent(OPENCODE_PLUGIN_NAME).replace("%2F", "/");
43738
+ return `https://registry.npmjs.org/${packagePath}/${encodeURIComponent(version2)}`;
43739
+ }
43740
+ async function resolveFenceFromNpmTarball(requestedVersion, fetchImpl) {
43741
+ const controller = new AbortController;
43742
+ const timeout = setTimeout(() => controller.abort(), NPM_TIMEOUT_MS);
43743
+ try {
43744
+ const metadataResponse = await fetchImpl(npmPackageVersionUrl(requestedVersion), {
43745
+ signal: controller.signal,
43746
+ headers: { Accept: "application/json" }
43747
+ });
43748
+ if (!metadataResponse.ok)
43749
+ return null;
43750
+ const metadata = await metadataResponse.json();
43751
+ if (typeof metadata.version !== "string" || typeof metadata.dist?.tarball !== "string") {
43752
+ return null;
43753
+ }
43754
+ const tarballUrl = new URL(metadata.dist.tarball);
43755
+ if (tarballUrl.protocol !== "https:")
43756
+ return null;
43757
+ const tarballResponse = await fetchImpl(tarballUrl, { signal: controller.signal });
43758
+ if (!tarballResponse.ok)
43759
+ return null;
43760
+ const contentLength = Number(tarballResponse.headers.get("content-length"));
43761
+ if (Number.isFinite(contentLength) && contentLength > MAX_TARBALL_BYTES)
43762
+ return null;
43763
+ const tarball = new Uint8Array(await tarballResponse.arrayBuffer());
43764
+ if (tarball.byteLength > MAX_TARBALL_BYTES)
43765
+ return null;
43766
+ const supportedVersion = readFenceFromNpmTarball(tarball);
43767
+ return supportedVersion === null ? null : { version: metadata.version, supportedVersion, source: "npm-tarball" };
43768
+ } catch {
43769
+ return null;
43770
+ } finally {
43771
+ clearTimeout(timeout);
43772
+ }
43773
+ }
43774
+ async function resolvePluginFence(specifier, requestedVersion, deps) {
43775
+ const installed = findInstalledPluginPackage(deps.getOpenCodePluginCacheDir(), specifier, requestedVersion);
43776
+ if (installed) {
43777
+ const supportedVersion = readFenceFromDist(installed.directory);
43778
+ if (supportedVersion !== null) {
43779
+ return { version: installed.version, supportedVersion, source: "installed" };
43780
+ }
43781
+ }
43782
+ return resolveFenceFromNpmTarball(requestedVersion, deps.fetch);
43783
+ }
43784
+ async function inspectPinnedOpenCodePluginSchemaFences(options, deps = {}) {
43785
+ const findEntry = deps.findPluginEntry ?? findPluginEntry;
43786
+ const resolutionDeps = {
43787
+ fetch: deps.fetch ?? globalThis.fetch,
43788
+ getOpenCodePluginCacheDir: deps.getOpenCodePluginCacheDir ?? getOpenCodePluginCacheDir
43789
+ };
43790
+ const resolvedBySpecifier = new Map;
43791
+ const findings = [];
43792
+ for (const surface of ["server", "tui"]) {
43793
+ const entry = findEntry(options.directory, surface);
43794
+ if (!entry?.isPinned || !entry.pinnedVersion)
43795
+ continue;
43796
+ let resolved = resolvedBySpecifier.get(entry.entry);
43797
+ if (!resolved) {
43798
+ resolved = resolvePluginFence(entry.entry, entry.pinnedVersion, resolutionDeps);
43799
+ resolvedBySpecifier.set(entry.entry, resolved);
43800
+ }
43801
+ const fence = await resolved;
43802
+ const supportedVersion = fence?.supportedVersion ?? null;
43803
+ findings.push({
43804
+ status: supportedVersion === null ? "unknown" : supportedVersion < options.databaseVersion ? "fail" : "pass",
43805
+ surface,
43806
+ specifier: entry.entry,
43807
+ configPath: entry.configPath,
43808
+ pinnedVersion: fence?.version ?? entry.pinnedVersion,
43809
+ databaseVersion: options.databaseVersion,
43810
+ supportedVersion,
43811
+ source: fence?.source ?? null
43812
+ });
43813
+ }
43814
+ return findings;
43815
+ }
43816
+ var PACKAGE_PATH_SEGMENTS, MAX_TARBALL_BYTES, NPM_TIMEOUT_MS = 5000, FENCE_PATTERN, EXACT_VERSION_PATTERN;
43817
+ var init_opencode_plugin_schema_fence = __esm(() => {
43818
+ init_checker();
43819
+ init_opencode_plugin_cache();
43820
+ init_paths();
43821
+ PACKAGE_PATH_SEGMENTS = OPENCODE_PLUGIN_NAME.split("/");
43822
+ MAX_TARBALL_BYTES = 25 * 1024 * 1024;
43823
+ FENCE_PATTERN = /\bLATEST_SUPPORTED_VERSION\s*=\s*(\d+)\b/g;
43824
+ EXACT_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
43825
+ });
43826
+
43355
43827
  // ../plugin/src/features/magic-context/fail-closed-block.ts
43828
+ function normalizeFailClosedProcessKind(process3) {
43829
+ switch (process3.kind) {
43830
+ case "OpenCode server":
43831
+ case "OpenCode instance (TUI/CLI)":
43832
+ case "Pi":
43833
+ case "process":
43834
+ return process3.kind;
43835
+ }
43836
+ switch (process3.harness?.trim().toLowerCase()) {
43837
+ case "opencode server":
43838
+ return "OpenCode server";
43839
+ case "opencode instance (tui/cli)":
43840
+ case "opencode instance":
43841
+ return "OpenCode instance (TUI/CLI)";
43842
+ case "pi":
43843
+ case "pi harness":
43844
+ case "omp":
43845
+ return "Pi";
43846
+ default:
43847
+ return "process";
43848
+ }
43849
+ }
43356
43850
  function formatFailClosedBlockingProcesses(processes) {
43357
43851
  const uniqueProcesses = new Map;
43358
43852
  for (const process3 of processes) {
43359
- if (!process3.harness.trim() || !Number.isInteger(process3.pid) || process3.pid <= 0)
43853
+ if (!Number.isInteger(process3.pid) || process3.pid <= 0)
43360
43854
  continue;
43361
- uniqueProcesses.set(`${process3.harness}\x00${process3.pid}`, {
43362
- harness: process3.harness.trim(),
43363
- pid: process3.pid
43364
- });
43855
+ const kind = normalizeFailClosedProcessKind(process3);
43856
+ uniqueProcesses.set(`${kind}\x00${process3.pid}`, { kind, pid: process3.pid });
43365
43857
  }
43366
43858
  const entries = [...uniqueProcesses.values()];
43367
43859
  const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
43368
- const rendered = visible.map(({ harness, pid }) => `${harness} (PID ${pid})`);
43860
+ const rendered = visible.map(({ kind, pid }) => `${kind} (PID ${pid})`);
43369
43861
  const omitted = entries.length - visible.length;
43370
43862
  if (omitted > 0)
43371
43863
  rendered.push(`${omitted} more blocking process(es)`);
43372
43864
  if (rendered.length === 0)
43373
- return "a live harness process";
43865
+ return "a live process";
43374
43866
  if (rendered.length === 1)
43375
43867
  return rendered[0];
43376
43868
  const last = rendered.pop();
@@ -43380,9 +43872,9 @@ function formatFailClosedBlockingMessage(reason) {
43380
43872
  if (reason.kind === "migration_guard") {
43381
43873
  if (reason.unreadableFile) {
43382
43874
  const arm = reason.unreadableArm ?? "io";
43383
- const recovery = arm === "io" ? `If no OpenCode server is running, it is safe to delete ${reason.unreadableFile} and retry.` : `The file may be a recent incomplete write; retry after the file is older than the ten-minute grace window, or stop OpenCode before deleting it.`;
43875
+ const recovery = arm === "io" ? `If none of these processes are running, it is safe to delete ${reason.unreadableFile} and retry.` : `The file may be a recent incomplete write; retry after the file is older than the ten-minute grace window, or stop the relevant process before deleting it.`;
43384
43876
  return [
43385
- `Magic Context cannot migrate the shared database because RPC discovery file ${reason.unreadableFile} is uncertain (${arm} arm), so the absence of a live OpenCode server cannot be proven.`,
43877
+ `Magic Context cannot migrate the shared database because RPC discovery file ${reason.unreadableFile} is uncertain (${arm} arm), so the absence of a live process cannot be proven.`,
43386
43878
  recovery,
43387
43879
  `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
43388
43880
  ].join(" ");
@@ -43461,13 +43953,13 @@ var init_storage_versions = __esm(async () => {
43461
43953
  });
43462
43954
 
43463
43955
  // src/commands/doctor-opencode-cache.ts
43464
- import { existsSync as existsSync28, readFileSync as readFileSync19, rmSync as rmSync3 } from "node:fs";
43956
+ import { existsSync as existsSync30, readFileSync as readFileSync21, rmSync as rmSync3 } from "node:fs";
43465
43957
  function readCachedPluginVersion(pluginCacheDir) {
43466
43958
  try {
43467
43959
  const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
43468
- if (!existsSync28(installedPkgPath))
43960
+ if (!existsSync30(installedPkgPath))
43469
43961
  return;
43470
- const pkg = JSON.parse(readFileSync19(installedPkgPath, "utf-8"));
43962
+ const pkg = JSON.parse(readFileSync21(installedPkgPath, "utf-8"));
43471
43963
  return typeof pkg.version === "string" ? pkg.version : undefined;
43472
43964
  } catch {
43473
43965
  return;
@@ -43476,7 +43968,7 @@ function readCachedPluginVersion(pluginCacheDir) {
43476
43968
  async function clearPluginCache(options = {}, deps = {}) {
43477
43969
  const remove = deps.remove ?? ((path6) => rmSync3(path6, { recursive: true, force: true }));
43478
43970
  const pluginCacheRoots = getOpenCodePluginCacheRoots();
43479
- const existingRoots = pluginCacheRoots.filter((root) => existsSync28(root));
43971
+ const existingRoots = pluginCacheRoots.filter((root) => existsSync30(root));
43480
43972
  if (existingRoots.length === 0) {
43481
43973
  return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
43482
43974
  }
@@ -43544,10 +44036,10 @@ var init_doctor_opencode_cache = __esm(() => {
43544
44036
 
43545
44037
  // src/commands/doctor-opencode.ts
43546
44038
  import { execSync as execSync2, spawnSync as spawnSync6 } from "node:child_process";
43547
- import { existsSync as existsSync29, readFileSync as readFileSync20, statSync as statSync11 } from "node:fs";
44039
+ import { existsSync as existsSync31, readFileSync as readFileSync22, statSync as statSync12 } from "node:fs";
43548
44040
  import { createRequire as createRequire5 } from "node:module";
43549
- import { homedir as homedir16 } from "node:os";
43550
- import { join as join25 } from "node:path";
44041
+ import { homedir as homedir17 } from "node:os";
44042
+ import { join as join28 } from "node:path";
43551
44043
  function resolveCompactionEnabledForDoctor() {
43552
44044
  try {
43553
44045
  const config2 = loadPluginConfig(process.cwd());
@@ -43646,15 +44138,15 @@ function getUserNpmrcPath() {
43646
44138
  if (custom2)
43647
44139
  return custom2;
43648
44140
  const home = process.env.HOME?.trim();
43649
- return join25(home || homedir16(), ".npmrc");
44141
+ return join28(home || homedir17(), ".npmrc");
43650
44142
  }
43651
44143
  function collectNpmReleaseAgeWarnings() {
43652
44144
  const ageWarnings = [];
43653
44145
  const npmrcPath = getUserNpmrcPath();
43654
- if (!existsSync29(npmrcPath))
44146
+ if (!existsSync31(npmrcPath))
43655
44147
  return ageWarnings;
43656
44148
  try {
43657
- const npmrc = readFileSync20(npmrcPath, "utf-8");
44149
+ const npmrc = readFileSync22(npmrcPath, "utf-8");
43658
44150
  for (const line of npmrc.split(`
43659
44151
  `)) {
43660
44152
  const trimmed = line.trim();
@@ -43793,12 +44285,12 @@ function checkLocalEmbeddingRuntimeForDoctor() {
43793
44285
  return { issues: 0 };
43794
44286
  }
43795
44287
  async function checkEmbeddingConfig(magicContextConfigPath) {
43796
- if (!existsSync29(magicContextConfigPath)) {
44288
+ if (!existsSync31(magicContextConfigPath)) {
43797
44289
  return checkLocalEmbeddingRuntimeForDoctor();
43798
44290
  }
43799
44291
  let rawText;
43800
44292
  try {
43801
- rawText = readFileSync20(magicContextConfigPath, "utf-8");
44293
+ rawText = readFileSync22(magicContextConfigPath, "utf-8");
43802
44294
  } catch {
43803
44295
  log2.warn("Could not read magic-context.jsonc for embedding check");
43804
44296
  return { issues: 1 };
@@ -43809,7 +44301,7 @@ async function checkEmbeddingConfig(magicContextConfigPath) {
43809
44301
  });
43810
44302
  let parsedConfig;
43811
44303
  try {
43812
- parsedConfig = import_comment_json11.parse(substituted.text);
44304
+ parsedConfig = import_comment_json12.parse(substituted.text);
43813
44305
  } catch (error51) {
43814
44306
  log2.warn(`Embedding check skipped — could not parse magic-context.jsonc: ${error51 instanceof Error ? error51.message : String(error51)}`);
43815
44307
  return { issues: 1 };
@@ -43921,7 +44413,7 @@ async function runDoctor2(options = {}) {
43921
44413
  const v22Result = await runV22BackfillCommands({
43922
44414
  name: "OpenCode",
43923
44415
  openDatabase: (readonly2 = true) => {
43924
- const dbPath2 = join25(getMagicContextStorageDir(), "context.db");
44416
+ const dbPath2 = join28(getMagicContextStorageDir(), "context.db");
43925
44417
  v22Db = readonly2 ? openExistingContextDatabase(dbPath2, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath2);
43926
44418
  return v22Db;
43927
44419
  },
@@ -43944,7 +44436,7 @@ async function runDoctor2(options = {}) {
43944
44436
  log2.success(msg);
43945
44437
  passCount++;
43946
44438
  };
43947
- const warn = (msg) => {
44439
+ const warn2 = (msg) => {
43948
44440
  log2.warn(msg);
43949
44441
  warnCount++;
43950
44442
  };
@@ -43953,17 +44445,17 @@ async function runDoctor2(options = {}) {
43953
44445
  failCount++;
43954
44446
  issues++;
43955
44447
  };
43956
- const authorityDbPath = join25(getMagicContextStorageDir(), "context.db");
44448
+ const authorityDbPath = join28(getMagicContextStorageDir(), "context.db");
43957
44449
  let authorityDb = null;
43958
44450
  try {
43959
44451
  authorityDb = openExistingContextDatabase(authorityDbPath, { readonly: true });
43960
44452
  if (authorityDb) {
43961
- await reportAuthorityMarkers({ db: authorityDb, info: log2.info, warn });
44453
+ await reportAuthorityMarkers({ db: authorityDb, info: log2.info, warn: warn2 });
43962
44454
  } else {
43963
44455
  log2.info("Authority: no context database found");
43964
44456
  }
43965
44457
  } catch (error51) {
43966
- warn(`Authority check unavailable: ${error51 instanceof Error ? error51.message : String(error51)}`);
44458
+ warn2(`Authority check unavailable: ${error51 instanceof Error ? error51.message : String(error51)}`);
43967
44459
  } finally {
43968
44460
  authorityDb?.close();
43969
44461
  }
@@ -43994,7 +44486,7 @@ async function runDoctor2(options = {}) {
43994
44486
  if (!npmLatest) {
43995
44487
  log2.info(`Magic Context CLI v${selfVersion2}; npm latest check unavailable`);
43996
44488
  } else if (compareVersions(selfVersion2, npmLatest) < 0) {
43997
- warn(`Magic Context CLI v${selfVersion2} is older than npm latest v${npmLatest}`);
44489
+ warn2(`Magic Context CLI v${selfVersion2} is older than npm latest v${npmLatest}`);
43998
44490
  } else {
43999
44491
  pass(`Magic Context CLI v${selfVersion2} is current (npm latest v${npmLatest})`);
44000
44492
  }
@@ -44004,15 +44496,15 @@ async function runDoctor2(options = {}) {
44004
44496
  } else {
44005
44497
  pass(`OpenCode config: ${paths.opencodeConfig}`);
44006
44498
  }
44007
- if (existsSync29(paths.magicContextConfig)) {
44499
+ if (existsSync31(paths.magicContextConfig)) {
44008
44500
  pass(`Magic Context config: ${paths.magicContextConfig}`);
44009
44501
  try {
44010
- const raw = readFileSync20(paths.magicContextConfig, "utf-8");
44502
+ const raw = readFileSync22(paths.magicContextConfig, "utf-8");
44011
44503
  const substituted = substituteConfigVariables({
44012
44504
  text: raw,
44013
44505
  configPath: paths.magicContextConfig
44014
44506
  }).text;
44015
- import_comment_json11.parse(substituted);
44507
+ import_comment_json12.parse(substituted);
44016
44508
  pass("magic-context.jsonc parses as valid JSONC");
44017
44509
  } catch (err) {
44018
44510
  fail(`magic-context.jsonc parse failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -44021,7 +44513,7 @@ async function runDoctor2(options = {}) {
44021
44513
  const result = loadPluginConfig(process.cwd());
44022
44514
  const warnings = result.configWarnings ?? [];
44023
44515
  if (warnings.length > 0) {
44024
- warn(`Magic Context config has ${warnings.length} warning(s) — see 'magic-context doctor --issue' for details`);
44516
+ warn2(`Magic Context config has ${warnings.length} warning(s) — see 'magic-context doctor --issue' for details`);
44025
44517
  } else {
44026
44518
  pass("Magic Context config loads successfully");
44027
44519
  }
@@ -44029,13 +44521,13 @@ async function runDoctor2(options = {}) {
44029
44521
  fail(`Could not load Magic Context config: ${err instanceof Error ? err.message : String(err)}`);
44030
44522
  }
44031
44523
  } else {
44032
- warn(`No magic-context.jsonc found — using defaults`);
44524
+ warn2(`No magic-context.jsonc found — using defaults`);
44033
44525
  log2.info(" Run 'setup' to create one with model recommendations");
44034
44526
  }
44035
- if (existsSync29(paths.magicContextConfig)) {
44527
+ if (existsSync31(paths.magicContextConfig)) {
44036
44528
  try {
44037
- const mcRaw = readFileSync20(paths.magicContextConfig, "utf-8");
44038
- const mcConfig = import_comment_json11.parse(mcRaw);
44529
+ const mcRaw = readFileSync22(paths.magicContextConfig, "utf-8");
44530
+ const mcConfig = import_comment_json12.parse(mcRaw);
44039
44531
  let mcChanged = false;
44040
44532
  const experimental = mcConfig.experimental;
44041
44533
  if (experimental && "compaction_markers" in experimental) {
@@ -44143,7 +44635,7 @@ async function runDoctor2(options = {}) {
44143
44635
  fixed++;
44144
44636
  }
44145
44637
  if (mcChanged) {
44146
- writeFileAtomic(paths.magicContextConfig, `${import_comment_json11.stringify(mcConfig, null, 2)}
44638
+ writeFileAtomic(paths.magicContextConfig, `${import_comment_json12.stringify(mcConfig, null, 2)}
44147
44639
  `);
44148
44640
  }
44149
44641
  } catch {
@@ -44152,12 +44644,12 @@ async function runDoctor2(options = {}) {
44152
44644
  }
44153
44645
  if (paths.opencodeConfigFormat !== "none") {
44154
44646
  try {
44155
- const raw = readFileSync20(paths.opencodeConfig, "utf-8");
44156
- const config2 = import_comment_json11.parse(raw);
44647
+ const raw = readFileSync22(paths.opencodeConfig, "utf-8");
44648
+ const config2 = import_comment_json12.parse(raw);
44157
44649
  const rawPlugins = Array.isArray(config2?.plugin) ? config2.plugin : [];
44158
44650
  const existingIdx = rawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
44159
44651
  if (rawPlugins.some((entry) => isLocalPathPluginEntry(entry) && String(entry).includes("magic-context") && !isDevPathPluginEntry(entry))) {
44160
- warn("An unverifiable local OpenCode plugin path was ignored because its package name is not Magic Context");
44652
+ warn2("An unverifiable local OpenCode plugin path was ignored because its package name is not Magic Context");
44161
44653
  }
44162
44654
  const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
44163
44655
  const entryAsString = (entry) => {
@@ -44177,7 +44669,7 @@ async function runDoctor2(options = {}) {
44177
44669
  } else {
44178
44670
  const isPinned = isPinnedOpenCodePluginSpecifier(oldEntryStr);
44179
44671
  if (isPinned && !options.force) {
44180
- warn(`Plugin pinned to ${oldEntryStr} in ${configName} — use 'doctor --force' to upgrade`);
44672
+ warn2(`Plugin pinned to ${oldEntryStr} in ${configName} — use 'doctor --force' to upgrade`);
44181
44673
  } else {
44182
44674
  if (Array.isArray(oldEntry) && oldEntry.length >= 1) {
44183
44675
  const replacement = [...oldEntry];
@@ -44187,7 +44679,7 @@ async function runDoctor2(options = {}) {
44187
44679
  rawPlugins[existingIdx] = OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
44188
44680
  }
44189
44681
  config2.plugin = rawPlugins;
44190
- writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config2, null, 2)}
44682
+ writeFileAtomic(paths.opencodeConfig, `${import_comment_json12.stringify(config2, null, 2)}
44191
44683
  `);
44192
44684
  pass(`Upgraded plugin entry in ${configName}: ${oldEntryStr} → ${OPENCODE_PLUGIN_ENTRY_WITH_VERSION}`);
44193
44685
  fixed++;
@@ -44196,13 +44688,13 @@ async function runDoctor2(options = {}) {
44196
44688
  } else {
44197
44689
  rawPlugins.push(OPENCODE_PLUGIN_ENTRY_WITH_VERSION);
44198
44690
  config2.plugin = rawPlugins;
44199
- writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config2, null, 2)}
44691
+ writeFileAtomic(paths.opencodeConfig, `${import_comment_json12.stringify(config2, null, 2)}
44200
44692
  `);
44201
44693
  pass(`Added plugin to ${configName}`);
44202
44694
  fixed++;
44203
44695
  }
44204
44696
  } catch {
44205
- warn("Could not parse opencode config to verify plugin entry");
44697
+ warn2("Could not parse opencode config to verify plugin entry");
44206
44698
  }
44207
44699
  }
44208
44700
  const cwd = process.cwd();
@@ -44219,14 +44711,14 @@ async function runDoctor2(options = {}) {
44219
44711
  fixed++;
44220
44712
  }
44221
44713
  if (actions.length > 0) {
44222
- warn("Restart OpenCode for conflict fixes to take effect");
44714
+ warn2("Restart OpenCode for conflict fixes to take effect");
44223
44715
  }
44224
44716
  } else {
44225
44717
  if (!compactionEnabled) {
44226
44718
  if (conflictResult.nativeCompaction.auto || conflictResult.nativeCompaction.prune) {
44227
44719
  pass("No conflicts detected (compaction, DCP, OMO hooks) — native compaction active (compaction-off mode)");
44228
44720
  } else {
44229
- warn("No compaction manager is active: Magic Context compaction is off and OpenCode auto-compaction is disabled");
44721
+ warn2("No compaction manager is active: Magic Context compaction is off and OpenCode auto-compaction is disabled");
44230
44722
  }
44231
44723
  } else {
44232
44724
  pass("No conflicts detected (compaction, DCP, OMO hooks)");
@@ -44235,16 +44727,16 @@ async function runDoctor2(options = {}) {
44235
44727
  const tuiAdded = ensureTuiPluginEntry();
44236
44728
  if (tuiAdded) {
44237
44729
  pass("Added TUI sidebar plugin to tui.json");
44238
- warn("Restart OpenCode to see the sidebar");
44730
+ warn2("Restart OpenCode to see the sidebar");
44239
44731
  fixed++;
44240
- } else if (existsSync29(paths.tuiConfig)) {
44732
+ } else if (existsSync31(paths.tuiConfig)) {
44241
44733
  try {
44242
- const tuiRaw = readFileSync20(paths.tuiConfig, "utf-8");
44243
- const tuiConfig = import_comment_json11.parse(tuiRaw);
44734
+ const tuiRaw = readFileSync22(paths.tuiConfig, "utf-8");
44735
+ const tuiConfig = import_comment_json12.parse(tuiRaw);
44244
44736
  const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
44245
44737
  const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
44246
44738
  if (tuiRawPlugins.some((entry) => isLocalPathPluginEntry(entry) && String(entry).includes("magic-context") && !isDevPathPluginEntry(entry))) {
44247
- warn("An unverifiable local TUI plugin path was ignored because its package name is not Magic Context");
44739
+ warn2("An unverifiable local TUI plugin path was ignored because its package name is not Magic Context");
44248
44740
  }
44249
44741
  const tuiEntryAsString = (entry) => {
44250
44742
  if (typeof entry === "string")
@@ -44261,7 +44753,7 @@ async function runDoctor2(options = {}) {
44261
44753
  } else {
44262
44754
  const tuiPinned = isPinnedOpenCodePluginSpecifier(tuiEntryStr);
44263
44755
  if (tuiPinned && !options.force) {
44264
- warn(`TUI plugin pinned to ${tuiEntryStr} — use 'doctor --force' to upgrade`);
44756
+ warn2(`TUI plugin pinned to ${tuiEntryStr} — use 'doctor --force' to upgrade`);
44265
44757
  } else if (tuiPinned && options.force) {
44266
44758
  if (Array.isArray(tuiEntry) && tuiEntry.length >= 1) {
44267
44759
  const replacement = [...tuiEntry];
@@ -44271,7 +44763,7 @@ async function runDoctor2(options = {}) {
44271
44763
  tuiRawPlugins[tuiIdx] = OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
44272
44764
  }
44273
44765
  tuiConfig.plugin = tuiRawPlugins;
44274
- writeFileAtomic(paths.tuiConfig, `${import_comment_json11.stringify(tuiConfig, null, 2)}
44766
+ writeFileAtomic(paths.tuiConfig, `${import_comment_json12.stringify(tuiConfig, null, 2)}
44275
44767
  `);
44276
44768
  pass(`Upgraded TUI plugin: ${tuiEntryStr} → ${OPENCODE_PLUGIN_ENTRY_WITH_VERSION}`);
44277
44769
  fixed++;
@@ -44288,10 +44780,10 @@ async function runDoctor2(options = {}) {
44288
44780
  } else {
44289
44781
  fail("Could not create or verify the TUI sidebar config");
44290
44782
  }
44291
- if (existsSync29(paths.magicContextConfig)) {
44783
+ if (existsSync31(paths.magicContextConfig)) {
44292
44784
  try {
44293
- const mcRaw = readFileSync20(paths.magicContextConfig, "utf-8");
44294
- const mcConfig = import_comment_json11.parse(mcRaw);
44785
+ const mcRaw = readFileSync22(paths.magicContextConfig, "utf-8");
44786
+ const mcConfig = import_comment_json12.parse(mcRaw);
44295
44787
  const warning = checkUserMemoriesDreamerCompatibility(mcConfig);
44296
44788
  if (warning) {
44297
44789
  log2.warn(warning);
@@ -44307,8 +44799,8 @@ async function runDoctor2(options = {}) {
44307
44799
  warnCount++;
44308
44800
  else
44309
44801
  passCount++;
44310
- const dbPath = join25(getMagicContextStorageDir(), "context.db");
44311
- if (!existsSync29(dbPath)) {
44802
+ const dbPath = join28(getMagicContextStorageDir(), "context.db");
44803
+ if (!existsSync31(dbPath)) {
44312
44804
  log2.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
44313
44805
  } else {
44314
44806
  log2.info(`Shared context DB exists at ${dbPath}`);
@@ -44321,6 +44813,21 @@ async function runDoctor2(options = {}) {
44321
44813
  pass("Opened the shared DB with a supported schema");
44322
44814
  const storageVersions = readStorageVersions(db);
44323
44815
  log2.info(formatStorageVersions(storageVersions));
44816
+ const pinnedPluginFenceFindings = await inspectPinnedOpenCodePluginSchemaFences({
44817
+ directory: process.cwd(),
44818
+ databaseVersion: storageVersions.context_db_schema_version
44819
+ });
44820
+ for (const finding of pinnedPluginFenceFindings) {
44821
+ const location = `${finding.surface} entry ${finding.specifier} in ${sanitizePathString(finding.configPath)}`;
44822
+ if (finding.status === "fail") {
44823
+ fail(`Pinned plugin schema fence mismatch: ${location} pins plugin v${finding.pinnedVersion}, which supports through schema v${finding.supportedVersion}; shared context.db is v${finding.databaseVersion}. Recovery: unpin the entry (use @latest), or upgrade the pin to a version released after this migration that supports v${finding.databaseVersion} or later.`);
44824
+ } else if (finding.status === "unknown") {
44825
+ warn2(`UNKNOWN: Pinned plugin schema fence could not be resolved for ${location}; shared context.db is v${finding.databaseVersion}, so doctor cannot verify the plugin that will run. Install the pinned package and rerun doctor, or unpin/upgrade it to a version released after this migration.`);
44826
+ issues++;
44827
+ } else {
44828
+ pass(`Pinned plugin schema fence: ${location} pins plugin v${finding.pinnedVersion}, which supports shared context.db v${finding.databaseVersion}.`);
44829
+ }
44830
+ }
44324
44831
  const fenceCheck = checkStorageVersionFence(storageVersions, {
44325
44832
  blockingProcesses: getLiveMigrationBlockingProcesses(getMagicContextStorageDir())
44326
44833
  });
@@ -44387,9 +44894,9 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
44387
44894
  } else if (cacheResult.action === "up_to_date") {
44388
44895
  pass(`Plugin cache up to date (v${cacheResult.cached})`);
44389
44896
  } else if (cacheResult.action === "check_unavailable") {
44390
- warn(`Plugin cache version check unavailable; preserving cached plugin${cacheResult.cached ? ` (cached: ${cacheResult.cached})` : ""}. Use doctor --force to reinstall it.`);
44897
+ warn2(`Plugin cache version check unavailable; preserving cached plugin${cacheResult.cached ? ` (cached: ${cacheResult.cached})` : ""}. Use doctor --force to reinstall it.`);
44391
44898
  } else if (cacheResult.action === "error") {
44392
- warn(`Could not clear plugin cache: ${cacheResult.error}`);
44899
+ warn2(`Could not clear plugin cache: ${cacheResult.error}`);
44393
44900
  if (cacheResult.clearedPaths && cacheResult.clearedPaths.length > 0) {
44394
44901
  log2.info(` Cleared roots: ${cacheResult.clearedPaths.join(", ")}`);
44395
44902
  }
@@ -44415,8 +44922,8 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
44415
44922
  }
44416
44923
  }
44417
44924
  const logPath = getMagicContextLogPath2("opencode");
44418
- if (existsSync29(logPath)) {
44419
- const logStat = statSync11(logPath);
44925
+ if (existsSync31(logPath)) {
44926
+ const logStat = statSync12(logPath);
44420
44927
  const sizeKb = (logStat.size / 1024).toFixed(0);
44421
44928
  log2.info(`Log file: ${logPath} (${sizeKb} KB)`);
44422
44929
  } else {
@@ -44427,7 +44934,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
44427
44934
  if (dumpBuckets.length > 0) {
44428
44935
  const totalCount = dumpBuckets.reduce((sum, b2) => sum + b2.count, 0);
44429
44936
  const sessionCount = dumpBuckets.length;
44430
- warn(`Historian debug dumps: ${totalCount} file(s) across ${sessionCount} project(s)`);
44937
+ warn2(`Historian debug dumps: ${totalCount} file(s) across ${sessionCount} project(s)`);
44431
44938
  for (const bucket of dumpBuckets) {
44432
44939
  log2.info(` [${bucket.directory}] ${bucket.count} file(s)`);
44433
44940
  for (const dump of bucket.recent.slice(0, 3)) {
@@ -44461,7 +44968,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
44461
44968
  }
44462
44969
  return 0;
44463
44970
  }
44464
- var import_comment_json11, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
44971
+ var import_comment_json12, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
44465
44972
  var init_doctor_opencode = __esm(async () => {
44466
44973
  init_config();
44467
44974
  init_agent_disable();
@@ -44480,6 +44987,7 @@ var init_doctor_opencode = __esm(async () => {
44480
44987
  init_opencode_detect();
44481
44988
  init_opencode_helpers();
44482
44989
  init_opencode_plugin_cache();
44990
+ init_opencode_plugin_schema_fence();
44483
44991
  init_paths();
44484
44992
  init_prompts();
44485
44993
  init_redaction2();
@@ -44491,15 +44999,15 @@ var init_doctor_opencode = __esm(async () => {
44491
44999
  init_v22_backfill_commands(),
44492
45000
  init_doctor_authority()
44493
45001
  ]);
44494
- import_comment_json11 = __toESM(require_src3(), 1);
45002
+ import_comment_json12 = __toESM(require_src3(), 1);
44495
45003
  });
44496
45004
 
44497
45005
  // src/lib/diagnostics-pi.ts
44498
45006
  import { createHash as createHash5 } from "node:crypto";
44499
- import { existsSync as existsSync30, readdirSync as readdirSync4, readFileSync as readFileSync21, statSync as statSync12 } from "node:fs";
45007
+ import { existsSync as existsSync32, readdirSync as readdirSync5, readFileSync as readFileSync23, statSync as statSync13 } from "node:fs";
44500
45008
  import { createRequire as createRequire6 } from "node:module";
44501
- import { homedir as homedir17, userInfo as userInfo2 } from "node:os";
44502
- import { join as join26 } from "node:path";
45009
+ import { homedir as homedir18, userInfo as userInfo2 } from "node:os";
45010
+ import { join as join29 } from "node:path";
44503
45011
  function getSelfVersion3() {
44504
45012
  const req = createRequire6(import.meta.url);
44505
45013
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -44514,7 +45022,7 @@ function getSelfVersion3() {
44514
45022
  }
44515
45023
  function fileSize2(path6) {
44516
45024
  try {
44517
- return existsSync30(path6) ? statSync12(path6).size : 0;
45025
+ return existsSync32(path6) ? statSync13(path6).size : 0;
44518
45026
  } catch {
44519
45027
  return 0;
44520
45028
  }
@@ -44530,7 +45038,7 @@ function redactSecretString(value) {
44530
45038
  return redactSecretText(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>");
44531
45039
  }
44532
45040
  function sanitizeString2(value) {
44533
- const home = process.env.HOME || homedir17();
45041
+ const home = process.env.HOME || homedir18();
44534
45042
  const username = userInfo2().username;
44535
45043
  const userHash = `<USER:${currentUserHash()}>`;
44536
45044
  let sanitized = redactSecretString(value);
@@ -44566,11 +45074,11 @@ function sanitizeValue2(value, key = "") {
44566
45074
  return value;
44567
45075
  }
44568
45076
  function readJsonc(path6) {
44569
- if (!existsSync30(path6))
45077
+ if (!existsSync32(path6))
44570
45078
  return { value: {} };
44571
45079
  try {
44572
45080
  return {
44573
- value: import_comment_json12.parse(readFileSync21(path6, "utf-8"))
45081
+ value: import_comment_json13.parse(readFileSync23(path6, "utf-8"))
44574
45082
  };
44575
45083
  } catch (error51) {
44576
45084
  return {
@@ -44586,7 +45094,7 @@ function readConfigDiagnostic(path6) {
44586
45094
  const parsed = readJsonc(path6);
44587
45095
  return {
44588
45096
  path: path6,
44589
- exists: existsSync30(path6),
45097
+ exists: existsSync32(path6),
44590
45098
  ...parsed.parseError ? { parseError: parsed.parseError } : {},
44591
45099
  flags: sanitizeValue2(parsed.value)
44592
45100
  };
@@ -44604,25 +45112,25 @@ function reverseSlugToDirectory(slug) {
44604
45112
  }
44605
45113
  function collectPiRecentSessions() {
44606
45114
  const sessionsRoot = getPiSessionsRoot();
44607
- if (!existsSync30(sessionsRoot))
45115
+ if (!existsSync32(sessionsRoot))
44608
45116
  return [];
44609
45117
  try {
44610
- const slugs = readdirSync4(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
45118
+ const slugs = readdirSync5(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
44611
45119
  const candidates = [];
44612
45120
  for (const slug of slugs) {
44613
45121
  const directory = reverseSlugToDirectory(slug);
44614
45122
  if (!directory)
44615
45123
  continue;
44616
- const slugDir = join26(sessionsRoot, slug);
45124
+ const slugDir = join29(sessionsRoot, slug);
44617
45125
  let files;
44618
45126
  try {
44619
- files = readdirSync4(slugDir).filter((name) => name.endsWith(".jsonl"));
45127
+ files = readdirSync5(slugDir).filter((name) => name.endsWith(".jsonl"));
44620
45128
  } catch {
44621
45129
  continue;
44622
45130
  }
44623
45131
  for (const file2 of files) {
44624
45132
  try {
44625
- const mtime = statSync12(join26(slugDir, file2)).mtimeMs;
45133
+ const mtime = statSync13(join29(slugDir, file2)).mtimeMs;
44626
45134
  const sessionId = file2.replace(/\.jsonl$/, "");
44627
45135
  candidates.push({ sessionId, directory, mtime });
44628
45136
  } catch {}
@@ -44640,7 +45148,7 @@ function collectPiRecentSessions() {
44640
45148
  }
44641
45149
  function parseHistorianDumpMeta2(path6) {
44642
45150
  try {
44643
- const xml = readFileSync21(path6, "utf-8");
45151
+ const xml = readFileSync23(path6, "utf-8");
44644
45152
  const parsed = parseCompartmentOutput(xml);
44645
45153
  const factCountByCategory = {};
44646
45154
  for (const fact of parsed.facts) {
@@ -44673,11 +45181,11 @@ function parseHistorianDumpMeta2(path6) {
44673
45181
  }
44674
45182
  }
44675
45183
  function listDumpsInDir2(dir, limit) {
44676
- if (!existsSync30(dir))
45184
+ if (!existsSync32(dir))
44677
45185
  return { count: 0, recent: [] };
44678
45186
  try {
44679
- const entries = readdirSync4(dir).filter((name) => name.endsWith(".xml")).map((name) => {
44680
- const stat = statSync12(join26(dir, name));
45187
+ const entries = readdirSync5(dir).filter((name) => name.endsWith(".xml")).map((name) => {
45188
+ const stat = statSync13(join29(dir, name));
44681
45189
  return {
44682
45190
  name,
44683
45191
  mtime: stat.mtimeMs,
@@ -44686,7 +45194,7 @@ function listDumpsInDir2(dir, limit) {
44686
45194
  }).sort((a3, b2) => b2.mtime - a3.mtime);
44687
45195
  const now = Date.now();
44688
45196
  const recent = entries.slice(0, limit).map((entry) => {
44689
- const meta3 = parseHistorianDumpMeta2(join26(dir, entry.name));
45197
+ const meta3 = parseHistorianDumpMeta2(join29(dir, entry.name));
44690
45198
  const summary = {
44691
45199
  name: entry.name,
44692
45200
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -44749,9 +45257,9 @@ async function collectDiagnostics2(cwd = process.cwd()) {
44749
45257
  const projectConfigPath = getProjectConfigPath(cwd);
44750
45258
  const loaded = loadPiConfig({ cwd });
44751
45259
  const storageDirPath = getMagicContextStorageDir();
44752
- const dbPath = join26(storageDirPath, "context.db");
45260
+ const dbPath = join29(storageDirPath, "context.db");
44753
45261
  const logPath = getMagicContextLogPath2("pi");
44754
- const logFileSize = existsSync30(logPath) ? statSync12(logPath).size : 0;
45262
+ const logFileSize = existsSync32(logPath) ? statSync13(logPath).size : 0;
44755
45263
  const otherPiExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
44756
45264
  const recentSessions = collectPiRecentSessions();
44757
45265
  const historianDumps = collectPiHistorianDumps(recentSessions);
@@ -44766,7 +45274,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
44766
45274
  piVersion: pi ? getPiVersion(pi.path) : null,
44767
45275
  settings: {
44768
45276
  path: settingsPath,
44769
- exists: existsSync30(settingsPath),
45277
+ exists: existsSync32(settingsPath),
44770
45278
  ...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
44771
45279
  hasMagicContextPackage: hasPiMagicContextPackage(packages),
44772
45280
  packages: sanitizeValue2(packages)
@@ -44782,7 +45290,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
44782
45290
  loadWarnings: loaded.warnings.map(sanitizeString2),
44783
45291
  storageDir: {
44784
45292
  path: storageDirPath,
44785
- exists: existsSync30(storageDirPath),
45293
+ exists: existsSync32(storageDirPath),
44786
45294
  contextDbSizeBytes: fileSize2(dbPath)
44787
45295
  },
44788
45296
  conflicts: {
@@ -44791,7 +45299,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
44791
45299
  },
44792
45300
  logFile: {
44793
45301
  path: logPath,
44794
- exists: existsSync30(logPath),
45302
+ exists: existsSync32(logPath),
44795
45303
  sizeKb: Math.round(logFileSize / 1024)
44796
45304
  },
44797
45305
  recentSessions,
@@ -44872,7 +45380,7 @@ function renderDiagnosticsMarkdown2(report) {
44872
45380
  ].join(`
44873
45381
  `);
44874
45382
  }
44875
- var import_comment_json12;
45383
+ var import_comment_json13;
44876
45384
  var init_diagnostics_pi = __esm(() => {
44877
45385
  init_migrate_config_location();
44878
45386
  init_compartment_parser();
@@ -44881,12 +45389,12 @@ var init_diagnostics_pi = __esm(() => {
44881
45389
  init_paths();
44882
45390
  init_pi_helpers();
44883
45391
  init_redaction2();
44884
- import_comment_json12 = __toESM(require_src3(), 1);
45392
+ import_comment_json13 = __toESM(require_src3(), 1);
44885
45393
  });
44886
45394
 
44887
45395
  // src/lib/logs-pi.ts
44888
- import { readFileSync as readFileSync22, writeFileSync as writeFileSync8 } from "node:fs";
44889
- import { join as join27 } from "node:path";
45396
+ import { readFileSync as readFileSync24, writeFileSync as writeFileSync9 } from "node:fs";
45397
+ import { join as join30 } from "node:path";
44890
45398
  function sanitizeLogContent2(content) {
44891
45399
  return sanitizeString2(content);
44892
45400
  }
@@ -44915,7 +45423,7 @@ function filterLogLinesBySession2(lines, sessionId) {
44915
45423
  }
44916
45424
  async function bundleIssueReport2(report, description, title, options = {}) {
44917
45425
  const LOG_TAIL_LINES = 400;
44918
- const allLogLines = report.logFile.exists ? readFileSync22(report.logFile.path, "utf-8").split(/\r?\n/) : [];
45426
+ const allLogLines = report.logFile.exists ? readFileSync24(report.logFile.path, "utf-8").split(/\r?\n/) : [];
44919
45427
  const logLines = filterLogLinesBySession2(allLogLines, options.sessionFilter ?? null);
44920
45428
  const recentLog = sanitizeLogContent2(logLines.slice(-LOG_TAIL_LINES).join(`
44921
45429
  `)).trim();
@@ -44951,8 +45459,8 @@ async function bundleIssueReport2(report, description, title, options = {}) {
44951
45459
  `);
44952
45460
  const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
44953
45461
  const cwd = options.cwd ?? process.cwd();
44954
- const path6 = join27(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
44955
- writeFileSync8(path6, `${bodyMarkdown}
45462
+ const path6 = join30(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
45463
+ writeFileSync9(path6, `${bodyMarkdown}
44956
45464
  `);
44957
45465
  return { path: path6, bodyMarkdown };
44958
45466
  }
@@ -44963,14 +45471,14 @@ var init_logs_pi = __esm(() => {
44963
45471
 
44964
45472
  // src/commands/doctor-pi.ts
44965
45473
  import { execFileSync as execFileSync6, spawnSync as spawnSync7 } from "node:child_process";
44966
- import { existsSync as existsSync31, mkdirSync as mkdirSync11, readdirSync as readdirSync5, readFileSync as readFileSync23, rmSync as rmSync4, statSync as statSync13 } from "node:fs";
45474
+ import { existsSync as existsSync33, mkdirSync as mkdirSync11, readdirSync as readdirSync6, readFileSync as readFileSync25, rmSync as rmSync4, statSync as statSync14 } from "node:fs";
44967
45475
  import { createRequire as createRequire7 } from "node:module";
44968
- import { homedir as homedir18 } from "node:os";
44969
- import { dirname as dirname16, isAbsolute as isAbsolute4, join as join28 } from "node:path";
45476
+ import { homedir as homedir19 } from "node:os";
45477
+ import { dirname as dirname17, isAbsolute as isAbsolute5, join as join31 } from "node:path";
44970
45478
  function depsFrom(options) {
44971
45479
  return {
44972
- ...DEFAULT_DEPS3,
44973
- prompts: options.prompts ?? DEFAULT_DEPS3.prompts,
45480
+ ...DEFAULT_DEPS5,
45481
+ prompts: options.prompts ?? DEFAULT_DEPS5.prompts,
44974
45482
  ...options.deps
44975
45483
  };
44976
45484
  }
@@ -45056,7 +45564,7 @@ function summarize(results) {
45056
45564
  function readJsonc2(path6) {
45057
45565
  try {
45058
45566
  return {
45059
- value: import_comment_json13.parse(readFileSync23(path6, "utf-8"))
45567
+ value: import_comment_json14.parse(readFileSync25(path6, "utf-8"))
45060
45568
  };
45061
45569
  } catch (error51) {
45062
45570
  return {
@@ -45075,28 +45583,28 @@ function piPluginDirCandidates(packages, cwd) {
45075
45583
  const spec = typeof entry === "string" ? entry.trim() : "";
45076
45584
  if (!spec || spec.startsWith("npm:"))
45077
45585
  continue;
45078
- const resolved = isAbsolute4(spec) ? spec : join28(agentDir, spec);
45586
+ const resolved = isAbsolute5(spec) ? spec : join31(agentDir, spec);
45079
45587
  dirs.push(resolved);
45080
45588
  }
45081
- dirs.push(join28(agentDir, "npm", "node_modules", PACKAGE_NAME));
45082
- dirs.push(join28(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME));
45083
- return dirs.filter((dir) => existsSync31(join28(dir, "package.json")));
45589
+ dirs.push(join31(agentDir, "npm", "node_modules", PACKAGE_NAME2));
45590
+ dirs.push(join31(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2));
45591
+ return dirs.filter((dir) => existsSync33(join31(dir, "package.json")));
45084
45592
  }
45085
45593
  function projectConfigPath(cwd) {
45086
45594
  return resolveCortexKitProjectConfigPath(cwd);
45087
45595
  }
45088
45596
  function readConfigForEmbedding(path6, isProjectConfig) {
45089
- if (!existsSync31(path6))
45597
+ if (!existsSync33(path6))
45090
45598
  return null;
45091
45599
  try {
45092
- const rawText = readFileSync23(path6, "utf-8");
45600
+ const rawText = readFileSync25(path6, "utf-8");
45093
45601
  const substituted = substituteConfigVariables({
45094
45602
  text: rawText,
45095
45603
  configPath: path6,
45096
45604
  isProjectConfig
45097
45605
  });
45098
45606
  const rejectedKeyPaths = [];
45099
- const parsed = sanitizeParsedJson(import_comment_json13.parse(substituted.text), {
45607
+ const parsed = sanitizeParsedJson(import_comment_json14.parse(substituted.text), {
45100
45608
  onRejectedKey: (keyPath) => rejectedKeyPaths.push(keyPath.join("."))
45101
45609
  });
45102
45610
  if (rejectedKeyPaths.length > 0) {
@@ -45167,38 +45675,38 @@ function pinnedVersionFromPackageSpecifier(specifier) {
45167
45675
  }
45168
45676
  function cacheRoots(cwd) {
45169
45677
  const home = process.env.HOME?.trim();
45170
- const cacheHome = process.env.XDG_CACHE_HOME || join28(home || homedir18(), ".cache");
45678
+ const cacheHome = process.env.XDG_CACHE_HOME || join31(home || homedir19(), ".cache");
45171
45679
  const piCacheRoot = getPiCacheRoot();
45172
45680
  return [
45173
- join28(piCacheRoot, "extensions"),
45174
- join28(piCacheRoot, "packages"),
45175
- join28(cacheHome, "pi", "extensions"),
45176
- join28(cacheHome, "pi", "packages"),
45177
- join28(getPiAgentConfigDir(), "cache", "extensions"),
45178
- join28(getPiAgentConfigDir(), "npm", "node_modules", PACKAGE_NAME),
45179
- join28(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME)
45681
+ join31(piCacheRoot, "extensions"),
45682
+ join31(piCacheRoot, "packages"),
45683
+ join31(cacheHome, "pi", "extensions"),
45684
+ join31(cacheHome, "pi", "packages"),
45685
+ join31(getPiAgentConfigDir(), "cache", "extensions"),
45686
+ join31(getPiAgentConfigDir(), "npm", "node_modules", PACKAGE_NAME2),
45687
+ join31(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2)
45180
45688
  ];
45181
45689
  }
45182
45690
  function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
45183
45691
  const found = new Map;
45184
45692
  const visit = (path6, depth) => {
45185
- if (depth < 0 || !existsSync31(path6))
45693
+ if (depth < 0 || !existsSync33(path6))
45186
45694
  return;
45187
45695
  let stat;
45188
45696
  try {
45189
- stat = statSync13(path6);
45697
+ stat = statSync14(path6);
45190
45698
  } catch {
45191
45699
  return;
45192
45700
  }
45193
45701
  if (!stat.isDirectory())
45194
45702
  return;
45195
- const packageJson = join28(path6, "package.json");
45196
- if (existsSync31(packageJson)) {
45703
+ const packageJson = join31(path6, "package.json");
45704
+ if (existsSync33(packageJson)) {
45197
45705
  try {
45198
- const pkg = JSON.parse(readFileSync23(packageJson, "utf-8"));
45706
+ const pkg = JSON.parse(readFileSync25(packageJson, "utf-8"));
45199
45707
  const name = typeof pkg.name === "string" ? pkg.name : "";
45200
45708
  const version2 = typeof pkg.version === "string" ? pkg.version : undefined;
45201
- if (name === PACKAGE_NAME) {
45709
+ if (name === PACKAGE_NAME2) {
45202
45710
  if (force || !version2 || expectedVersion && version2 !== expectedVersion) {
45203
45711
  found.set(path6, { path: path6, version: version2 });
45204
45712
  }
@@ -45210,12 +45718,12 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
45210
45718
  }
45211
45719
  let entries = [];
45212
45720
  try {
45213
- entries = readdirSync5(path6);
45721
+ entries = readdirSync6(path6);
45214
45722
  } catch {
45215
45723
  return;
45216
45724
  }
45217
45725
  for (const entry of entries)
45218
- visit(join28(path6, entry), depth - 1);
45726
+ visit(join31(path6, entry), depth - 1);
45219
45727
  };
45220
45728
  for (const root of cacheRoots(cwd))
45221
45729
  visit(root, 5);
@@ -45260,7 +45768,7 @@ async function runHealthChecks2(options) {
45260
45768
  }
45261
45769
  const settingsPath = getPiUserExtensionsPath();
45262
45770
  let packages = [];
45263
- if (!existsSync31(settingsPath)) {
45771
+ if (!existsSync33(settingsPath)) {
45264
45772
  add2(results, "fail", `Pi settings not found at ${settingsPath}`);
45265
45773
  repairPlan.addPackageEntry = true;
45266
45774
  } else {
@@ -45284,7 +45792,7 @@ async function runHealthChecks2(options) {
45284
45792
  ["user", userConfigPath, true],
45285
45793
  ["project", projectPath, false]
45286
45794
  ]) {
45287
- if (!existsSync31(path6)) {
45795
+ if (!existsSync33(path6)) {
45288
45796
  if (required2) {
45289
45797
  add2(results, "warn", `No ${label} magic-context.jsonc found at ${path6}`);
45290
45798
  if (userConfigMigrationRefused) {
@@ -45321,8 +45829,8 @@ async function runHealthChecks2(options) {
45321
45829
  add2(results, "pass", `historian.model "${historianModel}" has thinking_level "${historianThinkingLevel}" configured`);
45322
45830
  }
45323
45831
  const storageDir = getMagicContextStorageDir();
45324
- const dbPath = join28(storageDir, "context.db");
45325
- const existedBeforeOpen = existsSync31(dbPath);
45832
+ const dbPath = join31(storageDir, "context.db");
45833
+ const existedBeforeOpen = existsSync33(dbPath);
45326
45834
  if (existedBeforeOpen)
45327
45835
  add2(results, "pass", `Shared context DB exists at ${dbPath}`);
45328
45836
  else
@@ -45459,10 +45967,10 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
45459
45967
  add2(results, "pass", "Pi extension cache clean (no stale cached package found)");
45460
45968
  }
45461
45969
  const logPath = getMagicContextLogPath2("pi");
45462
- if (existsSync31(logPath)) {
45463
- const stat = statSync13(logPath);
45970
+ if (existsSync33(logPath)) {
45971
+ const stat = statSync14(logPath);
45464
45972
  const sizeKb = (stat.size / 1024).toFixed(0);
45465
- const lines = readFileSync23(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
45973
+ const lines = readFileSync25(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
45466
45974
  add2(results, "info", `Log file: ${logPath} (${sizeKb} KB)`);
45467
45975
  const lastLine = lines.at(-1);
45468
45976
  add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
@@ -45497,12 +46005,12 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
45497
46005
  return { results, repairPlan, ...summarize(results) };
45498
46006
  }
45499
46007
  function writeDefaultMagicContextConfig(path6) {
45500
- mkdirSync11(dirname16(path6), { recursive: true });
46008
+ mkdirSync11(dirname17(path6), { recursive: true });
45501
46009
  const config2 = {
45502
46010
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
45503
46011
  ...MagicContextConfigSchema.parse({})
45504
46012
  };
45505
- writeFileAtomic(path6, `${import_comment_json13.stringify(config2, null, 2)}
46013
+ writeFileAtomic(path6, `${import_comment_json14.stringify(config2, null, 2)}
45506
46014
  `);
45507
46015
  }
45508
46016
  function repair2(plan, prompts) {
@@ -45519,7 +46027,7 @@ function repair2(plan, prompts) {
45519
46027
  }
45520
46028
  if (plan.writeUserConfig) {
45521
46029
  const configPath = getPiUserConfigPath();
45522
- if (!existsSync31(configPath)) {
46030
+ if (!existsSync33(configPath)) {
45523
46031
  try {
45524
46032
  writeDefaultMagicContextConfig(configPath);
45525
46033
  prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
@@ -45639,7 +46147,7 @@ async function runDoctor3(options = {}) {
45639
46147
  const v22Result = await runV22BackfillCommands({
45640
46148
  name: "Pi",
45641
46149
  openDatabase: (readonly2 = true) => {
45642
- const dbPath = join28(getMagicContextStorageDir(), "context.db");
46150
+ const dbPath = join31(getMagicContextStorageDir(), "context.db");
45643
46151
  v22Db = readonly2 ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
45644
46152
  return v22Db;
45645
46153
  },
@@ -45704,7 +46212,7 @@ function parseDoctorArgs(args) {
45704
46212
  function doctor(args = []) {
45705
46213
  return runDoctor3(parseDoctorArgs(args));
45706
46214
  }
45707
- var import_comment_json13, PACKAGE_NAME = "@cortexkit/pi-magic-context", MIN_PI_VERSION = "0.74.0", ROW_COUNT_TABLES2, DEFAULT_DEPS3;
46215
+ var import_comment_json14, PACKAGE_NAME2 = "@cortexkit/pi-magic-context", MIN_PI_VERSION = "0.74.0", ROW_COUNT_TABLES2, DEFAULT_DEPS5;
45708
46216
  var init_doctor_pi = __esm(async () => {
45709
46217
  init_migrate_config_location();
45710
46218
  init_project_security();
@@ -45729,14 +46237,14 @@ var init_doctor_pi = __esm(async () => {
45729
46237
  init_storage_versions(),
45730
46238
  init_v22_backfill_commands()
45731
46239
  ]);
45732
- import_comment_json13 = __toESM(require_src3(), 1);
46240
+ import_comment_json14 = __toESM(require_src3(), 1);
45733
46241
  ROW_COUNT_TABLES2 = ["tags", "compartments", "memories", "notes", "dream_runs"];
45734
- DEFAULT_DEPS3 = {
46242
+ DEFAULT_DEPS5 = {
45735
46243
  prompts: promptIO,
45736
46244
  collectDiagnostics: collectDiagnostics2,
45737
46245
  detectPiBinary,
45738
46246
  getPiVersion,
45739
- getLatestNpmVersion: () => getLatestNpmVersion(PACKAGE_NAME),
46247
+ getLatestNpmVersion: () => getLatestNpmVersion(PACKAGE_NAME2),
45740
46248
  selfVersion: selfVersion2,
45741
46249
  probeEmbeddingEndpoint,
45742
46250
  openExistingContextDatabase,
@@ -45751,8 +46259,8 @@ var exports_doctor = {};
45751
46259
  __export(exports_doctor, {
45752
46260
  runDoctor: () => runDoctor4
45753
46261
  });
45754
- import { existsSync as existsSync32, rmSync as rmSync5 } from "node:fs";
45755
- import { join as join29 } from "node:path";
46262
+ import { existsSync as existsSync34, rmSync as rmSync5 } from "node:fs";
46263
+ import { join as join32 } from "node:path";
45756
46264
  async function runDoctor4(options) {
45757
46265
  if (options.clear)
45758
46266
  return runClear();
@@ -45770,7 +46278,7 @@ async function runDoctor4(options) {
45770
46278
  const result = await runV22BackfillCommands({
45771
46279
  name: "Magic Context",
45772
46280
  openDatabase: (readonly2 = true) => {
45773
- const dbPath = join29(getMagicContextStorageDir(), "context.db");
46281
+ const dbPath = join32(getMagicContextStorageDir(), "context.db");
45774
46282
  v22Db = readonly2 ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
45775
46283
  return v22Db;
45776
46284
  },
@@ -45784,7 +46292,7 @@ async function runDoctor4(options) {
45784
46292
  return result.exitCode;
45785
46293
  }
45786
46294
  const { sweepPendingMigrations: sweepPendingMigrations2, formatMigrationSweepLines: formatMigrationSweepLines2 } = await init_migrate().then(() => exports_migrate);
45787
- const sweepDbPath = join29(getMagicContextStorageDir(), "context.db");
46295
+ const sweepDbPath = join32(getMagicContextStorageDir(), "context.db");
45788
46296
  let sweepDb = null;
45789
46297
  try {
45790
46298
  sweepDb = openExistingContextDatabaseForMutation(sweepDbPath);
@@ -45880,7 +46388,7 @@ async function runClear() {
45880
46388
  const s = spinner2();
45881
46389
  s.start(`Clearing ${item.path}`);
45882
46390
  try {
45883
- if (existsSync32(item.path)) {
46391
+ if (existsSync34(item.path)) {
45884
46392
  rmSync5(item.path, { recursive: true, force: true });
45885
46393
  }
45886
46394
  s.stop(`Cleared ${item.path}`);
@@ -46026,12 +46534,12 @@ async function main(argv = process.argv.slice(2)) {
46026
46534
  console.error("Usage: magic-context doctor drain-authority <project>");
46027
46535
  return 1;
46028
46536
  }
46029
- const [{ runDoctorDrainAuthority: runDoctorDrainAuthority2 }, { getMagicContextStorageDir: getMagicContextStorageDir2 }, { join: join30 }] = await Promise.all([
46537
+ const [{ runDoctorDrainAuthority: runDoctorDrainAuthority2 }, { getMagicContextStorageDir: getMagicContextStorageDir2 }, { join: join33 }] = await Promise.all([
46030
46538
  init_doctor_authority().then(() => exports_doctor_authority),
46031
46539
  Promise.resolve().then(() => (init_data_path(), exports_data_path)),
46032
46540
  import("node:path")
46033
46541
  ]);
46034
- return runDoctorDrainAuthority2(projectRoot, join30(getMagicContextStorageDir2(), "context.db"));
46542
+ return runDoctorDrainAuthority2(projectRoot, join33(getMagicContextStorageDir2(), "context.db"));
46035
46543
  }
46036
46544
  if (rest[0] === "merge-identity") {
46037
46545
  const { runMergeIdentityCli: runMergeIdentityCli2 } = await init_doctor_merge_identity().then(() => exports_doctor_merge_identity);