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