@cortexkit/magic-context 0.44.1 → 0.44.3

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 +1288 -464
  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,65 @@ 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
+ if (transformPassScope.getStore()?.active || backgroundWriterScope.getStore())
1692
+ acquireShort(db, () => nativeExec(sql), sql.trim());
1693
+ else
1694
+ nativeExec(sql);
1695
+ return db;
1696
+ }
1697
+ return nativeExec(sql);
1698
+ }
1699
+ });
1700
+ Object.defineProperty(db, "transaction", {
1701
+ configurable: true,
1702
+ writable: true,
1703
+ value: (fn) => {
1704
+ const make = (mode) => function(...args) {
1705
+ const nested = isInTransaction(db);
1706
+ const savepoint = "mc_tx_sp";
1707
+ db.exec(nested ? `SAVEPOINT ${savepoint}` : `BEGIN ${mode}`);
1708
+ try {
1709
+ const result = fn.apply(this, args);
1710
+ db.exec(nested ? `RELEASE ${savepoint}` : "COMMIT");
1711
+ return result;
1712
+ } catch (error) {
1713
+ if (isInTransaction(db)) {
1714
+ if (nested) {
1715
+ db.exec(`ROLLBACK TO ${savepoint}`);
1716
+ db.exec(`RELEASE ${savepoint}`);
1717
+ } else
1718
+ db.exec("ROLLBACK");
1719
+ }
1720
+ throw error;
1721
+ }
1722
+ };
1723
+ const defaultTransaction = make(readonly ? "DEFERRED" : "IMMEDIATE");
1724
+ const variants = {
1725
+ default: defaultTransaction,
1726
+ deferred: make("DEFERRED"),
1727
+ immediate: make("IMMEDIATE"),
1728
+ exclusive: make("EXCLUSIVE"),
1729
+ database: db
1730
+ };
1731
+ for (const transaction of [
1732
+ variants.default,
1733
+ variants.deferred,
1734
+ variants.immediate,
1735
+ variants.exclusive
1736
+ ]) {
1737
+ Object.assign(transaction, variants);
1738
+ }
1739
+ return defaultTransaction;
1740
+ }
1741
+ });
1742
+ }
1683
1743
  function trackSqliteConnection(db, filename, options) {
1684
1744
  const originalClose = db.close.bind(db);
1685
1745
  const sequence = nextSqliteConnectionSequence++;
@@ -1688,6 +1748,7 @@ function trackSqliteConnection(db, filename, options) {
1688
1748
  filename: typeof filename === "string" ? filename : Buffer.isBuffer(filename) ? "<buffer>" : ":memory:",
1689
1749
  readonly: Boolean(options) && typeof options === "object" && (options.readonly === true || options.readOnly === true)
1690
1750
  };
1751
+ installTransactionRouting(db, metadata.readonly);
1691
1752
  Object.defineProperty(db, "close", {
1692
1753
  configurable: true,
1693
1754
  value: (...args) => {
@@ -1705,7 +1766,6 @@ function trackSqliteConnection(db, filename, options) {
1705
1766
  return db;
1706
1767
  }
1707
1768
  function buildNodeSqliteDatabaseClass(DatabaseSync) {
1708
- const SAVEPOINT = "mc_tx_sp";
1709
1769
 
1710
1770
  class NodeSqliteDatabase extends DatabaseSync {
1711
1771
  constructor(filename, options) {
@@ -1724,45 +1784,50 @@ function buildNodeSqliteDatabaseClass(DatabaseSync) {
1724
1784
  }
1725
1785
  return stmt;
1726
1786
  }
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
1787
  }
1764
1788
  return NodeSqliteDatabase;
1765
1789
  }
1790
+ function pragmaValue(db, name) {
1791
+ const row = db.prepare(`PRAGMA ${name}`).get();
1792
+ if (!row)
1793
+ return;
1794
+ return row[name] ?? Object.values(row)[0];
1795
+ }
1796
+ function pragmaNumber(db, name) {
1797
+ try {
1798
+ const value = pragmaValue(db, name);
1799
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
1800
+ } catch {
1801
+ return null;
1802
+ }
1803
+ }
1804
+ function isTransientSqliteError(error) {
1805
+ if (!error || typeof error !== "object")
1806
+ return false;
1807
+ const value = error;
1808
+ return typeof value.code === "string" && /^(SQLITE_BUSY|SQLITE_LOCKED)(_|$)/.test(value.code) || typeof value.errcode === "number" && [5, 6].includes(value.errcode & 255);
1809
+ }
1810
+ function acquireShort(db, acquire, site) {
1811
+ const started = performance.now();
1812
+ const previous = pragmaNumber(db, "busy_timeout");
1813
+ let acquired = false;
1814
+ try {
1815
+ const timeout = transformPassScope.getStore()?.active && !admissionScope.getStore() && !backgroundWriterScope.getStore() ? FOREGROUND_IN_PASS_BUSY_TIMEOUT_MS : SHORT_BUSY_TIMEOUT_MS;
1816
+ db.exec(`PRAGMA busy_timeout=${timeout}`);
1817
+ acquire();
1818
+ acquired = true;
1819
+ } catch (error) {
1820
+ if (transformPassScope.getStore()?.active && isTransientSqliteError(error))
1821
+ throw new SqliteAcquisitionBusyError(error, site);
1822
+ throw error;
1823
+ } finally {
1824
+ if (previous !== null)
1825
+ db.exec(`PRAGMA busy_timeout=${previous}`);
1826
+ const elapsed = performance.now() - started;
1827
+ if (elapsed >= 250)
1828
+ console.warn(`[${new Date().toISOString()}] [magic-context] sqlite acquisition site=${site} lane=${transformPassScope.getStore()?.active ? "foreground" : "background"} elapsed=${Math.round(elapsed)}ms attempts=1 outcome=${acquired ? "acquired" : "busy"}`);
1829
+ }
1830
+ }
1766
1831
  function isInTransaction(db) {
1767
1832
  const candidate = db;
1768
1833
  return candidate.inTransaction === true || candidate.isTransaction === true;
@@ -1775,7 +1840,13 @@ function withPrivilegedWriter(db, operation) {
1775
1840
  if (nested) {
1776
1841
  db.exec(`SAVEPOINT ${savepoint}`);
1777
1842
  } else {
1778
- db.exec("BEGIN IMMEDIATE");
1843
+ try {
1844
+ db.exec("BEGIN IMMEDIATE");
1845
+ } catch (error) {
1846
+ if (transformPassScope.getStore()?.active && isTransientSqliteError(error))
1847
+ throw new SqliteAcquisitionBusyError(error);
1848
+ throw error;
1849
+ }
1779
1850
  }
1780
1851
  privilegeDepth.set(db, previousDepth + 1);
1781
1852
  try {
@@ -1814,7 +1885,7 @@ function withPrivilegedWriter(db, operation) {
1814
1885
  throw error;
1815
1886
  }
1816
1887
  }
1817
- var reportSlowPrivilegedWrite, bunSpec, nodeSpec, SqliteRuntimeUnavailableError, detectedRuntime, isBun, sqliteModule, DatabaseImpl, trackedSqliteConnections, nextSqliteConnectionSequence = 1, TrackedDatabase, Database, privilegeDepth;
1888
+ var reportSlowPrivilegedWrite, bunSpec, nodeSpec, SqliteRuntimeUnavailableError, detectedRuntime, isBun, sqliteModule, DatabaseImpl, trackedSqliteConnections, nextSqliteConnectionSequence = 1, TrackedDatabase, Database, privilegeDepth, transformPassScope, admissionScope, backgroundWriterScope, SqliteAcquisitionBusyError, SHORT_BUSY_TIMEOUT_MS = 25, FOREGROUND_IN_PASS_BUSY_TIMEOUT_MS = 250;
1818
1889
  var init_sqlite = __esm(async () => {
1819
1890
  bunSpec = "bun:" + "sqlite";
1820
1891
  nodeSpec = "node:" + "sqlite";
@@ -1842,6 +1913,18 @@ var init_sqlite = __esm(async () => {
1842
1913
  });
1843
1914
  Database = TrackedDatabase;
1844
1915
  privilegeDepth = new WeakMap;
1916
+ transformPassScope = new AsyncLocalStorage;
1917
+ admissionScope = new AsyncLocalStorage;
1918
+ backgroundWriterScope = new AsyncLocalStorage;
1919
+ SqliteAcquisitionBusyError = class SqliteAcquisitionBusyError extends Error {
1920
+ code = "SQLITE_BUSY";
1921
+ stage;
1922
+ constructor(cause, stage = "BEGIN IMMEDIATE") {
1923
+ super("SQLite writer acquisition remained busy", { cause });
1924
+ this.name = "SqliteAcquisitionBusyError";
1925
+ this.stage = stage;
1926
+ }
1927
+ };
1845
1928
  });
1846
1929
 
1847
1930
  // src/lib/docs-proposal-gitignore.ts
@@ -4270,6 +4353,7 @@ function getPiVersion(piPath) {
4270
4353
  try {
4271
4354
  const invocation = getPiCommandInvocation(piPath, ["--version"]);
4272
4355
  const result = spawnSync(invocation.command, invocation.args, {
4356
+ windowsHide: true,
4273
4357
  encoding: "utf-8",
4274
4358
  timeout: 1e4
4275
4359
  });
@@ -4288,6 +4372,7 @@ function runPiCommand(piPath, args, timeout = 20000) {
4288
4372
  try {
4289
4373
  const invocation = getPiCommandInvocation(piPath, args);
4290
4374
  return execFileSync(invocation.command, invocation.args, {
4375
+ windowsHide: true,
4291
4376
  encoding: "utf-8",
4292
4377
  stdio: ["ignore", "pipe", "ignore"],
4293
4378
  timeout
@@ -4403,6 +4488,7 @@ function runOmpCommand(ompPath, args, timeout = 30000, overrides = {}) {
4403
4488
  try {
4404
4489
  const invocation = deps.getInvocation(ompPath, args);
4405
4490
  const result = deps.spawnSync(invocation.command, invocation.args, {
4491
+ windowsHide: true,
4406
4492
  encoding: "utf-8",
4407
4493
  timeout,
4408
4494
  maxBuffer: 10 * 1024 * 1024,
@@ -12794,7 +12880,7 @@ var init_opencode_plugin_cache = __esm(() => {
12794
12880
  import { spawnSync as spawnSync3 } from "node:child_process";
12795
12881
  import { existsSync as existsSync8, rmSync as rmSync2 } from "node:fs";
12796
12882
  function runLsof(args, spawn) {
12797
- const result = spawn("lsof", args, { encoding: "utf-8", timeout: 15000 });
12883
+ const result = spawn("lsof", args, { encoding: "utf-8", timeout: 15000, windowsHide: true });
12798
12884
  if (result.error)
12799
12885
  return { error: result.error.message };
12800
12886
  if (result.status !== 0 && result.status !== 1) {
@@ -13160,7 +13246,11 @@ function getOpenCodeCommandInvocation(binary, args) {
13160
13246
  }
13161
13247
  function runOpenCode(args, binary, timeoutMs) {
13162
13248
  try {
13163
- const options = { stdio: "pipe", ...timeoutMs ? { timeout: timeoutMs } : {} };
13249
+ const options = {
13250
+ stdio: "pipe",
13251
+ windowsHide: true,
13252
+ ...timeoutMs ? { timeout: timeoutMs } : {}
13253
+ };
13164
13254
  if (binary) {
13165
13255
  const invocation = getOpenCodeCommandInvocation(binary, args);
13166
13256
  return execFileSync2(invocation.command, invocation.args, {
@@ -14676,6 +14766,49 @@ function parseCron(expression) {
14676
14766
  function isValidCron(expression) {
14677
14767
  return parseCron(expression).ok;
14678
14768
  }
14769
+ function matchesDay(cron, date) {
14770
+ const dom = cron.dom.has(date.getDate());
14771
+ const dow = cron.dow.has(date.getDay());
14772
+ if (cron.domRestricted && cron.dowRestricted)
14773
+ return dom || dow;
14774
+ if (cron.domRestricted)
14775
+ return dom;
14776
+ if (cron.dowRestricted)
14777
+ return dow;
14778
+ return true;
14779
+ }
14780
+ function matchesCron(cron, date) {
14781
+ return cron.minute.has(date.getMinutes()) && cron.hour.has(date.getHours()) && cron.month.has(date.getMonth() + 1) && matchesDay(cron, date);
14782
+ }
14783
+ function civilMinuteKey(date) {
14784
+ const p = (n, w = 2) => String(n).padStart(w, "0");
14785
+ return `${p(date.getFullYear(), 4)}-${p(date.getMonth() + 1)}-${p(date.getDate())} ${p(date.getHours())}:${p(date.getMinutes())}`;
14786
+ }
14787
+ function nextOccurrence(cron, after, excludeCivilMinute, maxSearchMs = MAX_SEARCH_MS) {
14788
+ const afterMs = after.getTime();
14789
+ let cursorMs = Math.floor(afterMs / MINUTE_MS) * MINUTE_MS + MINUTE_MS;
14790
+ const capMs = afterMs + Math.max(0, Math.min(MAX_SEARCH_MS, maxSearchMs));
14791
+ while (cursorMs <= capMs) {
14792
+ const candidate = new Date(cursorMs);
14793
+ if (matchesCron(cron, candidate)) {
14794
+ if (!excludeCivilMinute || civilMinuteKey(candidate) !== excludeCivilMinute) {
14795
+ return candidate;
14796
+ }
14797
+ }
14798
+ cursorMs += MINUTE_MS;
14799
+ }
14800
+ return null;
14801
+ }
14802
+ function nextDueAtMs(expression, afterMs, consumedScheduledAtMs, maxSearchMs = MAX_SEARCH_MS) {
14803
+ if (expression.trim().length === 0)
14804
+ return null;
14805
+ const parsed = parseCron(expression);
14806
+ if (!parsed.ok)
14807
+ return null;
14808
+ const exclude = consumedScheduledAtMs !== undefined ? civilMinuteKey(new Date(consumedScheduledAtMs)) : undefined;
14809
+ const next = nextOccurrence(parsed.cron, new Date(afterMs), exclude, maxSearchMs);
14810
+ return next ? next.getTime() : null;
14811
+ }
14679
14812
  var FIELDS, MINUTE_MS = 60000, MAX_SEARCH_MS;
14680
14813
  var init_cron = __esm(() => {
14681
14814
  FIELDS = [
@@ -21156,9 +21289,9 @@ import { homedir as homedir9 } from "node:os";
21156
21289
  function defaultTaskConfig(task) {
21157
21290
  const base = { schedule: DEFAULT_TASK_SCHEDULES2[task] };
21158
21291
  if (task === "review-user-memories")
21159
- base.promotion_threshold = 3;
21292
+ base.promotion_threshold = DREAM_TASK_PROMOTION_DEFAULTS["review-user-memories"];
21160
21293
  if (task === "promote-primers")
21161
- base.promotion_threshold = 2;
21294
+ base.promotion_threshold = DREAM_TASK_PROMOTION_DEFAULTS["promote-primers"];
21162
21295
  return base;
21163
21296
  }
21164
21297
  function expandConfigPath(value) {
@@ -21169,7 +21302,7 @@ function expandConfigPath(value) {
21169
21302
  return `${homedir9()}/${trimmed.slice(2)}`;
21170
21303
  return trimmed;
21171
21304
  }
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;
21305
+ 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
21306
  var init_magic_context = __esm(() => {
21174
21307
  init_zod();
21175
21308
  init_language_directive();
@@ -21346,10 +21479,15 @@ var init_magic_context = __esm(() => {
21346
21479
  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
21480
  }).describe('5-field cron schedule (e.g. "0 3 * * *"), or "" to disable this task.');
21348
21481
  DreamTaskBaseConfigSchema = object({
21349
- schedule: CronScheduleSchema.default("")
21482
+ schedule: CronScheduleSchema.default(""),
21483
+ 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
21484
  }).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)");
21485
+ DREAM_TASK_PROMOTION_DEFAULTS = {
21486
+ "review-user-memories": 3,
21487
+ "promote-primers": 2
21488
+ };
21489
+ 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)");
21490
+ 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
21491
  DreamTaskConfigSchema = DreamTaskBaseConfigSchema.extend({
21354
21492
  promotion_threshold: PromotionThresholdSchema
21355
21493
  });
@@ -21526,7 +21664,7 @@ var init_magic_context = __esm(() => {
21526
21664
  });
21527
21665
  MagicContextConfigSchema = object({
21528
21666
  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."),
21667
+ 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
21668
  mural: object({
21531
21669
  enabled: boolean2().default(false),
21532
21670
  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 +25043,48 @@ var init_context_authority = __esm(async () => {
24905
25043
  mirrorFlights = new WeakMap;
24906
25044
  });
24907
25045
 
25046
+ // ../plugin/src/features/magic-context/memory/project-identity-cache.ts
25047
+ import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
25048
+ import { mkdirSync as mkdirSync6, readFileSync as readFileSync14, renameSync as renameSync4, writeFileSync as writeFileSync5 } from "node:fs";
25049
+ import path3 from "node:path";
25050
+ function projectDirectoryKey(directory) {
25051
+ const slashed = directory.replaceAll("\\", "/").replace(/^\/\/\?\/UNC\//i, "//").replace(/^\/\/\?\//, "");
25052
+ if (/^[a-z]:\//i.test(slashed) || slashed.startsWith("//")) {
25053
+ return path3.win32.normalize(slashed).replaceAll("\\", "/").replace(/\/$/, "").toLowerCase();
25054
+ }
25055
+ return path3.resolve(directory);
25056
+ }
25057
+ function cachePath(directory) {
25058
+ const hash = createHash2("sha256").update(projectDirectoryKey(directory)).digest("hex");
25059
+ return path3.join(getMagicContextStorageDir(), "project-identities", `${hash}.json`);
25060
+ }
25061
+ function rememberGitIdentity(directory, identity) {
25062
+ try {
25063
+ const destination = cachePath(directory);
25064
+ mkdirSync6(path3.dirname(destination), { recursive: true });
25065
+ const temporary = `${destination}.${randomUUID2()}.tmp`;
25066
+ writeFileSync5(temporary, JSON.stringify({ directory: projectDirectoryKey(directory), identity }), { mode: 384 });
25067
+ renameSync4(temporary, destination);
25068
+ } catch {}
25069
+ }
25070
+ function readRememberedGitIdentity(directory) {
25071
+ try {
25072
+ const record = JSON.parse(readFileSync14(cachePath(directory), "utf8"));
25073
+ if (record.directory === projectDirectoryKey(directory) && /^git:[0-9a-f]{7,64}$/.test(record.identity))
25074
+ return record.identity;
25075
+ } catch {}
25076
+ return;
25077
+ }
25078
+ var init_project_identity_cache = __esm(() => {
25079
+ init_data_path();
25080
+ });
25081
+
24908
25082
  // ../plugin/src/features/magic-context/memory/project-identity.ts
24909
25083
  import { execFileSync as execFileSync3 } from "node:child_process";
24910
- import { createHash as createHash2 } from "node:crypto";
25084
+ import { createHash as createHash3 } from "node:crypto";
24911
25085
  import { existsSync as existsSync21, realpathSync as realpathSync2, statSync as statSync9 } from "node:fs";
24912
- import path3 from "node:path";
25086
+ import { homedir as homedir14 } from "node:os";
25087
+ import path4 from "node:path";
24913
25088
  function asError(error) {
24914
25089
  return error instanceof Error ? error : undefined;
24915
25090
  }
@@ -24947,8 +25122,8 @@ function getErrorStderr(error) {
24947
25122
  return "";
24948
25123
  }
24949
25124
  function directoryFallback(directory) {
24950
- const canonical = path3.resolve(directory);
24951
- const hash = createHash2("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
25125
+ const canonical = path4.resolve(directory);
25126
+ const hash = createHash3("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
24952
25127
  return `dir:${hash}`;
24953
25128
  }
24954
25129
  function assertDirectoryUsable(canonicalDirectory, rawDirectory) {
@@ -24993,8 +25168,9 @@ function classifyGitError(error, rawDirectory) {
24993
25168
  }
24994
25169
  return new ProjectIdentityError("unknown", rawDirectory, "git rev-list failed while resolving project identity", asError(error));
24995
25170
  }
24996
- function resolveProjectIdentityStrict(directory) {
24997
- const canonical = path3.resolve(directory);
25171
+ function resolveProjectIdentityStrict(directory, allowHomeProject = homeProjectPermission) {
25172
+ assertProjectAllowed(directory, allowHomeProject);
25173
+ const canonical = path4.resolve(directory);
24998
25174
  const cached = identityCache.get(canonical);
24999
25175
  if (cached !== undefined) {
25000
25176
  return cached;
@@ -25010,7 +25186,8 @@ function resolveProjectIdentityStrict(directory) {
25010
25186
  encoding: "utf8",
25011
25187
  env: { ...process.env, LC_ALL: "C", LANG: "C" },
25012
25188
  stdio: ["ignore", "pipe", "pipe"],
25013
- timeout: GIT_TIMEOUT_MS
25189
+ timeout: GIT_TIMEOUT_MS,
25190
+ windowsHide: true
25014
25191
  });
25015
25192
  } catch (error) {
25016
25193
  throw classifyGitError(error, directory);
@@ -25023,13 +25200,17 @@ function resolveProjectIdentityStrict(directory) {
25023
25200
  const identity = `git:${rootCommit}`;
25024
25201
  identityCache.set(canonical, identity);
25025
25202
  lastKnownGitIdentityCache.set(canonical, identity);
25203
+ rememberGitIdentity(canonical, identity);
25204
+ const root = gitRootDirectory(canonical);
25205
+ if (root && root !== canonical)
25206
+ rememberGitIdentity(root, identity);
25026
25207
  transientFailureCooldown.delete(canonical);
25027
25208
  dubiousOwnershipFallbackDirectories.delete(canonical);
25028
25209
  transientGitIdentityReuseLoggedDirectories.delete(canonical);
25029
25210
  return identity;
25030
25211
  }
25031
25212
  function shouldUseDirectoryFallback(error) {
25032
- return error.errorClass !== "permission_denied";
25213
+ return error.errorClass !== "home_project_disabled";
25033
25214
  }
25034
25215
  function getActiveCooldown(canonical) {
25035
25216
  const until = transientFailureCooldown.get(canonical);
@@ -25041,7 +25222,7 @@ function getActiveCooldown(canonical) {
25041
25222
  return;
25042
25223
  }
25043
25224
  function lastKnownGitIdentity(canonical) {
25044
- return lastKnownGitIdentityCache.get(canonical) ?? identityCache.get(canonical);
25225
+ return lastKnownGitIdentityCache.get(canonical) ?? identityCache.get(canonical) ?? readRememberedGitIdentity(canonical);
25045
25226
  }
25046
25227
  function nearestLastKnownGitIdentity(canonical) {
25047
25228
  const visited = new Set;
@@ -25052,7 +25233,9 @@ function nearestLastKnownGitIdentity(canonical) {
25052
25233
  const cached = lastKnownGitIdentity(current);
25053
25234
  if (cached !== undefined)
25054
25235
  return { identity: cached, source: current };
25055
- const parent = path3.dirname(current);
25236
+ if (existsSync21(path4.join(current, ".git")))
25237
+ break;
25238
+ const parent = path4.dirname(current);
25056
25239
  if (parent === current)
25057
25240
  break;
25058
25241
  current = parent;
@@ -25081,7 +25264,7 @@ function reuseLastKnownGitIdentity(canonical) {
25081
25264
  return cached.identity;
25082
25265
  }
25083
25266
  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}`;
25267
+ 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
25268
  }
25086
25269
  function recordDubiousOwnershipFallback(canonical) {
25087
25270
  dubiousOwnershipFallbackDirectories.add(canonical);
@@ -25090,8 +25273,32 @@ function recordDubiousOwnershipFallback(canonical) {
25090
25273
  dubiousOwnershipLoggedDirectories.add(canonical);
25091
25274
  log3(`[magic-context] ${formatDubiousOwnershipWarning(canonical)}`);
25092
25275
  }
25093
- function resolveProjectIdentity(directory) {
25094
- const canonical = path3.resolve(directory);
25276
+ function canonicalUserHomeDirectory() {
25277
+ const homeDirectory = userHomeDirectoryForIdentity();
25278
+ try {
25279
+ return realpathSync2.native(homeDirectory);
25280
+ } catch {
25281
+ return homeDirectory;
25282
+ }
25283
+ }
25284
+ function isUserHomeDirectory(directory) {
25285
+ if (projectDirectoryKey(directory) === projectDirectoryKey(userHomeDirectoryForIdentity()))
25286
+ return true;
25287
+ try {
25288
+ return projectDirectoryKey(realpathSync2.native(path4.resolve(directory))) === projectDirectoryKey(canonicalUserHomeDirectory());
25289
+ } catch {
25290
+ return false;
25291
+ }
25292
+ }
25293
+ function assertProjectAllowed(directory, allowHomeProject) {
25294
+ const canonical = path4.resolve(directory);
25295
+ if (!allowHomeProject && (isUserHomeDirectory(directory) || isUserHomeDirectory(gitRootDirectory(canonical) ?? canonical))) {
25296
+ throw new ProjectIdentityError("home_project_disabled", directory, "Home project memory is disabled; set allow_home_project to opt in");
25297
+ }
25298
+ }
25299
+ function resolveProjectIdentity(directory, allowHomeProject = homeProjectPermission) {
25300
+ assertProjectAllowed(directory, allowHomeProject);
25301
+ const canonical = path4.resolve(directory);
25095
25302
  const cachedFallback = directoryFallbackCache.get(canonical);
25096
25303
  if (cachedFallback !== undefined) {
25097
25304
  if (!hasGitDir(canonical)) {
@@ -25105,27 +25312,30 @@ function resolveProjectIdentity(directory) {
25105
25312
  if (cachedGitIdentity !== undefined) {
25106
25313
  return cachedGitIdentity;
25107
25314
  }
25315
+ throw new ProjectIdentityError("git_identity_unavailable", directory, "Git identity unavailable; memory features paused until the retry cooldown expires");
25108
25316
  }
25109
25317
  return directoryFallback(canonical);
25110
25318
  }
25111
25319
  try {
25112
- return resolveProjectIdentityStrict(directory);
25320
+ return resolveProjectIdentityStrict(directory, allowHomeProject);
25113
25321
  } catch (error) {
25114
25322
  if (error instanceof ProjectIdentityError && shouldUseDirectoryFallback(error)) {
25115
25323
  const fallback = directoryFallback(canonical);
25116
25324
  const hasGitMetadata = hasGitDir(canonical);
25117
25325
  if (!hasGitMetadata) {
25326
+ if (error.errorClass === "permission_denied")
25327
+ throw error;
25118
25328
  directoryFallbackCache.set(canonical, fallback);
25119
25329
  transientFailureCooldown.delete(canonical);
25120
25330
  } else {
25121
25331
  transientFailureCooldown.set(canonical, nowMs() + TRANSIENT_FAILURE_COOLDOWN_MS);
25122
25332
  const cachedGitIdentity = reuseLastKnownGitIdentity(canonical);
25333
+ if (error.errorClass === "dubious_ownership")
25334
+ recordDubiousOwnershipFallback(canonical);
25123
25335
  if (cachedGitIdentity !== undefined) {
25124
25336
  return cachedGitIdentity;
25125
25337
  }
25126
- }
25127
- if (error.errorClass === "dubious_ownership") {
25128
- recordDubiousOwnershipFallback(canonical);
25338
+ throw error;
25129
25339
  }
25130
25340
  return fallback;
25131
25341
  }
@@ -25146,14 +25356,14 @@ function hasGitDir(canonical) {
25146
25356
  function gitRootInAncestorChain(startDirectory) {
25147
25357
  let current = startDirectory;
25148
25358
  while (true) {
25149
- if (existsSync21(path3.join(current, ".git"))) {
25359
+ if (existsSync21(path4.join(current, ".git"))) {
25150
25360
  try {
25151
25361
  return realpathSync2.native(current);
25152
25362
  } catch {
25153
- return path3.resolve(current);
25363
+ return path4.resolve(current);
25154
25364
  }
25155
25365
  }
25156
- const parent = path3.dirname(current);
25366
+ const parent = path4.dirname(current);
25157
25367
  if (parent === current) {
25158
25368
  return null;
25159
25369
  }
@@ -25163,9 +25373,21 @@ function gitRootInAncestorChain(startDirectory) {
25163
25373
  function hasGitDirInAncestorChain(startDirectory) {
25164
25374
  return gitRootInAncestorChain(startDirectory) !== null;
25165
25375
  }
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;
25376
+ function gitRootDirectory(canonical) {
25377
+ const direct = gitRootInAncestorChain(canonical);
25378
+ if (direct)
25379
+ return direct;
25380
+ try {
25381
+ const realCanonical = realpathSync2.native(canonical);
25382
+ return realCanonical === canonical ? null : gitRootInAncestorChain(realCanonical);
25383
+ } catch {
25384
+ return null;
25385
+ }
25386
+ }
25387
+ var GIT_TIMEOUT_MS = 5000, TRANSIENT_FAILURE_COOLDOWN_MS, identityCache, linkedGitWorktreeCache, lastKnownGitIdentityCache, directoryFallbackCache, transientFailureCooldown, dubiousOwnershipFallbackDirectories, dubiousOwnershipLoggedDirectories, dubiousOwnershipWarnedDirectories, transientGitIdentityReuseLoggedDirectories, sessionIdentityCache, homeProjectPermission = false, execFileSyncForIdentity, userHomeDirectoryForIdentity = () => homedir14(), nowMs = () => Date.now(), ProjectIdentityError;
25167
25388
  var init_project_identity = __esm(() => {
25168
25389
  init_logger();
25390
+ init_project_identity_cache();
25169
25391
  TRANSIENT_FAILURE_COOLDOWN_MS = 5 * 60 * 1000;
25170
25392
  identityCache = new Map;
25171
25393
  linkedGitWorktreeCache = new Map;
@@ -26865,6 +27087,11 @@ var init_user_facing_codes = __esm(() => {
26865
27087
  sentence: "Memory maintenance stopped at its hidden agent step limit.",
26866
27088
  action: "This task needs less work per run; changing the model connection will not help."
26867
27089
  },
27090
+ dream_token_budget: {
27091
+ code: "MC-D11",
27092
+ sentence: "Memory maintenance reached its prompt-token budget.",
27093
+ action: "The unfinished items will be retried on the next run."
27094
+ },
26868
27095
  dream_empty_completion: {
26869
27096
  code: "MC-D03",
26870
27097
  sentence: "Memory maintenance received no usable response.",
@@ -27776,8 +28003,8 @@ var init_pi_executable = __esm(() => {
27776
28003
  });
27777
28004
 
27778
28005
  // ../plugin/src/shared/rpc-utils.ts
27779
- import { execFileSync as execFileSync4 } from "node:child_process";
27780
- import { readFileSync as readFileSync14 } from "node:fs";
28006
+ import { execFile, execFileSync as execFileSync4 } from "node:child_process";
28007
+ import { readFileSync as readFileSync15 } from "node:fs";
27781
28008
  function isOwnRpcServerRecord(record) {
27782
28009
  return record.pid === process.pid && record.instance_id !== undefined && ownRpcServerInstanceIds.has(record.instance_id);
27783
28010
  }
@@ -27820,7 +28047,8 @@ function readPsProcessStartTime(pid) {
27820
28047
  const output = rpcIdentityExecFileSync("ps", ["-p", String(pid), "-o", "lstart="], {
27821
28048
  encoding: "utf8",
27822
28049
  timeout: PS_PROBE_TIMEOUT_MS,
27823
- stdio: ["ignore", "pipe", "pipe"]
28050
+ stdio: ["ignore", "pipe", "pipe"],
28051
+ windowsHide: true
27824
28052
  });
27825
28053
  const processStartTime = Date.parse(String(output).trim());
27826
28054
  return Number.isFinite(processStartTime) ? processStartTime : null;
@@ -27895,7 +28123,8 @@ function readWindowsProcess(pid) {
27895
28123
  const output = rpcIdentityExecFileSync("tasklist", ["/FO", "CSV", "/FI", `PID eq ${pid}`], {
27896
28124
  encoding: "utf8",
27897
28125
  timeout: PS_PROBE_TIMEOUT_MS,
27898
- stdio: ["ignore", "pipe", "pipe"]
28126
+ stdio: ["ignore", "pipe", "pipe"],
28127
+ windowsHide: true
27899
28128
  });
27900
28129
  const entries = parseTasklistOutput(String(output));
27901
28130
  if (entries === null)
@@ -27928,7 +28157,8 @@ function readPsProcessCommand(pid) {
27928
28157
  const output = rpcIdentityExecFileSync("ps", ["-p", String(pid), "-o", "command="], {
27929
28158
  encoding: "utf8",
27930
28159
  timeout: PS_PROBE_TIMEOUT_MS,
27931
- stdio: ["ignore", "pipe", "pipe"]
28160
+ stdio: ["ignore", "pipe", "pipe"],
28161
+ windowsHide: true
27932
28162
  });
27933
28163
  return String(output);
27934
28164
  } catch {
@@ -28039,7 +28269,8 @@ function execProcessList(exec, file, args, timeout = PS_PROBE_TIMEOUT_MS) {
28039
28269
  return String(exec(file, [...args], {
28040
28270
  encoding: "utf8",
28041
28271
  timeout,
28042
- stdio: ["ignore", "pipe", "pipe"]
28272
+ stdio: ["ignore", "pipe", "pipe"],
28273
+ windowsHide: true
28043
28274
  }));
28044
28275
  }
28045
28276
  function parseWindowsCreationDate(value) {
@@ -28101,7 +28332,7 @@ function parseWindowsCimOutput(output) {
28101
28332
  pid,
28102
28333
  parentPid: Number.isInteger(parentPid) && parentPid > 0 ? parentPid : null,
28103
28334
  commandLine,
28104
- imageName: commandLine ? executableName(commandTokens(commandLine)[0]) : null,
28335
+ imageName: typeof record.Name === "string" ? record.Name : commandLine ? executableName(commandTokens(commandLine)[0]) : null,
28105
28336
  startTime: parseWindowsCreationDate(record.CreationDate)
28106
28337
  });
28107
28338
  }
@@ -28179,14 +28410,14 @@ function readPosixParentPid(pid) {
28179
28410
  return null;
28180
28411
  }
28181
28412
  }
28182
- function collectAncestorPids(selfPid, parentByPid) {
28413
+ function collectAncestorPids(selfPid, parentByPid, probeParents = true) {
28183
28414
  const ancestors = new Set;
28184
28415
  let current = selfPid;
28185
28416
  for (let depth = 0;depth < MAX_ANCESTOR_WALK_DEPTH; depth += 1) {
28186
28417
  let ppid = null;
28187
28418
  if (parentByPid.has(current)) {
28188
28419
  ppid = parentByPid.get(current) ?? null;
28189
- } else if (rpcIdentityPlatform !== "win32") {
28420
+ } else if (rpcIdentityPlatform !== "win32" && probeParents) {
28190
28421
  ppid = readPosixParentPid(current);
28191
28422
  if (ppid == null && current === process.pid && process.ppid > 0) {
28192
28423
  ppid = process.ppid;
@@ -28203,8 +28434,8 @@ function collectAncestorPids(selfPid, parentByPid) {
28203
28434
  }
28204
28435
  return ancestors;
28205
28436
  }
28206
- function classifyLivePiSnapshot(snapshot) {
28207
- const ancestors = collectAncestorPids(process.pid, snapshot.parentByPid);
28437
+ function classifyLivePiSnapshot(snapshot, probeParents = true) {
28438
+ const ancestors = collectAncestorPids(process.pid, snapshot.parentByPid, probeParents);
28208
28439
  const processIds = new Set;
28209
28440
  const inconclusivePids = new Set;
28210
28441
  const skippedAncestorPids = [];
@@ -28249,8 +28480,9 @@ function inspectLivePiProcesses() {
28249
28480
  if (false) {}
28250
28481
  try {
28251
28482
  if (rpcIdentityPlatform === "win32") {
28252
- const cim = tryReadWindowsCimSnapshot(rpcProcessListExecFileSync);
28253
- const snapshot = cim ?? tryReadWindowsTasklistSnapshot();
28483
+ const now = rpcIdentityNowMs();
28484
+ const cached = windowsProcessSnapshotCache;
28485
+ const snapshot = cached && now >= cached.at && now - cached.at < WINDOWS_PROCESS_SNAPSHOT_TTL_MS ? cached.snapshot : tryReadWindowsCimSnapshot(rpcProcessListExecFileSync) ?? tryReadWindowsTasklistSnapshot();
28254
28486
  if (!snapshot) {
28255
28487
  return {
28256
28488
  state: "unreadable",
@@ -28258,6 +28490,8 @@ function inspectLivePiProcesses() {
28258
28490
  error: "process list unavailable"
28259
28491
  };
28260
28492
  }
28493
+ if (snapshot !== cached?.snapshot)
28494
+ windowsProcessSnapshotCache = { snapshot, at: now };
28261
28495
  rememberWindowsProcessFacts(snapshot.facts);
28262
28496
  return classifyLivePiSnapshot(snapshot);
28263
28497
  }
@@ -28303,7 +28537,81 @@ function parseRpcPortFile(content, fallbackPid = 0) {
28303
28537
  function isValidPort(port) {
28304
28538
  return Number.isInteger(port) && port > 0 && port <= 65535;
28305
28539
  }
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;
28540
+ function execProcessListAsync(file, args, timeout) {
28541
+ return new Promise((resolve, reject) => {
28542
+ execFile(file, args, { encoding: "utf8", timeout, windowsHide: true, maxBuffer: 8 * 1024 * 1024 }, (error, stdout) => {
28543
+ if (error)
28544
+ reject(error);
28545
+ else
28546
+ resolve(stdout);
28547
+ });
28548
+ });
28549
+ }
28550
+ function inspectProcessesAsync(forceFresh = false) {
28551
+ if (!forceFresh && asyncInspection && rpcIdentityNowMs() < asyncInspectionExpires)
28552
+ return asyncInspection;
28553
+ asyncInspectionExpires = Number.POSITIVE_INFINITY;
28554
+ asyncInspection = (async () => {
28555
+ let snapshot = null;
28556
+ try {
28557
+ if (rpcIdentityPlatform === "win32") {
28558
+ try {
28559
+ const output = await asyncProcessExec("powershell", ["-NoProfile", "-Command", WINDOWS_CIM_COMMAND], WINDOWS_CIM_PROBE_TIMEOUT_MS);
28560
+ const facts = parseWindowsCimOutput(output);
28561
+ if (facts)
28562
+ snapshot = snapshotFromFacts(facts, "cim");
28563
+ } catch {}
28564
+ if (!snapshot) {
28565
+ const entries = parseTasklistOutput(await asyncProcessExec("tasklist", ["/FO", "CSV"], PS_PROBE_TIMEOUT_MS));
28566
+ if (entries)
28567
+ snapshot = snapshotFromFacts(entries.map(({ pid, command }) => ({
28568
+ pid,
28569
+ parentPid: null,
28570
+ commandLine: null,
28571
+ imageName: command,
28572
+ startTime: null
28573
+ })), "tasklist");
28574
+ }
28575
+ } else {
28576
+ const output = await asyncProcessExec("ps", ["-axo", "pid=,ppid=,lstart=,command="], PS_PROBE_TIMEOUT_MS);
28577
+ const facts = [];
28578
+ for (const line of output.split(/\r?\n/)) {
28579
+ const match = /^\s*(\d+)\s+(\d+)\s+(\S+\s+\S+\s+\d+\s+\d+:\d+:\d+\s+\d+)\s+(.+)$/.exec(line);
28580
+ if (!match)
28581
+ continue;
28582
+ const startTime = Date.parse(match[3]);
28583
+ facts.push({
28584
+ pid: Number(match[1]),
28585
+ parentPid: Number(match[2]),
28586
+ commandLine: match[4],
28587
+ imageName: null,
28588
+ startTime: Number.isFinite(startTime) ? startTime : null
28589
+ });
28590
+ }
28591
+ snapshot = facts.length > 0 ? snapshotFromFacts(facts, "ps") : null;
28592
+ }
28593
+ } catch {}
28594
+ const fresh = snapshot !== null;
28595
+ if (snapshot)
28596
+ lastAsyncSnapshot = snapshot;
28597
+ else
28598
+ snapshot = lastAsyncSnapshot;
28599
+ const byPid = new Map(snapshot?.facts.map((fact) => [fact.pid, fact]));
28600
+ return {
28601
+ pi: snapshot ? classifyLivePiSnapshot(snapshot, false) : { state: "unreadable", processIds: [] },
28602
+ ...fresh && snapshot ? { processSnapshot: { source: snapshot.source, facts: snapshot.facts } } : {},
28603
+ evidence: (pid) => ({
28604
+ startTime: byPid.get(pid)?.startTime ?? null,
28605
+ commandLine: byPid.get(pid)?.commandLine ?? byPid.get(pid)?.imageName ?? null
28606
+ }),
28607
+ liveness: (pid) => byPid.has(pid) ? "alive" : fresh ? "dead" : "inconclusive"
28608
+ };
28609
+ })().finally(() => {
28610
+ asyncInspectionExpires = rpcIdentityNowMs() + WINDOWS_PROCESS_SNAPSHOT_TTL_MS;
28611
+ });
28612
+ return asyncInspection;
28613
+ }
28614
+ 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
28615
  var init_rpc_utils = __esm(() => {
28308
28616
  init_logger();
28309
28617
  init_pi_executable();
@@ -28317,11 +28625,12 @@ var init_rpc_utils = __esm(() => {
28317
28625
  "cljs/dist",
28318
28626
  "dist/bundle/cli"
28319
28627
  ];
28320
- rpcIdentityReadFileSync = readFileSync14;
28628
+ rpcIdentityReadFileSync = readFileSync15;
28321
28629
  rpcIdentityExecFileSync = execFileSync4;
28322
28630
  rpcIdentityProcessKill = process.kill;
28323
28631
  rpcProcessListExecFileSync = execFileSync4;
28324
28632
  rpcIdentityPlatform = process.platform;
28633
+ asyncProcessExec = execProcessListAsync;
28325
28634
  });
28326
28635
  // ../plugin/src/features/magic-context/fail-closed-block.ts
28327
28636
  function attachFailClosedBlockingProcessEvidence(process2, evidence) {
@@ -28463,11 +28772,11 @@ var init_fail_closed_block = __esm(() => {
28463
28772
  });
28464
28773
 
28465
28774
  // ../plugin/src/features/magic-context/message-fts-rowid-map.ts
28466
- import { createHash as createHash3 } from "node:crypto";
28775
+ import { createHash as createHash4 } from "node:crypto";
28467
28776
  var EMPTY_INDEX_CONTENT_HASH, upsertMapStatements, rangeReadyStatements, updateTimeStatements, activeBackfills;
28468
28777
  var init_message_fts_rowid_map = __esm(() => {
28469
28778
  init_write_transaction_timing();
28470
- EMPTY_INDEX_CONTENT_HASH = createHash3("sha256").update("").digest("hex");
28779
+ EMPTY_INDEX_CONTENT_HASH = createHash4("sha256").update("").digest("hex");
28471
28780
  upsertMapStatements = new WeakMap;
28472
28781
  rangeReadyStatements = new WeakMap;
28473
28782
  updateTimeStatements = new WeakMap;
@@ -31651,9 +31960,9 @@ import {
31651
31960
  copyFileSync,
31652
31961
  cpSync,
31653
31962
  existsSync as existsSync22,
31654
- mkdirSync as mkdirSync6,
31963
+ mkdirSync as mkdirSync7,
31655
31964
  readdirSync as readdirSync4,
31656
- readFileSync as readFileSync15,
31965
+ readFileSync as readFileSync16,
31657
31966
  statSync as statSync10,
31658
31967
  unlinkSync as unlinkSync3
31659
31968
  } from "node:fs";
@@ -31736,7 +32045,7 @@ function classifyJunkDiscovery(portFile, raw, staleFiles) {
31736
32045
  log3(`[magic-context] removing stale RPC discovery file ${portFile}: ${reason} record older than 10 minutes`);
31737
32046
  return null;
31738
32047
  }
31739
- function inspectRpcServerDiscovery(storageDir) {
32048
+ function inspectRpcServerDiscovery(storageDir, processes) {
31740
32049
  const rpcRoot = join18(storageDir, "rpc");
31741
32050
  let projectEntries;
31742
32051
  try {
@@ -31794,12 +32103,12 @@ function inspectRpcServerDiscovery(storageDir) {
31794
32103
  }
31795
32104
  if (isOwnRpcServerRecord(record))
31796
32105
  continue;
31797
- const liveness = isPidAlive(record.pid);
32106
+ const liveness = processes ? processes.liveness(record.pid) : isPidAlive(record.pid);
31798
32107
  if (liveness === "dead") {
31799
32108
  staleFiles.push(portFile);
31800
32109
  continue;
31801
32110
  }
31802
- const evidence = readProcessProbeEvidence(record.pid);
32111
+ const evidence = processes ? processes.evidence(record.pid) : readProcessProbeEvidence(record.pid);
31803
32112
  const identity = isPidIdentityPlausible(record, evidence);
31804
32113
  if (identity === "plausible") {
31805
32114
  pids.add(record.pid);
@@ -33108,7 +33417,7 @@ var init_storage_db = __esm(async () => {
33108
33417
  RPC_DISCOVERY_PARSE_GRACE_MS = 10 * 60 * 1000;
33109
33418
  defaultRpcDiscoveryFs = {
33110
33419
  readdirSync: (path, options) => options?.withFileTypes ? readdirSync4(path, { withFileTypes: true }) : readdirSync4(path),
33111
- readFileSync: (path, encoding) => String(readFileSync15(path, encoding)),
33420
+ readFileSync: (path, encoding) => String(readFileSync16(path, encoding)),
33112
33421
  statSync: (path) => ({ mtimeMs: statSync10(path).mtimeMs }),
33113
33422
  unlinkSync: (path) => unlinkSync3(path)
33114
33423
  };
@@ -33121,7 +33430,7 @@ var init_storage_db = __esm(async () => {
33121
33430
  });
33122
33431
 
33123
33432
  // src/lib/database-access.ts
33124
- import { existsSync as existsSync23, writeFileSync as writeFileSync5 } from "node:fs";
33433
+ import { existsSync as existsSync23, writeFileSync as writeFileSync6 } from "node:fs";
33125
33434
  import { pathToFileURL } from "node:url";
33126
33435
  function getPersistedSchemaVersion2(db) {
33127
33436
  return getPersistedSchemaVersion(db);
@@ -33175,7 +33484,7 @@ function openExistingContextDatabaseForMutation(path) {
33175
33484
  async function backupDatabaseSnapshot(db, destination) {
33176
33485
  const serializable = db;
33177
33486
  if (typeof serializable.serialize === "function") {
33178
- writeFileSync5(destination, serializable.serialize(), { flag: "wx" });
33487
+ writeFileSync6(destination, serializable.serialize(), { flag: "wx" });
33179
33488
  return;
33180
33489
  }
33181
33490
  const moduleName = "node:" + "sqlite";
@@ -33281,11 +33590,11 @@ async function reportAuthorityMarkers(args) {
33281
33590
  args.info(" no authority_managed markers");
33282
33591
  return;
33283
33592
  }
33593
+ const loaded = loadPluginConfig(process.cwd());
33284
33594
  let currentIdentity;
33285
33595
  try {
33286
- currentIdentity = resolveProjectIdentity(process.cwd());
33596
+ currentIdentity = resolveProjectIdentity(process.cwd(), loaded.allow_home_project);
33287
33597
  } catch {}
33288
- const loaded = loadPluginConfig(process.cwd());
33289
33598
  const transport = new SubcModuleTransport(loaded.subc?.connection_file ?? getDefaultSubcConnectionFile());
33290
33599
  for (const marker of markers) {
33291
33600
  if (marker.project_path !== currentIdentity) {
@@ -33312,12 +33621,18 @@ async function runDoctorDrainAuthority(projectRoot, dbPath) {
33312
33621
  return 1;
33313
33622
  }
33314
33623
  try {
33315
- const projectPath = resolveProjectIdentity(projectRoot);
33624
+ const loaded = loadPluginConfig(projectRoot);
33625
+ let projectPath;
33626
+ try {
33627
+ projectPath = resolveProjectIdentity(projectRoot, loaded.allow_home_project);
33628
+ } catch (error) {
33629
+ console.error(error instanceof Error ? error.message : String(error));
33630
+ return 1;
33631
+ }
33316
33632
  if (!getAuthorityManagedMarker(db, projectPath)) {
33317
33633
  console.log(`No authority_managed marker exists for ${projectPath}.`);
33318
33634
  return 0;
33319
33635
  }
33320
- const loaded = loadPluginConfig(projectRoot);
33321
33636
  const module = authorityClient(new SubcModuleTransport(loaded.subc?.connection_file ?? getDefaultSubcConnectionFile()), projectRoot);
33322
33637
  let drainedAny = false;
33323
33638
  for (const domain of AUTHORITY_DOMAINS) {
@@ -33457,7 +33772,10 @@ function logRow(db, fromIdentity, toIdentity, tableName, rowId, action, targetRo
33457
33772
  (from_identity, to_identity, table_name, row_id, action, target_row_id, merged_at)
33458
33773
  VALUES (?, ?, ?, ?, ?, ?, ?)`).run(fromIdentity, toIdentity, tableName, rowId, action, targetRowId, mergedAt);
33459
33774
  }
33460
- function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
33775
+ function normalizedContent(value) {
33776
+ return String(value).toLowerCase().replace(/\s+/g, " ").trim();
33777
+ }
33778
+ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt, review) {
33461
33779
  const sourceId = row.id;
33462
33780
  if (typeof sourceId !== "number")
33463
33781
  return false;
@@ -33465,10 +33783,13 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
33465
33783
  FROM memories
33466
33784
  WHERE project_path = ? AND category = ? AND normalized_hash = ? AND id <> ?
33467
33785
  LIMIT 1`).get(toIdentity, row.category, row.normalized_hash, sourceId);
33468
- if (collision && typeof collision.id === "number") {
33786
+ if (collision && normalizedContent(collision.content) !== normalizedContent(row.content)) {
33787
+ 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);
33788
+ review = true;
33789
+ } else if (collision && typeof collision.id === "number") {
33469
33790
  const targetId = collision.id;
33470
33791
  const targetSeen = Number(collision.seen_count ?? 1);
33471
- const mergedSeen = Math.max(targetSeen, Number(row.seen_count ?? 1));
33792
+ const mergedSeen = targetSeen + Number(row.seen_count ?? 1);
33472
33793
  const sourceClassifiedAt = Number(row.classified_at ?? 0);
33473
33794
  const targetClassifiedAt = Number(collision.classified_at ?? 0);
33474
33795
  if (sourceClassifiedAt > targetClassifiedAt) {
@@ -33501,8 +33822,9 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
33501
33822
  END`).run(targetId, sourceId);
33502
33823
  db.prepare("DELETE FROM memory_verifications WHERE memory_id = ?").run(sourceId);
33503
33824
  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);
33825
+ 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
33826
  }
33827
+ 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
33828
  db.prepare(`UPDATE memories
33507
33829
  SET status = 'archived',
33508
33830
  superseded_by_memory_id = ?,
@@ -33518,6 +33840,9 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
33518
33840
  logRow(db, fromIdentity, toIdentity, "memories", String(sourceId), "superseded", String(targetId), mergedAt);
33519
33841
  return true;
33520
33842
  }
33843
+ if (review) {
33844
+ 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);
33845
+ }
33521
33846
  const result = db.prepare("UPDATE memories SET project_path = ?, updated_at = ? WHERE id = ? AND project_path = ?").run(toIdentity, mergedAt, sourceId, fromIdentity);
33522
33847
  if ((result.changes ?? 0) === 0)
33523
33848
  return false;
@@ -33532,21 +33857,33 @@ function oldestOpenCycleStart(left, right) {
33532
33857
  const values = [left, right].filter((value) => typeof value === "number" && value > 0);
33533
33858
  return values.length > 0 ? Math.min(...values) : null;
33534
33859
  }
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);
33860
+ function reconcileTaskScheduleCollision(db, source, target, mergedAt) {
33861
+ 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
33862
  const latest = sourceIsNewer ? source : target;
33538
33863
  db.prepare(`UPDATE task_schedule_state
33539
33864
  SET last_run_at = ?, next_due_at = ?, schedule = ?, last_status = ?,
33540
33865
  last_error = ?, retry_count = ?, last_checked_commit = ?,
33541
33866
  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);
33867
+ 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
33868
  }
33544
33869
  function rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt) {
33545
33870
  const rowId = rowKey(db, table.name, row);
33546
33871
  const collision = findUniqueCollision(db, table, row, fromIdentity, toIdentity);
33547
33872
  if (collision) {
33548
33873
  if (table.name === "task_schedule_state") {
33549
- reconcileTaskScheduleCollision(db, row, collision);
33874
+ reconcileTaskScheduleCollision(db, row, collision, mergedAt);
33875
+ }
33876
+ const maximumColumns = {
33877
+ retrospective_processed_windows: ["processed_at"],
33878
+ embedding_identity_active: ["last_active_at"],
33879
+ memory_embedding_watermarks: ["written_memory_id", "embedded_memory_id", "updated_at"],
33880
+ project_state: ["project_memory_epoch", "project_user_profile_version", "updated_at"],
33881
+ project_key_files_version: ["version"]
33882
+ };
33883
+ const columns = maximumColumns[table.name];
33884
+ if (columns) {
33885
+ const targetPredicate = rowPredicate(db, table.name, collision);
33886
+ 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
33887
  }
33551
33888
  const sourcePredicate = rowPredicate(db, table.name, row);
33552
33889
  const result = db.prepare(`DELETE FROM ${quoteIdentifier(table.name)} WHERE ${sourcePredicate.sql}`).run(...sourcePredicate.values);
@@ -33555,6 +33892,9 @@ function rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt) {
33555
33892
  logRow(db, fromIdentity, toIdentity, table.name, rowId, "collision_deleted", rowKey(db, table.name, collision), mergedAt);
33556
33893
  return true;
33557
33894
  }
33895
+ if (table.name === "task_schedule_state") {
33896
+ 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);
33897
+ }
33558
33898
  const predicate = rowPredicate(db, table.name, row);
33559
33899
  const result = db.prepare(`UPDATE ${quoteIdentifier(table.name)}
33560
33900
  SET ${quoteIdentifier(table.identityColumn)} = ?
@@ -33566,21 +33906,37 @@ function rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt) {
33566
33906
  return true;
33567
33907
  }
33568
33908
  function tableSourceRows(db, table, fromIdentity) {
33569
- return db.prepare(`SELECT rowid, * FROM ${quoteIdentifier(table.name)} WHERE ${quoteIdentifier(table.identityColumn)} = ?`).all(fromIdentity);
33909
+ 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
33910
  }
33571
33911
  function assertMergeAllowed(db, fromIdentity, toIdentity) {
33912
+ 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);
33913
+ if (memberships.length === 2 && memberships[0].id !== memberships[1].id) {
33914
+ throw new Error(`Refusing identity merge: different workspaces ${memberships[0].name} and ${memberships[1].name}. Choose membership before merging.`);
33915
+ }
33572
33916
  if (!tableExists3(db, "authority_managed"))
33573
33917
  return;
33574
33918
  const source = db.prepare("SELECT 1 FROM authority_managed WHERE project_path = ? LIMIT 1").get(fromIdentity);
33575
33919
  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.`);
33920
+ 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
33921
  }
33578
33922
  const target = db.prepare("SELECT 1 FROM authority_managed WHERE project_path = ? LIMIT 1").get(toIdentity);
33579
33923
  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.`);
33924
+ 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.`);
33925
+ }
33926
+ }
33927
+ function memoryDisposition(db, from, to) {
33928
+ const duplicateMemoryIds = [];
33929
+ const reviewMemoryIds = [];
33930
+ for (const row of tableSourceRows(db, { name: "memories", identityColumn: "project_path", derived: false }, from)) {
33931
+ const collision = db.prepare("SELECT content FROM memories WHERE project_path = ? AND category = ? AND normalized_hash = ?").get(to, row.category, row.normalized_hash);
33932
+ if (collision && normalizedContent(collision.content) === normalizedContent(row.content))
33933
+ duplicateMemoryIds.push(Number(row.id));
33934
+ else if (db.prepare("SELECT 1 FROM memories WHERE project_path = ? AND category = ? LIMIT 1").get(to, row.category))
33935
+ reviewMemoryIds.push(Number(row.id));
33581
33936
  }
33937
+ return { duplicateMemoryIds, reviewMemoryIds };
33582
33938
  }
33583
- function auditIdentityMerge(db, fromIdentity, toIdentity) {
33939
+ function auditIdentityMerge(db, fromIdentity, toIdentity, now = Date.now()) {
33584
33940
  const auditedTables = discoverIdentityTables(db).map((table) => ({
33585
33941
  tableName: table.name,
33586
33942
  identityColumn: table.identityColumn,
@@ -33588,12 +33944,31 @@ function auditIdentityMerge(db, fromIdentity, toIdentity) {
33588
33944
  sourceRows: table.derived ? 0 : tableSourceRows(db, table, fromIdentity).length,
33589
33945
  changedRows: 0
33590
33946
  }));
33947
+ const changes = [];
33948
+ for (const table of discoverIdentityTables(db).filter((table) => !table.derived && table.name !== "memories")) {
33949
+ for (const row of tableSourceRows(db, table, fromIdentity)) {
33950
+ const collision = findUniqueCollision(db, table, row, fromIdentity, toIdentity);
33951
+ if (collision)
33952
+ changes.push(`${table.name} ${rowKey(db, table.name, row)}: collapse into ${rowKey(db, table.name, collision)} (target content/configuration retained; progress counters reconciled)`);
33953
+ if (table.name === "workspace_members")
33954
+ changes.push(`workspace ${row.workspace_id}: ${collision ? "collapse aliases" : "transfer source membership"}`);
33955
+ if (table.name === "task_schedule_state") {
33956
+ const schedule = String((collision ?? row).schedule ?? "");
33957
+ 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)))}`);
33958
+ }
33959
+ }
33960
+ }
33961
+ 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);
33962
+ for (const queue of queues)
33963
+ changes.push(`dream_queue ${JSON.stringify(queue.reason)}: ${queue.n} → 1 queued row`);
33591
33964
  return {
33592
33965
  fromIdentity,
33593
33966
  toIdentity,
33967
+ changes,
33594
33968
  auditedTables,
33595
33969
  changedRows: auditedTables.reduce((total, table) => total + table.sourceRows, 0),
33596
- dryRun: true
33970
+ dryRun: true,
33971
+ ...memoryDisposition(db, fromIdentity, toIdentity)
33597
33972
  };
33598
33973
  }
33599
33974
  function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
@@ -33605,11 +33980,14 @@ function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
33605
33980
  }
33606
33981
  assertMergeAllowed(db, fromIdentity, toIdentity);
33607
33982
  const tables = discoverIdentityTables(db);
33608
- const report = auditIdentityMerge(db, fromIdentity, toIdentity);
33983
+ const report = auditIdentityMerge(db, fromIdentity, toIdentity, options.now);
33609
33984
  if (options.dryRun)
33610
33985
  return report;
33986
+ if (report.changedRows === 0)
33987
+ return { ...report, dryRun: false };
33611
33988
  const mergedAt = options.now ?? Date.now();
33612
33989
  const run = db.transaction(() => {
33990
+ assertMergeAllowed(db, fromIdentity, toIdentity);
33613
33991
  if (tableExists3(db, "v22_identity_rekey_map")) {
33614
33992
  db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
33615
33993
  VALUES (?, ?, ?)
@@ -33624,11 +34002,15 @@ function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
33624
34002
  const rows = tableSourceRows(db, table, fromIdentity);
33625
34003
  tableReport.sourceRows = rows.length;
33626
34004
  for (const row of rows) {
33627
- const changed = table.name === "memories" ? mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) : rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt);
34005
+ 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
34006
  if (changed)
33629
34007
  tableReport.changedRows += 1;
33630
34008
  }
33631
34009
  }
34010
+ 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);
34011
+ db.prepare(`UPDATE dream_queue SET started_at = NULL WHERE project_path = ?`).run(toIdentity);
34012
+ db.prepare(`UPDATE git_sweep_coordinator SET lease_holder = NULL, lease_expires_at = NULL, last_swept_at = NULL WHERE project_path = ?`).run(toIdentity);
34013
+ 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
34014
  db.prepare(`INSERT INTO project_state
33633
34015
  (project_path, project_memory_epoch, project_user_profile_version, updated_at)
33634
34016
  VALUES (?, 1, 0, ?)
@@ -33645,6 +34027,7 @@ function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
33645
34027
  }
33646
34028
  var IDENTITY_COLUMNS, DERIVED_TABLE_SUFFIXES;
33647
34029
  var init_storage_identity_merge = __esm(() => {
34030
+ init_cron();
33648
34031
  IDENTITY_COLUMNS = new Set(["project_path", "project_identity"]);
33649
34032
  DERIVED_TABLE_SUFFIXES = [
33650
34033
  "_fts",
@@ -33656,84 +34039,88 @@ var init_storage_identity_merge = __esm(() => {
33656
34039
  ];
33657
34040
  });
33658
34041
 
33659
- // src/commands/doctor-merge-identity.ts
34042
+ // src/commands/doctor-identity-splits.ts
34043
+ import { realpathSync as realpathSync4 } from "node:fs";
33660
34044
  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;
34045
+ function tableExists4(db, table) {
34046
+ return !!db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(table);
33670
34047
  }
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;
34048
+ function findIdentitySplits(db, host, includeSingles = false) {
34049
+ if (!tableExists4(db, "session_projects"))
34050
+ return [];
34051
+ const directories = new Map;
34052
+ for (const table of ["session", "session_v2"]) {
34053
+ if (!tableExists4(host, table))
33682
34054
  continue;
34055
+ const rows = host.prepare(`SELECT id, directory FROM ${table} WHERE directory IS NOT NULL`).all();
34056
+ for (const row of rows) {
34057
+ if (!row.directory)
34058
+ continue;
34059
+ let canonical = row.directory;
34060
+ try {
34061
+ canonical = realpathSync4.native(canonical);
34062
+ } catch {}
34063
+ const key = `${table === "session" ? "opencode" : "opencode2"}\x00${row.id}`;
34064
+ const roots = directories.get(key) ?? new Set;
34065
+ roots.add(projectDirectoryKey(canonical));
34066
+ directories.set(key, roots);
33683
34067
  }
33684
- if (arg === "--dry-run" || arg === "--yes")
34068
+ }
34069
+ const byDirectory = new Map;
34070
+ const bindings = db.prepare("SELECT session_id, harness, project_path FROM session_projects WHERE harness IN ('opencode', 'opencode2')").all();
34071
+ for (const row of bindings) {
34072
+ if (!/^(git|dir):/.test(row.project_path))
33685
34073
  continue;
33686
- throw new Error(`Unknown doctor merge-identity option: ${arg}`);
34074
+ for (const directory of directories.get(`${row.harness}\x00${row.session_id}`) ?? []) {
34075
+ const identities = byDirectory.get(directory) ?? new Set;
34076
+ identities.add(row.project_path);
34077
+ byDirectory.set(directory, identities);
34078
+ }
33687
34079
  }
33688
- return {
33689
- from,
33690
- to,
33691
- dryRun: args.includes("--dry-run"),
33692
- yes: args.includes("--yes"),
33693
- ...dbPath ? { dbPath } : {}
33694
- };
34080
+ const count = (table, identity) => tableExists4(db, table) ? db.prepare(`SELECT COUNT(*) AS n FROM ${table} WHERE project_path = ?`).get(identity).n : 0;
34081
+ return [...byDirectory].filter(([, identities]) => includeSingles || identities.size > 1).sort(([a], [b]) => a.localeCompare(b)).map(([directory, identities]) => ({
34082
+ directory,
34083
+ identities: [...identities].sort().map((identity) => ({
34084
+ identity,
34085
+ sessions: count("session_projects", identity),
34086
+ memories: count("memories", identity),
34087
+ notes: count("notes", identity),
34088
+ dreamer: [
34089
+ "dream_queue",
34090
+ "dream_runs",
34091
+ "task_schedule_state",
34092
+ "retrospective_processed_windows"
34093
+ ].reduce((n, table) => n + count(table, identity), 0)
34094
+ }))
34095
+ }));
33695
34096
  }
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
- }
34097
+ function formatIdentitySplits(splits) {
34098
+ return splits.flatMap((split) => [
34099
+ `Project identity split: ${split.directory} (read-only; no merge performed)`,
34100
+ ...split.identities.map((row) => ` ${row.identity}: ${row.sessions} sessions, ${row.memories} memories, ${row.notes} notes, ${row.dreamer} dreamer rows (identity-wide counts)`)
34101
+ ]);
33709
34102
  }
33710
- function openMergeDatabase(path, mutate) {
33711
- const db = mutate ? openExistingContextDatabaseForMutation(path) : openExistingContextDatabase(path, { readonly: true });
34103
+ function diagnoseIdentitySplits() {
34104
+ const db = openExistingContextDatabase(join19(getMagicContextStorageDir(), "context.db"), {
34105
+ readonly: true
34106
+ });
33712
34107
  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);
34108
+ return [];
34109
+ let host = null;
33724
34110
  try {
33725
- const report = mergeProjectIdentities(db, options.from, options.to, {
33726
- dryRun: options.dryRun
33727
- });
33728
- printReport(report);
33729
- return 0;
34111
+ host = openExistingDatabase(resolveOpenCodeDbPath().path, { readonly: true });
34112
+ if (!host)
34113
+ return ["Identity split check skipped: OpenCode session directories unavailable."];
34114
+ return formatIdentitySplits(findIdentitySplits(db, host));
33730
34115
  } finally {
34116
+ host?.close();
33731
34117
  db.close();
33732
34118
  }
33733
34119
  }
33734
- var init_doctor_merge_identity = __esm(async () => {
33735
- init_storage_identity_merge();
34120
+ var init_doctor_identity_splits = __esm(async () => {
34121
+ init_project_identity_cache();
33736
34122
  init_data_path();
34123
+ init_opencode_db_path();
33737
34124
  await init_database_access();
33738
34125
  });
33739
34126
 
@@ -33746,7 +34133,7 @@ import {
33746
34133
  copyFileSync as copyFileSync2,
33747
34134
  existsSync as existsSync24,
33748
34135
  openSync as openSync4,
33749
- renameSync as renameSync4,
34136
+ renameSync as renameSync5,
33750
34137
  rmSync as rmSync3,
33751
34138
  statSync as statSync11
33752
34139
  } from "node:fs";
@@ -34001,15 +34388,15 @@ function activateReplacement(dbPath, replacementPath, originalAsidePath) {
34001
34388
  if (!existsSync24(from))
34002
34389
  continue;
34003
34390
  const to = `${originalAsidePath}${suffix}`;
34004
- renameSync4(from, to);
34391
+ renameSync5(from, to);
34005
34392
  movedOriginals.push({ from, to });
34006
34393
  }
34007
- renameSync4(replacementPath, dbPath);
34394
+ renameSync5(replacementPath, dbPath);
34008
34395
  return movedOriginals.map(({ to }) => to);
34009
34396
  } catch (error) {
34010
34397
  for (const moved of movedOriginals.reverse()) {
34011
34398
  if (existsSync24(moved.to) && !existsSync24(moved.from))
34012
- renameSync4(moved.to, moved.from);
34399
+ renameSync5(moved.to, moved.from);
34013
34400
  }
34014
34401
  throw error;
34015
34402
  }
@@ -34240,6 +34627,232 @@ var init_doctor_repair_db = __esm(async () => {
34240
34627
  ];
34241
34628
  });
34242
34629
 
34630
+ // src/commands/doctor-merge-identity.ts
34631
+ import { execFileSync as execFileSync5 } from "node:child_process";
34632
+ import { createHash as createHash5 } from "node:crypto";
34633
+ import {
34634
+ cpSync as cpSync2,
34635
+ existsSync as existsSync25,
34636
+ mkdirSync as mkdirSync8,
34637
+ mkdtempSync,
34638
+ readdirSync as readdirSync5,
34639
+ readFileSync as readFileSync17,
34640
+ renameSync as renameSync6,
34641
+ writeFileSync as writeFileSync7
34642
+ } from "node:fs";
34643
+ import { dirname as dirname13, join as join21 } from "node:path";
34644
+ function parseMergeIdentityArgs(args) {
34645
+ const values = {};
34646
+ const switches = new Set(["--apply", "--force", "--dry-run", "--yes"]);
34647
+ for (let i = 0;i < args.length; i++) {
34648
+ const flag = args[i];
34649
+ if (["--from", "--to", "--db", "--host-db"].includes(flag)) {
34650
+ const value = args[++i];
34651
+ if (!value || value.startsWith("--"))
34652
+ throw new Error(`${flag} requires a value`);
34653
+ if (values[flag])
34654
+ throw new Error(`Repeated option: ${flag}`);
34655
+ values[flag] = value;
34656
+ } else if (!switches.has(flag))
34657
+ throw new Error(`Unknown doctor merge-identities option: ${flag}`);
34658
+ }
34659
+ if (Boolean(values["--from"]) !== Boolean(values["--to"]))
34660
+ throw new Error("Supply both --from and --to");
34661
+ const apply = args.includes("--apply") || args.includes("--yes");
34662
+ if (apply && (!values["--from"] || args.includes("--dry-run")))
34663
+ throw new Error("--apply requires --from/--to and cannot be combined with --dry-run");
34664
+ return {
34665
+ from: values["--from"],
34666
+ to: values["--to"],
34667
+ dbPath: values["--db"],
34668
+ hostPath: values["--host-db"],
34669
+ dryRun: !apply,
34670
+ yes: apply,
34671
+ force: args.includes("--force")
34672
+ };
34673
+ }
34674
+ function printReport(report) {
34675
+ console.log(`Identity merge ${report.dryRun ? "preview" : "complete"}: ${report.fromIdentity} → ${report.toIdentity}`);
34676
+ for (const table of report.auditedTables) {
34677
+ console.log(` ${table.tableName}: ${report.dryRun ? table.sourceRows : table.changedRows} row(s)${table.derived ? " (derived; maintained by triggers)" : ""}`);
34678
+ }
34679
+ for (const change of report.changes)
34680
+ console.log(` ${change}`);
34681
+ console.log(` identical memories collapsed: ${report.duplicateMemoryIds.join(", ") || "none"}`);
34682
+ console.log(` potential content conflicts kept for review (same category): ${report.reviewMemoryIds.join(", ") || "none"}`);
34683
+ 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.");
34684
+ console.log(" Git indexes move; sweep leases reset for rebuilding. Existing memory embeddings remain valid (content unchanged); FTS triggers rekey indexes.");
34685
+ if (!report.changedRows)
34686
+ console.log(" No-op: no source rows remain to move.");
34687
+ if (report.dryRun)
34688
+ console.log(" No writes. Review this preview, then repeat with --apply to confirm.");
34689
+ }
34690
+ function resolveReadOnly(directory) {
34691
+ if (!existsSync25(directory))
34692
+ return;
34693
+ try {
34694
+ const roots = execFileSync5("git", ["rev-list", "--max-parents=0", "HEAD"], {
34695
+ cwd: directory,
34696
+ windowsHide: true,
34697
+ encoding: "utf8",
34698
+ timeout: 5000,
34699
+ stdio: ["ignore", "pipe", "pipe"]
34700
+ }).trim().split(/\s+/).filter((root) => /^[0-9a-f]{40,64}$/.test(root)).sort();
34701
+ if (roots[0])
34702
+ return `git:${roots[0]}`;
34703
+ } catch {}
34704
+ try {
34705
+ const result = execFileSync5("git", ["rev-parse", "--is-inside-work-tree"], {
34706
+ cwd: directory,
34707
+ windowsHide: true,
34708
+ encoding: "utf8",
34709
+ timeout: 5000,
34710
+ stdio: ["ignore", "pipe", "pipe"]
34711
+ });
34712
+ if (result.trim() === "true")
34713
+ return;
34714
+ } catch (error) {
34715
+ if (String(error.stderr).includes("not a git repository"))
34716
+ return `dir:${createHash5("md5").update(projectDirectoryKey(directory)).digest("hex").slice(0, 12)}`;
34717
+ }
34718
+ return;
34719
+ }
34720
+ function observations(db, hostPath, storageDir) {
34721
+ const host = openExistingDatabase(hostPath, { readonly: true });
34722
+ let rows = [];
34723
+ try {
34724
+ rows = host ? findIdentitySplits(db, host, true) : [];
34725
+ } finally {
34726
+ host?.close();
34727
+ }
34728
+ const add = (directory, identity) => {
34729
+ if (!/^(git|dir):/.test(identity))
34730
+ return;
34731
+ directory = projectDirectoryKey(directory);
34732
+ let row = rows.find((item) => item.directory === directory);
34733
+ if (!row) {
34734
+ row = { directory, identities: [] };
34735
+ rows.push(row);
34736
+ }
34737
+ if (!row.identities.some((item) => item.identity === identity))
34738
+ row.identities.push({ identity, sessions: 0, memories: 0, notes: 0, dreamer: 0 });
34739
+ };
34740
+ const sidecars = join21(storageDir, "project-identities");
34741
+ if (existsSync25(sidecars))
34742
+ for (const file of readdirSync5(sidecars)) {
34743
+ if (!file.endsWith(".json"))
34744
+ continue;
34745
+ try {
34746
+ const record = JSON.parse(readFileSync17(join21(sidecars, file), "utf8"));
34747
+ if (typeof record.directory === "string" && typeof record.identity === "string")
34748
+ add(record.directory, record.identity);
34749
+ } catch {}
34750
+ }
34751
+ for (const row of db.prepare("SELECT project_path, display_path FROM workspace_members").all())
34752
+ add(row.display_path, row.project_path);
34753
+ return rows;
34754
+ }
34755
+ function runMergeIdentityCli(args, deps = {}) {
34756
+ const options = parseMergeIdentityArgs(args);
34757
+ const dbPath = options.dbPath ?? join21(getMagicContextStorageDir(), "context.db");
34758
+ const storageDir = dirname13(dbPath);
34759
+ const hostPath = options.hostPath ?? (options.dbPath ? join21(storageDir, "host.db") : resolveOpenCodeDbPath().path);
34760
+ let db = openExistingContextDatabase(dbPath, {
34761
+ readonly: true,
34762
+ minimumSupportedVersion: CLI_SCHEMA_FLOOR_VERSION
34763
+ });
34764
+ if (!db)
34765
+ throw new Error(`Context database does not exist: ${dbPath}`);
34766
+ let directories = [];
34767
+ try {
34768
+ const observed = observations(db, hostPath, storageDir);
34769
+ if (!options.from || !options.to) {
34770
+ for (const split of observed.filter((row) => row.identities.length > 1)) {
34771
+ const target = resolveReadOnly(split.directory) ?? split.identities.map((row) => row.identity).filter((id) => id.startsWith("git:")).sort()[0];
34772
+ console.log(`Project identity split: ${split.directory}`);
34773
+ for (const row of split.identities)
34774
+ if (row.identity !== target)
34775
+ console.log(` ${row.identity} → ${target ?? "unresolved target"}`);
34776
+ }
34777
+ if (!observed.some((row) => row.identities.length > 1))
34778
+ console.log("No detected identity splits.");
34779
+ return 0;
34780
+ }
34781
+ if (options.from === options.to)
34782
+ throw new Error(`Source and target identities must differ: ${options.from}`);
34783
+ for (const identity of [options.from, options.to]) {
34784
+ 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);
34785
+ if (!known)
34786
+ throw new Error(`Unknown identity: ${identity}`);
34787
+ }
34788
+ const sourceDirs = observed.filter((row) => row.identities.some((item) => item.identity === options.from)).map((row) => row.directory);
34789
+ const targetDirs = observed.filter((row) => row.identities.some((item) => item.identity === options.to)).map((row) => row.directory);
34790
+ directories = [...new Set([...sourceDirs, ...targetDirs])];
34791
+ 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);
34792
+ 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))))
34793
+ throw new Error(`Refusing different directories for ${options.from} (${sourceDirs.join(", ") || "unknown"}) and ${options.to} (${targetDirs.join(", ") || "unknown"})`);
34794
+ if (!options.force && !directories.some((directory) => resolveReadOnly(directory) === options.to))
34795
+ throw new Error(`Target ${options.to} does not resolve for any observed directory on this machine; use --force only after reviewing the identity.`);
34796
+ const preview = mergeProjectIdentities(db, options.from, options.to, { dryRun: true });
34797
+ printReport(preview);
34798
+ if (options.dryRun)
34799
+ return 0;
34800
+ } finally {
34801
+ db.close();
34802
+ }
34803
+ const { from, to } = options;
34804
+ if (!from || !to)
34805
+ return 0;
34806
+ const holders = (deps.inspectHolders ?? defaultInspectHolders)(storageDir);
34807
+ const probe = (deps.probe ?? probeHostProcessesUsing)({
34808
+ files: [dbPath, `${dbPath}-wal`, `${dbPath}-shm`],
34809
+ directories: []
34810
+ });
34811
+ if (!holders.safe || probe.status !== "free")
34812
+ 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 : ""}`);
34813
+ const backup = mkdtempSync(join21(storageDir, "identity-merge-backup-"));
34814
+ const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
34815
+ console.log(`Backup directory: ${backup}`);
34816
+ 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`);
34817
+ const sidecarRoot = join21(storageDir, "project-identities");
34818
+ const sidecarBackup = join21(backup, "project-identities");
34819
+ mkdirSync8(sidecarBackup);
34820
+ if (existsSync25(sidecarRoot))
34821
+ cpSync2(sidecarRoot, sidecarBackup, { recursive: true });
34822
+ console.log(`Restore identity sidecars too: rm -rf ${quote(sidecarRoot)}; cp -R ${quote(sidecarBackup)} ${quote(sidecarRoot)}`);
34823
+ copyDatabaseBundle(dbPath, join21(backup, "context.db"));
34824
+ db = openExistingDatabase(dbPath, { readonly: false });
34825
+ if (!db)
34826
+ throw new Error(`Context database disappeared: ${dbPath}`);
34827
+ try {
34828
+ printReport(mergeProjectIdentities(db, from, to));
34829
+ } finally {
34830
+ db.close();
34831
+ }
34832
+ if (to.startsWith("git:"))
34833
+ for (const directory of directories) {
34834
+ const root = join21(storageDir, "project-identities");
34835
+ mkdirSync8(root, { recursive: true });
34836
+ const path = join21(root, `${createHash5("sha256").update(projectDirectoryKey(directory)).digest("hex")}.json`);
34837
+ const temporary = `${path}.merge.tmp`;
34838
+ writeFileSync7(temporary, JSON.stringify({ directory: projectDirectoryKey(directory), identity: options.to }), { mode: 384 });
34839
+ renameSync6(temporary, path);
34840
+ }
34841
+ return 0;
34842
+ }
34843
+ var init_doctor_merge_identity = __esm(async () => {
34844
+ init_project_identity_cache();
34845
+ init_storage_identity_merge();
34846
+ init_data_path();
34847
+ init_opencode_db_path();
34848
+ init_doctor_opencode2_cache();
34849
+ await __promiseAll([
34850
+ init_database_access(),
34851
+ init_doctor_identity_splits(),
34852
+ init_doctor_repair_db()
34853
+ ]);
34854
+ });
34855
+
34243
34856
  // src/commands/doctor-hidden-sessions.ts
34244
34857
  function parseMetadata(value) {
34245
34858
  if (value && typeof value === "object" && !Array.isArray(value)) {
@@ -34330,20 +34943,20 @@ var init_migration_paths = __esm(() => {
34330
34943
  });
34331
34944
 
34332
34945
  // 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";
34946
+ import { createHash as createHash6, randomBytes as randomBytes2 } from "node:crypto";
34947
+ import { existsSync as existsSync26, mkdirSync as mkdirSync9, renameSync as renameSync7, unlinkSync as unlinkSync4 } from "node:fs";
34948
+ import { dirname as dirname14, join as join22 } from "node:path";
34336
34949
  function defaultOpenCodeDbPath() {
34337
34950
  return getOpenCodeDatabasePath();
34338
34951
  }
34339
34952
  function defaultCortexkitDbPath() {
34340
- return join21(getMagicContextStorageDir(), "context.db");
34953
+ return join22(getMagicContextStorageDir(), "context.db");
34341
34954
  }
34342
34955
  function defaultPiSessionsRoot() {
34343
34956
  return getPiSessionsRoot();
34344
34957
  }
34345
34958
  function defaultFs() {
34346
- return { writeFileAtomic, unlinkSync: unlinkSync4, existsSync: existsSync25, renameSync: renameSync5, mkdirSync: mkdirSync7 };
34959
+ return { writeFileAtomic, unlinkSync: unlinkSync4, existsSync: existsSync26, renameSync: renameSync7, mkdirSync: mkdirSync9 };
34347
34960
  }
34348
34961
  function stmt(db, sql) {
34349
34962
  return db.prepare(sql);
@@ -34370,7 +34983,7 @@ function shortId() {
34370
34983
  return randomBytes2(4).toString("hex");
34371
34984
  }
34372
34985
  function migrationKeyFor(sourceSessionId, targetHarness) {
34373
- return createHash4("sha256").update(`${sourceSessionId}
34986
+ return createHash6("sha256").update(`${sourceSessionId}
34374
34987
  ${targetHarness}`).digest("hex");
34375
34988
  }
34376
34989
  function moduleManagedProjectForSession(db, sessionId) {
@@ -34409,7 +35022,7 @@ function sweepPendingMigrations(db, fs = defaultFs()) {
34409
35022
  }
34410
35023
  if (row.phase === "db_committed") {
34411
35024
  if (fs.existsSync(row.stage_path)) {
34412
- fs.mkdirSync(dirname13(row.final_path), { recursive: true });
35025
+ fs.mkdirSync(dirname14(row.final_path), { recursive: true });
34413
35026
  fs.renameSync(row.stage_path, row.final_path);
34414
35027
  stmt(db, "DELETE FROM migration_pending WHERE migration_key = ?").run(row.migration_key);
34415
35028
  report.rolledForward += 1;
@@ -34439,7 +35052,7 @@ function claimJournalIdentity(args) {
34439
35052
  migration_key, source_session_id, target_harness, pi_session_id,
34440
35053
  final_path, stage_path, content_sha256, phase, created_at
34441
35054
  ) 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);
35055
+ 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
35056
  const row = readPendingMigration(args.db, args.migrationKey);
34444
35057
  if (!row) {
34445
35058
  throw new Error("migration journal row disappeared during insert; aborting migration");
@@ -34944,7 +35557,7 @@ function migrateOpenCodeSessionToPi(opts) {
34944
35557
  const provider = opts.provider ?? model.provider;
34945
35558
  const modelId = opts.modelId ?? model.modelId;
34946
35559
  const cwd = session.directory ?? session.path ?? process.cwd();
34947
- const outputDir = join21(piSessionsRoot, projectPathToPiDirSlug(cwd));
35560
+ const outputDir = join22(piSessionsRoot, projectPathToPiDirSlug(cwd));
34948
35561
  const targetHarness = opts.targetHarness ?? "pi";
34949
35562
  const moduleManagedProject = cortexkitDb === null ? null : moduleManagedProjectForSession(cortexkitDb, session.id);
34950
35563
  if (moduleManagedProject) {
@@ -34968,8 +35581,8 @@ function migrateOpenCodeSessionToPi(opts) {
34968
35581
  migrationKey,
34969
35582
  sourceSessionId: session.id,
34970
35583
  targetHarness,
34971
- finalPathFor: (id) => join21(outputDir, `${formatPiFilenameTimestamp(now)}_${id}.jsonl`),
34972
- stageDir: join21(dirname13(piSessionsRoot), MIGRATION_STAGE_DIRNAME),
35584
+ finalPathFor: (id) => join22(outputDir, `${formatPiFilenameTimestamp(now)}_${id}.jsonl`),
35585
+ stageDir: join22(dirname14(piSessionsRoot), MIGRATION_STAGE_DIRNAME),
34973
35586
  now: now.getTime()
34974
35587
  });
34975
35588
  piSessionId = claimed.row.pi_session_id;
@@ -34978,7 +35591,7 @@ function migrateOpenCodeSessionToPi(opts) {
34978
35591
  journalResumed = claimed.resumed;
34979
35592
  } else {
34980
35593
  piSessionId = generateUuidV7(now);
34981
- finalPath = join21(outputDir, `${formatPiFilenameTimestamp(now)}_${piSessionId}.jsonl`);
35594
+ finalPath = join22(outputDir, `${formatPiFilenameTimestamp(now)}_${piSessionId}.jsonl`);
34982
35595
  stagePath = "";
34983
35596
  }
34984
35597
  const buildResult = buildPiEntries({
@@ -35017,11 +35630,11 @@ function migrateOpenCodeSessionToPi(opts) {
35017
35630
  `;
35018
35631
  if (!opts.dryRun) {
35019
35632
  if (journalActive && cortexkitDb !== null && migrationKey !== undefined && plan) {
35020
- const contentSha256 = createHash4("sha256").update(jsonl, "utf8").digest("hex");
35633
+ const contentSha256 = createHash6("sha256").update(jsonl, "utf8").digest("hex");
35021
35634
  commitStagedChecksum(cortexkitDb, migrationKey, contentSha256);
35022
35635
  fs.writeFileAtomic(stagePath, jsonl);
35023
35636
  plan.commit(migrationKey);
35024
- fs.mkdirSync(dirname13(finalPath), { recursive: true });
35637
+ fs.mkdirSync(dirname14(finalPath), { recursive: true });
35025
35638
  fs.renameSync(stagePath, finalPath);
35026
35639
  stmt(cortexkitDb, "DELETE FROM migration_pending WHERE migration_key = ?").run(migrationKey);
35027
35640
  } else {
@@ -35291,9 +35904,9 @@ var init_relocate_memory = __esm(() => {
35291
35904
  });
35292
35905
 
35293
35906
  // 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";
35907
+ import { existsSync as existsSync27, realpathSync as realpathSync5 } from "node:fs";
35908
+ import { homedir as homedir15 } from "node:os";
35909
+ import path5, { join as join23 } from "node:path";
35297
35910
  function existingSessionColumns(db) {
35298
35911
  const rows = db.prepare("PRAGMA table_info(session)").all();
35299
35912
  return new Set(rows.map((r) => r.name).filter((n) => typeof n === "string"));
@@ -35377,7 +35990,7 @@ function planMigrateSession(sessionId, rawTargetDirectory, deps) {
35377
35990
  ocProjectId = "global";
35378
35991
  ocWorktree = globalRow.worktree || "/";
35379
35992
  }
35380
- const sessionPath = path4.relative(ocWorktree, targetDirectory);
35993
+ const sessionPath = path5.relative(ocWorktree, targetDirectory);
35381
35994
  const ownershipRow = deps.contextDb.prepare("SELECT project_path FROM session_projects WHERE session_id = ? AND harness = 'opencode'").get(sessionId);
35382
35995
  const fromMcIdentity = ownershipRow?.project_path ?? (sessionRow.directory ? deps.resolveIdentity(sessionRow.directory) : "");
35383
35996
  const toMcIdentity = deps.resolveIdentity(targetDirectory);
@@ -35503,18 +36116,18 @@ function defaultOpenCodeDbPath2() {
35503
36116
  return getOpenCodeDatabasePath();
35504
36117
  }
35505
36118
  function defaultContextDbPath() {
35506
- return join22(getMagicContextStorageDir(), "context.db");
36119
+ return join23(getMagicContextStorageDir(), "context.db");
35507
36120
  }
35508
36121
  function realDeps(opencodeDb, contextDb) {
35509
36122
  return {
35510
36123
  opencodeDb,
35511
36124
  contextDb,
35512
36125
  resolveIdentity: resolveProjectIdentity,
35513
- hasGitDir: (dir) => existsSync26(join22(dir, ".git")),
35514
- realpath: (p) => realpathSync4(p)
36126
+ hasGitDir: (dir) => existsSync27(join23(dir, ".git")),
36127
+ realpath: (p) => realpathSync5(p)
35515
36128
  };
35516
36129
  }
35517
- function valueAfter2(args, flag) {
36130
+ function valueAfter(args, flag) {
35518
36131
  const index = args.indexOf(flag);
35519
36132
  if (index === -1)
35520
36133
  return null;
@@ -35568,11 +36181,11 @@ async function runMigrateSessionCli(args) {
35568
36181
  printMigrateSessionHelp();
35569
36182
  return 0;
35570
36183
  }
35571
- const sessionId = valueAfter2(args, "--session");
35572
- const toDir = valueAfter2(args, "--to");
36184
+ const sessionId = valueAfter(args, "--session");
36185
+ const toDir = valueAfter(args, "--to");
35573
36186
  const dryRun = args.includes("--dry-run");
35574
36187
  const skipConfirm = args.includes("--yes");
35575
- const memoriesFlag = valueAfter2(args, "--memories");
36188
+ const memoriesFlag = valueAfter(args, "--memories");
35576
36189
  if (!sessionId) {
35577
36190
  console.error("Missing required flag: --session <id>");
35578
36191
  printMigrateSessionHelp();
@@ -35588,8 +36201,8 @@ async function runMigrateSessionCli(args) {
35588
36201
  printMigrateSessionHelp();
35589
36202
  return 1;
35590
36203
  }
35591
- const expandedTo = toDir.startsWith("~") ? join22(homedir14(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
35592
- if (!existsSync26(expandedTo)) {
36204
+ const expandedTo = toDir.startsWith("~") ? join23(homedir15(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
36205
+ if (!existsSync27(expandedTo)) {
35593
36206
  console.error(`Target directory does not exist: ${expandedTo}`);
35594
36207
  return 1;
35595
36208
  }
@@ -35741,9 +36354,9 @@ var init_migrate_session = __esm(async () => {
35741
36354
  });
35742
36355
 
35743
36356
  // ../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";
36357
+ import { createHash as createHash7 } from "node:crypto";
36358
+ import { realpathSync as realpathSync6 } from "node:fs";
36359
+ import path6 from "node:path";
35747
36360
  function readMeta(db, key) {
35748
36361
  const row = db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(key);
35749
36362
  return row?.value ?? null;
@@ -35764,7 +36377,7 @@ function countFailures(db) {
35764
36377
  function classifyBackfillError(error) {
35765
36378
  if (error instanceof ProjectIdentityError) {
35766
36379
  return {
35767
- errorClass: error.errorClass === "dubious_ownership" ? "unknown" : error.errorClass,
36380
+ errorClass: error.errorClass === "dubious_ownership" || error.errorClass === "home_project_disabled" || error.errorClass === "git_identity_unavailable" ? "unknown" : error.errorClass,
35768
36381
  errorMessage: error.message
35769
36382
  };
35770
36383
  }
@@ -35786,11 +36399,11 @@ function resolveBackfillIdentity(rawProjectPath) {
35786
36399
  function computeLegacyRustDirIdentity(rawProjectPath) {
35787
36400
  let canonical;
35788
36401
  try {
35789
- canonical = realpathSync5(rawProjectPath);
36402
+ canonical = realpathSync6(rawProjectPath);
35790
36403
  } catch {
35791
- canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
36404
+ canonical = path6.isAbsolute(rawProjectPath) ? rawProjectPath : path6.join(process.cwd(), rawProjectPath);
35792
36405
  }
35793
- return `dir:${createHash5("sha256").update(canonical, "utf8").digest("hex")}`;
36406
+ return `dir:${createHash7("sha256").update(canonical, "utf8").digest("hex")}`;
35794
36407
  }
35795
36408
  function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
35796
36409
  db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
@@ -36011,7 +36624,7 @@ var init_tick_failure = __esm(() => {
36011
36624
  });
36012
36625
 
36013
36626
  // ../pi-plugin/src/config/index.ts
36014
- import { existsSync as existsSync27 } from "node:fs";
36627
+ import { existsSync as existsSync28 } from "node:fs";
36015
36628
  function getProjectConfigPaths(cwd) {
36016
36629
  const basePath = cortexKitProjectConfigBasePath(cwd);
36017
36630
  return [`${basePath}.jsonc`, `${basePath}.json`];
@@ -36021,10 +36634,10 @@ function getUserConfigPaths() {
36021
36634
  return [`${basePath}.jsonc`, `${basePath}.json`];
36022
36635
  }
36023
36636
  function resolveFirstExisting(paths) {
36024
- return paths.find((path) => existsSync27(path));
36637
+ return paths.find((path) => existsSync28(path));
36025
36638
  }
36026
36639
  function resolvePiLegacyFallback(sources) {
36027
- return sources.find((source) => existsSync27(source.path)) ?? null;
36640
+ return sources.find((source) => existsSync28(source.path)) ?? null;
36028
36641
  }
36029
36642
  function loadConfigFile(path, scope) {
36030
36643
  let raw;
@@ -36319,7 +36932,7 @@ function loadPiConfigDetailed(opts = {}, applyRuntimeGlobals = true) {
36319
36932
  if (loaded)
36320
36933
  loadedFiles.push(loaded);
36321
36934
  }
36322
- const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) => existsSync27(source.path));
36935
+ const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) => existsSync28(source.path));
36323
36936
  const userPath = resolveFirstExisting(getUserConfigPaths());
36324
36937
  const userLegacyFallback = userPath ? null : resolvePiLegacyFallback(harnessLegacy.user);
36325
36938
  const userReadPath = userPath ?? userLegacyFallback?.path;
@@ -36328,7 +36941,7 @@ function loadPiConfigDetailed(opts = {}, applyRuntimeGlobals = true) {
36328
36941
  if (loaded)
36329
36942
  loadedFiles.push(loaded);
36330
36943
  }
36331
- const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) => existsSync27(source.path));
36944
+ const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) => existsSync28(source.path));
36332
36945
  if (userLegacyFallback) {
36333
36946
  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
36947
  } else if (legacyUserUnmigrated) {
@@ -36450,10 +37063,11 @@ var DATABASE_REPAIR_COMMAND = "bunx @cortexkit/magic-context@latest doctor repai
36450
37063
 
36451
37064
  // src/lib/github-issue.ts
36452
37065
  import { spawnSync as spawnSync5 } from "node:child_process";
36453
- import { readFileSync as readFileSync16 } from "node:fs";
37066
+ import { readFileSync as readFileSync18 } from "node:fs";
36454
37067
  function runGhCommand(args) {
36455
37068
  try {
36456
37069
  const result = spawnSync5("gh", args, {
37070
+ windowsHide: true,
36457
37071
  encoding: "utf-8",
36458
37072
  stdio: ["ignore", "pipe", "pipe"]
36459
37073
  });
@@ -36476,7 +37090,7 @@ function failed(result) {
36476
37090
  function submitGithubIssue(title, bodyPath, runner = runGhCommand) {
36477
37091
  let body;
36478
37092
  try {
36479
- body = readFileSync16(bodyPath, "utf-8");
37093
+ body = readFileSync18(bodyPath, "utf-8");
36480
37094
  } catch (error) {
36481
37095
  return {
36482
37096
  ok: false,
@@ -36534,9 +37148,9 @@ var MAX_GITHUB_ISSUE_BODY_CHARS = 65536;
36534
37148
  var init_github_issue = () => {};
36535
37149
 
36536
37150
  // src/lib/log-lines.ts
36537
- import { existsSync as existsSync28, readFileSync as readFileSync17, statSync as statSync12 } from "node:fs";
37151
+ import { existsSync as existsSync29, readFileSync as readFileSync19, statSync as statSync12 } from "node:fs";
36538
37152
  import { tmpdir as tmpdir2 } from "node:os";
36539
- import { join as join23 } from "node:path";
37153
+ import { join as join24 } from "node:path";
36540
37154
  function tokenize(input, limit = Number.POSITIVE_INFINITY) {
36541
37155
  const tokens = [];
36542
37156
  let index = 0;
@@ -36822,20 +37436,20 @@ function parseLogLine(line) {
36822
37436
  }
36823
37437
  function getMagicContextLogPaths(harness, options = {}) {
36824
37438
  const override = options.override === undefined ? process.env.MAGIC_CONTEXT_LOG_PATH?.trim() : options.override?.trim();
36825
- const storageLogs = join23(options.storageDir ?? getMagicContextStorageDir(), "logs");
37439
+ const storageLogs = join24(options.storageDir ?? getMagicContextStorageDir(), "logs");
36826
37440
  return [
36827
37441
  ...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")
37442
+ join24(options.tempDir ?? tmpdir2(), harness, "magic-context", "magic-context.log"),
37443
+ join24(storageLogs, `magic-context.${harness}.log`),
37444
+ join24(storageLogs, "magic-context.log")
36831
37445
  ].filter((path, index, paths) => paths.indexOf(path) === index);
36832
37446
  }
36833
37447
  function inspectLogFile(path) {
36834
- if (!existsSync28(path)) {
37448
+ if (!existsSync29(path)) {
36835
37449
  return { path, exists: false, sizeKb: 0, lineCount: 0, grammar: "unknown" };
36836
37450
  }
36837
37451
  try {
36838
- const content = readFileSync17(path, "utf8");
37452
+ const content = readFileSync19(path, "utf8");
36839
37453
  const lines = content.split(/\r?\n/).filter((line) => line.length > 0);
36840
37454
  const grammars = new Set(lines.flatMap((line) => {
36841
37455
  const parsed = parseLogLine(line);
@@ -36862,7 +37476,7 @@ function readLogLines(files) {
36862
37476
  return [];
36863
37477
  try {
36864
37478
  let precedingTimestamp = "";
36865
- return readFileSync17(file.path, "utf8").split(/\r?\n/).filter((line) => line.length > 0).map((line, lineIndex) => {
37479
+ return readFileSync19(file.path, "utf8").split(/\r?\n/).filter((line) => line.length > 0).map((line, lineIndex) => {
36866
37480
  precedingTimestamp = parseLogLine(line)?.ts ?? precedingTimestamp;
36867
37481
  return { line, timestamp: precedingTimestamp, fileIndex, lineIndex };
36868
37482
  });
@@ -36911,10 +37525,10 @@ var init_redaction2 = __esm(() => {
36911
37525
  });
36912
37526
 
36913
37527
  // 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";
37528
+ import { execFileSync as execFileSync6, spawnSync as spawnSync6 } from "node:child_process";
37529
+ import { existsSync as existsSync30, mkdirSync as mkdirSync10, readFileSync as readFileSync20 } from "node:fs";
36916
37530
  import { createRequire as createRequire3 } from "node:module";
36917
- import { dirname as dirname14, join as join24, resolve as resolve8 } from "node:path";
37531
+ import { dirname as dirname15, join as join25, resolve as resolve8 } from "node:path";
36918
37532
  function parseSemver(value) {
36919
37533
  const match = value?.match(/(\d+)\.(\d+)\.(\d+)/);
36920
37534
  return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
@@ -36956,10 +37570,10 @@ function selfVersion() {
36956
37570
  return "unknown";
36957
37571
  }
36958
37572
  function readConfig2(path) {
36959
- if (!existsSync29(path))
37573
+ if (!existsSync30(path))
36960
37574
  return {};
36961
37575
  try {
36962
- const parsed = import_comment_json7.parse(readFileSync18(path, "utf-8"));
37576
+ const parsed = import_comment_json7.parse(readFileSync20(path, "utf-8"));
36963
37577
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? {} : { error: "top level is not an object" };
36964
37578
  } catch (error) {
36965
37579
  return { error: error instanceof Error ? error.message : String(error) };
@@ -36969,7 +37583,7 @@ function pluginDeclaresOmp(path) {
36969
37583
  if (!path)
36970
37584
  return null;
36971
37585
  try {
36972
- const pkg = JSON.parse(readFileSync18(join24(path, "package.json"), "utf-8"));
37586
+ const pkg = JSON.parse(readFileSync20(join25(path, "package.json"), "utf-8"));
36973
37587
  return Array.isArray(pkg.omp?.extensions) || Array.isArray(pkg.pi?.extensions);
36974
37588
  } catch {
36975
37589
  return null;
@@ -37050,7 +37664,7 @@ async function runHealthChecks(options) {
37050
37664
  }
37051
37665
  }
37052
37666
  const userConfigPath = getOmpUserConfigPath();
37053
- if (!existsSync29(userConfigPath)) {
37667
+ if (!existsSync30(userConfigPath)) {
37054
37668
  add(results, "warn", `No Magic Context user config at ${userConfigPath}`);
37055
37669
  repairPlan.writeUserConfig = true;
37056
37670
  } else {
@@ -37067,9 +37681,9 @@ async function runHealthChecks(options) {
37067
37681
  for (const warning of loaded.warnings.slice(0, 5))
37068
37682
  add(results, "warn", warning);
37069
37683
  const storage = getMagicContextStorageResolution();
37070
- const dbPath = join24(storage.path, "context.db");
37684
+ const dbPath = join25(storage.path, "context.db");
37071
37685
  add(results, "info", `Shared storage: ${storage.path} (source: ${storage.source})`);
37072
- if (!existsSync29(dbPath))
37686
+ if (!existsSync30(dbPath))
37073
37687
  add(results, "info", `Shared context DB will be created at ${dbPath}`);
37074
37688
  else {
37075
37689
  let db = null;
@@ -37123,7 +37737,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
37123
37737
  };
37124
37738
  }
37125
37739
  function writeDefaultConfig(path) {
37126
- mkdirSync8(dirname14(path), { recursive: true });
37740
+ mkdirSync10(dirname15(path), { recursive: true });
37127
37741
  const config = {
37128
37742
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
37129
37743
  ...MagicContextConfigSchema.parse({})
@@ -37133,7 +37747,7 @@ function writeDefaultConfig(path) {
37133
37747
  }
37134
37748
  async function repair(plan, deps, prompts, cwd) {
37135
37749
  let fixed = 0;
37136
- if (plan.writeUserConfig && !existsSync29(getOmpUserConfigPath())) {
37750
+ if (plan.writeUserConfig && !existsSync30(getOmpUserConfigPath())) {
37137
37751
  writeDefaultConfig(getOmpUserConfigPath());
37138
37752
  prompts.log.success(`Wrote default Magic Context config to ${getOmpUserConfigPath()}`);
37139
37753
  fixed += 1;
@@ -37175,6 +37789,7 @@ function timestamp2(date) {
37175
37789
  function runGhCommandWithDeps(deps, args) {
37176
37790
  if (args[0] === "issue") {
37177
37791
  const result = deps.spawnSync("gh", args, {
37792
+ windowsHide: true,
37178
37793
  encoding: "utf-8",
37179
37794
  stdio: ["ignore", "pipe", "pipe"]
37180
37795
  });
@@ -37186,6 +37801,7 @@ function runGhCommandWithDeps(deps, args) {
37186
37801
  }
37187
37802
  try {
37188
37803
  const output = deps.execFileSync("gh", args, {
37804
+ windowsHide: true,
37189
37805
  encoding: "utf-8",
37190
37806
  stdio: ["ignore", "pipe", "pipe"]
37191
37807
  });
@@ -37218,7 +37834,7 @@ async function runIssueFlow(options) {
37218
37834
  ...report.results.map((result) => `- ${result.status.toUpperCase()}: ${sanitizeDiagnosticText(result.message)}`)
37219
37835
  ].join(`
37220
37836
  `);
37221
- const path = join24(options.cwd, `magic-context-omp-issue-${timestamp2(options.deps.now())}.md`);
37837
+ const path = join25(options.cwd, `magic-context-omp-issue-${timestamp2(options.deps.now())}.md`);
37222
37838
  writeFileAtomic(path, `${body}
37223
37839
  `);
37224
37840
  options.prompts.log.success(`Sanitized report written to ${path}`);
@@ -37289,7 +37905,7 @@ var init_doctor_omp = __esm(async () => {
37289
37905
  openExistingContextDatabase,
37290
37906
  now: () => new Date,
37291
37907
  inspectMagicContextLogs,
37292
- execFileSync: execFileSync5,
37908
+ execFileSync: execFileSync6,
37293
37909
  spawnSync: spawnSync6
37294
37910
  };
37295
37911
  });
@@ -37406,7 +38022,7 @@ function truncate(text) {
37406
38022
  var DEFAULT_TIMEOUT_MS = 1e4, MAX_PREVIEW_CHARS = 240;
37407
38023
 
37408
38024
  // ../plugin/src/features/magic-context/memory/embedding-synapse.ts
37409
- import { createHash as createHash6 } from "node:crypto";
38025
+ import { createHash as createHash8 } from "node:crypto";
37410
38026
  function toSynapseLaneDescriptor(metadata) {
37411
38027
  const tokenBudget = metadata.recommended_token_budget;
37412
38028
  return {
@@ -37546,7 +38162,7 @@ function wait(ms) {
37546
38162
  return new Promise((resolve) => setTimeout(resolve, ms));
37547
38163
  }
37548
38164
  function sha256(value) {
37549
- return createHash6("sha256").update(value).digest("hex");
38165
+ return createHash8("sha256").update(value).digest("hex");
37550
38166
  }
37551
38167
  function stableJson2(value) {
37552
38168
  if (Array.isArray(value))
@@ -38190,12 +38806,12 @@ function listShadowBackfillStalls(db, projectIdentity) {
38190
38806
  var SHADOW_BACKFILL_PROVENANCE_KEY = "_magicContextShadowBackfill";
38191
38807
 
38192
38808
  // ../plugin/src/shared/auto-update-provenance.ts
38193
- import { existsSync as existsSync30, readFileSync as readFileSync19 } from "node:fs";
38809
+ import { existsSync as existsSync31, readFileSync as readFileSync21 } from "node:fs";
38194
38810
  function readAutoUpdateCheckState(path) {
38195
- if (!existsSync30(path))
38811
+ if (!existsSync31(path))
38196
38812
  return null;
38197
38813
  try {
38198
- const value = JSON.parse(readFileSync19(path, "utf-8"));
38814
+ const value = JSON.parse(readFileSync21(path, "utf-8"));
38199
38815
  if (!value || typeof value !== "object" || Array.isArray(value))
38200
38816
  return null;
38201
38817
  const raw = value;
@@ -38223,14 +38839,14 @@ var init_auto_update_provenance = () => {};
38223
38839
  // ../plugin/src/shared/tui-config.ts
38224
38840
  import {
38225
38841
  chmodSync as chmodSync5,
38226
- existsSync as existsSync31,
38227
- mkdirSync as mkdirSync9,
38228
- readFileSync as readFileSync20,
38229
- renameSync as renameSync6,
38842
+ existsSync as existsSync32,
38843
+ mkdirSync as mkdirSync11,
38844
+ readFileSync as readFileSync22,
38845
+ renameSync as renameSync8,
38230
38846
  statSync as statSync13,
38231
- writeFileSync as writeFileSync6
38847
+ writeFileSync as writeFileSync8
38232
38848
  } from "node:fs";
38233
- import { dirname as dirname15, join as join25 } from "node:path";
38849
+ import { dirname as dirname16, join as join26 } from "node:path";
38234
38850
  function pluginEntryId(entry) {
38235
38851
  if (typeof entry === "string")
38236
38852
  return entry;
@@ -38261,21 +38877,21 @@ function writeTuiConfigAtomic(configPath, config) {
38261
38877
  const body = `${import_comment_json8.stringify(config, null, 2)}
38262
38878
  `;
38263
38879
  const tmpPath = `${configPath}.tmp`;
38264
- writeFileSync6(tmpPath, body);
38880
+ writeFileSync8(tmpPath, body);
38265
38881
  try {
38266
38882
  if (statSync13(configPath, { throwIfNoEntry: false })?.isFile()) {
38267
38883
  chmodSync5(tmpPath, statSync13(configPath).mode & 511);
38268
38884
  }
38269
38885
  } catch {}
38270
- renameSync6(tmpPath, configPath);
38886
+ renameSync8(tmpPath, configPath);
38271
38887
  }
38272
38888
  function resolveTuiConfigPath(configDirOverride) {
38273
38889
  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))
38890
+ const jsoncPath = join26(configDir, "tui.jsonc");
38891
+ const jsonPath = join26(configDir, "tui.json");
38892
+ if (existsSync32(jsoncPath))
38277
38893
  return jsoncPath;
38278
- if (existsSync31(jsonPath))
38894
+ if (existsSync32(jsonPath))
38279
38895
  return jsonPath;
38280
38896
  return jsoncPath;
38281
38897
  }
@@ -38283,8 +38899,8 @@ function ensureTuiPluginEntry(options = {}) {
38283
38899
  try {
38284
38900
  const configPath = resolveTuiConfigPath(options.configDir);
38285
38901
  let config = {};
38286
- if (existsSync31(configPath)) {
38287
- const raw = readFileSync20(configPath, "utf-8");
38902
+ if (existsSync32(configPath)) {
38903
+ const raw = readFileSync22(configPath, "utf-8");
38288
38904
  config = import_comment_json8.parse(raw) ?? {};
38289
38905
  }
38290
38906
  const plugins = Array.isArray(config.plugin) ? [...config.plugin] : [];
@@ -38318,7 +38934,7 @@ function ensureTuiPluginEntry(options = {}) {
38318
38934
  }
38319
38935
  }
38320
38936
  config.plugin = plugins;
38321
- mkdirSync9(dirname15(configPath), { recursive: true });
38937
+ mkdirSync11(dirname16(configPath), { recursive: true });
38322
38938
  writeTuiConfigAtomic(configPath, config);
38323
38939
  log3(`[magic-context] updated TUI plugin entry in ${configPath}`);
38324
38940
  return true;
@@ -38336,9 +38952,9 @@ var init_tui_config = __esm(() => {
38336
38952
  });
38337
38953
 
38338
38954
  // src/lib/diagnostics-opencode.ts
38339
- import { existsSync as existsSync32, readdirSync as readdirSync5, readFileSync as readFileSync21, statSync as statSync14 } from "node:fs";
38955
+ import { existsSync as existsSync33, readdirSync as readdirSync6, readFileSync as readFileSync23, statSync as statSync14 } from "node:fs";
38340
38956
  import { createRequire as createRequire4 } from "node:module";
38341
- import { join as join26 } from "node:path";
38957
+ import { join as join27 } from "node:path";
38342
38958
  function getSelfVersion() {
38343
38959
  const require2 = createRequire4(import.meta.url);
38344
38960
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -38353,7 +38969,7 @@ function getSelfVersion() {
38353
38969
  }
38354
38970
  function readLegacyCachedVersion(root) {
38355
38971
  try {
38356
- const pkg = JSON.parse(readFileSync21(getOpenCodePluginPackageJsonPath(root), "utf-8"));
38972
+ const pkg = JSON.parse(readFileSync23(getOpenCodePluginPackageJsonPath(root), "utf-8"));
38357
38973
  return typeof pkg.version === "string" ? pkg.version : undefined;
38358
38974
  } catch {
38359
38975
  return;
@@ -38362,7 +38978,7 @@ function readLegacyCachedVersion(root) {
38362
38978
  function collectOpenCodePluginCacheReport(hostGeneration, opencodeConfig) {
38363
38979
  const installs = [];
38364
38980
  for (const root of getOpenCodePluginCacheRoots()) {
38365
- if (!existsSync32(root))
38981
+ if (!existsSync33(root))
38366
38982
  continue;
38367
38983
  const spec = root.endsWith("@latest") ? "latest" : "(bare)";
38368
38984
  installs.push({
@@ -38396,7 +39012,7 @@ function getStorageResolution() {
38396
39012
  }
38397
39013
  function fileSize(path) {
38398
39014
  try {
38399
- return existsSync32(path) ? statSync14(path).size : 0;
39015
+ return existsSync33(path) ? statSync14(path).size : 0;
38400
39016
  } catch {
38401
39017
  return 0;
38402
39018
  }
@@ -38408,10 +39024,10 @@ function sanitizeValue(value) {
38408
39024
  return sanitizeConfigValue(value);
38409
39025
  }
38410
39026
  function readConfig3(path) {
38411
- if (!existsSync32(path))
39027
+ if (!existsSync33(path))
38412
39028
  return { value: null };
38413
39029
  try {
38414
- const raw = readFileSync21(path, "utf-8");
39030
+ const raw = readFileSync23(path, "utf-8");
38415
39031
  const value = import_comment_json9.parse(raw);
38416
39032
  return { value };
38417
39033
  } catch (error) {
@@ -38436,7 +39052,7 @@ function configHasPluginEntry(config) {
38436
39052
  }
38437
39053
  function parseHistorianDumpMeta(path) {
38438
39054
  try {
38439
- const xml = readFileSync21(path, "utf-8");
39055
+ const xml = readFileSync23(path, "utf-8");
38440
39056
  const parsed = parseCompartmentOutput(xml);
38441
39057
  const factCountByCategory = {};
38442
39058
  for (const fact of parsed.facts) {
@@ -38469,11 +39085,11 @@ function parseHistorianDumpMeta(path) {
38469
39085
  }
38470
39086
  }
38471
39087
  function listDumpsInDir(dir, limit) {
38472
- if (!existsSync32(dir))
39088
+ if (!existsSync33(dir))
38473
39089
  return { count: 0, recent: [] };
38474
39090
  try {
38475
- const entries = readdirSync5(dir).filter((name) => name.endsWith(".xml")).map((name) => {
38476
- const stat = statSync14(join26(dir, name));
39091
+ const entries = readdirSync6(dir).filter((name) => name.endsWith(".xml")).map((name) => {
39092
+ const stat = statSync14(join27(dir, name));
38477
39093
  return {
38478
39094
  name,
38479
39095
  mtime: stat.mtimeMs,
@@ -38482,7 +39098,7 @@ function listDumpsInDir(dir, limit) {
38482
39098
  }).sort((a, b) => b.mtime - a.mtime);
38483
39099
  const now = Date.now();
38484
39100
  const recent = entries.slice(0, limit).map((entry) => {
38485
- const meta = parseHistorianDumpMeta(join26(dir, entry.name));
39101
+ const meta = parseHistorianDumpMeta(join27(dir, entry.name));
38486
39102
  const summary = {
38487
39103
  name: entry.name,
38488
39104
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -38620,8 +39236,8 @@ async function collectRecentSessions(resolution, hostGeneration) {
38620
39236
  }
38621
39237
  }
38622
39238
  async function collectHistorianFailures(storageDirPath) {
38623
- const contextDbPath = join26(storageDirPath, "context.db");
38624
- if (!existsSync32(contextDbPath))
39239
+ const contextDbPath = join27(storageDirPath, "context.db");
39240
+ if (!existsSync33(contextDbPath))
38625
39241
  return [];
38626
39242
  if (typeof globalThis.Bun === "undefined") {
38627
39243
  return [];
@@ -38654,8 +39270,8 @@ async function collectHistorianFailures(storageDirPath) {
38654
39270
  }
38655
39271
  }
38656
39272
  async function collectHistorianRuns(storageDirPath) {
38657
- const contextDbPath = join26(storageDirPath, "context.db");
38658
- if (!existsSync32(contextDbPath))
39273
+ const contextDbPath = join27(storageDirPath, "context.db");
39274
+ if (!existsSync33(contextDbPath))
38659
39275
  return [];
38660
39276
  if (typeof globalThis.Bun === "undefined")
38661
39277
  return [];
@@ -38728,7 +39344,7 @@ async function collectDiagnostics() {
38728
39344
  const magicContextConfig = readConfig3(configPaths.magicContextConfig);
38729
39345
  const storageResolution = getStorageResolution();
38730
39346
  const storageDirPath = storageResolution.path;
38731
- const contextDbPath = join26(storageDirPath, "context.db");
39347
+ const contextDbPath = join27(storageDirPath, "context.db");
38732
39348
  let compactionEnabled = false;
38733
39349
  try {
38734
39350
  compactionEnabled = isCompactionEnabled(loadPluginConfig(process.cwd()));
@@ -38760,7 +39376,7 @@ async function collectDiagnostics() {
38760
39376
  opencodeConfigHasPlugin: configHasPluginEntry(opencodeConfig.value),
38761
39377
  tuiConfigHasPlugin: configHasPluginEntry(tuiConfig.value),
38762
39378
  magicContextConfig: {
38763
- exists: existsSync32(configPaths.magicContextConfig),
39379
+ exists: existsSync33(configPaths.magicContextConfig),
38764
39380
  ...magicContextConfig.error ? { parseError: magicContextConfig.error } : {},
38765
39381
  flags: sanitizeValue(magicContextConfig.value ?? {}) ?? {}
38766
39382
  },
@@ -38768,7 +39384,7 @@ async function collectDiagnostics() {
38768
39384
  storageDir: {
38769
39385
  path: storageDirPath,
38770
39386
  source: storageResolution.source,
38771
- exists: existsSync32(storageDirPath),
39387
+ exists: existsSync33(storageDirPath),
38772
39388
  contextDbSizeBytes: fileSize(contextDbPath)
38773
39389
  },
38774
39390
  openCodeDatabase: {
@@ -39001,9 +39617,9 @@ var init_embedding_local = __esm(() => {
39001
39617
 
39002
39618
  // src/lib/embedding-runtime.ts
39003
39619
  import { spawnSync as spawnSync7 } from "node:child_process";
39004
- import { existsSync as existsSync33, readFileSync as readFileSync22 } from "node:fs";
39620
+ import { existsSync as existsSync34, readFileSync as readFileSync24 } from "node:fs";
39005
39621
  import { createRequire as createRequire5 } from "node:module";
39006
- import { dirname as dirname16, join as join27, sep } from "node:path";
39622
+ import { dirname as dirname17, join as join28, sep } from "node:path";
39007
39623
  function describeError(error) {
39008
39624
  const message = error instanceof Error ? error.message : String(error ?? "unknown error");
39009
39625
  const code = error?.code;
@@ -39011,6 +39627,7 @@ function describeError(error) {
39011
39627
  }
39012
39628
  function runOnnxRuntimeNodeLoadProbeChild(packageDir) {
39013
39629
  return spawnSync7(process.execPath, ["-e", ONNX_RUNTIME_NODE_LOAD_PROBE_SCRIPT], {
39630
+ windowsHide: true,
39014
39631
  encoding: "utf8",
39015
39632
  env: { ...process.env, [ONNX_LOAD_PROBE_PACKAGE_DIR_ENV]: packageDir },
39016
39633
  stdio: ["ignore", "pipe", "pipe"],
@@ -39144,11 +39761,11 @@ function expectedBinaryRelPath(platform, arch) {
39144
39761
  const supportedArch = arch === "x64" || arch === "arm64";
39145
39762
  if (!supportedPlatform || !supportedArch)
39146
39763
  return null;
39147
- return join27("bin", "napi-v6", platform, arch, "onnxruntime_binding.node");
39764
+ return join28("bin", "napi-v6", platform, arch, "onnxruntime_binding.node");
39148
39765
  }
39149
39766
  function onnxRuntimeNodeVersion(packageDir) {
39150
39767
  try {
39151
- const parsed = JSON.parse(readFileSync22(join27(packageDir, "package.json"), "utf8"));
39768
+ const parsed = JSON.parse(readFileSync24(join28(packageDir, "package.json"), "utf8"));
39152
39769
  return typeof parsed.version === "string" ? parsed.version : undefined;
39153
39770
  } catch {
39154
39771
  return;
@@ -39197,7 +39814,7 @@ function formatLocalEmbeddingRuntimeWasmSelected(status) {
39197
39814
  function requireNodeWasmBundle(probe, candidates) {
39198
39815
  if (probe.state === "failed")
39199
39816
  return probe;
39200
- const bundlePath = candidates.find((candidate) => existsSync33(candidate));
39817
+ const bundlePath = candidates.find((candidate) => existsSync34(candidate));
39201
39818
  return bundlePath ? probe : {
39202
39819
  state: "failed",
39203
39820
  reason: `functional Node WASM Transformers bundle is missing (checked ${candidates.join(", ")})`
@@ -39205,13 +39822,13 @@ function requireNodeWasmBundle(probe, candidates) {
39205
39822
  }
39206
39823
  function nodeWasmBundleCandidates(installRoot) {
39207
39824
  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")
39825
+ join28(installRoot, "dist", "transformers-node-wasm.js"),
39826
+ join28(installRoot, "node_modules", "@cortexkit", "opencode-magic-context", "dist", "transformers-node-wasm.js"),
39827
+ join28(installRoot, "node_modules", "@cortexkit", "pi-magic-context", "dist", "transformers-node-wasm.js")
39211
39828
  ];
39212
39829
  }
39213
39830
  function probeWasmRuntimeAt(installRoot) {
39214
- const requireFn = createRequire5(join27(installRoot, "package.json"));
39831
+ const requireFn = createRequire5(join28(installRoot, "package.json"));
39215
39832
  return requireNodeWasmBundle(probeWasmRuntimeFromRequire(requireFn), nodeWasmBundleCandidates(installRoot));
39216
39833
  }
39217
39834
  function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
@@ -39220,9 +39837,9 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
39220
39837
  const wasm = probeWasmRuntimeAt(installRoot);
39221
39838
  return wasm.state === "ok" ? { state: "wasm-selected", wasmPath: wasm.wasmPath } : { state: "wasm-broken", wasmReason: wasm.reason };
39222
39839
  }
39223
- const packageDir = join27(installRoot, "node_modules", "onnxruntime-node");
39840
+ const packageDir = join28(installRoot, "node_modules", "onnxruntime-node");
39224
39841
  let native;
39225
- if (!existsSync33(join27(packageDir, "package.json"))) {
39842
+ if (!existsSync34(join28(packageDir, "package.json"))) {
39226
39843
  native = { state: "package-missing", packageDir };
39227
39844
  } else {
39228
39845
  const rel = expectedBinaryRelPath(platform, arch);
@@ -39232,8 +39849,8 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
39232
39849
  binaryPath: packageDir
39233
39850
  };
39234
39851
  } else {
39235
- const binaryPath = join27(packageDir, rel);
39236
- native = existsSync33(binaryPath) ? probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath } : {
39852
+ const binaryPath = join28(packageDir, rel);
39853
+ native = existsSync34(binaryPath) ? probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath } : {
39237
39854
  state: "binary-missing",
39238
39855
  packageDir,
39239
39856
  expectedBinary: binaryPath,
@@ -39244,7 +39861,7 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
39244
39861
  return withWasmFallback(native, () => probeWasmRuntimeAt(installRoot));
39245
39862
  }
39246
39863
  function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
39247
- const existing = installRoots.filter((root) => existsSync33(root));
39864
+ const existing = installRoots.filter((root) => existsSync34(root));
39248
39865
  if (existing.length === 0) {
39249
39866
  return {
39250
39867
  state: "unknown",
@@ -39270,19 +39887,19 @@ function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, a
39270
39887
  function packageDirFromResolved(resolvedPath, packageName) {
39271
39888
  const marker = `node_modules${sep}${packageName.split("/").join(sep)}`;
39272
39889
  const idx = resolvedPath.indexOf(marker);
39273
- return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) : dirname16(resolvedPath);
39890
+ return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) : dirname17(resolvedPath);
39274
39891
  }
39275
39892
  function probeWasmRuntimeByResolution(pluginDir) {
39276
39893
  try {
39277
- const reqPlugin = createRequire5(join27(pluginDir, "package.json"));
39894
+ const reqPlugin = createRequire5(join28(pluginDir, "package.json"));
39278
39895
  const direct = probeWasmRuntimeFromRequire(reqPlugin);
39279
39896
  let probe = direct;
39280
39897
  if (direct.state === "failed" && direct.reason.startsWith("onnxruntime-web is not resolvable")) {
39281
39898
  const tfResolved = reqPlugin.resolve("@huggingface/transformers");
39282
39899
  const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
39283
- probe = probeWasmRuntimeFromRequire(createRequire5(join27(tfDir, "package.json")));
39900
+ probe = probeWasmRuntimeFromRequire(createRequire5(join28(tfDir, "package.json")));
39284
39901
  }
39285
- return requireNodeWasmBundle(probe, [join27(pluginDir, "dist", "transformers-node-wasm.js")]);
39902
+ return requireNodeWasmBundle(probe, [join28(pluginDir, "dist", "transformers-node-wasm.js")]);
39286
39903
  } catch (error) {
39287
39904
  return {
39288
39905
  state: "failed",
@@ -39291,7 +39908,7 @@ function probeWasmRuntimeByResolution(pluginDir) {
39291
39908
  }
39292
39909
  }
39293
39910
  function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
39294
- if (!existsSync33(join27(pluginDir, "package.json"))) {
39911
+ if (!existsSync34(join28(pluginDir, "package.json"))) {
39295
39912
  return { state: "unknown", reason: "plugin package dir not found" };
39296
39913
  }
39297
39914
  const selectedRuntime = resolveLocalEmbeddingRuntime(runtimePreference, host);
@@ -39302,13 +39919,13 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
39302
39919
  let onnxDir = null;
39303
39920
  let resolveError;
39304
39921
  try {
39305
- const reqPlugin = createRequire5(join27(pluginDir, "package.json"));
39922
+ const reqPlugin = createRequire5(join28(pluginDir, "package.json"));
39306
39923
  try {
39307
39924
  onnxDir = packageDirFromResolved(reqPlugin.resolve("onnxruntime-node"), "onnxruntime-node");
39308
39925
  } catch {
39309
39926
  const tfResolved = reqPlugin.resolve("@huggingface/transformers");
39310
39927
  const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
39311
- const reqTf = createRequire5(join27(tfDir, "package.json"));
39928
+ const reqTf = createRequire5(join28(tfDir, "package.json"));
39312
39929
  onnxDir = packageDirFromResolved(reqTf.resolve("onnxruntime-node"), "onnxruntime-node");
39313
39930
  }
39314
39931
  } catch (error) {
@@ -39316,7 +39933,7 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
39316
39933
  if (resolveError === "ERR_MODULE_NOT_FOUND" || resolveError === "MODULE_NOT_FOUND") {
39317
39934
  return withWasmFallback({
39318
39935
  state: "package-missing",
39319
- packageDir: join27(pluginDir, "node_modules", "onnxruntime-node")
39936
+ packageDir: join28(pluginDir, "node_modules", "onnxruntime-node")
39320
39937
  }, () => probeWasmRuntimeByResolution(pluginDir));
39321
39938
  }
39322
39939
  return {
@@ -39332,8 +39949,8 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
39332
39949
  if (rel === null) {
39333
39950
  native = probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath: onnxDir };
39334
39951
  } else {
39335
- const binaryPath = join27(onnxDir, rel);
39336
- native = existsSync33(binaryPath) ? probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath } : {
39952
+ const binaryPath = join28(onnxDir, rel);
39953
+ native = existsSync34(binaryPath) ? probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath } : {
39337
39954
  state: "binary-missing",
39338
39955
  packageDir: onnxDir,
39339
39956
  expectedBinary: binaryPath,
@@ -39475,8 +40092,8 @@ var init_issue_body = __esm(() => {
39475
40092
  });
39476
40093
 
39477
40094
  // src/lib/logs-opencode.ts
39478
- import { writeFileSync as writeFileSync7 } from "node:fs";
39479
- import { join as join28 } from "node:path";
40095
+ import { writeFileSync as writeFileSync9 } from "node:fs";
40096
+ import { join as join29 } from "node:path";
39480
40097
  function sanitizeLogContent(content) {
39481
40098
  return sanitizeDiagnosticText(content);
39482
40099
  }
@@ -39583,12 +40200,12 @@ async function bundleIssueReport(report, description, title, sessionFilter = nul
39583
40200
  const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
39584
40201
  const truncated = bodyMarkdown !== rawBodyMarkdown;
39585
40202
  const timestamp = formatTimestamp(new Date);
39586
- const path = join28(process.cwd(), `magic-context-issue-${timestamp}.md`);
39587
- writeFileSync7(path, `${bodyMarkdown}
40203
+ const path = join29(process.cwd(), `magic-context-issue-${timestamp}.md`);
40204
+ writeFileSync9(path, `${bodyMarkdown}
39588
40205
  `);
39589
- const fullPath = truncated ? join28(process.cwd(), `magic-context-issue-${timestamp}-full.md`) : undefined;
40206
+ const fullPath = truncated ? join29(process.cwd(), `magic-context-issue-${timestamp}-full.md`) : undefined;
39590
40207
  if (fullPath)
39591
- writeFileSync7(fullPath, `${rawBodyMarkdown}
40208
+ writeFileSync9(fullPath, `${rawBodyMarkdown}
39592
40209
  `);
39593
40210
  return { path, bodyMarkdown, ...fullPath ? { fullPath } : {}, truncated };
39594
40211
  }
@@ -39852,25 +40469,25 @@ function migrateExperimentalPinKeyFilesForDoctor(mcConfig) {
39852
40469
  }
39853
40470
 
39854
40471
  // ../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";
40472
+ import { homedir as homedir16, platform } from "node:os";
40473
+ import { join as join30 } from "node:path";
39857
40474
  function getOpenCodeCacheRoot() {
39858
40475
  if (platform() === "win32") {
39859
- return join29(process.env.LOCALAPPDATA ?? homedir15(), "opencode");
40476
+ return join30(process.env.LOCALAPPDATA ?? homedir16(), "opencode");
39860
40477
  }
39861
- return join29(homedir15(), ".cache", "opencode");
40478
+ return join30(homedir16(), ".cache", "opencode");
39862
40479
  }
39863
40480
  function getOpenCodeConfigRoot() {
39864
40481
  if (platform() === "win32") {
39865
- return join29(process.env.APPDATA ?? join29(homedir15(), "AppData", "Roaming"), "opencode");
40482
+ return join30(process.env.APPDATA ?? join30(homedir16(), "AppData", "Roaming"), "opencode");
39866
40483
  }
39867
- return join29(process.env.XDG_CONFIG_HOME ?? join29(homedir15(), ".config"), "opencode");
40484
+ return join30(process.env.XDG_CONFIG_HOME ?? join30(homedir16(), ".config"), "opencode");
39868
40485
  }
39869
40486
  var PACKAGE_NAME = "@cortexkit/opencode-magic-context", CACHE_DIR, USER_OPENCODE_CONFIG, USER_OPENCODE_CONFIG_JSONC;
39870
40487
  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");
40488
+ CACHE_DIR = join30(getOpenCodeCacheRoot(), "packages");
40489
+ USER_OPENCODE_CONFIG = join30(getOpenCodeConfigRoot(), "opencode.json");
40490
+ USER_OPENCODE_CONFIG_JSONC = join30(getOpenCodeConfigRoot(), "opencode.jsonc");
39874
40491
  });
39875
40492
 
39876
40493
  // ../plugin/src/hooks/auto-update-checker/types.ts
@@ -39894,14 +40511,14 @@ var init_types = __esm(() => {
39894
40511
  // ../plugin/src/hooks/auto-update-checker/checker.ts
39895
40512
  import {
39896
40513
  accessSync as accessSync2,
39897
- existsSync as existsSync34,
40514
+ existsSync as existsSync35,
39898
40515
  constants as fsConstants,
39899
- readFileSync as readFileSync23,
39900
- renameSync as renameSync7,
40516
+ readFileSync as readFileSync25,
40517
+ renameSync as renameSync9,
39901
40518
  statSync as statSync15,
39902
- writeFileSync as writeFileSync8
40519
+ writeFileSync as writeFileSync10
39903
40520
  } from "node:fs";
39904
- import { dirname as dirname17, isAbsolute as isAbsolute7, join as join30, resolve as resolve9 } from "node:path";
40521
+ import { dirname as dirname18, isAbsolute as isAbsolute7, join as join31, resolve as resolve9 } from "node:path";
39905
40522
  function warn(message) {
39906
40523
  log3(`WARN: ${message}`);
39907
40524
  }
@@ -39927,17 +40544,17 @@ function parseJsonConfig(content) {
39927
40544
  }
39928
40545
  function getSurfaceConfigPaths(directory, surface) {
39929
40546
  const name = surface === "server" ? "opencode" : "tui";
39930
- const globalDir = dirname17(USER_OPENCODE_CONFIG);
40547
+ const globalDir = dirname18(USER_OPENCODE_CONFIG);
39931
40548
  const dirs = [
39932
40549
  globalDir,
39933
40550
  directory,
39934
- join30(directory, ".opencode"),
40551
+ join31(directory, ".opencode"),
39935
40552
  process.env.OPENCODE_CONFIG_DIR
39936
40553
  ].filter((value) => Boolean(value));
39937
40554
  const paths = [];
39938
40555
  for (const dir of dirs) {
39939
40556
  for (const extension of ["json", "jsonc"]) {
39940
- const path = join30(dir, `${name}.${extension}`);
40557
+ const path = join31(dir, `${name}.${extension}`);
39941
40558
  if (!paths.includes(path))
39942
40559
  paths.push(path);
39943
40560
  }
@@ -39948,9 +40565,9 @@ function getWinningConfig(directory, surface) {
39948
40565
  let winner = null;
39949
40566
  for (const path of getSurfaceConfigPaths(directory, surface)) {
39950
40567
  try {
39951
- if (!existsSync34(path))
40568
+ if (!existsSync35(path))
39952
40569
  continue;
39953
- const parsed = parseJsonConfig(readFileSync23(path, "utf-8"));
40570
+ const parsed = parseJsonConfig(readFileSync25(path, "utf-8"));
39954
40571
  const entries = getPluginEntries(parsed);
39955
40572
  if (entries.some((entry) => entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))) {
39956
40573
  if (winner) {
@@ -39986,14 +40603,14 @@ var init_checker = __esm(() => {
39986
40603
  });
39987
40604
 
39988
40605
  // 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";
40606
+ import { existsSync as existsSync36, readdirSync as readdirSync7, readFileSync as readFileSync26 } from "node:fs";
40607
+ import { join as join32 } from "node:path";
39991
40608
  import { gunzipSync } from "node:zlib";
39992
40609
  function readPackageVersion(packageJsonPath) {
39993
40610
  try {
39994
- if (!existsSync35(packageJsonPath))
40611
+ if (!existsSync36(packageJsonPath))
39995
40612
  return null;
39996
- const packageJson = JSON.parse(readFileSync24(packageJsonPath, "utf-8"));
40613
+ const packageJson = JSON.parse(readFileSync26(packageJsonPath, "utf-8"));
39997
40614
  if (packageJson.name !== OPENCODE_PLUGIN_NAME || typeof packageJson.version !== "string") {
39998
40615
  return null;
39999
40616
  }
@@ -40012,8 +40629,8 @@ function readFenceValue(text) {
40012
40629
  return values.size === 1 ? [...values][0] ?? null : null;
40013
40630
  }
40014
40631
  function readFenceFromDist(packageDirectory) {
40015
- const distDirectory = join31(packageDirectory, "dist");
40016
- if (!existsSync35(distDirectory))
40632
+ const distDirectory = join32(packageDirectory, "dist");
40633
+ if (!existsSync36(distDirectory))
40017
40634
  return null;
40018
40635
  const pending = [distDirectory];
40019
40636
  const fenceValues = new Set;
@@ -40022,15 +40639,15 @@ function readFenceFromDist(packageDirectory) {
40022
40639
  if (!directory)
40023
40640
  continue;
40024
40641
  try {
40025
- for (const entry of readdirSync6(directory, { withFileTypes: true })) {
40026
- const path = join31(directory, entry.name);
40642
+ for (const entry of readdirSync7(directory, { withFileTypes: true })) {
40643
+ const path = join32(directory, entry.name);
40027
40644
  if (entry.isDirectory()) {
40028
40645
  pending.push(path);
40029
40646
  continue;
40030
40647
  }
40031
40648
  if (!entry.isFile() || !/\.(?:[cm]?js|ts)$/.test(entry.name))
40032
40649
  continue;
40033
- const fence = readFenceValue(readFileSync24(path, "utf-8"));
40650
+ const fence = readFenceValue(readFileSync26(path, "utf-8"));
40034
40651
  if (fence !== null)
40035
40652
  fenceValues.add(fence);
40036
40653
  }
@@ -40041,20 +40658,20 @@ function readFenceFromDist(packageDirectory) {
40041
40658
  return fenceValues.size === 1 ? [...fenceValues][0] ?? null : null;
40042
40659
  }
40043
40660
  function findInstalledPluginPackage(cacheDirectory, specifier, requestedVersion) {
40044
- const directCacheRoot = join31(cacheDirectory, specifier);
40661
+ const directCacheRoot = join32(cacheDirectory, specifier);
40045
40662
  const candidates = [directCacheRoot];
40046
40663
  try {
40047
- for (const entry of readdirSync6(cacheDirectory, { withFileTypes: true })) {
40664
+ for (const entry of readdirSync7(cacheDirectory, { withFileTypes: true })) {
40048
40665
  if (!entry.isDirectory())
40049
40666
  continue;
40050
- const candidate = join31(cacheDirectory, entry.name);
40667
+ const candidate = join32(cacheDirectory, entry.name);
40051
40668
  if (!candidates.includes(candidate))
40052
40669
  candidates.push(candidate);
40053
40670
  }
40054
40671
  } catch {}
40055
40672
  for (const cacheRoot of candidates) {
40056
- const directory = join31(cacheRoot, "node_modules", ...PACKAGE_PATH_SEGMENTS);
40057
- const version = readPackageVersion(join31(directory, "package.json"));
40673
+ const directory = join32(cacheRoot, "node_modules", ...PACKAGE_PATH_SEGMENTS);
40674
+ const version = readPackageVersion(join32(directory, "package.json"));
40058
40675
  if (!version)
40059
40676
  continue;
40060
40677
  if (cacheRoot === directCacheRoot || EXACT_VERSION_PATTERN.test(requestedVersion) && version === requestedVersion) {
@@ -40248,13 +40865,13 @@ var init_storage_versions = __esm(async () => {
40248
40865
  });
40249
40866
 
40250
40867
  // src/commands/doctor-opencode-cache.ts
40251
- import { existsSync as existsSync36, readFileSync as readFileSync25, rmSync as rmSync4 } from "node:fs";
40868
+ import { existsSync as existsSync37, readFileSync as readFileSync27, rmSync as rmSync4 } from "node:fs";
40252
40869
  function readCachedPluginVersion(pluginCacheDir) {
40253
40870
  try {
40254
40871
  const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
40255
- if (!existsSync36(installedPkgPath))
40872
+ if (!existsSync37(installedPkgPath))
40256
40873
  return;
40257
- const pkg = JSON.parse(readFileSync25(installedPkgPath, "utf-8"));
40874
+ const pkg = JSON.parse(readFileSync27(installedPkgPath, "utf-8"));
40258
40875
  return typeof pkg.version === "string" ? pkg.version : undefined;
40259
40876
  } catch {
40260
40877
  return;
@@ -40263,7 +40880,7 @@ function readCachedPluginVersion(pluginCacheDir) {
40263
40880
  async function clearPluginCache(options = {}, deps = {}) {
40264
40881
  const remove = deps.remove ?? ((path) => rmSync4(path, { recursive: true, force: true }));
40265
40882
  const pluginCacheRoots = getOpenCodePluginCacheRoots();
40266
- const existingRoots = pluginCacheRoots.filter((root) => existsSync36(root));
40883
+ const existingRoots = pluginCacheRoots.filter((root) => existsSync37(root));
40267
40884
  if (existingRoots.length === 0) {
40268
40885
  return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
40269
40886
  }
@@ -40330,19 +40947,19 @@ var init_doctor_opencode_cache = __esm(() => {
40330
40947
  });
40331
40948
 
40332
40949
  // src/commands/doctor-cached-plugin-fence.ts
40333
- import { existsSync as existsSync37 } from "node:fs";
40334
- import { dirname as dirname18 } from "node:path";
40950
+ import { existsSync as existsSync38 } from "node:fs";
40951
+ import { dirname as dirname19 } from "node:path";
40335
40952
  function listCachedOpenCodePluginFences(sources = {}) {
40336
40953
  const fences = [];
40337
40954
  for (const root of sources.openCodeV1Roots ?? getOpenCodePluginCacheRoots()) {
40338
40955
  const packageJson = getOpenCodePluginPackageJsonPath(root);
40339
- if (!existsSync37(packageJson))
40956
+ if (!existsSync38(packageJson))
40340
40957
  continue;
40341
40958
  fences.push({
40342
40959
  host: "opencode1",
40343
40960
  directory: root,
40344
40961
  version: readCachedPluginVersion(root),
40345
- supportedVersion: readFenceFromDist(dirname18(packageJson))
40962
+ supportedVersion: readFenceFromDist(dirname19(packageJson))
40346
40963
  });
40347
40964
  }
40348
40965
  for (const slot of listOpenCodeV2PluginCacheSlots(sources.openCodeV2NpmCacheDir)) {
@@ -40356,7 +40973,7 @@ function listCachedOpenCodePluginFences(sources = {}) {
40356
40973
  directory: slot.slot,
40357
40974
  spec: slot.spec,
40358
40975
  version: slot.version,
40359
- supportedVersion: readFenceFromDist(dirname18(getOpenCodePluginPackageJsonPath(generation)))
40976
+ supportedVersion: readFenceFromDist(dirname19(getOpenCodePluginPackageJsonPath(generation)))
40360
40977
  });
40361
40978
  }
40362
40979
  return fences;
@@ -40431,11 +41048,11 @@ function mcMarkerPredicate(column = "data") {
40431
41048
  AND json_extract(${data}, '$.summary') = 1
40432
41049
  AND json_extract(${data}, '$.providerID') = 'magic-context'`;
40433
41050
  }
40434
- function tableExists4(db, table) {
41051
+ function tableExists5(db, table) {
40435
41052
  return db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ? LIMIT 1").get(table) != null;
40436
41053
  }
40437
41054
  function countMissingCompleted(db) {
40438
- if (!tableExists4(db, "message"))
41055
+ if (!tableExists5(db, "message"))
40439
41056
  return 0;
40440
41057
  const row = db.prepare(`SELECT COUNT(*) AS count
40441
41058
  FROM message
@@ -40444,7 +41061,7 @@ function countMissingCompleted(db) {
40444
41061
  return Number(row?.count ?? 0);
40445
41062
  }
40446
41063
  function migrationV1ToV2Completed(db) {
40447
- if (!tableExists4(db, "kv"))
41064
+ if (!tableExists5(db, "kv"))
40448
41065
  return false;
40449
41066
  const columns = db.prepare("PRAGMA table_info(kv)").all();
40450
41067
  const names = new Set(columns.flatMap((column) => typeof column.name === "string" ? [column.name] : []));
@@ -40461,7 +41078,7 @@ function migrationV1ToV2Completed(db) {
40461
41078
  }
40462
41079
  }
40463
41080
  function countUnmatchedConvertedMarkers(db, migratedV2Schema) {
40464
- if (!migratedV2Schema || !tableExists4(db, "message"))
41081
+ if (!migratedV2Schema || !tableExists5(db, "message"))
40465
41082
  return 0;
40466
41083
  const row = db.prepare(`SELECT COUNT(DISTINCT json_extract(${safeData("marker.data")}, '$.parentID')) AS count
40467
41084
  FROM message marker
@@ -40476,7 +41093,7 @@ function countUnmatchedConvertedMarkers(db, migratedV2Schema) {
40476
41093
  return Number(row?.count ?? 0);
40477
41094
  }
40478
41095
  function countPostConversionMessages(db, migratedV2Schema) {
40479
- if (!migratedV2Schema || !tableExists4(db, "message") || !tableExists4(db, "session")) {
41096
+ if (!migratedV2Schema || !tableExists5(db, "message") || !tableExists5(db, "session")) {
40480
41097
  return { messages: 0, sessions: 0 };
40481
41098
  }
40482
41099
  const row = db.prepare(`SELECT COUNT(*) AS messages, COUNT(DISTINCT converted.session_id) AS sessions
@@ -40493,7 +41110,7 @@ function countPostConversionMessages(db, migratedV2Schema) {
40493
41110
  function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
40494
41111
  const missingBefore = countMissingCompleted(db);
40495
41112
  let repaired = 0;
40496
- if (options.fix && missingBefore > 0 && tableExists4(db, "message")) {
41113
+ if (options.fix && missingBefore > 0 && tableExists5(db, "message")) {
40497
41114
  repaired = db.transaction(() => {
40498
41115
  const result = db.prepare(`UPDATE message
40499
41116
  SET data = json_set(
@@ -40507,7 +41124,7 @@ function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
40507
41124
  })();
40508
41125
  }
40509
41126
  const missingAfter = countMissingCompleted(db);
40510
- const migratedV2Schema = tableExists4(db, "session_v2") && tableExists4(db, "session_message");
41127
+ const migratedV2Schema = tableExists5(db, "session_v2") && tableExists5(db, "session_message");
40511
41128
  const migrationCompleted = migrationV1ToV2Completed(db);
40512
41129
  const unmatchedConvertedMarkers = countUnmatchedConvertedMarkers(db, migratedV2Schema);
40513
41130
  const postConversion = countPostConversionMessages(db, migratedV2Schema);
@@ -40618,6 +41235,182 @@ var init_doctor_harness_relabel = __esm(async () => {
40618
41235
  await init_opencode2_relabel();
40619
41236
  });
40620
41237
 
41238
+ // src/commands/doctor-hidden-children.ts
41239
+ import { spawnSync as spawnSync8 } from "node:child_process";
41240
+ import { existsSync as existsSync39, realpathSync as realpathSync7 } from "node:fs";
41241
+ import { dirname as dirname20 } from "node:path";
41242
+ async function assertHiddenChildStoresClosed(contextDbPath, hostDbPath, platform = process.platform, processProbe = () => inspectProcessesAsync(true)) {
41243
+ if (platform === "win32") {
41244
+ const processes = await processProbe();
41245
+ if (processes.pi.state !== "known" || processes.pi.processIds.length > 0 || (processes.pi.inconclusivePids?.length ?? 0) > 0 || processes.processSnapshot?.source !== "cim") {
41246
+ throw new Error("Windows process probe could not rule out OpenCode, Pi or ck-mc holders");
41247
+ }
41248
+ const unknown = processes.processSnapshot.facts.filter(({ pid, imageName, commandLine }) => pid !== process.pid && (!imageName && !commandLine || /^(?:bun|node|deno)(?:\.exe)?$/i.test(imageName ?? "") && !commandLine));
41249
+ if (unknown.length)
41250
+ throw new Error(`Windows process identity is unavailable (PID ${unknown.map(({ pid }) => pid).join(", ")})`);
41251
+ const blockers = processes.processSnapshot.facts.filter(({ pid, imageName, commandLine }) => {
41252
+ if (pid === process.pid)
41253
+ return false;
41254
+ const image = (imageName ?? "").toLowerCase().replaceAll("\\", "/").split("/").at(-1) ?? "";
41255
+ return /^(?:opencode|opencode2|pi|omp|ck-mc)(?:\.exe)?$/.test(image) || /(?:^|[\\/\s"'])(?:ck-mc|opencode2?)(?:\.exe|\.js|\.mjs)?(?:$|[\s"'])/i.test(commandLine ?? "");
41256
+ });
41257
+ if (blockers.length)
41258
+ throw new Error(`OpenCode, Pi or ck-mc process is running (PID ${blockers.map(({ pid }) => pid).join(", ")})`);
41259
+ return;
41260
+ }
41261
+ const inspection = defaultInspectHolders(dirname20(contextDbPath));
41262
+ if (!inspection.safe) {
41263
+ throw new Error(`database holders cannot be ruled out: ${[...inspection.blockers, inspection.uncertainty].filter(Boolean).join("; ")}`);
41264
+ }
41265
+ const paths = [contextDbPath, hostDbPath].flatMap((path) => [path, `${path}-wal`, `${path}-shm`].filter(existsSync39).map((file) => realpathSync7(file)));
41266
+ const result = spawnSync8("lsof", ["-Fn", "--", ...paths], {
41267
+ encoding: "utf8",
41268
+ timeout: 30000,
41269
+ maxBuffer: 32 * 1024 * 1024,
41270
+ windowsHide: true
41271
+ });
41272
+ if (result.error || result.stderr?.trim() || result.status !== 0 && !(result.status === 1 && !result.stdout?.trim())) {
41273
+ throw new Error(`lsof could not inspect database holders: ${result.error?.message ?? result.stderr ?? result.status}`);
41274
+ }
41275
+ const opened = result.stdout.split(`
41276
+ `).filter((line) => line.startsWith("n"));
41277
+ if (opened.length)
41278
+ throw new Error(`database holder is present: ${opened.map((line) => line.slice(1)).join(", ")}`);
41279
+ if (result.status === 0)
41280
+ throw new Error("lsof returned success without any file evidence");
41281
+ }
41282
+ function assertVerifiedV2Schema(db) {
41283
+ const table = db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all();
41284
+ const names = new Set(table.map((row) => row.name));
41285
+ if (!names.has("session_v2") || !names.has("session_message") || names.has("message") || names.has("part")) {
41286
+ throw new Error("OpenCode store is not the verified OpenCode 2 session_v2 schema");
41287
+ }
41288
+ const fields = db.prepare("PRAGMA table_info('session_v2')").all();
41289
+ if (!fields.some((field) => field.name === "id" && field.pk === 1) || !fields.some((field) => field.name === "metadata") || !fields.some((field) => field.name === "directory")) {
41290
+ throw new Error("OpenCode session_v2 columns differ from the verified schema");
41291
+ }
41292
+ const dependents = table.flatMap(({ name }) => {
41293
+ const foreignKeys = db.prepare(`PRAGMA foreign_key_list('${name.replaceAll("'", "''")}')`).all();
41294
+ return foreignKeys.filter((key) => key.table === "session_v2").map((key) => ({ name, ...key }));
41295
+ });
41296
+ 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")) {
41297
+ throw new Error("OpenCode session_v2 cascade schema differs from the verified 2.0.18 host");
41298
+ }
41299
+ }
41300
+ async function cleanupRetiredHiddenChildren(options) {
41301
+ const { contextDbPath, hostDbPath, fix = false } = options;
41302
+ if (!existsSync39(contextDbPath) || !existsSync39(hostDbPath))
41303
+ return { waiting: 0, deleted: 0 };
41304
+ const context = new Database(contextDbPath, { readonly: true, fileMustExist: true });
41305
+ const host = new Database(hostDbPath, { readonly: true, fileMustExist: true });
41306
+ let states;
41307
+ let candidates;
41308
+ let waiting;
41309
+ try {
41310
+ assertVerifiedV2Schema(host);
41311
+ const rows = context.prepare("SELECT key, value FROM schema_migrations_meta WHERE substr(key, 1, ?) = ?").all(PREFIX.length, PREFIX);
41312
+ states = rows.map(({ key, value }) => {
41313
+ const state = JSON.parse(value);
41314
+ if (state.version !== 1 || !Array.isArray(state.retired_children) || state.retired_children.some((child) => typeof child.id !== "string")) {
41315
+ throw new Error(`Invalid hidden-child state at ${key}`);
41316
+ }
41317
+ return { key, state };
41318
+ });
41319
+ const ids = [
41320
+ ...new Set(states.flatMap(({ state }) => state.retired_children.map((child) => child.id)))
41321
+ ];
41322
+ waiting = ids.length;
41323
+ candidates = ids.filter((id) => {
41324
+ const row = host.prepare("SELECT metadata FROM session_v2 WHERE id = ?").get(id);
41325
+ if (!row)
41326
+ return false;
41327
+ let marker;
41328
+ try {
41329
+ marker = JSON.parse(row.metadata ?? "null");
41330
+ } catch {
41331
+ return false;
41332
+ }
41333
+ return marker?.magic_context === "hidden-run";
41334
+ });
41335
+ } finally {
41336
+ context.close();
41337
+ host.close();
41338
+ }
41339
+ options.report?.(`${waiting} retired hidden sessions are waiting for deletion${fix ? "" : "; run `doctor --fix` with OpenCode closed"}`);
41340
+ if (!fix || candidates.length === 0)
41341
+ return { waiting, deleted: 0 };
41342
+ const inspect = options.inspectHolders ?? ((context, host) => assertHiddenChildStoresClosed(context, host, options.platform, options.processProbe));
41343
+ await inspect(contextDbPath, hostDbPath);
41344
+ const backup = `${hostDbPath}.hidden-child-backup-${new Date().toISOString().replace(/[:.]/g, "-")}-${process.pid}`;
41345
+ copyDatabaseBundle(hostDbPath, backup);
41346
+ options.report?.(`OpenCode store backup: ${backup}`);
41347
+ await inspect(contextDbPath, hostDbPath);
41348
+ const writableHost = new Database(hostDbPath);
41349
+ let writableContext;
41350
+ const deletedIds = [];
41351
+ let hostLocked = false;
41352
+ let contextLocked = false;
41353
+ try {
41354
+ writableHost.exec("PRAGMA busy_timeout = 250");
41355
+ writableHost.exec("PRAGMA foreign_keys = ON");
41356
+ writableContext = new Database(contextDbPath);
41357
+ writableContext.exec("PRAGMA busy_timeout = 250");
41358
+ try {
41359
+ writableHost.exec("BEGIN EXCLUSIVE");
41360
+ hostLocked = true;
41361
+ writableContext.exec("BEGIN EXCLUSIVE");
41362
+ contextLocked = true;
41363
+ } catch (error) {
41364
+ throw new Error(`Cannot acquire exclusive locks on ${hostDbPath} and ${contextDbPath}: ${error instanceof Error ? error.message : String(error)}`);
41365
+ }
41366
+ assertVerifiedV2Schema(writableHost);
41367
+ for (const id of candidates) {
41368
+ const result = writableHost.prepare("DELETE FROM session_v2 WHERE id = ? AND json_valid(metadata) AND json_extract(metadata, '$.magic_context') = 'hidden-run'").run(id);
41369
+ if (result.changes > 0)
41370
+ deletedIds.push(id);
41371
+ }
41372
+ for (const { key } of states) {
41373
+ const current = writableContext.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(key);
41374
+ if (!current)
41375
+ throw new Error(`Hidden-child state ${key} disappeared during repair`);
41376
+ const state = JSON.parse(current.value);
41377
+ if (state.version !== 1 || !Array.isArray(state.retired_children)) {
41378
+ throw new Error(`Hidden-child state ${key} changed during repair`);
41379
+ }
41380
+ state.retired_children = state.retired_children.filter((child) => !deletedIds.includes(child.id));
41381
+ writableContext.prepare("UPDATE schema_migrations_meta SET value = ? WHERE key = ?").run(JSON.stringify(state), key);
41382
+ }
41383
+ writableHost.exec("COMMIT");
41384
+ hostLocked = false;
41385
+ writableContext.exec("COMMIT");
41386
+ contextLocked = false;
41387
+ } finally {
41388
+ if (contextLocked)
41389
+ writableContext?.exec("ROLLBACK");
41390
+ if (hostLocked)
41391
+ writableHost.exec("ROLLBACK");
41392
+ writableContext?.close();
41393
+ writableHost.close();
41394
+ }
41395
+ options.report?.(`Deleted ${deletedIds.length} marked, recorded hidden sessions`);
41396
+ return { waiting, deleted: deletedIds.length, backup };
41397
+ }
41398
+ var PREFIX = "opencode2_hidden_children:", CASCADE_TABLES;
41399
+ var init_doctor_hidden_children = __esm(async () => {
41400
+ init_rpc_utils();
41401
+ await __promiseAll([
41402
+ init_sqlite(),
41403
+ init_doctor_repair_db()
41404
+ ]);
41405
+ CASCADE_TABLES = [
41406
+ "instruction_entry",
41407
+ "instruction_state",
41408
+ "session_inbox",
41409
+ "session_message",
41410
+ "session_pending"
41411
+ ];
41412
+ });
41413
+
40621
41414
  // src/commands/doctor-opencode-plugin-duplicates.ts
40622
41415
  import { isDeepStrictEqual } from "node:util";
40623
41416
  function entryOptions(entry) {
@@ -40844,11 +41637,11 @@ function formatUnresolvedCompartmentSession(session) {
40844
41637
  }
40845
41638
 
40846
41639
  // 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";
41640
+ import { spawnSync as spawnSync9 } from "node:child_process";
41641
+ import { existsSync as existsSync40, mkdtempSync as mkdtempSync2, readFileSync as readFileSync28, rmSync as rmSync5 } from "node:fs";
40849
41642
  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";
41643
+ import { homedir as homedir17, tmpdir as tmpdir3 } from "node:os";
41644
+ import { join as join33 } from "node:path";
40852
41645
  function formatSharedDbRowCounts(db) {
40853
41646
  return SHARED_DB_ROW_COUNT_TABLES.map((table) => {
40854
41647
  try {
@@ -40879,7 +41672,8 @@ function findUnknownConfiguredModels(configured, catalog) {
40879
41672
  return [];
40880
41673
  });
40881
41674
  }
40882
- function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args, cwd) => spawnSync8("opencode", args, {
41675
+ function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args, cwd) => spawnSync9("opencode", args, {
41676
+ windowsHide: true,
40883
41677
  cwd,
40884
41678
  encoding: "utf8",
40885
41679
  timeout: hostGeneration === "v2" ? 90000 : 45000,
@@ -40916,7 +41710,7 @@ function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args
40916
41710
  }
40917
41711
  if (models.length === 0)
40918
41712
  return;
40919
- const tempRoot = mkdtempSync(join32(tmpdir3(), "magic-context-opencode-catalog-"));
41713
+ const tempRoot = mkdtempSync2(join33(tmpdir3(), "magic-context-opencode-catalog-"));
40920
41714
  try {
40921
41715
  const command = hostGeneration === "v2" ? ["api", "model.list", "--param", `directory=${projectDir}`] : ["models", "--verbose"];
40922
41716
  const guidance = `opencode ${command.join(" ")}`;
@@ -41092,7 +41886,7 @@ function getSelfVersion2() {
41092
41886
  function describeAutoUpdateStall(specifier, autoUpdateEnabled, storageDir = getMagicContextStorageDir()) {
41093
41887
  if (!autoUpdateEnabled || !isPinnedOpenCodePluginSpecifier(specifier))
41094
41888
  return null;
41095
- const state = readAutoUpdateCheckState(join32(storageDir, AUTO_UPDATE_CHECK_STATE_FILENAME));
41889
+ const state = readAutoUpdateCheckState(join33(storageDir, AUTO_UPDATE_CHECK_STATE_FILENAME));
41096
41890
  const owner = isUpdaterPinnedSpec(state, specifier) ? "updater" : "you";
41097
41891
  return `auto-update: stalled — config pinned to ${specifier} (by ${owner})`;
41098
41892
  }
@@ -41101,15 +41895,15 @@ function getUserNpmrcPath() {
41101
41895
  if (custom)
41102
41896
  return custom;
41103
41897
  const home = process.env.HOME?.trim();
41104
- return join32(home || homedir16(), ".npmrc");
41898
+ return join33(home || homedir17(), ".npmrc");
41105
41899
  }
41106
41900
  function collectNpmReleaseAgeWarnings() {
41107
41901
  const ageWarnings = [];
41108
41902
  const npmrcPath = getUserNpmrcPath();
41109
- if (!existsSync38(npmrcPath))
41903
+ if (!existsSync40(npmrcPath))
41110
41904
  return ageWarnings;
41111
41905
  try {
41112
- const npmrc = readFileSync26(npmrcPath, "utf-8");
41906
+ const npmrc = readFileSync28(npmrcPath, "utf-8");
41113
41907
  for (const line of npmrc.split(`
41114
41908
  `)) {
41115
41909
  const trimmed = line.trim();
@@ -41142,15 +41936,18 @@ function compareVersions(a, b) {
41142
41936
  function openBrowser(url) {
41143
41937
  try {
41144
41938
  if (process.platform === "darwin") {
41145
- const child = spawnSync8("open", [url], { stdio: "ignore" });
41939
+ const child = spawnSync9("open", [url], { windowsHide: true, stdio: "ignore" });
41146
41940
  if (child.status === 0)
41147
41941
  return;
41148
41942
  } else if (process.platform === "linux") {
41149
- const child = spawnSync8("xdg-open", [url], { stdio: "ignore" });
41943
+ const child = spawnSync9("xdg-open", [url], { windowsHide: true, stdio: "ignore" });
41150
41944
  if (child.status === 0)
41151
41945
  return;
41152
41946
  } else if (process.platform === "win32") {
41153
- const child = spawnSync8("cmd", ["/c", "start", "", url], { stdio: "ignore" });
41947
+ const child = spawnSync9("cmd", ["/c", "start", "", url], {
41948
+ windowsHide: true,
41949
+ stdio: "ignore"
41950
+ });
41154
41951
  if (child.status === 0)
41155
41952
  return;
41156
41953
  }
@@ -41243,7 +42040,7 @@ function checkLocalEmbeddingRuntimeForDoctor(runtimePreference = "auto") {
41243
42040
  return { issues: 0 };
41244
42041
  }
41245
42042
  async function checkEmbeddingConfig(magicContextConfigPath) {
41246
- if (!existsSync38(magicContextConfigPath)) {
42043
+ if (!existsSync40(magicContextConfigPath)) {
41247
42044
  return checkLocalEmbeddingRuntimeForDoctor();
41248
42045
  }
41249
42046
  let rawText;
@@ -41400,7 +42197,7 @@ async function runDoctor2(options = {}) {
41400
42197
  const v22Result = await runV22BackfillCommands({
41401
42198
  name: "OpenCode",
41402
42199
  openDatabase: (readonly = true) => {
41403
- const dbPath = join32(getMagicContextStorageDir(), "context.db");
42200
+ const dbPath = join33(getMagicContextStorageDir(), "context.db");
41404
42201
  v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
41405
42202
  return v22Db;
41406
42203
  },
@@ -41432,7 +42229,7 @@ async function runDoctor2(options = {}) {
41432
42229
  failCount++;
41433
42230
  issues++;
41434
42231
  };
41435
- const authorityDbPath = join32(getMagicContextStorageDir(), "context.db");
42232
+ const authorityDbPath = join33(getMagicContextStorageDir(), "context.db");
41436
42233
  let authorityDb = null;
41437
42234
  try {
41438
42235
  authorityDb = openExistingContextDatabase(authorityDbPath, { readonly: true });
@@ -41486,6 +42283,19 @@ async function runDoctor2(options = {}) {
41486
42283
  else
41487
42284
  fail(openCodeDbCheck.message);
41488
42285
  if (openCodeDbCheck.ok) {
42286
+ if (storeGeneration === "v2") {
42287
+ try {
42288
+ const cleanup = await cleanupRetiredHiddenChildren({
42289
+ contextDbPath: authorityDbPath,
42290
+ hostDbPath: openCodeDbResolution.path,
42291
+ fix: options.fix,
42292
+ report: (line) => log2.info(line)
42293
+ });
42294
+ fixed += cleanup.deleted;
42295
+ } catch (error) {
42296
+ fail(`Retired hidden-child cleanup refused: ${error instanceof Error ? error.message : String(error)}`);
42297
+ }
42298
+ }
41489
42299
  let markerDb = null;
41490
42300
  try {
41491
42301
  markerDb = new Database(openCodeDbResolution.path, {
@@ -41593,7 +42403,7 @@ async function runDoctor2(options = {}) {
41593
42403
  pass(`OpenCode config: ${paths.opencodeConfig}`);
41594
42404
  }
41595
42405
  let autoUpdateEnabled = true;
41596
- if (existsSync38(paths.magicContextConfig)) {
42406
+ if (existsSync40(paths.magicContextConfig)) {
41597
42407
  pass(`Magic Context config: ${paths.magicContextConfig}`);
41598
42408
  try {
41599
42409
  const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
@@ -41629,7 +42439,7 @@ async function runDoctor2(options = {}) {
41629
42439
  warn(`No magic-context.jsonc found — using defaults`);
41630
42440
  log2.info(" Run 'setup' to create one with model recommendations");
41631
42441
  }
41632
- if (existsSync38(paths.magicContextConfig)) {
42442
+ if (existsSync40(paths.magicContextConfig)) {
41633
42443
  try {
41634
42444
  const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
41635
42445
  if (!raw)
@@ -41759,7 +42569,7 @@ async function runDoctor2(options = {}) {
41759
42569
  };
41760
42570
  if (paths.opencodeConfigFormat !== "none") {
41761
42571
  try {
41762
- const raw = readFileSync26(paths.opencodeConfig, "utf-8");
42572
+ const raw = readFileSync28(paths.opencodeConfig, "utf-8");
41763
42573
  const config = import_comment_json11.parse(raw);
41764
42574
  const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
41765
42575
  if (checkPluginDuplicates(config, configName, options, {
@@ -41828,9 +42638,9 @@ async function runDoctor2(options = {}) {
41828
42638
  pass("Added TUI sidebar plugin to tui.json");
41829
42639
  warn("Restart OpenCode to see the sidebar");
41830
42640
  fixed++;
41831
- } else if (existsSync38(paths.tuiConfig)) {
42641
+ } else if (existsSync40(paths.tuiConfig)) {
41832
42642
  try {
41833
- const tuiRaw = readFileSync26(paths.tuiConfig, "utf-8");
42643
+ const tuiRaw = readFileSync28(paths.tuiConfig, "utf-8");
41834
42644
  const tuiConfig = import_comment_json11.parse(tuiRaw);
41835
42645
  const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
41836
42646
  const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
@@ -41868,7 +42678,7 @@ async function runDoctor2(options = {}) {
41868
42678
  fail("Could not create or verify the TUI sidebar config");
41869
42679
  }
41870
42680
  }
41871
- if (existsSync38(paths.magicContextConfig)) {
42681
+ if (existsSync40(paths.magicContextConfig)) {
41872
42682
  try {
41873
42683
  const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
41874
42684
  if (!raw)
@@ -41890,9 +42700,9 @@ async function runDoctor2(options = {}) {
41890
42700
  else
41891
42701
  passCount++;
41892
42702
  const storage = getMagicContextStorageResolution();
41893
- const dbPath = join32(storage.path, "context.db");
42703
+ const dbPath = join33(storage.path, "context.db");
41894
42704
  log2.info(`Shared storage: ${storage.path} (source: ${storage.source})`);
41895
- if (!existsSync38(dbPath)) {
42705
+ if (!existsSync40(dbPath)) {
41896
42706
  log2.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
41897
42707
  } else {
41898
42708
  log2.info(`Shared context DB exists at ${dbPath}`);
@@ -41994,7 +42804,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
41994
42804
  let v2DistTag;
41995
42805
  if (paths.opencodeConfigFormat !== "none") {
41996
42806
  try {
41997
- v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(readFileSync26(paths.opencodeConfig, "utf-8")));
42807
+ v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8")));
41998
42808
  } catch {}
41999
42809
  }
42000
42810
  const v2Cache = reportOpenCodeV2PluginCache(checkOpenCodeV2PluginCache({
@@ -42121,16 +42931,17 @@ var init_doctor_opencode = __esm(async () => {
42121
42931
  init_v22_backfill_commands(),
42122
42932
  init_doctor_authority(),
42123
42933
  init_doctor_cached_plugin_fence(),
42124
- init_doctor_harness_relabel()
42934
+ init_doctor_harness_relabel(),
42935
+ init_doctor_hidden_children()
42125
42936
  ]);
42126
42937
  import_comment_json11 = __toESM(require_src3(), 1);
42127
42938
  SHARED_DB_ROW_COUNT_TABLES = ["tags", "compartments", "memories", "notes", "dream_runs"];
42128
42939
  });
42129
42940
 
42130
42941
  // src/lib/diagnostics-pi.ts
42131
- import { existsSync as existsSync39, readdirSync as readdirSync7, readFileSync as readFileSync27, statSync as statSync16 } from "node:fs";
42942
+ import { existsSync as existsSync41, readdirSync as readdirSync8, readFileSync as readFileSync29, statSync as statSync16 } from "node:fs";
42132
42943
  import { createRequire as createRequire7 } from "node:module";
42133
- import { join as join33 } from "node:path";
42944
+ import { join as join34 } from "node:path";
42134
42945
  function getSelfVersion3() {
42135
42946
  const req = createRequire7(import.meta.url);
42136
42947
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -42145,7 +42956,7 @@ function getSelfVersion3() {
42145
42956
  }
42146
42957
  function fileSize2(path) {
42147
42958
  try {
42148
- return existsSync39(path) ? statSync16(path).size : 0;
42959
+ return existsSync41(path) ? statSync16(path).size : 0;
42149
42960
  } catch {
42150
42961
  return 0;
42151
42962
  }
@@ -42157,11 +42968,11 @@ function sanitizeValue2(value) {
42157
42968
  return sanitizeConfigValue(value);
42158
42969
  }
42159
42970
  function readJsonc(path) {
42160
- if (!existsSync39(path))
42971
+ if (!existsSync41(path))
42161
42972
  return { value: {} };
42162
42973
  try {
42163
42974
  return {
42164
- value: import_comment_json12.parse(readFileSync27(path, "utf-8"))
42975
+ value: import_comment_json12.parse(readFileSync29(path, "utf-8"))
42165
42976
  };
42166
42977
  } catch (error) {
42167
42978
  return {
@@ -42177,7 +42988,7 @@ function readConfigDiagnostic(path) {
42177
42988
  const parsed = readJsonc(path);
42178
42989
  return {
42179
42990
  path,
42180
- exists: existsSync39(path),
42991
+ exists: existsSync41(path),
42181
42992
  ...parsed.parseError ? { parseError: parsed.parseError } : {},
42182
42993
  flags: sanitizeValue2(parsed.value)
42183
42994
  };
@@ -42195,25 +43006,25 @@ function reverseSlugToDirectory(slug) {
42195
43006
  }
42196
43007
  function collectPiRecentSessions() {
42197
43008
  const sessionsRoot = getPiSessionsRoot();
42198
- if (!existsSync39(sessionsRoot))
43009
+ if (!existsSync41(sessionsRoot))
42199
43010
  return [];
42200
43011
  try {
42201
- const slugs = readdirSync7(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
43012
+ const slugs = readdirSync8(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
42202
43013
  const candidates = [];
42203
43014
  for (const slug of slugs) {
42204
43015
  const directory = reverseSlugToDirectory(slug);
42205
43016
  if (!directory)
42206
43017
  continue;
42207
- const slugDir = join33(sessionsRoot, slug);
43018
+ const slugDir = join34(sessionsRoot, slug);
42208
43019
  let files;
42209
43020
  try {
42210
- files = readdirSync7(slugDir).filter((name) => name.endsWith(".jsonl"));
43021
+ files = readdirSync8(slugDir).filter((name) => name.endsWith(".jsonl"));
42211
43022
  } catch {
42212
43023
  continue;
42213
43024
  }
42214
43025
  for (const file of files) {
42215
43026
  try {
42216
- const mtime = statSync16(join33(slugDir, file)).mtimeMs;
43027
+ const mtime = statSync16(join34(slugDir, file)).mtimeMs;
42217
43028
  const sessionId = file.replace(/\.jsonl$/, "");
42218
43029
  candidates.push({ sessionId, directory, mtime });
42219
43030
  } catch {}
@@ -42231,7 +43042,7 @@ function collectPiRecentSessions() {
42231
43042
  }
42232
43043
  function parseHistorianDumpMeta2(path) {
42233
43044
  try {
42234
- const xml = readFileSync27(path, "utf-8");
43045
+ const xml = readFileSync29(path, "utf-8");
42235
43046
  const parsed = parseCompartmentOutput(xml);
42236
43047
  const factCountByCategory = {};
42237
43048
  for (const fact of parsed.facts) {
@@ -42264,11 +43075,11 @@ function parseHistorianDumpMeta2(path) {
42264
43075
  }
42265
43076
  }
42266
43077
  function listDumpsInDir2(dir, limit) {
42267
- if (!existsSync39(dir))
43078
+ if (!existsSync41(dir))
42268
43079
  return { count: 0, recent: [] };
42269
43080
  try {
42270
- const entries = readdirSync7(dir).filter((name) => name.endsWith(".xml")).map((name) => {
42271
- const stat = statSync16(join33(dir, name));
43081
+ const entries = readdirSync8(dir).filter((name) => name.endsWith(".xml")).map((name) => {
43082
+ const stat = statSync16(join34(dir, name));
42272
43083
  return {
42273
43084
  name,
42274
43085
  mtime: stat.mtimeMs,
@@ -42277,7 +43088,7 @@ function listDumpsInDir2(dir, limit) {
42277
43088
  }).sort((a, b) => b.mtime - a.mtime);
42278
43089
  const now = Date.now();
42279
43090
  const recent = entries.slice(0, limit).map((entry) => {
42280
- const meta = parseHistorianDumpMeta2(join33(dir, entry.name));
43091
+ const meta = parseHistorianDumpMeta2(join34(dir, entry.name));
42281
43092
  const summary = {
42282
43093
  name: entry.name,
42283
43094
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -42341,7 +43152,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
42341
43152
  const loaded = loadPiConfig({ cwd });
42342
43153
  const storageResolution = getMagicContextStorageResolution();
42343
43154
  const storageDirPath = storageResolution.path;
42344
- const dbPath = join33(storageDirPath, "context.db");
43155
+ const dbPath = join34(storageDirPath, "context.db");
42345
43156
  const logFiles = inspectMagicContextLogs("pi");
42346
43157
  const primaryLog = logFiles.find((file) => file.exists) ?? logFiles[0];
42347
43158
  const otherPiExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
@@ -42358,7 +43169,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
42358
43169
  piVersion: pi ? getPiVersion(pi.path) : null,
42359
43170
  settings: {
42360
43171
  path: settingsPath,
42361
- exists: existsSync39(settingsPath),
43172
+ exists: existsSync41(settingsPath),
42362
43173
  ...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
42363
43174
  hasMagicContextPackage: hasPiMagicContextPackage(packages),
42364
43175
  packages: sanitizeValue2(packages)
@@ -42375,7 +43186,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
42375
43186
  storageDir: {
42376
43187
  path: storageDirPath,
42377
43188
  source: storageResolution.source,
42378
- exists: existsSync39(storageDirPath),
43189
+ exists: existsSync41(storageDirPath),
42379
43190
  contextDbSizeBytes: fileSize2(dbPath)
42380
43191
  },
42381
43192
  conflicts: {
@@ -42480,8 +43291,8 @@ var init_diagnostics_pi = __esm(() => {
42480
43291
  });
42481
43292
 
42482
43293
  // 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";
43294
+ import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
43295
+ import { dirname as dirname21, join as join35 } from "node:path";
42485
43296
  function sanitizeLogContent2(content) {
42486
43297
  return sanitizeString2(content);
42487
43298
  }
@@ -42551,13 +43362,13 @@ async function bundleIssueReport2(report, description, title, options = {}) {
42551
43362
  const truncated = bodyMarkdown !== rawBodyMarkdown;
42552
43363
  const cwd = options.cwd ?? process.cwd();
42553
43364
  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}
43365
+ const path = options.outputPath ?? join35(cwd, `magic-context-pi-issue-${timestamp}.md`);
43366
+ mkdirSync12(dirname21(path), { recursive: true });
43367
+ writeFileSync11(path, `${bodyMarkdown}
42557
43368
  `);
42558
- const fullPath = truncated ? options.outputPath ? `${options.outputPath}.full.md` : join34(cwd, `magic-context-pi-issue-${timestamp}-full.md`) : undefined;
43369
+ const fullPath = truncated ? options.outputPath ? `${options.outputPath}.full.md` : join35(cwd, `magic-context-pi-issue-${timestamp}-full.md`) : undefined;
42559
43370
  if (fullPath)
42560
- writeFileSync9(fullPath, `${rawBodyMarkdown}
43371
+ writeFileSync11(fullPath, `${rawBodyMarkdown}
42561
43372
  `);
42562
43373
  return { path, bodyMarkdown, ...fullPath ? { fullPath } : {}, truncated };
42563
43374
  }
@@ -42568,11 +43379,11 @@ var init_logs_pi = __esm(() => {
42568
43379
  });
42569
43380
 
42570
43381
  // 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";
43382
+ import { execFileSync as execFileSync7, spawnSync as spawnSync10 } from "node:child_process";
43383
+ import { existsSync as existsSync42, mkdirSync as mkdirSync13, readdirSync as readdirSync9, readFileSync as readFileSync30, rmSync as rmSync6, statSync as statSync17 } from "node:fs";
42573
43384
  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";
43385
+ import { homedir as homedir18 } from "node:os";
43386
+ import { dirname as dirname22, isAbsolute as isAbsolute8, join as join36 } from "node:path";
42576
43387
  function depsFrom(options) {
42577
43388
  return {
42578
43389
  ...DEFAULT_DEPS5,
@@ -42609,7 +43420,8 @@ function selfVersion2() {
42609
43420
  }
42610
43421
  function getLatestNpmVersion(packageName) {
42611
43422
  try {
42612
- return execFileSync6("npm", ["view", packageName, "version"], {
43423
+ return execFileSync7("npm", ["view", packageName, "version"], {
43424
+ windowsHide: true,
42613
43425
  encoding: "utf-8",
42614
43426
  stdio: ["ignore", "pipe", "ignore"],
42615
43427
  timeout: 1e4
@@ -42663,7 +43475,7 @@ function summarize(results) {
42663
43475
  function readJsonc2(path) {
42664
43476
  try {
42665
43477
  return {
42666
- value: import_comment_json13.parse(readFileSync28(path, "utf-8"))
43478
+ value: import_comment_json13.parse(readFileSync30(path, "utf-8"))
42667
43479
  };
42668
43480
  } catch (error) {
42669
43481
  return {
@@ -42713,15 +43525,15 @@ function piPluginDirCandidates(packages, cwd) {
42713
43525
  if (resolved)
42714
43526
  dirs.push(resolved);
42715
43527
  }
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")));
43528
+ dirs.push(join36(agentDir, "npm", "node_modules", PACKAGE_NAME2));
43529
+ dirs.push(join36(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2));
43530
+ return dirs.filter((dir) => existsSync42(join36(dir, "package.json")));
42719
43531
  }
42720
43532
  function projectConfigPath(cwd) {
42721
43533
  return resolveCortexKitProjectConfigPath(cwd);
42722
43534
  }
42723
43535
  function readConfigForEmbedding(path, isProjectConfig) {
42724
- if (!existsSync40(path))
43536
+ if (!existsSync42(path))
42725
43537
  return null;
42726
43538
  try {
42727
43539
  const raw = loadRawConfigFile({
@@ -42807,22 +43619,22 @@ function pinnedVersionFromPackageSpecifier(specifier) {
42807
43619
  }
42808
43620
  function cacheRoots(cwd) {
42809
43621
  const home = process.env.HOME?.trim();
42810
- const cacheHome = process.env.XDG_CACHE_HOME || join35(home || homedir17(), ".cache");
43622
+ const cacheHome = process.env.XDG_CACHE_HOME || join36(home || homedir18(), ".cache");
42811
43623
  const piCacheRoot = getPiCacheRoot();
42812
43624
  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)
43625
+ join36(piCacheRoot, "extensions"),
43626
+ join36(piCacheRoot, "packages"),
43627
+ join36(cacheHome, "pi", "extensions"),
43628
+ join36(cacheHome, "pi", "packages"),
43629
+ join36(getPiAgentConfigDir(), "cache", "extensions"),
43630
+ join36(getPiAgentConfigDir(), "npm", "node_modules", PACKAGE_NAME2),
43631
+ join36(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2)
42820
43632
  ];
42821
43633
  }
42822
43634
  function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
42823
43635
  const found = new Map;
42824
43636
  const visit = (path, depth) => {
42825
- if (depth < 0 || !existsSync40(path))
43637
+ if (depth < 0 || !existsSync42(path))
42826
43638
  return;
42827
43639
  let stat;
42828
43640
  try {
@@ -42832,10 +43644,10 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
42832
43644
  }
42833
43645
  if (!stat.isDirectory())
42834
43646
  return;
42835
- const packageJson = join35(path, "package.json");
42836
- if (existsSync40(packageJson)) {
43647
+ const packageJson = join36(path, "package.json");
43648
+ if (existsSync42(packageJson)) {
42837
43649
  try {
42838
- const pkg = JSON.parse(readFileSync28(packageJson, "utf-8"));
43650
+ const pkg = JSON.parse(readFileSync30(packageJson, "utf-8"));
42839
43651
  const name = typeof pkg.name === "string" ? pkg.name : "";
42840
43652
  const version = typeof pkg.version === "string" ? pkg.version : undefined;
42841
43653
  if (name === PACKAGE_NAME2) {
@@ -42850,12 +43662,12 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
42850
43662
  }
42851
43663
  let entries = [];
42852
43664
  try {
42853
- entries = readdirSync8(path);
43665
+ entries = readdirSync9(path);
42854
43666
  } catch {
42855
43667
  return;
42856
43668
  }
42857
43669
  for (const entry of entries)
42858
- visit(join35(path, entry), depth - 1);
43670
+ visit(join36(path, entry), depth - 1);
42859
43671
  };
42860
43672
  for (const root of cacheRoots(cwd))
42861
43673
  visit(root, 5);
@@ -42900,7 +43712,7 @@ async function runHealthChecks2(options) {
42900
43712
  }
42901
43713
  const settingsPath = getPiUserExtensionsPath();
42902
43714
  let packages = [];
42903
- if (!existsSync40(settingsPath)) {
43715
+ if (!existsSync42(settingsPath)) {
42904
43716
  add2(results, "fail", `Pi settings not found at ${settingsPath}`);
42905
43717
  repairPlan.addPackageEntry = true;
42906
43718
  } else {
@@ -42924,7 +43736,7 @@ async function runHealthChecks2(options) {
42924
43736
  ["user", userConfigPath, true],
42925
43737
  ["project", projectPath, false]
42926
43738
  ]) {
42927
- if (!existsSync40(path)) {
43739
+ if (!existsSync42(path)) {
42928
43740
  if (required) {
42929
43741
  add2(results, "warn", `No ${label} magic-context.jsonc found at ${path}`);
42930
43742
  if (userConfigMigrationRefused) {
@@ -42964,9 +43776,9 @@ async function runHealthChecks2(options) {
42964
43776
  }
42965
43777
  const storage = getMagicContextStorageResolution();
42966
43778
  const storageDir = storage.path;
42967
- const dbPath = join35(storageDir, "context.db");
43779
+ const dbPath = join36(storageDir, "context.db");
42968
43780
  add2(results, "info", `Shared storage: ${storageDir} (source: ${storage.source})`);
42969
- const existedBeforeOpen = existsSync40(dbPath);
43781
+ const existedBeforeOpen = existsSync42(dbPath);
42970
43782
  if (existedBeforeOpen)
42971
43783
  add2(results, "pass", `Shared context DB exists at ${dbPath}`);
42972
43784
  else
@@ -43184,7 +43996,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
43184
43996
  return { results, repairPlan, ...summarize(results) };
43185
43997
  }
43186
43998
  function writeDefaultMagicContextConfig(path) {
43187
- mkdirSync11(dirname20(path), { recursive: true });
43999
+ mkdirSync13(dirname22(path), { recursive: true });
43188
44000
  const config = {
43189
44001
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
43190
44002
  ...MagicContextConfigSchema.parse({})
@@ -43206,7 +44018,7 @@ function repair2(plan, prompts) {
43206
44018
  }
43207
44019
  if (plan.writeUserConfig) {
43208
44020
  const configPath = getPiUserConfigPath();
43209
- if (!existsSync40(configPath)) {
44021
+ if (!existsSync42(configPath)) {
43210
44022
  try {
43211
44023
  writeDefaultMagicContextConfig(configPath);
43212
44024
  prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
@@ -43230,6 +44042,7 @@ function repair2(plan, prompts) {
43230
44042
  function runGhCommandWithDeps2(deps, args) {
43231
44043
  if (args[0] === "issue") {
43232
44044
  const result = deps.spawnSync("gh", args, {
44045
+ windowsHide: true,
43233
44046
  encoding: "utf-8",
43234
44047
  stdio: ["ignore", "pipe", "pipe"]
43235
44048
  });
@@ -43241,6 +44054,7 @@ function runGhCommandWithDeps2(deps, args) {
43241
44054
  }
43242
44055
  try {
43243
44056
  const output = deps.execFileSync("gh", args, {
44057
+ windowsHide: true,
43244
44058
  encoding: "utf-8",
43245
44059
  stdio: ["ignore", "pipe", "pipe"]
43246
44060
  });
@@ -43258,7 +44072,7 @@ async function runIssueFlow3(options) {
43258
44072
  if (options.reportPath) {
43259
44073
  try {
43260
44074
  const report = await options.deps.collectDiagnostics(options.cwd);
43261
- const outputPath = isAbsolute8(options.reportPath) ? options.reportPath : join35(options.cwd, options.reportPath);
44075
+ const outputPath = isAbsolute8(options.reportPath) ? options.reportPath : join36(options.cwd, options.reportPath);
43262
44076
  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
44077
  options.prompts.log.info(`Report written to ${bundled.path}`);
43264
44078
  return 0;
@@ -43342,7 +44156,7 @@ async function runDoctor3(options = {}) {
43342
44156
  const v22Result = await runV22BackfillCommands({
43343
44157
  name: "Pi",
43344
44158
  openDatabase: (readonly = true) => {
43345
- const dbPath = join35(getMagicContextStorageDir(), "context.db");
44159
+ const dbPath = join36(getMagicContextStorageDir(), "context.db");
43346
44160
  v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
43347
44161
  return v22Db;
43348
44162
  },
@@ -43384,7 +44198,7 @@ async function runDoctor3(options = {}) {
43384
44198
  prompts.outro(first.fail > 0 ? "Doctor found failures" : "Doctor complete");
43385
44199
  return first.fail > 0 ? 1 : 0;
43386
44200
  }
43387
- function valueAfter3(args, flag) {
44201
+ function valueAfter2(args, flag) {
43388
44202
  const index = args.indexOf(flag);
43389
44203
  if (index === -1)
43390
44204
  return null;
@@ -43394,8 +44208,8 @@ function valueAfter3(args, flag) {
43394
44208
  return next;
43395
44209
  }
43396
44210
  function parseDoctorArgs(args) {
43397
- const rekeyV22DirIdentity = valueAfter3(args, "--rekey-v22-dir-identity");
43398
- const report = valueAfter3(args, "--report");
44211
+ const rekeyV22DirIdentity = valueAfter2(args, "--rekey-v22-dir-identity");
44212
+ const report = valueAfter2(args, "--report");
43399
44213
  return {
43400
44214
  force: args.includes("--force"),
43401
44215
  issue: args.includes("--issue") || report !== null,
@@ -43452,14 +44266,14 @@ var init_doctor_pi = __esm(async () => {
43452
44266
  probeEmbeddingEndpoint,
43453
44267
  openExistingContextDatabase,
43454
44268
  now: () => new Date,
43455
- execFileSync: execFileSync6,
43456
- spawnSync: spawnSync9
44269
+ execFileSync: execFileSync7,
44270
+ spawnSync: spawnSync10
43457
44271
  };
43458
44272
  });
43459
44273
 
43460
44274
  // src/commands/doctor.ts
43461
- import { existsSync as existsSync41, rmSync as rmSync7 } from "node:fs";
43462
- import { join as join36 } from "node:path";
44275
+ import { existsSync as existsSync43, rmSync as rmSync7 } from "node:fs";
44276
+ import { join as join37 } from "node:path";
43463
44277
  async function runDoctor4(options) {
43464
44278
  if (options.clear)
43465
44279
  return runClear();
@@ -43477,7 +44291,7 @@ async function runDoctor4(options) {
43477
44291
  const result = await runV22BackfillCommands({
43478
44292
  name: "Magic Context",
43479
44293
  openDatabase: (readonly = true) => {
43480
- const dbPath = join36(getMagicContextStorageDir(), "context.db");
44294
+ const dbPath = join37(getMagicContextStorageDir(), "context.db");
43481
44295
  v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
43482
44296
  return v22Db;
43483
44297
  },
@@ -43490,8 +44304,14 @@ async function runDoctor4(options) {
43490
44304
  if (result.handled)
43491
44305
  return result.exitCode;
43492
44306
  }
44307
+ try {
44308
+ for (const line of diagnoseIdentitySplits())
44309
+ log2.warn(line);
44310
+ } catch (error) {
44311
+ log2.warn(`Identity split check unavailable: ${error instanceof Error ? error.message : String(error)}`);
44312
+ }
43493
44313
  await init_migrate();
43494
- const sweepDbPath = join36(getMagicContextStorageDir(), "context.db");
44314
+ const sweepDbPath = join37(getMagicContextStorageDir(), "context.db");
43495
44315
  let sweepDb = null;
43496
44316
  try {
43497
44317
  sweepDb = openExistingContextDatabaseForMutation(sweepDbPath);
@@ -43605,7 +44425,7 @@ async function runClear() {
43605
44425
  failed += 1;
43606
44426
  continue;
43607
44427
  }
43608
- } else if (existsSync41(item.path)) {
44428
+ } else if (existsSync43(item.path)) {
43609
44429
  rmSync7(item.path, { recursive: true, force: true });
43610
44430
  }
43611
44431
  s.stop(`Cleared ${item.path}`);
@@ -43635,6 +44455,7 @@ var init_doctor = __esm(async () => {
43635
44455
  await __promiseAll([
43636
44456
  init_database_access(),
43637
44457
  init_v22_backfill_commands(),
44458
+ init_doctor_identity_splits(),
43638
44459
  init_doctor_omp(),
43639
44460
  init_doctor_opencode(),
43640
44461
  init_doctor_pi()
@@ -43696,7 +44517,7 @@ var DOCTOR_HELP = [
43696
44517
  " drain-authority <project> Drain module memory/note authority back to TypeScript",
43697
44518
  " migrate Migrate an OpenCode session to Pi or OMP JSONL",
43698
44519
  " migrate-session Re-home an OpenCode session to another directory",
43699
- " merge-identity Merge project rows between identities",
44520
+ " merge-identities Preview or explicitly merge split identities",
43700
44521
  " repair-db Back up and salvage a corrupted shared database",
43701
44522
  " list-hidden-sessions List Magic Context OpenCode 2 roots",
43702
44523
  ""
@@ -43712,16 +44533,19 @@ var DRAIN_AUTHORITY_HELP = [
43712
44533
  `);
43713
44534
  var MERGE_IDENTITY_HELP = [
43714
44535
  "",
43715
- " Usage: magic-context doctor merge-identity --from <identity> --to <identity> [--dry-run] [--yes] [--db <path>]",
44536
+ " Usage: magic-context doctor merge-identities [--from <identity> --to <identity>] [--apply] [--force] [--db <path>]",
43716
44537
  "",
43717
44538
  " Merge every project-scoped row from one project identity into another.",
43718
44539
  "",
43719
44540
  " Options:",
43720
44541
  " --from <identity> Identity whose rows are moved",
43721
44542
  " --to <identity> Identity that receives them",
43722
- " --dry-run Report what would change without writing",
43723
- " --yes Confirm the write (required unless --dry-run)",
44543
+ " (no flags) List splits; --from/--to previews without writing",
44544
+ " --apply Confirm the reviewed preview; hosts must be closed",
44545
+ " --force Permit a target not resolving on this machine",
43724
44546
  " --db <path> Use this context.db instead of the shared one",
44547
+ " --host-db <path> Read session directories from this host database",
44548
+ " Legacy alias: doctor merge-identity; --dry-run previews, --yes applies",
43725
44549
  ""
43726
44550
  ].join(`
43727
44551
  `);
@@ -43745,7 +44569,7 @@ function subcommandHelp(argv) {
43745
44569
  const subcommand = rest[0];
43746
44570
  if (subcommand === "drain-authority")
43747
44571
  return DRAIN_AUTHORITY_HELP;
43748
- if (subcommand === "merge-identity")
44572
+ if (subcommand === "merge-identity" || subcommand === "merge-identities")
43749
44573
  return MERGE_IDENTITY_HELP;
43750
44574
  if (subcommand === "list-hidden-sessions")
43751
44575
  return LIST_HIDDEN_SESSIONS_HELP;
@@ -43794,7 +44618,7 @@ function getVersion() {
43794
44618
  }
43795
44619
  return "0.0.0";
43796
44620
  }
43797
- function valueAfter4(args, flag) {
44621
+ function valueAfter3(args, flag) {
43798
44622
  const index = args.indexOf(flag);
43799
44623
  if (index === -1)
43800
44624
  return null;
@@ -43879,7 +44703,7 @@ async function main(argv = process.argv.slice(2)) {
43879
44703
  ]);
43880
44704
  return runDoctorDrainAuthority(projectRoot, join(getMagicContextStorageDir(), "context.db"));
43881
44705
  }
43882
- if (rest[0] === "merge-identity") {
44706
+ if (rest[0] === "merge-identities" || rest[0] === "merge-identity") {
43883
44707
  await init_doctor_merge_identity();
43884
44708
  return runMergeIdentityCli(rest.slice(1));
43885
44709
  }
@@ -43900,8 +44724,8 @@ async function main(argv = process.argv.slice(2)) {
43900
44724
  return runMigrateSessionCli(rest.slice(1));
43901
44725
  }
43902
44726
  await init_doctor();
43903
- const rekeyV22DirIdentity = valueAfter4(rest, "--rekey-v22-dir-identity");
43904
- const report = valueAfter4(rest, "--report");
44727
+ const rekeyV22DirIdentity = valueAfter3(rest, "--rekey-v22-dir-identity");
44728
+ const report = valueAfter3(rest, "--report");
43905
44729
  return runDoctor4({
43906
44730
  force: rest.includes("--force"),
43907
44731
  fix: rest.includes("--fix"),