@cortexkit/magic-context 0.36.1 → 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 +1414 -350
  2. package/package.json +3 -3
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,27 +12849,55 @@ 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
12848
12889
  import * as fs from "node:fs";
12849
12890
  import * as path2 from "node:path";
12850
- function ensureDir4(filePath) {
12851
- const dir = path2.dirname(filePath);
12852
- if (dir === lastEnsuredDir)
12853
- return;
12891
+ function recordSwallowedWrite(error) {
12854
12892
  try {
12855
- fs.mkdirSync(dir, { recursive: true });
12856
- lastEnsuredDir = dir;
12893
+ swallowedWriteCount++;
12894
+ lastErrorMessage = error instanceof Error ? error.message : String(error);
12895
+ lastErrorTime = new Date().toISOString();
12857
12896
  } catch {}
12858
12897
  }
12898
+ function ensureDir4(filePath) {
12899
+ fs.mkdirSync(path2.dirname(filePath), { recursive: true });
12900
+ }
12859
12901
  function flush() {
12860
12902
  if (flushTimer) {
12861
12903
  clearTimeout(flushTimer);
@@ -12869,7 +12911,9 @@ function flush() {
12869
12911
  const logFile = getMagicContextLogPath();
12870
12912
  ensureDir4(logFile);
12871
12913
  fs.appendFileSync(logFile, data);
12872
- } catch {}
12914
+ } catch (error) {
12915
+ recordSwallowedWrite(error);
12916
+ }
12873
12917
  }
12874
12918
  function scheduleFlush() {
12875
12919
  if (flushTimer)
@@ -12895,7 +12939,7 @@ ${data.stack}` : ""}` : ` ${JSON.stringify(data)}`;
12895
12939
  }
12896
12940
  } catch {}
12897
12941
  }
12898
- var isTestEnv = false, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50, lastEnsuredDir = null;
12942
+ var isTestEnv = false, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50, swallowedWriteCount = 0, lastErrorMessage = null, lastErrorTime = null;
12899
12943
  var init_logger = __esm(() => {
12900
12944
  init_data_path();
12901
12945
  buffer = [];
@@ -12903,6 +12947,43 @@ var init_logger = __esm(() => {
12903
12947
  process.on("exit", flush);
12904
12948
  }
12905
12949
  });
12950
+ // ../plugin/src/shared/window-geometry.ts
12951
+ function setWindowOverlayPath(path3) {
12952
+ configuredOverlayPath = path3;
12953
+ loadedOverlayPath = undefined;
12954
+ loadedOverlay = undefined;
12955
+ }
12956
+ var GRADES, UNITS, BOUNDARIES, UNKNOWN_REASONS, NUMERIC_FACT_KEYS, configuredOverlayPath, loadedOverlayPath, loadedOverlay, geometryClampLogSeen;
12957
+ var init_window_geometry = __esm(() => {
12958
+ init_data_path();
12959
+ init_harness_provider_map();
12960
+ init_logger();
12961
+ GRADES = new Set([
12962
+ "provider_asserted_runtime",
12963
+ "measured",
12964
+ "provider_asserted_doc",
12965
+ "catalog",
12966
+ "unknown"
12967
+ ]);
12968
+ UNITS = new Set(["provider", "estimate"]);
12969
+ BOUNDARIES = new Set(["Observed", "Asserted", "Corrected"]);
12970
+ UNKNOWN_REASONS = new Set([
12971
+ "placeholder_output_equals_context",
12972
+ "placeholder_zero",
12973
+ "never_measured",
12974
+ "not_single_valued_at_key",
12975
+ "retracted"
12976
+ ]);
12977
+ NUMERIC_FACT_KEYS = new Set([
12978
+ "window.advertised",
12979
+ "window.enforced",
12980
+ "output.advertised",
12981
+ "output.enforced",
12982
+ "output.default"
12983
+ ]);
12984
+ geometryClampLogSeen = new Set;
12985
+ });
12986
+
12906
12987
  // ../plugin/src/shared/models-dev-cache.ts
12907
12988
  function setOutputReserveConfig(config) {
12908
12989
  outputReserveConfig = config;
@@ -12912,6 +12993,7 @@ var init_models_dev_cache = __esm(() => {
12912
12993
  init_data_path();
12913
12994
  init_harness_provider_map();
12914
12995
  init_logger();
12996
+ init_window_geometry();
12915
12997
  SEPARATE_OUTPUT_QUOTA_PROVIDERS = new Set(["google", "google-antigravity"]);
12916
12998
  reserveClampLogSeen = new Set;
12917
12999
  });
@@ -27951,6 +28033,9 @@ function isValidPromptSurfaceModelKey(key) {
27951
28033
  return true;
27952
28034
  return modelID.length > 0 && !modelID.startsWith("/") && !modelID.endsWith("/") && !modelID.includes("//");
27953
28035
  }
28036
+ var init_prompt_surface = __esm(() => {
28037
+ init_harness_provider_map();
28038
+ });
27954
28039
 
27955
28040
  // ../plugin/src/config/schema/agent-overrides.ts
27956
28041
  var PermissionValueSchema, PermissionSchema, AgentOverrideConfigSchema;
@@ -28005,6 +28090,7 @@ var init_magic_context = __esm(() => {
28005
28090
  init_zod();
28006
28091
  init_language_directive();
28007
28092
  init_cron();
28093
+ init_prompt_surface();
28008
28094
  init_agent_overrides();
28009
28095
  PiThinkingLevelSchema = exports_external.enum(["off", "minimal", "low", "medium", "high", "xhigh", "max"]).optional();
28010
28096
  PiConfigSchema = exports_external.object({
@@ -28200,7 +28286,10 @@ var init_magic_context = __esm(() => {
28200
28286
  output_reserve: exports_external.union([
28201
28287
  exports_external.number().min(0),
28202
28288
  exports_external.object({ default: exports_external.number().min(0) }).catchall(exports_external.number().min(0))
28203
- ]).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.'),
28290
+ models: exports_external.object({
28291
+ window_overlay_path: exports_external.string().trim().min(1).optional()
28292
+ }).optional().describe("User-only Fusiform window-overlay settings. The path defaults to <dataDir>/fusiform/window-overlay.json."),
28204
28293
  toast_duration_ms: exports_external.number().min(0).max(60000).default(5000).describe("TUI toast lifetime in milliseconds for Magic Context notifications. Set to 0 to disable Magic Context toasts entirely (min: 0, max: 60000, default: 5000)"),
28205
28294
  execute_threshold_percentage: exports_external.union([
28206
28295
  exports_external.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE),
@@ -28252,7 +28341,7 @@ var init_magic_context = __esm(() => {
28252
28341
  overlay: exports_external.boolean().default(true).describe("Pi only: show the persistent todo overlay above the editor while tasks are active.")
28253
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."),
28254
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."),
28255
- 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."),
28256
28345
  caveman_text_compression: exports_external.object({
28257
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%)."),
28258
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.")
@@ -28407,6 +28496,11 @@ function stripUnsafeProjectConfigFields(projectRaw) {
28407
28496
  delete projectRaw.output_reserve;
28408
28497
  warnings.push("Ignoring output_reserve from project config (security: output-token reservation only honors user-level config).");
28409
28498
  }
28499
+ const models = projectRaw.models;
28500
+ if (isPlainObject2(models) && "window_overlay_path" in models) {
28501
+ delete models.window_overlay_path;
28502
+ warnings.push("Ignoring models.window_overlay_path from project config (security: only user-level config may select model geometry metadata).");
28503
+ }
28410
28504
  if ("language" in projectRaw) {
28411
28505
  delete projectRaw.language;
28412
28506
  warnings.push("Ignoring language from project config (security: output language is a user-level setting).");
@@ -29085,6 +29179,7 @@ function loadPluginConfigDetailed(directory) {
29085
29179
  const recoveredTopLevelKeys = [];
29086
29180
  const config2 = parsePluginConfig(mergedRaw, recoveredTopLevelKeys);
29087
29181
  setOutputReserveConfig(config2.output_reserve);
29182
+ setWindowOverlayPath(config2.models?.window_overlay_path);
29088
29183
  if (config2.configWarnings?.length) {
29089
29184
  allWarnings.push(...config2.configWarnings.map((w) => {
29090
29185
  if (userLoaded && projectLoaded)
@@ -29126,6 +29221,7 @@ function loadPluginConfigDetailed(directory) {
29126
29221
  var init_config = __esm(() => {
29127
29222
  init_jsonc_parser();
29128
29223
  init_models_dev_cache();
29224
+ init_window_geometry();
29129
29225
  init_agent_disable();
29130
29226
  init_migrate_config_location();
29131
29227
  init_migrate_dreamer_v2();
@@ -29176,14 +29272,17 @@ function detectConflicts(directory, options) {
29176
29272
  omoAnthropicRecovery: false
29177
29273
  };
29178
29274
  const reasons = [];
29179
- const compactionResult = checkCompaction(directory);
29275
+ let compactionResult = options?.resolvedCompaction ?? checkCompaction(directory);
29276
+ if (process.env.OPENCODE_DISABLE_AUTOCOMPACT) {
29277
+ compactionResult = { auto: false, prune: false };
29278
+ }
29180
29279
  if (compactionEnabled && compactionResult.auto) {
29181
29280
  conflicts.compactionAuto = true;
29182
- reasons.push("OpenCode auto-compaction is enabled (compaction.auto=true)");
29281
+ reasons.push(options?.resolvedCompaction ? "OpenCode auto-compaction is enabled (compaction.auto=true) (resolved config)" : "OpenCode auto-compaction is enabled (compaction.auto=true)");
29183
29282
  }
29184
29283
  if (compactionEnabled && compactionResult.prune) {
29185
29284
  conflicts.compactionPrune = true;
29186
- reasons.push("OpenCode prune is enabled (compaction.prune=true)");
29285
+ reasons.push(options?.resolvedCompaction ? "OpenCode prune is enabled (compaction.prune=true) (resolved config)" : "OpenCode prune is enabled (compaction.prune=true)");
29187
29286
  }
29188
29287
  const dcpFound = checkDcpPlugin(directory);
29189
29288
  if (dcpFound) {
@@ -29371,6 +29470,7 @@ function readOmoDisabledHooks(directory) {
29371
29470
  var DCP_PACKAGE_NAMES, OMO_PACKAGE_NAMES;
29372
29471
  var init_conflict_detector = __esm(() => {
29373
29472
  init_jsonc_parser();
29473
+ init_logger();
29374
29474
  init_opencode_config_dir();
29375
29475
  DCP_PACKAGE_NAMES = new Set(["@tarquinen/opencode-dcp"]);
29376
29476
  OMO_PACKAGE_NAMES = new Set(["oh-my-opencode", "oh-my-openagent"]);
@@ -29823,10 +29923,11 @@ function runOpenCode(args, binary, timeoutMs) {
29823
29923
  function getOpenCodeVersion(binary) {
29824
29924
  return runOpenCode(["--version"], binary, OPENCODE_VERSION_PROBE_TIMEOUT_MS);
29825
29925
  }
29826
- function describeOpenCodeInstallations(installations) {
29926
+ function describeOpenCodeInstallations(installations, deps = {}) {
29927
+ const getVersion = deps.getVersion ?? getOpenCodeVersion;
29827
29928
  return installations.map((installation, index) => ({
29828
29929
  ...installation,
29829
- version: installation.kind === "cli" ? getOpenCodeVersion(installation.path) ?? "unknown" : "unknown",
29930
+ version: installation.kind === "cli" ? getVersion(installation.path) ?? "unknown" : "unknown",
29830
29931
  active: index === 0
29831
29932
  }));
29832
29933
  }
@@ -30671,6 +30772,7 @@ function prepareMirrorPageStatements(db) {
30671
30772
  return {
30672
30773
  identityByModule: db.prepare("SELECT context_row_id FROM mirror_identity WHERE domain = ? AND module_project = ? AND module_row_id = ?"),
30673
30774
  insertIdentity: db.prepare("INSERT OR IGNORE INTO mirror_identity(domain, module_project, module_row_id, context_row_id) VALUES (?, ?, ?, ?)"),
30775
+ deleteIdentityByContext: db.prepare("DELETE FROM mirror_identity WHERE domain = ? AND context_row_id = ?"),
30674
30776
  deleteLiveMemory: db.prepare("DELETE FROM mirror_live_memory_rows WHERE module_project = ? AND module_row_id = ?"),
30675
30777
  deletePendingReferencesForMemory: db.prepare("DELETE FROM mirror_pending_references WHERE domain = ? AND module_project = ? AND (module_row_id = ? OR target_module_row_id = ?)"),
30676
30778
  deleteIdentity: db.prepare("DELETE FROM mirror_identity WHERE domain = ? AND module_project = ? AND module_row_id = ?"),
@@ -30722,7 +30824,7 @@ function prepareMirrorPageStatements(db) {
30722
30824
  check_quarantined_until = ?, check_next_due_at = ?, check_compiled_at = ?, check_false_since_at = ?,
30723
30825
  check_last_liveness_at = ?, last_checked_at = ?, check_status = ?, check_version = ?,
30724
30826
  policy_version = ?, anchor_block_id = ?, anchor_ordinal = ?, created_at = ?, updated_at = ? WHERE id = ?`),
30725
- upsertNoteRevision: db.prepare("INSERT INTO mirror_note_revisions(module_project, module_row_id, context_row_id, status_version) VALUES (?, ?, ?, ?) ON CONFLICT(module_project, module_row_id) DO UPDATE SET context_row_id = excluded.context_row_id, status_version = excluded.status_version"),
30827
+ upsertNoteRevision: db.prepare("INSERT OR REPLACE INTO mirror_note_revisions(module_project, module_row_id, context_row_id, status_version) VALUES (?, ?, ?, ?)"),
30726
30828
  translateMemoryReferences: db.prepare(`UPDATE memories
30727
30829
  SET superseded_by_memory_id = (
30728
30830
  SELECT target.context_row_id
@@ -30795,6 +30897,9 @@ function rememberIdentity(db, domain2, moduleProject, moduleRowId, contextRowId,
30795
30897
  const existing = mirrorIdentity(db, domain2, moduleProject, moduleRowId, statements);
30796
30898
  if (existing)
30797
30899
  return;
30900
+ if (domain2 === "notes") {
30901
+ (statements?.deleteIdentityByContext ?? db.prepare("DELETE FROM mirror_identity WHERE domain = ? AND context_row_id = ?")).run(domain2, contextRowId);
30902
+ }
30798
30903
  (statements?.insertIdentity ?? db.prepare("INSERT OR IGNORE INTO mirror_identity(domain, module_project, module_row_id, context_row_id) VALUES (?, ?, ?, ?)")).run(domain2, moduleProject, moduleRowId, contextRowId);
30799
30904
  }
30800
30905
  function contextMemoryId(db, domain2, moduleProject, row, moduleRowId, statements) {
@@ -31427,11 +31532,12 @@ function gitRootInAncestorChain(startDirectory) {
31427
31532
  function hasGitDirInAncestorChain(startDirectory) {
31428
31533
  return gitRootInAncestorChain(startDirectory) !== null;
31429
31534
  }
31430
- var GIT_TIMEOUT_MS = 5000, TRANSIENT_FAILURE_COOLDOWN_MS, identityCache, lastKnownGitIdentityCache, directoryFallbackCache, transientFailureCooldown, dubiousOwnershipFallbackDirectories, dubiousOwnershipLoggedDirectories, dubiousOwnershipWarnedDirectories, transientGitIdentityReuseLoggedDirectories, execFileSyncForIdentity, nowMs = () => Date.now(), ProjectIdentityError;
31535
+ var GIT_TIMEOUT_MS = 5000, TRANSIENT_FAILURE_COOLDOWN_MS, identityCache, linkedGitWorktreeCache, lastKnownGitIdentityCache, directoryFallbackCache, transientFailureCooldown, dubiousOwnershipFallbackDirectories, dubiousOwnershipLoggedDirectories, dubiousOwnershipWarnedDirectories, transientGitIdentityReuseLoggedDirectories, execFileSyncForIdentity, nowMs = () => Date.now(), ProjectIdentityError;
31431
31536
  var init_project_identity = __esm(() => {
31432
31537
  init_logger();
31433
31538
  TRANSIENT_FAILURE_COOLDOWN_MS = 5 * 60 * 1000;
31434
31539
  identityCache = new Map;
31540
+ linkedGitWorktreeCache = new Map;
31435
31541
  lastKnownGitIdentityCache = new Map;
31436
31542
  directoryFallbackCache = new Map;
31437
31543
  transientFailureCooldown = new Map;
@@ -33731,6 +33837,7 @@ class SubcModuleTransport {
33731
33837
  return error51;
33732
33838
  }
33733
33839
  async beforeDeadline(operation, deadlineMs, detail) {
33840
+ operation.catch(() => {});
33734
33841
  const remainingMs = deadlineMs - Date.now();
33735
33842
  if (remainingMs <= 0)
33736
33843
  throw this.deadlineError(detail);
@@ -34145,12 +34252,14 @@ import { execFileSync as execFileSync4 } from "node:child_process";
34145
34252
  import { readFileSync as readFileSync12 } from "node:fs";
34146
34253
  function isPidAlive(pid) {
34147
34254
  if (!Number.isInteger(pid) || pid <= 0)
34148
- return false;
34255
+ return "dead";
34256
+ if (rpcIdentityPlatform === "win32")
34257
+ return readWindowsProcess(pid).state;
34149
34258
  try {
34150
- process.kill(pid, 0);
34151
- return true;
34152
- } catch (err) {
34153
- return err.code === "EPERM";
34259
+ rpcIdentityProcessKill(pid, 0);
34260
+ return "alive";
34261
+ } catch (error51) {
34262
+ return error51.code === "ESRCH" ? "dead" : "inconclusive";
34154
34263
  }
34155
34264
  }
34156
34265
  function parseLinuxProcessStartTime(statContent, uptimeContent) {
@@ -34179,7 +34288,8 @@ function readPsProcessStartTime(pid) {
34179
34288
  try {
34180
34289
  const output = rpcIdentityExecFileSync("ps", ["-p", String(pid), "-o", "lstart="], {
34181
34290
  encoding: "utf8",
34182
- timeout: PS_PROBE_TIMEOUT_MS
34291
+ timeout: PS_PROBE_TIMEOUT_MS,
34292
+ stdio: ["ignore", "pipe", "pipe"]
34183
34293
  });
34184
34294
  const processStartTime = Date.parse(String(output).trim());
34185
34295
  return Number.isFinite(processStartTime) ? processStartTime : null;
@@ -34187,6 +34297,70 @@ function readPsProcessStartTime(pid) {
34187
34297
  return null;
34188
34298
  }
34189
34299
  }
34300
+ function parseCsvLine(line) {
34301
+ const fields = [];
34302
+ let field = "";
34303
+ let quoted = false;
34304
+ for (let index = 0;index < line.length; index += 1) {
34305
+ const character = line[index];
34306
+ if (character === '"') {
34307
+ if (quoted && line[index + 1] === '"') {
34308
+ field += '"';
34309
+ index += 1;
34310
+ } else {
34311
+ quoted = !quoted;
34312
+ }
34313
+ } else if (character === "," && !quoted) {
34314
+ fields.push(field);
34315
+ field = "";
34316
+ } else {
34317
+ field += character;
34318
+ }
34319
+ }
34320
+ if (quoted)
34321
+ return null;
34322
+ fields.push(field);
34323
+ return fields;
34324
+ }
34325
+ function parseTasklistOutput(output) {
34326
+ const entries = [];
34327
+ let sawHeader = false;
34328
+ for (const rawLine of output.split(/\r?\n/)) {
34329
+ const line = rawLine.trim();
34330
+ if (!line)
34331
+ continue;
34332
+ if (TASKLIST_NO_TASKS_PATTERN.test(line))
34333
+ return [];
34334
+ const fields = parseCsvLine(line);
34335
+ if (!fields)
34336
+ continue;
34337
+ if (fields[1]?.trim().toLowerCase() === "pid") {
34338
+ sawHeader = true;
34339
+ continue;
34340
+ }
34341
+ const pid = Number(fields[1]);
34342
+ if (!Number.isInteger(pid) || pid <= 0 || !fields[0])
34343
+ continue;
34344
+ entries.push({ pid, command: fields[0] });
34345
+ }
34346
+ return entries.length > 0 || sawHeader ? entries : null;
34347
+ }
34348
+ function readWindowsProcess(pid) {
34349
+ try {
34350
+ const output = rpcIdentityExecFileSync("tasklist", ["/FO", "CSV", "/FI", `PID eq ${pid}`], {
34351
+ encoding: "utf8",
34352
+ timeout: PS_PROBE_TIMEOUT_MS,
34353
+ stdio: ["ignore", "pipe", "pipe"]
34354
+ });
34355
+ const entries = parseTasklistOutput(String(output));
34356
+ if (entries === null)
34357
+ return { state: "inconclusive" };
34358
+ const process3 = entries.find((entry) => entry.pid === pid);
34359
+ return process3 ? { state: "alive", command: process3.command } : { state: "dead" };
34360
+ } catch {
34361
+ return { state: "inconclusive" };
34362
+ }
34363
+ }
34190
34364
  function readLinuxProcessCommand(pid) {
34191
34365
  try {
34192
34366
  return String(rpcIdentityReadFileSync(`/proc/${pid}/cmdline`, "utf8"));
@@ -34198,40 +34372,86 @@ function readPsProcessCommand(pid) {
34198
34372
  try {
34199
34373
  const output = rpcIdentityExecFileSync("ps", ["-p", String(pid), "-o", "command="], {
34200
34374
  encoding: "utf8",
34201
- timeout: PS_PROBE_TIMEOUT_MS
34375
+ timeout: PS_PROBE_TIMEOUT_MS,
34376
+ stdio: ["ignore", "pipe", "pipe"]
34202
34377
  });
34203
34378
  return String(output);
34204
34379
  } catch {
34205
34380
  return null;
34206
34381
  }
34207
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
+ }
34208
34428
  function commandLooksLikeOpenCode(command) {
34209
34429
  const normalized = command.toLowerCase();
34210
34430
  return OPEN_CODE_COMMAND_MARKERS.some((marker) => normalized.includes(marker));
34211
34431
  }
34212
34432
  function isPidIdentityPlausible(record2) {
34213
34433
  if (!Number.isInteger(record2.pid) || record2.pid <= 0)
34214
- return false;
34434
+ return "implausible";
34215
34435
  if (Number.isFinite(record2.started_at) && record2.started_at > 0) {
34216
- const processStartTime = rpcIdentityPlatform === "linux" ? readLinuxProcessStartTime(record2.pid) : readPsProcessStartTime(record2.pid);
34436
+ const processStartTime = rpcIdentityPlatform === "linux" ? readLinuxProcessStartTime(record2.pid) : rpcIdentityPlatform === "win32" ? null : readPsProcessStartTime(record2.pid);
34217
34437
  if (processStartTime === null)
34218
- return true;
34219
- return processStartTime <= record2.started_at + RPC_IDENTITY_SKEW_TOLERANCE_MS;
34438
+ return "inconclusive";
34439
+ return processStartTime <= record2.started_at + RPC_IDENTITY_SKEW_TOLERANCE_MS ? "plausible" : "implausible";
34220
34440
  }
34221
- const command = rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(record2.pid) : readPsProcessCommand(record2.pid);
34441
+ const command = rpcIdentityPlatform === "linux" ? readLinuxProcessCommand(record2.pid) : rpcIdentityPlatform === "win32" ? readWindowsProcess(record2.pid).command ?? null : readPsProcessCommand(record2.pid);
34222
34442
  if (command === null)
34223
- return true;
34224
- return commandLooksLikeOpenCode(command);
34443
+ return "inconclusive";
34444
+ return commandLooksLikeOpenCode(command) ? "plausible" : "implausible";
34225
34445
  }
34226
34446
  function commandLooksLikePi(command) {
34227
34447
  const normalized = command.trim().toLowerCase().replaceAll("\\", "/");
34228
34448
  const tokens = normalized.split(/\s+/).filter(Boolean);
34229
- const executableName = (token) => (token ?? "").split("/").at(-1) ?? "";
34230
- const first = executableName(tokens[0]).replace(/\.exe$/, "");
34449
+ const executableName2 = (token) => (token ?? "").split("/").at(-1) ?? "";
34450
+ const first = executableName2(tokens[0]).replace(/\.exe$/, "");
34231
34451
  if (["pi", "pi.cmd", "omp", "oh-my-pi"].includes(first))
34232
34452
  return true;
34233
34453
  if (["node", "bun", "deno"].includes(first)) {
34234
- const script = executableName(tokens[1]);
34454
+ const script = executableName2(tokens[1]);
34235
34455
  return ["pi", "pi.js", "pi.mjs", "pi.cjs"].includes(script) || normalized.includes("pi-coding-agent");
34236
34456
  }
34237
34457
  return false;
@@ -34239,20 +34459,39 @@ function commandLooksLikePi(command) {
34239
34459
  function inspectLivePiProcesses() {
34240
34460
  if (false) {}
34241
34461
  try {
34242
- const output = String(rpcProcessListExecFileSync("ps", ["-axo", "pid=,command="], {
34462
+ const isWindows = rpcIdentityPlatform === "win32";
34463
+ const output = String(rpcProcessListExecFileSync(isWindows ? "tasklist" : "ps", isWindows ? ["/FO", "CSV"] : ["-axo", "pid=,command="], {
34243
34464
  encoding: "utf8",
34244
- timeout: PS_PROBE_TIMEOUT_MS
34465
+ timeout: PS_PROBE_TIMEOUT_MS,
34466
+ stdio: ["ignore", "pipe", "pipe"]
34245
34467
  }));
34246
34468
  const pids = new Set;
34247
- for (const line of output.split(/\r?\n/)) {
34248
- const match = /^\s*(\d+)\s+(.+)$/.exec(line);
34249
- if (!match)
34250
- continue;
34251
- const pid = Number(match[1]);
34252
- if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid)
34253
- continue;
34254
- if (commandLooksLikePi(match[2]))
34255
- pids.add(pid);
34469
+ if (isWindows) {
34470
+ const entries = parseTasklistOutput(output);
34471
+ if (entries === null) {
34472
+ return {
34473
+ state: "unreadable",
34474
+ processIds: [],
34475
+ error: "tasklist output unavailable"
34476
+ };
34477
+ }
34478
+ for (const entry of entries) {
34479
+ if (entry.pid === process.pid)
34480
+ continue;
34481
+ if (commandLooksLikePi(entry.command))
34482
+ pids.add(entry.pid);
34483
+ }
34484
+ } else {
34485
+ for (const line of output.split(/\r?\n/)) {
34486
+ const match = /^\s*(\d+)\s+(.+)$/.exec(line);
34487
+ if (!match)
34488
+ continue;
34489
+ const pid = Number(match[1]);
34490
+ if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid)
34491
+ continue;
34492
+ if (commandLooksLikePi(match[2]))
34493
+ pids.add(pid);
34494
+ }
34256
34495
  }
34257
34496
  return { state: "known", processIds: [...pids].sort((left, right) => left - right) };
34258
34497
  } catch (error51) {
@@ -34282,6 +34521,8 @@ function parseRpcPortFile(content, fallbackPid = 0) {
34282
34521
  port: port2,
34283
34522
  pid,
34284
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,
34285
34526
  token: typeof parsed.token === "string" ? parsed.token : undefined,
34286
34527
  instance_id: typeof parsed.instance_id === "string" ? parsed.instance_id : undefined
34287
34528
  };
@@ -34297,11 +34538,13 @@ function parseRpcPortFile(content, fallbackPid = 0) {
34297
34538
  function isValidPort(port) {
34298
34539
  return Number.isInteger(port) && port > 0 && port <= 65535;
34299
34540
  }
34300
- var RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, OPEN_CODE_COMMAND_MARKERS, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now();
34541
+ var RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, OPEN_CODE_COMMAND_MARKERS, TASKLIST_NO_TASKS_PATTERN, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcIdentityProcessKill, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now();
34301
34542
  var init_rpc_utils = __esm(() => {
34302
34543
  OPEN_CODE_COMMAND_MARKERS = ["opencode", "node", "bun", "electron"];
34544
+ TASKLIST_NO_TASKS_PATTERN = /^INFO:\s+No tasks are running which match the specified criteria\.?$/im;
34303
34545
  rpcIdentityReadFileSync = readFileSync12;
34304
34546
  rpcIdentityExecFileSync = execFileSync4;
34547
+ rpcIdentityProcessKill = process.kill;
34305
34548
  rpcProcessListExecFileSync = execFileSync4;
34306
34549
  rpcIdentityPlatform = process.platform;
34307
34550
  });
@@ -34528,6 +34771,8 @@ function healAllNullColumns(db) {
34528
34771
  ["stripped_placeholder_ids", ""],
34529
34772
  ["stale_reduce_stripped_ids", ""],
34530
34773
  ["processed_image_stripped_ids", ""],
34774
+ ["merged_reasoning_stripped_ids", ""],
34775
+ ["trailing_blank_decisions", ""],
34531
34776
  ["memory_block_cache", ""],
34532
34777
  ["memory_block_ids", ""],
34533
34778
  ["compaction_marker_state", ""],
@@ -34981,6 +35226,7 @@ var init_migrations = __esm(() => {
34981
35226
  status TEXT NOT NULL DEFAULT 'active',
34982
35227
  promoted_at INTEGER NOT NULL,
34983
35228
  source_candidate_ids TEXT DEFAULT '[]',
35229
+ source_candidate_provenance TEXT,
34984
35230
  created_at INTEGER NOT NULL,
34985
35231
  updated_at INTEGER NOT NULL
34986
35232
  );
@@ -36007,6 +36253,7 @@ var init_migrations = __esm(() => {
36007
36253
  last_observed_at INTEGER,
36008
36254
  answer_refreshed_at INTEGER,
36009
36255
  source_candidate_ids TEXT NOT NULL DEFAULT '[]',
36256
+ source_candidate_provenance TEXT,
36010
36257
  created_at INTEGER NOT NULL,
36011
36258
  updated_at INTEGER NOT NULL
36012
36259
  );
@@ -36816,6 +37063,37 @@ var init_migrations = __esm(() => {
36816
37063
  ensureColumn(db, "notes", "compiled_at", "INTEGER");
36817
37064
  ensureColumn(db, "notes", "compile_status", "TEXT CHECK(compile_status IN ('compiled', 'plain', 'refused'))");
36818
37065
  }
37066
+ },
37067
+ {
37068
+ version: 77,
37069
+ description: "persist scoped provenance for promoted user memories and primers",
37070
+ up(db) {
37071
+ if (tableExists(db, "user_memories")) {
37072
+ ensureColumn(db, "user_memories", "source_candidate_provenance", "TEXT");
37073
+ }
37074
+ if (tableExists(db, "primers")) {
37075
+ ensureColumn(db, "primers", "source_candidate_provenance", "TEXT");
37076
+ }
37077
+ }
37078
+ },
37079
+ {
37080
+ version: 78,
37081
+ description: "add migration_pending journal for crash-safe cross-harness session migration",
37082
+ up(db) {
37083
+ db.exec(`
37084
+ CREATE TABLE IF NOT EXISTS migration_pending (
37085
+ migration_key TEXT PRIMARY KEY,
37086
+ source_session_id TEXT NOT NULL,
37087
+ target_harness TEXT NOT NULL,
37088
+ pi_session_id TEXT NOT NULL,
37089
+ final_path TEXT NOT NULL,
37090
+ stage_path TEXT NOT NULL,
37091
+ content_sha256 TEXT NOT NULL,
37092
+ phase TEXT NOT NULL CHECK (phase IN ('staged', 'db_committed')),
37093
+ created_at INTEGER NOT NULL
37094
+ );
37095
+ `);
37096
+ }
36819
37097
  }
36820
37098
  ];
36821
37099
  LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m3) => Math.max(max, m3.version), 0);
@@ -36859,7 +37137,7 @@ import {
36859
37137
  statSync as statSync7,
36860
37138
  unlinkSync as unlinkSync2
36861
37139
  } from "node:fs";
36862
- 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";
36863
37141
  function getPersistedSchemaVersion(db) {
36864
37142
  const hasMigrationsTable = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'schema_migrations'").get();
36865
37143
  if (!hasMigrationsTable) {
@@ -36891,6 +37169,28 @@ function invalidDiscoveryReason(raw) {
36891
37169
  }
36892
37170
  return "parse-invalid";
36893
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
+ }
36894
37194
  function classifyJunkDiscovery(portFile, raw, staleFiles) {
36895
37195
  let mtimeMs;
36896
37196
  try {
@@ -36943,7 +37243,9 @@ function inspectRpcServerDiscovery(storageDir) {
36943
37243
  return { state: "absent", serverPids: [], staleFiles: [] };
36944
37244
  }
36945
37245
  const pids = new Set;
37246
+ const processByPid = new Map;
36946
37247
  const staleFiles = [];
37248
+ const inconclusivePids = new Set;
36947
37249
  for (const portFile of portFiles) {
36948
37250
  let raw;
36949
37251
  try {
@@ -36963,10 +37265,23 @@ function inspectRpcServerDiscovery(storageDir) {
36963
37265
  return junk;
36964
37266
  continue;
36965
37267
  }
36966
- if (isPidAlive(record2.pid) && isPidIdentityPlausible(record2))
37268
+ const liveness = isPidAlive(record2.pid);
37269
+ const identity = liveness === "dead" ? "implausible" : isPidIdentityPlausible(record2);
37270
+ if (liveness === "alive" && identity === "plausible") {
36967
37271
  pids.add(record2.pid);
36968
- else
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
+ }
37280
+ } else if (liveness === "dead" || identity === "implausible") {
36969
37281
  staleFiles.push(portFile);
37282
+ } else {
37283
+ inconclusivePids.add(record2.pid);
37284
+ }
36970
37285
  }
36971
37286
  for (const staleFile of staleFiles) {
36972
37287
  try {
@@ -36977,14 +37292,28 @@ function inspectRpcServerDiscovery(storageDir) {
36977
37292
  }
36978
37293
  const serverPids = [...pids].sort((a3, b2) => a3 - b2);
36979
37294
  if (serverPids.length > 0) {
36980
- 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
+ };
37301
+ }
37302
+ const uncertainPids = [...inconclusivePids].sort((a3, b2) => a3 - b2);
37303
+ if (uncertainPids.length > 0) {
37304
+ return {
37305
+ state: "inconclusive",
37306
+ serverPids: [],
37307
+ staleFiles,
37308
+ inconclusivePids: uncertainPids
37309
+ };
36981
37310
  }
36982
37311
  return { state: "stale", serverPids: [], staleFiles };
36983
37312
  }
36984
37313
  function getLiveMigrationBlockingProcesses(storageDir) {
36985
37314
  const discovery = inspectRpcServerDiscovery(storageDir);
36986
- const openCode = discovery.state === "live" ? discovery.serverPids.map((pid) => ({ harness: "OpenCode server", pid })) : [];
36987
- 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 }));
36988
37317
  return [...openCode, ...pi];
36989
37318
  }
36990
37319
  function applySqliteTuningPragmas(db) {
@@ -37163,6 +37492,7 @@ function initializeDatabase(db) {
37163
37492
  last_observed_at INTEGER,
37164
37493
  answer_refreshed_at INTEGER,
37165
37494
  source_candidate_ids TEXT NOT NULL DEFAULT '[]',
37495
+ source_candidate_provenance TEXT,
37166
37496
  created_at INTEGER NOT NULL,
37167
37497
  updated_at INTEGER NOT NULL
37168
37498
  );
@@ -37798,6 +38128,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
37798
38128
  ensureColumn(db, "primer_candidates", "question_embedding", "BLOB");
37799
38129
  ensureColumn(db, "primer_candidates", "question_embedding_model_id", "TEXT");
37800
38130
  ensureColumn(db, "primers", "question_embedding_model_id", "TEXT");
38131
+ ensureColumn(db, "primers", "source_candidate_provenance", "TEXT");
38132
+ const hasUserMemoriesTable = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'user_memories'").get();
38133
+ if (hasUserMemoriesTable) {
38134
+ ensureColumn(db, "user_memories", "source_candidate_provenance", "TEXT");
38135
+ }
37801
38136
  db.exec(`
37802
38137
  CREATE UNIQUE INDEX IF NOT EXISTS idx_primer_candidates_occurrence
37803
38138
  ON primer_candidates(project_path, harness, session_id, source_start_message_id, source_end_message_id);
@@ -37871,6 +38206,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
37871
38206
  ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
37872
38207
  ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
37873
38208
  ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
38209
+ ensureColumn(db, "session_meta", "merged_reasoning_stripped_ids", "TEXT DEFAULT ''");
38210
+ ensureColumn(db, "session_meta", "trailing_blank_decisions", "TEXT DEFAULT ''");
37874
38211
  ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
37875
38212
  ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
37876
38213
  ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
@@ -38089,7 +38426,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
38089
38426
  ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
38090
38427
  ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
38091
38428
  }
38092
- var databases, pendingAsyncOpens, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, LATEST_SUPPORTED_VERSION = 76, 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;
38093
38430
  var init_storage_db = __esm(async () => {
38094
38431
  init_data_path();
38095
38432
  init_logger();
@@ -38119,6 +38456,7 @@ var init_storage_db = __esm(async () => {
38119
38456
  cacheSizeMb: 64,
38120
38457
  mmapSizeMb: 0
38121
38458
  };
38459
+ CHANNEL2_CLAIM_TTL_MS = 10 * 60000;
38122
38460
  });
38123
38461
 
38124
38462
  // src/lib/database-access.ts
@@ -38224,8 +38562,44 @@ var init_database_access = __esm(async () => {
38224
38562
  var exports_doctor_authority = {};
38225
38563
  __export(exports_doctor_authority, {
38226
38564
  runDoctorDrainAuthority: () => runDoctorDrainAuthority,
38227
- reportAuthorityMarkers: () => reportAuthorityMarkers
38565
+ reportAuthorityMarkers: () => reportAuthorityMarkers,
38566
+ authorityDrainCommand: () => authorityDrainCommand,
38567
+ assertProjectsUseTsAuthority: () => assertProjectsUseTsAuthority
38228
38568
  });
38569
+ function authorityDrainCommand(project) {
38570
+ return `magic-context doctor drain-authority ${project.projectRoot ?? `<${project.role} project root>`}`;
38571
+ }
38572
+ async function assertProjectsUseTsAuthority(args) {
38573
+ const markers = listAuthorityManagedMarkers(args.db);
38574
+ const markerByProject = new Map(markers.map((marker) => [marker.project_path, marker]));
38575
+ for (const project of args.projects) {
38576
+ const marker = markerByProject.get(project.projectPath);
38577
+ if (!marker)
38578
+ continue;
38579
+ const projectRoot = project.projectRoot;
38580
+ if (!projectRoot) {
38581
+ throw new Error(`Migration refused: durable module authority for ${project.role} project ${project.projectPath} cannot be checked because its project directory is unavailable. ` + `Writes remain fenced. Drain it first: ${authorityDrainCommand(project)}`);
38582
+ }
38583
+ let statuses;
38584
+ try {
38585
+ statuses = await Promise.all(AUTHORITY_DOMAINS.map((domain2) => args.module.authorityStatus({
38586
+ context_store_uuid: marker.context_store_uuid,
38587
+ project: project.projectPath,
38588
+ projectRoot,
38589
+ domain: domain2
38590
+ })));
38591
+ } catch (error51) {
38592
+ throw new Error(`Migration refused: module unreachable while checking ${project.role} project ${project.projectPath}; writes remain fenced. ` + `Drain it first: ${authorityDrainCommand(project)}. ` + `Module error: ${error51 instanceof Error ? error51.message : String(error51)}`);
38593
+ }
38594
+ for (const [index, status] of statuses.entries()) {
38595
+ const state = status.authority?.state ?? "TS";
38596
+ if (state === "TS")
38597
+ continue;
38598
+ throw new Error(`Migration refused: ${project.role} project ${project.projectPath} has ${AUTHORITY_DOMAINS[index]} authority in ${state} mode; writes remain fenced. ` + `Drain it first: ${authorityDrainCommand(project)}`);
38599
+ }
38600
+ }
38601
+ return { markers };
38602
+ }
38229
38603
  function authorityClient(transport, projectRoot) {
38230
38604
  return {
38231
38605
  authorityStatus: (request) => transport.authorityStatus({ ...request, projectRoot }),
@@ -38258,12 +38632,12 @@ async function reportAuthorityMarkers(args) {
38258
38632
  }
38259
38633
  try {
38260
38634
  const module = authorityClient(transport, process.cwd());
38261
- const statuses = await Promise.all(DOMAINS.map((domain2) => module.authorityStatus({
38635
+ const statuses = await Promise.all(AUTHORITY_DOMAINS.map((domain2) => module.authorityStatus({
38262
38636
  context_store_uuid: ensureContextStoreUuid(args.db),
38263
38637
  project: marker.project_path,
38264
38638
  domain: domain2
38265
38639
  })));
38266
- args.info(` ${marker.project_path}: ${statuses.map((status, index) => `${DOMAINS[index]}=${status.authority?.state ?? "TS"}`).join(", ")}`);
38640
+ args.info(` ${marker.project_path}: ${statuses.map((status, index) => `${AUTHORITY_DOMAINS[index]}=${status.authority?.state ?? "TS"}`).join(", ")}`);
38267
38641
  } catch {
38268
38642
  args.warn(` ${marker.project_path}: module unreachable — writes fenced; run with rust mode or restore subc connectivity`);
38269
38643
  }
@@ -38283,7 +38657,7 @@ async function runDoctorDrainAuthority(projectRoot, dbPath) {
38283
38657
  }
38284
38658
  const module = authorityClient(new SubcModuleTransport, projectRoot);
38285
38659
  let drainedAny = false;
38286
- for (const domain2 of DOMAINS) {
38660
+ for (const domain2 of AUTHORITY_DOMAINS) {
38287
38661
  const status = await module.authorityStatus({
38288
38662
  context_store_uuid: ensureContextStoreUuid(db),
38289
38663
  project: projectPath,
@@ -38327,7 +38701,6 @@ async function runDoctorDrainAuthority(projectRoot, dbPath) {
38327
38701
  db.close();
38328
38702
  }
38329
38703
  }
38330
- var DOMAINS;
38331
38704
  var init_doctor_authority = __esm(async () => {
38332
38705
  init_project_identity();
38333
38706
  init_storage_project_state();
@@ -38336,7 +38709,6 @@ var init_doctor_authority = __esm(async () => {
38336
38709
  init_context_authority(),
38337
38710
  init_database_access()
38338
38711
  ]);
38339
- DOMAINS = ["memories", "notes"];
38340
38712
  });
38341
38713
 
38342
38714
  // ../plugin/src/features/magic-context/storage-identity-merge.ts
@@ -39005,7 +39377,7 @@ function printHelp() {
39005
39377
  }
39006
39378
  async function runRepairDb(options = {}) {
39007
39379
  const prompts = options.prompts ?? promptIO;
39008
- const deps = { ...DEFAULT_DEPS, ...options.deps };
39380
+ const deps = { ...DEFAULT_DEPS3, ...options.deps };
39009
39381
  const storageDir = options.storageDir ?? dirname11(options.dbPath ?? join16(getMagicContextStorageDir(), "context.db"));
39010
39382
  const dbPath = options.dbPath ?? join16(storageDir, "context.db");
39011
39383
  const stamp = timestamp(deps.now());
@@ -39175,7 +39547,7 @@ async function runRepairDbCli(args, options = {}) {
39175
39547
  }
39176
39548
  return runRepairDb(options);
39177
39549
  }
39178
- 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;
39179
39551
  var init_doctor_repair_db = __esm(async () => {
39180
39552
  init_migrations();
39181
39553
  init_data_path();
@@ -39195,7 +39567,7 @@ var init_doctor_repair_db = __esm(async () => {
39195
39567
  unsalvageable: 2,
39196
39568
  refused: 3
39197
39569
  };
39198
- DEFAULT_DEPS = {
39570
+ DEFAULT_DEPS3 = {
39199
39571
  now: () => new Date,
39200
39572
  sqliteExecutable: defaultSqliteExecutable(),
39201
39573
  inspectHolders: defaultInspectHolders
@@ -39225,17 +39597,20 @@ var init_migration_paths = () => {};
39225
39597
  // src/commands/migrate.ts
39226
39598
  var exports_migrate = {};
39227
39599
  __export(exports_migrate, {
39600
+ sweepPendingMigrations: () => sweepPendingMigrations,
39228
39601
  runMigrateCli: () => runMigrateCli,
39229
39602
  projectPathToPiDirSlug: () => projectPathToPiDirSlug,
39230
39603
  printMigrateHelp: () => printMigrateHelp,
39231
39604
  parseMigrateArgs: () => parseMigrateArgs,
39605
+ migrationKeyFor: () => migrationKeyFor,
39232
39606
  migrateOpenCodeSessionToPi: () => migrateOpenCodeSessionToPi,
39233
39607
  generateUuidV7: () => generateUuidV7,
39234
- formatPiFilenameTimestamp: () => formatPiFilenameTimestamp
39608
+ formatPiFilenameTimestamp: () => formatPiFilenameTimestamp,
39609
+ formatMigrationSweepLines: () => formatMigrationSweepLines
39235
39610
  });
39236
- import { randomBytes as randomBytes2 } from "node:crypto";
39237
- import { unlinkSync as unlinkSync3 } from "node:fs";
39238
- import { join as join18 } from "node:path";
39611
+ import { createHash as createHash3, randomBytes as randomBytes2 } from "node:crypto";
39612
+ import { existsSync as existsSync21, mkdirSync as mkdirSync8, renameSync as renameSync4, unlinkSync as unlinkSync3 } from "node:fs";
39613
+ import { dirname as dirname12, join as join18 } from "node:path";
39239
39614
  function defaultOpenCodeDbPath() {
39240
39615
  return getOpenCodeDatabasePath();
39241
39616
  }
@@ -39246,7 +39621,7 @@ function defaultPiSessionsRoot() {
39246
39621
  return getPiSessionsRoot();
39247
39622
  }
39248
39623
  function defaultFs() {
39249
- return { writeFileAtomic, unlinkSync: unlinkSync3 };
39624
+ return { writeFileAtomic, unlinkSync: unlinkSync3, existsSync: existsSync21, renameSync: renameSync4, mkdirSync: mkdirSync8 };
39250
39625
  }
39251
39626
  function stmt(db, sql) {
39252
39627
  return db.prepare(sql);
@@ -39272,6 +39647,74 @@ function generateUuidV7(date5 = new Date) {
39272
39647
  function shortId() {
39273
39648
  return randomBytes2(4).toString("hex");
39274
39649
  }
39650
+ function migrationKeyFor(sourceSessionId, targetHarness) {
39651
+ return createHash3("sha256").update(`${sourceSessionId}
39652
+ ${targetHarness}`).digest("hex");
39653
+ }
39654
+ function hasMigrationJournal(db) {
39655
+ return Boolean(stmt(db, "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'migration_pending'").get());
39656
+ }
39657
+ function sweepPendingMigrations(db, fs3 = defaultFs()) {
39658
+ const report = {
39659
+ completed: 0,
39660
+ rolledForward: 0,
39661
+ rolledBack: 0,
39662
+ lost: []
39663
+ };
39664
+ if (!hasMigrationJournal(db))
39665
+ return report;
39666
+ const rows = stmt(db, `SELECT migration_key, source_session_id, target_harness, pi_session_id,
39667
+ final_path, stage_path, content_sha256, phase, created_at
39668
+ FROM migration_pending
39669
+ ORDER BY created_at ASC`).all();
39670
+ for (const row of rows) {
39671
+ if (fs3.existsSync(row.final_path)) {
39672
+ stmt(db, "DELETE FROM migration_pending WHERE migration_key = ?").run(row.migration_key);
39673
+ report.completed += 1;
39674
+ continue;
39675
+ }
39676
+ if (row.phase === "db_committed") {
39677
+ if (fs3.existsSync(row.stage_path)) {
39678
+ fs3.mkdirSync(dirname12(row.final_path), { recursive: true });
39679
+ fs3.renameSync(row.stage_path, row.final_path);
39680
+ stmt(db, "DELETE FROM migration_pending WHERE migration_key = ?").run(row.migration_key);
39681
+ report.rolledForward += 1;
39682
+ } else {
39683
+ report.lost.push(row);
39684
+ }
39685
+ continue;
39686
+ }
39687
+ try {
39688
+ fs3.unlinkSync(row.stage_path);
39689
+ } catch {}
39690
+ stmt(db, "DELETE FROM migration_pending WHERE migration_key = ?").run(row.migration_key);
39691
+ report.rolledBack += 1;
39692
+ }
39693
+ return report;
39694
+ }
39695
+ function readPendingMigration(db, migrationKey) {
39696
+ return stmt(db, JOURNAL_SELECT_SQL).get(migrationKey);
39697
+ }
39698
+ function claimJournalIdentity(args) {
39699
+ const existing = readPendingMigration(args.db, args.migrationKey);
39700
+ if (existing) {
39701
+ return { row: existing, resumed: true };
39702
+ }
39703
+ const piSessionId = generateUuidV7(new Date(args.now));
39704
+ stmt(args.db, `INSERT INTO migration_pending (
39705
+ migration_key, source_session_id, target_harness, pi_session_id,
39706
+ final_path, stage_path, content_sha256, phase, created_at
39707
+ ) VALUES (?, ?, ?, ?, ?, ?, '', 'staged', ?)
39708
+ ON CONFLICT(migration_key) DO NOTHING`).run(args.migrationKey, args.sourceSessionId, args.targetHarness, piSessionId, args.finalPathFor(piSessionId), join18(args.stageDir, `${args.migrationKey}.jsonl`), args.now);
39709
+ const row = readPendingMigration(args.db, args.migrationKey);
39710
+ if (!row) {
39711
+ throw new Error("migration journal row disappeared during insert; aborting migration");
39712
+ }
39713
+ return { row, resumed: row.pi_session_id !== piSessionId };
39714
+ }
39715
+ function commitStagedChecksum(db, migrationKey, contentSha256) {
39716
+ stmt(db, "UPDATE migration_pending SET content_sha256 = ? WHERE migration_key = ?").run(contentSha256, migrationKey);
39717
+ }
39275
39718
  function parseJsonObject(text3) {
39276
39719
  const parsed = JSON.parse(text3);
39277
39720
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -39431,7 +39874,7 @@ function convertPartToEntries(ctx) {
39431
39874
  }
39432
39875
  }
39433
39876
  function buildPiEntries(params) {
39434
- const sessionUuid = generateUuidV7(params.now);
39877
+ const sessionUuid = params.piSessionId;
39435
39878
  const nowIso = params.now.toISOString();
39436
39879
  const entries = [
39437
39880
  {
@@ -39467,6 +39910,7 @@ The following conversation was migrated from a different harness. Reasoning cont
39467
39910
  list.push(part);
39468
39911
  partsByMessage.set(part.message_id, list);
39469
39912
  }
39913
+ const messageIdToFirstPiEntryId = new Map;
39470
39914
  const messageIdToLastPiEntryId = new Map;
39471
39915
  const orderedSourceMessageIds = [];
39472
39916
  let parentId = boundary.id;
@@ -39477,6 +39921,7 @@ The following conversation was migrated from a different harness. Reasoning cont
39477
39921
  const timestamp2 = isoFromMs(message.time_created, params.now);
39478
39922
  const tokens = tokensFromMessage(message);
39479
39923
  const usage = tokensToPiUsage(tokens);
39924
+ let firstEntryIdForMessage = null;
39480
39925
  let lastEntryIdForMessage = null;
39481
39926
  for (const part of partsByMessage.get(message.id) ?? []) {
39482
39927
  const newEntries = convertPartToEntries({
@@ -39491,10 +39936,13 @@ The following conversation was migrated from a different harness. Reasoning cont
39491
39936
  entry.parentId = parentId;
39492
39937
  entries.push(entry);
39493
39938
  parentId = entry.id;
39939
+ if (firstEntryIdForMessage === null)
39940
+ firstEntryIdForMessage = parentId;
39494
39941
  lastEntryIdForMessage = parentId;
39495
39942
  }
39496
39943
  }
39497
- if (lastEntryIdForMessage !== null) {
39944
+ if (lastEntryIdForMessage !== null && firstEntryIdForMessage !== null) {
39945
+ messageIdToFirstPiEntryId.set(message.id, firstEntryIdForMessage);
39498
39946
  messageIdToLastPiEntryId.set(message.id, lastEntryIdForMessage);
39499
39947
  orderedSourceMessageIds.push(message.id);
39500
39948
  }
@@ -39502,6 +39950,7 @@ The following conversation was migrated from a different harness. Reasoning cont
39502
39950
  return {
39503
39951
  entries,
39504
39952
  piSessionId: sessionUuid,
39953
+ messageIdToFirstPiEntryId,
39505
39954
  messageIdToLastPiEntryId,
39506
39955
  orderedSourceMessageIds
39507
39956
  };
@@ -39539,8 +39988,9 @@ function fetchRows(db, sessionId, maxMessages) {
39539
39988
  throw error51;
39540
39989
  }
39541
39990
  }
39542
- function remapBoundaryId(openCodeMessageId, messageIdToLastPiEntryId, orderedSourceMessageIds) {
39543
- const direct = messageIdToLastPiEntryId.get(openCodeMessageId);
39991
+ function remapBoundaryId(openCodeMessageId, edge, messageIdToFirstPiEntryId, messageIdToLastPiEntryId, orderedSourceMessageIds) {
39992
+ const directMap = edge === "start" ? messageIdToFirstPiEntryId : messageIdToLastPiEntryId;
39993
+ const direct = directMap.get(openCodeMessageId);
39544
39994
  if (direct !== undefined)
39545
39995
  return { piEntryId: direct, exact: true };
39546
39996
  let nearestAtOrBefore;
@@ -39601,8 +40051,8 @@ function copyMagicContextState(args) {
39601
40051
  let boundariesApproximated = 0;
39602
40052
  const remappedCompartments = [];
39603
40053
  for (const c3 of sourceCompartments) {
39604
- const startRemap = remapBoundaryId(c3.start_message_id, args.messageIdToLastPiEntryId, args.orderedSourceMessageIds);
39605
- const endRemap = remapBoundaryId(c3.end_message_id, args.messageIdToLastPiEntryId, args.orderedSourceMessageIds);
40054
+ const startRemap = remapBoundaryId(c3.start_message_id, "start", args.messageIdToFirstPiEntryId, args.messageIdToLastPiEntryId, args.orderedSourceMessageIds);
40055
+ const endRemap = remapBoundaryId(c3.end_message_id, "end", args.messageIdToFirstPiEntryId, args.messageIdToLastPiEntryId, args.orderedSourceMessageIds);
39606
40056
  if (!startRemap || !endRemap)
39607
40057
  continue;
39608
40058
  if (!startRemap.exact || !endRemap.exact)
@@ -39631,9 +40081,9 @@ function copyMagicContextState(args) {
39631
40081
  lastCompartmentEndPiEntryId: remappedCompartments.at(-1)?.end_message_id
39632
40082
  };
39633
40083
  if (args.dryRun) {
39634
- return { ...result, commit: () => {} };
40084
+ return { ...result, remappedCompartments, commit: () => {} };
39635
40085
  }
39636
- const commit = () => {
40086
+ const commit = (journalKey) => {
39637
40087
  const insertCompartment = stmt(args.cortexkitDb, `INSERT INTO compartments (
39638
40088
  session_id, sequence, start_message, end_message,
39639
40089
  start_message_id, end_message_id, title, content,
@@ -39645,19 +40095,72 @@ function copyMagicContextState(args) {
39645
40095
  ) VALUES (?, ?, ?, ?, ?, 'pi')`);
39646
40096
  args.cortexkitDb.exec("BEGIN IMMEDIATE");
39647
40097
  try {
40098
+ stmt(args.cortexkitDb, "DELETE FROM compartments WHERE session_id = ? AND harness = 'pi'").run(args.piSessionId);
40099
+ stmt(args.cortexkitDb, "DELETE FROM session_facts WHERE session_id = ? AND harness = 'pi'").run(args.piSessionId);
39648
40100
  for (const c3 of remappedCompartments) {
39649
40101
  insertCompartment.run(args.piSessionId, c3.sequence, c3.start_message, c3.end_message, c3.start_message_id, c3.end_message_id, c3.title, c3.content, c3.p1, c3.p2, c3.p3, c3.p4, typeof c3.importance === "number" ? c3.importance : 50, c3.episode_type, c3.legacy, args.now);
39650
40102
  }
39651
40103
  for (const f2 of sourceFacts) {
39652
40104
  insertFact.run(args.piSessionId, f2.category, f2.content, f2.created_at, f2.updated_at);
39653
40105
  }
40106
+ if (journalKey !== undefined) {
40107
+ stmt(args.cortexkitDb, "UPDATE migration_pending SET phase = 'db_committed' WHERE migration_key = ?").run(journalKey);
40108
+ }
39654
40109
  args.cortexkitDb.exec("COMMIT");
39655
40110
  } catch (error51) {
39656
40111
  args.cortexkitDb.exec("ROLLBACK");
39657
40112
  throw error51;
39658
40113
  }
39659
40114
  };
39660
- return { ...result, commit };
40115
+ return { ...result, remappedCompartments, commit };
40116
+ }
40117
+ function derivePiRuntimeOrdinals(entries) {
40118
+ const ordinalByEntryId = new Map;
40119
+ let nextOrdinal = 1;
40120
+ const pendingToolResultIds = [];
40121
+ const foldPendingInto = (ordinal) => {
40122
+ for (const id of pendingToolResultIds)
40123
+ ordinalByEntryId.set(id, ordinal);
40124
+ pendingToolResultIds.length = 0;
40125
+ };
40126
+ for (const entry of entries) {
40127
+ const message = entry.message;
40128
+ if (entry.type !== "message" || typeof entry.id !== "string" || message === null || typeof message !== "object") {
40129
+ continue;
40130
+ }
40131
+ const role = message.role;
40132
+ if (role === "toolResult") {
40133
+ pendingToolResultIds.push(entry.id);
40134
+ continue;
40135
+ }
40136
+ if (role === "assistant" && pendingToolResultIds.length > 0) {
40137
+ foldPendingInto(nextOrdinal);
40138
+ nextOrdinal += 1;
40139
+ }
40140
+ const ordinal = nextOrdinal;
40141
+ nextOrdinal += 1;
40142
+ if (role === "user" && pendingToolResultIds.length > 0) {
40143
+ foldPendingInto(ordinal);
40144
+ }
40145
+ ordinalByEntryId.set(entry.id, ordinal);
40146
+ }
40147
+ if (pendingToolResultIds.length > 0) {
40148
+ foldPendingInto(nextOrdinal);
40149
+ }
40150
+ return ordinalByEntryId;
40151
+ }
40152
+ function applyRuntimeOrdinals(remappedCompartments, entries) {
40153
+ const ordinals = derivePiRuntimeOrdinals(entries);
40154
+ for (const compartment of remappedCompartments) {
40155
+ const startOrdinal = ordinals.get(compartment.start_message_id);
40156
+ const endOrdinal = ordinals.get(compartment.end_message_id);
40157
+ if (startOrdinal === undefined || endOrdinal === undefined) {
40158
+ const missing = startOrdinal === undefined ? compartment.start_message_id : compartment.end_message_id;
40159
+ throw new Error(`Migration boundary entry ${missing} has no runtime ordinal; migrator invariant violated`);
40160
+ }
40161
+ compartment.start_message = startOrdinal;
40162
+ compartment.end_message = endOrdinal;
40163
+ }
39661
40164
  }
39662
40165
  function ensureValidOptions(opts) {
39663
40166
  if (!opts.from)
@@ -39707,52 +40210,88 @@ function migrateOpenCodeSessionToPi(opts) {
39707
40210
  const modelId = opts.modelId ?? model.modelId;
39708
40211
  const cwd = session.directory ?? session.path ?? process.cwd();
39709
40212
  const outputDir = join18(piSessionsRoot, projectPathToPiDirSlug(cwd));
40213
+ const targetHarness = opts.targetHarness ?? "pi";
40214
+ const journalActive = cortexkitDb !== null && !opts.dryRun;
40215
+ let recovery;
40216
+ let migrationKey;
40217
+ let journalResumed = false;
40218
+ let piSessionId;
40219
+ let finalPath;
40220
+ let stagePath;
40221
+ if (journalActive && cortexkitDb !== null) {
40222
+ if (!hasMigrationJournal(cortexkitDb)) {
40223
+ throw new Error("context.db has no migration_pending journal (shared schema older than v78). Run a harness session once so the plugin can upgrade the schema, then retry doctor migrate.");
40224
+ }
40225
+ recovery = sweepPendingMigrations(cortexkitDb, fs3);
40226
+ migrationKey = migrationKeyFor(session.id, targetHarness);
40227
+ const claimed = claimJournalIdentity({
40228
+ db: cortexkitDb,
40229
+ migrationKey,
40230
+ sourceSessionId: session.id,
40231
+ targetHarness,
40232
+ finalPathFor: (id) => join18(outputDir, `${formatPiFilenameTimestamp(now)}_${id}.jsonl`),
40233
+ stageDir: join18(dirname12(piSessionsRoot), MIGRATION_STAGE_DIRNAME),
40234
+ now: now.getTime()
40235
+ });
40236
+ piSessionId = claimed.row.pi_session_id;
40237
+ finalPath = claimed.row.final_path;
40238
+ stagePath = claimed.row.stage_path;
40239
+ journalResumed = claimed.resumed;
40240
+ } else {
40241
+ piSessionId = generateUuidV7(now);
40242
+ finalPath = join18(outputDir, `${formatPiFilenameTimestamp(now)}_${piSessionId}.jsonl`);
40243
+ stagePath = "";
40244
+ }
39710
40245
  const buildResult = buildPiEntries({
39711
40246
  session,
39712
40247
  messages,
39713
40248
  parts,
39714
40249
  now,
39715
40250
  provider,
39716
- modelId
40251
+ modelId,
40252
+ piSessionId
39717
40253
  });
39718
40254
  let copyResult = {
39719
40255
  compartmentsCopied: 0,
39720
40256
  factsCopied: 0,
39721
40257
  boundariesApproximated: 0
39722
40258
  };
39723
- let commitMagicContextState = null;
40259
+ let plan = null;
39724
40260
  if (cortexkitDb !== null) {
39725
- const plan = copyMagicContextState({
40261
+ plan = copyMagicContextState({
39726
40262
  cortexkitDb,
39727
40263
  sourceSessionId: session.id,
39728
- piSessionId: buildResult.piSessionId,
40264
+ piSessionId,
40265
+ messageIdToFirstPiEntryId: buildResult.messageIdToFirstPiEntryId,
39729
40266
  messageIdToLastPiEntryId: buildResult.messageIdToLastPiEntryId,
39730
40267
  orderedSourceMessageIds: buildResult.orderedSourceMessageIds,
39731
40268
  now: now.getTime(),
39732
40269
  dryRun: Boolean(opts.dryRun)
39733
40270
  });
39734
40271
  copyResult = plan;
39735
- commitMagicContextState = plan.commit;
39736
40272
  }
39737
40273
  const compactionMarker = insertCompactionMarker(buildResult.entries, copyResult.lastCompartmentEndPiEntryId);
39738
- const outputPath = join18(outputDir, `${formatPiFilenameTimestamp(now)}_${buildResult.piSessionId}.jsonl`);
40274
+ if (plan)
40275
+ applyRuntimeOrdinals(plan.remappedCompartments, buildResult.entries);
39739
40276
  const jsonl = `${buildResult.entries.map((entry) => JSON.stringify(entry)).join(`
39740
40277
  `)}
39741
40278
  `;
39742
40279
  if (!opts.dryRun) {
39743
- fs3.writeFileAtomic(outputPath, jsonl);
39744
- try {
39745
- commitMagicContextState?.();
39746
- } catch (commitError) {
39747
- try {
39748
- fs3.unlinkSync(outputPath);
39749
- } catch {}
39750
- throw commitError;
40280
+ if (journalActive && cortexkitDb !== null && migrationKey !== undefined && plan) {
40281
+ const contentSha256 = createHash3("sha256").update(jsonl, "utf8").digest("hex");
40282
+ commitStagedChecksum(cortexkitDb, migrationKey, contentSha256);
40283
+ fs3.writeFileAtomic(stagePath, jsonl);
40284
+ plan.commit(migrationKey);
40285
+ fs3.mkdirSync(dirname12(finalPath), { recursive: true });
40286
+ fs3.renameSync(stagePath, finalPath);
40287
+ stmt(cortexkitDb, "DELETE FROM migration_pending WHERE migration_key = ?").run(migrationKey);
40288
+ } else {
40289
+ fs3.writeFileAtomic(finalPath, jsonl);
39751
40290
  }
39752
40291
  }
39753
40292
  return {
39754
- outputPath,
39755
- piSessionId: buildResult.piSessionId,
40293
+ outputPath: finalPath,
40294
+ piSessionId,
39756
40295
  messageCount: buildResult.entries.length - 2,
39757
40296
  byteCount: Buffer.byteLength(jsonl, "utf8"),
39758
40297
  sourceMessageCount,
@@ -39762,6 +40301,9 @@ function migrateOpenCodeSessionToPi(opts) {
39762
40301
  compactionMarkerWritten: compactionMarker.written,
39763
40302
  compactionBoundaryEntryId: compactionMarker.boundaryEntryId,
39764
40303
  compactionFirstKeptEntryId: compactionMarker.firstKeptEntryId,
40304
+ ...migrationKey !== undefined ? { migrationKey } : {},
40305
+ ...journalActive ? { journalResumed } : {},
40306
+ ...recovery !== undefined ? { recovery } : {},
39765
40307
  ...cortexkitSchemaVersionBefore !== null && cortexkitDb !== null ? {
39766
40308
  cortexkitSchemaVersionBefore,
39767
40309
  cortexkitSchemaVersionAfter: getPersistedSchemaVersion2(cortexkitDb)
@@ -39828,9 +40370,32 @@ function printMigrateHelp() {
39828
40370
  - compartments + session_facts are copied to the new Pi session_id;
39829
40371
  compartment boundary message IDs are remapped to the corresponding
39830
40372
  Pi entry IDs (nearest-at-or-before for boundaries that don't have
39831
- a direct message-level Pi entry)
40373
+ a direct message-level Pi entry), and compartment start/end ordinals
40374
+ are recomputed in the ordinal basis the Pi runtime reader produces
40375
+
40376
+ Crash safety:
40377
+ - each migration is tracked in the shared DB's migration_pending journal
40378
+ and staged outside the sessions tree; an interrupted run is reconciled
40379
+ by phase on the next 'doctor migrate' or plain 'doctor' run, reusing the
40380
+ original Pi session id instead of minting a second one
39832
40381
  `);
39833
40382
  }
40383
+ function formatMigrationSweepLines(report) {
40384
+ const lines = [];
40385
+ if (report.rolledForward > 0) {
40386
+ lines.push(`Recovered ${report.rolledForward} interrupted session migration(s) by completing the staged file rename.`);
40387
+ }
40388
+ if (report.rolledBack > 0) {
40389
+ lines.push(`Rolled back ${report.rolledBack} incomplete session migration(s) that never committed shared state.`);
40390
+ }
40391
+ if (report.completed > 0) {
40392
+ lines.push(`Cleared ${report.completed} finished session-migration journal row(s).`);
40393
+ }
40394
+ for (const row of report.lost) {
40395
+ lines.push(`LOST session migration content: source ${row.source_session_id} → ${row.target_harness} session ${row.pi_session_id}; expected file ${row.final_path} (sha256 ${row.content_sha256}). Re-run doctor migrate for this session to rebuild it.`);
40396
+ }
40397
+ return lines;
40398
+ }
39834
40399
  async function runMigrateCli(args) {
39835
40400
  try {
39836
40401
  const parsed = parseMigrateArgs(args);
@@ -39840,8 +40405,14 @@ async function runMigrateCli(args) {
39840
40405
  sessionId: parsed.session,
39841
40406
  maxMessages: parsed.maxMessages,
39842
40407
  dryRun: parsed.dryRun,
39843
- piSessionsRoot: parsed.to === "omp" ? getOmpSessionsRoot() : undefined
40408
+ piSessionsRoot: parsed.to === "omp" ? getOmpSessionsRoot() : undefined,
40409
+ targetHarness: parsed.to === "omp" ? "omp" : "pi"
39844
40410
  });
40411
+ if (result.recovery) {
40412
+ for (const line of formatMigrationSweepLines(result.recovery)) {
40413
+ console.log(line);
40414
+ }
40415
+ }
39845
40416
  const action = result.dryRun ? "Would write" : "Wrote";
39846
40417
  console.log(`${action} ${target} session JSONL:`);
39847
40418
  console.log(` path: ${result.outputPath}`);
@@ -39858,6 +40429,9 @@ async function runMigrateCli(args) {
39858
40429
  if (result.boundariesApproximated > 0) {
39859
40430
  console.log(` boundaries approximated: ${result.boundariesApproximated} (nearest-at-or-before)`);
39860
40431
  }
40432
+ if (result.migrationKey !== undefined) {
40433
+ console.log(` journal: ${result.migrationKey.slice(0, 12)}…${result.journalResumed ? " (resumed interrupted attempt)" : ""}`);
40434
+ }
39861
40435
  if (!result.dryRun) {
39862
40436
  console.log(`${target} may need to be restarted to pick up the new session file.`);
39863
40437
  if (result.cortexkitSchemaVersionBefore !== undefined) {
@@ -39875,7 +40449,9 @@ async function runMigrateCli(args) {
39875
40449
  return 1;
39876
40450
  }
39877
40451
  }
39878
- var DEFAULT_PROVIDER = "openai-codex", DEFAULT_MODEL = "gpt-5.5", MIGRATION_COMPACTION_SUMMARY = "Magic Context compacted prior conversation. See <session-history> block for the structured summary.", PART_LOOKUP_CHUNK_SIZE = 900;
40452
+ var DEFAULT_PROVIDER = "openai-codex", DEFAULT_MODEL = "gpt-5.5", MIGRATION_COMPACTION_SUMMARY = "Magic Context compacted prior conversation. See <session-history> block for the structured summary.", PART_LOOKUP_CHUNK_SIZE = 900, MIGRATION_STAGE_DIRNAME = ".mc-migrations", JOURNAL_SELECT_SQL = `SELECT migration_key, source_session_id, target_harness, pi_session_id,
40453
+ final_path, stage_path, content_sha256, phase, created_at
40454
+ FROM migration_pending WHERE migration_key = ?`;
39879
40455
  var init_migrate = __esm(async () => {
39880
40456
  init_data_path();
39881
40457
  init_atomic_write();
@@ -39979,15 +40555,72 @@ var exports_migrate_session = {};
39979
40555
  __export(exports_migrate_session, {
39980
40556
  runMigrateSessionCli: () => runMigrateSessionCli,
39981
40557
  planMigrateSession: () => planMigrateSession,
40558
+ assertMigrateSessionIsSafeToRehome: () => assertMigrateSessionIsSafeToRehome,
39982
40559
  applyMigrateSession: () => applyMigrateSession
39983
40560
  });
39984
- import { existsSync as existsSync21, realpathSync as realpathSync4 } from "node:fs";
40561
+ import { existsSync as existsSync22, realpathSync as realpathSync4 } from "node:fs";
39985
40562
  import { homedir as homedir13 } from "node:os";
39986
40563
  import path4, { join as join19 } from "node:path";
39987
40564
  function existingSessionColumns(db) {
39988
40565
  const rows = db.prepare("PRAGMA table_info(session)").all();
39989
40566
  return new Set(rows.map((r2) => r2.name).filter((n2) => typeof n2 === "string"));
39990
40567
  }
40568
+ function isModuleCacheStatePresent(status) {
40569
+ if (!status || typeof status !== "object")
40570
+ return false;
40571
+ const rowVersion = status.row_version;
40572
+ return typeof rowVersion === "number";
40573
+ }
40574
+ function drainCommandsForMarkers(markers, projects) {
40575
+ const byProject = new Map(projects.map((project) => [project.projectPath, project]));
40576
+ return [
40577
+ ...new Set(markers.map((marker) => authorityDrainCommand(byProject.get(marker.project_path) ?? {
40578
+ role: "marked",
40579
+ projectPath: marker.project_path,
40580
+ projectRoot: null
40581
+ })))
40582
+ ].join("; ");
40583
+ }
40584
+ async function assertMigrateSessionIsSafeToRehome(args) {
40585
+ const projects = [
40586
+ {
40587
+ role: "source",
40588
+ projectPath: args.plan.fromMcIdentity,
40589
+ projectRoot: args.plan.currentDirectory
40590
+ },
40591
+ {
40592
+ role: "target",
40593
+ projectPath: args.plan.toMcIdentity,
40594
+ projectRoot: args.plan.targetDirectory
40595
+ }
40596
+ ];
40597
+ const authority = await assertProjectsUseTsAuthority({
40598
+ db: args.contextDb,
40599
+ projects,
40600
+ module: args.module
40601
+ });
40602
+ let sessionStatus;
40603
+ try {
40604
+ sessionStatus = await args.module.sessionStatus({
40605
+ sessionId: args.plan.sessionId,
40606
+ projectRoot: args.plan.currentDirectory ?? args.plan.targetDirectory
40607
+ });
40608
+ } catch (error51) {
40609
+ const message = error51 instanceof Error ? error51.message : String(error51);
40610
+ if (authority.markers.length === 0) {
40611
+ return {
40612
+ warnings: [
40613
+ `Module session-cache state was not checked because the module is unreachable: ${message}. No durable authority markers exist, so continuing for this pure-TypeScript installation.`
40614
+ ]
40615
+ };
40616
+ }
40617
+ throw new Error("Migration refused: module session-cache state is unreachable while durable authority markers exist; writes remain fenced. " + `Drain marked projects first: ${drainCommandsForMarkers(authority.markers, projects)}. ` + `Module error: ${message}`);
40618
+ }
40619
+ if (isModuleCacheStatePresent(sessionStatus)) {
40620
+ throw new Error(`Migration refused: the module still holds transform cache state for session ${args.plan.sessionId}. ` + "Use TypeScript transform mode for the session's project, or run `ck session delete` after preserving any needed state, then re-run this migration.");
40621
+ }
40622
+ return { warnings: [] };
40623
+ }
39991
40624
  function planMigrateSession(sessionId, rawTargetDirectory, deps) {
39992
40625
  const sessionRow = deps.opencodeDb.prepare("SELECT id, directory FROM session WHERE id = ?").get(sessionId);
39993
40626
  if (!sessionRow) {
@@ -40144,7 +40777,7 @@ function realDeps(opencodeDb, contextDb) {
40144
40777
  opencodeDb,
40145
40778
  contextDb,
40146
40779
  resolveIdentity: resolveProjectIdentity,
40147
- hasGitDir: (dir) => existsSync21(join19(dir, ".git")),
40780
+ hasGitDir: (dir) => existsSync22(join19(dir, ".git")),
40148
40781
  realpath: (p2) => realpathSync4(p2)
40149
40782
  };
40150
40783
  }
@@ -40223,7 +40856,7 @@ async function runMigrateSessionCli(args) {
40223
40856
  return 1;
40224
40857
  }
40225
40858
  const expandedTo = toDir.startsWith("~") ? join19(homedir13(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
40226
- if (!existsSync21(expandedTo)) {
40859
+ if (!existsSync22(expandedTo)) {
40227
40860
  console.error(`Target directory does not exist: ${expandedTo}`);
40228
40861
  return 1;
40229
40862
  }
@@ -40249,6 +40882,27 @@ async function runMigrateSessionCli(args) {
40249
40882
  } catch {}
40250
40883
  const deps = realDeps(opencodeDb, contextDb);
40251
40884
  const plan = planMigrateSession(sessionId, expandedTo, deps);
40885
+ const transport = new SubcModuleTransport;
40886
+ const safety = await assertMigrateSessionIsSafeToRehome({
40887
+ plan,
40888
+ contextDb,
40889
+ module: {
40890
+ authorityStatus: (request) => transport.authorityStatus(request),
40891
+ sessionStatus: ({ sessionId: statusSessionId, projectRoot }) => transport.call({
40892
+ sessionId: statusSessionId,
40893
+ projectRoot,
40894
+ method: "session.status",
40895
+ body: {
40896
+ method: "session.status",
40897
+ v: 1,
40898
+ session_id: statusSessionId
40899
+ }
40900
+ })
40901
+ }
40902
+ });
40903
+ for (const warning of safety.warnings) {
40904
+ promptIO.log.warn(warning);
40905
+ }
40252
40906
  promptIO.note([
40253
40907
  `session: ${plan.sessionId}`,
40254
40908
  `from: ${plan.currentDirectory ?? "(unknown)"}`,
@@ -40332,10 +40986,14 @@ var init_migrate_session = __esm(async () => {
40332
40986
  init_project_identity();
40333
40987
  init_relocate_memory();
40334
40988
  init_storage_project_state();
40989
+ init_module_transport();
40335
40990
  init_data_path();
40336
40991
  init_migration_paths();
40337
40992
  init_prompts();
40338
- await init_database_access();
40993
+ await __promiseAll([
40994
+ init_database_access(),
40995
+ init_doctor_authority()
40996
+ ]);
40339
40997
  VALID_MEMORY_ACTIONS = new Set([
40340
40998
  "move-all",
40341
40999
  "move-originated",
@@ -40346,7 +41004,7 @@ var init_migrate_session = __esm(async () => {
40346
41004
  });
40347
41005
 
40348
41006
  // ../plugin/src/features/magic-context/v22-deferred-backfill.ts
40349
- import { createHash as createHash3 } from "node:crypto";
41007
+ import { createHash as createHash4 } from "node:crypto";
40350
41008
  import { realpathSync as realpathSync5 } from "node:fs";
40351
41009
  import path5 from "node:path";
40352
41010
  function readMeta(db, key) {
@@ -40395,7 +41053,7 @@ function computeLegacyRustDirIdentity(rawProjectPath) {
40395
41053
  } catch {
40396
41054
  canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
40397
41055
  }
40398
- return `dir:${createHash3("sha256").update(canonical, "utf8").digest("hex")}`;
41056
+ return `dir:${createHash4("sha256").update(canonical, "utf8").digest("hex")}`;
40399
41057
  }
40400
41058
  function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
40401
41059
  db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
@@ -40580,7 +41238,7 @@ var init_v22_backfill_commands = __esm(async () => {
40580
41238
  });
40581
41239
 
40582
41240
  // ../pi-plugin/src/config/index.ts
40583
- import { existsSync as existsSync22, readFileSync as readFileSync14 } from "node:fs";
41241
+ import { existsSync as existsSync23, readFileSync as readFileSync14 } from "node:fs";
40584
41242
  function getProjectConfigPaths(cwd) {
40585
41243
  const basePath = cortexKitProjectConfigBasePath(cwd);
40586
41244
  return [`${basePath}.jsonc`, `${basePath}.json`];
@@ -40590,10 +41248,10 @@ function getUserConfigPaths() {
40590
41248
  return [`${basePath}.jsonc`, `${basePath}.json`];
40591
41249
  }
40592
41250
  function resolveFirstExisting(paths) {
40593
- return paths.find((path6) => existsSync22(path6));
41251
+ return paths.find((path6) => existsSync23(path6));
40594
41252
  }
40595
41253
  function resolvePiLegacyFallback(sources) {
40596
- return sources.find((source) => existsSync22(source.path)) ?? null;
41254
+ return sources.find((source) => existsSync23(source.path)) ?? null;
40597
41255
  }
40598
41256
  function loadConfigFile(path6, scope) {
40599
41257
  try {
@@ -40750,7 +41408,7 @@ function loadPiConfig(opts = {}) {
40750
41408
  if (loaded)
40751
41409
  loadedFiles.push(loaded);
40752
41410
  }
40753
- const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) => existsSync22(source.path));
41411
+ const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) => existsSync23(source.path));
40754
41412
  const userPath = resolveFirstExisting(getUserConfigPaths());
40755
41413
  const userLegacyFallback = userPath ? null : resolvePiLegacyFallback(harnessLegacy.user);
40756
41414
  const userReadPath = userPath ?? userLegacyFallback?.path;
@@ -40759,7 +41417,7 @@ function loadPiConfig(opts = {}) {
40759
41417
  if (loaded)
40760
41418
  loadedFiles.push(loaded);
40761
41419
  }
40762
- const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) => existsSync22(source.path));
41420
+ const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) => existsSync23(source.path));
40763
41421
  if (userLegacyFallback) {
40764
41422
  warnings.push(`[user config] reading legacy config from ${userLegacyFallback.path} until migration completes; run \`npx @cortexkit/magic-context doctor\` to consolidate into the shared CortexKit location.`);
40765
41423
  } else if (legacyUserUnmigrated) {
@@ -40803,6 +41461,7 @@ function loadPiConfig(opts = {}) {
40803
41461
  }
40804
41462
  const parsed = parsePiConfig(rawConfig);
40805
41463
  setOutputReserveConfig(parsed.config.output_reserve);
41464
+ setWindowOverlayPath(parsed.config.models?.window_overlay_path);
40806
41465
  warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
40807
41466
  return {
40808
41467
  config: parsed.config,
@@ -40821,6 +41480,7 @@ var init_config2 = __esm(() => {
40821
41480
  init_variable();
40822
41481
  init_jsonc_parser();
40823
41482
  init_models_dev_cache();
41483
+ init_window_geometry();
40824
41484
  import_comment_json7 = __toESM(require_src3(), 1);
40825
41485
  });
40826
41486
 
@@ -41040,9 +41700,9 @@ var init_redaction2 = __esm(() => {
41040
41700
 
41041
41701
  // src/commands/doctor-omp.ts
41042
41702
  import { execFileSync as execFileSync5, spawnSync as spawnSync4 } from "node:child_process";
41043
- import { existsSync as existsSync23, mkdirSync as mkdirSync8, readFileSync as readFileSync15 } from "node:fs";
41703
+ import { existsSync as existsSync24, mkdirSync as mkdirSync9, readFileSync as readFileSync15 } from "node:fs";
41044
41704
  import { createRequire as createRequire2 } from "node:module";
41045
- import { dirname as dirname12, join as join20, resolve as resolve5 } from "node:path";
41705
+ import { dirname as dirname13, join as join20, resolve as resolve6 } from "node:path";
41046
41706
  function parseSemver(value) {
41047
41707
  const match = value?.match(/(\d+)\.(\d+)\.(\d+)/);
41048
41708
  return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
@@ -41084,7 +41744,7 @@ function selfVersion() {
41084
41744
  return "unknown";
41085
41745
  }
41086
41746
  function readConfig2(path6) {
41087
- if (!existsSync23(path6))
41747
+ if (!existsSync24(path6))
41088
41748
  return {};
41089
41749
  try {
41090
41750
  const parsed = import_comment_json8.parse(readFileSync15(path6, "utf-8"));
@@ -41168,8 +41828,8 @@ async function runHealthChecks(options) {
41168
41828
  if (!reportedAgentDir.ok) {
41169
41829
  add(results, "warn", "Could not verify OMP active agent directory");
41170
41830
  } else {
41171
- const reportedPath = resolve5(reportedAgentDir.stdout);
41172
- const expectedPath = resolve5(getOmpAgentDir());
41831
+ const reportedPath = resolve6(reportedAgentDir.stdout);
41832
+ const expectedPath = resolve6(getOmpAgentDir());
41173
41833
  if (reportedPath === expectedPath) {
41174
41834
  add(results, "pass", `OMP agent directory resolved to ${getOmpAgentDir()}`);
41175
41835
  } else {
@@ -41178,7 +41838,7 @@ async function runHealthChecks(options) {
41178
41838
  }
41179
41839
  }
41180
41840
  const userConfigPath = getOmpUserConfigPath();
41181
- if (!existsSync23(userConfigPath)) {
41841
+ if (!existsSync24(userConfigPath)) {
41182
41842
  add(results, "warn", `No Magic Context user config at ${userConfigPath}`);
41183
41843
  repairPlan.writeUserConfig = true;
41184
41844
  } else {
@@ -41195,7 +41855,7 @@ async function runHealthChecks(options) {
41195
41855
  for (const warning of loaded.warnings.slice(0, 5))
41196
41856
  add(results, "warn", warning);
41197
41857
  const dbPath = join20(getMagicContextStorageDir(), "context.db");
41198
- if (!existsSync23(dbPath))
41858
+ if (!existsSync24(dbPath))
41199
41859
  add(results, "info", `Shared context DB will be created at ${dbPath}`);
41200
41860
  else {
41201
41861
  let db = null;
@@ -41224,7 +41884,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
41224
41884
  add(results, "info", `OMP non-global config: ${source}`);
41225
41885
  }
41226
41886
  const logPath = getMagicContextLogPath2("pi");
41227
- add(results, "info", `Pi-compatible runtime log: ${logPath}${existsSync23(logPath) ? "" : " (not created yet)"}`);
41887
+ add(results, "info", `Pi-compatible runtime log: ${logPath}${existsSync24(logPath) ? "" : " (not created yet)"}`);
41228
41888
  if (!options.quiet)
41229
41889
  for (const result of results)
41230
41890
  printResult(options.prompts, result);
@@ -41237,7 +41897,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
41237
41897
  };
41238
41898
  }
41239
41899
  function writeDefaultConfig(path6) {
41240
- mkdirSync8(dirname12(path6), { recursive: true });
41900
+ mkdirSync9(dirname13(path6), { recursive: true });
41241
41901
  const config2 = {
41242
41902
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
41243
41903
  ...MagicContextConfigSchema.parse({})
@@ -41247,7 +41907,7 @@ function writeDefaultConfig(path6) {
41247
41907
  }
41248
41908
  async function repair(plan, deps, prompts, cwd) {
41249
41909
  let fixed = 0;
41250
- if (plan.writeUserConfig && !existsSync23(getOmpUserConfigPath())) {
41910
+ if (plan.writeUserConfig && !existsSync24(getOmpUserConfigPath())) {
41251
41911
  writeDefaultConfig(getOmpUserConfigPath());
41252
41912
  prompts.log.success(`Wrote default Magic Context config to ${getOmpUserConfigPath()}`);
41253
41913
  fixed += 1;
@@ -41341,8 +42001,8 @@ async function runIssueFlow(options) {
41341
42001
  }
41342
42002
  async function runDoctor(options = {}) {
41343
42003
  const deps = {
41344
- ...DEFAULT_DEPS2,
41345
- prompts: options.prompts ?? DEFAULT_DEPS2.prompts,
42004
+ ...DEFAULT_DEPS4,
42005
+ prompts: options.prompts ?? DEFAULT_DEPS4.prompts,
41346
42006
  ...options.deps
41347
42007
  };
41348
42008
  const prompts = options.prompts ?? deps.prompts;
@@ -41368,7 +42028,7 @@ async function runDoctor(options = {}) {
41368
42028
  prompts.log.message(`Summary: PASS ${second.pass} / WARN ${second.warn} / FAIL ${second.fail}`);
41369
42029
  return second.fail === 0 ? 0 : 1;
41370
42030
  }
41371
- 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;
41372
42032
  var init_doctor_omp = __esm(async () => {
41373
42033
  init_magic_context();
41374
42034
  init_data_path();
@@ -41382,7 +42042,7 @@ var init_doctor_omp = __esm(async () => {
41382
42042
  init_redaction2();
41383
42043
  await init_database_access();
41384
42044
  import_comment_json8 = __toESM(require_src3(), 1);
41385
- DEFAULT_DEPS2 = {
42045
+ DEFAULT_DEPS4 = {
41386
42046
  prompts: promptIO,
41387
42047
  detectOmpBinary,
41388
42048
  getOmpVersion,
@@ -41510,14 +42170,14 @@ var DEFAULT_TIMEOUT_MS = 1e4, MAX_PREVIEW_CHARS = 240;
41510
42170
  // ../plugin/src/shared/tui-config.ts
41511
42171
  import {
41512
42172
  chmodSync as chmodSync4,
41513
- existsSync as existsSync24,
41514
- mkdirSync as mkdirSync9,
42173
+ existsSync as existsSync25,
42174
+ mkdirSync as mkdirSync10,
41515
42175
  readFileSync as readFileSync16,
41516
- renameSync as renameSync4,
42176
+ renameSync as renameSync5,
41517
42177
  statSync as statSync9,
41518
42178
  writeFileSync as writeFileSync6
41519
42179
  } from "node:fs";
41520
- import { dirname as dirname13, join as join21 } from "node:path";
42180
+ import { dirname as dirname14, join as join21 } from "node:path";
41521
42181
  function pluginEntryId(entry) {
41522
42182
  if (typeof entry === "string")
41523
42183
  return entry;
@@ -41554,15 +42214,15 @@ function writeTuiConfigAtomic(configPath, config2) {
41554
42214
  chmodSync4(tmpPath, statSync9(configPath).mode & 511);
41555
42215
  }
41556
42216
  } catch {}
41557
- renameSync4(tmpPath, configPath);
42217
+ renameSync5(tmpPath, configPath);
41558
42218
  }
41559
42219
  function resolveTuiConfigPath(configDirOverride) {
41560
42220
  const configDir = configDirOverride ?? getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
41561
42221
  const jsoncPath = join21(configDir, "tui.jsonc");
41562
42222
  const jsonPath = join21(configDir, "tui.json");
41563
- if (existsSync24(jsoncPath))
42223
+ if (existsSync25(jsoncPath))
41564
42224
  return jsoncPath;
41565
- if (existsSync24(jsonPath))
42225
+ if (existsSync25(jsonPath))
41566
42226
  return jsonPath;
41567
42227
  return jsoncPath;
41568
42228
  }
@@ -41570,7 +42230,7 @@ function ensureTuiPluginEntry(options = {}) {
41570
42230
  try {
41571
42231
  const configPath = resolveTuiConfigPath(options.configDir);
41572
42232
  let config2 = {};
41573
- if (existsSync24(configPath)) {
42233
+ if (existsSync25(configPath)) {
41574
42234
  const raw = readFileSync16(configPath, "utf-8");
41575
42235
  config2 = import_comment_json9.parse(raw) ?? {};
41576
42236
  }
@@ -41605,7 +42265,7 @@ function ensureTuiPluginEntry(options = {}) {
41605
42265
  }
41606
42266
  }
41607
42267
  config2.plugin = plugins;
41608
- mkdirSync9(dirname13(configPath), { recursive: true });
42268
+ mkdirSync10(dirname14(configPath), { recursive: true });
41609
42269
  writeTuiConfigAtomic(configPath, config2);
41610
42270
  log3(`[magic-context] updated TUI plugin entry in ${configPath}`);
41611
42271
  return true;
@@ -41623,7 +42283,7 @@ var init_tui_config = __esm(() => {
41623
42283
  });
41624
42284
 
41625
42285
  // src/lib/diagnostics-opencode.ts
41626
- import { existsSync as existsSync25, readdirSync as readdirSync3, readFileSync as readFileSync17, statSync as statSync10 } from "node:fs";
42286
+ import { existsSync as existsSync26, readdirSync as readdirSync3, readFileSync as readFileSync17, statSync as statSync10 } from "node:fs";
41627
42287
  import { createRequire as createRequire3 } from "node:module";
41628
42288
  import { homedir as homedir15 } from "node:os";
41629
42289
  import { join as join22 } from "node:path";
@@ -41644,7 +42304,7 @@ function getPluginCacheInfo() {
41644
42304
  let cached2;
41645
42305
  for (const installedPkgPath of getOpenCodePluginPackageJsonPaths()) {
41646
42306
  try {
41647
- if (existsSync25(installedPkgPath)) {
42307
+ if (existsSync26(installedPkgPath)) {
41648
42308
  const pkg = JSON.parse(readFileSync17(installedPkgPath, "utf-8"));
41649
42309
  cached2 = typeof pkg.version === "string" ? pkg.version : undefined;
41650
42310
  if (cached2)
@@ -41662,7 +42322,7 @@ function getStorageDir() {
41662
42322
  }
41663
42323
  function fileSize(path6) {
41664
42324
  try {
41665
- return existsSync25(path6) ? statSync10(path6).size : 0;
42325
+ return existsSync26(path6) ? statSync10(path6).size : 0;
41666
42326
  } catch {
41667
42327
  return 0;
41668
42328
  }
@@ -41674,7 +42334,7 @@ function sanitizeValue(value) {
41674
42334
  return sanitizeConfigValue(value);
41675
42335
  }
41676
42336
  function readConfig3(path6) {
41677
- if (!existsSync25(path6))
42337
+ if (!existsSync26(path6))
41678
42338
  return { value: null };
41679
42339
  try {
41680
42340
  const raw = readFileSync17(path6, "utf-8");
@@ -41735,7 +42395,7 @@ function parseHistorianDumpMeta(path6) {
41735
42395
  }
41736
42396
  }
41737
42397
  function listDumpsInDir(dir, limit) {
41738
- if (!existsSync25(dir))
42398
+ if (!existsSync26(dir))
41739
42399
  return { count: 0, recent: [] };
41740
42400
  try {
41741
42401
  const entries = readdirSync3(dir).filter((name) => name.endsWith(".xml")).map((name) => {
@@ -41805,7 +42465,7 @@ function collectHistorianDumps(recentSessions) {
41805
42465
  async function collectRecentSessions() {
41806
42466
  const dataHome = process.env.XDG_DATA_HOME || join22(process.env.HOME || homedir15(), ".local", "share");
41807
42467
  const opencodeDbPath = join22(dataHome, "opencode", "opencode.db");
41808
- if (!existsSync25(opencodeDbPath))
42468
+ if (!existsSync26(opencodeDbPath))
41809
42469
  return [];
41810
42470
  if (typeof globalThis.Bun === "undefined") {
41811
42471
  return [];
@@ -41840,7 +42500,7 @@ async function collectRecentSessions() {
41840
42500
  }
41841
42501
  async function collectHistorianFailures(storageDirPath) {
41842
42502
  const contextDbPath = join22(storageDirPath, "context.db");
41843
- if (!existsSync25(contextDbPath))
42503
+ if (!existsSync26(contextDbPath))
41844
42504
  return [];
41845
42505
  if (typeof globalThis.Bun === "undefined") {
41846
42506
  return [];
@@ -41874,7 +42534,7 @@ async function collectHistorianFailures(storageDirPath) {
41874
42534
  }
41875
42535
  async function collectHistorianRuns(storageDirPath) {
41876
42536
  const contextDbPath = join22(storageDirPath, "context.db");
41877
- if (!existsSync25(contextDbPath))
42537
+ if (!existsSync26(contextDbPath))
41878
42538
  return [];
41879
42539
  if (typeof globalThis.Bun === "undefined")
41880
42540
  return [];
@@ -41945,7 +42605,7 @@ async function collectDiagnostics() {
41945
42605
  const storageDirPath = getStorageDir();
41946
42606
  const contextDbPath = join22(storageDirPath, "context.db");
41947
42607
  const logPath = getMagicContextLogPath2("opencode");
41948
- const logFileSize = existsSync25(logPath) ? statSync10(logPath).size : 0;
42608
+ const logFileSize = existsSync26(logPath) ? statSync10(logPath).size : 0;
41949
42609
  let compactionEnabled = false;
41950
42610
  try {
41951
42611
  compactionEnabled = isCompactionEnabled(loadPluginConfig(process.cwd()));
@@ -41973,14 +42633,14 @@ async function collectDiagnostics() {
41973
42633
  opencodeConfigHasPlugin: configHasPluginEntry(opencodeConfig.value),
41974
42634
  tuiConfigHasPlugin: configHasPluginEntry(tuiConfig.value),
41975
42635
  magicContextConfig: {
41976
- exists: existsSync25(configPaths.magicContextConfig),
42636
+ exists: existsSync26(configPaths.magicContextConfig),
41977
42637
  ...magicContextConfig.error ? { parseError: magicContextConfig.error } : {},
41978
42638
  flags: sanitizeValue(magicContextConfig.value ?? {}) ?? {}
41979
42639
  },
41980
42640
  pluginCache: getPluginCacheInfo(),
41981
42641
  storageDir: {
41982
42642
  path: storageDirPath,
41983
- exists: existsSync25(storageDirPath),
42643
+ exists: existsSync26(storageDirPath),
41984
42644
  contextDbSizeBytes: fileSize(contextDbPath)
41985
42645
  },
41986
42646
  conflicts: {
@@ -41991,7 +42651,7 @@ async function collectDiagnostics() {
41991
42651
  },
41992
42652
  logFile: {
41993
42653
  path: logPath,
41994
- exists: existsSync25(logPath),
42654
+ exists: existsSync26(logPath),
41995
42655
  sizeKb: Math.round(logFileSize / 1024)
41996
42656
  },
41997
42657
  recentSessions,
@@ -42144,9 +42804,9 @@ var init_diagnostics_opencode = __esm(() => {
42144
42804
 
42145
42805
  // src/lib/embedding-runtime.ts
42146
42806
  import { spawnSync as spawnSync5 } from "node:child_process";
42147
- import { existsSync as existsSync26 } from "node:fs";
42807
+ import { existsSync as existsSync27 } from "node:fs";
42148
42808
  import { createRequire as createRequire4 } from "node:module";
42149
- import { dirname as dirname14, join as join23, sep } from "node:path";
42809
+ import { dirname as dirname15, join as join23, sep } from "node:path";
42150
42810
  function describeError(error51) {
42151
42811
  const message = error51 instanceof Error ? error51.message : String(error51 ?? "unknown error");
42152
42812
  const code = error51?.code;
@@ -42259,7 +42919,7 @@ function expectedBinaryRelPath(platform, arch) {
42259
42919
  }
42260
42920
  function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform, arch = process.arch) {
42261
42921
  const packageDir = join23(installRoot, "node_modules", "onnxruntime-node");
42262
- if (!existsSync26(join23(packageDir, "package.json"))) {
42922
+ if (!existsSync27(join23(packageDir, "package.json"))) {
42263
42923
  return { state: "package-missing", packageDir };
42264
42924
  }
42265
42925
  const rel = expectedBinaryRelPath(platform, arch);
@@ -42267,13 +42927,13 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
42267
42927
  return probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath: packageDir };
42268
42928
  }
42269
42929
  const binaryPath = join23(packageDir, rel);
42270
- if (!existsSync26(binaryPath)) {
42930
+ if (!existsSync27(binaryPath)) {
42271
42931
  return { state: "binary-missing", packageDir, expectedBinary: binaryPath };
42272
42932
  }
42273
42933
  return probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath };
42274
42934
  }
42275
42935
  function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, arch = process.arch) {
42276
- const existing = installRoots.filter((root) => existsSync26(root));
42936
+ const existing = installRoots.filter((root) => existsSync27(root));
42277
42937
  if (existing.length === 0) {
42278
42938
  return {
42279
42939
  state: "unknown",
@@ -42293,10 +42953,10 @@ function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, a
42293
42953
  function packageDirFromResolved(resolvedPath, packageName) {
42294
42954
  const marker = `node_modules${sep}${packageName.split("/").join(sep)}`;
42295
42955
  const idx = resolvedPath.indexOf(marker);
42296
- return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) : dirname14(resolvedPath);
42956
+ return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) : dirname15(resolvedPath);
42297
42957
  }
42298
42958
  function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.platform, arch = process.arch) {
42299
- if (!existsSync26(join23(pluginDir, "package.json"))) {
42959
+ if (!existsSync27(join23(pluginDir, "package.json"))) {
42300
42960
  return { state: "unknown", reason: "plugin package dir not found" };
42301
42961
  }
42302
42962
  let onnxDir = null;
@@ -42332,7 +42992,7 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
42332
42992
  return probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath: onnxDir };
42333
42993
  }
42334
42994
  const binaryPath = join23(onnxDir, rel);
42335
- if (!existsSync26(binaryPath)) {
42995
+ if (!existsSync27(binaryPath)) {
42336
42996
  return { state: "binary-missing", packageDir: onnxDir, expectedBinary: binaryPath };
42337
42997
  }
42338
42998
  return probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath };
@@ -42818,25 +43478,391 @@ function migrateExperimentalPinKeyFilesForDoctor(mcConfig) {
42818
43478
  return true;
42819
43479
  }
42820
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
+
42821
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
+ }
42822
43850
  function formatFailClosedBlockingProcesses(processes) {
42823
43851
  const uniqueProcesses = new Map;
42824
43852
  for (const process3 of processes) {
42825
- if (!process3.harness.trim() || !Number.isInteger(process3.pid) || process3.pid <= 0)
43853
+ if (!Number.isInteger(process3.pid) || process3.pid <= 0)
42826
43854
  continue;
42827
- uniqueProcesses.set(`${process3.harness}\x00${process3.pid}`, {
42828
- harness: process3.harness.trim(),
42829
- pid: process3.pid
42830
- });
43855
+ const kind = normalizeFailClosedProcessKind(process3);
43856
+ uniqueProcesses.set(`${kind}\x00${process3.pid}`, { kind, pid: process3.pid });
42831
43857
  }
42832
43858
  const entries = [...uniqueProcesses.values()];
42833
43859
  const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
42834
- const rendered = visible.map(({ harness, pid }) => `${harness} (PID ${pid})`);
43860
+ const rendered = visible.map(({ kind, pid }) => `${kind} (PID ${pid})`);
42835
43861
  const omitted = entries.length - visible.length;
42836
43862
  if (omitted > 0)
42837
43863
  rendered.push(`${omitted} more blocking process(es)`);
42838
43864
  if (rendered.length === 0)
42839
- return "a live harness process";
43865
+ return "a live process";
42840
43866
  if (rendered.length === 1)
42841
43867
  return rendered[0];
42842
43868
  const last = rendered.pop();
@@ -42846,9 +43872,9 @@ function formatFailClosedBlockingMessage(reason) {
42846
43872
  if (reason.kind === "migration_guard") {
42847
43873
  if (reason.unreadableFile) {
42848
43874
  const arm = reason.unreadableArm ?? "io";
42849
- 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.`;
42850
43876
  return [
42851
- `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.`,
42852
43878
  recovery,
42853
43879
  `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
42854
43880
  ].join(" ");
@@ -42927,13 +43953,13 @@ var init_storage_versions = __esm(async () => {
42927
43953
  });
42928
43954
 
42929
43955
  // src/commands/doctor-opencode-cache.ts
42930
- import { existsSync as existsSync27, readFileSync as readFileSync19, rmSync as rmSync3 } from "node:fs";
43956
+ import { existsSync as existsSync30, readFileSync as readFileSync21, rmSync as rmSync3 } from "node:fs";
42931
43957
  function readCachedPluginVersion(pluginCacheDir) {
42932
43958
  try {
42933
43959
  const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
42934
- if (!existsSync27(installedPkgPath))
43960
+ if (!existsSync30(installedPkgPath))
42935
43961
  return;
42936
- const pkg = JSON.parse(readFileSync19(installedPkgPath, "utf-8"));
43962
+ const pkg = JSON.parse(readFileSync21(installedPkgPath, "utf-8"));
42937
43963
  return typeof pkg.version === "string" ? pkg.version : undefined;
42938
43964
  } catch {
42939
43965
  return;
@@ -42942,7 +43968,7 @@ function readCachedPluginVersion(pluginCacheDir) {
42942
43968
  async function clearPluginCache(options = {}, deps = {}) {
42943
43969
  const remove = deps.remove ?? ((path6) => rmSync3(path6, { recursive: true, force: true }));
42944
43970
  const pluginCacheRoots = getOpenCodePluginCacheRoots();
42945
- const existingRoots = pluginCacheRoots.filter((root) => existsSync27(root));
43971
+ const existingRoots = pluginCacheRoots.filter((root) => existsSync30(root));
42946
43972
  if (existingRoots.length === 0) {
42947
43973
  return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
42948
43974
  }
@@ -43010,10 +44036,10 @@ var init_doctor_opencode_cache = __esm(() => {
43010
44036
 
43011
44037
  // src/commands/doctor-opencode.ts
43012
44038
  import { execSync as execSync2, spawnSync as spawnSync6 } from "node:child_process";
43013
- import { existsSync as existsSync28, readFileSync as readFileSync20, statSync as statSync11 } from "node:fs";
44039
+ import { existsSync as existsSync31, readFileSync as readFileSync22, statSync as statSync12 } from "node:fs";
43014
44040
  import { createRequire as createRequire5 } from "node:module";
43015
- import { homedir as homedir16 } from "node:os";
43016
- import { join as join25 } from "node:path";
44041
+ import { homedir as homedir17 } from "node:os";
44042
+ import { join as join28 } from "node:path";
43017
44043
  function resolveCompactionEnabledForDoctor() {
43018
44044
  try {
43019
44045
  const config2 = loadPluginConfig(process.cwd());
@@ -43112,15 +44138,15 @@ function getUserNpmrcPath() {
43112
44138
  if (custom2)
43113
44139
  return custom2;
43114
44140
  const home = process.env.HOME?.trim();
43115
- return join25(home || homedir16(), ".npmrc");
44141
+ return join28(home || homedir17(), ".npmrc");
43116
44142
  }
43117
44143
  function collectNpmReleaseAgeWarnings() {
43118
44144
  const ageWarnings = [];
43119
44145
  const npmrcPath = getUserNpmrcPath();
43120
- if (!existsSync28(npmrcPath))
44146
+ if (!existsSync31(npmrcPath))
43121
44147
  return ageWarnings;
43122
44148
  try {
43123
- const npmrc = readFileSync20(npmrcPath, "utf-8");
44149
+ const npmrc = readFileSync22(npmrcPath, "utf-8");
43124
44150
  for (const line of npmrc.split(`
43125
44151
  `)) {
43126
44152
  const trimmed = line.trim();
@@ -43259,12 +44285,12 @@ function checkLocalEmbeddingRuntimeForDoctor() {
43259
44285
  return { issues: 0 };
43260
44286
  }
43261
44287
  async function checkEmbeddingConfig(magicContextConfigPath) {
43262
- if (!existsSync28(magicContextConfigPath)) {
44288
+ if (!existsSync31(magicContextConfigPath)) {
43263
44289
  return checkLocalEmbeddingRuntimeForDoctor();
43264
44290
  }
43265
44291
  let rawText;
43266
44292
  try {
43267
- rawText = readFileSync20(magicContextConfigPath, "utf-8");
44293
+ rawText = readFileSync22(magicContextConfigPath, "utf-8");
43268
44294
  } catch {
43269
44295
  log2.warn("Could not read magic-context.jsonc for embedding check");
43270
44296
  return { issues: 1 };
@@ -43275,7 +44301,7 @@ async function checkEmbeddingConfig(magicContextConfigPath) {
43275
44301
  });
43276
44302
  let parsedConfig;
43277
44303
  try {
43278
- parsedConfig = import_comment_json11.parse(substituted.text);
44304
+ parsedConfig = import_comment_json12.parse(substituted.text);
43279
44305
  } catch (error51) {
43280
44306
  log2.warn(`Embedding check skipped — could not parse magic-context.jsonc: ${error51 instanceof Error ? error51.message : String(error51)}`);
43281
44307
  return { issues: 1 };
@@ -43387,7 +44413,7 @@ async function runDoctor2(options = {}) {
43387
44413
  const v22Result = await runV22BackfillCommands({
43388
44414
  name: "OpenCode",
43389
44415
  openDatabase: (readonly2 = true) => {
43390
- const dbPath2 = join25(getMagicContextStorageDir(), "context.db");
44416
+ const dbPath2 = join28(getMagicContextStorageDir(), "context.db");
43391
44417
  v22Db = readonly2 ? openExistingContextDatabase(dbPath2, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath2);
43392
44418
  return v22Db;
43393
44419
  },
@@ -43410,7 +44436,7 @@ async function runDoctor2(options = {}) {
43410
44436
  log2.success(msg);
43411
44437
  passCount++;
43412
44438
  };
43413
- const warn = (msg) => {
44439
+ const warn2 = (msg) => {
43414
44440
  log2.warn(msg);
43415
44441
  warnCount++;
43416
44442
  };
@@ -43419,17 +44445,17 @@ async function runDoctor2(options = {}) {
43419
44445
  failCount++;
43420
44446
  issues++;
43421
44447
  };
43422
- const authorityDbPath = join25(getMagicContextStorageDir(), "context.db");
44448
+ const authorityDbPath = join28(getMagicContextStorageDir(), "context.db");
43423
44449
  let authorityDb = null;
43424
44450
  try {
43425
44451
  authorityDb = openExistingContextDatabase(authorityDbPath, { readonly: true });
43426
44452
  if (authorityDb) {
43427
- await reportAuthorityMarkers({ db: authorityDb, info: log2.info, warn });
44453
+ await reportAuthorityMarkers({ db: authorityDb, info: log2.info, warn: warn2 });
43428
44454
  } else {
43429
44455
  log2.info("Authority: no context database found");
43430
44456
  }
43431
44457
  } catch (error51) {
43432
- warn(`Authority check unavailable: ${error51 instanceof Error ? error51.message : String(error51)}`);
44458
+ warn2(`Authority check unavailable: ${error51 instanceof Error ? error51.message : String(error51)}`);
43433
44459
  } finally {
43434
44460
  authorityDb?.close();
43435
44461
  }
@@ -43460,7 +44486,7 @@ async function runDoctor2(options = {}) {
43460
44486
  if (!npmLatest) {
43461
44487
  log2.info(`Magic Context CLI v${selfVersion2}; npm latest check unavailable`);
43462
44488
  } else if (compareVersions(selfVersion2, npmLatest) < 0) {
43463
- 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}`);
43464
44490
  } else {
43465
44491
  pass(`Magic Context CLI v${selfVersion2} is current (npm latest v${npmLatest})`);
43466
44492
  }
@@ -43470,15 +44496,15 @@ async function runDoctor2(options = {}) {
43470
44496
  } else {
43471
44497
  pass(`OpenCode config: ${paths.opencodeConfig}`);
43472
44498
  }
43473
- if (existsSync28(paths.magicContextConfig)) {
44499
+ if (existsSync31(paths.magicContextConfig)) {
43474
44500
  pass(`Magic Context config: ${paths.magicContextConfig}`);
43475
44501
  try {
43476
- const raw = readFileSync20(paths.magicContextConfig, "utf-8");
44502
+ const raw = readFileSync22(paths.magicContextConfig, "utf-8");
43477
44503
  const substituted = substituteConfigVariables({
43478
44504
  text: raw,
43479
44505
  configPath: paths.magicContextConfig
43480
44506
  }).text;
43481
- import_comment_json11.parse(substituted);
44507
+ import_comment_json12.parse(substituted);
43482
44508
  pass("magic-context.jsonc parses as valid JSONC");
43483
44509
  } catch (err) {
43484
44510
  fail(`magic-context.jsonc parse failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -43487,7 +44513,7 @@ async function runDoctor2(options = {}) {
43487
44513
  const result = loadPluginConfig(process.cwd());
43488
44514
  const warnings = result.configWarnings ?? [];
43489
44515
  if (warnings.length > 0) {
43490
- 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`);
43491
44517
  } else {
43492
44518
  pass("Magic Context config loads successfully");
43493
44519
  }
@@ -43495,13 +44521,13 @@ async function runDoctor2(options = {}) {
43495
44521
  fail(`Could not load Magic Context config: ${err instanceof Error ? err.message : String(err)}`);
43496
44522
  }
43497
44523
  } else {
43498
- warn(`No magic-context.jsonc found — using defaults`);
44524
+ warn2(`No magic-context.jsonc found — using defaults`);
43499
44525
  log2.info(" Run 'setup' to create one with model recommendations");
43500
44526
  }
43501
- if (existsSync28(paths.magicContextConfig)) {
44527
+ if (existsSync31(paths.magicContextConfig)) {
43502
44528
  try {
43503
- const mcRaw = readFileSync20(paths.magicContextConfig, "utf-8");
43504
- const mcConfig = import_comment_json11.parse(mcRaw);
44529
+ const mcRaw = readFileSync22(paths.magicContextConfig, "utf-8");
44530
+ const mcConfig = import_comment_json12.parse(mcRaw);
43505
44531
  let mcChanged = false;
43506
44532
  const experimental = mcConfig.experimental;
43507
44533
  if (experimental && "compaction_markers" in experimental) {
@@ -43609,7 +44635,7 @@ async function runDoctor2(options = {}) {
43609
44635
  fixed++;
43610
44636
  }
43611
44637
  if (mcChanged) {
43612
- writeFileAtomic(paths.magicContextConfig, `${import_comment_json11.stringify(mcConfig, null, 2)}
44638
+ writeFileAtomic(paths.magicContextConfig, `${import_comment_json12.stringify(mcConfig, null, 2)}
43613
44639
  `);
43614
44640
  }
43615
44641
  } catch {
@@ -43618,12 +44644,12 @@ async function runDoctor2(options = {}) {
43618
44644
  }
43619
44645
  if (paths.opencodeConfigFormat !== "none") {
43620
44646
  try {
43621
- const raw = readFileSync20(paths.opencodeConfig, "utf-8");
43622
- const config2 = import_comment_json11.parse(raw);
44647
+ const raw = readFileSync22(paths.opencodeConfig, "utf-8");
44648
+ const config2 = import_comment_json12.parse(raw);
43623
44649
  const rawPlugins = Array.isArray(config2?.plugin) ? config2.plugin : [];
43624
44650
  const existingIdx = rawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
43625
44651
  if (rawPlugins.some((entry) => isLocalPathPluginEntry(entry) && String(entry).includes("magic-context") && !isDevPathPluginEntry(entry))) {
43626
- 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");
43627
44653
  }
43628
44654
  const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
43629
44655
  const entryAsString = (entry) => {
@@ -43643,7 +44669,7 @@ async function runDoctor2(options = {}) {
43643
44669
  } else {
43644
44670
  const isPinned = isPinnedOpenCodePluginSpecifier(oldEntryStr);
43645
44671
  if (isPinned && !options.force) {
43646
- 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`);
43647
44673
  } else {
43648
44674
  if (Array.isArray(oldEntry) && oldEntry.length >= 1) {
43649
44675
  const replacement = [...oldEntry];
@@ -43653,7 +44679,7 @@ async function runDoctor2(options = {}) {
43653
44679
  rawPlugins[existingIdx] = OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
43654
44680
  }
43655
44681
  config2.plugin = rawPlugins;
43656
- writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config2, null, 2)}
44682
+ writeFileAtomic(paths.opencodeConfig, `${import_comment_json12.stringify(config2, null, 2)}
43657
44683
  `);
43658
44684
  pass(`Upgraded plugin entry in ${configName}: ${oldEntryStr} → ${OPENCODE_PLUGIN_ENTRY_WITH_VERSION}`);
43659
44685
  fixed++;
@@ -43662,18 +44688,19 @@ async function runDoctor2(options = {}) {
43662
44688
  } else {
43663
44689
  rawPlugins.push(OPENCODE_PLUGIN_ENTRY_WITH_VERSION);
43664
44690
  config2.plugin = rawPlugins;
43665
- writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config2, null, 2)}
44691
+ writeFileAtomic(paths.opencodeConfig, `${import_comment_json12.stringify(config2, null, 2)}
43666
44692
  `);
43667
44693
  pass(`Added plugin to ${configName}`);
43668
44694
  fixed++;
43669
44695
  }
43670
44696
  } catch {
43671
- warn("Could not parse opencode config to verify plugin entry");
44697
+ warn2("Could not parse opencode config to verify plugin entry");
43672
44698
  }
43673
44699
  }
43674
44700
  const cwd = process.cwd();
43675
44701
  const compactionEnabled = resolveCompactionEnabledForDoctor();
43676
44702
  const conflictResult = detectConflicts(cwd, { compactionEnabled });
44703
+ log2.info("Compaction check: file-based; the running server's resolved config may differ — `opencode debug config` is authoritative");
43677
44704
  if (conflictResult.hasConflict) {
43678
44705
  for (const reason of conflictResult.reasons) {
43679
44706
  fail(`Conflict: ${reason}`);
@@ -43684,14 +44711,14 @@ async function runDoctor2(options = {}) {
43684
44711
  fixed++;
43685
44712
  }
43686
44713
  if (actions.length > 0) {
43687
- warn("Restart OpenCode for conflict fixes to take effect");
44714
+ warn2("Restart OpenCode for conflict fixes to take effect");
43688
44715
  }
43689
44716
  } else {
43690
44717
  if (!compactionEnabled) {
43691
44718
  if (conflictResult.nativeCompaction.auto || conflictResult.nativeCompaction.prune) {
43692
44719
  pass("No conflicts detected (compaction, DCP, OMO hooks) — native compaction active (compaction-off mode)");
43693
44720
  } else {
43694
- 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");
43695
44722
  }
43696
44723
  } else {
43697
44724
  pass("No conflicts detected (compaction, DCP, OMO hooks)");
@@ -43700,16 +44727,16 @@ async function runDoctor2(options = {}) {
43700
44727
  const tuiAdded = ensureTuiPluginEntry();
43701
44728
  if (tuiAdded) {
43702
44729
  pass("Added TUI sidebar plugin to tui.json");
43703
- warn("Restart OpenCode to see the sidebar");
44730
+ warn2("Restart OpenCode to see the sidebar");
43704
44731
  fixed++;
43705
- } else if (existsSync28(paths.tuiConfig)) {
44732
+ } else if (existsSync31(paths.tuiConfig)) {
43706
44733
  try {
43707
- const tuiRaw = readFileSync20(paths.tuiConfig, "utf-8");
43708
- const tuiConfig = import_comment_json11.parse(tuiRaw);
44734
+ const tuiRaw = readFileSync22(paths.tuiConfig, "utf-8");
44735
+ const tuiConfig = import_comment_json12.parse(tuiRaw);
43709
44736
  const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
43710
44737
  const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
43711
44738
  if (tuiRawPlugins.some((entry) => isLocalPathPluginEntry(entry) && String(entry).includes("magic-context") && !isDevPathPluginEntry(entry))) {
43712
- 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");
43713
44740
  }
43714
44741
  const tuiEntryAsString = (entry) => {
43715
44742
  if (typeof entry === "string")
@@ -43726,7 +44753,7 @@ async function runDoctor2(options = {}) {
43726
44753
  } else {
43727
44754
  const tuiPinned = isPinnedOpenCodePluginSpecifier(tuiEntryStr);
43728
44755
  if (tuiPinned && !options.force) {
43729
- warn(`TUI plugin pinned to ${tuiEntryStr} — use 'doctor --force' to upgrade`);
44756
+ warn2(`TUI plugin pinned to ${tuiEntryStr} — use 'doctor --force' to upgrade`);
43730
44757
  } else if (tuiPinned && options.force) {
43731
44758
  if (Array.isArray(tuiEntry) && tuiEntry.length >= 1) {
43732
44759
  const replacement = [...tuiEntry];
@@ -43736,7 +44763,7 @@ async function runDoctor2(options = {}) {
43736
44763
  tuiRawPlugins[tuiIdx] = OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
43737
44764
  }
43738
44765
  tuiConfig.plugin = tuiRawPlugins;
43739
- writeFileAtomic(paths.tuiConfig, `${import_comment_json11.stringify(tuiConfig, null, 2)}
44766
+ writeFileAtomic(paths.tuiConfig, `${import_comment_json12.stringify(tuiConfig, null, 2)}
43740
44767
  `);
43741
44768
  pass(`Upgraded TUI plugin: ${tuiEntryStr} → ${OPENCODE_PLUGIN_ENTRY_WITH_VERSION}`);
43742
44769
  fixed++;
@@ -43753,10 +44780,10 @@ async function runDoctor2(options = {}) {
43753
44780
  } else {
43754
44781
  fail("Could not create or verify the TUI sidebar config");
43755
44782
  }
43756
- if (existsSync28(paths.magicContextConfig)) {
44783
+ if (existsSync31(paths.magicContextConfig)) {
43757
44784
  try {
43758
- const mcRaw = readFileSync20(paths.magicContextConfig, "utf-8");
43759
- const mcConfig = import_comment_json11.parse(mcRaw);
44785
+ const mcRaw = readFileSync22(paths.magicContextConfig, "utf-8");
44786
+ const mcConfig = import_comment_json12.parse(mcRaw);
43760
44787
  const warning = checkUserMemoriesDreamerCompatibility(mcConfig);
43761
44788
  if (warning) {
43762
44789
  log2.warn(warning);
@@ -43772,8 +44799,8 @@ async function runDoctor2(options = {}) {
43772
44799
  warnCount++;
43773
44800
  else
43774
44801
  passCount++;
43775
- const dbPath = join25(getMagicContextStorageDir(), "context.db");
43776
- if (!existsSync28(dbPath)) {
44802
+ const dbPath = join28(getMagicContextStorageDir(), "context.db");
44803
+ if (!existsSync31(dbPath)) {
43777
44804
  log2.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
43778
44805
  } else {
43779
44806
  log2.info(`Shared context DB exists at ${dbPath}`);
@@ -43786,6 +44813,21 @@ async function runDoctor2(options = {}) {
43786
44813
  pass("Opened the shared DB with a supported schema");
43787
44814
  const storageVersions = readStorageVersions(db);
43788
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
+ }
43789
44831
  const fenceCheck = checkStorageVersionFence(storageVersions, {
43790
44832
  blockingProcesses: getLiveMigrationBlockingProcesses(getMagicContextStorageDir())
43791
44833
  });
@@ -43852,9 +44894,9 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
43852
44894
  } else if (cacheResult.action === "up_to_date") {
43853
44895
  pass(`Plugin cache up to date (v${cacheResult.cached})`);
43854
44896
  } else if (cacheResult.action === "check_unavailable") {
43855
- 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.`);
43856
44898
  } else if (cacheResult.action === "error") {
43857
- warn(`Could not clear plugin cache: ${cacheResult.error}`);
44899
+ warn2(`Could not clear plugin cache: ${cacheResult.error}`);
43858
44900
  if (cacheResult.clearedPaths && cacheResult.clearedPaths.length > 0) {
43859
44901
  log2.info(` Cleared roots: ${cacheResult.clearedPaths.join(", ")}`);
43860
44902
  }
@@ -43880,8 +44922,8 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
43880
44922
  }
43881
44923
  }
43882
44924
  const logPath = getMagicContextLogPath2("opencode");
43883
- if (existsSync28(logPath)) {
43884
- const logStat = statSync11(logPath);
44925
+ if (existsSync31(logPath)) {
44926
+ const logStat = statSync12(logPath);
43885
44927
  const sizeKb = (logStat.size / 1024).toFixed(0);
43886
44928
  log2.info(`Log file: ${logPath} (${sizeKb} KB)`);
43887
44929
  } else {
@@ -43892,7 +44934,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
43892
44934
  if (dumpBuckets.length > 0) {
43893
44935
  const totalCount = dumpBuckets.reduce((sum, b2) => sum + b2.count, 0);
43894
44936
  const sessionCount = dumpBuckets.length;
43895
- warn(`Historian debug dumps: ${totalCount} file(s) across ${sessionCount} project(s)`);
44937
+ warn2(`Historian debug dumps: ${totalCount} file(s) across ${sessionCount} project(s)`);
43896
44938
  for (const bucket of dumpBuckets) {
43897
44939
  log2.info(` [${bucket.directory}] ${bucket.count} file(s)`);
43898
44940
  for (const dump of bucket.recent.slice(0, 3)) {
@@ -43926,7 +44968,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
43926
44968
  }
43927
44969
  return 0;
43928
44970
  }
43929
- var import_comment_json11, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
44971
+ var import_comment_json12, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
43930
44972
  var init_doctor_opencode = __esm(async () => {
43931
44973
  init_config();
43932
44974
  init_agent_disable();
@@ -43945,6 +44987,7 @@ var init_doctor_opencode = __esm(async () => {
43945
44987
  init_opencode_detect();
43946
44988
  init_opencode_helpers();
43947
44989
  init_opencode_plugin_cache();
44990
+ init_opencode_plugin_schema_fence();
43948
44991
  init_paths();
43949
44992
  init_prompts();
43950
44993
  init_redaction2();
@@ -43956,15 +44999,15 @@ var init_doctor_opencode = __esm(async () => {
43956
44999
  init_v22_backfill_commands(),
43957
45000
  init_doctor_authority()
43958
45001
  ]);
43959
- import_comment_json11 = __toESM(require_src3(), 1);
45002
+ import_comment_json12 = __toESM(require_src3(), 1);
43960
45003
  });
43961
45004
 
43962
45005
  // src/lib/diagnostics-pi.ts
43963
- import { createHash as createHash4 } from "node:crypto";
43964
- import { existsSync as existsSync29, readdirSync as readdirSync4, readFileSync as readFileSync21, statSync as statSync12 } from "node:fs";
45006
+ import { createHash as createHash5 } from "node:crypto";
45007
+ import { existsSync as existsSync32, readdirSync as readdirSync5, readFileSync as readFileSync23, statSync as statSync13 } from "node:fs";
43965
45008
  import { createRequire as createRequire6 } from "node:module";
43966
- import { homedir as homedir17, userInfo as userInfo2 } from "node:os";
43967
- 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";
43968
45011
  function getSelfVersion3() {
43969
45012
  const req = createRequire6(import.meta.url);
43970
45013
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -43979,7 +45022,7 @@ function getSelfVersion3() {
43979
45022
  }
43980
45023
  function fileSize2(path6) {
43981
45024
  try {
43982
- return existsSync29(path6) ? statSync12(path6).size : 0;
45025
+ return existsSync32(path6) ? statSync13(path6).size : 0;
43983
45026
  } catch {
43984
45027
  return 0;
43985
45028
  }
@@ -43989,13 +45032,13 @@ function escapeRegex3(value) {
43989
45032
  }
43990
45033
  function currentUserHash() {
43991
45034
  const username = userInfo2().username || "unknown";
43992
- return createHash4("sha256").update(username).digest("hex").slice(0, 12);
45035
+ return createHash5("sha256").update(username).digest("hex").slice(0, 12);
43993
45036
  }
43994
45037
  function redactSecretString(value) {
43995
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>");
43996
45039
  }
43997
45040
  function sanitizeString2(value) {
43998
- const home = process.env.HOME || homedir17();
45041
+ const home = process.env.HOME || homedir18();
43999
45042
  const username = userInfo2().username;
44000
45043
  const userHash = `<USER:${currentUserHash()}>`;
44001
45044
  let sanitized = redactSecretString(value);
@@ -44031,11 +45074,11 @@ function sanitizeValue2(value, key = "") {
44031
45074
  return value;
44032
45075
  }
44033
45076
  function readJsonc(path6) {
44034
- if (!existsSync29(path6))
45077
+ if (!existsSync32(path6))
44035
45078
  return { value: {} };
44036
45079
  try {
44037
45080
  return {
44038
- value: import_comment_json12.parse(readFileSync21(path6, "utf-8"))
45081
+ value: import_comment_json13.parse(readFileSync23(path6, "utf-8"))
44039
45082
  };
44040
45083
  } catch (error51) {
44041
45084
  return {
@@ -44051,7 +45094,7 @@ function readConfigDiagnostic(path6) {
44051
45094
  const parsed = readJsonc(path6);
44052
45095
  return {
44053
45096
  path: path6,
44054
- exists: existsSync29(path6),
45097
+ exists: existsSync32(path6),
44055
45098
  ...parsed.parseError ? { parseError: parsed.parseError } : {},
44056
45099
  flags: sanitizeValue2(parsed.value)
44057
45100
  };
@@ -44069,25 +45112,25 @@ function reverseSlugToDirectory(slug) {
44069
45112
  }
44070
45113
  function collectPiRecentSessions() {
44071
45114
  const sessionsRoot = getPiSessionsRoot();
44072
- if (!existsSync29(sessionsRoot))
45115
+ if (!existsSync32(sessionsRoot))
44073
45116
  return [];
44074
45117
  try {
44075
- 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);
44076
45119
  const candidates = [];
44077
45120
  for (const slug of slugs) {
44078
45121
  const directory = reverseSlugToDirectory(slug);
44079
45122
  if (!directory)
44080
45123
  continue;
44081
- const slugDir = join26(sessionsRoot, slug);
45124
+ const slugDir = join29(sessionsRoot, slug);
44082
45125
  let files;
44083
45126
  try {
44084
- files = readdirSync4(slugDir).filter((name) => name.endsWith(".jsonl"));
45127
+ files = readdirSync5(slugDir).filter((name) => name.endsWith(".jsonl"));
44085
45128
  } catch {
44086
45129
  continue;
44087
45130
  }
44088
45131
  for (const file2 of files) {
44089
45132
  try {
44090
- const mtime = statSync12(join26(slugDir, file2)).mtimeMs;
45133
+ const mtime = statSync13(join29(slugDir, file2)).mtimeMs;
44091
45134
  const sessionId = file2.replace(/\.jsonl$/, "");
44092
45135
  candidates.push({ sessionId, directory, mtime });
44093
45136
  } catch {}
@@ -44105,7 +45148,7 @@ function collectPiRecentSessions() {
44105
45148
  }
44106
45149
  function parseHistorianDumpMeta2(path6) {
44107
45150
  try {
44108
- const xml = readFileSync21(path6, "utf-8");
45151
+ const xml = readFileSync23(path6, "utf-8");
44109
45152
  const parsed = parseCompartmentOutput(xml);
44110
45153
  const factCountByCategory = {};
44111
45154
  for (const fact of parsed.facts) {
@@ -44138,11 +45181,11 @@ function parseHistorianDumpMeta2(path6) {
44138
45181
  }
44139
45182
  }
44140
45183
  function listDumpsInDir2(dir, limit) {
44141
- if (!existsSync29(dir))
45184
+ if (!existsSync32(dir))
44142
45185
  return { count: 0, recent: [] };
44143
45186
  try {
44144
- const entries = readdirSync4(dir).filter((name) => name.endsWith(".xml")).map((name) => {
44145
- 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));
44146
45189
  return {
44147
45190
  name,
44148
45191
  mtime: stat.mtimeMs,
@@ -44151,7 +45194,7 @@ function listDumpsInDir2(dir, limit) {
44151
45194
  }).sort((a3, b2) => b2.mtime - a3.mtime);
44152
45195
  const now = Date.now();
44153
45196
  const recent = entries.slice(0, limit).map((entry) => {
44154
- const meta3 = parseHistorianDumpMeta2(join26(dir, entry.name));
45197
+ const meta3 = parseHistorianDumpMeta2(join29(dir, entry.name));
44155
45198
  const summary = {
44156
45199
  name: entry.name,
44157
45200
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -44214,9 +45257,9 @@ async function collectDiagnostics2(cwd = process.cwd()) {
44214
45257
  const projectConfigPath = getProjectConfigPath(cwd);
44215
45258
  const loaded = loadPiConfig({ cwd });
44216
45259
  const storageDirPath = getMagicContextStorageDir();
44217
- const dbPath = join26(storageDirPath, "context.db");
45260
+ const dbPath = join29(storageDirPath, "context.db");
44218
45261
  const logPath = getMagicContextLogPath2("pi");
44219
- const logFileSize = existsSync29(logPath) ? statSync12(logPath).size : 0;
45262
+ const logFileSize = existsSync32(logPath) ? statSync13(logPath).size : 0;
44220
45263
  const otherPiExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
44221
45264
  const recentSessions = collectPiRecentSessions();
44222
45265
  const historianDumps = collectPiHistorianDumps(recentSessions);
@@ -44231,7 +45274,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
44231
45274
  piVersion: pi ? getPiVersion(pi.path) : null,
44232
45275
  settings: {
44233
45276
  path: settingsPath,
44234
- exists: existsSync29(settingsPath),
45277
+ exists: existsSync32(settingsPath),
44235
45278
  ...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
44236
45279
  hasMagicContextPackage: hasPiMagicContextPackage(packages),
44237
45280
  packages: sanitizeValue2(packages)
@@ -44247,7 +45290,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
44247
45290
  loadWarnings: loaded.warnings.map(sanitizeString2),
44248
45291
  storageDir: {
44249
45292
  path: storageDirPath,
44250
- exists: existsSync29(storageDirPath),
45293
+ exists: existsSync32(storageDirPath),
44251
45294
  contextDbSizeBytes: fileSize2(dbPath)
44252
45295
  },
44253
45296
  conflicts: {
@@ -44256,7 +45299,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
44256
45299
  },
44257
45300
  logFile: {
44258
45301
  path: logPath,
44259
- exists: existsSync29(logPath),
45302
+ exists: existsSync32(logPath),
44260
45303
  sizeKb: Math.round(logFileSize / 1024)
44261
45304
  },
44262
45305
  recentSessions,
@@ -44337,7 +45380,7 @@ function renderDiagnosticsMarkdown2(report) {
44337
45380
  ].join(`
44338
45381
  `);
44339
45382
  }
44340
- var import_comment_json12;
45383
+ var import_comment_json13;
44341
45384
  var init_diagnostics_pi = __esm(() => {
44342
45385
  init_migrate_config_location();
44343
45386
  init_compartment_parser();
@@ -44346,12 +45389,12 @@ var init_diagnostics_pi = __esm(() => {
44346
45389
  init_paths();
44347
45390
  init_pi_helpers();
44348
45391
  init_redaction2();
44349
- import_comment_json12 = __toESM(require_src3(), 1);
45392
+ import_comment_json13 = __toESM(require_src3(), 1);
44350
45393
  });
44351
45394
 
44352
45395
  // src/lib/logs-pi.ts
44353
- import { readFileSync as readFileSync22, writeFileSync as writeFileSync8 } from "node:fs";
44354
- 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";
44355
45398
  function sanitizeLogContent2(content) {
44356
45399
  return sanitizeString2(content);
44357
45400
  }
@@ -44380,7 +45423,7 @@ function filterLogLinesBySession2(lines, sessionId) {
44380
45423
  }
44381
45424
  async function bundleIssueReport2(report, description, title, options = {}) {
44382
45425
  const LOG_TAIL_LINES = 400;
44383
- 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/) : [];
44384
45427
  const logLines = filterLogLinesBySession2(allLogLines, options.sessionFilter ?? null);
44385
45428
  const recentLog = sanitizeLogContent2(logLines.slice(-LOG_TAIL_LINES).join(`
44386
45429
  `)).trim();
@@ -44416,8 +45459,8 @@ async function bundleIssueReport2(report, description, title, options = {}) {
44416
45459
  `);
44417
45460
  const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
44418
45461
  const cwd = options.cwd ?? process.cwd();
44419
- const path6 = join27(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
44420
- writeFileSync8(path6, `${bodyMarkdown}
45462
+ const path6 = join30(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
45463
+ writeFileSync9(path6, `${bodyMarkdown}
44421
45464
  `);
44422
45465
  return { path: path6, bodyMarkdown };
44423
45466
  }
@@ -44428,14 +45471,14 @@ var init_logs_pi = __esm(() => {
44428
45471
 
44429
45472
  // src/commands/doctor-pi.ts
44430
45473
  import { execFileSync as execFileSync6, spawnSync as spawnSync7 } from "node:child_process";
44431
- import { existsSync as existsSync30, mkdirSync as mkdirSync10, 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";
44432
45475
  import { createRequire as createRequire7 } from "node:module";
44433
- import { homedir as homedir18 } from "node:os";
44434
- import { dirname as dirname15, 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";
44435
45478
  function depsFrom(options) {
44436
45479
  return {
44437
- ...DEFAULT_DEPS3,
44438
- prompts: options.prompts ?? DEFAULT_DEPS3.prompts,
45480
+ ...DEFAULT_DEPS5,
45481
+ prompts: options.prompts ?? DEFAULT_DEPS5.prompts,
44439
45482
  ...options.deps
44440
45483
  };
44441
45484
  }
@@ -44521,7 +45564,7 @@ function summarize(results) {
44521
45564
  function readJsonc2(path6) {
44522
45565
  try {
44523
45566
  return {
44524
- value: import_comment_json13.parse(readFileSync23(path6, "utf-8"))
45567
+ value: import_comment_json14.parse(readFileSync25(path6, "utf-8"))
44525
45568
  };
44526
45569
  } catch (error51) {
44527
45570
  return {
@@ -44540,28 +45583,28 @@ function piPluginDirCandidates(packages, cwd) {
44540
45583
  const spec = typeof entry === "string" ? entry.trim() : "";
44541
45584
  if (!spec || spec.startsWith("npm:"))
44542
45585
  continue;
44543
- const resolved = isAbsolute4(spec) ? spec : join28(agentDir, spec);
45586
+ const resolved = isAbsolute5(spec) ? spec : join31(agentDir, spec);
44544
45587
  dirs.push(resolved);
44545
45588
  }
44546
- dirs.push(join28(agentDir, "npm", "node_modules", PACKAGE_NAME));
44547
- dirs.push(join28(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME));
44548
- return dirs.filter((dir) => existsSync30(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")));
44549
45592
  }
44550
45593
  function projectConfigPath(cwd) {
44551
45594
  return resolveCortexKitProjectConfigPath(cwd);
44552
45595
  }
44553
45596
  function readConfigForEmbedding(path6, isProjectConfig) {
44554
- if (!existsSync30(path6))
45597
+ if (!existsSync33(path6))
44555
45598
  return null;
44556
45599
  try {
44557
- const rawText = readFileSync23(path6, "utf-8");
45600
+ const rawText = readFileSync25(path6, "utf-8");
44558
45601
  const substituted = substituteConfigVariables({
44559
45602
  text: rawText,
44560
45603
  configPath: path6,
44561
45604
  isProjectConfig
44562
45605
  });
44563
45606
  const rejectedKeyPaths = [];
44564
- const parsed = sanitizeParsedJson(import_comment_json13.parse(substituted.text), {
45607
+ const parsed = sanitizeParsedJson(import_comment_json14.parse(substituted.text), {
44565
45608
  onRejectedKey: (keyPath) => rejectedKeyPaths.push(keyPath.join("."))
44566
45609
  });
44567
45610
  if (rejectedKeyPaths.length > 0) {
@@ -44632,38 +45675,38 @@ function pinnedVersionFromPackageSpecifier(specifier) {
44632
45675
  }
44633
45676
  function cacheRoots(cwd) {
44634
45677
  const home = process.env.HOME?.trim();
44635
- const cacheHome = process.env.XDG_CACHE_HOME || join28(home || homedir18(), ".cache");
45678
+ const cacheHome = process.env.XDG_CACHE_HOME || join31(home || homedir19(), ".cache");
44636
45679
  const piCacheRoot = getPiCacheRoot();
44637
45680
  return [
44638
- join28(piCacheRoot, "extensions"),
44639
- join28(piCacheRoot, "packages"),
44640
- join28(cacheHome, "pi", "extensions"),
44641
- join28(cacheHome, "pi", "packages"),
44642
- join28(getPiAgentConfigDir(), "cache", "extensions"),
44643
- join28(getPiAgentConfigDir(), "npm", "node_modules", PACKAGE_NAME),
44644
- 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)
44645
45688
  ];
44646
45689
  }
44647
45690
  function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
44648
45691
  const found = new Map;
44649
45692
  const visit = (path6, depth) => {
44650
- if (depth < 0 || !existsSync30(path6))
45693
+ if (depth < 0 || !existsSync33(path6))
44651
45694
  return;
44652
45695
  let stat;
44653
45696
  try {
44654
- stat = statSync13(path6);
45697
+ stat = statSync14(path6);
44655
45698
  } catch {
44656
45699
  return;
44657
45700
  }
44658
45701
  if (!stat.isDirectory())
44659
45702
  return;
44660
- const packageJson = join28(path6, "package.json");
44661
- if (existsSync30(packageJson)) {
45703
+ const packageJson = join31(path6, "package.json");
45704
+ if (existsSync33(packageJson)) {
44662
45705
  try {
44663
- const pkg = JSON.parse(readFileSync23(packageJson, "utf-8"));
45706
+ const pkg = JSON.parse(readFileSync25(packageJson, "utf-8"));
44664
45707
  const name = typeof pkg.name === "string" ? pkg.name : "";
44665
45708
  const version2 = typeof pkg.version === "string" ? pkg.version : undefined;
44666
- if (name === PACKAGE_NAME) {
45709
+ if (name === PACKAGE_NAME2) {
44667
45710
  if (force || !version2 || expectedVersion && version2 !== expectedVersion) {
44668
45711
  found.set(path6, { path: path6, version: version2 });
44669
45712
  }
@@ -44675,12 +45718,12 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
44675
45718
  }
44676
45719
  let entries = [];
44677
45720
  try {
44678
- entries = readdirSync5(path6);
45721
+ entries = readdirSync6(path6);
44679
45722
  } catch {
44680
45723
  return;
44681
45724
  }
44682
45725
  for (const entry of entries)
44683
- visit(join28(path6, entry), depth - 1);
45726
+ visit(join31(path6, entry), depth - 1);
44684
45727
  };
44685
45728
  for (const root of cacheRoots(cwd))
44686
45729
  visit(root, 5);
@@ -44725,7 +45768,7 @@ async function runHealthChecks2(options) {
44725
45768
  }
44726
45769
  const settingsPath = getPiUserExtensionsPath();
44727
45770
  let packages = [];
44728
- if (!existsSync30(settingsPath)) {
45771
+ if (!existsSync33(settingsPath)) {
44729
45772
  add2(results, "fail", `Pi settings not found at ${settingsPath}`);
44730
45773
  repairPlan.addPackageEntry = true;
44731
45774
  } else {
@@ -44749,7 +45792,7 @@ async function runHealthChecks2(options) {
44749
45792
  ["user", userConfigPath, true],
44750
45793
  ["project", projectPath, false]
44751
45794
  ]) {
44752
- if (!existsSync30(path6)) {
45795
+ if (!existsSync33(path6)) {
44753
45796
  if (required2) {
44754
45797
  add2(results, "warn", `No ${label} magic-context.jsonc found at ${path6}`);
44755
45798
  if (userConfigMigrationRefused) {
@@ -44786,8 +45829,8 @@ async function runHealthChecks2(options) {
44786
45829
  add2(results, "pass", `historian.model "${historianModel}" has thinking_level "${historianThinkingLevel}" configured`);
44787
45830
  }
44788
45831
  const storageDir = getMagicContextStorageDir();
44789
- const dbPath = join28(storageDir, "context.db");
44790
- const existedBeforeOpen = existsSync30(dbPath);
45832
+ const dbPath = join31(storageDir, "context.db");
45833
+ const existedBeforeOpen = existsSync33(dbPath);
44791
45834
  if (existedBeforeOpen)
44792
45835
  add2(results, "pass", `Shared context DB exists at ${dbPath}`);
44793
45836
  else
@@ -44924,10 +45967,10 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
44924
45967
  add2(results, "pass", "Pi extension cache clean (no stale cached package found)");
44925
45968
  }
44926
45969
  const logPath = getMagicContextLogPath2("pi");
44927
- if (existsSync30(logPath)) {
44928
- const stat = statSync13(logPath);
45970
+ if (existsSync33(logPath)) {
45971
+ const stat = statSync14(logPath);
44929
45972
  const sizeKb = (stat.size / 1024).toFixed(0);
44930
- 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);
44931
45974
  add2(results, "info", `Log file: ${logPath} (${sizeKb} KB)`);
44932
45975
  const lastLine = lines.at(-1);
44933
45976
  add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
@@ -44962,12 +46005,12 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
44962
46005
  return { results, repairPlan, ...summarize(results) };
44963
46006
  }
44964
46007
  function writeDefaultMagicContextConfig(path6) {
44965
- mkdirSync10(dirname15(path6), { recursive: true });
46008
+ mkdirSync11(dirname17(path6), { recursive: true });
44966
46009
  const config2 = {
44967
46010
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
44968
46011
  ...MagicContextConfigSchema.parse({})
44969
46012
  };
44970
- writeFileAtomic(path6, `${import_comment_json13.stringify(config2, null, 2)}
46013
+ writeFileAtomic(path6, `${import_comment_json14.stringify(config2, null, 2)}
44971
46014
  `);
44972
46015
  }
44973
46016
  function repair2(plan, prompts) {
@@ -44984,7 +46027,7 @@ function repair2(plan, prompts) {
44984
46027
  }
44985
46028
  if (plan.writeUserConfig) {
44986
46029
  const configPath = getPiUserConfigPath();
44987
- if (!existsSync30(configPath)) {
46030
+ if (!existsSync33(configPath)) {
44988
46031
  try {
44989
46032
  writeDefaultMagicContextConfig(configPath);
44990
46033
  prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
@@ -45104,7 +46147,7 @@ async function runDoctor3(options = {}) {
45104
46147
  const v22Result = await runV22BackfillCommands({
45105
46148
  name: "Pi",
45106
46149
  openDatabase: (readonly2 = true) => {
45107
- const dbPath = join28(getMagicContextStorageDir(), "context.db");
46150
+ const dbPath = join31(getMagicContextStorageDir(), "context.db");
45108
46151
  v22Db = readonly2 ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
45109
46152
  return v22Db;
45110
46153
  },
@@ -45169,7 +46212,7 @@ function parseDoctorArgs(args) {
45169
46212
  function doctor(args = []) {
45170
46213
  return runDoctor3(parseDoctorArgs(args));
45171
46214
  }
45172
- 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;
45173
46216
  var init_doctor_pi = __esm(async () => {
45174
46217
  init_migrate_config_location();
45175
46218
  init_project_security();
@@ -45194,14 +46237,14 @@ var init_doctor_pi = __esm(async () => {
45194
46237
  init_storage_versions(),
45195
46238
  init_v22_backfill_commands()
45196
46239
  ]);
45197
- import_comment_json13 = __toESM(require_src3(), 1);
46240
+ import_comment_json14 = __toESM(require_src3(), 1);
45198
46241
  ROW_COUNT_TABLES2 = ["tags", "compartments", "memories", "notes", "dream_runs"];
45199
- DEFAULT_DEPS3 = {
46242
+ DEFAULT_DEPS5 = {
45200
46243
  prompts: promptIO,
45201
46244
  collectDiagnostics: collectDiagnostics2,
45202
46245
  detectPiBinary,
45203
46246
  getPiVersion,
45204
- getLatestNpmVersion: () => getLatestNpmVersion(PACKAGE_NAME),
46247
+ getLatestNpmVersion: () => getLatestNpmVersion(PACKAGE_NAME2),
45205
46248
  selfVersion: selfVersion2,
45206
46249
  probeEmbeddingEndpoint,
45207
46250
  openExistingContextDatabase,
@@ -45216,8 +46259,8 @@ var exports_doctor = {};
45216
46259
  __export(exports_doctor, {
45217
46260
  runDoctor: () => runDoctor4
45218
46261
  });
45219
- import { existsSync as existsSync31, rmSync as rmSync5 } from "node:fs";
45220
- 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";
45221
46264
  async function runDoctor4(options) {
45222
46265
  if (options.clear)
45223
46266
  return runClear();
@@ -45235,7 +46278,7 @@ async function runDoctor4(options) {
45235
46278
  const result = await runV22BackfillCommands({
45236
46279
  name: "Magic Context",
45237
46280
  openDatabase: (readonly2 = true) => {
45238
- const dbPath = join29(getMagicContextStorageDir(), "context.db");
46281
+ const dbPath = join32(getMagicContextStorageDir(), "context.db");
45239
46282
  v22Db = readonly2 ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
45240
46283
  return v22Db;
45241
46284
  },
@@ -45248,6 +46291,27 @@ async function runDoctor4(options) {
45248
46291
  if (result.handled)
45249
46292
  return result.exitCode;
45250
46293
  }
46294
+ const { sweepPendingMigrations: sweepPendingMigrations2, formatMigrationSweepLines: formatMigrationSweepLines2 } = await init_migrate().then(() => exports_migrate);
46295
+ const sweepDbPath = join32(getMagicContextStorageDir(), "context.db");
46296
+ let sweepDb = null;
46297
+ try {
46298
+ sweepDb = openExistingContextDatabaseForMutation(sweepDbPath);
46299
+ } catch {}
46300
+ if (sweepDb !== null) {
46301
+ try {
46302
+ const report = sweepPendingMigrations2(sweepDb);
46303
+ for (const line of formatMigrationSweepLines2(report)) {
46304
+ if (line.startsWith("LOST"))
46305
+ log2.error(line);
46306
+ else
46307
+ log2.info(line);
46308
+ }
46309
+ } catch (error51) {
46310
+ log2.warn(`Session-migration recovery sweep failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
46311
+ } finally {
46312
+ sweepDb.close();
46313
+ }
46314
+ }
45251
46315
  let anyFailure = false;
45252
46316
  for (const adapter of adapters) {
45253
46317
  log2.step(`Running doctor for ${adapter.displayName}…`);
@@ -45324,7 +46388,7 @@ async function runClear() {
45324
46388
  const s = spinner2();
45325
46389
  s.start(`Clearing ${item.path}`);
45326
46390
  try {
45327
- if (existsSync31(item.path)) {
46391
+ if (existsSync34(item.path)) {
45328
46392
  rmSync5(item.path, { recursive: true, force: true });
45329
46393
  }
45330
46394
  s.stop(`Cleared ${item.path}`);
@@ -45340,9 +46404,9 @@ async function runClear() {
45340
46404
  function formatSize(bytes) {
45341
46405
  if (bytes < 1024)
45342
46406
  return `${bytes} B`;
45343
- if (bytes < 1024 * 1024)
46407
+ if (bytes < 1048576)
45344
46408
  return `${(bytes / 1024).toFixed(1)} KB`;
45345
- if (bytes < 1024 * 1024 * 1024)
46409
+ if (bytes < 1073741824)
45346
46410
  return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
45347
46411
  return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;
45348
46412
  }
@@ -45470,12 +46534,12 @@ async function main(argv = process.argv.slice(2)) {
45470
46534
  console.error("Usage: magic-context doctor drain-authority <project>");
45471
46535
  return 1;
45472
46536
  }
45473
- const [{ runDoctorDrainAuthority: runDoctorDrainAuthority2 }, { getMagicContextStorageDir: getMagicContextStorageDir2 }, { join: join30 }] = await Promise.all([
46537
+ const [{ runDoctorDrainAuthority: runDoctorDrainAuthority2 }, { getMagicContextStorageDir: getMagicContextStorageDir2 }, { join: join33 }] = await Promise.all([
45474
46538
  init_doctor_authority().then(() => exports_doctor_authority),
45475
46539
  Promise.resolve().then(() => (init_data_path(), exports_data_path)),
45476
46540
  import("node:path")
45477
46541
  ]);
45478
- return runDoctorDrainAuthority2(projectRoot, join30(getMagicContextStorageDir2(), "context.db"));
46542
+ return runDoctorDrainAuthority2(projectRoot, join33(getMagicContextStorageDir2(), "context.db"));
45479
46543
  }
45480
46544
  if (rest[0] === "merge-identity") {
45481
46545
  const { runMergeIdentityCli: runMergeIdentityCli2 } = await init_doctor_merge_identity().then(() => exports_doctor_merge_identity);