@cortexkit/magic-context 0.44.1 → 0.44.2

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 +1251 -460
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1647,6 +1647,7 @@ var init_prompts = __esm(() => {
1647
1647
  });
1648
1648
 
1649
1649
  // ../plugin/src/shared/sqlite.ts
1650
+ import { AsyncLocalStorage } from "node:async_hooks";
1650
1651
  function registerSlowWriteReporter(reporter) {
1651
1652
  reportSlowPrivilegedWrite = reporter;
1652
1653
  }
@@ -1680,6 +1681,62 @@ async function loadSqliteModule(runtime = detectSqliteRuntime(), importer = impo
1680
1681
  throw error;
1681
1682
  }
1682
1683
  }
1684
+ function installTransactionRouting(db, readonly) {
1685
+ const nativeExec = db.exec.bind(db);
1686
+ Object.defineProperty(db, "exec", {
1687
+ configurable: true,
1688
+ writable: true,
1689
+ value: (sql) => {
1690
+ if (/^\s*BEGIN\s+(?:IMMEDIATE|EXCLUSIVE)(?:\s+TRANSACTION)?\s*;?\s*$/i.test(sql)) {
1691
+ retryAcquisition(() => nativeExec(sql), sql.trim());
1692
+ return db;
1693
+ }
1694
+ return nativeExec(sql);
1695
+ }
1696
+ });
1697
+ Object.defineProperty(db, "transaction", {
1698
+ configurable: true,
1699
+ writable: true,
1700
+ value: (fn) => {
1701
+ const make = (mode) => function(...args) {
1702
+ const nested = isInTransaction(db);
1703
+ const savepoint = "mc_tx_sp";
1704
+ db.exec(nested ? `SAVEPOINT ${savepoint}` : `BEGIN ${mode}`);
1705
+ try {
1706
+ const result = fn.apply(this, args);
1707
+ db.exec(nested ? `RELEASE ${savepoint}` : "COMMIT");
1708
+ return result;
1709
+ } catch (error) {
1710
+ if (isInTransaction(db)) {
1711
+ if (nested) {
1712
+ db.exec(`ROLLBACK TO ${savepoint}`);
1713
+ db.exec(`RELEASE ${savepoint}`);
1714
+ } else
1715
+ db.exec("ROLLBACK");
1716
+ }
1717
+ throw error;
1718
+ }
1719
+ };
1720
+ const defaultTransaction = make(readonly ? "DEFERRED" : "IMMEDIATE");
1721
+ const variants = {
1722
+ default: defaultTransaction,
1723
+ deferred: make("DEFERRED"),
1724
+ immediate: make("IMMEDIATE"),
1725
+ exclusive: make("EXCLUSIVE"),
1726
+ database: db
1727
+ };
1728
+ for (const transaction of [
1729
+ variants.default,
1730
+ variants.deferred,
1731
+ variants.immediate,
1732
+ variants.exclusive
1733
+ ]) {
1734
+ Object.assign(transaction, variants);
1735
+ }
1736
+ return defaultTransaction;
1737
+ }
1738
+ });
1739
+ }
1683
1740
  function trackSqliteConnection(db, filename, options) {
1684
1741
  const originalClose = db.close.bind(db);
1685
1742
  const sequence = nextSqliteConnectionSequence++;
@@ -1688,6 +1745,7 @@ function trackSqliteConnection(db, filename, options) {
1688
1745
  filename: typeof filename === "string" ? filename : Buffer.isBuffer(filename) ? "<buffer>" : ":memory:",
1689
1746
  readonly: Boolean(options) && typeof options === "object" && (options.readonly === true || options.readOnly === true)
1690
1747
  };
1748
+ installTransactionRouting(db, metadata.readonly);
1691
1749
  Object.defineProperty(db, "close", {
1692
1750
  configurable: true,
1693
1751
  value: (...args) => {
@@ -1705,7 +1763,6 @@ function trackSqliteConnection(db, filename, options) {
1705
1763
  return db;
1706
1764
  }
1707
1765
  function buildNodeSqliteDatabaseClass(DatabaseSync) {
1708
- const SAVEPOINT = "mc_tx_sp";
1709
1766
 
1710
1767
  class NodeSqliteDatabase extends DatabaseSync {
1711
1768
  constructor(filename, options) {
@@ -1724,45 +1781,34 @@ function buildNodeSqliteDatabaseClass(DatabaseSync) {
1724
1781
  }
1725
1782
  return stmt;
1726
1783
  }
1727
- transaction(fn) {
1728
- const self = this;
1729
- const execute = (mode, receiver, args) => {
1730
- const nested = self.isTransaction === true;
1731
- self.exec(nested ? `SAVEPOINT ${SAVEPOINT}` : `BEGIN${mode ? ` ${mode}` : ""}`);
1732
- try {
1733
- const result = fn.apply(receiver, args);
1734
- self.exec(nested ? `RELEASE ${SAVEPOINT}` : "COMMIT");
1735
- return result;
1736
- } catch (error) {
1737
- if (nested) {
1738
- self.exec(`ROLLBACK TO ${SAVEPOINT}`);
1739
- self.exec(`RELEASE ${SAVEPOINT}`);
1740
- } else {
1741
- self.exec("ROLLBACK");
1742
- }
1743
- throw error;
1744
- }
1745
- };
1746
- const wrapped = function(...args) {
1747
- return execute("", this, args);
1748
- };
1749
- wrapped.default = function(...args) {
1750
- return execute("", this, args);
1751
- };
1752
- wrapped.deferred = function(...args) {
1753
- return execute("DEFERRED", this, args);
1754
- };
1755
- wrapped.immediate = function(...args) {
1756
- return execute("IMMEDIATE", this, args);
1757
- };
1758
- wrapped.exclusive = function(...args) {
1759
- return execute("EXCLUSIVE", this, args);
1760
- };
1761
- return wrapped;
1762
- }
1763
1784
  }
1764
1785
  return NodeSqliteDatabase;
1765
1786
  }
1787
+ function isTransientSqliteError(error) {
1788
+ if (!error || typeof error !== "object")
1789
+ return false;
1790
+ const value = error;
1791
+ return typeof value.code === "string" && /^(SQLITE_BUSY|SQLITE_LOCKED)(_|$)/.test(value.code) || typeof value.errcode === "number" && [5, 6].includes(value.errcode & 255);
1792
+ }
1793
+ function retryAcquisition(acquire, stage) {
1794
+ if (!transformPassScope.getStore()?.active) {
1795
+ acquire();
1796
+ return;
1797
+ }
1798
+ const delays = [500, 1000];
1799
+ for (let attempt = 0;; attempt++) {
1800
+ try {
1801
+ acquire();
1802
+ return;
1803
+ } catch (error) {
1804
+ if (error instanceof SqliteAcquisitionBusyError || !isTransientSqliteError(error))
1805
+ throw error;
1806
+ if (attempt === delays.length)
1807
+ throw new SqliteAcquisitionBusyError(error, stage);
1808
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, delays[attempt]);
1809
+ }
1810
+ }
1811
+ }
1766
1812
  function isInTransaction(db) {
1767
1813
  const candidate = db;
1768
1814
  return candidate.inTransaction === true || candidate.isTransaction === true;
@@ -1775,7 +1821,7 @@ function withPrivilegedWriter(db, operation) {
1775
1821
  if (nested) {
1776
1822
  db.exec(`SAVEPOINT ${savepoint}`);
1777
1823
  } else {
1778
- db.exec("BEGIN IMMEDIATE");
1824
+ retryAcquisition(() => db.exec("BEGIN IMMEDIATE"), "BEGIN IMMEDIATE");
1779
1825
  }
1780
1826
  privilegeDepth.set(db, previousDepth + 1);
1781
1827
  try {
@@ -1814,7 +1860,7 @@ function withPrivilegedWriter(db, operation) {
1814
1860
  throw error;
1815
1861
  }
1816
1862
  }
1817
- var reportSlowPrivilegedWrite, bunSpec, nodeSpec, SqliteRuntimeUnavailableError, detectedRuntime, isBun, sqliteModule, DatabaseImpl, trackedSqliteConnections, nextSqliteConnectionSequence = 1, TrackedDatabase, Database, privilegeDepth;
1863
+ var reportSlowPrivilegedWrite, bunSpec, nodeSpec, SqliteRuntimeUnavailableError, detectedRuntime, isBun, sqliteModule, DatabaseImpl, trackedSqliteConnections, nextSqliteConnectionSequence = 1, TrackedDatabase, Database, privilegeDepth, transformPassScope, SqliteAcquisitionBusyError;
1818
1864
  var init_sqlite = __esm(async () => {
1819
1865
  bunSpec = "bun:" + "sqlite";
1820
1866
  nodeSpec = "node:" + "sqlite";
@@ -1842,6 +1888,16 @@ var init_sqlite = __esm(async () => {
1842
1888
  });
1843
1889
  Database = TrackedDatabase;
1844
1890
  privilegeDepth = new WeakMap;
1891
+ transformPassScope = new AsyncLocalStorage;
1892
+ SqliteAcquisitionBusyError = class SqliteAcquisitionBusyError extends Error {
1893
+ code = "SQLITE_BUSY";
1894
+ stage;
1895
+ constructor(cause, stage = "BEGIN IMMEDIATE") {
1896
+ super("SQLite writer acquisition remained busy after 3 attempts", { cause });
1897
+ this.name = "SqliteAcquisitionBusyError";
1898
+ this.stage = stage;
1899
+ }
1900
+ };
1845
1901
  });
1846
1902
 
1847
1903
  // src/lib/docs-proposal-gitignore.ts
@@ -4270,6 +4326,7 @@ function getPiVersion(piPath) {
4270
4326
  try {
4271
4327
  const invocation = getPiCommandInvocation(piPath, ["--version"]);
4272
4328
  const result = spawnSync(invocation.command, invocation.args, {
4329
+ windowsHide: true,
4273
4330
  encoding: "utf-8",
4274
4331
  timeout: 1e4
4275
4332
  });
@@ -4288,6 +4345,7 @@ function runPiCommand(piPath, args, timeout = 20000) {
4288
4345
  try {
4289
4346
  const invocation = getPiCommandInvocation(piPath, args);
4290
4347
  return execFileSync(invocation.command, invocation.args, {
4348
+ windowsHide: true,
4291
4349
  encoding: "utf-8",
4292
4350
  stdio: ["ignore", "pipe", "ignore"],
4293
4351
  timeout
@@ -4403,6 +4461,7 @@ function runOmpCommand(ompPath, args, timeout = 30000, overrides = {}) {
4403
4461
  try {
4404
4462
  const invocation = deps.getInvocation(ompPath, args);
4405
4463
  const result = deps.spawnSync(invocation.command, invocation.args, {
4464
+ windowsHide: true,
4406
4465
  encoding: "utf-8",
4407
4466
  timeout,
4408
4467
  maxBuffer: 10 * 1024 * 1024,
@@ -12794,7 +12853,7 @@ var init_opencode_plugin_cache = __esm(() => {
12794
12853
  import { spawnSync as spawnSync3 } from "node:child_process";
12795
12854
  import { existsSync as existsSync8, rmSync as rmSync2 } from "node:fs";
12796
12855
  function runLsof(args, spawn) {
12797
- const result = spawn("lsof", args, { encoding: "utf-8", timeout: 15000 });
12856
+ const result = spawn("lsof", args, { encoding: "utf-8", timeout: 15000, windowsHide: true });
12798
12857
  if (result.error)
12799
12858
  return { error: result.error.message };
12800
12859
  if (result.status !== 0 && result.status !== 1) {
@@ -13160,7 +13219,11 @@ function getOpenCodeCommandInvocation(binary, args) {
13160
13219
  }
13161
13220
  function runOpenCode(args, binary, timeoutMs) {
13162
13221
  try {
13163
- const options = { stdio: "pipe", ...timeoutMs ? { timeout: timeoutMs } : {} };
13222
+ const options = {
13223
+ stdio: "pipe",
13224
+ windowsHide: true,
13225
+ ...timeoutMs ? { timeout: timeoutMs } : {}
13226
+ };
13164
13227
  if (binary) {
13165
13228
  const invocation = getOpenCodeCommandInvocation(binary, args);
13166
13229
  return execFileSync2(invocation.command, invocation.args, {
@@ -14676,6 +14739,49 @@ function parseCron(expression) {
14676
14739
  function isValidCron(expression) {
14677
14740
  return parseCron(expression).ok;
14678
14741
  }
14742
+ function matchesDay(cron, date) {
14743
+ const dom = cron.dom.has(date.getDate());
14744
+ const dow = cron.dow.has(date.getDay());
14745
+ if (cron.domRestricted && cron.dowRestricted)
14746
+ return dom || dow;
14747
+ if (cron.domRestricted)
14748
+ return dom;
14749
+ if (cron.dowRestricted)
14750
+ return dow;
14751
+ return true;
14752
+ }
14753
+ function matchesCron(cron, date) {
14754
+ return cron.minute.has(date.getMinutes()) && cron.hour.has(date.getHours()) && cron.month.has(date.getMonth() + 1) && matchesDay(cron, date);
14755
+ }
14756
+ function civilMinuteKey(date) {
14757
+ const p = (n, w = 2) => String(n).padStart(w, "0");
14758
+ return `${p(date.getFullYear(), 4)}-${p(date.getMonth() + 1)}-${p(date.getDate())} ${p(date.getHours())}:${p(date.getMinutes())}`;
14759
+ }
14760
+ function nextOccurrence(cron, after, excludeCivilMinute, maxSearchMs = MAX_SEARCH_MS) {
14761
+ const afterMs = after.getTime();
14762
+ let cursorMs = Math.floor(afterMs / MINUTE_MS) * MINUTE_MS + MINUTE_MS;
14763
+ const capMs = afterMs + Math.max(0, Math.min(MAX_SEARCH_MS, maxSearchMs));
14764
+ while (cursorMs <= capMs) {
14765
+ const candidate = new Date(cursorMs);
14766
+ if (matchesCron(cron, candidate)) {
14767
+ if (!excludeCivilMinute || civilMinuteKey(candidate) !== excludeCivilMinute) {
14768
+ return candidate;
14769
+ }
14770
+ }
14771
+ cursorMs += MINUTE_MS;
14772
+ }
14773
+ return null;
14774
+ }
14775
+ function nextDueAtMs(expression, afterMs, consumedScheduledAtMs, maxSearchMs = MAX_SEARCH_MS) {
14776
+ if (expression.trim().length === 0)
14777
+ return null;
14778
+ const parsed = parseCron(expression);
14779
+ if (!parsed.ok)
14780
+ return null;
14781
+ const exclude = consumedScheduledAtMs !== undefined ? civilMinuteKey(new Date(consumedScheduledAtMs)) : undefined;
14782
+ const next = nextOccurrence(parsed.cron, new Date(afterMs), exclude, maxSearchMs);
14783
+ return next ? next.getTime() : null;
14784
+ }
14679
14785
  var FIELDS, MINUTE_MS = 60000, MAX_SEARCH_MS;
14680
14786
  var init_cron = __esm(() => {
14681
14787
  FIELDS = [
@@ -21156,9 +21262,9 @@ import { homedir as homedir9 } from "node:os";
21156
21262
  function defaultTaskConfig(task) {
21157
21263
  const base = { schedule: DEFAULT_TASK_SCHEDULES2[task] };
21158
21264
  if (task === "review-user-memories")
21159
- base.promotion_threshold = 3;
21265
+ base.promotion_threshold = DREAM_TASK_PROMOTION_DEFAULTS["review-user-memories"];
21160
21266
  if (task === "promote-primers")
21161
- base.promotion_threshold = 2;
21267
+ base.promotion_threshold = DREAM_TASK_PROMOTION_DEFAULTS["promote-primers"];
21162
21268
  return base;
21163
21269
  }
21164
21270
  function expandConfigPath(value) {
@@ -21169,7 +21275,7 @@ function expandConfigPath(value) {
21169
21275
  return `${homedir9()}/${trimmed.slice(2)}`;
21170
21276
  return trimmed;
21171
21277
  }
21172
- var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 90% for cache safety: output capacity is reserved from the usable context window, and the remaining 10% absorbs mid-turn growth before the absolute 95% emergency wall. Use a value between 20 and 90.", DEFAULT_HISTORIAN_TIMEOUT_MS = 600000, DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15, PROTECTED_TOKENS_MIN = 4000, DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2", PiThinkingLevelSchema, OmpThinkingLevelSchema, PiConfigSchema, PromptSurfacePresetSchema, PromptSurfaceModelKeySchema, PromptSurfaceToolKeySchema, PromptSurfaceConfigSchema, PER_HARNESS_MIGRATION_INVENTORY, PER_HARNESS_MODEL_KEYS, OcEntryObjectSchema, OcEntrySchema, PiEntryObjectSchema, PiEntrySchema, OmpEntryObjectSchema, OmpEntrySchema, OpenCodeHarnessBlockSchema, PiHarnessBlockSchema, OmpHarnessBlockSchema, OpenCodeTaskExecutionSchema, PiTaskExecutionSchema, OmpTaskExecutionSchema, DreamerOpenCodeHarnessBlockSchema, DreamerPiHarnessBlockSchema, DreamerOmpHarnessBlockSchema, ProfileOpenCodeModelBlockSchema, ProfilePiModelBlockSchema, ProfileOmpModelBlockSchema, ProfileHistorianSchema, ProfileDreamerSchema, ConfigProfileSchema, ConfigProfilesSchema, CronScheduleSchema, DreamTaskBaseConfigSchema, PromotionThresholdSchema, PrimerPromotionThresholdSchema, DreamTaskConfigSchema, ReviewUserMemoriesTaskConfigSchema, PromotePrimersTaskConfigSchema, RetrospectiveTaskConfigSchema, DEFAULT_TASK_SCHEDULES2, DreamTasksSchema, AgentMetadataSchema, DreamerConfigSchema, HistorianConfigSchema, EmbeddingFallbackProviderSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema, LIVE_RELOAD_CONFIG_PATHS;
21278
+ var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65, EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 90% for cache safety: output capacity is reserved from the usable context window, and the remaining 10% absorbs mid-turn growth before the absolute 95% emergency wall. Use a value between 20 and 90.", DEFAULT_HISTORIAN_TIMEOUT_MS = 600000, DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15, PROTECTED_TOKENS_MIN = 4000, DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2", PiThinkingLevelSchema, OmpThinkingLevelSchema, PiConfigSchema, PromptSurfacePresetSchema, PromptSurfaceModelKeySchema, PromptSurfaceToolKeySchema, PromptSurfaceConfigSchema, PER_HARNESS_MIGRATION_INVENTORY, PER_HARNESS_MODEL_KEYS, OcEntryObjectSchema, OcEntrySchema, PiEntryObjectSchema, PiEntrySchema, OmpEntryObjectSchema, OmpEntrySchema, OpenCodeHarnessBlockSchema, PiHarnessBlockSchema, OmpHarnessBlockSchema, OpenCodeTaskExecutionSchema, PiTaskExecutionSchema, OmpTaskExecutionSchema, DreamerOpenCodeHarnessBlockSchema, DreamerPiHarnessBlockSchema, DreamerOmpHarnessBlockSchema, ProfileOpenCodeModelBlockSchema, ProfilePiModelBlockSchema, ProfileOmpModelBlockSchema, ProfileHistorianSchema, ProfileDreamerSchema, ConfigProfileSchema, ConfigProfilesSchema, CronScheduleSchema, DreamTaskBaseConfigSchema, DREAM_TASK_PROMOTION_DEFAULTS, PromotionThresholdSchema, PrimerPromotionThresholdSchema, DreamTaskConfigSchema, ReviewUserMemoriesTaskConfigSchema, PromotePrimersTaskConfigSchema, RetrospectiveTaskConfigSchema, DEFAULT_TASK_SCHEDULES2, DreamTasksSchema, AgentMetadataSchema, DreamerConfigSchema, HistorianConfigSchema, EmbeddingFallbackProviderSchema, BaseEmbeddingConfigSchema, EmbeddingConfigSchema, MagicContextConfigSchema, LIVE_RELOAD_CONFIG_PATHS;
21173
21279
  var init_magic_context = __esm(() => {
21174
21280
  init_zod();
21175
21281
  init_language_directive();
@@ -21346,10 +21452,15 @@ var init_magic_context = __esm(() => {
21346
21452
  message: 'Invalid schedule: use a 5-field cron expression (e.g. "0 3 * * *" for 3am daily, "0 3 * * 0" for Sunday 3am, "0 */6 * * *" every 6h) or "" to disable.'
21347
21453
  }).describe('5-field cron schedule (e.g. "0 3 * * *"), or "" to disable this task.');
21348
21454
  DreamTaskBaseConfigSchema = object({
21349
- schedule: CronScheduleSchema.default("")
21455
+ schedule: CronScheduleSchema.default(""),
21456
+ token_budget: number2().int().positive().optional().describe("Maximum cumulative prompt tokens (input + cache read + cache write) for one tool-loop child. Defaults vary by task.")
21350
21457
  }).strict();
21351
- PromotionThresholdSchema = number2().min(2).max(20).optional().describe("review-user-memories: min candidate observations before promotion is considered (default: 3)");
21352
- PrimerPromotionThresholdSchema = number2().min(2).max(20).optional().describe("promote-primers: min recurring source days before promotion is considered (default: 2)");
21458
+ DREAM_TASK_PROMOTION_DEFAULTS = {
21459
+ "review-user-memories": 3,
21460
+ "promote-primers": 2
21461
+ };
21462
+ PromotionThresholdSchema = number2().min(2).max(20).default(DREAM_TASK_PROMOTION_DEFAULTS["review-user-memories"]).describe("review-user-memories: min candidate observations before promotion is considered (default: 3)");
21463
+ PrimerPromotionThresholdSchema = number2().min(2).max(20).default(DREAM_TASK_PROMOTION_DEFAULTS["promote-primers"]).describe("promote-primers: min recurring source days before promotion is considered (default: 2)");
21353
21464
  DreamTaskConfigSchema = DreamTaskBaseConfigSchema.extend({
21354
21465
  promotion_threshold: PromotionThresholdSchema
21355
21466
  });
@@ -21526,7 +21637,7 @@ var init_magic_context = __esm(() => {
21526
21637
  });
21527
21638
  MagicContextConfigSchema = object({
21528
21639
  enabled: boolean2().default(true).describe("Enable magic context (default: true)"),
21529
- allow_home_project: boolean2().default(false).describe("Allow Magic Context sessions launched from the exact canonical home directory. The home session uses its deterministic dir: identity so pre-gate memories reconnect. USER-LEVEL ONLY: project config is ignored. The home identity is excluded from registry seed exports, never resolves descendants by containment, and cannot join a workspace."),
21640
+ allow_home_project: boolean2().default(false).describe("Allow Magic Context sessions launched from the exact canonical home directory. A non-git home uses its deterministic dir: identity; a home repository uses its git: identity. USER-LEVEL ONLY: project config is ignored. The home identity is excluded from registry seed exports, never resolves descendants by containment, and cannot join a workspace."),
21530
21641
  mural: object({
21531
21642
  enabled: boolean2().default(false),
21532
21643
  model: string2().trim().min(1).optional().describe("Model for the compress-cues task that compresses each memory into a mural cue. The mural image itself is rendered deterministically (no author model).")
@@ -24905,11 +25016,48 @@ var init_context_authority = __esm(async () => {
24905
25016
  mirrorFlights = new WeakMap;
24906
25017
  });
24907
25018
 
25019
+ // ../plugin/src/features/magic-context/memory/project-identity-cache.ts
25020
+ import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
25021
+ import { mkdirSync as mkdirSync6, readFileSync as readFileSync14, renameSync as renameSync4, writeFileSync as writeFileSync5 } from "node:fs";
25022
+ import path3 from "node:path";
25023
+ function projectDirectoryKey(directory) {
25024
+ const slashed = directory.replaceAll("\\", "/").replace(/^\/\/\?\/UNC\//i, "//").replace(/^\/\/\?\//, "");
25025
+ if (/^[a-z]:\//i.test(slashed) || slashed.startsWith("//")) {
25026
+ return path3.win32.normalize(slashed).replaceAll("\\", "/").replace(/\/$/, "").toLowerCase();
25027
+ }
25028
+ return path3.resolve(directory);
25029
+ }
25030
+ function cachePath(directory) {
25031
+ const hash = createHash2("sha256").update(projectDirectoryKey(directory)).digest("hex");
25032
+ return path3.join(getMagicContextStorageDir(), "project-identities", `${hash}.json`);
25033
+ }
25034
+ function rememberGitIdentity(directory, identity) {
25035
+ try {
25036
+ const destination = cachePath(directory);
25037
+ mkdirSync6(path3.dirname(destination), { recursive: true });
25038
+ const temporary = `${destination}.${randomUUID2()}.tmp`;
25039
+ writeFileSync5(temporary, JSON.stringify({ directory: projectDirectoryKey(directory), identity }), { mode: 384 });
25040
+ renameSync4(temporary, destination);
25041
+ } catch {}
25042
+ }
25043
+ function readRememberedGitIdentity(directory) {
25044
+ try {
25045
+ const record = JSON.parse(readFileSync14(cachePath(directory), "utf8"));
25046
+ if (record.directory === projectDirectoryKey(directory) && /^git:[0-9a-f]{7,64}$/.test(record.identity))
25047
+ return record.identity;
25048
+ } catch {}
25049
+ return;
25050
+ }
25051
+ var init_project_identity_cache = __esm(() => {
25052
+ init_data_path();
25053
+ });
25054
+
24908
25055
  // ../plugin/src/features/magic-context/memory/project-identity.ts
24909
25056
  import { execFileSync as execFileSync3 } from "node:child_process";
24910
- import { createHash as createHash2 } from "node:crypto";
25057
+ import { createHash as createHash3 } from "node:crypto";
24911
25058
  import { existsSync as existsSync21, realpathSync as realpathSync2, statSync as statSync9 } from "node:fs";
24912
- import path3 from "node:path";
25059
+ import { homedir as homedir14 } from "node:os";
25060
+ import path4 from "node:path";
24913
25061
  function asError(error) {
24914
25062
  return error instanceof Error ? error : undefined;
24915
25063
  }
@@ -24947,8 +25095,8 @@ function getErrorStderr(error) {
24947
25095
  return "";
24948
25096
  }
24949
25097
  function directoryFallback(directory) {
24950
- const canonical = path3.resolve(directory);
24951
- const hash = createHash2("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
25098
+ const canonical = path4.resolve(directory);
25099
+ const hash = createHash3("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
24952
25100
  return `dir:${hash}`;
24953
25101
  }
24954
25102
  function assertDirectoryUsable(canonicalDirectory, rawDirectory) {
@@ -24993,8 +25141,9 @@ function classifyGitError(error, rawDirectory) {
24993
25141
  }
24994
25142
  return new ProjectIdentityError("unknown", rawDirectory, "git rev-list failed while resolving project identity", asError(error));
24995
25143
  }
24996
- function resolveProjectIdentityStrict(directory) {
24997
- const canonical = path3.resolve(directory);
25144
+ function resolveProjectIdentityStrict(directory, allowHomeProject = false) {
25145
+ assertProjectAllowed(directory, allowHomeProject);
25146
+ const canonical = path4.resolve(directory);
24998
25147
  const cached = identityCache.get(canonical);
24999
25148
  if (cached !== undefined) {
25000
25149
  return cached;
@@ -25010,7 +25159,8 @@ function resolveProjectIdentityStrict(directory) {
25010
25159
  encoding: "utf8",
25011
25160
  env: { ...process.env, LC_ALL: "C", LANG: "C" },
25012
25161
  stdio: ["ignore", "pipe", "pipe"],
25013
- timeout: GIT_TIMEOUT_MS
25162
+ timeout: GIT_TIMEOUT_MS,
25163
+ windowsHide: true
25014
25164
  });
25015
25165
  } catch (error) {
25016
25166
  throw classifyGitError(error, directory);
@@ -25023,13 +25173,17 @@ function resolveProjectIdentityStrict(directory) {
25023
25173
  const identity = `git:${rootCommit}`;
25024
25174
  identityCache.set(canonical, identity);
25025
25175
  lastKnownGitIdentityCache.set(canonical, identity);
25176
+ rememberGitIdentity(canonical, identity);
25177
+ const root = gitRootDirectory(canonical);
25178
+ if (root && root !== canonical)
25179
+ rememberGitIdentity(root, identity);
25026
25180
  transientFailureCooldown.delete(canonical);
25027
25181
  dubiousOwnershipFallbackDirectories.delete(canonical);
25028
25182
  transientGitIdentityReuseLoggedDirectories.delete(canonical);
25029
25183
  return identity;
25030
25184
  }
25031
25185
  function shouldUseDirectoryFallback(error) {
25032
- return error.errorClass !== "permission_denied";
25186
+ return error.errorClass !== "home_project_disabled";
25033
25187
  }
25034
25188
  function getActiveCooldown(canonical) {
25035
25189
  const until = transientFailureCooldown.get(canonical);
@@ -25041,7 +25195,7 @@ function getActiveCooldown(canonical) {
25041
25195
  return;
25042
25196
  }
25043
25197
  function lastKnownGitIdentity(canonical) {
25044
- return lastKnownGitIdentityCache.get(canonical) ?? identityCache.get(canonical);
25198
+ return lastKnownGitIdentityCache.get(canonical) ?? identityCache.get(canonical) ?? readRememberedGitIdentity(canonical);
25045
25199
  }
25046
25200
  function nearestLastKnownGitIdentity(canonical) {
25047
25201
  const visited = new Set;
@@ -25052,7 +25206,9 @@ function nearestLastKnownGitIdentity(canonical) {
25052
25206
  const cached = lastKnownGitIdentity(current);
25053
25207
  if (cached !== undefined)
25054
25208
  return { identity: cached, source: current };
25055
- const parent = path3.dirname(current);
25209
+ if (existsSync21(path4.join(current, ".git")))
25210
+ break;
25211
+ const parent = path4.dirname(current);
25056
25212
  if (parent === current)
25057
25213
  break;
25058
25214
  current = parent;
@@ -25081,7 +25237,7 @@ function reuseLastKnownGitIdentity(canonical) {
25081
25237
  return cached.identity;
25082
25238
  }
25083
25239
  function formatDubiousOwnershipWarning(canonical) {
25084
- return `Magic Context: git refused to read ${canonical} (dubious ownership — the repo is owned by a different user). Using a directory-based project identity for now, which keeps memory separate from this repo's normal identity. Fix: git config --global --add safe.directory ${canonical}`;
25240
+ return `Magic Context: git refused to read ${canonical} (dubious ownership — the repo is owned by a different user). Memory features are paused unless a previous git identity is available. Fix: git config --global --add safe.directory ${canonical}`;
25085
25241
  }
25086
25242
  function recordDubiousOwnershipFallback(canonical) {
25087
25243
  dubiousOwnershipFallbackDirectories.add(canonical);
@@ -25090,8 +25246,32 @@ function recordDubiousOwnershipFallback(canonical) {
25090
25246
  dubiousOwnershipLoggedDirectories.add(canonical);
25091
25247
  log3(`[magic-context] ${formatDubiousOwnershipWarning(canonical)}`);
25092
25248
  }
25093
- function resolveProjectIdentity(directory) {
25094
- const canonical = path3.resolve(directory);
25249
+ function canonicalUserHomeDirectory() {
25250
+ const homeDirectory = userHomeDirectoryForIdentity();
25251
+ try {
25252
+ return realpathSync2.native(homeDirectory);
25253
+ } catch {
25254
+ return homeDirectory;
25255
+ }
25256
+ }
25257
+ function isUserHomeDirectory(directory) {
25258
+ if (projectDirectoryKey(directory) === projectDirectoryKey(userHomeDirectoryForIdentity()))
25259
+ return true;
25260
+ try {
25261
+ return projectDirectoryKey(realpathSync2.native(path4.resolve(directory))) === projectDirectoryKey(canonicalUserHomeDirectory());
25262
+ } catch {
25263
+ return false;
25264
+ }
25265
+ }
25266
+ function assertProjectAllowed(directory, allowHomeProject) {
25267
+ const canonical = path4.resolve(directory);
25268
+ if (!allowHomeProject && (isUserHomeDirectory(directory) || isUserHomeDirectory(gitRootDirectory(canonical) ?? canonical))) {
25269
+ throw new ProjectIdentityError("home_project_disabled", directory, "Home project memory is disabled; set allow_home_project to opt in");
25270
+ }
25271
+ }
25272
+ function resolveProjectIdentity(directory, allowHomeProject = false) {
25273
+ assertProjectAllowed(directory, allowHomeProject);
25274
+ const canonical = path4.resolve(directory);
25095
25275
  const cachedFallback = directoryFallbackCache.get(canonical);
25096
25276
  if (cachedFallback !== undefined) {
25097
25277
  if (!hasGitDir(canonical)) {
@@ -25105,27 +25285,30 @@ function resolveProjectIdentity(directory) {
25105
25285
  if (cachedGitIdentity !== undefined) {
25106
25286
  return cachedGitIdentity;
25107
25287
  }
25288
+ throw new ProjectIdentityError("git_identity_unavailable", directory, "Git identity unavailable; memory features paused until the retry cooldown expires");
25108
25289
  }
25109
25290
  return directoryFallback(canonical);
25110
25291
  }
25111
25292
  try {
25112
- return resolveProjectIdentityStrict(directory);
25293
+ return resolveProjectIdentityStrict(directory, allowHomeProject);
25113
25294
  } catch (error) {
25114
25295
  if (error instanceof ProjectIdentityError && shouldUseDirectoryFallback(error)) {
25115
25296
  const fallback = directoryFallback(canonical);
25116
25297
  const hasGitMetadata = hasGitDir(canonical);
25117
25298
  if (!hasGitMetadata) {
25299
+ if (error.errorClass === "permission_denied")
25300
+ throw error;
25118
25301
  directoryFallbackCache.set(canonical, fallback);
25119
25302
  transientFailureCooldown.delete(canonical);
25120
25303
  } else {
25121
25304
  transientFailureCooldown.set(canonical, nowMs() + TRANSIENT_FAILURE_COOLDOWN_MS);
25122
25305
  const cachedGitIdentity = reuseLastKnownGitIdentity(canonical);
25306
+ if (error.errorClass === "dubious_ownership")
25307
+ recordDubiousOwnershipFallback(canonical);
25123
25308
  if (cachedGitIdentity !== undefined) {
25124
25309
  return cachedGitIdentity;
25125
25310
  }
25126
- }
25127
- if (error.errorClass === "dubious_ownership") {
25128
- recordDubiousOwnershipFallback(canonical);
25311
+ throw error;
25129
25312
  }
25130
25313
  return fallback;
25131
25314
  }
@@ -25146,14 +25329,14 @@ function hasGitDir(canonical) {
25146
25329
  function gitRootInAncestorChain(startDirectory) {
25147
25330
  let current = startDirectory;
25148
25331
  while (true) {
25149
- if (existsSync21(path3.join(current, ".git"))) {
25332
+ if (existsSync21(path4.join(current, ".git"))) {
25150
25333
  try {
25151
25334
  return realpathSync2.native(current);
25152
25335
  } catch {
25153
- return path3.resolve(current);
25336
+ return path4.resolve(current);
25154
25337
  }
25155
25338
  }
25156
- const parent = path3.dirname(current);
25339
+ const parent = path4.dirname(current);
25157
25340
  if (parent === current) {
25158
25341
  return null;
25159
25342
  }
@@ -25163,9 +25346,21 @@ function gitRootInAncestorChain(startDirectory) {
25163
25346
  function hasGitDirInAncestorChain(startDirectory) {
25164
25347
  return gitRootInAncestorChain(startDirectory) !== null;
25165
25348
  }
25166
- var GIT_TIMEOUT_MS = 5000, TRANSIENT_FAILURE_COOLDOWN_MS, identityCache, linkedGitWorktreeCache, lastKnownGitIdentityCache, directoryFallbackCache, transientFailureCooldown, dubiousOwnershipFallbackDirectories, dubiousOwnershipLoggedDirectories, dubiousOwnershipWarnedDirectories, transientGitIdentityReuseLoggedDirectories, sessionIdentityCache, execFileSyncForIdentity, nowMs = () => Date.now(), ProjectIdentityError;
25349
+ function gitRootDirectory(canonical) {
25350
+ const direct = gitRootInAncestorChain(canonical);
25351
+ if (direct)
25352
+ return direct;
25353
+ try {
25354
+ const realCanonical = realpathSync2.native(canonical);
25355
+ return realCanonical === canonical ? null : gitRootInAncestorChain(realCanonical);
25356
+ } catch {
25357
+ return null;
25358
+ }
25359
+ }
25360
+ var GIT_TIMEOUT_MS = 5000, TRANSIENT_FAILURE_COOLDOWN_MS, identityCache, linkedGitWorktreeCache, lastKnownGitIdentityCache, directoryFallbackCache, transientFailureCooldown, dubiousOwnershipFallbackDirectories, dubiousOwnershipLoggedDirectories, dubiousOwnershipWarnedDirectories, transientGitIdentityReuseLoggedDirectories, sessionIdentityCache, execFileSyncForIdentity, userHomeDirectoryForIdentity = () => homedir14(), nowMs = () => Date.now(), ProjectIdentityError;
25167
25361
  var init_project_identity = __esm(() => {
25168
25362
  init_logger();
25363
+ init_project_identity_cache();
25169
25364
  TRANSIENT_FAILURE_COOLDOWN_MS = 5 * 60 * 1000;
25170
25365
  identityCache = new Map;
25171
25366
  linkedGitWorktreeCache = new Map;
@@ -26865,6 +27060,11 @@ var init_user_facing_codes = __esm(() => {
26865
27060
  sentence: "Memory maintenance stopped at its hidden agent step limit.",
26866
27061
  action: "This task needs less work per run; changing the model connection will not help."
26867
27062
  },
27063
+ dream_token_budget: {
27064
+ code: "MC-D11",
27065
+ sentence: "Memory maintenance reached its prompt-token budget.",
27066
+ action: "The unfinished items will be retried on the next run."
27067
+ },
26868
27068
  dream_empty_completion: {
26869
27069
  code: "MC-D03",
26870
27070
  sentence: "Memory maintenance received no usable response.",
@@ -27776,8 +27976,8 @@ var init_pi_executable = __esm(() => {
27776
27976
  });
27777
27977
 
27778
27978
  // ../plugin/src/shared/rpc-utils.ts
27779
- import { execFileSync as execFileSync4 } from "node:child_process";
27780
- import { readFileSync as readFileSync14 } from "node:fs";
27979
+ import { execFile, execFileSync as execFileSync4 } from "node:child_process";
27980
+ import { readFileSync as readFileSync15 } from "node:fs";
27781
27981
  function isOwnRpcServerRecord(record) {
27782
27982
  return record.pid === process.pid && record.instance_id !== undefined && ownRpcServerInstanceIds.has(record.instance_id);
27783
27983
  }
@@ -27820,7 +28020,8 @@ function readPsProcessStartTime(pid) {
27820
28020
  const output = rpcIdentityExecFileSync("ps", ["-p", String(pid), "-o", "lstart="], {
27821
28021
  encoding: "utf8",
27822
28022
  timeout: PS_PROBE_TIMEOUT_MS,
27823
- stdio: ["ignore", "pipe", "pipe"]
28023
+ stdio: ["ignore", "pipe", "pipe"],
28024
+ windowsHide: true
27824
28025
  });
27825
28026
  const processStartTime = Date.parse(String(output).trim());
27826
28027
  return Number.isFinite(processStartTime) ? processStartTime : null;
@@ -27895,7 +28096,8 @@ function readWindowsProcess(pid) {
27895
28096
  const output = rpcIdentityExecFileSync("tasklist", ["/FO", "CSV", "/FI", `PID eq ${pid}`], {
27896
28097
  encoding: "utf8",
27897
28098
  timeout: PS_PROBE_TIMEOUT_MS,
27898
- stdio: ["ignore", "pipe", "pipe"]
28099
+ stdio: ["ignore", "pipe", "pipe"],
28100
+ windowsHide: true
27899
28101
  });
27900
28102
  const entries = parseTasklistOutput(String(output));
27901
28103
  if (entries === null)
@@ -27928,7 +28130,8 @@ function readPsProcessCommand(pid) {
27928
28130
  const output = rpcIdentityExecFileSync("ps", ["-p", String(pid), "-o", "command="], {
27929
28131
  encoding: "utf8",
27930
28132
  timeout: PS_PROBE_TIMEOUT_MS,
27931
- stdio: ["ignore", "pipe", "pipe"]
28133
+ stdio: ["ignore", "pipe", "pipe"],
28134
+ windowsHide: true
27932
28135
  });
27933
28136
  return String(output);
27934
28137
  } catch {
@@ -28039,7 +28242,8 @@ function execProcessList(exec, file, args, timeout = PS_PROBE_TIMEOUT_MS) {
28039
28242
  return String(exec(file, [...args], {
28040
28243
  encoding: "utf8",
28041
28244
  timeout,
28042
- stdio: ["ignore", "pipe", "pipe"]
28245
+ stdio: ["ignore", "pipe", "pipe"],
28246
+ windowsHide: true
28043
28247
  }));
28044
28248
  }
28045
28249
  function parseWindowsCreationDate(value) {
@@ -28101,7 +28305,7 @@ function parseWindowsCimOutput(output) {
28101
28305
  pid,
28102
28306
  parentPid: Number.isInteger(parentPid) && parentPid > 0 ? parentPid : null,
28103
28307
  commandLine,
28104
- imageName: commandLine ? executableName(commandTokens(commandLine)[0]) : null,
28308
+ imageName: typeof record.Name === "string" ? record.Name : commandLine ? executableName(commandTokens(commandLine)[0]) : null,
28105
28309
  startTime: parseWindowsCreationDate(record.CreationDate)
28106
28310
  });
28107
28311
  }
@@ -28179,14 +28383,14 @@ function readPosixParentPid(pid) {
28179
28383
  return null;
28180
28384
  }
28181
28385
  }
28182
- function collectAncestorPids(selfPid, parentByPid) {
28386
+ function collectAncestorPids(selfPid, parentByPid, probeParents = true) {
28183
28387
  const ancestors = new Set;
28184
28388
  let current = selfPid;
28185
28389
  for (let depth = 0;depth < MAX_ANCESTOR_WALK_DEPTH; depth += 1) {
28186
28390
  let ppid = null;
28187
28391
  if (parentByPid.has(current)) {
28188
28392
  ppid = parentByPid.get(current) ?? null;
28189
- } else if (rpcIdentityPlatform !== "win32") {
28393
+ } else if (rpcIdentityPlatform !== "win32" && probeParents) {
28190
28394
  ppid = readPosixParentPid(current);
28191
28395
  if (ppid == null && current === process.pid && process.ppid > 0) {
28192
28396
  ppid = process.ppid;
@@ -28203,8 +28407,8 @@ function collectAncestorPids(selfPid, parentByPid) {
28203
28407
  }
28204
28408
  return ancestors;
28205
28409
  }
28206
- function classifyLivePiSnapshot(snapshot) {
28207
- const ancestors = collectAncestorPids(process.pid, snapshot.parentByPid);
28410
+ function classifyLivePiSnapshot(snapshot, probeParents = true) {
28411
+ const ancestors = collectAncestorPids(process.pid, snapshot.parentByPid, probeParents);
28208
28412
  const processIds = new Set;
28209
28413
  const inconclusivePids = new Set;
28210
28414
  const skippedAncestorPids = [];
@@ -28249,8 +28453,9 @@ function inspectLivePiProcesses() {
28249
28453
  if (false) {}
28250
28454
  try {
28251
28455
  if (rpcIdentityPlatform === "win32") {
28252
- const cim = tryReadWindowsCimSnapshot(rpcProcessListExecFileSync);
28253
- const snapshot = cim ?? tryReadWindowsTasklistSnapshot();
28456
+ const now = rpcIdentityNowMs();
28457
+ const cached = windowsProcessSnapshotCache;
28458
+ const snapshot = cached && now >= cached.at && now - cached.at < WINDOWS_PROCESS_SNAPSHOT_TTL_MS ? cached.snapshot : tryReadWindowsCimSnapshot(rpcProcessListExecFileSync) ?? tryReadWindowsTasklistSnapshot();
28254
28459
  if (!snapshot) {
28255
28460
  return {
28256
28461
  state: "unreadable",
@@ -28258,6 +28463,8 @@ function inspectLivePiProcesses() {
28258
28463
  error: "process list unavailable"
28259
28464
  };
28260
28465
  }
28466
+ if (snapshot !== cached?.snapshot)
28467
+ windowsProcessSnapshotCache = { snapshot, at: now };
28261
28468
  rememberWindowsProcessFacts(snapshot.facts);
28262
28469
  return classifyLivePiSnapshot(snapshot);
28263
28470
  }
@@ -28303,7 +28510,81 @@ function parseRpcPortFile(content, fallbackPid = 0) {
28303
28510
  function isValidPort(port) {
28304
28511
  return Number.isInteger(port) && port > 0 && port <= 65535;
28305
28512
  }
28306
- var ownRpcServerInstanceIds, RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, WINDOWS_CIM_PROBE_TIMEOUT_MS = 5000, MAX_ANCESTOR_WALK_DEPTH = 16, OPEN_CODE_COMMAND_MARKERS, TASKLIST_NO_TASKS_PATTERN, WINDOWS_CIM_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress", PI_HARNESS_ARC_MARKERS, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcIdentityProcessKill, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now(), windowsProcessFactsCache = null;
28513
+ function execProcessListAsync(file, args, timeout) {
28514
+ return new Promise((resolve, reject) => {
28515
+ execFile(file, args, { encoding: "utf8", timeout, windowsHide: true, maxBuffer: 8 * 1024 * 1024 }, (error, stdout) => {
28516
+ if (error)
28517
+ reject(error);
28518
+ else
28519
+ resolve(stdout);
28520
+ });
28521
+ });
28522
+ }
28523
+ function inspectProcessesAsync(forceFresh = false) {
28524
+ if (!forceFresh && asyncInspection && rpcIdentityNowMs() < asyncInspectionExpires)
28525
+ return asyncInspection;
28526
+ asyncInspectionExpires = Number.POSITIVE_INFINITY;
28527
+ asyncInspection = (async () => {
28528
+ let snapshot = null;
28529
+ try {
28530
+ if (rpcIdentityPlatform === "win32") {
28531
+ try {
28532
+ const output = await asyncProcessExec("powershell", ["-NoProfile", "-Command", WINDOWS_CIM_COMMAND], WINDOWS_CIM_PROBE_TIMEOUT_MS);
28533
+ const facts = parseWindowsCimOutput(output);
28534
+ if (facts)
28535
+ snapshot = snapshotFromFacts(facts, "cim");
28536
+ } catch {}
28537
+ if (!snapshot) {
28538
+ const entries = parseTasklistOutput(await asyncProcessExec("tasklist", ["/FO", "CSV"], PS_PROBE_TIMEOUT_MS));
28539
+ if (entries)
28540
+ snapshot = snapshotFromFacts(entries.map(({ pid, command }) => ({
28541
+ pid,
28542
+ parentPid: null,
28543
+ commandLine: null,
28544
+ imageName: command,
28545
+ startTime: null
28546
+ })), "tasklist");
28547
+ }
28548
+ } else {
28549
+ const output = await asyncProcessExec("ps", ["-axo", "pid=,ppid=,lstart=,command="], PS_PROBE_TIMEOUT_MS);
28550
+ const facts = [];
28551
+ for (const line of output.split(/\r?\n/)) {
28552
+ const match = /^\s*(\d+)\s+(\d+)\s+(\S+\s+\S+\s+\d+\s+\d+:\d+:\d+\s+\d+)\s+(.+)$/.exec(line);
28553
+ if (!match)
28554
+ continue;
28555
+ const startTime = Date.parse(match[3]);
28556
+ facts.push({
28557
+ pid: Number(match[1]),
28558
+ parentPid: Number(match[2]),
28559
+ commandLine: match[4],
28560
+ imageName: null,
28561
+ startTime: Number.isFinite(startTime) ? startTime : null
28562
+ });
28563
+ }
28564
+ snapshot = facts.length > 0 ? snapshotFromFacts(facts, "ps") : null;
28565
+ }
28566
+ } catch {}
28567
+ const fresh = snapshot !== null;
28568
+ if (snapshot)
28569
+ lastAsyncSnapshot = snapshot;
28570
+ else
28571
+ snapshot = lastAsyncSnapshot;
28572
+ const byPid = new Map(snapshot?.facts.map((fact) => [fact.pid, fact]));
28573
+ return {
28574
+ pi: snapshot ? classifyLivePiSnapshot(snapshot, false) : { state: "unreadable", processIds: [] },
28575
+ ...fresh && snapshot ? { processSnapshot: { source: snapshot.source, facts: snapshot.facts } } : {},
28576
+ evidence: (pid) => ({
28577
+ startTime: byPid.get(pid)?.startTime ?? null,
28578
+ commandLine: byPid.get(pid)?.commandLine ?? byPid.get(pid)?.imageName ?? null
28579
+ }),
28580
+ liveness: (pid) => byPid.has(pid) ? "alive" : fresh ? "dead" : "inconclusive"
28581
+ };
28582
+ })().finally(() => {
28583
+ asyncInspectionExpires = rpcIdentityNowMs() + WINDOWS_PROCESS_SNAPSHOT_TTL_MS;
28584
+ });
28585
+ return asyncInspection;
28586
+ }
28587
+ var ownRpcServerInstanceIds, RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, WINDOWS_CIM_PROBE_TIMEOUT_MS = 5000, WINDOWS_PROCESS_SNAPSHOT_TTL_MS = 2000, MAX_ANCESTOR_WALK_DEPTH = 16, OPEN_CODE_COMMAND_MARKERS, TASKLIST_NO_TASKS_PATTERN, WINDOWS_CIM_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,Name,CommandLine,CreationDate | ConvertTo-Json -Compress", PI_HARNESS_ARC_MARKERS, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcIdentityProcessKill, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now(), windowsProcessFactsCache = null, windowsProcessSnapshotCache = null, asyncProcessExec, asyncInspection, asyncInspectionExpires = 0, lastAsyncSnapshot = null;
28307
28588
  var init_rpc_utils = __esm(() => {
28308
28589
  init_logger();
28309
28590
  init_pi_executable();
@@ -28317,11 +28598,12 @@ var init_rpc_utils = __esm(() => {
28317
28598
  "cljs/dist",
28318
28599
  "dist/bundle/cli"
28319
28600
  ];
28320
- rpcIdentityReadFileSync = readFileSync14;
28601
+ rpcIdentityReadFileSync = readFileSync15;
28321
28602
  rpcIdentityExecFileSync = execFileSync4;
28322
28603
  rpcIdentityProcessKill = process.kill;
28323
28604
  rpcProcessListExecFileSync = execFileSync4;
28324
28605
  rpcIdentityPlatform = process.platform;
28606
+ asyncProcessExec = execProcessListAsync;
28325
28607
  });
28326
28608
  // ../plugin/src/features/magic-context/fail-closed-block.ts
28327
28609
  function attachFailClosedBlockingProcessEvidence(process2, evidence) {
@@ -28463,11 +28745,11 @@ var init_fail_closed_block = __esm(() => {
28463
28745
  });
28464
28746
 
28465
28747
  // ../plugin/src/features/magic-context/message-fts-rowid-map.ts
28466
- import { createHash as createHash3 } from "node:crypto";
28748
+ import { createHash as createHash4 } from "node:crypto";
28467
28749
  var EMPTY_INDEX_CONTENT_HASH, upsertMapStatements, rangeReadyStatements, updateTimeStatements, activeBackfills;
28468
28750
  var init_message_fts_rowid_map = __esm(() => {
28469
28751
  init_write_transaction_timing();
28470
- EMPTY_INDEX_CONTENT_HASH = createHash3("sha256").update("").digest("hex");
28752
+ EMPTY_INDEX_CONTENT_HASH = createHash4("sha256").update("").digest("hex");
28471
28753
  upsertMapStatements = new WeakMap;
28472
28754
  rangeReadyStatements = new WeakMap;
28473
28755
  updateTimeStatements = new WeakMap;
@@ -31651,9 +31933,9 @@ import {
31651
31933
  copyFileSync,
31652
31934
  cpSync,
31653
31935
  existsSync as existsSync22,
31654
- mkdirSync as mkdirSync6,
31936
+ mkdirSync as mkdirSync7,
31655
31937
  readdirSync as readdirSync4,
31656
- readFileSync as readFileSync15,
31938
+ readFileSync as readFileSync16,
31657
31939
  statSync as statSync10,
31658
31940
  unlinkSync as unlinkSync3
31659
31941
  } from "node:fs";
@@ -31736,7 +32018,7 @@ function classifyJunkDiscovery(portFile, raw, staleFiles) {
31736
32018
  log3(`[magic-context] removing stale RPC discovery file ${portFile}: ${reason} record older than 10 minutes`);
31737
32019
  return null;
31738
32020
  }
31739
- function inspectRpcServerDiscovery(storageDir) {
32021
+ function inspectRpcServerDiscovery(storageDir, processes) {
31740
32022
  const rpcRoot = join18(storageDir, "rpc");
31741
32023
  let projectEntries;
31742
32024
  try {
@@ -31794,12 +32076,12 @@ function inspectRpcServerDiscovery(storageDir) {
31794
32076
  }
31795
32077
  if (isOwnRpcServerRecord(record))
31796
32078
  continue;
31797
- const liveness = isPidAlive(record.pid);
32079
+ const liveness = processes ? processes.liveness(record.pid) : isPidAlive(record.pid);
31798
32080
  if (liveness === "dead") {
31799
32081
  staleFiles.push(portFile);
31800
32082
  continue;
31801
32083
  }
31802
- const evidence = readProcessProbeEvidence(record.pid);
32084
+ const evidence = processes ? processes.evidence(record.pid) : readProcessProbeEvidence(record.pid);
31803
32085
  const identity = isPidIdentityPlausible(record, evidence);
31804
32086
  if (identity === "plausible") {
31805
32087
  pids.add(record.pid);
@@ -33108,7 +33390,7 @@ var init_storage_db = __esm(async () => {
33108
33390
  RPC_DISCOVERY_PARSE_GRACE_MS = 10 * 60 * 1000;
33109
33391
  defaultRpcDiscoveryFs = {
33110
33392
  readdirSync: (path, options) => options?.withFileTypes ? readdirSync4(path, { withFileTypes: true }) : readdirSync4(path),
33111
- readFileSync: (path, encoding) => String(readFileSync15(path, encoding)),
33393
+ readFileSync: (path, encoding) => String(readFileSync16(path, encoding)),
33112
33394
  statSync: (path) => ({ mtimeMs: statSync10(path).mtimeMs }),
33113
33395
  unlinkSync: (path) => unlinkSync3(path)
33114
33396
  };
@@ -33121,7 +33403,7 @@ var init_storage_db = __esm(async () => {
33121
33403
  });
33122
33404
 
33123
33405
  // src/lib/database-access.ts
33124
- import { existsSync as existsSync23, writeFileSync as writeFileSync5 } from "node:fs";
33406
+ import { existsSync as existsSync23, writeFileSync as writeFileSync6 } from "node:fs";
33125
33407
  import { pathToFileURL } from "node:url";
33126
33408
  function getPersistedSchemaVersion2(db) {
33127
33409
  return getPersistedSchemaVersion(db);
@@ -33175,7 +33457,7 @@ function openExistingContextDatabaseForMutation(path) {
33175
33457
  async function backupDatabaseSnapshot(db, destination) {
33176
33458
  const serializable = db;
33177
33459
  if (typeof serializable.serialize === "function") {
33178
- writeFileSync5(destination, serializable.serialize(), { flag: "wx" });
33460
+ writeFileSync6(destination, serializable.serialize(), { flag: "wx" });
33179
33461
  return;
33180
33462
  }
33181
33463
  const moduleName = "node:" + "sqlite";
@@ -33457,7 +33739,10 @@ function logRow(db, fromIdentity, toIdentity, tableName, rowId, action, targetRo
33457
33739
  (from_identity, to_identity, table_name, row_id, action, target_row_id, merged_at)
33458
33740
  VALUES (?, ?, ?, ?, ?, ?, ?)`).run(fromIdentity, toIdentity, tableName, rowId, action, targetRowId, mergedAt);
33459
33741
  }
33460
- function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
33742
+ function normalizedContent(value) {
33743
+ return String(value).toLowerCase().replace(/\s+/g, " ").trim();
33744
+ }
33745
+ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt, review) {
33461
33746
  const sourceId = row.id;
33462
33747
  if (typeof sourceId !== "number")
33463
33748
  return false;
@@ -33465,10 +33750,13 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
33465
33750
  FROM memories
33466
33751
  WHERE project_path = ? AND category = ? AND normalized_hash = ? AND id <> ?
33467
33752
  LIMIT 1`).get(toIdentity, row.category, row.normalized_hash, sourceId);
33468
- if (collision && typeof collision.id === "number") {
33753
+ if (collision && normalizedContent(collision.content) !== normalizedContent(row.content)) {
33754
+ db.prepare("UPDATE memories SET normalized_hash = ?, metadata_json = json_set(CASE WHEN json_valid(metadata_json) THEN metadata_json ELSE '{}' END, '$.identity_merge_original_hash', ?, '$.identity_merge_review', ?) WHERE id = ?").run(`${row.normalized_hash}:identity-conflict:${sourceId}`, row.normalized_hash, fromIdentity, sourceId);
33755
+ review = true;
33756
+ } else if (collision && typeof collision.id === "number") {
33469
33757
  const targetId = collision.id;
33470
33758
  const targetSeen = Number(collision.seen_count ?? 1);
33471
- const mergedSeen = Math.max(targetSeen, Number(row.seen_count ?? 1));
33759
+ const mergedSeen = targetSeen + Number(row.seen_count ?? 1);
33472
33760
  const sourceClassifiedAt = Number(row.classified_at ?? 0);
33473
33761
  const targetClassifiedAt = Number(collision.classified_at ?? 0);
33474
33762
  if (sourceClassifiedAt > targetClassifiedAt) {
@@ -33501,8 +33789,9 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
33501
33789
  END`).run(targetId, sourceId);
33502
33790
  db.prepare("DELETE FROM memory_verifications WHERE memory_id = ?").run(sourceId);
33503
33791
  if (mergedSeen !== targetSeen || collision.status === null || collision.status === undefined) {
33504
- db.prepare("UPDATE memories SET seen_count = ?, status = COALESCE(status, 'active'), updated_at = ? WHERE id = ?").run(mergedSeen, mergedAt, targetId);
33792
+ db.prepare("UPDATE memories SET seen_count = ?, status = CASE WHEN ? = 'active' THEN 'active' ELSE COALESCE(status, 'active') END, updated_at = ? WHERE id = ?").run(mergedSeen, row.status, mergedAt, targetId);
33505
33793
  }
33794
+ db.prepare(`UPDATE memories SET first_seen_at = MIN(first_seen_at, ?), last_seen_at = MAX(last_seen_at, ?), retrieval_count = COALESCE(retrieval_count, 0) + ?, merged_from = CASE WHEN merged_from IS NULL OR merged_from = '' THEN ? ELSE merged_from || ',' || ? END WHERE id = ?`).run(row.first_seen_at, row.last_seen_at, Number(row.retrieval_count ?? 0), String(sourceId), String(sourceId), targetId);
33506
33795
  db.prepare(`UPDATE memories
33507
33796
  SET status = 'archived',
33508
33797
  superseded_by_memory_id = ?,
@@ -33518,6 +33807,9 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
33518
33807
  logRow(db, fromIdentity, toIdentity, "memories", String(sourceId), "superseded", String(targetId), mergedAt);
33519
33808
  return true;
33520
33809
  }
33810
+ if (review) {
33811
+ db.prepare("UPDATE memories SET metadata_json = json_set(CASE WHEN json_valid(metadata_json) THEN metadata_json ELSE '{}' END, '$.identity_merge_review', ?) WHERE id = ?").run(fromIdentity, sourceId);
33812
+ }
33521
33813
  const result = db.prepare("UPDATE memories SET project_path = ?, updated_at = ? WHERE id = ? AND project_path = ?").run(toIdentity, mergedAt, sourceId, fromIdentity);
33522
33814
  if ((result.changes ?? 0) === 0)
33523
33815
  return false;
@@ -33532,21 +33824,33 @@ function oldestOpenCycleStart(left, right) {
33532
33824
  const values = [left, right].filter((value) => typeof value === "number" && value > 0);
33533
33825
  return values.length > 0 ? Math.min(...values) : null;
33534
33826
  }
33535
- function reconcileTaskScheduleCollision(db, source, target) {
33536
- const sourceIsNewer = typeof source.last_run_at === "number" && (typeof target.last_run_at !== "number" || source.last_run_at > target.last_run_at);
33827
+ function reconcileTaskScheduleCollision(db, source, target, mergedAt) {
33828
+ const sourceIsNewer = source.last_status === "completed" && (target.last_status !== "completed" || typeof source.last_run_at === "number" && (typeof target.last_run_at !== "number" || source.last_run_at > target.last_run_at));
33537
33829
  const latest = sourceIsNewer ? source : target;
33538
33830
  db.prepare(`UPDATE task_schedule_state
33539
33831
  SET last_run_at = ?, next_due_at = ?, schedule = ?, last_status = ?,
33540
33832
  last_error = ?, retry_count = ?, last_checked_commit = ?,
33541
33833
  last_broad_run_at = ?, retrospective_watermark_ms = ?
33542
- WHERE project_path = ? AND task = ?`).run(nullableMaximum(source.last_run_at, target.last_run_at), latest.next_due_at, latest.schedule, latest.last_status, latest.last_error, latest.retry_count, latest.last_checked_commit, oldestOpenCycleStart(source.last_broad_run_at, target.last_broad_run_at), nullableMaximum(source.retrospective_watermark_ms, target.retrospective_watermark_ms), target.project_path, target.task);
33834
+ WHERE project_path = ? AND task = ?`).run(latest.last_run_at, nextDueAtMs(String(target.schedule ?? ""), Math.max(mergedAt, Number(source.last_run_at ?? 0), Number(target.last_run_at ?? 0))), target.schedule, latest.last_status, latest.last_error, latest.retry_count, latest.last_checked_commit, oldestOpenCycleStart(source.last_broad_run_at, target.last_broad_run_at), nullableMaximum(source.retrospective_watermark_ms, target.retrospective_watermark_ms), target.project_path, target.task);
33543
33835
  }
33544
33836
  function rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt) {
33545
33837
  const rowId = rowKey(db, table.name, row);
33546
33838
  const collision = findUniqueCollision(db, table, row, fromIdentity, toIdentity);
33547
33839
  if (collision) {
33548
33840
  if (table.name === "task_schedule_state") {
33549
- reconcileTaskScheduleCollision(db, row, collision);
33841
+ reconcileTaskScheduleCollision(db, row, collision, mergedAt);
33842
+ }
33843
+ const maximumColumns = {
33844
+ retrospective_processed_windows: ["processed_at"],
33845
+ embedding_identity_active: ["last_active_at"],
33846
+ memory_embedding_watermarks: ["written_memory_id", "embedded_memory_id", "updated_at"],
33847
+ project_state: ["project_memory_epoch", "project_user_profile_version", "updated_at"],
33848
+ project_key_files_version: ["version"]
33849
+ };
33850
+ const columns = maximumColumns[table.name];
33851
+ if (columns) {
33852
+ const targetPredicate = rowPredicate(db, table.name, collision);
33853
+ db.prepare(`UPDATE ${quoteIdentifier(table.name)} SET ${columns.map((column) => `${quoteIdentifier(column)} = ?`).join(", ")} WHERE ${targetPredicate.sql}`).run(...columns.map((column) => nullableMaximum(row[column], collision[column])), ...targetPredicate.values);
33550
33854
  }
33551
33855
  const sourcePredicate = rowPredicate(db, table.name, row);
33552
33856
  const result = db.prepare(`DELETE FROM ${quoteIdentifier(table.name)} WHERE ${sourcePredicate.sql}`).run(...sourcePredicate.values);
@@ -33555,6 +33859,9 @@ function rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt) {
33555
33859
  logRow(db, fromIdentity, toIdentity, table.name, rowId, "collision_deleted", rowKey(db, table.name, collision), mergedAt);
33556
33860
  return true;
33557
33861
  }
33862
+ if (table.name === "task_schedule_state") {
33863
+ db.prepare("UPDATE task_schedule_state SET next_due_at = ? WHERE project_path = ? AND task = ?").run(nextDueAtMs(String(row.schedule ?? ""), Math.max(mergedAt, Number(row.last_run_at ?? 0))), fromIdentity, row.task);
33864
+ }
33558
33865
  const predicate = rowPredicate(db, table.name, row);
33559
33866
  const result = db.prepare(`UPDATE ${quoteIdentifier(table.name)}
33560
33867
  SET ${quoteIdentifier(table.identityColumn)} = ?
@@ -33566,21 +33873,37 @@ function rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt) {
33566
33873
  return true;
33567
33874
  }
33568
33875
  function tableSourceRows(db, table, fromIdentity) {
33569
- return db.prepare(`SELECT rowid, * FROM ${quoteIdentifier(table.name)} WHERE ${quoteIdentifier(table.identityColumn)} = ?`).all(fromIdentity);
33876
+ return db.prepare(`SELECT rowid, * FROM ${quoteIdentifier(table.name)} WHERE ${quoteIdentifier(table.identityColumn)} = ?${table.name === "memories" ? " AND NOT (status = 'archived' AND superseded_by_memory_id IS NOT NULL AND EXISTS (SELECT 1 FROM identity_merge_log l WHERE l.table_name = 'memories' AND l.row_id = CAST(memories.id AS TEXT) AND l.from_identity = memories.project_path AND l.action = 'superseded'))" : ""}`).all(fromIdentity);
33570
33877
  }
33571
33878
  function assertMergeAllowed(db, fromIdentity, toIdentity) {
33879
+ const memberships = db.prepare(`SELECT m.project_path, w.id, w.name FROM workspace_members m JOIN workspaces w ON w.id = m.workspace_id WHERE m.project_path IN (?, ?)`).all(fromIdentity, toIdentity);
33880
+ if (memberships.length === 2 && memberships[0].id !== memberships[1].id) {
33881
+ throw new Error(`Refusing identity merge: different workspaces ${memberships[0].name} and ${memberships[1].name}. Choose membership before merging.`);
33882
+ }
33572
33883
  if (!tableExists3(db, "authority_managed"))
33573
33884
  return;
33574
33885
  const source = db.prepare("SELECT 1 FROM authority_managed WHERE project_path = ? LIMIT 1").get(fromIdentity);
33575
33886
  if (source) {
33576
- throw new Error(`Refusing identity merge: ${fromIdentity} is managed by the Rust module. Drain module authority before re-keying; module-store re-keying is not in scope.`);
33887
+ throw new Error(`Refusing identity merge: ${fromIdentity} is managed by the Rust module: this project runs in Rust mode and its data lives in the module store. Merging will be possible once the single-store migration lands.`);
33577
33888
  }
33578
33889
  const target = db.prepare("SELECT 1 FROM authority_managed WHERE project_path = ? LIMIT 1").get(toIdentity);
33579
33890
  if (target) {
33580
- throw new Error(`Refusing identity merge: ${toIdentity} is managed by the Rust module. Module-owned target pools cannot be re-keyed by this command.`);
33891
+ throw new Error(`Refusing identity merge: ${toIdentity} is managed by the Rust module: this project runs in Rust mode and its data lives in the module store. Merging will be possible once the single-store migration lands.`);
33581
33892
  }
33582
33893
  }
33583
- function auditIdentityMerge(db, fromIdentity, toIdentity) {
33894
+ function memoryDisposition(db, from, to) {
33895
+ const duplicateMemoryIds = [];
33896
+ const reviewMemoryIds = [];
33897
+ for (const row of tableSourceRows(db, { name: "memories", identityColumn: "project_path", derived: false }, from)) {
33898
+ const collision = db.prepare("SELECT content FROM memories WHERE project_path = ? AND category = ? AND normalized_hash = ?").get(to, row.category, row.normalized_hash);
33899
+ if (collision && normalizedContent(collision.content) === normalizedContent(row.content))
33900
+ duplicateMemoryIds.push(Number(row.id));
33901
+ else if (db.prepare("SELECT 1 FROM memories WHERE project_path = ? AND category = ? LIMIT 1").get(to, row.category))
33902
+ reviewMemoryIds.push(Number(row.id));
33903
+ }
33904
+ return { duplicateMemoryIds, reviewMemoryIds };
33905
+ }
33906
+ function auditIdentityMerge(db, fromIdentity, toIdentity, now = Date.now()) {
33584
33907
  const auditedTables = discoverIdentityTables(db).map((table) => ({
33585
33908
  tableName: table.name,
33586
33909
  identityColumn: table.identityColumn,
@@ -33588,12 +33911,31 @@ function auditIdentityMerge(db, fromIdentity, toIdentity) {
33588
33911
  sourceRows: table.derived ? 0 : tableSourceRows(db, table, fromIdentity).length,
33589
33912
  changedRows: 0
33590
33913
  }));
33914
+ const changes = [];
33915
+ for (const table of discoverIdentityTables(db).filter((table) => !table.derived && table.name !== "memories")) {
33916
+ for (const row of tableSourceRows(db, table, fromIdentity)) {
33917
+ const collision = findUniqueCollision(db, table, row, fromIdentity, toIdentity);
33918
+ if (collision)
33919
+ changes.push(`${table.name} ${rowKey(db, table.name, row)}: collapse into ${rowKey(db, table.name, collision)} (target content/configuration retained; progress counters reconciled)`);
33920
+ if (table.name === "workspace_members")
33921
+ changes.push(`workspace ${row.workspace_id}: ${collision ? "collapse aliases" : "transfer source membership"}`);
33922
+ if (table.name === "task_schedule_state") {
33923
+ const schedule = String((collision ?? row).schedule ?? "");
33924
+ changes.push(`task ${row.task}: schedule ${JSON.stringify(row.schedule)} → ${JSON.stringify(schedule)}; next_due_at → ${nextDueAtMs(schedule, Math.max(now, Number(row.last_run_at ?? 0), Number(collision?.last_run_at ?? 0)))}`);
33925
+ }
33926
+ }
33927
+ }
33928
+ const queues = db.prepare("SELECT reason, COUNT(*) AS n FROM dream_queue WHERE project_path IN (?, ?) GROUP BY reason HAVING COUNT(*) > 1").all(fromIdentity, toIdentity);
33929
+ for (const queue of queues)
33930
+ changes.push(`dream_queue ${JSON.stringify(queue.reason)}: ${queue.n} → 1 queued row`);
33591
33931
  return {
33592
33932
  fromIdentity,
33593
33933
  toIdentity,
33934
+ changes,
33594
33935
  auditedTables,
33595
33936
  changedRows: auditedTables.reduce((total, table) => total + table.sourceRows, 0),
33596
- dryRun: true
33937
+ dryRun: true,
33938
+ ...memoryDisposition(db, fromIdentity, toIdentity)
33597
33939
  };
33598
33940
  }
33599
33941
  function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
@@ -33605,11 +33947,14 @@ function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
33605
33947
  }
33606
33948
  assertMergeAllowed(db, fromIdentity, toIdentity);
33607
33949
  const tables = discoverIdentityTables(db);
33608
- const report = auditIdentityMerge(db, fromIdentity, toIdentity);
33950
+ const report = auditIdentityMerge(db, fromIdentity, toIdentity, options.now);
33609
33951
  if (options.dryRun)
33610
33952
  return report;
33953
+ if (report.changedRows === 0)
33954
+ return { ...report, dryRun: false };
33611
33955
  const mergedAt = options.now ?? Date.now();
33612
33956
  const run = db.transaction(() => {
33957
+ assertMergeAllowed(db, fromIdentity, toIdentity);
33613
33958
  if (tableExists3(db, "v22_identity_rekey_map")) {
33614
33959
  db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
33615
33960
  VALUES (?, ?, ?)
@@ -33624,11 +33969,15 @@ function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
33624
33969
  const rows = tableSourceRows(db, table, fromIdentity);
33625
33970
  tableReport.sourceRows = rows.length;
33626
33971
  for (const row of rows) {
33627
- const changed = table.name === "memories" ? mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) : rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt);
33972
+ const changed = table.name === "memories" ? mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt, report.reviewMemoryIds.includes(Number(row.id))) : rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt);
33628
33973
  if (changed)
33629
33974
  tableReport.changedRows += 1;
33630
33975
  }
33631
33976
  }
33977
+ db.prepare(`DELETE FROM dream_queue WHERE project_path = ? AND id NOT IN (SELECT MIN(id) FROM dream_queue WHERE project_path = ? GROUP BY reason)`).run(toIdentity, toIdentity);
33978
+ db.prepare(`UPDATE dream_queue SET started_at = NULL WHERE project_path = ?`).run(toIdentity);
33979
+ db.prepare(`UPDATE git_sweep_coordinator SET lease_holder = NULL, lease_expires_at = NULL, last_swept_at = NULL WHERE project_path = ?`).run(toIdentity);
33980
+ db.prepare(`UPDATE session_meta SET cached_m0_bytes = NULL, cached_m0_project_identity = NULL WHERE cached_m0_project_identity IN (?, ?)`).run(fromIdentity, toIdentity);
33632
33981
  db.prepare(`INSERT INTO project_state
33633
33982
  (project_path, project_memory_epoch, project_user_profile_version, updated_at)
33634
33983
  VALUES (?, 1, 0, ?)
@@ -33645,6 +33994,7 @@ function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
33645
33994
  }
33646
33995
  var IDENTITY_COLUMNS, DERIVED_TABLE_SUFFIXES;
33647
33996
  var init_storage_identity_merge = __esm(() => {
33997
+ init_cron();
33648
33998
  IDENTITY_COLUMNS = new Set(["project_path", "project_identity"]);
33649
33999
  DERIVED_TABLE_SUFFIXES = [
33650
34000
  "_fts",
@@ -33656,84 +34006,88 @@ var init_storage_identity_merge = __esm(() => {
33656
34006
  ];
33657
34007
  });
33658
34008
 
33659
- // src/commands/doctor-merge-identity.ts
34009
+ // src/commands/doctor-identity-splits.ts
34010
+ import { realpathSync as realpathSync4 } from "node:fs";
33660
34011
  import { join as join19 } from "node:path";
33661
- function valueAfter(args, flag) {
33662
- const index = args.indexOf(flag);
33663
- if (index < 0)
33664
- return null;
33665
- const value = args[index + 1];
33666
- if (!value || value.startsWith("--")) {
33667
- throw new Error(`${flag} requires a value`);
33668
- }
33669
- return value;
34012
+ function tableExists4(db, table) {
34013
+ return !!db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(table);
33670
34014
  }
33671
- function parseMergeIdentityArgs(args) {
33672
- const from = valueAfter(args, "--from");
33673
- const to = valueAfter(args, "--to");
33674
- if (!from || !to)
33675
- throw new Error("doctor merge-identity requires --from and --to");
33676
- const dbPath = valueAfter(args, "--db");
33677
- const knownFlags = new Set(["--from", "--to", "--db"]);
33678
- for (let index = 0;index < args.length; index += 1) {
33679
- const arg = args[index];
33680
- if (knownFlags.has(arg)) {
33681
- index += 1;
34015
+ function findIdentitySplits(db, host, includeSingles = false) {
34016
+ if (!tableExists4(db, "session_projects"))
34017
+ return [];
34018
+ const directories = new Map;
34019
+ for (const table of ["session", "session_v2"]) {
34020
+ if (!tableExists4(host, table))
33682
34021
  continue;
34022
+ const rows = host.prepare(`SELECT id, directory FROM ${table} WHERE directory IS NOT NULL`).all();
34023
+ for (const row of rows) {
34024
+ if (!row.directory)
34025
+ continue;
34026
+ let canonical = row.directory;
34027
+ try {
34028
+ canonical = realpathSync4.native(canonical);
34029
+ } catch {}
34030
+ const key = `${table === "session" ? "opencode" : "opencode2"}\x00${row.id}`;
34031
+ const roots = directories.get(key) ?? new Set;
34032
+ roots.add(projectDirectoryKey(canonical));
34033
+ directories.set(key, roots);
33683
34034
  }
33684
- if (arg === "--dry-run" || arg === "--yes")
34035
+ }
34036
+ const byDirectory = new Map;
34037
+ const bindings = db.prepare("SELECT session_id, harness, project_path FROM session_projects WHERE harness IN ('opencode', 'opencode2')").all();
34038
+ for (const row of bindings) {
34039
+ if (!/^(git|dir):/.test(row.project_path))
33685
34040
  continue;
33686
- throw new Error(`Unknown doctor merge-identity option: ${arg}`);
34041
+ for (const directory of directories.get(`${row.harness}\x00${row.session_id}`) ?? []) {
34042
+ const identities = byDirectory.get(directory) ?? new Set;
34043
+ identities.add(row.project_path);
34044
+ byDirectory.set(directory, identities);
34045
+ }
33687
34046
  }
33688
- return {
33689
- from,
33690
- to,
33691
- dryRun: args.includes("--dry-run"),
33692
- yes: args.includes("--yes"),
33693
- ...dbPath ? { dbPath } : {}
33694
- };
34047
+ const count = (table, identity) => tableExists4(db, table) ? db.prepare(`SELECT COUNT(*) AS n FROM ${table} WHERE project_path = ?`).get(identity).n : 0;
34048
+ return [...byDirectory].filter(([, identities]) => includeSingles || identities.size > 1).sort(([a], [b]) => a.localeCompare(b)).map(([directory, identities]) => ({
34049
+ directory,
34050
+ identities: [...identities].sort().map((identity) => ({
34051
+ identity,
34052
+ sessions: count("session_projects", identity),
34053
+ memories: count("memories", identity),
34054
+ notes: count("notes", identity),
34055
+ dreamer: [
34056
+ "dream_queue",
34057
+ "dream_runs",
34058
+ "task_schedule_state",
34059
+ "retrospective_processed_windows"
34060
+ ].reduce((n, table) => n + count(table, identity), 0)
34061
+ }))
34062
+ }));
33695
34063
  }
33696
- function printReport(report) {
33697
- console.log(`Identity merge ${report.dryRun ? "preview" : "complete"}:`);
33698
- console.log(` from: ${report.fromIdentity}`);
33699
- console.log(` to: ${report.toIdentity}`);
33700
- console.log(" audited project-scoped tables:");
33701
- for (const table of report.auditedTables) {
33702
- const suffix = table.derived ? " (derived; updated by source triggers)" : "";
33703
- console.log(` ${table.tableName} [${table.identityColumn}]${suffix}: ${report.dryRun ? table.sourceRows : table.changedRows} row(s)`);
33704
- }
33705
- console.log(` rows changed: ${report.changedRows}`);
33706
- if (report.dryRun) {
33707
- console.log(" no database writes performed");
33708
- }
34064
+ function formatIdentitySplits(splits) {
34065
+ return splits.flatMap((split) => [
34066
+ `Project identity split: ${split.directory} (read-only; no merge performed)`,
34067
+ ...split.identities.map((row) => ` ${row.identity}: ${row.sessions} sessions, ${row.memories} memories, ${row.notes} notes, ${row.dreamer} dreamer rows (identity-wide counts)`)
34068
+ ]);
33709
34069
  }
33710
- function openMergeDatabase(path, mutate) {
33711
- const db = mutate ? openExistingContextDatabaseForMutation(path) : openExistingContextDatabase(path, { readonly: true });
34070
+ function diagnoseIdentitySplits() {
34071
+ const db = openExistingContextDatabase(join19(getMagicContextStorageDir(), "context.db"), {
34072
+ readonly: true
34073
+ });
33712
34074
  if (!db)
33713
- throw new Error(`Context database does not exist: ${path}`);
33714
- return db;
33715
- }
33716
- function runMergeIdentityCli(args) {
33717
- const options = parseMergeIdentityArgs(args);
33718
- if (!options.dryRun && !options.yes) {
33719
- console.error("Refusing to mutate context.db without explicit --yes. Re-run with --yes, or use --dry-run to preview.");
33720
- return 2;
33721
- }
33722
- const dbPath = options.dbPath ?? join19(getMagicContextStorageDir(), "context.db");
33723
- const db = openMergeDatabase(dbPath, !options.dryRun);
34075
+ return [];
34076
+ let host = null;
33724
34077
  try {
33725
- const report = mergeProjectIdentities(db, options.from, options.to, {
33726
- dryRun: options.dryRun
33727
- });
33728
- printReport(report);
33729
- return 0;
34078
+ host = openExistingDatabase(resolveOpenCodeDbPath().path, { readonly: true });
34079
+ if (!host)
34080
+ return ["Identity split check skipped: OpenCode session directories unavailable."];
34081
+ return formatIdentitySplits(findIdentitySplits(db, host));
33730
34082
  } finally {
34083
+ host?.close();
33731
34084
  db.close();
33732
34085
  }
33733
34086
  }
33734
- var init_doctor_merge_identity = __esm(async () => {
33735
- init_storage_identity_merge();
34087
+ var init_doctor_identity_splits = __esm(async () => {
34088
+ init_project_identity_cache();
33736
34089
  init_data_path();
34090
+ init_opencode_db_path();
33737
34091
  await init_database_access();
33738
34092
  });
33739
34093
 
@@ -33746,7 +34100,7 @@ import {
33746
34100
  copyFileSync as copyFileSync2,
33747
34101
  existsSync as existsSync24,
33748
34102
  openSync as openSync4,
33749
- renameSync as renameSync4,
34103
+ renameSync as renameSync5,
33750
34104
  rmSync as rmSync3,
33751
34105
  statSync as statSync11
33752
34106
  } from "node:fs";
@@ -34001,15 +34355,15 @@ function activateReplacement(dbPath, replacementPath, originalAsidePath) {
34001
34355
  if (!existsSync24(from))
34002
34356
  continue;
34003
34357
  const to = `${originalAsidePath}${suffix}`;
34004
- renameSync4(from, to);
34358
+ renameSync5(from, to);
34005
34359
  movedOriginals.push({ from, to });
34006
34360
  }
34007
- renameSync4(replacementPath, dbPath);
34361
+ renameSync5(replacementPath, dbPath);
34008
34362
  return movedOriginals.map(({ to }) => to);
34009
34363
  } catch (error) {
34010
34364
  for (const moved of movedOriginals.reverse()) {
34011
34365
  if (existsSync24(moved.to) && !existsSync24(moved.from))
34012
- renameSync4(moved.to, moved.from);
34366
+ renameSync5(moved.to, moved.from);
34013
34367
  }
34014
34368
  throw error;
34015
34369
  }
@@ -34240,6 +34594,232 @@ var init_doctor_repair_db = __esm(async () => {
34240
34594
  ];
34241
34595
  });
34242
34596
 
34597
+ // src/commands/doctor-merge-identity.ts
34598
+ import { execFileSync as execFileSync5 } from "node:child_process";
34599
+ import { createHash as createHash5 } from "node:crypto";
34600
+ import {
34601
+ cpSync as cpSync2,
34602
+ existsSync as existsSync25,
34603
+ mkdirSync as mkdirSync8,
34604
+ mkdtempSync,
34605
+ readdirSync as readdirSync5,
34606
+ readFileSync as readFileSync17,
34607
+ renameSync as renameSync6,
34608
+ writeFileSync as writeFileSync7
34609
+ } from "node:fs";
34610
+ import { dirname as dirname13, join as join21 } from "node:path";
34611
+ function parseMergeIdentityArgs(args) {
34612
+ const values = {};
34613
+ const switches = new Set(["--apply", "--force", "--dry-run", "--yes"]);
34614
+ for (let i = 0;i < args.length; i++) {
34615
+ const flag = args[i];
34616
+ if (["--from", "--to", "--db", "--host-db"].includes(flag)) {
34617
+ const value = args[++i];
34618
+ if (!value || value.startsWith("--"))
34619
+ throw new Error(`${flag} requires a value`);
34620
+ if (values[flag])
34621
+ throw new Error(`Repeated option: ${flag}`);
34622
+ values[flag] = value;
34623
+ } else if (!switches.has(flag))
34624
+ throw new Error(`Unknown doctor merge-identities option: ${flag}`);
34625
+ }
34626
+ if (Boolean(values["--from"]) !== Boolean(values["--to"]))
34627
+ throw new Error("Supply both --from and --to");
34628
+ const apply = args.includes("--apply") || args.includes("--yes");
34629
+ if (apply && (!values["--from"] || args.includes("--dry-run")))
34630
+ throw new Error("--apply requires --from/--to and cannot be combined with --dry-run");
34631
+ return {
34632
+ from: values["--from"],
34633
+ to: values["--to"],
34634
+ dbPath: values["--db"],
34635
+ hostPath: values["--host-db"],
34636
+ dryRun: !apply,
34637
+ yes: apply,
34638
+ force: args.includes("--force")
34639
+ };
34640
+ }
34641
+ function printReport(report) {
34642
+ console.log(`Identity merge ${report.dryRun ? "preview" : "complete"}: ${report.fromIdentity} → ${report.toIdentity}`);
34643
+ for (const table of report.auditedTables) {
34644
+ console.log(` ${table.tableName}: ${report.dryRun ? table.sourceRows : table.changedRows} row(s)${table.derived ? " (derived; maintained by triggers)" : ""}`);
34645
+ }
34646
+ for (const change of report.changes)
34647
+ console.log(` ${change}`);
34648
+ console.log(` identical memories collapsed: ${report.duplicateMemoryIds.join(", ") || "none"}`);
34649
+ console.log(` potential content conflicts kept for review (same category): ${report.reviewMemoryIds.join(", ") || "none"}`);
34650
+ console.log(" Workspace aliases collapse; source-only membership transfers. Target schedules win; next_due_at is recomputed. Queued reasons deduplicate; run history and processed windows remain.");
34651
+ console.log(" Git indexes move; sweep leases reset for rebuilding. Existing memory embeddings remain valid (content unchanged); FTS triggers rekey indexes.");
34652
+ if (!report.changedRows)
34653
+ console.log(" No-op: no source rows remain to move.");
34654
+ if (report.dryRun)
34655
+ console.log(" No writes. Review this preview, then repeat with --apply to confirm.");
34656
+ }
34657
+ function resolveReadOnly(directory) {
34658
+ if (!existsSync25(directory))
34659
+ return;
34660
+ try {
34661
+ const roots = execFileSync5("git", ["rev-list", "--max-parents=0", "HEAD"], {
34662
+ cwd: directory,
34663
+ windowsHide: true,
34664
+ encoding: "utf8",
34665
+ timeout: 5000,
34666
+ stdio: ["ignore", "pipe", "pipe"]
34667
+ }).trim().split(/\s+/).filter((root) => /^[0-9a-f]{40,64}$/.test(root)).sort();
34668
+ if (roots[0])
34669
+ return `git:${roots[0]}`;
34670
+ } catch {}
34671
+ try {
34672
+ const result = execFileSync5("git", ["rev-parse", "--is-inside-work-tree"], {
34673
+ cwd: directory,
34674
+ windowsHide: true,
34675
+ encoding: "utf8",
34676
+ timeout: 5000,
34677
+ stdio: ["ignore", "pipe", "pipe"]
34678
+ });
34679
+ if (result.trim() === "true")
34680
+ return;
34681
+ } catch (error) {
34682
+ if (String(error.stderr).includes("not a git repository"))
34683
+ return `dir:${createHash5("md5").update(projectDirectoryKey(directory)).digest("hex").slice(0, 12)}`;
34684
+ }
34685
+ return;
34686
+ }
34687
+ function observations(db, hostPath, storageDir) {
34688
+ const host = openExistingDatabase(hostPath, { readonly: true });
34689
+ let rows = [];
34690
+ try {
34691
+ rows = host ? findIdentitySplits(db, host, true) : [];
34692
+ } finally {
34693
+ host?.close();
34694
+ }
34695
+ const add = (directory, identity) => {
34696
+ if (!/^(git|dir):/.test(identity))
34697
+ return;
34698
+ directory = projectDirectoryKey(directory);
34699
+ let row = rows.find((item) => item.directory === directory);
34700
+ if (!row) {
34701
+ row = { directory, identities: [] };
34702
+ rows.push(row);
34703
+ }
34704
+ if (!row.identities.some((item) => item.identity === identity))
34705
+ row.identities.push({ identity, sessions: 0, memories: 0, notes: 0, dreamer: 0 });
34706
+ };
34707
+ const sidecars = join21(storageDir, "project-identities");
34708
+ if (existsSync25(sidecars))
34709
+ for (const file of readdirSync5(sidecars)) {
34710
+ if (!file.endsWith(".json"))
34711
+ continue;
34712
+ try {
34713
+ const record = JSON.parse(readFileSync17(join21(sidecars, file), "utf8"));
34714
+ if (typeof record.directory === "string" && typeof record.identity === "string")
34715
+ add(record.directory, record.identity);
34716
+ } catch {}
34717
+ }
34718
+ for (const row of db.prepare("SELECT project_path, display_path FROM workspace_members").all())
34719
+ add(row.display_path, row.project_path);
34720
+ return rows;
34721
+ }
34722
+ function runMergeIdentityCli(args, deps = {}) {
34723
+ const options = parseMergeIdentityArgs(args);
34724
+ const dbPath = options.dbPath ?? join21(getMagicContextStorageDir(), "context.db");
34725
+ const storageDir = dirname13(dbPath);
34726
+ const hostPath = options.hostPath ?? (options.dbPath ? join21(storageDir, "host.db") : resolveOpenCodeDbPath().path);
34727
+ let db = openExistingContextDatabase(dbPath, {
34728
+ readonly: true,
34729
+ minimumSupportedVersion: CLI_SCHEMA_FLOOR_VERSION
34730
+ });
34731
+ if (!db)
34732
+ throw new Error(`Context database does not exist: ${dbPath}`);
34733
+ let directories = [];
34734
+ try {
34735
+ const observed = observations(db, hostPath, storageDir);
34736
+ if (!options.from || !options.to) {
34737
+ for (const split of observed.filter((row) => row.identities.length > 1)) {
34738
+ const target = resolveReadOnly(split.directory) ?? split.identities.map((row) => row.identity).filter((id) => id.startsWith("git:")).sort()[0];
34739
+ console.log(`Project identity split: ${split.directory}`);
34740
+ for (const row of split.identities)
34741
+ if (row.identity !== target)
34742
+ console.log(` ${row.identity} → ${target ?? "unresolved target"}`);
34743
+ }
34744
+ if (!observed.some((row) => row.identities.length > 1))
34745
+ console.log("No detected identity splits.");
34746
+ return 0;
34747
+ }
34748
+ if (options.from === options.to)
34749
+ throw new Error(`Source and target identities must differ: ${options.from}`);
34750
+ for (const identity of [options.from, options.to]) {
34751
+ const known = auditIdentityMerge(db, identity, options.to).changedRows > 0 || db.prepare("SELECT 1 FROM v22_identity_rekey_map WHERE old_project_path = ? OR new_project_path = ?").get(identity, identity);
34752
+ if (!known)
34753
+ throw new Error(`Unknown identity: ${identity}`);
34754
+ }
34755
+ const sourceDirs = observed.filter((row) => row.identities.some((item) => item.identity === options.from)).map((row) => row.directory);
34756
+ const targetDirs = observed.filter((row) => row.identities.some((item) => item.identity === options.to)).map((row) => row.directory);
34757
+ directories = [...new Set([...sourceDirs, ...targetDirs])];
34758
+ const alreadyMerged = auditIdentityMerge(db, options.from, options.to).changedRows === 0 && db.prepare("SELECT 1 FROM v22_identity_rekey_map WHERE old_project_path = ? AND new_project_path = ?").get(options.from, options.to);
34759
+ if (!alreadyMerged && options.from.startsWith("git:") && options.to.startsWith("git:") && (!sourceDirs.length || !targetDirs.length || sourceDirs.some((dir) => !targetDirs.includes(dir)) || targetDirs.some((dir) => !sourceDirs.includes(dir))))
34760
+ throw new Error(`Refusing different directories for ${options.from} (${sourceDirs.join(", ") || "unknown"}) and ${options.to} (${targetDirs.join(", ") || "unknown"})`);
34761
+ if (!options.force && !directories.some((directory) => resolveReadOnly(directory) === options.to))
34762
+ throw new Error(`Target ${options.to} does not resolve for any observed directory on this machine; use --force only after reviewing the identity.`);
34763
+ const preview = mergeProjectIdentities(db, options.from, options.to, { dryRun: true });
34764
+ printReport(preview);
34765
+ if (options.dryRun)
34766
+ return 0;
34767
+ } finally {
34768
+ db.close();
34769
+ }
34770
+ const { from, to } = options;
34771
+ if (!from || !to)
34772
+ return 0;
34773
+ const holders = (deps.inspectHolders ?? defaultInspectHolders)(storageDir);
34774
+ const probe = (deps.probe ?? probeHostProcessesUsing)({
34775
+ files: [dbPath, `${dbPath}-wal`, `${dbPath}-shm`],
34776
+ directories: []
34777
+ });
34778
+ if (!holders.safe || probe.status !== "free")
34779
+ throw new Error(`Refusing merge: close OpenCode, Pi, OpenCode 2 and ck-mc. ${holders.blockers.join(", ")} ${holders.uncertainty ?? ""} ${probe.status === "in_use" ? `context.db holders: ${probe.pids.join(", ")}` : probe.status === "unknown" ? probe.reason : ""}`);
34780
+ const backup = mkdtempSync(join21(storageDir, "identity-merge-backup-"));
34781
+ const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
34782
+ console.log(`Backup directory: ${backup}`);
34783
+ console.log(`Restore with hosts closed: rm -f ${quote(`${dbPath}-wal`)} ${quote(`${dbPath}-shm`)}; cp ${quote(join21(backup, "context.db"))} ${quote(dbPath)}; if test -f ${quote(join21(backup, "context.db-wal"))}; then cp ${quote(join21(backup, "context.db-wal"))} ${quote(`${dbPath}-wal`)}; fi`);
34784
+ const sidecarRoot = join21(storageDir, "project-identities");
34785
+ const sidecarBackup = join21(backup, "project-identities");
34786
+ mkdirSync8(sidecarBackup);
34787
+ if (existsSync25(sidecarRoot))
34788
+ cpSync2(sidecarRoot, sidecarBackup, { recursive: true });
34789
+ console.log(`Restore identity sidecars too: rm -rf ${quote(sidecarRoot)}; cp -R ${quote(sidecarBackup)} ${quote(sidecarRoot)}`);
34790
+ copyDatabaseBundle(dbPath, join21(backup, "context.db"));
34791
+ db = openExistingDatabase(dbPath, { readonly: false });
34792
+ if (!db)
34793
+ throw new Error(`Context database disappeared: ${dbPath}`);
34794
+ try {
34795
+ printReport(mergeProjectIdentities(db, from, to));
34796
+ } finally {
34797
+ db.close();
34798
+ }
34799
+ if (to.startsWith("git:"))
34800
+ for (const directory of directories) {
34801
+ const root = join21(storageDir, "project-identities");
34802
+ mkdirSync8(root, { recursive: true });
34803
+ const path = join21(root, `${createHash5("sha256").update(projectDirectoryKey(directory)).digest("hex")}.json`);
34804
+ const temporary = `${path}.merge.tmp`;
34805
+ writeFileSync7(temporary, JSON.stringify({ directory: projectDirectoryKey(directory), identity: options.to }), { mode: 384 });
34806
+ renameSync6(temporary, path);
34807
+ }
34808
+ return 0;
34809
+ }
34810
+ var init_doctor_merge_identity = __esm(async () => {
34811
+ init_project_identity_cache();
34812
+ init_storage_identity_merge();
34813
+ init_data_path();
34814
+ init_opencode_db_path();
34815
+ init_doctor_opencode2_cache();
34816
+ await __promiseAll([
34817
+ init_database_access(),
34818
+ init_doctor_identity_splits(),
34819
+ init_doctor_repair_db()
34820
+ ]);
34821
+ });
34822
+
34243
34823
  // src/commands/doctor-hidden-sessions.ts
34244
34824
  function parseMetadata(value) {
34245
34825
  if (value && typeof value === "object" && !Array.isArray(value)) {
@@ -34330,20 +34910,20 @@ var init_migration_paths = __esm(() => {
34330
34910
  });
34331
34911
 
34332
34912
  // src/commands/migrate.ts
34333
- import { createHash as createHash4, randomBytes as randomBytes2 } from "node:crypto";
34334
- import { existsSync as existsSync25, mkdirSync as mkdirSync7, renameSync as renameSync5, unlinkSync as unlinkSync4 } from "node:fs";
34335
- import { dirname as dirname13, join as join21 } from "node:path";
34913
+ import { createHash as createHash6, randomBytes as randomBytes2 } from "node:crypto";
34914
+ import { existsSync as existsSync26, mkdirSync as mkdirSync9, renameSync as renameSync7, unlinkSync as unlinkSync4 } from "node:fs";
34915
+ import { dirname as dirname14, join as join22 } from "node:path";
34336
34916
  function defaultOpenCodeDbPath() {
34337
34917
  return getOpenCodeDatabasePath();
34338
34918
  }
34339
34919
  function defaultCortexkitDbPath() {
34340
- return join21(getMagicContextStorageDir(), "context.db");
34920
+ return join22(getMagicContextStorageDir(), "context.db");
34341
34921
  }
34342
34922
  function defaultPiSessionsRoot() {
34343
34923
  return getPiSessionsRoot();
34344
34924
  }
34345
34925
  function defaultFs() {
34346
- return { writeFileAtomic, unlinkSync: unlinkSync4, existsSync: existsSync25, renameSync: renameSync5, mkdirSync: mkdirSync7 };
34926
+ return { writeFileAtomic, unlinkSync: unlinkSync4, existsSync: existsSync26, renameSync: renameSync7, mkdirSync: mkdirSync9 };
34347
34927
  }
34348
34928
  function stmt(db, sql) {
34349
34929
  return db.prepare(sql);
@@ -34370,7 +34950,7 @@ function shortId() {
34370
34950
  return randomBytes2(4).toString("hex");
34371
34951
  }
34372
34952
  function migrationKeyFor(sourceSessionId, targetHarness) {
34373
- return createHash4("sha256").update(`${sourceSessionId}
34953
+ return createHash6("sha256").update(`${sourceSessionId}
34374
34954
  ${targetHarness}`).digest("hex");
34375
34955
  }
34376
34956
  function moduleManagedProjectForSession(db, sessionId) {
@@ -34409,7 +34989,7 @@ function sweepPendingMigrations(db, fs = defaultFs()) {
34409
34989
  }
34410
34990
  if (row.phase === "db_committed") {
34411
34991
  if (fs.existsSync(row.stage_path)) {
34412
- fs.mkdirSync(dirname13(row.final_path), { recursive: true });
34992
+ fs.mkdirSync(dirname14(row.final_path), { recursive: true });
34413
34993
  fs.renameSync(row.stage_path, row.final_path);
34414
34994
  stmt(db, "DELETE FROM migration_pending WHERE migration_key = ?").run(row.migration_key);
34415
34995
  report.rolledForward += 1;
@@ -34439,7 +35019,7 @@ function claimJournalIdentity(args) {
34439
35019
  migration_key, source_session_id, target_harness, pi_session_id,
34440
35020
  final_path, stage_path, content_sha256, phase, created_at
34441
35021
  ) VALUES (?, ?, ?, ?, ?, ?, '', 'staged', ?)
34442
- ON CONFLICT(migration_key) DO NOTHING`).run(args.migrationKey, args.sourceSessionId, args.targetHarness, piSessionId, args.finalPathFor(piSessionId), join21(args.stageDir, `${args.migrationKey}.jsonl`), args.now);
35022
+ ON CONFLICT(migration_key) DO NOTHING`).run(args.migrationKey, args.sourceSessionId, args.targetHarness, piSessionId, args.finalPathFor(piSessionId), join22(args.stageDir, `${args.migrationKey}.jsonl`), args.now);
34443
35023
  const row = readPendingMigration(args.db, args.migrationKey);
34444
35024
  if (!row) {
34445
35025
  throw new Error("migration journal row disappeared during insert; aborting migration");
@@ -34944,7 +35524,7 @@ function migrateOpenCodeSessionToPi(opts) {
34944
35524
  const provider = opts.provider ?? model.provider;
34945
35525
  const modelId = opts.modelId ?? model.modelId;
34946
35526
  const cwd = session.directory ?? session.path ?? process.cwd();
34947
- const outputDir = join21(piSessionsRoot, projectPathToPiDirSlug(cwd));
35527
+ const outputDir = join22(piSessionsRoot, projectPathToPiDirSlug(cwd));
34948
35528
  const targetHarness = opts.targetHarness ?? "pi";
34949
35529
  const moduleManagedProject = cortexkitDb === null ? null : moduleManagedProjectForSession(cortexkitDb, session.id);
34950
35530
  if (moduleManagedProject) {
@@ -34968,8 +35548,8 @@ function migrateOpenCodeSessionToPi(opts) {
34968
35548
  migrationKey,
34969
35549
  sourceSessionId: session.id,
34970
35550
  targetHarness,
34971
- finalPathFor: (id) => join21(outputDir, `${formatPiFilenameTimestamp(now)}_${id}.jsonl`),
34972
- stageDir: join21(dirname13(piSessionsRoot), MIGRATION_STAGE_DIRNAME),
35551
+ finalPathFor: (id) => join22(outputDir, `${formatPiFilenameTimestamp(now)}_${id}.jsonl`),
35552
+ stageDir: join22(dirname14(piSessionsRoot), MIGRATION_STAGE_DIRNAME),
34973
35553
  now: now.getTime()
34974
35554
  });
34975
35555
  piSessionId = claimed.row.pi_session_id;
@@ -34978,7 +35558,7 @@ function migrateOpenCodeSessionToPi(opts) {
34978
35558
  journalResumed = claimed.resumed;
34979
35559
  } else {
34980
35560
  piSessionId = generateUuidV7(now);
34981
- finalPath = join21(outputDir, `${formatPiFilenameTimestamp(now)}_${piSessionId}.jsonl`);
35561
+ finalPath = join22(outputDir, `${formatPiFilenameTimestamp(now)}_${piSessionId}.jsonl`);
34982
35562
  stagePath = "";
34983
35563
  }
34984
35564
  const buildResult = buildPiEntries({
@@ -35017,11 +35597,11 @@ function migrateOpenCodeSessionToPi(opts) {
35017
35597
  `;
35018
35598
  if (!opts.dryRun) {
35019
35599
  if (journalActive && cortexkitDb !== null && migrationKey !== undefined && plan) {
35020
- const contentSha256 = createHash4("sha256").update(jsonl, "utf8").digest("hex");
35600
+ const contentSha256 = createHash6("sha256").update(jsonl, "utf8").digest("hex");
35021
35601
  commitStagedChecksum(cortexkitDb, migrationKey, contentSha256);
35022
35602
  fs.writeFileAtomic(stagePath, jsonl);
35023
35603
  plan.commit(migrationKey);
35024
- fs.mkdirSync(dirname13(finalPath), { recursive: true });
35604
+ fs.mkdirSync(dirname14(finalPath), { recursive: true });
35025
35605
  fs.renameSync(stagePath, finalPath);
35026
35606
  stmt(cortexkitDb, "DELETE FROM migration_pending WHERE migration_key = ?").run(migrationKey);
35027
35607
  } else {
@@ -35291,9 +35871,9 @@ var init_relocate_memory = __esm(() => {
35291
35871
  });
35292
35872
 
35293
35873
  // src/commands/migrate-session.ts
35294
- import { existsSync as existsSync26, realpathSync as realpathSync4 } from "node:fs";
35295
- import { homedir as homedir14 } from "node:os";
35296
- import path4, { join as join22 } from "node:path";
35874
+ import { existsSync as existsSync27, realpathSync as realpathSync5 } from "node:fs";
35875
+ import { homedir as homedir15 } from "node:os";
35876
+ import path5, { join as join23 } from "node:path";
35297
35877
  function existingSessionColumns(db) {
35298
35878
  const rows = db.prepare("PRAGMA table_info(session)").all();
35299
35879
  return new Set(rows.map((r) => r.name).filter((n) => typeof n === "string"));
@@ -35377,7 +35957,7 @@ function planMigrateSession(sessionId, rawTargetDirectory, deps) {
35377
35957
  ocProjectId = "global";
35378
35958
  ocWorktree = globalRow.worktree || "/";
35379
35959
  }
35380
- const sessionPath = path4.relative(ocWorktree, targetDirectory);
35960
+ const sessionPath = path5.relative(ocWorktree, targetDirectory);
35381
35961
  const ownershipRow = deps.contextDb.prepare("SELECT project_path FROM session_projects WHERE session_id = ? AND harness = 'opencode'").get(sessionId);
35382
35962
  const fromMcIdentity = ownershipRow?.project_path ?? (sessionRow.directory ? deps.resolveIdentity(sessionRow.directory) : "");
35383
35963
  const toMcIdentity = deps.resolveIdentity(targetDirectory);
@@ -35503,18 +36083,18 @@ function defaultOpenCodeDbPath2() {
35503
36083
  return getOpenCodeDatabasePath();
35504
36084
  }
35505
36085
  function defaultContextDbPath() {
35506
- return join22(getMagicContextStorageDir(), "context.db");
36086
+ return join23(getMagicContextStorageDir(), "context.db");
35507
36087
  }
35508
36088
  function realDeps(opencodeDb, contextDb) {
35509
36089
  return {
35510
36090
  opencodeDb,
35511
36091
  contextDb,
35512
36092
  resolveIdentity: resolveProjectIdentity,
35513
- hasGitDir: (dir) => existsSync26(join22(dir, ".git")),
35514
- realpath: (p) => realpathSync4(p)
36093
+ hasGitDir: (dir) => existsSync27(join23(dir, ".git")),
36094
+ realpath: (p) => realpathSync5(p)
35515
36095
  };
35516
36096
  }
35517
- function valueAfter2(args, flag) {
36097
+ function valueAfter(args, flag) {
35518
36098
  const index = args.indexOf(flag);
35519
36099
  if (index === -1)
35520
36100
  return null;
@@ -35568,11 +36148,11 @@ async function runMigrateSessionCli(args) {
35568
36148
  printMigrateSessionHelp();
35569
36149
  return 0;
35570
36150
  }
35571
- const sessionId = valueAfter2(args, "--session");
35572
- const toDir = valueAfter2(args, "--to");
36151
+ const sessionId = valueAfter(args, "--session");
36152
+ const toDir = valueAfter(args, "--to");
35573
36153
  const dryRun = args.includes("--dry-run");
35574
36154
  const skipConfirm = args.includes("--yes");
35575
- const memoriesFlag = valueAfter2(args, "--memories");
36155
+ const memoriesFlag = valueAfter(args, "--memories");
35576
36156
  if (!sessionId) {
35577
36157
  console.error("Missing required flag: --session <id>");
35578
36158
  printMigrateSessionHelp();
@@ -35588,8 +36168,8 @@ async function runMigrateSessionCli(args) {
35588
36168
  printMigrateSessionHelp();
35589
36169
  return 1;
35590
36170
  }
35591
- const expandedTo = toDir.startsWith("~") ? join22(homedir14(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
35592
- if (!existsSync26(expandedTo)) {
36171
+ const expandedTo = toDir.startsWith("~") ? join23(homedir15(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
36172
+ if (!existsSync27(expandedTo)) {
35593
36173
  console.error(`Target directory does not exist: ${expandedTo}`);
35594
36174
  return 1;
35595
36175
  }
@@ -35741,9 +36321,9 @@ var init_migrate_session = __esm(async () => {
35741
36321
  });
35742
36322
 
35743
36323
  // ../plugin/src/features/magic-context/v22-deferred-backfill.ts
35744
- import { createHash as createHash5 } from "node:crypto";
35745
- import { realpathSync as realpathSync5 } from "node:fs";
35746
- import path5 from "node:path";
36324
+ import { createHash as createHash7 } from "node:crypto";
36325
+ import { realpathSync as realpathSync6 } from "node:fs";
36326
+ import path6 from "node:path";
35747
36327
  function readMeta(db, key) {
35748
36328
  const row = db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(key);
35749
36329
  return row?.value ?? null;
@@ -35764,7 +36344,7 @@ function countFailures(db) {
35764
36344
  function classifyBackfillError(error) {
35765
36345
  if (error instanceof ProjectIdentityError) {
35766
36346
  return {
35767
- errorClass: error.errorClass === "dubious_ownership" ? "unknown" : error.errorClass,
36347
+ errorClass: error.errorClass === "dubious_ownership" || error.errorClass === "home_project_disabled" || error.errorClass === "git_identity_unavailable" ? "unknown" : error.errorClass,
35768
36348
  errorMessage: error.message
35769
36349
  };
35770
36350
  }
@@ -35786,11 +36366,11 @@ function resolveBackfillIdentity(rawProjectPath) {
35786
36366
  function computeLegacyRustDirIdentity(rawProjectPath) {
35787
36367
  let canonical;
35788
36368
  try {
35789
- canonical = realpathSync5(rawProjectPath);
36369
+ canonical = realpathSync6(rawProjectPath);
35790
36370
  } catch {
35791
- canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
36371
+ canonical = path6.isAbsolute(rawProjectPath) ? rawProjectPath : path6.join(process.cwd(), rawProjectPath);
35792
36372
  }
35793
- return `dir:${createHash5("sha256").update(canonical, "utf8").digest("hex")}`;
36373
+ return `dir:${createHash7("sha256").update(canonical, "utf8").digest("hex")}`;
35794
36374
  }
35795
36375
  function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
35796
36376
  db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
@@ -36011,7 +36591,7 @@ var init_tick_failure = __esm(() => {
36011
36591
  });
36012
36592
 
36013
36593
  // ../pi-plugin/src/config/index.ts
36014
- import { existsSync as existsSync27 } from "node:fs";
36594
+ import { existsSync as existsSync28 } from "node:fs";
36015
36595
  function getProjectConfigPaths(cwd) {
36016
36596
  const basePath = cortexKitProjectConfigBasePath(cwd);
36017
36597
  return [`${basePath}.jsonc`, `${basePath}.json`];
@@ -36021,10 +36601,10 @@ function getUserConfigPaths() {
36021
36601
  return [`${basePath}.jsonc`, `${basePath}.json`];
36022
36602
  }
36023
36603
  function resolveFirstExisting(paths) {
36024
- return paths.find((path) => existsSync27(path));
36604
+ return paths.find((path) => existsSync28(path));
36025
36605
  }
36026
36606
  function resolvePiLegacyFallback(sources) {
36027
- return sources.find((source) => existsSync27(source.path)) ?? null;
36607
+ return sources.find((source) => existsSync28(source.path)) ?? null;
36028
36608
  }
36029
36609
  function loadConfigFile(path, scope) {
36030
36610
  let raw;
@@ -36319,7 +36899,7 @@ function loadPiConfigDetailed(opts = {}, applyRuntimeGlobals = true) {
36319
36899
  if (loaded)
36320
36900
  loadedFiles.push(loaded);
36321
36901
  }
36322
- const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) => existsSync27(source.path));
36902
+ const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) => existsSync28(source.path));
36323
36903
  const userPath = resolveFirstExisting(getUserConfigPaths());
36324
36904
  const userLegacyFallback = userPath ? null : resolvePiLegacyFallback(harnessLegacy.user);
36325
36905
  const userReadPath = userPath ?? userLegacyFallback?.path;
@@ -36328,7 +36908,7 @@ function loadPiConfigDetailed(opts = {}, applyRuntimeGlobals = true) {
36328
36908
  if (loaded)
36329
36909
  loadedFiles.push(loaded);
36330
36910
  }
36331
- const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) => existsSync27(source.path));
36911
+ const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) => existsSync28(source.path));
36332
36912
  if (userLegacyFallback) {
36333
36913
  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.`);
36334
36914
  } else if (legacyUserUnmigrated) {
@@ -36450,10 +37030,11 @@ var DATABASE_REPAIR_COMMAND = "bunx @cortexkit/magic-context@latest doctor repai
36450
37030
 
36451
37031
  // src/lib/github-issue.ts
36452
37032
  import { spawnSync as spawnSync5 } from "node:child_process";
36453
- import { readFileSync as readFileSync16 } from "node:fs";
37033
+ import { readFileSync as readFileSync18 } from "node:fs";
36454
37034
  function runGhCommand(args) {
36455
37035
  try {
36456
37036
  const result = spawnSync5("gh", args, {
37037
+ windowsHide: true,
36457
37038
  encoding: "utf-8",
36458
37039
  stdio: ["ignore", "pipe", "pipe"]
36459
37040
  });
@@ -36476,7 +37057,7 @@ function failed(result) {
36476
37057
  function submitGithubIssue(title, bodyPath, runner = runGhCommand) {
36477
37058
  let body;
36478
37059
  try {
36479
- body = readFileSync16(bodyPath, "utf-8");
37060
+ body = readFileSync18(bodyPath, "utf-8");
36480
37061
  } catch (error) {
36481
37062
  return {
36482
37063
  ok: false,
@@ -36534,9 +37115,9 @@ var MAX_GITHUB_ISSUE_BODY_CHARS = 65536;
36534
37115
  var init_github_issue = () => {};
36535
37116
 
36536
37117
  // src/lib/log-lines.ts
36537
- import { existsSync as existsSync28, readFileSync as readFileSync17, statSync as statSync12 } from "node:fs";
37118
+ import { existsSync as existsSync29, readFileSync as readFileSync19, statSync as statSync12 } from "node:fs";
36538
37119
  import { tmpdir as tmpdir2 } from "node:os";
36539
- import { join as join23 } from "node:path";
37120
+ import { join as join24 } from "node:path";
36540
37121
  function tokenize(input, limit = Number.POSITIVE_INFINITY) {
36541
37122
  const tokens = [];
36542
37123
  let index = 0;
@@ -36822,20 +37403,20 @@ function parseLogLine(line) {
36822
37403
  }
36823
37404
  function getMagicContextLogPaths(harness, options = {}) {
36824
37405
  const override = options.override === undefined ? process.env.MAGIC_CONTEXT_LOG_PATH?.trim() : options.override?.trim();
36825
- const storageLogs = join23(options.storageDir ?? getMagicContextStorageDir(), "logs");
37406
+ const storageLogs = join24(options.storageDir ?? getMagicContextStorageDir(), "logs");
36826
37407
  return [
36827
37408
  ...override ? [override] : [],
36828
- join23(options.tempDir ?? tmpdir2(), harness, "magic-context", "magic-context.log"),
36829
- join23(storageLogs, `magic-context.${harness}.log`),
36830
- join23(storageLogs, "magic-context.log")
37409
+ join24(options.tempDir ?? tmpdir2(), harness, "magic-context", "magic-context.log"),
37410
+ join24(storageLogs, `magic-context.${harness}.log`),
37411
+ join24(storageLogs, "magic-context.log")
36831
37412
  ].filter((path, index, paths) => paths.indexOf(path) === index);
36832
37413
  }
36833
37414
  function inspectLogFile(path) {
36834
- if (!existsSync28(path)) {
37415
+ if (!existsSync29(path)) {
36835
37416
  return { path, exists: false, sizeKb: 0, lineCount: 0, grammar: "unknown" };
36836
37417
  }
36837
37418
  try {
36838
- const content = readFileSync17(path, "utf8");
37419
+ const content = readFileSync19(path, "utf8");
36839
37420
  const lines = content.split(/\r?\n/).filter((line) => line.length > 0);
36840
37421
  const grammars = new Set(lines.flatMap((line) => {
36841
37422
  const parsed = parseLogLine(line);
@@ -36862,7 +37443,7 @@ function readLogLines(files) {
36862
37443
  return [];
36863
37444
  try {
36864
37445
  let precedingTimestamp = "";
36865
- return readFileSync17(file.path, "utf8").split(/\r?\n/).filter((line) => line.length > 0).map((line, lineIndex) => {
37446
+ return readFileSync19(file.path, "utf8").split(/\r?\n/).filter((line) => line.length > 0).map((line, lineIndex) => {
36866
37447
  precedingTimestamp = parseLogLine(line)?.ts ?? precedingTimestamp;
36867
37448
  return { line, timestamp: precedingTimestamp, fileIndex, lineIndex };
36868
37449
  });
@@ -36911,10 +37492,10 @@ var init_redaction2 = __esm(() => {
36911
37492
  });
36912
37493
 
36913
37494
  // src/commands/doctor-omp.ts
36914
- import { execFileSync as execFileSync5, spawnSync as spawnSync6 } from "node:child_process";
36915
- import { existsSync as existsSync29, mkdirSync as mkdirSync8, readFileSync as readFileSync18 } from "node:fs";
37495
+ import { execFileSync as execFileSync6, spawnSync as spawnSync6 } from "node:child_process";
37496
+ import { existsSync as existsSync30, mkdirSync as mkdirSync10, readFileSync as readFileSync20 } from "node:fs";
36916
37497
  import { createRequire as createRequire3 } from "node:module";
36917
- import { dirname as dirname14, join as join24, resolve as resolve8 } from "node:path";
37498
+ import { dirname as dirname15, join as join25, resolve as resolve8 } from "node:path";
36918
37499
  function parseSemver(value) {
36919
37500
  const match = value?.match(/(\d+)\.(\d+)\.(\d+)/);
36920
37501
  return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
@@ -36956,10 +37537,10 @@ function selfVersion() {
36956
37537
  return "unknown";
36957
37538
  }
36958
37539
  function readConfig2(path) {
36959
- if (!existsSync29(path))
37540
+ if (!existsSync30(path))
36960
37541
  return {};
36961
37542
  try {
36962
- const parsed = import_comment_json7.parse(readFileSync18(path, "utf-8"));
37543
+ const parsed = import_comment_json7.parse(readFileSync20(path, "utf-8"));
36963
37544
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? {} : { error: "top level is not an object" };
36964
37545
  } catch (error) {
36965
37546
  return { error: error instanceof Error ? error.message : String(error) };
@@ -36969,7 +37550,7 @@ function pluginDeclaresOmp(path) {
36969
37550
  if (!path)
36970
37551
  return null;
36971
37552
  try {
36972
- const pkg = JSON.parse(readFileSync18(join24(path, "package.json"), "utf-8"));
37553
+ const pkg = JSON.parse(readFileSync20(join25(path, "package.json"), "utf-8"));
36973
37554
  return Array.isArray(pkg.omp?.extensions) || Array.isArray(pkg.pi?.extensions);
36974
37555
  } catch {
36975
37556
  return null;
@@ -37050,7 +37631,7 @@ async function runHealthChecks(options) {
37050
37631
  }
37051
37632
  }
37052
37633
  const userConfigPath = getOmpUserConfigPath();
37053
- if (!existsSync29(userConfigPath)) {
37634
+ if (!existsSync30(userConfigPath)) {
37054
37635
  add(results, "warn", `No Magic Context user config at ${userConfigPath}`);
37055
37636
  repairPlan.writeUserConfig = true;
37056
37637
  } else {
@@ -37067,9 +37648,9 @@ async function runHealthChecks(options) {
37067
37648
  for (const warning of loaded.warnings.slice(0, 5))
37068
37649
  add(results, "warn", warning);
37069
37650
  const storage = getMagicContextStorageResolution();
37070
- const dbPath = join24(storage.path, "context.db");
37651
+ const dbPath = join25(storage.path, "context.db");
37071
37652
  add(results, "info", `Shared storage: ${storage.path} (source: ${storage.source})`);
37072
- if (!existsSync29(dbPath))
37653
+ if (!existsSync30(dbPath))
37073
37654
  add(results, "info", `Shared context DB will be created at ${dbPath}`);
37074
37655
  else {
37075
37656
  let db = null;
@@ -37123,7 +37704,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
37123
37704
  };
37124
37705
  }
37125
37706
  function writeDefaultConfig(path) {
37126
- mkdirSync8(dirname14(path), { recursive: true });
37707
+ mkdirSync10(dirname15(path), { recursive: true });
37127
37708
  const config = {
37128
37709
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
37129
37710
  ...MagicContextConfigSchema.parse({})
@@ -37133,7 +37714,7 @@ function writeDefaultConfig(path) {
37133
37714
  }
37134
37715
  async function repair(plan, deps, prompts, cwd) {
37135
37716
  let fixed = 0;
37136
- if (plan.writeUserConfig && !existsSync29(getOmpUserConfigPath())) {
37717
+ if (plan.writeUserConfig && !existsSync30(getOmpUserConfigPath())) {
37137
37718
  writeDefaultConfig(getOmpUserConfigPath());
37138
37719
  prompts.log.success(`Wrote default Magic Context config to ${getOmpUserConfigPath()}`);
37139
37720
  fixed += 1;
@@ -37175,6 +37756,7 @@ function timestamp2(date) {
37175
37756
  function runGhCommandWithDeps(deps, args) {
37176
37757
  if (args[0] === "issue") {
37177
37758
  const result = deps.spawnSync("gh", args, {
37759
+ windowsHide: true,
37178
37760
  encoding: "utf-8",
37179
37761
  stdio: ["ignore", "pipe", "pipe"]
37180
37762
  });
@@ -37186,6 +37768,7 @@ function runGhCommandWithDeps(deps, args) {
37186
37768
  }
37187
37769
  try {
37188
37770
  const output = deps.execFileSync("gh", args, {
37771
+ windowsHide: true,
37189
37772
  encoding: "utf-8",
37190
37773
  stdio: ["ignore", "pipe", "pipe"]
37191
37774
  });
@@ -37218,7 +37801,7 @@ async function runIssueFlow(options) {
37218
37801
  ...report.results.map((result) => `- ${result.status.toUpperCase()}: ${sanitizeDiagnosticText(result.message)}`)
37219
37802
  ].join(`
37220
37803
  `);
37221
- const path = join24(options.cwd, `magic-context-omp-issue-${timestamp2(options.deps.now())}.md`);
37804
+ const path = join25(options.cwd, `magic-context-omp-issue-${timestamp2(options.deps.now())}.md`);
37222
37805
  writeFileAtomic(path, `${body}
37223
37806
  `);
37224
37807
  options.prompts.log.success(`Sanitized report written to ${path}`);
@@ -37289,7 +37872,7 @@ var init_doctor_omp = __esm(async () => {
37289
37872
  openExistingContextDatabase,
37290
37873
  now: () => new Date,
37291
37874
  inspectMagicContextLogs,
37292
- execFileSync: execFileSync5,
37875
+ execFileSync: execFileSync6,
37293
37876
  spawnSync: spawnSync6
37294
37877
  };
37295
37878
  });
@@ -37406,7 +37989,7 @@ function truncate(text) {
37406
37989
  var DEFAULT_TIMEOUT_MS = 1e4, MAX_PREVIEW_CHARS = 240;
37407
37990
 
37408
37991
  // ../plugin/src/features/magic-context/memory/embedding-synapse.ts
37409
- import { createHash as createHash6 } from "node:crypto";
37992
+ import { createHash as createHash8 } from "node:crypto";
37410
37993
  function toSynapseLaneDescriptor(metadata) {
37411
37994
  const tokenBudget = metadata.recommended_token_budget;
37412
37995
  return {
@@ -37546,7 +38129,7 @@ function wait(ms) {
37546
38129
  return new Promise((resolve) => setTimeout(resolve, ms));
37547
38130
  }
37548
38131
  function sha256(value) {
37549
- return createHash6("sha256").update(value).digest("hex");
38132
+ return createHash8("sha256").update(value).digest("hex");
37550
38133
  }
37551
38134
  function stableJson2(value) {
37552
38135
  if (Array.isArray(value))
@@ -38190,12 +38773,12 @@ function listShadowBackfillStalls(db, projectIdentity) {
38190
38773
  var SHADOW_BACKFILL_PROVENANCE_KEY = "_magicContextShadowBackfill";
38191
38774
 
38192
38775
  // ../plugin/src/shared/auto-update-provenance.ts
38193
- import { existsSync as existsSync30, readFileSync as readFileSync19 } from "node:fs";
38776
+ import { existsSync as existsSync31, readFileSync as readFileSync21 } from "node:fs";
38194
38777
  function readAutoUpdateCheckState(path) {
38195
- if (!existsSync30(path))
38778
+ if (!existsSync31(path))
38196
38779
  return null;
38197
38780
  try {
38198
- const value = JSON.parse(readFileSync19(path, "utf-8"));
38781
+ const value = JSON.parse(readFileSync21(path, "utf-8"));
38199
38782
  if (!value || typeof value !== "object" || Array.isArray(value))
38200
38783
  return null;
38201
38784
  const raw = value;
@@ -38223,14 +38806,14 @@ var init_auto_update_provenance = () => {};
38223
38806
  // ../plugin/src/shared/tui-config.ts
38224
38807
  import {
38225
38808
  chmodSync as chmodSync5,
38226
- existsSync as existsSync31,
38227
- mkdirSync as mkdirSync9,
38228
- readFileSync as readFileSync20,
38229
- renameSync as renameSync6,
38809
+ existsSync as existsSync32,
38810
+ mkdirSync as mkdirSync11,
38811
+ readFileSync as readFileSync22,
38812
+ renameSync as renameSync8,
38230
38813
  statSync as statSync13,
38231
- writeFileSync as writeFileSync6
38814
+ writeFileSync as writeFileSync8
38232
38815
  } from "node:fs";
38233
- import { dirname as dirname15, join as join25 } from "node:path";
38816
+ import { dirname as dirname16, join as join26 } from "node:path";
38234
38817
  function pluginEntryId(entry) {
38235
38818
  if (typeof entry === "string")
38236
38819
  return entry;
@@ -38261,21 +38844,21 @@ function writeTuiConfigAtomic(configPath, config) {
38261
38844
  const body = `${import_comment_json8.stringify(config, null, 2)}
38262
38845
  `;
38263
38846
  const tmpPath = `${configPath}.tmp`;
38264
- writeFileSync6(tmpPath, body);
38847
+ writeFileSync8(tmpPath, body);
38265
38848
  try {
38266
38849
  if (statSync13(configPath, { throwIfNoEntry: false })?.isFile()) {
38267
38850
  chmodSync5(tmpPath, statSync13(configPath).mode & 511);
38268
38851
  }
38269
38852
  } catch {}
38270
- renameSync6(tmpPath, configPath);
38853
+ renameSync8(tmpPath, configPath);
38271
38854
  }
38272
38855
  function resolveTuiConfigPath(configDirOverride) {
38273
38856
  const configDir = configDirOverride ?? getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
38274
- const jsoncPath = join25(configDir, "tui.jsonc");
38275
- const jsonPath = join25(configDir, "tui.json");
38276
- if (existsSync31(jsoncPath))
38857
+ const jsoncPath = join26(configDir, "tui.jsonc");
38858
+ const jsonPath = join26(configDir, "tui.json");
38859
+ if (existsSync32(jsoncPath))
38277
38860
  return jsoncPath;
38278
- if (existsSync31(jsonPath))
38861
+ if (existsSync32(jsonPath))
38279
38862
  return jsonPath;
38280
38863
  return jsoncPath;
38281
38864
  }
@@ -38283,8 +38866,8 @@ function ensureTuiPluginEntry(options = {}) {
38283
38866
  try {
38284
38867
  const configPath = resolveTuiConfigPath(options.configDir);
38285
38868
  let config = {};
38286
- if (existsSync31(configPath)) {
38287
- const raw = readFileSync20(configPath, "utf-8");
38869
+ if (existsSync32(configPath)) {
38870
+ const raw = readFileSync22(configPath, "utf-8");
38288
38871
  config = import_comment_json8.parse(raw) ?? {};
38289
38872
  }
38290
38873
  const plugins = Array.isArray(config.plugin) ? [...config.plugin] : [];
@@ -38318,7 +38901,7 @@ function ensureTuiPluginEntry(options = {}) {
38318
38901
  }
38319
38902
  }
38320
38903
  config.plugin = plugins;
38321
- mkdirSync9(dirname15(configPath), { recursive: true });
38904
+ mkdirSync11(dirname16(configPath), { recursive: true });
38322
38905
  writeTuiConfigAtomic(configPath, config);
38323
38906
  log3(`[magic-context] updated TUI plugin entry in ${configPath}`);
38324
38907
  return true;
@@ -38336,9 +38919,9 @@ var init_tui_config = __esm(() => {
38336
38919
  });
38337
38920
 
38338
38921
  // src/lib/diagnostics-opencode.ts
38339
- import { existsSync as existsSync32, readdirSync as readdirSync5, readFileSync as readFileSync21, statSync as statSync14 } from "node:fs";
38922
+ import { existsSync as existsSync33, readdirSync as readdirSync6, readFileSync as readFileSync23, statSync as statSync14 } from "node:fs";
38340
38923
  import { createRequire as createRequire4 } from "node:module";
38341
- import { join as join26 } from "node:path";
38924
+ import { join as join27 } from "node:path";
38342
38925
  function getSelfVersion() {
38343
38926
  const require2 = createRequire4(import.meta.url);
38344
38927
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -38353,7 +38936,7 @@ function getSelfVersion() {
38353
38936
  }
38354
38937
  function readLegacyCachedVersion(root) {
38355
38938
  try {
38356
- const pkg = JSON.parse(readFileSync21(getOpenCodePluginPackageJsonPath(root), "utf-8"));
38939
+ const pkg = JSON.parse(readFileSync23(getOpenCodePluginPackageJsonPath(root), "utf-8"));
38357
38940
  return typeof pkg.version === "string" ? pkg.version : undefined;
38358
38941
  } catch {
38359
38942
  return;
@@ -38362,7 +38945,7 @@ function readLegacyCachedVersion(root) {
38362
38945
  function collectOpenCodePluginCacheReport(hostGeneration, opencodeConfig) {
38363
38946
  const installs = [];
38364
38947
  for (const root of getOpenCodePluginCacheRoots()) {
38365
- if (!existsSync32(root))
38948
+ if (!existsSync33(root))
38366
38949
  continue;
38367
38950
  const spec = root.endsWith("@latest") ? "latest" : "(bare)";
38368
38951
  installs.push({
@@ -38396,7 +38979,7 @@ function getStorageResolution() {
38396
38979
  }
38397
38980
  function fileSize(path) {
38398
38981
  try {
38399
- return existsSync32(path) ? statSync14(path).size : 0;
38982
+ return existsSync33(path) ? statSync14(path).size : 0;
38400
38983
  } catch {
38401
38984
  return 0;
38402
38985
  }
@@ -38408,10 +38991,10 @@ function sanitizeValue(value) {
38408
38991
  return sanitizeConfigValue(value);
38409
38992
  }
38410
38993
  function readConfig3(path) {
38411
- if (!existsSync32(path))
38994
+ if (!existsSync33(path))
38412
38995
  return { value: null };
38413
38996
  try {
38414
- const raw = readFileSync21(path, "utf-8");
38997
+ const raw = readFileSync23(path, "utf-8");
38415
38998
  const value = import_comment_json9.parse(raw);
38416
38999
  return { value };
38417
39000
  } catch (error) {
@@ -38436,7 +39019,7 @@ function configHasPluginEntry(config) {
38436
39019
  }
38437
39020
  function parseHistorianDumpMeta(path) {
38438
39021
  try {
38439
- const xml = readFileSync21(path, "utf-8");
39022
+ const xml = readFileSync23(path, "utf-8");
38440
39023
  const parsed = parseCompartmentOutput(xml);
38441
39024
  const factCountByCategory = {};
38442
39025
  for (const fact of parsed.facts) {
@@ -38469,11 +39052,11 @@ function parseHistorianDumpMeta(path) {
38469
39052
  }
38470
39053
  }
38471
39054
  function listDumpsInDir(dir, limit) {
38472
- if (!existsSync32(dir))
39055
+ if (!existsSync33(dir))
38473
39056
  return { count: 0, recent: [] };
38474
39057
  try {
38475
- const entries = readdirSync5(dir).filter((name) => name.endsWith(".xml")).map((name) => {
38476
- const stat = statSync14(join26(dir, name));
39058
+ const entries = readdirSync6(dir).filter((name) => name.endsWith(".xml")).map((name) => {
39059
+ const stat = statSync14(join27(dir, name));
38477
39060
  return {
38478
39061
  name,
38479
39062
  mtime: stat.mtimeMs,
@@ -38482,7 +39065,7 @@ function listDumpsInDir(dir, limit) {
38482
39065
  }).sort((a, b) => b.mtime - a.mtime);
38483
39066
  const now = Date.now();
38484
39067
  const recent = entries.slice(0, limit).map((entry) => {
38485
- const meta = parseHistorianDumpMeta(join26(dir, entry.name));
39068
+ const meta = parseHistorianDumpMeta(join27(dir, entry.name));
38486
39069
  const summary = {
38487
39070
  name: entry.name,
38488
39071
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -38620,8 +39203,8 @@ async function collectRecentSessions(resolution, hostGeneration) {
38620
39203
  }
38621
39204
  }
38622
39205
  async function collectHistorianFailures(storageDirPath) {
38623
- const contextDbPath = join26(storageDirPath, "context.db");
38624
- if (!existsSync32(contextDbPath))
39206
+ const contextDbPath = join27(storageDirPath, "context.db");
39207
+ if (!existsSync33(contextDbPath))
38625
39208
  return [];
38626
39209
  if (typeof globalThis.Bun === "undefined") {
38627
39210
  return [];
@@ -38654,8 +39237,8 @@ async function collectHistorianFailures(storageDirPath) {
38654
39237
  }
38655
39238
  }
38656
39239
  async function collectHistorianRuns(storageDirPath) {
38657
- const contextDbPath = join26(storageDirPath, "context.db");
38658
- if (!existsSync32(contextDbPath))
39240
+ const contextDbPath = join27(storageDirPath, "context.db");
39241
+ if (!existsSync33(contextDbPath))
38659
39242
  return [];
38660
39243
  if (typeof globalThis.Bun === "undefined")
38661
39244
  return [];
@@ -38728,7 +39311,7 @@ async function collectDiagnostics() {
38728
39311
  const magicContextConfig = readConfig3(configPaths.magicContextConfig);
38729
39312
  const storageResolution = getStorageResolution();
38730
39313
  const storageDirPath = storageResolution.path;
38731
- const contextDbPath = join26(storageDirPath, "context.db");
39314
+ const contextDbPath = join27(storageDirPath, "context.db");
38732
39315
  let compactionEnabled = false;
38733
39316
  try {
38734
39317
  compactionEnabled = isCompactionEnabled(loadPluginConfig(process.cwd()));
@@ -38760,7 +39343,7 @@ async function collectDiagnostics() {
38760
39343
  opencodeConfigHasPlugin: configHasPluginEntry(opencodeConfig.value),
38761
39344
  tuiConfigHasPlugin: configHasPluginEntry(tuiConfig.value),
38762
39345
  magicContextConfig: {
38763
- exists: existsSync32(configPaths.magicContextConfig),
39346
+ exists: existsSync33(configPaths.magicContextConfig),
38764
39347
  ...magicContextConfig.error ? { parseError: magicContextConfig.error } : {},
38765
39348
  flags: sanitizeValue(magicContextConfig.value ?? {}) ?? {}
38766
39349
  },
@@ -38768,7 +39351,7 @@ async function collectDiagnostics() {
38768
39351
  storageDir: {
38769
39352
  path: storageDirPath,
38770
39353
  source: storageResolution.source,
38771
- exists: existsSync32(storageDirPath),
39354
+ exists: existsSync33(storageDirPath),
38772
39355
  contextDbSizeBytes: fileSize(contextDbPath)
38773
39356
  },
38774
39357
  openCodeDatabase: {
@@ -39001,9 +39584,9 @@ var init_embedding_local = __esm(() => {
39001
39584
 
39002
39585
  // src/lib/embedding-runtime.ts
39003
39586
  import { spawnSync as spawnSync7 } from "node:child_process";
39004
- import { existsSync as existsSync33, readFileSync as readFileSync22 } from "node:fs";
39587
+ import { existsSync as existsSync34, readFileSync as readFileSync24 } from "node:fs";
39005
39588
  import { createRequire as createRequire5 } from "node:module";
39006
- import { dirname as dirname16, join as join27, sep } from "node:path";
39589
+ import { dirname as dirname17, join as join28, sep } from "node:path";
39007
39590
  function describeError(error) {
39008
39591
  const message = error instanceof Error ? error.message : String(error ?? "unknown error");
39009
39592
  const code = error?.code;
@@ -39011,6 +39594,7 @@ function describeError(error) {
39011
39594
  }
39012
39595
  function runOnnxRuntimeNodeLoadProbeChild(packageDir) {
39013
39596
  return spawnSync7(process.execPath, ["-e", ONNX_RUNTIME_NODE_LOAD_PROBE_SCRIPT], {
39597
+ windowsHide: true,
39014
39598
  encoding: "utf8",
39015
39599
  env: { ...process.env, [ONNX_LOAD_PROBE_PACKAGE_DIR_ENV]: packageDir },
39016
39600
  stdio: ["ignore", "pipe", "pipe"],
@@ -39144,11 +39728,11 @@ function expectedBinaryRelPath(platform, arch) {
39144
39728
  const supportedArch = arch === "x64" || arch === "arm64";
39145
39729
  if (!supportedPlatform || !supportedArch)
39146
39730
  return null;
39147
- return join27("bin", "napi-v6", platform, arch, "onnxruntime_binding.node");
39731
+ return join28("bin", "napi-v6", platform, arch, "onnxruntime_binding.node");
39148
39732
  }
39149
39733
  function onnxRuntimeNodeVersion(packageDir) {
39150
39734
  try {
39151
- const parsed = JSON.parse(readFileSync22(join27(packageDir, "package.json"), "utf8"));
39735
+ const parsed = JSON.parse(readFileSync24(join28(packageDir, "package.json"), "utf8"));
39152
39736
  return typeof parsed.version === "string" ? parsed.version : undefined;
39153
39737
  } catch {
39154
39738
  return;
@@ -39197,7 +39781,7 @@ function formatLocalEmbeddingRuntimeWasmSelected(status) {
39197
39781
  function requireNodeWasmBundle(probe, candidates) {
39198
39782
  if (probe.state === "failed")
39199
39783
  return probe;
39200
- const bundlePath = candidates.find((candidate) => existsSync33(candidate));
39784
+ const bundlePath = candidates.find((candidate) => existsSync34(candidate));
39201
39785
  return bundlePath ? probe : {
39202
39786
  state: "failed",
39203
39787
  reason: `functional Node WASM Transformers bundle is missing (checked ${candidates.join(", ")})`
@@ -39205,13 +39789,13 @@ function requireNodeWasmBundle(probe, candidates) {
39205
39789
  }
39206
39790
  function nodeWasmBundleCandidates(installRoot) {
39207
39791
  return [
39208
- join27(installRoot, "dist", "transformers-node-wasm.js"),
39209
- join27(installRoot, "node_modules", "@cortexkit", "opencode-magic-context", "dist", "transformers-node-wasm.js"),
39210
- join27(installRoot, "node_modules", "@cortexkit", "pi-magic-context", "dist", "transformers-node-wasm.js")
39792
+ join28(installRoot, "dist", "transformers-node-wasm.js"),
39793
+ join28(installRoot, "node_modules", "@cortexkit", "opencode-magic-context", "dist", "transformers-node-wasm.js"),
39794
+ join28(installRoot, "node_modules", "@cortexkit", "pi-magic-context", "dist", "transformers-node-wasm.js")
39211
39795
  ];
39212
39796
  }
39213
39797
  function probeWasmRuntimeAt(installRoot) {
39214
- const requireFn = createRequire5(join27(installRoot, "package.json"));
39798
+ const requireFn = createRequire5(join28(installRoot, "package.json"));
39215
39799
  return requireNodeWasmBundle(probeWasmRuntimeFromRequire(requireFn), nodeWasmBundleCandidates(installRoot));
39216
39800
  }
39217
39801
  function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
@@ -39220,9 +39804,9 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
39220
39804
  const wasm = probeWasmRuntimeAt(installRoot);
39221
39805
  return wasm.state === "ok" ? { state: "wasm-selected", wasmPath: wasm.wasmPath } : { state: "wasm-broken", wasmReason: wasm.reason };
39222
39806
  }
39223
- const packageDir = join27(installRoot, "node_modules", "onnxruntime-node");
39807
+ const packageDir = join28(installRoot, "node_modules", "onnxruntime-node");
39224
39808
  let native;
39225
- if (!existsSync33(join27(packageDir, "package.json"))) {
39809
+ if (!existsSync34(join28(packageDir, "package.json"))) {
39226
39810
  native = { state: "package-missing", packageDir };
39227
39811
  } else {
39228
39812
  const rel = expectedBinaryRelPath(platform, arch);
@@ -39232,8 +39816,8 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
39232
39816
  binaryPath: packageDir
39233
39817
  };
39234
39818
  } else {
39235
- const binaryPath = join27(packageDir, rel);
39236
- native = existsSync33(binaryPath) ? probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath } : {
39819
+ const binaryPath = join28(packageDir, rel);
39820
+ native = existsSync34(binaryPath) ? probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath } : {
39237
39821
  state: "binary-missing",
39238
39822
  packageDir,
39239
39823
  expectedBinary: binaryPath,
@@ -39244,7 +39828,7 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
39244
39828
  return withWasmFallback(native, () => probeWasmRuntimeAt(installRoot));
39245
39829
  }
39246
39830
  function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
39247
- const existing = installRoots.filter((root) => existsSync33(root));
39831
+ const existing = installRoots.filter((root) => existsSync34(root));
39248
39832
  if (existing.length === 0) {
39249
39833
  return {
39250
39834
  state: "unknown",
@@ -39270,19 +39854,19 @@ function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, a
39270
39854
  function packageDirFromResolved(resolvedPath, packageName) {
39271
39855
  const marker = `node_modules${sep}${packageName.split("/").join(sep)}`;
39272
39856
  const idx = resolvedPath.indexOf(marker);
39273
- return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) : dirname16(resolvedPath);
39857
+ return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) : dirname17(resolvedPath);
39274
39858
  }
39275
39859
  function probeWasmRuntimeByResolution(pluginDir) {
39276
39860
  try {
39277
- const reqPlugin = createRequire5(join27(pluginDir, "package.json"));
39861
+ const reqPlugin = createRequire5(join28(pluginDir, "package.json"));
39278
39862
  const direct = probeWasmRuntimeFromRequire(reqPlugin);
39279
39863
  let probe = direct;
39280
39864
  if (direct.state === "failed" && direct.reason.startsWith("onnxruntime-web is not resolvable")) {
39281
39865
  const tfResolved = reqPlugin.resolve("@huggingface/transformers");
39282
39866
  const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
39283
- probe = probeWasmRuntimeFromRequire(createRequire5(join27(tfDir, "package.json")));
39867
+ probe = probeWasmRuntimeFromRequire(createRequire5(join28(tfDir, "package.json")));
39284
39868
  }
39285
- return requireNodeWasmBundle(probe, [join27(pluginDir, "dist", "transformers-node-wasm.js")]);
39869
+ return requireNodeWasmBundle(probe, [join28(pluginDir, "dist", "transformers-node-wasm.js")]);
39286
39870
  } catch (error) {
39287
39871
  return {
39288
39872
  state: "failed",
@@ -39291,7 +39875,7 @@ function probeWasmRuntimeByResolution(pluginDir) {
39291
39875
  }
39292
39876
  }
39293
39877
  function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
39294
- if (!existsSync33(join27(pluginDir, "package.json"))) {
39878
+ if (!existsSync34(join28(pluginDir, "package.json"))) {
39295
39879
  return { state: "unknown", reason: "plugin package dir not found" };
39296
39880
  }
39297
39881
  const selectedRuntime = resolveLocalEmbeddingRuntime(runtimePreference, host);
@@ -39302,13 +39886,13 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
39302
39886
  let onnxDir = null;
39303
39887
  let resolveError;
39304
39888
  try {
39305
- const reqPlugin = createRequire5(join27(pluginDir, "package.json"));
39889
+ const reqPlugin = createRequire5(join28(pluginDir, "package.json"));
39306
39890
  try {
39307
39891
  onnxDir = packageDirFromResolved(reqPlugin.resolve("onnxruntime-node"), "onnxruntime-node");
39308
39892
  } catch {
39309
39893
  const tfResolved = reqPlugin.resolve("@huggingface/transformers");
39310
39894
  const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
39311
- const reqTf = createRequire5(join27(tfDir, "package.json"));
39895
+ const reqTf = createRequire5(join28(tfDir, "package.json"));
39312
39896
  onnxDir = packageDirFromResolved(reqTf.resolve("onnxruntime-node"), "onnxruntime-node");
39313
39897
  }
39314
39898
  } catch (error) {
@@ -39316,7 +39900,7 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
39316
39900
  if (resolveError === "ERR_MODULE_NOT_FOUND" || resolveError === "MODULE_NOT_FOUND") {
39317
39901
  return withWasmFallback({
39318
39902
  state: "package-missing",
39319
- packageDir: join27(pluginDir, "node_modules", "onnxruntime-node")
39903
+ packageDir: join28(pluginDir, "node_modules", "onnxruntime-node")
39320
39904
  }, () => probeWasmRuntimeByResolution(pluginDir));
39321
39905
  }
39322
39906
  return {
@@ -39332,8 +39916,8 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
39332
39916
  if (rel === null) {
39333
39917
  native = probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath: onnxDir };
39334
39918
  } else {
39335
- const binaryPath = join27(onnxDir, rel);
39336
- native = existsSync33(binaryPath) ? probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath } : {
39919
+ const binaryPath = join28(onnxDir, rel);
39920
+ native = existsSync34(binaryPath) ? probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath } : {
39337
39921
  state: "binary-missing",
39338
39922
  packageDir: onnxDir,
39339
39923
  expectedBinary: binaryPath,
@@ -39475,8 +40059,8 @@ var init_issue_body = __esm(() => {
39475
40059
  });
39476
40060
 
39477
40061
  // src/lib/logs-opencode.ts
39478
- import { writeFileSync as writeFileSync7 } from "node:fs";
39479
- import { join as join28 } from "node:path";
40062
+ import { writeFileSync as writeFileSync9 } from "node:fs";
40063
+ import { join as join29 } from "node:path";
39480
40064
  function sanitizeLogContent(content) {
39481
40065
  return sanitizeDiagnosticText(content);
39482
40066
  }
@@ -39583,12 +40167,12 @@ async function bundleIssueReport(report, description, title, sessionFilter = nul
39583
40167
  const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
39584
40168
  const truncated = bodyMarkdown !== rawBodyMarkdown;
39585
40169
  const timestamp = formatTimestamp(new Date);
39586
- const path = join28(process.cwd(), `magic-context-issue-${timestamp}.md`);
39587
- writeFileSync7(path, `${bodyMarkdown}
40170
+ const path = join29(process.cwd(), `magic-context-issue-${timestamp}.md`);
40171
+ writeFileSync9(path, `${bodyMarkdown}
39588
40172
  `);
39589
- const fullPath = truncated ? join28(process.cwd(), `magic-context-issue-${timestamp}-full.md`) : undefined;
40173
+ const fullPath = truncated ? join29(process.cwd(), `magic-context-issue-${timestamp}-full.md`) : undefined;
39590
40174
  if (fullPath)
39591
- writeFileSync7(fullPath, `${rawBodyMarkdown}
40175
+ writeFileSync9(fullPath, `${rawBodyMarkdown}
39592
40176
  `);
39593
40177
  return { path, bodyMarkdown, ...fullPath ? { fullPath } : {}, truncated };
39594
40178
  }
@@ -39852,25 +40436,25 @@ function migrateExperimentalPinKeyFilesForDoctor(mcConfig) {
39852
40436
  }
39853
40437
 
39854
40438
  // ../plugin/src/hooks/auto-update-checker/constants.ts
39855
- import { homedir as homedir15, platform } from "node:os";
39856
- import { join as join29 } from "node:path";
40439
+ import { homedir as homedir16, platform } from "node:os";
40440
+ import { join as join30 } from "node:path";
39857
40441
  function getOpenCodeCacheRoot() {
39858
40442
  if (platform() === "win32") {
39859
- return join29(process.env.LOCALAPPDATA ?? homedir15(), "opencode");
40443
+ return join30(process.env.LOCALAPPDATA ?? homedir16(), "opencode");
39860
40444
  }
39861
- return join29(homedir15(), ".cache", "opencode");
40445
+ return join30(homedir16(), ".cache", "opencode");
39862
40446
  }
39863
40447
  function getOpenCodeConfigRoot() {
39864
40448
  if (platform() === "win32") {
39865
- return join29(process.env.APPDATA ?? join29(homedir15(), "AppData", "Roaming"), "opencode");
40449
+ return join30(process.env.APPDATA ?? join30(homedir16(), "AppData", "Roaming"), "opencode");
39866
40450
  }
39867
- return join29(process.env.XDG_CONFIG_HOME ?? join29(homedir15(), ".config"), "opencode");
40451
+ return join30(process.env.XDG_CONFIG_HOME ?? join30(homedir16(), ".config"), "opencode");
39868
40452
  }
39869
40453
  var PACKAGE_NAME = "@cortexkit/opencode-magic-context", CACHE_DIR, USER_OPENCODE_CONFIG, USER_OPENCODE_CONFIG_JSONC;
39870
40454
  var init_constants2 = __esm(() => {
39871
- CACHE_DIR = join29(getOpenCodeCacheRoot(), "packages");
39872
- USER_OPENCODE_CONFIG = join29(getOpenCodeConfigRoot(), "opencode.json");
39873
- USER_OPENCODE_CONFIG_JSONC = join29(getOpenCodeConfigRoot(), "opencode.jsonc");
40455
+ CACHE_DIR = join30(getOpenCodeCacheRoot(), "packages");
40456
+ USER_OPENCODE_CONFIG = join30(getOpenCodeConfigRoot(), "opencode.json");
40457
+ USER_OPENCODE_CONFIG_JSONC = join30(getOpenCodeConfigRoot(), "opencode.jsonc");
39874
40458
  });
39875
40459
 
39876
40460
  // ../plugin/src/hooks/auto-update-checker/types.ts
@@ -39894,14 +40478,14 @@ var init_types = __esm(() => {
39894
40478
  // ../plugin/src/hooks/auto-update-checker/checker.ts
39895
40479
  import {
39896
40480
  accessSync as accessSync2,
39897
- existsSync as existsSync34,
40481
+ existsSync as existsSync35,
39898
40482
  constants as fsConstants,
39899
- readFileSync as readFileSync23,
39900
- renameSync as renameSync7,
40483
+ readFileSync as readFileSync25,
40484
+ renameSync as renameSync9,
39901
40485
  statSync as statSync15,
39902
- writeFileSync as writeFileSync8
40486
+ writeFileSync as writeFileSync10
39903
40487
  } from "node:fs";
39904
- import { dirname as dirname17, isAbsolute as isAbsolute7, join as join30, resolve as resolve9 } from "node:path";
40488
+ import { dirname as dirname18, isAbsolute as isAbsolute7, join as join31, resolve as resolve9 } from "node:path";
39905
40489
  function warn(message) {
39906
40490
  log3(`WARN: ${message}`);
39907
40491
  }
@@ -39927,17 +40511,17 @@ function parseJsonConfig(content) {
39927
40511
  }
39928
40512
  function getSurfaceConfigPaths(directory, surface) {
39929
40513
  const name = surface === "server" ? "opencode" : "tui";
39930
- const globalDir = dirname17(USER_OPENCODE_CONFIG);
40514
+ const globalDir = dirname18(USER_OPENCODE_CONFIG);
39931
40515
  const dirs = [
39932
40516
  globalDir,
39933
40517
  directory,
39934
- join30(directory, ".opencode"),
40518
+ join31(directory, ".opencode"),
39935
40519
  process.env.OPENCODE_CONFIG_DIR
39936
40520
  ].filter((value) => Boolean(value));
39937
40521
  const paths = [];
39938
40522
  for (const dir of dirs) {
39939
40523
  for (const extension of ["json", "jsonc"]) {
39940
- const path = join30(dir, `${name}.${extension}`);
40524
+ const path = join31(dir, `${name}.${extension}`);
39941
40525
  if (!paths.includes(path))
39942
40526
  paths.push(path);
39943
40527
  }
@@ -39948,9 +40532,9 @@ function getWinningConfig(directory, surface) {
39948
40532
  let winner = null;
39949
40533
  for (const path of getSurfaceConfigPaths(directory, surface)) {
39950
40534
  try {
39951
- if (!existsSync34(path))
40535
+ if (!existsSync35(path))
39952
40536
  continue;
39953
- const parsed = parseJsonConfig(readFileSync23(path, "utf-8"));
40537
+ const parsed = parseJsonConfig(readFileSync25(path, "utf-8"));
39954
40538
  const entries = getPluginEntries(parsed);
39955
40539
  if (entries.some((entry) => entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))) {
39956
40540
  if (winner) {
@@ -39986,14 +40570,14 @@ var init_checker = __esm(() => {
39986
40570
  });
39987
40571
 
39988
40572
  // src/lib/opencode-plugin-schema-fence.ts
39989
- import { existsSync as existsSync35, readdirSync as readdirSync6, readFileSync as readFileSync24 } from "node:fs";
39990
- import { join as join31 } from "node:path";
40573
+ import { existsSync as existsSync36, readdirSync as readdirSync7, readFileSync as readFileSync26 } from "node:fs";
40574
+ import { join as join32 } from "node:path";
39991
40575
  import { gunzipSync } from "node:zlib";
39992
40576
  function readPackageVersion(packageJsonPath) {
39993
40577
  try {
39994
- if (!existsSync35(packageJsonPath))
40578
+ if (!existsSync36(packageJsonPath))
39995
40579
  return null;
39996
- const packageJson = JSON.parse(readFileSync24(packageJsonPath, "utf-8"));
40580
+ const packageJson = JSON.parse(readFileSync26(packageJsonPath, "utf-8"));
39997
40581
  if (packageJson.name !== OPENCODE_PLUGIN_NAME || typeof packageJson.version !== "string") {
39998
40582
  return null;
39999
40583
  }
@@ -40012,8 +40596,8 @@ function readFenceValue(text) {
40012
40596
  return values.size === 1 ? [...values][0] ?? null : null;
40013
40597
  }
40014
40598
  function readFenceFromDist(packageDirectory) {
40015
- const distDirectory = join31(packageDirectory, "dist");
40016
- if (!existsSync35(distDirectory))
40599
+ const distDirectory = join32(packageDirectory, "dist");
40600
+ if (!existsSync36(distDirectory))
40017
40601
  return null;
40018
40602
  const pending = [distDirectory];
40019
40603
  const fenceValues = new Set;
@@ -40022,15 +40606,15 @@ function readFenceFromDist(packageDirectory) {
40022
40606
  if (!directory)
40023
40607
  continue;
40024
40608
  try {
40025
- for (const entry of readdirSync6(directory, { withFileTypes: true })) {
40026
- const path = join31(directory, entry.name);
40609
+ for (const entry of readdirSync7(directory, { withFileTypes: true })) {
40610
+ const path = join32(directory, entry.name);
40027
40611
  if (entry.isDirectory()) {
40028
40612
  pending.push(path);
40029
40613
  continue;
40030
40614
  }
40031
40615
  if (!entry.isFile() || !/\.(?:[cm]?js|ts)$/.test(entry.name))
40032
40616
  continue;
40033
- const fence = readFenceValue(readFileSync24(path, "utf-8"));
40617
+ const fence = readFenceValue(readFileSync26(path, "utf-8"));
40034
40618
  if (fence !== null)
40035
40619
  fenceValues.add(fence);
40036
40620
  }
@@ -40041,20 +40625,20 @@ function readFenceFromDist(packageDirectory) {
40041
40625
  return fenceValues.size === 1 ? [...fenceValues][0] ?? null : null;
40042
40626
  }
40043
40627
  function findInstalledPluginPackage(cacheDirectory, specifier, requestedVersion) {
40044
- const directCacheRoot = join31(cacheDirectory, specifier);
40628
+ const directCacheRoot = join32(cacheDirectory, specifier);
40045
40629
  const candidates = [directCacheRoot];
40046
40630
  try {
40047
- for (const entry of readdirSync6(cacheDirectory, { withFileTypes: true })) {
40631
+ for (const entry of readdirSync7(cacheDirectory, { withFileTypes: true })) {
40048
40632
  if (!entry.isDirectory())
40049
40633
  continue;
40050
- const candidate = join31(cacheDirectory, entry.name);
40634
+ const candidate = join32(cacheDirectory, entry.name);
40051
40635
  if (!candidates.includes(candidate))
40052
40636
  candidates.push(candidate);
40053
40637
  }
40054
40638
  } catch {}
40055
40639
  for (const cacheRoot of candidates) {
40056
- const directory = join31(cacheRoot, "node_modules", ...PACKAGE_PATH_SEGMENTS);
40057
- const version = readPackageVersion(join31(directory, "package.json"));
40640
+ const directory = join32(cacheRoot, "node_modules", ...PACKAGE_PATH_SEGMENTS);
40641
+ const version = readPackageVersion(join32(directory, "package.json"));
40058
40642
  if (!version)
40059
40643
  continue;
40060
40644
  if (cacheRoot === directCacheRoot || EXACT_VERSION_PATTERN.test(requestedVersion) && version === requestedVersion) {
@@ -40248,13 +40832,13 @@ var init_storage_versions = __esm(async () => {
40248
40832
  });
40249
40833
 
40250
40834
  // src/commands/doctor-opencode-cache.ts
40251
- import { existsSync as existsSync36, readFileSync as readFileSync25, rmSync as rmSync4 } from "node:fs";
40835
+ import { existsSync as existsSync37, readFileSync as readFileSync27, rmSync as rmSync4 } from "node:fs";
40252
40836
  function readCachedPluginVersion(pluginCacheDir) {
40253
40837
  try {
40254
40838
  const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
40255
- if (!existsSync36(installedPkgPath))
40839
+ if (!existsSync37(installedPkgPath))
40256
40840
  return;
40257
- const pkg = JSON.parse(readFileSync25(installedPkgPath, "utf-8"));
40841
+ const pkg = JSON.parse(readFileSync27(installedPkgPath, "utf-8"));
40258
40842
  return typeof pkg.version === "string" ? pkg.version : undefined;
40259
40843
  } catch {
40260
40844
  return;
@@ -40263,7 +40847,7 @@ function readCachedPluginVersion(pluginCacheDir) {
40263
40847
  async function clearPluginCache(options = {}, deps = {}) {
40264
40848
  const remove = deps.remove ?? ((path) => rmSync4(path, { recursive: true, force: true }));
40265
40849
  const pluginCacheRoots = getOpenCodePluginCacheRoots();
40266
- const existingRoots = pluginCacheRoots.filter((root) => existsSync36(root));
40850
+ const existingRoots = pluginCacheRoots.filter((root) => existsSync37(root));
40267
40851
  if (existingRoots.length === 0) {
40268
40852
  return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
40269
40853
  }
@@ -40330,19 +40914,19 @@ var init_doctor_opencode_cache = __esm(() => {
40330
40914
  });
40331
40915
 
40332
40916
  // src/commands/doctor-cached-plugin-fence.ts
40333
- import { existsSync as existsSync37 } from "node:fs";
40334
- import { dirname as dirname18 } from "node:path";
40917
+ import { existsSync as existsSync38 } from "node:fs";
40918
+ import { dirname as dirname19 } from "node:path";
40335
40919
  function listCachedOpenCodePluginFences(sources = {}) {
40336
40920
  const fences = [];
40337
40921
  for (const root of sources.openCodeV1Roots ?? getOpenCodePluginCacheRoots()) {
40338
40922
  const packageJson = getOpenCodePluginPackageJsonPath(root);
40339
- if (!existsSync37(packageJson))
40923
+ if (!existsSync38(packageJson))
40340
40924
  continue;
40341
40925
  fences.push({
40342
40926
  host: "opencode1",
40343
40927
  directory: root,
40344
40928
  version: readCachedPluginVersion(root),
40345
- supportedVersion: readFenceFromDist(dirname18(packageJson))
40929
+ supportedVersion: readFenceFromDist(dirname19(packageJson))
40346
40930
  });
40347
40931
  }
40348
40932
  for (const slot of listOpenCodeV2PluginCacheSlots(sources.openCodeV2NpmCacheDir)) {
@@ -40356,7 +40940,7 @@ function listCachedOpenCodePluginFences(sources = {}) {
40356
40940
  directory: slot.slot,
40357
40941
  spec: slot.spec,
40358
40942
  version: slot.version,
40359
- supportedVersion: readFenceFromDist(dirname18(getOpenCodePluginPackageJsonPath(generation)))
40943
+ supportedVersion: readFenceFromDist(dirname19(getOpenCodePluginPackageJsonPath(generation)))
40360
40944
  });
40361
40945
  }
40362
40946
  return fences;
@@ -40431,11 +41015,11 @@ function mcMarkerPredicate(column = "data") {
40431
41015
  AND json_extract(${data}, '$.summary') = 1
40432
41016
  AND json_extract(${data}, '$.providerID') = 'magic-context'`;
40433
41017
  }
40434
- function tableExists4(db, table) {
41018
+ function tableExists5(db, table) {
40435
41019
  return db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ? LIMIT 1").get(table) != null;
40436
41020
  }
40437
41021
  function countMissingCompleted(db) {
40438
- if (!tableExists4(db, "message"))
41022
+ if (!tableExists5(db, "message"))
40439
41023
  return 0;
40440
41024
  const row = db.prepare(`SELECT COUNT(*) AS count
40441
41025
  FROM message
@@ -40444,7 +41028,7 @@ function countMissingCompleted(db) {
40444
41028
  return Number(row?.count ?? 0);
40445
41029
  }
40446
41030
  function migrationV1ToV2Completed(db) {
40447
- if (!tableExists4(db, "kv"))
41031
+ if (!tableExists5(db, "kv"))
40448
41032
  return false;
40449
41033
  const columns = db.prepare("PRAGMA table_info(kv)").all();
40450
41034
  const names = new Set(columns.flatMap((column) => typeof column.name === "string" ? [column.name] : []));
@@ -40461,7 +41045,7 @@ function migrationV1ToV2Completed(db) {
40461
41045
  }
40462
41046
  }
40463
41047
  function countUnmatchedConvertedMarkers(db, migratedV2Schema) {
40464
- if (!migratedV2Schema || !tableExists4(db, "message"))
41048
+ if (!migratedV2Schema || !tableExists5(db, "message"))
40465
41049
  return 0;
40466
41050
  const row = db.prepare(`SELECT COUNT(DISTINCT json_extract(${safeData("marker.data")}, '$.parentID')) AS count
40467
41051
  FROM message marker
@@ -40476,7 +41060,7 @@ function countUnmatchedConvertedMarkers(db, migratedV2Schema) {
40476
41060
  return Number(row?.count ?? 0);
40477
41061
  }
40478
41062
  function countPostConversionMessages(db, migratedV2Schema) {
40479
- if (!migratedV2Schema || !tableExists4(db, "message") || !tableExists4(db, "session")) {
41063
+ if (!migratedV2Schema || !tableExists5(db, "message") || !tableExists5(db, "session")) {
40480
41064
  return { messages: 0, sessions: 0 };
40481
41065
  }
40482
41066
  const row = db.prepare(`SELECT COUNT(*) AS messages, COUNT(DISTINCT converted.session_id) AS sessions
@@ -40493,7 +41077,7 @@ function countPostConversionMessages(db, migratedV2Schema) {
40493
41077
  function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
40494
41078
  const missingBefore = countMissingCompleted(db);
40495
41079
  let repaired = 0;
40496
- if (options.fix && missingBefore > 0 && tableExists4(db, "message")) {
41080
+ if (options.fix && missingBefore > 0 && tableExists5(db, "message")) {
40497
41081
  repaired = db.transaction(() => {
40498
41082
  const result = db.prepare(`UPDATE message
40499
41083
  SET data = json_set(
@@ -40507,7 +41091,7 @@ function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
40507
41091
  })();
40508
41092
  }
40509
41093
  const missingAfter = countMissingCompleted(db);
40510
- const migratedV2Schema = tableExists4(db, "session_v2") && tableExists4(db, "session_message");
41094
+ const migratedV2Schema = tableExists5(db, "session_v2") && tableExists5(db, "session_message");
40511
41095
  const migrationCompleted = migrationV1ToV2Completed(db);
40512
41096
  const unmatchedConvertedMarkers = countUnmatchedConvertedMarkers(db, migratedV2Schema);
40513
41097
  const postConversion = countPostConversionMessages(db, migratedV2Schema);
@@ -40618,6 +41202,182 @@ var init_doctor_harness_relabel = __esm(async () => {
40618
41202
  await init_opencode2_relabel();
40619
41203
  });
40620
41204
 
41205
+ // src/commands/doctor-hidden-children.ts
41206
+ import { spawnSync as spawnSync8 } from "node:child_process";
41207
+ import { existsSync as existsSync39, realpathSync as realpathSync7 } from "node:fs";
41208
+ import { dirname as dirname20 } from "node:path";
41209
+ async function assertHiddenChildStoresClosed(contextDbPath, hostDbPath, platform = process.platform, processProbe = () => inspectProcessesAsync(true)) {
41210
+ if (platform === "win32") {
41211
+ const processes = await processProbe();
41212
+ if (processes.pi.state !== "known" || processes.pi.processIds.length > 0 || (processes.pi.inconclusivePids?.length ?? 0) > 0 || processes.processSnapshot?.source !== "cim") {
41213
+ throw new Error("Windows process probe could not rule out OpenCode, Pi or ck-mc holders");
41214
+ }
41215
+ const unknown = processes.processSnapshot.facts.filter(({ pid, imageName, commandLine }) => pid !== process.pid && (!imageName && !commandLine || /^(?:bun|node|deno)(?:\.exe)?$/i.test(imageName ?? "") && !commandLine));
41216
+ if (unknown.length)
41217
+ throw new Error(`Windows process identity is unavailable (PID ${unknown.map(({ pid }) => pid).join(", ")})`);
41218
+ const blockers = processes.processSnapshot.facts.filter(({ pid, imageName, commandLine }) => {
41219
+ if (pid === process.pid)
41220
+ return false;
41221
+ const image = (imageName ?? "").toLowerCase().replaceAll("\\", "/").split("/").at(-1) ?? "";
41222
+ return /^(?:opencode|opencode2|pi|omp|ck-mc)(?:\.exe)?$/.test(image) || /(?:^|[\\/\s"'])(?:ck-mc|opencode2?)(?:\.exe|\.js|\.mjs)?(?:$|[\s"'])/i.test(commandLine ?? "");
41223
+ });
41224
+ if (blockers.length)
41225
+ throw new Error(`OpenCode, Pi or ck-mc process is running (PID ${blockers.map(({ pid }) => pid).join(", ")})`);
41226
+ return;
41227
+ }
41228
+ const inspection = defaultInspectHolders(dirname20(contextDbPath));
41229
+ if (!inspection.safe) {
41230
+ throw new Error(`database holders cannot be ruled out: ${[...inspection.blockers, inspection.uncertainty].filter(Boolean).join("; ")}`);
41231
+ }
41232
+ const paths = [contextDbPath, hostDbPath].flatMap((path) => [path, `${path}-wal`, `${path}-shm`].filter(existsSync39).map((file) => realpathSync7(file)));
41233
+ const result = spawnSync8("lsof", ["-Fn", "--", ...paths], {
41234
+ encoding: "utf8",
41235
+ timeout: 30000,
41236
+ maxBuffer: 32 * 1024 * 1024,
41237
+ windowsHide: true
41238
+ });
41239
+ if (result.error || result.stderr?.trim() || result.status !== 0 && !(result.status === 1 && !result.stdout?.trim())) {
41240
+ throw new Error(`lsof could not inspect database holders: ${result.error?.message ?? result.stderr ?? result.status}`);
41241
+ }
41242
+ const opened = result.stdout.split(`
41243
+ `).filter((line) => line.startsWith("n"));
41244
+ if (opened.length)
41245
+ throw new Error(`database holder is present: ${opened.map((line) => line.slice(1)).join(", ")}`);
41246
+ if (result.status === 0)
41247
+ throw new Error("lsof returned success without any file evidence");
41248
+ }
41249
+ function assertVerifiedV2Schema(db) {
41250
+ const table = db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all();
41251
+ const names = new Set(table.map((row) => row.name));
41252
+ if (!names.has("session_v2") || !names.has("session_message") || names.has("message") || names.has("part")) {
41253
+ throw new Error("OpenCode store is not the verified OpenCode 2 session_v2 schema");
41254
+ }
41255
+ const fields = db.prepare("PRAGMA table_info('session_v2')").all();
41256
+ if (!fields.some((field) => field.name === "id" && field.pk === 1) || !fields.some((field) => field.name === "metadata") || !fields.some((field) => field.name === "directory")) {
41257
+ throw new Error("OpenCode session_v2 columns differ from the verified schema");
41258
+ }
41259
+ const dependents = table.flatMap(({ name }) => {
41260
+ const foreignKeys = db.prepare(`PRAGMA foreign_key_list('${name.replaceAll("'", "''")}')`).all();
41261
+ return foreignKeys.filter((key) => key.table === "session_v2").map((key) => ({ name, ...key }));
41262
+ });
41263
+ if (dependents.length !== CASCADE_TABLES.length || dependents.some((key) => !CASCADE_TABLES.includes(key.name) || key.from !== "session_id" || key.to !== "id" || key.on_delete !== "CASCADE")) {
41264
+ throw new Error("OpenCode session_v2 cascade schema differs from the verified 2.0.18 host");
41265
+ }
41266
+ }
41267
+ async function cleanupRetiredHiddenChildren(options) {
41268
+ const { contextDbPath, hostDbPath, fix = false } = options;
41269
+ if (!existsSync39(contextDbPath) || !existsSync39(hostDbPath))
41270
+ return { waiting: 0, deleted: 0 };
41271
+ const context = new Database(contextDbPath, { readonly: true, fileMustExist: true });
41272
+ const host = new Database(hostDbPath, { readonly: true, fileMustExist: true });
41273
+ let states;
41274
+ let candidates;
41275
+ let waiting;
41276
+ try {
41277
+ assertVerifiedV2Schema(host);
41278
+ const rows = context.prepare("SELECT key, value FROM schema_migrations_meta WHERE substr(key, 1, ?) = ?").all(PREFIX.length, PREFIX);
41279
+ states = rows.map(({ key, value }) => {
41280
+ const state = JSON.parse(value);
41281
+ if (state.version !== 1 || !Array.isArray(state.retired_children) || state.retired_children.some((child) => typeof child.id !== "string")) {
41282
+ throw new Error(`Invalid hidden-child state at ${key}`);
41283
+ }
41284
+ return { key, state };
41285
+ });
41286
+ const ids = [
41287
+ ...new Set(states.flatMap(({ state }) => state.retired_children.map((child) => child.id)))
41288
+ ];
41289
+ waiting = ids.length;
41290
+ candidates = ids.filter((id) => {
41291
+ const row = host.prepare("SELECT metadata FROM session_v2 WHERE id = ?").get(id);
41292
+ if (!row)
41293
+ return false;
41294
+ let marker;
41295
+ try {
41296
+ marker = JSON.parse(row.metadata ?? "null");
41297
+ } catch {
41298
+ return false;
41299
+ }
41300
+ return marker?.magic_context === "hidden-run";
41301
+ });
41302
+ } finally {
41303
+ context.close();
41304
+ host.close();
41305
+ }
41306
+ options.report?.(`${waiting} retired hidden sessions are waiting for deletion${fix ? "" : "; run `doctor --fix` with OpenCode closed"}`);
41307
+ if (!fix || candidates.length === 0)
41308
+ return { waiting, deleted: 0 };
41309
+ const inspect = options.inspectHolders ?? ((context, host) => assertHiddenChildStoresClosed(context, host, options.platform, options.processProbe));
41310
+ await inspect(contextDbPath, hostDbPath);
41311
+ const backup = `${hostDbPath}.hidden-child-backup-${new Date().toISOString().replace(/[:.]/g, "-")}-${process.pid}`;
41312
+ copyDatabaseBundle(hostDbPath, backup);
41313
+ options.report?.(`OpenCode store backup: ${backup}`);
41314
+ await inspect(contextDbPath, hostDbPath);
41315
+ const writableHost = new Database(hostDbPath);
41316
+ let writableContext;
41317
+ const deletedIds = [];
41318
+ let hostLocked = false;
41319
+ let contextLocked = false;
41320
+ try {
41321
+ writableHost.exec("PRAGMA busy_timeout = 250");
41322
+ writableHost.exec("PRAGMA foreign_keys = ON");
41323
+ writableContext = new Database(contextDbPath);
41324
+ writableContext.exec("PRAGMA busy_timeout = 250");
41325
+ try {
41326
+ writableHost.exec("BEGIN EXCLUSIVE");
41327
+ hostLocked = true;
41328
+ writableContext.exec("BEGIN EXCLUSIVE");
41329
+ contextLocked = true;
41330
+ } catch (error) {
41331
+ throw new Error(`Cannot acquire exclusive locks on ${hostDbPath} and ${contextDbPath}: ${error instanceof Error ? error.message : String(error)}`);
41332
+ }
41333
+ assertVerifiedV2Schema(writableHost);
41334
+ for (const id of candidates) {
41335
+ const result = writableHost.prepare("DELETE FROM session_v2 WHERE id = ? AND json_valid(metadata) AND json_extract(metadata, '$.magic_context') = 'hidden-run'").run(id);
41336
+ if (result.changes > 0)
41337
+ deletedIds.push(id);
41338
+ }
41339
+ for (const { key } of states) {
41340
+ const current = writableContext.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(key);
41341
+ if (!current)
41342
+ throw new Error(`Hidden-child state ${key} disappeared during repair`);
41343
+ const state = JSON.parse(current.value);
41344
+ if (state.version !== 1 || !Array.isArray(state.retired_children)) {
41345
+ throw new Error(`Hidden-child state ${key} changed during repair`);
41346
+ }
41347
+ state.retired_children = state.retired_children.filter((child) => !deletedIds.includes(child.id));
41348
+ writableContext.prepare("UPDATE schema_migrations_meta SET value = ? WHERE key = ?").run(JSON.stringify(state), key);
41349
+ }
41350
+ writableHost.exec("COMMIT");
41351
+ hostLocked = false;
41352
+ writableContext.exec("COMMIT");
41353
+ contextLocked = false;
41354
+ } finally {
41355
+ if (contextLocked)
41356
+ writableContext?.exec("ROLLBACK");
41357
+ if (hostLocked)
41358
+ writableHost.exec("ROLLBACK");
41359
+ writableContext?.close();
41360
+ writableHost.close();
41361
+ }
41362
+ options.report?.(`Deleted ${deletedIds.length} marked, recorded hidden sessions`);
41363
+ return { waiting, deleted: deletedIds.length, backup };
41364
+ }
41365
+ var PREFIX = "opencode2_hidden_children:", CASCADE_TABLES;
41366
+ var init_doctor_hidden_children = __esm(async () => {
41367
+ init_rpc_utils();
41368
+ await __promiseAll([
41369
+ init_sqlite(),
41370
+ init_doctor_repair_db()
41371
+ ]);
41372
+ CASCADE_TABLES = [
41373
+ "instruction_entry",
41374
+ "instruction_state",
41375
+ "session_inbox",
41376
+ "session_message",
41377
+ "session_pending"
41378
+ ];
41379
+ });
41380
+
40621
41381
  // src/commands/doctor-opencode-plugin-duplicates.ts
40622
41382
  import { isDeepStrictEqual } from "node:util";
40623
41383
  function entryOptions(entry) {
@@ -40844,11 +41604,11 @@ function formatUnresolvedCompartmentSession(session) {
40844
41604
  }
40845
41605
 
40846
41606
  // src/commands/doctor-opencode.ts
40847
- import { spawnSync as spawnSync8 } from "node:child_process";
40848
- import { existsSync as existsSync38, mkdtempSync, readFileSync as readFileSync26, rmSync as rmSync5 } from "node:fs";
41607
+ import { spawnSync as spawnSync9 } from "node:child_process";
41608
+ import { existsSync as existsSync40, mkdtempSync as mkdtempSync2, readFileSync as readFileSync28, rmSync as rmSync5 } from "node:fs";
40849
41609
  import { createRequire as createRequire6 } from "node:module";
40850
- import { homedir as homedir16, tmpdir as tmpdir3 } from "node:os";
40851
- import { join as join32 } from "node:path";
41610
+ import { homedir as homedir17, tmpdir as tmpdir3 } from "node:os";
41611
+ import { join as join33 } from "node:path";
40852
41612
  function formatSharedDbRowCounts(db) {
40853
41613
  return SHARED_DB_ROW_COUNT_TABLES.map((table) => {
40854
41614
  try {
@@ -40879,7 +41639,8 @@ function findUnknownConfiguredModels(configured, catalog) {
40879
41639
  return [];
40880
41640
  });
40881
41641
  }
40882
- function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args, cwd) => spawnSync8("opencode", args, {
41642
+ function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args, cwd) => spawnSync9("opencode", args, {
41643
+ windowsHide: true,
40883
41644
  cwd,
40884
41645
  encoding: "utf8",
40885
41646
  timeout: hostGeneration === "v2" ? 90000 : 45000,
@@ -40916,7 +41677,7 @@ function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args
40916
41677
  }
40917
41678
  if (models.length === 0)
40918
41679
  return;
40919
- const tempRoot = mkdtempSync(join32(tmpdir3(), "magic-context-opencode-catalog-"));
41680
+ const tempRoot = mkdtempSync2(join33(tmpdir3(), "magic-context-opencode-catalog-"));
40920
41681
  try {
40921
41682
  const command = hostGeneration === "v2" ? ["api", "model.list", "--param", `directory=${projectDir}`] : ["models", "--verbose"];
40922
41683
  const guidance = `opencode ${command.join(" ")}`;
@@ -41092,7 +41853,7 @@ function getSelfVersion2() {
41092
41853
  function describeAutoUpdateStall(specifier, autoUpdateEnabled, storageDir = getMagicContextStorageDir()) {
41093
41854
  if (!autoUpdateEnabled || !isPinnedOpenCodePluginSpecifier(specifier))
41094
41855
  return null;
41095
- const state = readAutoUpdateCheckState(join32(storageDir, AUTO_UPDATE_CHECK_STATE_FILENAME));
41856
+ const state = readAutoUpdateCheckState(join33(storageDir, AUTO_UPDATE_CHECK_STATE_FILENAME));
41096
41857
  const owner = isUpdaterPinnedSpec(state, specifier) ? "updater" : "you";
41097
41858
  return `auto-update: stalled — config pinned to ${specifier} (by ${owner})`;
41098
41859
  }
@@ -41101,15 +41862,15 @@ function getUserNpmrcPath() {
41101
41862
  if (custom)
41102
41863
  return custom;
41103
41864
  const home = process.env.HOME?.trim();
41104
- return join32(home || homedir16(), ".npmrc");
41865
+ return join33(home || homedir17(), ".npmrc");
41105
41866
  }
41106
41867
  function collectNpmReleaseAgeWarnings() {
41107
41868
  const ageWarnings = [];
41108
41869
  const npmrcPath = getUserNpmrcPath();
41109
- if (!existsSync38(npmrcPath))
41870
+ if (!existsSync40(npmrcPath))
41110
41871
  return ageWarnings;
41111
41872
  try {
41112
- const npmrc = readFileSync26(npmrcPath, "utf-8");
41873
+ const npmrc = readFileSync28(npmrcPath, "utf-8");
41113
41874
  for (const line of npmrc.split(`
41114
41875
  `)) {
41115
41876
  const trimmed = line.trim();
@@ -41142,15 +41903,18 @@ function compareVersions(a, b) {
41142
41903
  function openBrowser(url) {
41143
41904
  try {
41144
41905
  if (process.platform === "darwin") {
41145
- const child = spawnSync8("open", [url], { stdio: "ignore" });
41906
+ const child = spawnSync9("open", [url], { windowsHide: true, stdio: "ignore" });
41146
41907
  if (child.status === 0)
41147
41908
  return;
41148
41909
  } else if (process.platform === "linux") {
41149
- const child = spawnSync8("xdg-open", [url], { stdio: "ignore" });
41910
+ const child = spawnSync9("xdg-open", [url], { windowsHide: true, stdio: "ignore" });
41150
41911
  if (child.status === 0)
41151
41912
  return;
41152
41913
  } else if (process.platform === "win32") {
41153
- const child = spawnSync8("cmd", ["/c", "start", "", url], { stdio: "ignore" });
41914
+ const child = spawnSync9("cmd", ["/c", "start", "", url], {
41915
+ windowsHide: true,
41916
+ stdio: "ignore"
41917
+ });
41154
41918
  if (child.status === 0)
41155
41919
  return;
41156
41920
  }
@@ -41243,7 +42007,7 @@ function checkLocalEmbeddingRuntimeForDoctor(runtimePreference = "auto") {
41243
42007
  return { issues: 0 };
41244
42008
  }
41245
42009
  async function checkEmbeddingConfig(magicContextConfigPath) {
41246
- if (!existsSync38(magicContextConfigPath)) {
42010
+ if (!existsSync40(magicContextConfigPath)) {
41247
42011
  return checkLocalEmbeddingRuntimeForDoctor();
41248
42012
  }
41249
42013
  let rawText;
@@ -41400,7 +42164,7 @@ async function runDoctor2(options = {}) {
41400
42164
  const v22Result = await runV22BackfillCommands({
41401
42165
  name: "OpenCode",
41402
42166
  openDatabase: (readonly = true) => {
41403
- const dbPath = join32(getMagicContextStorageDir(), "context.db");
42167
+ const dbPath = join33(getMagicContextStorageDir(), "context.db");
41404
42168
  v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
41405
42169
  return v22Db;
41406
42170
  },
@@ -41432,7 +42196,7 @@ async function runDoctor2(options = {}) {
41432
42196
  failCount++;
41433
42197
  issues++;
41434
42198
  };
41435
- const authorityDbPath = join32(getMagicContextStorageDir(), "context.db");
42199
+ const authorityDbPath = join33(getMagicContextStorageDir(), "context.db");
41436
42200
  let authorityDb = null;
41437
42201
  try {
41438
42202
  authorityDb = openExistingContextDatabase(authorityDbPath, { readonly: true });
@@ -41486,6 +42250,19 @@ async function runDoctor2(options = {}) {
41486
42250
  else
41487
42251
  fail(openCodeDbCheck.message);
41488
42252
  if (openCodeDbCheck.ok) {
42253
+ if (storeGeneration === "v2") {
42254
+ try {
42255
+ const cleanup = await cleanupRetiredHiddenChildren({
42256
+ contextDbPath: authorityDbPath,
42257
+ hostDbPath: openCodeDbResolution.path,
42258
+ fix: options.fix,
42259
+ report: (line) => log2.info(line)
42260
+ });
42261
+ fixed += cleanup.deleted;
42262
+ } catch (error) {
42263
+ fail(`Retired hidden-child cleanup refused: ${error instanceof Error ? error.message : String(error)}`);
42264
+ }
42265
+ }
41489
42266
  let markerDb = null;
41490
42267
  try {
41491
42268
  markerDb = new Database(openCodeDbResolution.path, {
@@ -41593,7 +42370,7 @@ async function runDoctor2(options = {}) {
41593
42370
  pass(`OpenCode config: ${paths.opencodeConfig}`);
41594
42371
  }
41595
42372
  let autoUpdateEnabled = true;
41596
- if (existsSync38(paths.magicContextConfig)) {
42373
+ if (existsSync40(paths.magicContextConfig)) {
41597
42374
  pass(`Magic Context config: ${paths.magicContextConfig}`);
41598
42375
  try {
41599
42376
  const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
@@ -41629,7 +42406,7 @@ async function runDoctor2(options = {}) {
41629
42406
  warn(`No magic-context.jsonc found — using defaults`);
41630
42407
  log2.info(" Run 'setup' to create one with model recommendations");
41631
42408
  }
41632
- if (existsSync38(paths.magicContextConfig)) {
42409
+ if (existsSync40(paths.magicContextConfig)) {
41633
42410
  try {
41634
42411
  const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
41635
42412
  if (!raw)
@@ -41759,7 +42536,7 @@ async function runDoctor2(options = {}) {
41759
42536
  };
41760
42537
  if (paths.opencodeConfigFormat !== "none") {
41761
42538
  try {
41762
- const raw = readFileSync26(paths.opencodeConfig, "utf-8");
42539
+ const raw = readFileSync28(paths.opencodeConfig, "utf-8");
41763
42540
  const config = import_comment_json11.parse(raw);
41764
42541
  const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
41765
42542
  if (checkPluginDuplicates(config, configName, options, {
@@ -41828,9 +42605,9 @@ async function runDoctor2(options = {}) {
41828
42605
  pass("Added TUI sidebar plugin to tui.json");
41829
42606
  warn("Restart OpenCode to see the sidebar");
41830
42607
  fixed++;
41831
- } else if (existsSync38(paths.tuiConfig)) {
42608
+ } else if (existsSync40(paths.tuiConfig)) {
41832
42609
  try {
41833
- const tuiRaw = readFileSync26(paths.tuiConfig, "utf-8");
42610
+ const tuiRaw = readFileSync28(paths.tuiConfig, "utf-8");
41834
42611
  const tuiConfig = import_comment_json11.parse(tuiRaw);
41835
42612
  const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
41836
42613
  const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
@@ -41868,7 +42645,7 @@ async function runDoctor2(options = {}) {
41868
42645
  fail("Could not create or verify the TUI sidebar config");
41869
42646
  }
41870
42647
  }
41871
- if (existsSync38(paths.magicContextConfig)) {
42648
+ if (existsSync40(paths.magicContextConfig)) {
41872
42649
  try {
41873
42650
  const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
41874
42651
  if (!raw)
@@ -41890,9 +42667,9 @@ async function runDoctor2(options = {}) {
41890
42667
  else
41891
42668
  passCount++;
41892
42669
  const storage = getMagicContextStorageResolution();
41893
- const dbPath = join32(storage.path, "context.db");
42670
+ const dbPath = join33(storage.path, "context.db");
41894
42671
  log2.info(`Shared storage: ${storage.path} (source: ${storage.source})`);
41895
- if (!existsSync38(dbPath)) {
42672
+ if (!existsSync40(dbPath)) {
41896
42673
  log2.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
41897
42674
  } else {
41898
42675
  log2.info(`Shared context DB exists at ${dbPath}`);
@@ -41994,7 +42771,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
41994
42771
  let v2DistTag;
41995
42772
  if (paths.opencodeConfigFormat !== "none") {
41996
42773
  try {
41997
- v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(readFileSync26(paths.opencodeConfig, "utf-8")));
42774
+ v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8")));
41998
42775
  } catch {}
41999
42776
  }
42000
42777
  const v2Cache = reportOpenCodeV2PluginCache(checkOpenCodeV2PluginCache({
@@ -42121,16 +42898,17 @@ var init_doctor_opencode = __esm(async () => {
42121
42898
  init_v22_backfill_commands(),
42122
42899
  init_doctor_authority(),
42123
42900
  init_doctor_cached_plugin_fence(),
42124
- init_doctor_harness_relabel()
42901
+ init_doctor_harness_relabel(),
42902
+ init_doctor_hidden_children()
42125
42903
  ]);
42126
42904
  import_comment_json11 = __toESM(require_src3(), 1);
42127
42905
  SHARED_DB_ROW_COUNT_TABLES = ["tags", "compartments", "memories", "notes", "dream_runs"];
42128
42906
  });
42129
42907
 
42130
42908
  // src/lib/diagnostics-pi.ts
42131
- import { existsSync as existsSync39, readdirSync as readdirSync7, readFileSync as readFileSync27, statSync as statSync16 } from "node:fs";
42909
+ import { existsSync as existsSync41, readdirSync as readdirSync8, readFileSync as readFileSync29, statSync as statSync16 } from "node:fs";
42132
42910
  import { createRequire as createRequire7 } from "node:module";
42133
- import { join as join33 } from "node:path";
42911
+ import { join as join34 } from "node:path";
42134
42912
  function getSelfVersion3() {
42135
42913
  const req = createRequire7(import.meta.url);
42136
42914
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -42145,7 +42923,7 @@ function getSelfVersion3() {
42145
42923
  }
42146
42924
  function fileSize2(path) {
42147
42925
  try {
42148
- return existsSync39(path) ? statSync16(path).size : 0;
42926
+ return existsSync41(path) ? statSync16(path).size : 0;
42149
42927
  } catch {
42150
42928
  return 0;
42151
42929
  }
@@ -42157,11 +42935,11 @@ function sanitizeValue2(value) {
42157
42935
  return sanitizeConfigValue(value);
42158
42936
  }
42159
42937
  function readJsonc(path) {
42160
- if (!existsSync39(path))
42938
+ if (!existsSync41(path))
42161
42939
  return { value: {} };
42162
42940
  try {
42163
42941
  return {
42164
- value: import_comment_json12.parse(readFileSync27(path, "utf-8"))
42942
+ value: import_comment_json12.parse(readFileSync29(path, "utf-8"))
42165
42943
  };
42166
42944
  } catch (error) {
42167
42945
  return {
@@ -42177,7 +42955,7 @@ function readConfigDiagnostic(path) {
42177
42955
  const parsed = readJsonc(path);
42178
42956
  return {
42179
42957
  path,
42180
- exists: existsSync39(path),
42958
+ exists: existsSync41(path),
42181
42959
  ...parsed.parseError ? { parseError: parsed.parseError } : {},
42182
42960
  flags: sanitizeValue2(parsed.value)
42183
42961
  };
@@ -42195,25 +42973,25 @@ function reverseSlugToDirectory(slug) {
42195
42973
  }
42196
42974
  function collectPiRecentSessions() {
42197
42975
  const sessionsRoot = getPiSessionsRoot();
42198
- if (!existsSync39(sessionsRoot))
42976
+ if (!existsSync41(sessionsRoot))
42199
42977
  return [];
42200
42978
  try {
42201
- const slugs = readdirSync7(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
42979
+ const slugs = readdirSync8(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
42202
42980
  const candidates = [];
42203
42981
  for (const slug of slugs) {
42204
42982
  const directory = reverseSlugToDirectory(slug);
42205
42983
  if (!directory)
42206
42984
  continue;
42207
- const slugDir = join33(sessionsRoot, slug);
42985
+ const slugDir = join34(sessionsRoot, slug);
42208
42986
  let files;
42209
42987
  try {
42210
- files = readdirSync7(slugDir).filter((name) => name.endsWith(".jsonl"));
42988
+ files = readdirSync8(slugDir).filter((name) => name.endsWith(".jsonl"));
42211
42989
  } catch {
42212
42990
  continue;
42213
42991
  }
42214
42992
  for (const file of files) {
42215
42993
  try {
42216
- const mtime = statSync16(join33(slugDir, file)).mtimeMs;
42994
+ const mtime = statSync16(join34(slugDir, file)).mtimeMs;
42217
42995
  const sessionId = file.replace(/\.jsonl$/, "");
42218
42996
  candidates.push({ sessionId, directory, mtime });
42219
42997
  } catch {}
@@ -42231,7 +43009,7 @@ function collectPiRecentSessions() {
42231
43009
  }
42232
43010
  function parseHistorianDumpMeta2(path) {
42233
43011
  try {
42234
- const xml = readFileSync27(path, "utf-8");
43012
+ const xml = readFileSync29(path, "utf-8");
42235
43013
  const parsed = parseCompartmentOutput(xml);
42236
43014
  const factCountByCategory = {};
42237
43015
  for (const fact of parsed.facts) {
@@ -42264,11 +43042,11 @@ function parseHistorianDumpMeta2(path) {
42264
43042
  }
42265
43043
  }
42266
43044
  function listDumpsInDir2(dir, limit) {
42267
- if (!existsSync39(dir))
43045
+ if (!existsSync41(dir))
42268
43046
  return { count: 0, recent: [] };
42269
43047
  try {
42270
- const entries = readdirSync7(dir).filter((name) => name.endsWith(".xml")).map((name) => {
42271
- const stat = statSync16(join33(dir, name));
43048
+ const entries = readdirSync8(dir).filter((name) => name.endsWith(".xml")).map((name) => {
43049
+ const stat = statSync16(join34(dir, name));
42272
43050
  return {
42273
43051
  name,
42274
43052
  mtime: stat.mtimeMs,
@@ -42277,7 +43055,7 @@ function listDumpsInDir2(dir, limit) {
42277
43055
  }).sort((a, b) => b.mtime - a.mtime);
42278
43056
  const now = Date.now();
42279
43057
  const recent = entries.slice(0, limit).map((entry) => {
42280
- const meta = parseHistorianDumpMeta2(join33(dir, entry.name));
43058
+ const meta = parseHistorianDumpMeta2(join34(dir, entry.name));
42281
43059
  const summary = {
42282
43060
  name: entry.name,
42283
43061
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -42341,7 +43119,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
42341
43119
  const loaded = loadPiConfig({ cwd });
42342
43120
  const storageResolution = getMagicContextStorageResolution();
42343
43121
  const storageDirPath = storageResolution.path;
42344
- const dbPath = join33(storageDirPath, "context.db");
43122
+ const dbPath = join34(storageDirPath, "context.db");
42345
43123
  const logFiles = inspectMagicContextLogs("pi");
42346
43124
  const primaryLog = logFiles.find((file) => file.exists) ?? logFiles[0];
42347
43125
  const otherPiExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
@@ -42358,7 +43136,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
42358
43136
  piVersion: pi ? getPiVersion(pi.path) : null,
42359
43137
  settings: {
42360
43138
  path: settingsPath,
42361
- exists: existsSync39(settingsPath),
43139
+ exists: existsSync41(settingsPath),
42362
43140
  ...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
42363
43141
  hasMagicContextPackage: hasPiMagicContextPackage(packages),
42364
43142
  packages: sanitizeValue2(packages)
@@ -42375,7 +43153,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
42375
43153
  storageDir: {
42376
43154
  path: storageDirPath,
42377
43155
  source: storageResolution.source,
42378
- exists: existsSync39(storageDirPath),
43156
+ exists: existsSync41(storageDirPath),
42379
43157
  contextDbSizeBytes: fileSize2(dbPath)
42380
43158
  },
42381
43159
  conflicts: {
@@ -42480,8 +43258,8 @@ var init_diagnostics_pi = __esm(() => {
42480
43258
  });
42481
43259
 
42482
43260
  // src/lib/logs-pi.ts
42483
- import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "node:fs";
42484
- import { dirname as dirname19, join as join34 } from "node:path";
43261
+ import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
43262
+ import { dirname as dirname21, join as join35 } from "node:path";
42485
43263
  function sanitizeLogContent2(content) {
42486
43264
  return sanitizeString2(content);
42487
43265
  }
@@ -42551,13 +43329,13 @@ async function bundleIssueReport2(report, description, title, options = {}) {
42551
43329
  const truncated = bodyMarkdown !== rawBodyMarkdown;
42552
43330
  const cwd = options.cwd ?? process.cwd();
42553
43331
  const timestamp = formatTimestamp2(options.now ?? new Date);
42554
- const path = options.outputPath ?? join34(cwd, `magic-context-pi-issue-${timestamp}.md`);
42555
- mkdirSync10(dirname19(path), { recursive: true });
42556
- writeFileSync9(path, `${bodyMarkdown}
43332
+ const path = options.outputPath ?? join35(cwd, `magic-context-pi-issue-${timestamp}.md`);
43333
+ mkdirSync12(dirname21(path), { recursive: true });
43334
+ writeFileSync11(path, `${bodyMarkdown}
42557
43335
  `);
42558
- const fullPath = truncated ? options.outputPath ? `${options.outputPath}.full.md` : join34(cwd, `magic-context-pi-issue-${timestamp}-full.md`) : undefined;
43336
+ const fullPath = truncated ? options.outputPath ? `${options.outputPath}.full.md` : join35(cwd, `magic-context-pi-issue-${timestamp}-full.md`) : undefined;
42559
43337
  if (fullPath)
42560
- writeFileSync9(fullPath, `${rawBodyMarkdown}
43338
+ writeFileSync11(fullPath, `${rawBodyMarkdown}
42561
43339
  `);
42562
43340
  return { path, bodyMarkdown, ...fullPath ? { fullPath } : {}, truncated };
42563
43341
  }
@@ -42568,11 +43346,11 @@ var init_logs_pi = __esm(() => {
42568
43346
  });
42569
43347
 
42570
43348
  // src/commands/doctor-pi.ts
42571
- import { execFileSync as execFileSync6, spawnSync as spawnSync9 } from "node:child_process";
42572
- import { existsSync as existsSync40, mkdirSync as mkdirSync11, readdirSync as readdirSync8, readFileSync as readFileSync28, rmSync as rmSync6, statSync as statSync17 } from "node:fs";
43349
+ import { execFileSync as execFileSync7, spawnSync as spawnSync10 } from "node:child_process";
43350
+ import { existsSync as existsSync42, mkdirSync as mkdirSync13, readdirSync as readdirSync9, readFileSync as readFileSync30, rmSync as rmSync6, statSync as statSync17 } from "node:fs";
42573
43351
  import { createRequire as createRequire8 } from "node:module";
42574
- import { homedir as homedir17 } from "node:os";
42575
- import { dirname as dirname20, isAbsolute as isAbsolute8, join as join35 } from "node:path";
43352
+ import { homedir as homedir18 } from "node:os";
43353
+ import { dirname as dirname22, isAbsolute as isAbsolute8, join as join36 } from "node:path";
42576
43354
  function depsFrom(options) {
42577
43355
  return {
42578
43356
  ...DEFAULT_DEPS5,
@@ -42609,7 +43387,8 @@ function selfVersion2() {
42609
43387
  }
42610
43388
  function getLatestNpmVersion(packageName) {
42611
43389
  try {
42612
- return execFileSync6("npm", ["view", packageName, "version"], {
43390
+ return execFileSync7("npm", ["view", packageName, "version"], {
43391
+ windowsHide: true,
42613
43392
  encoding: "utf-8",
42614
43393
  stdio: ["ignore", "pipe", "ignore"],
42615
43394
  timeout: 1e4
@@ -42663,7 +43442,7 @@ function summarize(results) {
42663
43442
  function readJsonc2(path) {
42664
43443
  try {
42665
43444
  return {
42666
- value: import_comment_json13.parse(readFileSync28(path, "utf-8"))
43445
+ value: import_comment_json13.parse(readFileSync30(path, "utf-8"))
42667
43446
  };
42668
43447
  } catch (error) {
42669
43448
  return {
@@ -42713,15 +43492,15 @@ function piPluginDirCandidates(packages, cwd) {
42713
43492
  if (resolved)
42714
43493
  dirs.push(resolved);
42715
43494
  }
42716
- dirs.push(join35(agentDir, "npm", "node_modules", PACKAGE_NAME2));
42717
- dirs.push(join35(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2));
42718
- return dirs.filter((dir) => existsSync40(join35(dir, "package.json")));
43495
+ dirs.push(join36(agentDir, "npm", "node_modules", PACKAGE_NAME2));
43496
+ dirs.push(join36(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2));
43497
+ return dirs.filter((dir) => existsSync42(join36(dir, "package.json")));
42719
43498
  }
42720
43499
  function projectConfigPath(cwd) {
42721
43500
  return resolveCortexKitProjectConfigPath(cwd);
42722
43501
  }
42723
43502
  function readConfigForEmbedding(path, isProjectConfig) {
42724
- if (!existsSync40(path))
43503
+ if (!existsSync42(path))
42725
43504
  return null;
42726
43505
  try {
42727
43506
  const raw = loadRawConfigFile({
@@ -42807,22 +43586,22 @@ function pinnedVersionFromPackageSpecifier(specifier) {
42807
43586
  }
42808
43587
  function cacheRoots(cwd) {
42809
43588
  const home = process.env.HOME?.trim();
42810
- const cacheHome = process.env.XDG_CACHE_HOME || join35(home || homedir17(), ".cache");
43589
+ const cacheHome = process.env.XDG_CACHE_HOME || join36(home || homedir18(), ".cache");
42811
43590
  const piCacheRoot = getPiCacheRoot();
42812
43591
  return [
42813
- join35(piCacheRoot, "extensions"),
42814
- join35(piCacheRoot, "packages"),
42815
- join35(cacheHome, "pi", "extensions"),
42816
- join35(cacheHome, "pi", "packages"),
42817
- join35(getPiAgentConfigDir(), "cache", "extensions"),
42818
- join35(getPiAgentConfigDir(), "npm", "node_modules", PACKAGE_NAME2),
42819
- join35(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2)
43592
+ join36(piCacheRoot, "extensions"),
43593
+ join36(piCacheRoot, "packages"),
43594
+ join36(cacheHome, "pi", "extensions"),
43595
+ join36(cacheHome, "pi", "packages"),
43596
+ join36(getPiAgentConfigDir(), "cache", "extensions"),
43597
+ join36(getPiAgentConfigDir(), "npm", "node_modules", PACKAGE_NAME2),
43598
+ join36(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2)
42820
43599
  ];
42821
43600
  }
42822
43601
  function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
42823
43602
  const found = new Map;
42824
43603
  const visit = (path, depth) => {
42825
- if (depth < 0 || !existsSync40(path))
43604
+ if (depth < 0 || !existsSync42(path))
42826
43605
  return;
42827
43606
  let stat;
42828
43607
  try {
@@ -42832,10 +43611,10 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
42832
43611
  }
42833
43612
  if (!stat.isDirectory())
42834
43613
  return;
42835
- const packageJson = join35(path, "package.json");
42836
- if (existsSync40(packageJson)) {
43614
+ const packageJson = join36(path, "package.json");
43615
+ if (existsSync42(packageJson)) {
42837
43616
  try {
42838
- const pkg = JSON.parse(readFileSync28(packageJson, "utf-8"));
43617
+ const pkg = JSON.parse(readFileSync30(packageJson, "utf-8"));
42839
43618
  const name = typeof pkg.name === "string" ? pkg.name : "";
42840
43619
  const version = typeof pkg.version === "string" ? pkg.version : undefined;
42841
43620
  if (name === PACKAGE_NAME2) {
@@ -42850,12 +43629,12 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
42850
43629
  }
42851
43630
  let entries = [];
42852
43631
  try {
42853
- entries = readdirSync8(path);
43632
+ entries = readdirSync9(path);
42854
43633
  } catch {
42855
43634
  return;
42856
43635
  }
42857
43636
  for (const entry of entries)
42858
- visit(join35(path, entry), depth - 1);
43637
+ visit(join36(path, entry), depth - 1);
42859
43638
  };
42860
43639
  for (const root of cacheRoots(cwd))
42861
43640
  visit(root, 5);
@@ -42900,7 +43679,7 @@ async function runHealthChecks2(options) {
42900
43679
  }
42901
43680
  const settingsPath = getPiUserExtensionsPath();
42902
43681
  let packages = [];
42903
- if (!existsSync40(settingsPath)) {
43682
+ if (!existsSync42(settingsPath)) {
42904
43683
  add2(results, "fail", `Pi settings not found at ${settingsPath}`);
42905
43684
  repairPlan.addPackageEntry = true;
42906
43685
  } else {
@@ -42924,7 +43703,7 @@ async function runHealthChecks2(options) {
42924
43703
  ["user", userConfigPath, true],
42925
43704
  ["project", projectPath, false]
42926
43705
  ]) {
42927
- if (!existsSync40(path)) {
43706
+ if (!existsSync42(path)) {
42928
43707
  if (required) {
42929
43708
  add2(results, "warn", `No ${label} magic-context.jsonc found at ${path}`);
42930
43709
  if (userConfigMigrationRefused) {
@@ -42964,9 +43743,9 @@ async function runHealthChecks2(options) {
42964
43743
  }
42965
43744
  const storage = getMagicContextStorageResolution();
42966
43745
  const storageDir = storage.path;
42967
- const dbPath = join35(storageDir, "context.db");
43746
+ const dbPath = join36(storageDir, "context.db");
42968
43747
  add2(results, "info", `Shared storage: ${storageDir} (source: ${storage.source})`);
42969
- const existedBeforeOpen = existsSync40(dbPath);
43748
+ const existedBeforeOpen = existsSync42(dbPath);
42970
43749
  if (existedBeforeOpen)
42971
43750
  add2(results, "pass", `Shared context DB exists at ${dbPath}`);
42972
43751
  else
@@ -43184,7 +43963,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
43184
43963
  return { results, repairPlan, ...summarize(results) };
43185
43964
  }
43186
43965
  function writeDefaultMagicContextConfig(path) {
43187
- mkdirSync11(dirname20(path), { recursive: true });
43966
+ mkdirSync13(dirname22(path), { recursive: true });
43188
43967
  const config = {
43189
43968
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
43190
43969
  ...MagicContextConfigSchema.parse({})
@@ -43206,7 +43985,7 @@ function repair2(plan, prompts) {
43206
43985
  }
43207
43986
  if (plan.writeUserConfig) {
43208
43987
  const configPath = getPiUserConfigPath();
43209
- if (!existsSync40(configPath)) {
43988
+ if (!existsSync42(configPath)) {
43210
43989
  try {
43211
43990
  writeDefaultMagicContextConfig(configPath);
43212
43991
  prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
@@ -43230,6 +44009,7 @@ function repair2(plan, prompts) {
43230
44009
  function runGhCommandWithDeps2(deps, args) {
43231
44010
  if (args[0] === "issue") {
43232
44011
  const result = deps.spawnSync("gh", args, {
44012
+ windowsHide: true,
43233
44013
  encoding: "utf-8",
43234
44014
  stdio: ["ignore", "pipe", "pipe"]
43235
44015
  });
@@ -43241,6 +44021,7 @@ function runGhCommandWithDeps2(deps, args) {
43241
44021
  }
43242
44022
  try {
43243
44023
  const output = deps.execFileSync("gh", args, {
44024
+ windowsHide: true,
43244
44025
  encoding: "utf-8",
43245
44026
  stdio: ["ignore", "pipe", "pipe"]
43246
44027
  });
@@ -43258,7 +44039,7 @@ async function runIssueFlow3(options) {
43258
44039
  if (options.reportPath) {
43259
44040
  try {
43260
44041
  const report = await options.deps.collectDiagnostics(options.cwd);
43261
- const outputPath = isAbsolute8(options.reportPath) ? options.reportPath : join35(options.cwd, options.reportPath);
44042
+ const outputPath = isAbsolute8(options.reportPath) ? options.reportPath : join36(options.cwd, options.reportPath);
43262
44043
  const bundled = await bundleIssueReport2(report, "Generated non-interactively by `doctor --issue --report`.", "Magic Context diagnostic report", { cwd: options.cwd, now: options.deps.now(), outputPath });
43263
44044
  options.prompts.log.info(`Report written to ${bundled.path}`);
43264
44045
  return 0;
@@ -43342,7 +44123,7 @@ async function runDoctor3(options = {}) {
43342
44123
  const v22Result = await runV22BackfillCommands({
43343
44124
  name: "Pi",
43344
44125
  openDatabase: (readonly = true) => {
43345
- const dbPath = join35(getMagicContextStorageDir(), "context.db");
44126
+ const dbPath = join36(getMagicContextStorageDir(), "context.db");
43346
44127
  v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
43347
44128
  return v22Db;
43348
44129
  },
@@ -43384,7 +44165,7 @@ async function runDoctor3(options = {}) {
43384
44165
  prompts.outro(first.fail > 0 ? "Doctor found failures" : "Doctor complete");
43385
44166
  return first.fail > 0 ? 1 : 0;
43386
44167
  }
43387
- function valueAfter3(args, flag) {
44168
+ function valueAfter2(args, flag) {
43388
44169
  const index = args.indexOf(flag);
43389
44170
  if (index === -1)
43390
44171
  return null;
@@ -43394,8 +44175,8 @@ function valueAfter3(args, flag) {
43394
44175
  return next;
43395
44176
  }
43396
44177
  function parseDoctorArgs(args) {
43397
- const rekeyV22DirIdentity = valueAfter3(args, "--rekey-v22-dir-identity");
43398
- const report = valueAfter3(args, "--report");
44178
+ const rekeyV22DirIdentity = valueAfter2(args, "--rekey-v22-dir-identity");
44179
+ const report = valueAfter2(args, "--report");
43399
44180
  return {
43400
44181
  force: args.includes("--force"),
43401
44182
  issue: args.includes("--issue") || report !== null,
@@ -43452,14 +44233,14 @@ var init_doctor_pi = __esm(async () => {
43452
44233
  probeEmbeddingEndpoint,
43453
44234
  openExistingContextDatabase,
43454
44235
  now: () => new Date,
43455
- execFileSync: execFileSync6,
43456
- spawnSync: spawnSync9
44236
+ execFileSync: execFileSync7,
44237
+ spawnSync: spawnSync10
43457
44238
  };
43458
44239
  });
43459
44240
 
43460
44241
  // src/commands/doctor.ts
43461
- import { existsSync as existsSync41, rmSync as rmSync7 } from "node:fs";
43462
- import { join as join36 } from "node:path";
44242
+ import { existsSync as existsSync43, rmSync as rmSync7 } from "node:fs";
44243
+ import { join as join37 } from "node:path";
43463
44244
  async function runDoctor4(options) {
43464
44245
  if (options.clear)
43465
44246
  return runClear();
@@ -43477,7 +44258,7 @@ async function runDoctor4(options) {
43477
44258
  const result = await runV22BackfillCommands({
43478
44259
  name: "Magic Context",
43479
44260
  openDatabase: (readonly = true) => {
43480
- const dbPath = join36(getMagicContextStorageDir(), "context.db");
44261
+ const dbPath = join37(getMagicContextStorageDir(), "context.db");
43481
44262
  v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
43482
44263
  return v22Db;
43483
44264
  },
@@ -43490,8 +44271,14 @@ async function runDoctor4(options) {
43490
44271
  if (result.handled)
43491
44272
  return result.exitCode;
43492
44273
  }
44274
+ try {
44275
+ for (const line of diagnoseIdentitySplits())
44276
+ log2.warn(line);
44277
+ } catch (error) {
44278
+ log2.warn(`Identity split check unavailable: ${error instanceof Error ? error.message : String(error)}`);
44279
+ }
43493
44280
  await init_migrate();
43494
- const sweepDbPath = join36(getMagicContextStorageDir(), "context.db");
44281
+ const sweepDbPath = join37(getMagicContextStorageDir(), "context.db");
43495
44282
  let sweepDb = null;
43496
44283
  try {
43497
44284
  sweepDb = openExistingContextDatabaseForMutation(sweepDbPath);
@@ -43605,7 +44392,7 @@ async function runClear() {
43605
44392
  failed += 1;
43606
44393
  continue;
43607
44394
  }
43608
- } else if (existsSync41(item.path)) {
44395
+ } else if (existsSync43(item.path)) {
43609
44396
  rmSync7(item.path, { recursive: true, force: true });
43610
44397
  }
43611
44398
  s.stop(`Cleared ${item.path}`);
@@ -43635,6 +44422,7 @@ var init_doctor = __esm(async () => {
43635
44422
  await __promiseAll([
43636
44423
  init_database_access(),
43637
44424
  init_v22_backfill_commands(),
44425
+ init_doctor_identity_splits(),
43638
44426
  init_doctor_omp(),
43639
44427
  init_doctor_opencode(),
43640
44428
  init_doctor_pi()
@@ -43696,7 +44484,7 @@ var DOCTOR_HELP = [
43696
44484
  " drain-authority <project> Drain module memory/note authority back to TypeScript",
43697
44485
  " migrate Migrate an OpenCode session to Pi or OMP JSONL",
43698
44486
  " migrate-session Re-home an OpenCode session to another directory",
43699
- " merge-identity Merge project rows between identities",
44487
+ " merge-identities Preview or explicitly merge split identities",
43700
44488
  " repair-db Back up and salvage a corrupted shared database",
43701
44489
  " list-hidden-sessions List Magic Context OpenCode 2 roots",
43702
44490
  ""
@@ -43712,16 +44500,19 @@ var DRAIN_AUTHORITY_HELP = [
43712
44500
  `);
43713
44501
  var MERGE_IDENTITY_HELP = [
43714
44502
  "",
43715
- " Usage: magic-context doctor merge-identity --from <identity> --to <identity> [--dry-run] [--yes] [--db <path>]",
44503
+ " Usage: magic-context doctor merge-identities [--from <identity> --to <identity>] [--apply] [--force] [--db <path>]",
43716
44504
  "",
43717
44505
  " Merge every project-scoped row from one project identity into another.",
43718
44506
  "",
43719
44507
  " Options:",
43720
44508
  " --from <identity> Identity whose rows are moved",
43721
44509
  " --to <identity> Identity that receives them",
43722
- " --dry-run Report what would change without writing",
43723
- " --yes Confirm the write (required unless --dry-run)",
44510
+ " (no flags) List splits; --from/--to previews without writing",
44511
+ " --apply Confirm the reviewed preview; hosts must be closed",
44512
+ " --force Permit a target not resolving on this machine",
43724
44513
  " --db <path> Use this context.db instead of the shared one",
44514
+ " --host-db <path> Read session directories from this host database",
44515
+ " Legacy alias: doctor merge-identity; --dry-run previews, --yes applies",
43725
44516
  ""
43726
44517
  ].join(`
43727
44518
  `);
@@ -43745,7 +44536,7 @@ function subcommandHelp(argv) {
43745
44536
  const subcommand = rest[0];
43746
44537
  if (subcommand === "drain-authority")
43747
44538
  return DRAIN_AUTHORITY_HELP;
43748
- if (subcommand === "merge-identity")
44539
+ if (subcommand === "merge-identity" || subcommand === "merge-identities")
43749
44540
  return MERGE_IDENTITY_HELP;
43750
44541
  if (subcommand === "list-hidden-sessions")
43751
44542
  return LIST_HIDDEN_SESSIONS_HELP;
@@ -43794,7 +44585,7 @@ function getVersion() {
43794
44585
  }
43795
44586
  return "0.0.0";
43796
44587
  }
43797
- function valueAfter4(args, flag) {
44588
+ function valueAfter3(args, flag) {
43798
44589
  const index = args.indexOf(flag);
43799
44590
  if (index === -1)
43800
44591
  return null;
@@ -43879,7 +44670,7 @@ async function main(argv = process.argv.slice(2)) {
43879
44670
  ]);
43880
44671
  return runDoctorDrainAuthority(projectRoot, join(getMagicContextStorageDir(), "context.db"));
43881
44672
  }
43882
- if (rest[0] === "merge-identity") {
44673
+ if (rest[0] === "merge-identities" || rest[0] === "merge-identity") {
43883
44674
  await init_doctor_merge_identity();
43884
44675
  return runMergeIdentityCli(rest.slice(1));
43885
44676
  }
@@ -43900,8 +44691,8 @@ async function main(argv = process.argv.slice(2)) {
43900
44691
  return runMigrateSessionCli(rest.slice(1));
43901
44692
  }
43902
44693
  await init_doctor();
43903
- const rekeyV22DirIdentity = valueAfter4(rest, "--rekey-v22-dir-identity");
43904
- const report = valueAfter4(rest, "--report");
44694
+ const rekeyV22DirIdentity = valueAfter3(rest, "--rekey-v22-dir-identity");
44695
+ const report = valueAfter3(rest, "--report");
43905
44696
  return runDoctor4({
43906
44697
  force: rest.includes("--force"),
43907
44698
  fix: rest.includes("--fix"),