@cortexkit/magic-context 0.44.0 → 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 +1256 -463
- 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).")
|
|
@@ -21541,7 +21652,7 @@ var init_magic_context = __esm(() => {
|
|
|
21541
21652
|
smart_notes: object({
|
|
21542
21653
|
retina_handoff: boolean2().default(false).describe("When true, dreamer skips smart notes whose surface conditions compiled to retina provider configs at authoring time. Default false keeps both paths active until the retina consumer is deployed.")
|
|
21543
21654
|
}).default({ retina_handoff: false }).describe("Smart-note ownership transition controls."),
|
|
21544
|
-
cache_ttl: union([string2(), object({ default: string2() }).catchall(string2())]).default("5m").describe(`How long Magic Context assumes the provider's cached prefix stays valid. This is MC's own deferral gate — it does not change the provider's actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard,
|
|
21655
|
+
cache_ttl: union([string2(), object({ default: string2() }).catchall(string2())]).default("5m").describe(`How long Magic Context assumes the provider's cached prefix stays valid. This is MC's own deferral gate — it does not change the provider's actual cache lifetime. String (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "provider/model": "1h", "provider/*": "never" }); keys resolve most-specific first (exact provider/model, bare model ID, shorter dash-prefixes, then the provider/* wildcard). Explicit per-model entries win; otherwise GPT-5.6 and later (including gpt-6*, through any provider prefix) use a built-in 30m lifetime before the object default or 5m fallback. An unset or global "5m" opts into built-in defaults; any other global string is an explicit policy and wins. Policy is frozen per session, including across restarts; a model switch resolves against that frozen policy. /ctx-status shows the effective value and source. OpenAI documents at least 30 minutes since the latest write or reuse: https://developers.openai.com/api/docs/guides/prompt-caching (Cache lifetime and Summary of model differences). Set to "never" to mean MC never assumes expiry (for lanes kept warm externally by a cache-keep tool) — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time. Provider-side extended TTL is a separate request-level concern (cache_control: { ttl } in the request body).`),
|
|
21545
21656
|
prompt_surface: PromptSurfaceConfigSchema.default({ default: "full" }).describe("Prompt-surface presets: default is full; models use bare model IDs, provider/model, or provider/* routing keys. Guidance and tool-description overrides are user-level only. OpenCode 1.x, Pi, and OMP register tool descriptions once per process (they follow the default preset). OpenCode 2 rewrites the five ctx_* descriptions per request from the draft model."),
|
|
21546
21657
|
output_reserve: union([
|
|
21547
21658
|
number2().min(0),
|
|
@@ -21600,9 +21711,9 @@ var init_magic_context = __esm(() => {
|
|
|
21600
21711
|
enabled: boolean2().default(true).describe("When false, Magic Context stops managing the context window and keeps its knowledge layer: memory and docs/user-profile/key-files injection through additive m[0]/m[1], raw-message FTS indexing, dreamer, notes, ctx_search, ctx_expand, ctx_memory, and /ctx-embed remain available. MC's historian/compartment preparation, tagging, markers, pruning, folding, drops, strips, splicing, synthetic context-management todos, temporal markers, nudges, and fail-closed blocking stop; ctx_expand remains a knowledge-surface tool. fail_closed_blocking is inert: a transform failure passes the input messages through without blocking or cancelling. This setting does not enable native compaction: OpenCode's compaction.auto / compaction.prune or Pi's equivalent owns the window, or nothing does. MC's compaction.enabled in magic-context.jsonc is distinct from OpenCode's compaction.auto / compaction.prune in opencode.jsonc; they are different files and different owners. On the first turn after disabling, a long session may trigger one native compaction cycle; MC removes only its own marker boundary, leaves native boundaries and stored compartments intact, and does no pre-trimming mitigation. Marker cleanup is lazy per session, so an unresumed session is cleaned when it is next resumed. If compaction is enabled again, run /ctx-wrapup when the historian is runnable to catch up. OpenCode peer verification against v1.18.4 confirms native compaction covers child sessions: subagents receive additive memory/docs injection and no MC reclaim in this mode, so keep subagent tasks small or leave compaction.enabled on for long subagent runs. This is boot-resolved and requires a process restart; project-tier compaction.enabled is stripped so a cloned repository cannot disable the user's setting. The sidebar reports raw usage as Context: <pct>% · native compaction or Context: <pct>% · no active compaction and does not show an MC execute-threshold fill. /ctx-wrapup, /ctx-recomp, and /ctx-flush refuse without context-management side effects; /ctx-embed remains functional. Raw content hidden by a native boundary before Magic Context's first pass is not retroactively indexed.")
|
|
21601
21712
|
}).default({ enabled: true }).describe("Compaction-off mode gate. Default true (MC manages the context window as today). Set compaction.enabled=false to keep the knowledge layer while letting native compaction (or nothing) own the window. Boot-resolved; requires a restart to change."),
|
|
21602
21713
|
todowrite: object({
|
|
21603
|
-
enabled: boolean2().default(
|
|
21714
|
+
enabled: boolean2().default(false).describe("Pi only: off by default. Set todowrite.enabled=true to register Magic Context's todowrite task-list tool and /todos command. OpenCode ships its own built-in todowrite; this setting has no effect there."),
|
|
21604
21715
|
overlay: boolean2().default(true).describe("Pi only: show the persistent todo overlay above the editor while tasks are active.")
|
|
21605
|
-
}).default({ enabled:
|
|
21716
|
+
}).default({ enabled: false, overlay: true }).describe("Pi-only todowrite tool and overlay controls. Pi registers tools and widgets at extension boot, so changing this after /cd requires /reload or restart."),
|
|
21606
21717
|
pi: PiConfigSchema.describe("Pi-only child-process extension controls. This setting is user-level only; project configuration cannot choose which extensions a user's subagent children load."),
|
|
21607
21718
|
smart_drops: boolean2().default(false).describe("Content-aware reclaim of provably-superseded tool output, layered on the existing execute-pass auto-drop. When on: superseded todowrite (keep newest 1), spent ctx_reduce (keep newest 3), and zero-value meta (bash_status, bash_kill, ctx_note read/dismiss) outputs are dropped; older edits to a file are compressed to a filePath-preserving marker while the newest edit per file stays full. Only acts on passes already busting the cache, so it never originates a cache bust. Honors the protected-tag reserve. Experimental: opt-in, default off until cache stability is proven; when off the wire is byte-identical to the positional-only reclaim. Requires a restart."),
|
|
21608
21719
|
caveman_text_compression: object({
|
|
@@ -21651,10 +21762,12 @@ var init_magic_context = __esm(() => {
|
|
|
21651
21762
|
"historian.omp.fallback_models",
|
|
21652
21763
|
"historian.omp.thinking_level",
|
|
21653
21764
|
"historian.two_pass",
|
|
21765
|
+
"historian.maxTokens",
|
|
21654
21766
|
"historian_timeout_ms",
|
|
21655
21767
|
"commit_cluster_trigger.enabled",
|
|
21656
21768
|
"commit_cluster_trigger.min_clusters",
|
|
21657
21769
|
"memory.auto_promote",
|
|
21770
|
+
"dreamer.maxTokens",
|
|
21658
21771
|
"dreamer.opencode.model",
|
|
21659
21772
|
"dreamer.opencode.fallback_models",
|
|
21660
21773
|
"dreamer.opencode.variant",
|
|
@@ -24903,11 +25016,48 @@ var init_context_authority = __esm(async () => {
|
|
|
24903
25016
|
mirrorFlights = new WeakMap;
|
|
24904
25017
|
});
|
|
24905
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
|
+
|
|
24906
25055
|
// ../plugin/src/features/magic-context/memory/project-identity.ts
|
|
24907
25056
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
24908
|
-
import { createHash as
|
|
25057
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
24909
25058
|
import { existsSync as existsSync21, realpathSync as realpathSync2, statSync as statSync9 } from "node:fs";
|
|
24910
|
-
import
|
|
25059
|
+
import { homedir as homedir14 } from "node:os";
|
|
25060
|
+
import path4 from "node:path";
|
|
24911
25061
|
function asError(error) {
|
|
24912
25062
|
return error instanceof Error ? error : undefined;
|
|
24913
25063
|
}
|
|
@@ -24945,8 +25095,8 @@ function getErrorStderr(error) {
|
|
|
24945
25095
|
return "";
|
|
24946
25096
|
}
|
|
24947
25097
|
function directoryFallback(directory) {
|
|
24948
|
-
const canonical =
|
|
24949
|
-
const hash =
|
|
25098
|
+
const canonical = path4.resolve(directory);
|
|
25099
|
+
const hash = createHash3("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
|
|
24950
25100
|
return `dir:${hash}`;
|
|
24951
25101
|
}
|
|
24952
25102
|
function assertDirectoryUsable(canonicalDirectory, rawDirectory) {
|
|
@@ -24991,8 +25141,9 @@ function classifyGitError(error, rawDirectory) {
|
|
|
24991
25141
|
}
|
|
24992
25142
|
return new ProjectIdentityError("unknown", rawDirectory, "git rev-list failed while resolving project identity", asError(error));
|
|
24993
25143
|
}
|
|
24994
|
-
function resolveProjectIdentityStrict(directory) {
|
|
24995
|
-
|
|
25144
|
+
function resolveProjectIdentityStrict(directory, allowHomeProject = false) {
|
|
25145
|
+
assertProjectAllowed(directory, allowHomeProject);
|
|
25146
|
+
const canonical = path4.resolve(directory);
|
|
24996
25147
|
const cached = identityCache.get(canonical);
|
|
24997
25148
|
if (cached !== undefined) {
|
|
24998
25149
|
return cached;
|
|
@@ -25008,7 +25159,8 @@ function resolveProjectIdentityStrict(directory) {
|
|
|
25008
25159
|
encoding: "utf8",
|
|
25009
25160
|
env: { ...process.env, LC_ALL: "C", LANG: "C" },
|
|
25010
25161
|
stdio: ["ignore", "pipe", "pipe"],
|
|
25011
|
-
timeout: GIT_TIMEOUT_MS
|
|
25162
|
+
timeout: GIT_TIMEOUT_MS,
|
|
25163
|
+
windowsHide: true
|
|
25012
25164
|
});
|
|
25013
25165
|
} catch (error) {
|
|
25014
25166
|
throw classifyGitError(error, directory);
|
|
@@ -25021,13 +25173,17 @@ function resolveProjectIdentityStrict(directory) {
|
|
|
25021
25173
|
const identity = `git:${rootCommit}`;
|
|
25022
25174
|
identityCache.set(canonical, identity);
|
|
25023
25175
|
lastKnownGitIdentityCache.set(canonical, identity);
|
|
25176
|
+
rememberGitIdentity(canonical, identity);
|
|
25177
|
+
const root = gitRootDirectory(canonical);
|
|
25178
|
+
if (root && root !== canonical)
|
|
25179
|
+
rememberGitIdentity(root, identity);
|
|
25024
25180
|
transientFailureCooldown.delete(canonical);
|
|
25025
25181
|
dubiousOwnershipFallbackDirectories.delete(canonical);
|
|
25026
25182
|
transientGitIdentityReuseLoggedDirectories.delete(canonical);
|
|
25027
25183
|
return identity;
|
|
25028
25184
|
}
|
|
25029
25185
|
function shouldUseDirectoryFallback(error) {
|
|
25030
|
-
return error.errorClass !== "
|
|
25186
|
+
return error.errorClass !== "home_project_disabled";
|
|
25031
25187
|
}
|
|
25032
25188
|
function getActiveCooldown(canonical) {
|
|
25033
25189
|
const until = transientFailureCooldown.get(canonical);
|
|
@@ -25039,7 +25195,7 @@ function getActiveCooldown(canonical) {
|
|
|
25039
25195
|
return;
|
|
25040
25196
|
}
|
|
25041
25197
|
function lastKnownGitIdentity(canonical) {
|
|
25042
|
-
return lastKnownGitIdentityCache.get(canonical) ?? identityCache.get(canonical);
|
|
25198
|
+
return lastKnownGitIdentityCache.get(canonical) ?? identityCache.get(canonical) ?? readRememberedGitIdentity(canonical);
|
|
25043
25199
|
}
|
|
25044
25200
|
function nearestLastKnownGitIdentity(canonical) {
|
|
25045
25201
|
const visited = new Set;
|
|
@@ -25050,7 +25206,9 @@ function nearestLastKnownGitIdentity(canonical) {
|
|
|
25050
25206
|
const cached = lastKnownGitIdentity(current);
|
|
25051
25207
|
if (cached !== undefined)
|
|
25052
25208
|
return { identity: cached, source: current };
|
|
25053
|
-
|
|
25209
|
+
if (existsSync21(path4.join(current, ".git")))
|
|
25210
|
+
break;
|
|
25211
|
+
const parent = path4.dirname(current);
|
|
25054
25212
|
if (parent === current)
|
|
25055
25213
|
break;
|
|
25056
25214
|
current = parent;
|
|
@@ -25079,7 +25237,7 @@ function reuseLastKnownGitIdentity(canonical) {
|
|
|
25079
25237
|
return cached.identity;
|
|
25080
25238
|
}
|
|
25081
25239
|
function formatDubiousOwnershipWarning(canonical) {
|
|
25082
|
-
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}`;
|
|
25083
25241
|
}
|
|
25084
25242
|
function recordDubiousOwnershipFallback(canonical) {
|
|
25085
25243
|
dubiousOwnershipFallbackDirectories.add(canonical);
|
|
@@ -25088,8 +25246,32 @@ function recordDubiousOwnershipFallback(canonical) {
|
|
|
25088
25246
|
dubiousOwnershipLoggedDirectories.add(canonical);
|
|
25089
25247
|
log3(`[magic-context] ${formatDubiousOwnershipWarning(canonical)}`);
|
|
25090
25248
|
}
|
|
25091
|
-
function
|
|
25092
|
-
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);
|
|
25093
25275
|
const cachedFallback = directoryFallbackCache.get(canonical);
|
|
25094
25276
|
if (cachedFallback !== undefined) {
|
|
25095
25277
|
if (!hasGitDir(canonical)) {
|
|
@@ -25103,27 +25285,30 @@ function resolveProjectIdentity(directory) {
|
|
|
25103
25285
|
if (cachedGitIdentity !== undefined) {
|
|
25104
25286
|
return cachedGitIdentity;
|
|
25105
25287
|
}
|
|
25288
|
+
throw new ProjectIdentityError("git_identity_unavailable", directory, "Git identity unavailable; memory features paused until the retry cooldown expires");
|
|
25106
25289
|
}
|
|
25107
25290
|
return directoryFallback(canonical);
|
|
25108
25291
|
}
|
|
25109
25292
|
try {
|
|
25110
|
-
return resolveProjectIdentityStrict(directory);
|
|
25293
|
+
return resolveProjectIdentityStrict(directory, allowHomeProject);
|
|
25111
25294
|
} catch (error) {
|
|
25112
25295
|
if (error instanceof ProjectIdentityError && shouldUseDirectoryFallback(error)) {
|
|
25113
25296
|
const fallback = directoryFallback(canonical);
|
|
25114
25297
|
const hasGitMetadata = hasGitDir(canonical);
|
|
25115
25298
|
if (!hasGitMetadata) {
|
|
25299
|
+
if (error.errorClass === "permission_denied")
|
|
25300
|
+
throw error;
|
|
25116
25301
|
directoryFallbackCache.set(canonical, fallback);
|
|
25117
25302
|
transientFailureCooldown.delete(canonical);
|
|
25118
25303
|
} else {
|
|
25119
25304
|
transientFailureCooldown.set(canonical, nowMs() + TRANSIENT_FAILURE_COOLDOWN_MS);
|
|
25120
25305
|
const cachedGitIdentity = reuseLastKnownGitIdentity(canonical);
|
|
25306
|
+
if (error.errorClass === "dubious_ownership")
|
|
25307
|
+
recordDubiousOwnershipFallback(canonical);
|
|
25121
25308
|
if (cachedGitIdentity !== undefined) {
|
|
25122
25309
|
return cachedGitIdentity;
|
|
25123
25310
|
}
|
|
25124
|
-
|
|
25125
|
-
if (error.errorClass === "dubious_ownership") {
|
|
25126
|
-
recordDubiousOwnershipFallback(canonical);
|
|
25311
|
+
throw error;
|
|
25127
25312
|
}
|
|
25128
25313
|
return fallback;
|
|
25129
25314
|
}
|
|
@@ -25144,14 +25329,14 @@ function hasGitDir(canonical) {
|
|
|
25144
25329
|
function gitRootInAncestorChain(startDirectory) {
|
|
25145
25330
|
let current = startDirectory;
|
|
25146
25331
|
while (true) {
|
|
25147
|
-
if (existsSync21(
|
|
25332
|
+
if (existsSync21(path4.join(current, ".git"))) {
|
|
25148
25333
|
try {
|
|
25149
25334
|
return realpathSync2.native(current);
|
|
25150
25335
|
} catch {
|
|
25151
|
-
return
|
|
25336
|
+
return path4.resolve(current);
|
|
25152
25337
|
}
|
|
25153
25338
|
}
|
|
25154
|
-
const parent =
|
|
25339
|
+
const parent = path4.dirname(current);
|
|
25155
25340
|
if (parent === current) {
|
|
25156
25341
|
return null;
|
|
25157
25342
|
}
|
|
@@ -25161,9 +25346,21 @@ function gitRootInAncestorChain(startDirectory) {
|
|
|
25161
25346
|
function hasGitDirInAncestorChain(startDirectory) {
|
|
25162
25347
|
return gitRootInAncestorChain(startDirectory) !== null;
|
|
25163
25348
|
}
|
|
25164
|
-
|
|
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;
|
|
25165
25361
|
var init_project_identity = __esm(() => {
|
|
25166
25362
|
init_logger();
|
|
25363
|
+
init_project_identity_cache();
|
|
25167
25364
|
TRANSIENT_FAILURE_COOLDOWN_MS = 5 * 60 * 1000;
|
|
25168
25365
|
identityCache = new Map;
|
|
25169
25366
|
linkedGitWorktreeCache = new Map;
|
|
@@ -26863,6 +27060,11 @@ var init_user_facing_codes = __esm(() => {
|
|
|
26863
27060
|
sentence: "Memory maintenance stopped at its hidden agent step limit.",
|
|
26864
27061
|
action: "This task needs less work per run; changing the model connection will not help."
|
|
26865
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
|
+
},
|
|
26866
27068
|
dream_empty_completion: {
|
|
26867
27069
|
code: "MC-D03",
|
|
26868
27070
|
sentence: "Memory maintenance received no usable response.",
|
|
@@ -27774,8 +27976,8 @@ var init_pi_executable = __esm(() => {
|
|
|
27774
27976
|
});
|
|
27775
27977
|
|
|
27776
27978
|
// ../plugin/src/shared/rpc-utils.ts
|
|
27777
|
-
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
27778
|
-
import { readFileSync as
|
|
27979
|
+
import { execFile, execFileSync as execFileSync4 } from "node:child_process";
|
|
27980
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
27779
27981
|
function isOwnRpcServerRecord(record) {
|
|
27780
27982
|
return record.pid === process.pid && record.instance_id !== undefined && ownRpcServerInstanceIds.has(record.instance_id);
|
|
27781
27983
|
}
|
|
@@ -27818,7 +28020,8 @@ function readPsProcessStartTime(pid) {
|
|
|
27818
28020
|
const output = rpcIdentityExecFileSync("ps", ["-p", String(pid), "-o", "lstart="], {
|
|
27819
28021
|
encoding: "utf8",
|
|
27820
28022
|
timeout: PS_PROBE_TIMEOUT_MS,
|
|
27821
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
28023
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
28024
|
+
windowsHide: true
|
|
27822
28025
|
});
|
|
27823
28026
|
const processStartTime = Date.parse(String(output).trim());
|
|
27824
28027
|
return Number.isFinite(processStartTime) ? processStartTime : null;
|
|
@@ -27893,7 +28096,8 @@ function readWindowsProcess(pid) {
|
|
|
27893
28096
|
const output = rpcIdentityExecFileSync("tasklist", ["/FO", "CSV", "/FI", `PID eq ${pid}`], {
|
|
27894
28097
|
encoding: "utf8",
|
|
27895
28098
|
timeout: PS_PROBE_TIMEOUT_MS,
|
|
27896
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
28099
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
28100
|
+
windowsHide: true
|
|
27897
28101
|
});
|
|
27898
28102
|
const entries = parseTasklistOutput(String(output));
|
|
27899
28103
|
if (entries === null)
|
|
@@ -27926,7 +28130,8 @@ function readPsProcessCommand(pid) {
|
|
|
27926
28130
|
const output = rpcIdentityExecFileSync("ps", ["-p", String(pid), "-o", "command="], {
|
|
27927
28131
|
encoding: "utf8",
|
|
27928
28132
|
timeout: PS_PROBE_TIMEOUT_MS,
|
|
27929
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
28133
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
28134
|
+
windowsHide: true
|
|
27930
28135
|
});
|
|
27931
28136
|
return String(output);
|
|
27932
28137
|
} catch {
|
|
@@ -28037,7 +28242,8 @@ function execProcessList(exec, file, args, timeout = PS_PROBE_TIMEOUT_MS) {
|
|
|
28037
28242
|
return String(exec(file, [...args], {
|
|
28038
28243
|
encoding: "utf8",
|
|
28039
28244
|
timeout,
|
|
28040
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
28245
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
28246
|
+
windowsHide: true
|
|
28041
28247
|
}));
|
|
28042
28248
|
}
|
|
28043
28249
|
function parseWindowsCreationDate(value) {
|
|
@@ -28099,7 +28305,7 @@ function parseWindowsCimOutput(output) {
|
|
|
28099
28305
|
pid,
|
|
28100
28306
|
parentPid: Number.isInteger(parentPid) && parentPid > 0 ? parentPid : null,
|
|
28101
28307
|
commandLine,
|
|
28102
|
-
imageName: commandLine ? executableName(commandTokens(commandLine)[0]) : null,
|
|
28308
|
+
imageName: typeof record.Name === "string" ? record.Name : commandLine ? executableName(commandTokens(commandLine)[0]) : null,
|
|
28103
28309
|
startTime: parseWindowsCreationDate(record.CreationDate)
|
|
28104
28310
|
});
|
|
28105
28311
|
}
|
|
@@ -28177,14 +28383,14 @@ function readPosixParentPid(pid) {
|
|
|
28177
28383
|
return null;
|
|
28178
28384
|
}
|
|
28179
28385
|
}
|
|
28180
|
-
function collectAncestorPids(selfPid, parentByPid) {
|
|
28386
|
+
function collectAncestorPids(selfPid, parentByPid, probeParents = true) {
|
|
28181
28387
|
const ancestors = new Set;
|
|
28182
28388
|
let current = selfPid;
|
|
28183
28389
|
for (let depth = 0;depth < MAX_ANCESTOR_WALK_DEPTH; depth += 1) {
|
|
28184
28390
|
let ppid = null;
|
|
28185
28391
|
if (parentByPid.has(current)) {
|
|
28186
28392
|
ppid = parentByPid.get(current) ?? null;
|
|
28187
|
-
} else if (rpcIdentityPlatform !== "win32") {
|
|
28393
|
+
} else if (rpcIdentityPlatform !== "win32" && probeParents) {
|
|
28188
28394
|
ppid = readPosixParentPid(current);
|
|
28189
28395
|
if (ppid == null && current === process.pid && process.ppid > 0) {
|
|
28190
28396
|
ppid = process.ppid;
|
|
@@ -28201,8 +28407,8 @@ function collectAncestorPids(selfPid, parentByPid) {
|
|
|
28201
28407
|
}
|
|
28202
28408
|
return ancestors;
|
|
28203
28409
|
}
|
|
28204
|
-
function classifyLivePiSnapshot(snapshot) {
|
|
28205
|
-
const ancestors = collectAncestorPids(process.pid, snapshot.parentByPid);
|
|
28410
|
+
function classifyLivePiSnapshot(snapshot, probeParents = true) {
|
|
28411
|
+
const ancestors = collectAncestorPids(process.pid, snapshot.parentByPid, probeParents);
|
|
28206
28412
|
const processIds = new Set;
|
|
28207
28413
|
const inconclusivePids = new Set;
|
|
28208
28414
|
const skippedAncestorPids = [];
|
|
@@ -28247,8 +28453,9 @@ function inspectLivePiProcesses() {
|
|
|
28247
28453
|
if (false) {}
|
|
28248
28454
|
try {
|
|
28249
28455
|
if (rpcIdentityPlatform === "win32") {
|
|
28250
|
-
const
|
|
28251
|
-
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();
|
|
28252
28459
|
if (!snapshot) {
|
|
28253
28460
|
return {
|
|
28254
28461
|
state: "unreadable",
|
|
@@ -28256,6 +28463,8 @@ function inspectLivePiProcesses() {
|
|
|
28256
28463
|
error: "process list unavailable"
|
|
28257
28464
|
};
|
|
28258
28465
|
}
|
|
28466
|
+
if (snapshot !== cached?.snapshot)
|
|
28467
|
+
windowsProcessSnapshotCache = { snapshot, at: now };
|
|
28259
28468
|
rememberWindowsProcessFacts(snapshot.facts);
|
|
28260
28469
|
return classifyLivePiSnapshot(snapshot);
|
|
28261
28470
|
}
|
|
@@ -28301,7 +28510,81 @@ function parseRpcPortFile(content, fallbackPid = 0) {
|
|
|
28301
28510
|
function isValidPort(port) {
|
|
28302
28511
|
return Number.isInteger(port) && port > 0 && port <= 65535;
|
|
28303
28512
|
}
|
|
28304
|
-
|
|
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;
|
|
28305
28588
|
var init_rpc_utils = __esm(() => {
|
|
28306
28589
|
init_logger();
|
|
28307
28590
|
init_pi_executable();
|
|
@@ -28315,11 +28598,12 @@ var init_rpc_utils = __esm(() => {
|
|
|
28315
28598
|
"cljs/dist",
|
|
28316
28599
|
"dist/bundle/cli"
|
|
28317
28600
|
];
|
|
28318
|
-
rpcIdentityReadFileSync =
|
|
28601
|
+
rpcIdentityReadFileSync = readFileSync15;
|
|
28319
28602
|
rpcIdentityExecFileSync = execFileSync4;
|
|
28320
28603
|
rpcIdentityProcessKill = process.kill;
|
|
28321
28604
|
rpcProcessListExecFileSync = execFileSync4;
|
|
28322
28605
|
rpcIdentityPlatform = process.platform;
|
|
28606
|
+
asyncProcessExec = execProcessListAsync;
|
|
28323
28607
|
});
|
|
28324
28608
|
// ../plugin/src/features/magic-context/fail-closed-block.ts
|
|
28325
28609
|
function attachFailClosedBlockingProcessEvidence(process2, evidence) {
|
|
@@ -28461,11 +28745,11 @@ var init_fail_closed_block = __esm(() => {
|
|
|
28461
28745
|
});
|
|
28462
28746
|
|
|
28463
28747
|
// ../plugin/src/features/magic-context/message-fts-rowid-map.ts
|
|
28464
|
-
import { createHash as
|
|
28748
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
28465
28749
|
var EMPTY_INDEX_CONTENT_HASH, upsertMapStatements, rangeReadyStatements, updateTimeStatements, activeBackfills;
|
|
28466
28750
|
var init_message_fts_rowid_map = __esm(() => {
|
|
28467
28751
|
init_write_transaction_timing();
|
|
28468
|
-
EMPTY_INDEX_CONTENT_HASH =
|
|
28752
|
+
EMPTY_INDEX_CONTENT_HASH = createHash4("sha256").update("").digest("hex");
|
|
28469
28753
|
upsertMapStatements = new WeakMap;
|
|
28470
28754
|
rangeReadyStatements = new WeakMap;
|
|
28471
28755
|
updateTimeStatements = new WeakMap;
|
|
@@ -31649,9 +31933,9 @@ import {
|
|
|
31649
31933
|
copyFileSync,
|
|
31650
31934
|
cpSync,
|
|
31651
31935
|
existsSync as existsSync22,
|
|
31652
|
-
mkdirSync as
|
|
31936
|
+
mkdirSync as mkdirSync7,
|
|
31653
31937
|
readdirSync as readdirSync4,
|
|
31654
|
-
readFileSync as
|
|
31938
|
+
readFileSync as readFileSync16,
|
|
31655
31939
|
statSync as statSync10,
|
|
31656
31940
|
unlinkSync as unlinkSync3
|
|
31657
31941
|
} from "node:fs";
|
|
@@ -31734,7 +32018,7 @@ function classifyJunkDiscovery(portFile, raw, staleFiles) {
|
|
|
31734
32018
|
log3(`[magic-context] removing stale RPC discovery file ${portFile}: ${reason} record older than 10 minutes`);
|
|
31735
32019
|
return null;
|
|
31736
32020
|
}
|
|
31737
|
-
function inspectRpcServerDiscovery(storageDir) {
|
|
32021
|
+
function inspectRpcServerDiscovery(storageDir, processes) {
|
|
31738
32022
|
const rpcRoot = join18(storageDir, "rpc");
|
|
31739
32023
|
let projectEntries;
|
|
31740
32024
|
try {
|
|
@@ -31792,12 +32076,12 @@ function inspectRpcServerDiscovery(storageDir) {
|
|
|
31792
32076
|
}
|
|
31793
32077
|
if (isOwnRpcServerRecord(record))
|
|
31794
32078
|
continue;
|
|
31795
|
-
const liveness = isPidAlive(record.pid);
|
|
32079
|
+
const liveness = processes ? processes.liveness(record.pid) : isPidAlive(record.pid);
|
|
31796
32080
|
if (liveness === "dead") {
|
|
31797
32081
|
staleFiles.push(portFile);
|
|
31798
32082
|
continue;
|
|
31799
32083
|
}
|
|
31800
|
-
const evidence = readProcessProbeEvidence(record.pid);
|
|
32084
|
+
const evidence = processes ? processes.evidence(record.pid) : readProcessProbeEvidence(record.pid);
|
|
31801
32085
|
const identity = isPidIdentityPlausible(record, evidence);
|
|
31802
32086
|
if (identity === "plausible") {
|
|
31803
32087
|
pids.add(record.pid);
|
|
@@ -33106,7 +33390,7 @@ var init_storage_db = __esm(async () => {
|
|
|
33106
33390
|
RPC_DISCOVERY_PARSE_GRACE_MS = 10 * 60 * 1000;
|
|
33107
33391
|
defaultRpcDiscoveryFs = {
|
|
33108
33392
|
readdirSync: (path, options) => options?.withFileTypes ? readdirSync4(path, { withFileTypes: true }) : readdirSync4(path),
|
|
33109
|
-
readFileSync: (path, encoding) => String(
|
|
33393
|
+
readFileSync: (path, encoding) => String(readFileSync16(path, encoding)),
|
|
33110
33394
|
statSync: (path) => ({ mtimeMs: statSync10(path).mtimeMs }),
|
|
33111
33395
|
unlinkSync: (path) => unlinkSync3(path)
|
|
33112
33396
|
};
|
|
@@ -33119,7 +33403,7 @@ var init_storage_db = __esm(async () => {
|
|
|
33119
33403
|
});
|
|
33120
33404
|
|
|
33121
33405
|
// src/lib/database-access.ts
|
|
33122
|
-
import { existsSync as existsSync23, writeFileSync as
|
|
33406
|
+
import { existsSync as existsSync23, writeFileSync as writeFileSync6 } from "node:fs";
|
|
33123
33407
|
import { pathToFileURL } from "node:url";
|
|
33124
33408
|
function getPersistedSchemaVersion2(db) {
|
|
33125
33409
|
return getPersistedSchemaVersion(db);
|
|
@@ -33173,7 +33457,7 @@ function openExistingContextDatabaseForMutation(path) {
|
|
|
33173
33457
|
async function backupDatabaseSnapshot(db, destination) {
|
|
33174
33458
|
const serializable = db;
|
|
33175
33459
|
if (typeof serializable.serialize === "function") {
|
|
33176
|
-
|
|
33460
|
+
writeFileSync6(destination, serializable.serialize(), { flag: "wx" });
|
|
33177
33461
|
return;
|
|
33178
33462
|
}
|
|
33179
33463
|
const moduleName = "node:" + "sqlite";
|
|
@@ -33455,7 +33739,10 @@ function logRow(db, fromIdentity, toIdentity, tableName, rowId, action, targetRo
|
|
|
33455
33739
|
(from_identity, to_identity, table_name, row_id, action, target_row_id, merged_at)
|
|
33456
33740
|
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(fromIdentity, toIdentity, tableName, rowId, action, targetRowId, mergedAt);
|
|
33457
33741
|
}
|
|
33458
|
-
function
|
|
33742
|
+
function normalizedContent(value) {
|
|
33743
|
+
return String(value).toLowerCase().replace(/\s+/g, " ").trim();
|
|
33744
|
+
}
|
|
33745
|
+
function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt, review) {
|
|
33459
33746
|
const sourceId = row.id;
|
|
33460
33747
|
if (typeof sourceId !== "number")
|
|
33461
33748
|
return false;
|
|
@@ -33463,10 +33750,13 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
|
|
|
33463
33750
|
FROM memories
|
|
33464
33751
|
WHERE project_path = ? AND category = ? AND normalized_hash = ? AND id <> ?
|
|
33465
33752
|
LIMIT 1`).get(toIdentity, row.category, row.normalized_hash, sourceId);
|
|
33466
|
-
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") {
|
|
33467
33757
|
const targetId = collision.id;
|
|
33468
33758
|
const targetSeen = Number(collision.seen_count ?? 1);
|
|
33469
|
-
const mergedSeen =
|
|
33759
|
+
const mergedSeen = targetSeen + Number(row.seen_count ?? 1);
|
|
33470
33760
|
const sourceClassifiedAt = Number(row.classified_at ?? 0);
|
|
33471
33761
|
const targetClassifiedAt = Number(collision.classified_at ?? 0);
|
|
33472
33762
|
if (sourceClassifiedAt > targetClassifiedAt) {
|
|
@@ -33499,8 +33789,9 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
|
|
|
33499
33789
|
END`).run(targetId, sourceId);
|
|
33500
33790
|
db.prepare("DELETE FROM memory_verifications WHERE memory_id = ?").run(sourceId);
|
|
33501
33791
|
if (mergedSeen !== targetSeen || collision.status === null || collision.status === undefined) {
|
|
33502
|
-
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);
|
|
33503
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);
|
|
33504
33795
|
db.prepare(`UPDATE memories
|
|
33505
33796
|
SET status = 'archived',
|
|
33506
33797
|
superseded_by_memory_id = ?,
|
|
@@ -33516,6 +33807,9 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
|
|
|
33516
33807
|
logRow(db, fromIdentity, toIdentity, "memories", String(sourceId), "superseded", String(targetId), mergedAt);
|
|
33517
33808
|
return true;
|
|
33518
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
|
+
}
|
|
33519
33813
|
const result = db.prepare("UPDATE memories SET project_path = ?, updated_at = ? WHERE id = ? AND project_path = ?").run(toIdentity, mergedAt, sourceId, fromIdentity);
|
|
33520
33814
|
if ((result.changes ?? 0) === 0)
|
|
33521
33815
|
return false;
|
|
@@ -33530,21 +33824,33 @@ function oldestOpenCycleStart(left, right) {
|
|
|
33530
33824
|
const values = [left, right].filter((value) => typeof value === "number" && value > 0);
|
|
33531
33825
|
return values.length > 0 ? Math.min(...values) : null;
|
|
33532
33826
|
}
|
|
33533
|
-
function reconcileTaskScheduleCollision(db, source, target) {
|
|
33534
|
-
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));
|
|
33535
33829
|
const latest = sourceIsNewer ? source : target;
|
|
33536
33830
|
db.prepare(`UPDATE task_schedule_state
|
|
33537
33831
|
SET last_run_at = ?, next_due_at = ?, schedule = ?, last_status = ?,
|
|
33538
33832
|
last_error = ?, retry_count = ?, last_checked_commit = ?,
|
|
33539
33833
|
last_broad_run_at = ?, retrospective_watermark_ms = ?
|
|
33540
|
-
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);
|
|
33541
33835
|
}
|
|
33542
33836
|
function rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt) {
|
|
33543
33837
|
const rowId = rowKey(db, table.name, row);
|
|
33544
33838
|
const collision = findUniqueCollision(db, table, row, fromIdentity, toIdentity);
|
|
33545
33839
|
if (collision) {
|
|
33546
33840
|
if (table.name === "task_schedule_state") {
|
|
33547
|
-
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);
|
|
33548
33854
|
}
|
|
33549
33855
|
const sourcePredicate = rowPredicate(db, table.name, row);
|
|
33550
33856
|
const result = db.prepare(`DELETE FROM ${quoteIdentifier(table.name)} WHERE ${sourcePredicate.sql}`).run(...sourcePredicate.values);
|
|
@@ -33553,6 +33859,9 @@ function rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt) {
|
|
|
33553
33859
|
logRow(db, fromIdentity, toIdentity, table.name, rowId, "collision_deleted", rowKey(db, table.name, collision), mergedAt);
|
|
33554
33860
|
return true;
|
|
33555
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
|
+
}
|
|
33556
33865
|
const predicate = rowPredicate(db, table.name, row);
|
|
33557
33866
|
const result = db.prepare(`UPDATE ${quoteIdentifier(table.name)}
|
|
33558
33867
|
SET ${quoteIdentifier(table.identityColumn)} = ?
|
|
@@ -33564,21 +33873,37 @@ function rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt) {
|
|
|
33564
33873
|
return true;
|
|
33565
33874
|
}
|
|
33566
33875
|
function tableSourceRows(db, table, fromIdentity) {
|
|
33567
|
-
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);
|
|
33568
33877
|
}
|
|
33569
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
|
+
}
|
|
33570
33883
|
if (!tableExists3(db, "authority_managed"))
|
|
33571
33884
|
return;
|
|
33572
33885
|
const source = db.prepare("SELECT 1 FROM authority_managed WHERE project_path = ? LIMIT 1").get(fromIdentity);
|
|
33573
33886
|
if (source) {
|
|
33574
|
-
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.`);
|
|
33575
33888
|
}
|
|
33576
33889
|
const target = db.prepare("SELECT 1 FROM authority_managed WHERE project_path = ? LIMIT 1").get(toIdentity);
|
|
33577
33890
|
if (target) {
|
|
33578
|
-
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.`);
|
|
33579
33892
|
}
|
|
33580
33893
|
}
|
|
33581
|
-
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()) {
|
|
33582
33907
|
const auditedTables = discoverIdentityTables(db).map((table) => ({
|
|
33583
33908
|
tableName: table.name,
|
|
33584
33909
|
identityColumn: table.identityColumn,
|
|
@@ -33586,12 +33911,31 @@ function auditIdentityMerge(db, fromIdentity, toIdentity) {
|
|
|
33586
33911
|
sourceRows: table.derived ? 0 : tableSourceRows(db, table, fromIdentity).length,
|
|
33587
33912
|
changedRows: 0
|
|
33588
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`);
|
|
33589
33931
|
return {
|
|
33590
33932
|
fromIdentity,
|
|
33591
33933
|
toIdentity,
|
|
33934
|
+
changes,
|
|
33592
33935
|
auditedTables,
|
|
33593
33936
|
changedRows: auditedTables.reduce((total, table) => total + table.sourceRows, 0),
|
|
33594
|
-
dryRun: true
|
|
33937
|
+
dryRun: true,
|
|
33938
|
+
...memoryDisposition(db, fromIdentity, toIdentity)
|
|
33595
33939
|
};
|
|
33596
33940
|
}
|
|
33597
33941
|
function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
|
|
@@ -33603,11 +33947,14 @@ function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
|
|
|
33603
33947
|
}
|
|
33604
33948
|
assertMergeAllowed(db, fromIdentity, toIdentity);
|
|
33605
33949
|
const tables = discoverIdentityTables(db);
|
|
33606
|
-
const report = auditIdentityMerge(db, fromIdentity, toIdentity);
|
|
33950
|
+
const report = auditIdentityMerge(db, fromIdentity, toIdentity, options.now);
|
|
33607
33951
|
if (options.dryRun)
|
|
33608
33952
|
return report;
|
|
33953
|
+
if (report.changedRows === 0)
|
|
33954
|
+
return { ...report, dryRun: false };
|
|
33609
33955
|
const mergedAt = options.now ?? Date.now();
|
|
33610
33956
|
const run = db.transaction(() => {
|
|
33957
|
+
assertMergeAllowed(db, fromIdentity, toIdentity);
|
|
33611
33958
|
if (tableExists3(db, "v22_identity_rekey_map")) {
|
|
33612
33959
|
db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
|
|
33613
33960
|
VALUES (?, ?, ?)
|
|
@@ -33622,11 +33969,15 @@ function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
|
|
|
33622
33969
|
const rows = tableSourceRows(db, table, fromIdentity);
|
|
33623
33970
|
tableReport.sourceRows = rows.length;
|
|
33624
33971
|
for (const row of rows) {
|
|
33625
|
-
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);
|
|
33626
33973
|
if (changed)
|
|
33627
33974
|
tableReport.changedRows += 1;
|
|
33628
33975
|
}
|
|
33629
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);
|
|
33630
33981
|
db.prepare(`INSERT INTO project_state
|
|
33631
33982
|
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
33632
33983
|
VALUES (?, 1, 0, ?)
|
|
@@ -33643,6 +33994,7 @@ function mergeProjectIdentities(db, fromIdentity, toIdentity, options = {}) {
|
|
|
33643
33994
|
}
|
|
33644
33995
|
var IDENTITY_COLUMNS, DERIVED_TABLE_SUFFIXES;
|
|
33645
33996
|
var init_storage_identity_merge = __esm(() => {
|
|
33997
|
+
init_cron();
|
|
33646
33998
|
IDENTITY_COLUMNS = new Set(["project_path", "project_identity"]);
|
|
33647
33999
|
DERIVED_TABLE_SUFFIXES = [
|
|
33648
34000
|
"_fts",
|
|
@@ -33654,84 +34006,88 @@ var init_storage_identity_merge = __esm(() => {
|
|
|
33654
34006
|
];
|
|
33655
34007
|
});
|
|
33656
34008
|
|
|
33657
|
-
// src/commands/doctor-
|
|
34009
|
+
// src/commands/doctor-identity-splits.ts
|
|
34010
|
+
import { realpathSync as realpathSync4 } from "node:fs";
|
|
33658
34011
|
import { join as join19 } from "node:path";
|
|
33659
|
-
function
|
|
33660
|
-
|
|
33661
|
-
if (index < 0)
|
|
33662
|
-
return null;
|
|
33663
|
-
const value = args[index + 1];
|
|
33664
|
-
if (!value || value.startsWith("--")) {
|
|
33665
|
-
throw new Error(`${flag} requires a value`);
|
|
33666
|
-
}
|
|
33667
|
-
return value;
|
|
34012
|
+
function tableExists4(db, table) {
|
|
34013
|
+
return !!db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(table);
|
|
33668
34014
|
}
|
|
33669
|
-
function
|
|
33670
|
-
|
|
33671
|
-
|
|
33672
|
-
|
|
33673
|
-
|
|
33674
|
-
|
|
33675
|
-
const knownFlags = new Set(["--from", "--to", "--db"]);
|
|
33676
|
-
for (let index = 0;index < args.length; index += 1) {
|
|
33677
|
-
const arg = args[index];
|
|
33678
|
-
if (knownFlags.has(arg)) {
|
|
33679
|
-
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))
|
|
33680
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);
|
|
33681
34034
|
}
|
|
33682
|
-
|
|
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))
|
|
33683
34040
|
continue;
|
|
33684
|
-
|
|
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
|
+
}
|
|
33685
34046
|
}
|
|
33686
|
-
|
|
33687
|
-
|
|
33688
|
-
|
|
33689
|
-
|
|
33690
|
-
|
|
33691
|
-
|
|
33692
|
-
|
|
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
|
+
}));
|
|
33693
34063
|
}
|
|
33694
|
-
function
|
|
33695
|
-
|
|
33696
|
-
|
|
33697
|
-
|
|
33698
|
-
|
|
33699
|
-
for (const table of report.auditedTables) {
|
|
33700
|
-
const suffix = table.derived ? " (derived; updated by source triggers)" : "";
|
|
33701
|
-
console.log(` ${table.tableName} [${table.identityColumn}]${suffix}: ${report.dryRun ? table.sourceRows : table.changedRows} row(s)`);
|
|
33702
|
-
}
|
|
33703
|
-
console.log(` rows changed: ${report.changedRows}`);
|
|
33704
|
-
if (report.dryRun) {
|
|
33705
|
-
console.log(" no database writes performed");
|
|
33706
|
-
}
|
|
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
|
+
]);
|
|
33707
34069
|
}
|
|
33708
|
-
function
|
|
33709
|
-
const db =
|
|
34070
|
+
function diagnoseIdentitySplits() {
|
|
34071
|
+
const db = openExistingContextDatabase(join19(getMagicContextStorageDir(), "context.db"), {
|
|
34072
|
+
readonly: true
|
|
34073
|
+
});
|
|
33710
34074
|
if (!db)
|
|
33711
|
-
|
|
33712
|
-
|
|
33713
|
-
}
|
|
33714
|
-
function runMergeIdentityCli(args) {
|
|
33715
|
-
const options = parseMergeIdentityArgs(args);
|
|
33716
|
-
if (!options.dryRun && !options.yes) {
|
|
33717
|
-
console.error("Refusing to mutate context.db without explicit --yes. Re-run with --yes, or use --dry-run to preview.");
|
|
33718
|
-
return 2;
|
|
33719
|
-
}
|
|
33720
|
-
const dbPath = options.dbPath ?? join19(getMagicContextStorageDir(), "context.db");
|
|
33721
|
-
const db = openMergeDatabase(dbPath, !options.dryRun);
|
|
34075
|
+
return [];
|
|
34076
|
+
let host = null;
|
|
33722
34077
|
try {
|
|
33723
|
-
|
|
33724
|
-
|
|
33725
|
-
|
|
33726
|
-
|
|
33727
|
-
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));
|
|
33728
34082
|
} finally {
|
|
34083
|
+
host?.close();
|
|
33729
34084
|
db.close();
|
|
33730
34085
|
}
|
|
33731
34086
|
}
|
|
33732
|
-
var
|
|
33733
|
-
|
|
34087
|
+
var init_doctor_identity_splits = __esm(async () => {
|
|
34088
|
+
init_project_identity_cache();
|
|
33734
34089
|
init_data_path();
|
|
34090
|
+
init_opencode_db_path();
|
|
33735
34091
|
await init_database_access();
|
|
33736
34092
|
});
|
|
33737
34093
|
|
|
@@ -33744,7 +34100,7 @@ import {
|
|
|
33744
34100
|
copyFileSync as copyFileSync2,
|
|
33745
34101
|
existsSync as existsSync24,
|
|
33746
34102
|
openSync as openSync4,
|
|
33747
|
-
renameSync as
|
|
34103
|
+
renameSync as renameSync5,
|
|
33748
34104
|
rmSync as rmSync3,
|
|
33749
34105
|
statSync as statSync11
|
|
33750
34106
|
} from "node:fs";
|
|
@@ -33999,15 +34355,15 @@ function activateReplacement(dbPath, replacementPath, originalAsidePath) {
|
|
|
33999
34355
|
if (!existsSync24(from))
|
|
34000
34356
|
continue;
|
|
34001
34357
|
const to = `${originalAsidePath}${suffix}`;
|
|
34002
|
-
|
|
34358
|
+
renameSync5(from, to);
|
|
34003
34359
|
movedOriginals.push({ from, to });
|
|
34004
34360
|
}
|
|
34005
|
-
|
|
34361
|
+
renameSync5(replacementPath, dbPath);
|
|
34006
34362
|
return movedOriginals.map(({ to }) => to);
|
|
34007
34363
|
} catch (error) {
|
|
34008
34364
|
for (const moved of movedOriginals.reverse()) {
|
|
34009
34365
|
if (existsSync24(moved.to) && !existsSync24(moved.from))
|
|
34010
|
-
|
|
34366
|
+
renameSync5(moved.to, moved.from);
|
|
34011
34367
|
}
|
|
34012
34368
|
throw error;
|
|
34013
34369
|
}
|
|
@@ -34238,6 +34594,232 @@ var init_doctor_repair_db = __esm(async () => {
|
|
|
34238
34594
|
];
|
|
34239
34595
|
});
|
|
34240
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
|
+
|
|
34241
34823
|
// src/commands/doctor-hidden-sessions.ts
|
|
34242
34824
|
function parseMetadata(value) {
|
|
34243
34825
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
@@ -34328,20 +34910,20 @@ var init_migration_paths = __esm(() => {
|
|
|
34328
34910
|
});
|
|
34329
34911
|
|
|
34330
34912
|
// src/commands/migrate.ts
|
|
34331
|
-
import { createHash as
|
|
34332
|
-
import { existsSync as
|
|
34333
|
-
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";
|
|
34334
34916
|
function defaultOpenCodeDbPath() {
|
|
34335
34917
|
return getOpenCodeDatabasePath();
|
|
34336
34918
|
}
|
|
34337
34919
|
function defaultCortexkitDbPath() {
|
|
34338
|
-
return
|
|
34920
|
+
return join22(getMagicContextStorageDir(), "context.db");
|
|
34339
34921
|
}
|
|
34340
34922
|
function defaultPiSessionsRoot() {
|
|
34341
34923
|
return getPiSessionsRoot();
|
|
34342
34924
|
}
|
|
34343
34925
|
function defaultFs() {
|
|
34344
|
-
return { writeFileAtomic, unlinkSync: unlinkSync4, existsSync:
|
|
34926
|
+
return { writeFileAtomic, unlinkSync: unlinkSync4, existsSync: existsSync26, renameSync: renameSync7, mkdirSync: mkdirSync9 };
|
|
34345
34927
|
}
|
|
34346
34928
|
function stmt(db, sql) {
|
|
34347
34929
|
return db.prepare(sql);
|
|
@@ -34368,7 +34950,7 @@ function shortId() {
|
|
|
34368
34950
|
return randomBytes2(4).toString("hex");
|
|
34369
34951
|
}
|
|
34370
34952
|
function migrationKeyFor(sourceSessionId, targetHarness) {
|
|
34371
|
-
return
|
|
34953
|
+
return createHash6("sha256").update(`${sourceSessionId}
|
|
34372
34954
|
${targetHarness}`).digest("hex");
|
|
34373
34955
|
}
|
|
34374
34956
|
function moduleManagedProjectForSession(db, sessionId) {
|
|
@@ -34407,7 +34989,7 @@ function sweepPendingMigrations(db, fs = defaultFs()) {
|
|
|
34407
34989
|
}
|
|
34408
34990
|
if (row.phase === "db_committed") {
|
|
34409
34991
|
if (fs.existsSync(row.stage_path)) {
|
|
34410
|
-
fs.mkdirSync(
|
|
34992
|
+
fs.mkdirSync(dirname14(row.final_path), { recursive: true });
|
|
34411
34993
|
fs.renameSync(row.stage_path, row.final_path);
|
|
34412
34994
|
stmt(db, "DELETE FROM migration_pending WHERE migration_key = ?").run(row.migration_key);
|
|
34413
34995
|
report.rolledForward += 1;
|
|
@@ -34437,7 +35019,7 @@ function claimJournalIdentity(args) {
|
|
|
34437
35019
|
migration_key, source_session_id, target_harness, pi_session_id,
|
|
34438
35020
|
final_path, stage_path, content_sha256, phase, created_at
|
|
34439
35021
|
) VALUES (?, ?, ?, ?, ?, ?, '', 'staged', ?)
|
|
34440
|
-
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);
|
|
34441
35023
|
const row = readPendingMigration(args.db, args.migrationKey);
|
|
34442
35024
|
if (!row) {
|
|
34443
35025
|
throw new Error("migration journal row disappeared during insert; aborting migration");
|
|
@@ -34942,7 +35524,7 @@ function migrateOpenCodeSessionToPi(opts) {
|
|
|
34942
35524
|
const provider = opts.provider ?? model.provider;
|
|
34943
35525
|
const modelId = opts.modelId ?? model.modelId;
|
|
34944
35526
|
const cwd = session.directory ?? session.path ?? process.cwd();
|
|
34945
|
-
const outputDir =
|
|
35527
|
+
const outputDir = join22(piSessionsRoot, projectPathToPiDirSlug(cwd));
|
|
34946
35528
|
const targetHarness = opts.targetHarness ?? "pi";
|
|
34947
35529
|
const moduleManagedProject = cortexkitDb === null ? null : moduleManagedProjectForSession(cortexkitDb, session.id);
|
|
34948
35530
|
if (moduleManagedProject) {
|
|
@@ -34966,8 +35548,8 @@ function migrateOpenCodeSessionToPi(opts) {
|
|
|
34966
35548
|
migrationKey,
|
|
34967
35549
|
sourceSessionId: session.id,
|
|
34968
35550
|
targetHarness,
|
|
34969
|
-
finalPathFor: (id) =>
|
|
34970
|
-
stageDir:
|
|
35551
|
+
finalPathFor: (id) => join22(outputDir, `${formatPiFilenameTimestamp(now)}_${id}.jsonl`),
|
|
35552
|
+
stageDir: join22(dirname14(piSessionsRoot), MIGRATION_STAGE_DIRNAME),
|
|
34971
35553
|
now: now.getTime()
|
|
34972
35554
|
});
|
|
34973
35555
|
piSessionId = claimed.row.pi_session_id;
|
|
@@ -34976,7 +35558,7 @@ function migrateOpenCodeSessionToPi(opts) {
|
|
|
34976
35558
|
journalResumed = claimed.resumed;
|
|
34977
35559
|
} else {
|
|
34978
35560
|
piSessionId = generateUuidV7(now);
|
|
34979
|
-
finalPath =
|
|
35561
|
+
finalPath = join22(outputDir, `${formatPiFilenameTimestamp(now)}_${piSessionId}.jsonl`);
|
|
34980
35562
|
stagePath = "";
|
|
34981
35563
|
}
|
|
34982
35564
|
const buildResult = buildPiEntries({
|
|
@@ -35015,11 +35597,11 @@ function migrateOpenCodeSessionToPi(opts) {
|
|
|
35015
35597
|
`;
|
|
35016
35598
|
if (!opts.dryRun) {
|
|
35017
35599
|
if (journalActive && cortexkitDb !== null && migrationKey !== undefined && plan) {
|
|
35018
|
-
const contentSha256 =
|
|
35600
|
+
const contentSha256 = createHash6("sha256").update(jsonl, "utf8").digest("hex");
|
|
35019
35601
|
commitStagedChecksum(cortexkitDb, migrationKey, contentSha256);
|
|
35020
35602
|
fs.writeFileAtomic(stagePath, jsonl);
|
|
35021
35603
|
plan.commit(migrationKey);
|
|
35022
|
-
fs.mkdirSync(
|
|
35604
|
+
fs.mkdirSync(dirname14(finalPath), { recursive: true });
|
|
35023
35605
|
fs.renameSync(stagePath, finalPath);
|
|
35024
35606
|
stmt(cortexkitDb, "DELETE FROM migration_pending WHERE migration_key = ?").run(migrationKey);
|
|
35025
35607
|
} else {
|
|
@@ -35289,9 +35871,9 @@ var init_relocate_memory = __esm(() => {
|
|
|
35289
35871
|
});
|
|
35290
35872
|
|
|
35291
35873
|
// src/commands/migrate-session.ts
|
|
35292
|
-
import { existsSync as
|
|
35293
|
-
import { homedir as
|
|
35294
|
-
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";
|
|
35295
35877
|
function existingSessionColumns(db) {
|
|
35296
35878
|
const rows = db.prepare("PRAGMA table_info(session)").all();
|
|
35297
35879
|
return new Set(rows.map((r) => r.name).filter((n) => typeof n === "string"));
|
|
@@ -35375,7 +35957,7 @@ function planMigrateSession(sessionId, rawTargetDirectory, deps) {
|
|
|
35375
35957
|
ocProjectId = "global";
|
|
35376
35958
|
ocWorktree = globalRow.worktree || "/";
|
|
35377
35959
|
}
|
|
35378
|
-
const sessionPath =
|
|
35960
|
+
const sessionPath = path5.relative(ocWorktree, targetDirectory);
|
|
35379
35961
|
const ownershipRow = deps.contextDb.prepare("SELECT project_path FROM session_projects WHERE session_id = ? AND harness = 'opencode'").get(sessionId);
|
|
35380
35962
|
const fromMcIdentity = ownershipRow?.project_path ?? (sessionRow.directory ? deps.resolveIdentity(sessionRow.directory) : "");
|
|
35381
35963
|
const toMcIdentity = deps.resolveIdentity(targetDirectory);
|
|
@@ -35501,18 +36083,18 @@ function defaultOpenCodeDbPath2() {
|
|
|
35501
36083
|
return getOpenCodeDatabasePath();
|
|
35502
36084
|
}
|
|
35503
36085
|
function defaultContextDbPath() {
|
|
35504
|
-
return
|
|
36086
|
+
return join23(getMagicContextStorageDir(), "context.db");
|
|
35505
36087
|
}
|
|
35506
36088
|
function realDeps(opencodeDb, contextDb) {
|
|
35507
36089
|
return {
|
|
35508
36090
|
opencodeDb,
|
|
35509
36091
|
contextDb,
|
|
35510
36092
|
resolveIdentity: resolveProjectIdentity,
|
|
35511
|
-
hasGitDir: (dir) =>
|
|
35512
|
-
realpath: (p) =>
|
|
36093
|
+
hasGitDir: (dir) => existsSync27(join23(dir, ".git")),
|
|
36094
|
+
realpath: (p) => realpathSync5(p)
|
|
35513
36095
|
};
|
|
35514
36096
|
}
|
|
35515
|
-
function
|
|
36097
|
+
function valueAfter(args, flag) {
|
|
35516
36098
|
const index = args.indexOf(flag);
|
|
35517
36099
|
if (index === -1)
|
|
35518
36100
|
return null;
|
|
@@ -35566,11 +36148,11 @@ async function runMigrateSessionCli(args) {
|
|
|
35566
36148
|
printMigrateSessionHelp();
|
|
35567
36149
|
return 0;
|
|
35568
36150
|
}
|
|
35569
|
-
const sessionId =
|
|
35570
|
-
const toDir =
|
|
36151
|
+
const sessionId = valueAfter(args, "--session");
|
|
36152
|
+
const toDir = valueAfter(args, "--to");
|
|
35571
36153
|
const dryRun = args.includes("--dry-run");
|
|
35572
36154
|
const skipConfirm = args.includes("--yes");
|
|
35573
|
-
const memoriesFlag =
|
|
36155
|
+
const memoriesFlag = valueAfter(args, "--memories");
|
|
35574
36156
|
if (!sessionId) {
|
|
35575
36157
|
console.error("Missing required flag: --session <id>");
|
|
35576
36158
|
printMigrateSessionHelp();
|
|
@@ -35586,8 +36168,8 @@ async function runMigrateSessionCli(args) {
|
|
|
35586
36168
|
printMigrateSessionHelp();
|
|
35587
36169
|
return 1;
|
|
35588
36170
|
}
|
|
35589
|
-
const expandedTo = toDir.startsWith("~") ?
|
|
35590
|
-
if (!
|
|
36171
|
+
const expandedTo = toDir.startsWith("~") ? join23(homedir15(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
|
|
36172
|
+
if (!existsSync27(expandedTo)) {
|
|
35591
36173
|
console.error(`Target directory does not exist: ${expandedTo}`);
|
|
35592
36174
|
return 1;
|
|
35593
36175
|
}
|
|
@@ -35739,9 +36321,9 @@ var init_migrate_session = __esm(async () => {
|
|
|
35739
36321
|
});
|
|
35740
36322
|
|
|
35741
36323
|
// ../plugin/src/features/magic-context/v22-deferred-backfill.ts
|
|
35742
|
-
import { createHash as
|
|
35743
|
-
import { realpathSync as
|
|
35744
|
-
import
|
|
36324
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
36325
|
+
import { realpathSync as realpathSync6 } from "node:fs";
|
|
36326
|
+
import path6 from "node:path";
|
|
35745
36327
|
function readMeta(db, key) {
|
|
35746
36328
|
const row = db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(key);
|
|
35747
36329
|
return row?.value ?? null;
|
|
@@ -35762,7 +36344,7 @@ function countFailures(db) {
|
|
|
35762
36344
|
function classifyBackfillError(error) {
|
|
35763
36345
|
if (error instanceof ProjectIdentityError) {
|
|
35764
36346
|
return {
|
|
35765
|
-
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,
|
|
35766
36348
|
errorMessage: error.message
|
|
35767
36349
|
};
|
|
35768
36350
|
}
|
|
@@ -35784,11 +36366,11 @@ function resolveBackfillIdentity(rawProjectPath) {
|
|
|
35784
36366
|
function computeLegacyRustDirIdentity(rawProjectPath) {
|
|
35785
36367
|
let canonical;
|
|
35786
36368
|
try {
|
|
35787
|
-
canonical =
|
|
36369
|
+
canonical = realpathSync6(rawProjectPath);
|
|
35788
36370
|
} catch {
|
|
35789
|
-
canonical =
|
|
36371
|
+
canonical = path6.isAbsolute(rawProjectPath) ? rawProjectPath : path6.join(process.cwd(), rawProjectPath);
|
|
35790
36372
|
}
|
|
35791
|
-
return `dir:${
|
|
36373
|
+
return `dir:${createHash7("sha256").update(canonical, "utf8").digest("hex")}`;
|
|
35792
36374
|
}
|
|
35793
36375
|
function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
|
|
35794
36376
|
db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
|
|
@@ -36009,7 +36591,7 @@ var init_tick_failure = __esm(() => {
|
|
|
36009
36591
|
});
|
|
36010
36592
|
|
|
36011
36593
|
// ../pi-plugin/src/config/index.ts
|
|
36012
|
-
import { existsSync as
|
|
36594
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
36013
36595
|
function getProjectConfigPaths(cwd) {
|
|
36014
36596
|
const basePath = cortexKitProjectConfigBasePath(cwd);
|
|
36015
36597
|
return [`${basePath}.jsonc`, `${basePath}.json`];
|
|
@@ -36019,10 +36601,10 @@ function getUserConfigPaths() {
|
|
|
36019
36601
|
return [`${basePath}.jsonc`, `${basePath}.json`];
|
|
36020
36602
|
}
|
|
36021
36603
|
function resolveFirstExisting(paths) {
|
|
36022
|
-
return paths.find((path) =>
|
|
36604
|
+
return paths.find((path) => existsSync28(path));
|
|
36023
36605
|
}
|
|
36024
36606
|
function resolvePiLegacyFallback(sources) {
|
|
36025
|
-
return sources.find((source) =>
|
|
36607
|
+
return sources.find((source) => existsSync28(source.path)) ?? null;
|
|
36026
36608
|
}
|
|
36027
36609
|
function loadConfigFile(path, scope) {
|
|
36028
36610
|
let raw;
|
|
@@ -36317,7 +36899,7 @@ function loadPiConfigDetailed(opts = {}, applyRuntimeGlobals = true) {
|
|
|
36317
36899
|
if (loaded)
|
|
36318
36900
|
loadedFiles.push(loaded);
|
|
36319
36901
|
}
|
|
36320
|
-
const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) =>
|
|
36902
|
+
const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) => existsSync28(source.path));
|
|
36321
36903
|
const userPath = resolveFirstExisting(getUserConfigPaths());
|
|
36322
36904
|
const userLegacyFallback = userPath ? null : resolvePiLegacyFallback(harnessLegacy.user);
|
|
36323
36905
|
const userReadPath = userPath ?? userLegacyFallback?.path;
|
|
@@ -36326,7 +36908,7 @@ function loadPiConfigDetailed(opts = {}, applyRuntimeGlobals = true) {
|
|
|
36326
36908
|
if (loaded)
|
|
36327
36909
|
loadedFiles.push(loaded);
|
|
36328
36910
|
}
|
|
36329
|
-
const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) =>
|
|
36911
|
+
const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) => existsSync28(source.path));
|
|
36330
36912
|
if (userLegacyFallback) {
|
|
36331
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.`);
|
|
36332
36914
|
} else if (legacyUserUnmigrated) {
|
|
@@ -36448,10 +37030,11 @@ var DATABASE_REPAIR_COMMAND = "bunx @cortexkit/magic-context@latest doctor repai
|
|
|
36448
37030
|
|
|
36449
37031
|
// src/lib/github-issue.ts
|
|
36450
37032
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
36451
|
-
import { readFileSync as
|
|
37033
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
36452
37034
|
function runGhCommand(args) {
|
|
36453
37035
|
try {
|
|
36454
37036
|
const result = spawnSync5("gh", args, {
|
|
37037
|
+
windowsHide: true,
|
|
36455
37038
|
encoding: "utf-8",
|
|
36456
37039
|
stdio: ["ignore", "pipe", "pipe"]
|
|
36457
37040
|
});
|
|
@@ -36474,7 +37057,7 @@ function failed(result) {
|
|
|
36474
37057
|
function submitGithubIssue(title, bodyPath, runner = runGhCommand) {
|
|
36475
37058
|
let body;
|
|
36476
37059
|
try {
|
|
36477
|
-
body =
|
|
37060
|
+
body = readFileSync18(bodyPath, "utf-8");
|
|
36478
37061
|
} catch (error) {
|
|
36479
37062
|
return {
|
|
36480
37063
|
ok: false,
|
|
@@ -36532,9 +37115,9 @@ var MAX_GITHUB_ISSUE_BODY_CHARS = 65536;
|
|
|
36532
37115
|
var init_github_issue = () => {};
|
|
36533
37116
|
|
|
36534
37117
|
// src/lib/log-lines.ts
|
|
36535
|
-
import { existsSync as
|
|
37118
|
+
import { existsSync as existsSync29, readFileSync as readFileSync19, statSync as statSync12 } from "node:fs";
|
|
36536
37119
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
36537
|
-
import { join as
|
|
37120
|
+
import { join as join24 } from "node:path";
|
|
36538
37121
|
function tokenize(input, limit = Number.POSITIVE_INFINITY) {
|
|
36539
37122
|
const tokens = [];
|
|
36540
37123
|
let index = 0;
|
|
@@ -36820,20 +37403,20 @@ function parseLogLine(line) {
|
|
|
36820
37403
|
}
|
|
36821
37404
|
function getMagicContextLogPaths(harness, options = {}) {
|
|
36822
37405
|
const override = options.override === undefined ? process.env.MAGIC_CONTEXT_LOG_PATH?.trim() : options.override?.trim();
|
|
36823
|
-
const storageLogs =
|
|
37406
|
+
const storageLogs = join24(options.storageDir ?? getMagicContextStorageDir(), "logs");
|
|
36824
37407
|
return [
|
|
36825
37408
|
...override ? [override] : [],
|
|
36826
|
-
|
|
36827
|
-
|
|
36828
|
-
|
|
37409
|
+
join24(options.tempDir ?? tmpdir2(), harness, "magic-context", "magic-context.log"),
|
|
37410
|
+
join24(storageLogs, `magic-context.${harness}.log`),
|
|
37411
|
+
join24(storageLogs, "magic-context.log")
|
|
36829
37412
|
].filter((path, index, paths) => paths.indexOf(path) === index);
|
|
36830
37413
|
}
|
|
36831
37414
|
function inspectLogFile(path) {
|
|
36832
|
-
if (!
|
|
37415
|
+
if (!existsSync29(path)) {
|
|
36833
37416
|
return { path, exists: false, sizeKb: 0, lineCount: 0, grammar: "unknown" };
|
|
36834
37417
|
}
|
|
36835
37418
|
try {
|
|
36836
|
-
const content =
|
|
37419
|
+
const content = readFileSync19(path, "utf8");
|
|
36837
37420
|
const lines = content.split(/\r?\n/).filter((line) => line.length > 0);
|
|
36838
37421
|
const grammars = new Set(lines.flatMap((line) => {
|
|
36839
37422
|
const parsed = parseLogLine(line);
|
|
@@ -36860,7 +37443,7 @@ function readLogLines(files) {
|
|
|
36860
37443
|
return [];
|
|
36861
37444
|
try {
|
|
36862
37445
|
let precedingTimestamp = "";
|
|
36863
|
-
return
|
|
37446
|
+
return readFileSync19(file.path, "utf8").split(/\r?\n/).filter((line) => line.length > 0).map((line, lineIndex) => {
|
|
36864
37447
|
precedingTimestamp = parseLogLine(line)?.ts ?? precedingTimestamp;
|
|
36865
37448
|
return { line, timestamp: precedingTimestamp, fileIndex, lineIndex };
|
|
36866
37449
|
});
|
|
@@ -36909,10 +37492,10 @@ var init_redaction2 = __esm(() => {
|
|
|
36909
37492
|
});
|
|
36910
37493
|
|
|
36911
37494
|
// src/commands/doctor-omp.ts
|
|
36912
|
-
import { execFileSync as
|
|
36913
|
-
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";
|
|
36914
37497
|
import { createRequire as createRequire3 } from "node:module";
|
|
36915
|
-
import { dirname as
|
|
37498
|
+
import { dirname as dirname15, join as join25, resolve as resolve8 } from "node:path";
|
|
36916
37499
|
function parseSemver(value) {
|
|
36917
37500
|
const match = value?.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
36918
37501
|
return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
|
|
@@ -36954,10 +37537,10 @@ function selfVersion() {
|
|
|
36954
37537
|
return "unknown";
|
|
36955
37538
|
}
|
|
36956
37539
|
function readConfig2(path) {
|
|
36957
|
-
if (!
|
|
37540
|
+
if (!existsSync30(path))
|
|
36958
37541
|
return {};
|
|
36959
37542
|
try {
|
|
36960
|
-
const parsed = import_comment_json7.parse(
|
|
37543
|
+
const parsed = import_comment_json7.parse(readFileSync20(path, "utf-8"));
|
|
36961
37544
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? {} : { error: "top level is not an object" };
|
|
36962
37545
|
} catch (error) {
|
|
36963
37546
|
return { error: error instanceof Error ? error.message : String(error) };
|
|
@@ -36967,7 +37550,7 @@ function pluginDeclaresOmp(path) {
|
|
|
36967
37550
|
if (!path)
|
|
36968
37551
|
return null;
|
|
36969
37552
|
try {
|
|
36970
|
-
const pkg = JSON.parse(
|
|
37553
|
+
const pkg = JSON.parse(readFileSync20(join25(path, "package.json"), "utf-8"));
|
|
36971
37554
|
return Array.isArray(pkg.omp?.extensions) || Array.isArray(pkg.pi?.extensions);
|
|
36972
37555
|
} catch {
|
|
36973
37556
|
return null;
|
|
@@ -37048,7 +37631,7 @@ async function runHealthChecks(options) {
|
|
|
37048
37631
|
}
|
|
37049
37632
|
}
|
|
37050
37633
|
const userConfigPath = getOmpUserConfigPath();
|
|
37051
|
-
if (!
|
|
37634
|
+
if (!existsSync30(userConfigPath)) {
|
|
37052
37635
|
add(results, "warn", `No Magic Context user config at ${userConfigPath}`);
|
|
37053
37636
|
repairPlan.writeUserConfig = true;
|
|
37054
37637
|
} else {
|
|
@@ -37065,9 +37648,9 @@ async function runHealthChecks(options) {
|
|
|
37065
37648
|
for (const warning of loaded.warnings.slice(0, 5))
|
|
37066
37649
|
add(results, "warn", warning);
|
|
37067
37650
|
const storage = getMagicContextStorageResolution();
|
|
37068
|
-
const dbPath =
|
|
37651
|
+
const dbPath = join25(storage.path, "context.db");
|
|
37069
37652
|
add(results, "info", `Shared storage: ${storage.path} (source: ${storage.source})`);
|
|
37070
|
-
if (!
|
|
37653
|
+
if (!existsSync30(dbPath))
|
|
37071
37654
|
add(results, "info", `Shared context DB will be created at ${dbPath}`);
|
|
37072
37655
|
else {
|
|
37073
37656
|
let db = null;
|
|
@@ -37121,7 +37704,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
37121
37704
|
};
|
|
37122
37705
|
}
|
|
37123
37706
|
function writeDefaultConfig(path) {
|
|
37124
|
-
|
|
37707
|
+
mkdirSync10(dirname15(path), { recursive: true });
|
|
37125
37708
|
const config = {
|
|
37126
37709
|
$schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
|
|
37127
37710
|
...MagicContextConfigSchema.parse({})
|
|
@@ -37131,7 +37714,7 @@ function writeDefaultConfig(path) {
|
|
|
37131
37714
|
}
|
|
37132
37715
|
async function repair(plan, deps, prompts, cwd) {
|
|
37133
37716
|
let fixed = 0;
|
|
37134
|
-
if (plan.writeUserConfig && !
|
|
37717
|
+
if (plan.writeUserConfig && !existsSync30(getOmpUserConfigPath())) {
|
|
37135
37718
|
writeDefaultConfig(getOmpUserConfigPath());
|
|
37136
37719
|
prompts.log.success(`Wrote default Magic Context config to ${getOmpUserConfigPath()}`);
|
|
37137
37720
|
fixed += 1;
|
|
@@ -37173,6 +37756,7 @@ function timestamp2(date) {
|
|
|
37173
37756
|
function runGhCommandWithDeps(deps, args) {
|
|
37174
37757
|
if (args[0] === "issue") {
|
|
37175
37758
|
const result = deps.spawnSync("gh", args, {
|
|
37759
|
+
windowsHide: true,
|
|
37176
37760
|
encoding: "utf-8",
|
|
37177
37761
|
stdio: ["ignore", "pipe", "pipe"]
|
|
37178
37762
|
});
|
|
@@ -37184,6 +37768,7 @@ function runGhCommandWithDeps(deps, args) {
|
|
|
37184
37768
|
}
|
|
37185
37769
|
try {
|
|
37186
37770
|
const output = deps.execFileSync("gh", args, {
|
|
37771
|
+
windowsHide: true,
|
|
37187
37772
|
encoding: "utf-8",
|
|
37188
37773
|
stdio: ["ignore", "pipe", "pipe"]
|
|
37189
37774
|
});
|
|
@@ -37216,7 +37801,7 @@ async function runIssueFlow(options) {
|
|
|
37216
37801
|
...report.results.map((result) => `- ${result.status.toUpperCase()}: ${sanitizeDiagnosticText(result.message)}`)
|
|
37217
37802
|
].join(`
|
|
37218
37803
|
`);
|
|
37219
|
-
const path =
|
|
37804
|
+
const path = join25(options.cwd, `magic-context-omp-issue-${timestamp2(options.deps.now())}.md`);
|
|
37220
37805
|
writeFileAtomic(path, `${body}
|
|
37221
37806
|
`);
|
|
37222
37807
|
options.prompts.log.success(`Sanitized report written to ${path}`);
|
|
@@ -37287,7 +37872,7 @@ var init_doctor_omp = __esm(async () => {
|
|
|
37287
37872
|
openExistingContextDatabase,
|
|
37288
37873
|
now: () => new Date,
|
|
37289
37874
|
inspectMagicContextLogs,
|
|
37290
|
-
execFileSync:
|
|
37875
|
+
execFileSync: execFileSync6,
|
|
37291
37876
|
spawnSync: spawnSync6
|
|
37292
37877
|
};
|
|
37293
37878
|
});
|
|
@@ -37404,7 +37989,7 @@ function truncate(text) {
|
|
|
37404
37989
|
var DEFAULT_TIMEOUT_MS = 1e4, MAX_PREVIEW_CHARS = 240;
|
|
37405
37990
|
|
|
37406
37991
|
// ../plugin/src/features/magic-context/memory/embedding-synapse.ts
|
|
37407
|
-
import { createHash as
|
|
37992
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
37408
37993
|
function toSynapseLaneDescriptor(metadata) {
|
|
37409
37994
|
const tokenBudget = metadata.recommended_token_budget;
|
|
37410
37995
|
return {
|
|
@@ -37544,7 +38129,7 @@ function wait(ms) {
|
|
|
37544
38129
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
37545
38130
|
}
|
|
37546
38131
|
function sha256(value) {
|
|
37547
|
-
return
|
|
38132
|
+
return createHash8("sha256").update(value).digest("hex");
|
|
37548
38133
|
}
|
|
37549
38134
|
function stableJson2(value) {
|
|
37550
38135
|
if (Array.isArray(value))
|
|
@@ -38188,12 +38773,12 @@ function listShadowBackfillStalls(db, projectIdentity) {
|
|
|
38188
38773
|
var SHADOW_BACKFILL_PROVENANCE_KEY = "_magicContextShadowBackfill";
|
|
38189
38774
|
|
|
38190
38775
|
// ../plugin/src/shared/auto-update-provenance.ts
|
|
38191
|
-
import { existsSync as
|
|
38776
|
+
import { existsSync as existsSync31, readFileSync as readFileSync21 } from "node:fs";
|
|
38192
38777
|
function readAutoUpdateCheckState(path) {
|
|
38193
|
-
if (!
|
|
38778
|
+
if (!existsSync31(path))
|
|
38194
38779
|
return null;
|
|
38195
38780
|
try {
|
|
38196
|
-
const value = JSON.parse(
|
|
38781
|
+
const value = JSON.parse(readFileSync21(path, "utf-8"));
|
|
38197
38782
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
38198
38783
|
return null;
|
|
38199
38784
|
const raw = value;
|
|
@@ -38221,14 +38806,14 @@ var init_auto_update_provenance = () => {};
|
|
|
38221
38806
|
// ../plugin/src/shared/tui-config.ts
|
|
38222
38807
|
import {
|
|
38223
38808
|
chmodSync as chmodSync5,
|
|
38224
|
-
existsSync as
|
|
38225
|
-
mkdirSync as
|
|
38226
|
-
readFileSync as
|
|
38227
|
-
renameSync as
|
|
38809
|
+
existsSync as existsSync32,
|
|
38810
|
+
mkdirSync as mkdirSync11,
|
|
38811
|
+
readFileSync as readFileSync22,
|
|
38812
|
+
renameSync as renameSync8,
|
|
38228
38813
|
statSync as statSync13,
|
|
38229
|
-
writeFileSync as
|
|
38814
|
+
writeFileSync as writeFileSync8
|
|
38230
38815
|
} from "node:fs";
|
|
38231
|
-
import { dirname as
|
|
38816
|
+
import { dirname as dirname16, join as join26 } from "node:path";
|
|
38232
38817
|
function pluginEntryId(entry) {
|
|
38233
38818
|
if (typeof entry === "string")
|
|
38234
38819
|
return entry;
|
|
@@ -38259,21 +38844,21 @@ function writeTuiConfigAtomic(configPath, config) {
|
|
|
38259
38844
|
const body = `${import_comment_json8.stringify(config, null, 2)}
|
|
38260
38845
|
`;
|
|
38261
38846
|
const tmpPath = `${configPath}.tmp`;
|
|
38262
|
-
|
|
38847
|
+
writeFileSync8(tmpPath, body);
|
|
38263
38848
|
try {
|
|
38264
38849
|
if (statSync13(configPath, { throwIfNoEntry: false })?.isFile()) {
|
|
38265
38850
|
chmodSync5(tmpPath, statSync13(configPath).mode & 511);
|
|
38266
38851
|
}
|
|
38267
38852
|
} catch {}
|
|
38268
|
-
|
|
38853
|
+
renameSync8(tmpPath, configPath);
|
|
38269
38854
|
}
|
|
38270
38855
|
function resolveTuiConfigPath(configDirOverride) {
|
|
38271
38856
|
const configDir = configDirOverride ?? getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
|
|
38272
|
-
const jsoncPath =
|
|
38273
|
-
const jsonPath =
|
|
38274
|
-
if (
|
|
38857
|
+
const jsoncPath = join26(configDir, "tui.jsonc");
|
|
38858
|
+
const jsonPath = join26(configDir, "tui.json");
|
|
38859
|
+
if (existsSync32(jsoncPath))
|
|
38275
38860
|
return jsoncPath;
|
|
38276
|
-
if (
|
|
38861
|
+
if (existsSync32(jsonPath))
|
|
38277
38862
|
return jsonPath;
|
|
38278
38863
|
return jsoncPath;
|
|
38279
38864
|
}
|
|
@@ -38281,8 +38866,8 @@ function ensureTuiPluginEntry(options = {}) {
|
|
|
38281
38866
|
try {
|
|
38282
38867
|
const configPath = resolveTuiConfigPath(options.configDir);
|
|
38283
38868
|
let config = {};
|
|
38284
|
-
if (
|
|
38285
|
-
const raw =
|
|
38869
|
+
if (existsSync32(configPath)) {
|
|
38870
|
+
const raw = readFileSync22(configPath, "utf-8");
|
|
38286
38871
|
config = import_comment_json8.parse(raw) ?? {};
|
|
38287
38872
|
}
|
|
38288
38873
|
const plugins = Array.isArray(config.plugin) ? [...config.plugin] : [];
|
|
@@ -38316,7 +38901,7 @@ function ensureTuiPluginEntry(options = {}) {
|
|
|
38316
38901
|
}
|
|
38317
38902
|
}
|
|
38318
38903
|
config.plugin = plugins;
|
|
38319
|
-
|
|
38904
|
+
mkdirSync11(dirname16(configPath), { recursive: true });
|
|
38320
38905
|
writeTuiConfigAtomic(configPath, config);
|
|
38321
38906
|
log3(`[magic-context] updated TUI plugin entry in ${configPath}`);
|
|
38322
38907
|
return true;
|
|
@@ -38334,9 +38919,9 @@ var init_tui_config = __esm(() => {
|
|
|
38334
38919
|
});
|
|
38335
38920
|
|
|
38336
38921
|
// src/lib/diagnostics-opencode.ts
|
|
38337
|
-
import { existsSync as
|
|
38922
|
+
import { existsSync as existsSync33, readdirSync as readdirSync6, readFileSync as readFileSync23, statSync as statSync14 } from "node:fs";
|
|
38338
38923
|
import { createRequire as createRequire4 } from "node:module";
|
|
38339
|
-
import { join as
|
|
38924
|
+
import { join as join27 } from "node:path";
|
|
38340
38925
|
function getSelfVersion() {
|
|
38341
38926
|
const require2 = createRequire4(import.meta.url);
|
|
38342
38927
|
for (const relPath of ["../../package.json", "../package.json"]) {
|
|
@@ -38351,7 +38936,7 @@ function getSelfVersion() {
|
|
|
38351
38936
|
}
|
|
38352
38937
|
function readLegacyCachedVersion(root) {
|
|
38353
38938
|
try {
|
|
38354
|
-
const pkg = JSON.parse(
|
|
38939
|
+
const pkg = JSON.parse(readFileSync23(getOpenCodePluginPackageJsonPath(root), "utf-8"));
|
|
38355
38940
|
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
38356
38941
|
} catch {
|
|
38357
38942
|
return;
|
|
@@ -38360,7 +38945,7 @@ function readLegacyCachedVersion(root) {
|
|
|
38360
38945
|
function collectOpenCodePluginCacheReport(hostGeneration, opencodeConfig) {
|
|
38361
38946
|
const installs = [];
|
|
38362
38947
|
for (const root of getOpenCodePluginCacheRoots()) {
|
|
38363
|
-
if (!
|
|
38948
|
+
if (!existsSync33(root))
|
|
38364
38949
|
continue;
|
|
38365
38950
|
const spec = root.endsWith("@latest") ? "latest" : "(bare)";
|
|
38366
38951
|
installs.push({
|
|
@@ -38394,7 +38979,7 @@ function getStorageResolution() {
|
|
|
38394
38979
|
}
|
|
38395
38980
|
function fileSize(path) {
|
|
38396
38981
|
try {
|
|
38397
|
-
return
|
|
38982
|
+
return existsSync33(path) ? statSync14(path).size : 0;
|
|
38398
38983
|
} catch {
|
|
38399
38984
|
return 0;
|
|
38400
38985
|
}
|
|
@@ -38406,10 +38991,10 @@ function sanitizeValue(value) {
|
|
|
38406
38991
|
return sanitizeConfigValue(value);
|
|
38407
38992
|
}
|
|
38408
38993
|
function readConfig3(path) {
|
|
38409
|
-
if (!
|
|
38994
|
+
if (!existsSync33(path))
|
|
38410
38995
|
return { value: null };
|
|
38411
38996
|
try {
|
|
38412
|
-
const raw =
|
|
38997
|
+
const raw = readFileSync23(path, "utf-8");
|
|
38413
38998
|
const value = import_comment_json9.parse(raw);
|
|
38414
38999
|
return { value };
|
|
38415
39000
|
} catch (error) {
|
|
@@ -38434,7 +39019,7 @@ function configHasPluginEntry(config) {
|
|
|
38434
39019
|
}
|
|
38435
39020
|
function parseHistorianDumpMeta(path) {
|
|
38436
39021
|
try {
|
|
38437
|
-
const xml =
|
|
39022
|
+
const xml = readFileSync23(path, "utf-8");
|
|
38438
39023
|
const parsed = parseCompartmentOutput(xml);
|
|
38439
39024
|
const factCountByCategory = {};
|
|
38440
39025
|
for (const fact of parsed.facts) {
|
|
@@ -38467,11 +39052,11 @@ function parseHistorianDumpMeta(path) {
|
|
|
38467
39052
|
}
|
|
38468
39053
|
}
|
|
38469
39054
|
function listDumpsInDir(dir, limit) {
|
|
38470
|
-
if (!
|
|
39055
|
+
if (!existsSync33(dir))
|
|
38471
39056
|
return { count: 0, recent: [] };
|
|
38472
39057
|
try {
|
|
38473
|
-
const entries =
|
|
38474
|
-
const stat = statSync14(
|
|
39058
|
+
const entries = readdirSync6(dir).filter((name) => name.endsWith(".xml")).map((name) => {
|
|
39059
|
+
const stat = statSync14(join27(dir, name));
|
|
38475
39060
|
return {
|
|
38476
39061
|
name,
|
|
38477
39062
|
mtime: stat.mtimeMs,
|
|
@@ -38480,7 +39065,7 @@ function listDumpsInDir(dir, limit) {
|
|
|
38480
39065
|
}).sort((a, b) => b.mtime - a.mtime);
|
|
38481
39066
|
const now = Date.now();
|
|
38482
39067
|
const recent = entries.slice(0, limit).map((entry) => {
|
|
38483
|
-
const meta = parseHistorianDumpMeta(
|
|
39068
|
+
const meta = parseHistorianDumpMeta(join27(dir, entry.name));
|
|
38484
39069
|
const summary = {
|
|
38485
39070
|
name: entry.name,
|
|
38486
39071
|
ageMinutes: Math.round((now - entry.mtime) / 60000),
|
|
@@ -38618,8 +39203,8 @@ async function collectRecentSessions(resolution, hostGeneration) {
|
|
|
38618
39203
|
}
|
|
38619
39204
|
}
|
|
38620
39205
|
async function collectHistorianFailures(storageDirPath) {
|
|
38621
|
-
const contextDbPath =
|
|
38622
|
-
if (!
|
|
39206
|
+
const contextDbPath = join27(storageDirPath, "context.db");
|
|
39207
|
+
if (!existsSync33(contextDbPath))
|
|
38623
39208
|
return [];
|
|
38624
39209
|
if (typeof globalThis.Bun === "undefined") {
|
|
38625
39210
|
return [];
|
|
@@ -38652,8 +39237,8 @@ async function collectHistorianFailures(storageDirPath) {
|
|
|
38652
39237
|
}
|
|
38653
39238
|
}
|
|
38654
39239
|
async function collectHistorianRuns(storageDirPath) {
|
|
38655
|
-
const contextDbPath =
|
|
38656
|
-
if (!
|
|
39240
|
+
const contextDbPath = join27(storageDirPath, "context.db");
|
|
39241
|
+
if (!existsSync33(contextDbPath))
|
|
38657
39242
|
return [];
|
|
38658
39243
|
if (typeof globalThis.Bun === "undefined")
|
|
38659
39244
|
return [];
|
|
@@ -38726,7 +39311,7 @@ async function collectDiagnostics() {
|
|
|
38726
39311
|
const magicContextConfig = readConfig3(configPaths.magicContextConfig);
|
|
38727
39312
|
const storageResolution = getStorageResolution();
|
|
38728
39313
|
const storageDirPath = storageResolution.path;
|
|
38729
|
-
const contextDbPath =
|
|
39314
|
+
const contextDbPath = join27(storageDirPath, "context.db");
|
|
38730
39315
|
let compactionEnabled = false;
|
|
38731
39316
|
try {
|
|
38732
39317
|
compactionEnabled = isCompactionEnabled(loadPluginConfig(process.cwd()));
|
|
@@ -38758,7 +39343,7 @@ async function collectDiagnostics() {
|
|
|
38758
39343
|
opencodeConfigHasPlugin: configHasPluginEntry(opencodeConfig.value),
|
|
38759
39344
|
tuiConfigHasPlugin: configHasPluginEntry(tuiConfig.value),
|
|
38760
39345
|
magicContextConfig: {
|
|
38761
|
-
exists:
|
|
39346
|
+
exists: existsSync33(configPaths.magicContextConfig),
|
|
38762
39347
|
...magicContextConfig.error ? { parseError: magicContextConfig.error } : {},
|
|
38763
39348
|
flags: sanitizeValue(magicContextConfig.value ?? {}) ?? {}
|
|
38764
39349
|
},
|
|
@@ -38766,7 +39351,7 @@ async function collectDiagnostics() {
|
|
|
38766
39351
|
storageDir: {
|
|
38767
39352
|
path: storageDirPath,
|
|
38768
39353
|
source: storageResolution.source,
|
|
38769
|
-
exists:
|
|
39354
|
+
exists: existsSync33(storageDirPath),
|
|
38770
39355
|
contextDbSizeBytes: fileSize(contextDbPath)
|
|
38771
39356
|
},
|
|
38772
39357
|
openCodeDatabase: {
|
|
@@ -38999,9 +39584,9 @@ var init_embedding_local = __esm(() => {
|
|
|
38999
39584
|
|
|
39000
39585
|
// src/lib/embedding-runtime.ts
|
|
39001
39586
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
39002
|
-
import { existsSync as
|
|
39587
|
+
import { existsSync as existsSync34, readFileSync as readFileSync24 } from "node:fs";
|
|
39003
39588
|
import { createRequire as createRequire5 } from "node:module";
|
|
39004
|
-
import { dirname as
|
|
39589
|
+
import { dirname as dirname17, join as join28, sep } from "node:path";
|
|
39005
39590
|
function describeError(error) {
|
|
39006
39591
|
const message = error instanceof Error ? error.message : String(error ?? "unknown error");
|
|
39007
39592
|
const code = error?.code;
|
|
@@ -39009,6 +39594,7 @@ function describeError(error) {
|
|
|
39009
39594
|
}
|
|
39010
39595
|
function runOnnxRuntimeNodeLoadProbeChild(packageDir) {
|
|
39011
39596
|
return spawnSync7(process.execPath, ["-e", ONNX_RUNTIME_NODE_LOAD_PROBE_SCRIPT], {
|
|
39597
|
+
windowsHide: true,
|
|
39012
39598
|
encoding: "utf8",
|
|
39013
39599
|
env: { ...process.env, [ONNX_LOAD_PROBE_PACKAGE_DIR_ENV]: packageDir },
|
|
39014
39600
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -39142,11 +39728,11 @@ function expectedBinaryRelPath(platform, arch) {
|
|
|
39142
39728
|
const supportedArch = arch === "x64" || arch === "arm64";
|
|
39143
39729
|
if (!supportedPlatform || !supportedArch)
|
|
39144
39730
|
return null;
|
|
39145
|
-
return
|
|
39731
|
+
return join28("bin", "napi-v6", platform, arch, "onnxruntime_binding.node");
|
|
39146
39732
|
}
|
|
39147
39733
|
function onnxRuntimeNodeVersion(packageDir) {
|
|
39148
39734
|
try {
|
|
39149
|
-
const parsed = JSON.parse(
|
|
39735
|
+
const parsed = JSON.parse(readFileSync24(join28(packageDir, "package.json"), "utf8"));
|
|
39150
39736
|
return typeof parsed.version === "string" ? parsed.version : undefined;
|
|
39151
39737
|
} catch {
|
|
39152
39738
|
return;
|
|
@@ -39195,7 +39781,7 @@ function formatLocalEmbeddingRuntimeWasmSelected(status) {
|
|
|
39195
39781
|
function requireNodeWasmBundle(probe, candidates) {
|
|
39196
39782
|
if (probe.state === "failed")
|
|
39197
39783
|
return probe;
|
|
39198
|
-
const bundlePath = candidates.find((candidate) =>
|
|
39784
|
+
const bundlePath = candidates.find((candidate) => existsSync34(candidate));
|
|
39199
39785
|
return bundlePath ? probe : {
|
|
39200
39786
|
state: "failed",
|
|
39201
39787
|
reason: `functional Node WASM Transformers bundle is missing (checked ${candidates.join(", ")})`
|
|
@@ -39203,13 +39789,13 @@ function requireNodeWasmBundle(probe, candidates) {
|
|
|
39203
39789
|
}
|
|
39204
39790
|
function nodeWasmBundleCandidates(installRoot) {
|
|
39205
39791
|
return [
|
|
39206
|
-
|
|
39207
|
-
|
|
39208
|
-
|
|
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")
|
|
39209
39795
|
];
|
|
39210
39796
|
}
|
|
39211
39797
|
function probeWasmRuntimeAt(installRoot) {
|
|
39212
|
-
const requireFn = createRequire5(
|
|
39798
|
+
const requireFn = createRequire5(join28(installRoot, "package.json"));
|
|
39213
39799
|
return requireNodeWasmBundle(probeWasmRuntimeFromRequire(requireFn), nodeWasmBundleCandidates(installRoot));
|
|
39214
39800
|
}
|
|
39215
39801
|
function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
|
|
@@ -39218,9 +39804,9 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
|
|
|
39218
39804
|
const wasm = probeWasmRuntimeAt(installRoot);
|
|
39219
39805
|
return wasm.state === "ok" ? { state: "wasm-selected", wasmPath: wasm.wasmPath } : { state: "wasm-broken", wasmReason: wasm.reason };
|
|
39220
39806
|
}
|
|
39221
|
-
const packageDir =
|
|
39807
|
+
const packageDir = join28(installRoot, "node_modules", "onnxruntime-node");
|
|
39222
39808
|
let native;
|
|
39223
|
-
if (!
|
|
39809
|
+
if (!existsSync34(join28(packageDir, "package.json"))) {
|
|
39224
39810
|
native = { state: "package-missing", packageDir };
|
|
39225
39811
|
} else {
|
|
39226
39812
|
const rel = expectedBinaryRelPath(platform, arch);
|
|
@@ -39230,8 +39816,8 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
|
|
|
39230
39816
|
binaryPath: packageDir
|
|
39231
39817
|
};
|
|
39232
39818
|
} else {
|
|
39233
|
-
const binaryPath =
|
|
39234
|
-
native =
|
|
39819
|
+
const binaryPath = join28(packageDir, rel);
|
|
39820
|
+
native = existsSync34(binaryPath) ? probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath } : {
|
|
39235
39821
|
state: "binary-missing",
|
|
39236
39822
|
packageDir,
|
|
39237
39823
|
expectedBinary: binaryPath,
|
|
@@ -39242,7 +39828,7 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
|
|
|
39242
39828
|
return withWasmFallback(native, () => probeWasmRuntimeAt(installRoot));
|
|
39243
39829
|
}
|
|
39244
39830
|
function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
|
|
39245
|
-
const existing = installRoots.filter((root) =>
|
|
39831
|
+
const existing = installRoots.filter((root) => existsSync34(root));
|
|
39246
39832
|
if (existing.length === 0) {
|
|
39247
39833
|
return {
|
|
39248
39834
|
state: "unknown",
|
|
@@ -39268,19 +39854,19 @@ function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, a
|
|
|
39268
39854
|
function packageDirFromResolved(resolvedPath, packageName) {
|
|
39269
39855
|
const marker = `node_modules${sep}${packageName.split("/").join(sep)}`;
|
|
39270
39856
|
const idx = resolvedPath.indexOf(marker);
|
|
39271
|
-
return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) :
|
|
39857
|
+
return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) : dirname17(resolvedPath);
|
|
39272
39858
|
}
|
|
39273
39859
|
function probeWasmRuntimeByResolution(pluginDir) {
|
|
39274
39860
|
try {
|
|
39275
|
-
const reqPlugin = createRequire5(
|
|
39861
|
+
const reqPlugin = createRequire5(join28(pluginDir, "package.json"));
|
|
39276
39862
|
const direct = probeWasmRuntimeFromRequire(reqPlugin);
|
|
39277
39863
|
let probe = direct;
|
|
39278
39864
|
if (direct.state === "failed" && direct.reason.startsWith("onnxruntime-web is not resolvable")) {
|
|
39279
39865
|
const tfResolved = reqPlugin.resolve("@huggingface/transformers");
|
|
39280
39866
|
const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
|
|
39281
|
-
probe = probeWasmRuntimeFromRequire(createRequire5(
|
|
39867
|
+
probe = probeWasmRuntimeFromRequire(createRequire5(join28(tfDir, "package.json")));
|
|
39282
39868
|
}
|
|
39283
|
-
return requireNodeWasmBundle(probe, [
|
|
39869
|
+
return requireNodeWasmBundle(probe, [join28(pluginDir, "dist", "transformers-node-wasm.js")]);
|
|
39284
39870
|
} catch (error) {
|
|
39285
39871
|
return {
|
|
39286
39872
|
state: "failed",
|
|
@@ -39289,7 +39875,7 @@ function probeWasmRuntimeByResolution(pluginDir) {
|
|
|
39289
39875
|
}
|
|
39290
39876
|
}
|
|
39291
39877
|
function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
|
|
39292
|
-
if (!
|
|
39878
|
+
if (!existsSync34(join28(pluginDir, "package.json"))) {
|
|
39293
39879
|
return { state: "unknown", reason: "plugin package dir not found" };
|
|
39294
39880
|
}
|
|
39295
39881
|
const selectedRuntime = resolveLocalEmbeddingRuntime(runtimePreference, host);
|
|
@@ -39300,13 +39886,13 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
|
|
|
39300
39886
|
let onnxDir = null;
|
|
39301
39887
|
let resolveError;
|
|
39302
39888
|
try {
|
|
39303
|
-
const reqPlugin = createRequire5(
|
|
39889
|
+
const reqPlugin = createRequire5(join28(pluginDir, "package.json"));
|
|
39304
39890
|
try {
|
|
39305
39891
|
onnxDir = packageDirFromResolved(reqPlugin.resolve("onnxruntime-node"), "onnxruntime-node");
|
|
39306
39892
|
} catch {
|
|
39307
39893
|
const tfResolved = reqPlugin.resolve("@huggingface/transformers");
|
|
39308
39894
|
const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
|
|
39309
|
-
const reqTf = createRequire5(
|
|
39895
|
+
const reqTf = createRequire5(join28(tfDir, "package.json"));
|
|
39310
39896
|
onnxDir = packageDirFromResolved(reqTf.resolve("onnxruntime-node"), "onnxruntime-node");
|
|
39311
39897
|
}
|
|
39312
39898
|
} catch (error) {
|
|
@@ -39314,7 +39900,7 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
|
|
|
39314
39900
|
if (resolveError === "ERR_MODULE_NOT_FOUND" || resolveError === "MODULE_NOT_FOUND") {
|
|
39315
39901
|
return withWasmFallback({
|
|
39316
39902
|
state: "package-missing",
|
|
39317
|
-
packageDir:
|
|
39903
|
+
packageDir: join28(pluginDir, "node_modules", "onnxruntime-node")
|
|
39318
39904
|
}, () => probeWasmRuntimeByResolution(pluginDir));
|
|
39319
39905
|
}
|
|
39320
39906
|
return {
|
|
@@ -39330,8 +39916,8 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
|
|
|
39330
39916
|
if (rel === null) {
|
|
39331
39917
|
native = probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath: onnxDir };
|
|
39332
39918
|
} else {
|
|
39333
|
-
const binaryPath =
|
|
39334
|
-
native =
|
|
39919
|
+
const binaryPath = join28(onnxDir, rel);
|
|
39920
|
+
native = existsSync34(binaryPath) ? probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath } : {
|
|
39335
39921
|
state: "binary-missing",
|
|
39336
39922
|
packageDir: onnxDir,
|
|
39337
39923
|
expectedBinary: binaryPath,
|
|
@@ -39473,8 +40059,8 @@ var init_issue_body = __esm(() => {
|
|
|
39473
40059
|
});
|
|
39474
40060
|
|
|
39475
40061
|
// src/lib/logs-opencode.ts
|
|
39476
|
-
import { writeFileSync as
|
|
39477
|
-
import { join as
|
|
40062
|
+
import { writeFileSync as writeFileSync9 } from "node:fs";
|
|
40063
|
+
import { join as join29 } from "node:path";
|
|
39478
40064
|
function sanitizeLogContent(content) {
|
|
39479
40065
|
return sanitizeDiagnosticText(content);
|
|
39480
40066
|
}
|
|
@@ -39581,12 +40167,12 @@ async function bundleIssueReport(report, description, title, sessionFilter = nul
|
|
|
39581
40167
|
const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
|
|
39582
40168
|
const truncated = bodyMarkdown !== rawBodyMarkdown;
|
|
39583
40169
|
const timestamp = formatTimestamp(new Date);
|
|
39584
|
-
const path =
|
|
39585
|
-
|
|
40170
|
+
const path = join29(process.cwd(), `magic-context-issue-${timestamp}.md`);
|
|
40171
|
+
writeFileSync9(path, `${bodyMarkdown}
|
|
39586
40172
|
`);
|
|
39587
|
-
const fullPath = truncated ?
|
|
40173
|
+
const fullPath = truncated ? join29(process.cwd(), `magic-context-issue-${timestamp}-full.md`) : undefined;
|
|
39588
40174
|
if (fullPath)
|
|
39589
|
-
|
|
40175
|
+
writeFileSync9(fullPath, `${rawBodyMarkdown}
|
|
39590
40176
|
`);
|
|
39591
40177
|
return { path, bodyMarkdown, ...fullPath ? { fullPath } : {}, truncated };
|
|
39592
40178
|
}
|
|
@@ -39850,25 +40436,25 @@ function migrateExperimentalPinKeyFilesForDoctor(mcConfig) {
|
|
|
39850
40436
|
}
|
|
39851
40437
|
|
|
39852
40438
|
// ../plugin/src/hooks/auto-update-checker/constants.ts
|
|
39853
|
-
import { homedir as
|
|
39854
|
-
import { join as
|
|
40439
|
+
import { homedir as homedir16, platform } from "node:os";
|
|
40440
|
+
import { join as join30 } from "node:path";
|
|
39855
40441
|
function getOpenCodeCacheRoot() {
|
|
39856
40442
|
if (platform() === "win32") {
|
|
39857
|
-
return
|
|
40443
|
+
return join30(process.env.LOCALAPPDATA ?? homedir16(), "opencode");
|
|
39858
40444
|
}
|
|
39859
|
-
return
|
|
40445
|
+
return join30(homedir16(), ".cache", "opencode");
|
|
39860
40446
|
}
|
|
39861
40447
|
function getOpenCodeConfigRoot() {
|
|
39862
40448
|
if (platform() === "win32") {
|
|
39863
|
-
return
|
|
40449
|
+
return join30(process.env.APPDATA ?? join30(homedir16(), "AppData", "Roaming"), "opencode");
|
|
39864
40450
|
}
|
|
39865
|
-
return
|
|
40451
|
+
return join30(process.env.XDG_CONFIG_HOME ?? join30(homedir16(), ".config"), "opencode");
|
|
39866
40452
|
}
|
|
39867
40453
|
var PACKAGE_NAME = "@cortexkit/opencode-magic-context", CACHE_DIR, USER_OPENCODE_CONFIG, USER_OPENCODE_CONFIG_JSONC;
|
|
39868
40454
|
var init_constants2 = __esm(() => {
|
|
39869
|
-
CACHE_DIR =
|
|
39870
|
-
USER_OPENCODE_CONFIG =
|
|
39871
|
-
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");
|
|
39872
40458
|
});
|
|
39873
40459
|
|
|
39874
40460
|
// ../plugin/src/hooks/auto-update-checker/types.ts
|
|
@@ -39892,14 +40478,14 @@ var init_types = __esm(() => {
|
|
|
39892
40478
|
// ../plugin/src/hooks/auto-update-checker/checker.ts
|
|
39893
40479
|
import {
|
|
39894
40480
|
accessSync as accessSync2,
|
|
39895
|
-
existsSync as
|
|
40481
|
+
existsSync as existsSync35,
|
|
39896
40482
|
constants as fsConstants,
|
|
39897
|
-
readFileSync as
|
|
39898
|
-
renameSync as
|
|
40483
|
+
readFileSync as readFileSync25,
|
|
40484
|
+
renameSync as renameSync9,
|
|
39899
40485
|
statSync as statSync15,
|
|
39900
|
-
writeFileSync as
|
|
40486
|
+
writeFileSync as writeFileSync10
|
|
39901
40487
|
} from "node:fs";
|
|
39902
|
-
import { dirname as
|
|
40488
|
+
import { dirname as dirname18, isAbsolute as isAbsolute7, join as join31, resolve as resolve9 } from "node:path";
|
|
39903
40489
|
function warn(message) {
|
|
39904
40490
|
log3(`WARN: ${message}`);
|
|
39905
40491
|
}
|
|
@@ -39925,17 +40511,17 @@ function parseJsonConfig(content) {
|
|
|
39925
40511
|
}
|
|
39926
40512
|
function getSurfaceConfigPaths(directory, surface) {
|
|
39927
40513
|
const name = surface === "server" ? "opencode" : "tui";
|
|
39928
|
-
const globalDir =
|
|
40514
|
+
const globalDir = dirname18(USER_OPENCODE_CONFIG);
|
|
39929
40515
|
const dirs = [
|
|
39930
40516
|
globalDir,
|
|
39931
40517
|
directory,
|
|
39932
|
-
|
|
40518
|
+
join31(directory, ".opencode"),
|
|
39933
40519
|
process.env.OPENCODE_CONFIG_DIR
|
|
39934
40520
|
].filter((value) => Boolean(value));
|
|
39935
40521
|
const paths = [];
|
|
39936
40522
|
for (const dir of dirs) {
|
|
39937
40523
|
for (const extension of ["json", "jsonc"]) {
|
|
39938
|
-
const path =
|
|
40524
|
+
const path = join31(dir, `${name}.${extension}`);
|
|
39939
40525
|
if (!paths.includes(path))
|
|
39940
40526
|
paths.push(path);
|
|
39941
40527
|
}
|
|
@@ -39946,9 +40532,9 @@ function getWinningConfig(directory, surface) {
|
|
|
39946
40532
|
let winner = null;
|
|
39947
40533
|
for (const path of getSurfaceConfigPaths(directory, surface)) {
|
|
39948
40534
|
try {
|
|
39949
|
-
if (!
|
|
40535
|
+
if (!existsSync35(path))
|
|
39950
40536
|
continue;
|
|
39951
|
-
const parsed = parseJsonConfig(
|
|
40537
|
+
const parsed = parseJsonConfig(readFileSync25(path, "utf-8"));
|
|
39952
40538
|
const entries = getPluginEntries(parsed);
|
|
39953
40539
|
if (entries.some((entry) => entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))) {
|
|
39954
40540
|
if (winner) {
|
|
@@ -39984,14 +40570,14 @@ var init_checker = __esm(() => {
|
|
|
39984
40570
|
});
|
|
39985
40571
|
|
|
39986
40572
|
// src/lib/opencode-plugin-schema-fence.ts
|
|
39987
|
-
import { existsSync as
|
|
39988
|
-
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";
|
|
39989
40575
|
import { gunzipSync } from "node:zlib";
|
|
39990
40576
|
function readPackageVersion(packageJsonPath) {
|
|
39991
40577
|
try {
|
|
39992
|
-
if (!
|
|
40578
|
+
if (!existsSync36(packageJsonPath))
|
|
39993
40579
|
return null;
|
|
39994
|
-
const packageJson = JSON.parse(
|
|
40580
|
+
const packageJson = JSON.parse(readFileSync26(packageJsonPath, "utf-8"));
|
|
39995
40581
|
if (packageJson.name !== OPENCODE_PLUGIN_NAME || typeof packageJson.version !== "string") {
|
|
39996
40582
|
return null;
|
|
39997
40583
|
}
|
|
@@ -40010,8 +40596,8 @@ function readFenceValue(text) {
|
|
|
40010
40596
|
return values.size === 1 ? [...values][0] ?? null : null;
|
|
40011
40597
|
}
|
|
40012
40598
|
function readFenceFromDist(packageDirectory) {
|
|
40013
|
-
const distDirectory =
|
|
40014
|
-
if (!
|
|
40599
|
+
const distDirectory = join32(packageDirectory, "dist");
|
|
40600
|
+
if (!existsSync36(distDirectory))
|
|
40015
40601
|
return null;
|
|
40016
40602
|
const pending = [distDirectory];
|
|
40017
40603
|
const fenceValues = new Set;
|
|
@@ -40020,15 +40606,15 @@ function readFenceFromDist(packageDirectory) {
|
|
|
40020
40606
|
if (!directory)
|
|
40021
40607
|
continue;
|
|
40022
40608
|
try {
|
|
40023
|
-
for (const entry of
|
|
40024
|
-
const path =
|
|
40609
|
+
for (const entry of readdirSync7(directory, { withFileTypes: true })) {
|
|
40610
|
+
const path = join32(directory, entry.name);
|
|
40025
40611
|
if (entry.isDirectory()) {
|
|
40026
40612
|
pending.push(path);
|
|
40027
40613
|
continue;
|
|
40028
40614
|
}
|
|
40029
40615
|
if (!entry.isFile() || !/\.(?:[cm]?js|ts)$/.test(entry.name))
|
|
40030
40616
|
continue;
|
|
40031
|
-
const fence = readFenceValue(
|
|
40617
|
+
const fence = readFenceValue(readFileSync26(path, "utf-8"));
|
|
40032
40618
|
if (fence !== null)
|
|
40033
40619
|
fenceValues.add(fence);
|
|
40034
40620
|
}
|
|
@@ -40039,20 +40625,20 @@ function readFenceFromDist(packageDirectory) {
|
|
|
40039
40625
|
return fenceValues.size === 1 ? [...fenceValues][0] ?? null : null;
|
|
40040
40626
|
}
|
|
40041
40627
|
function findInstalledPluginPackage(cacheDirectory, specifier, requestedVersion) {
|
|
40042
|
-
const directCacheRoot =
|
|
40628
|
+
const directCacheRoot = join32(cacheDirectory, specifier);
|
|
40043
40629
|
const candidates = [directCacheRoot];
|
|
40044
40630
|
try {
|
|
40045
|
-
for (const entry of
|
|
40631
|
+
for (const entry of readdirSync7(cacheDirectory, { withFileTypes: true })) {
|
|
40046
40632
|
if (!entry.isDirectory())
|
|
40047
40633
|
continue;
|
|
40048
|
-
const candidate =
|
|
40634
|
+
const candidate = join32(cacheDirectory, entry.name);
|
|
40049
40635
|
if (!candidates.includes(candidate))
|
|
40050
40636
|
candidates.push(candidate);
|
|
40051
40637
|
}
|
|
40052
40638
|
} catch {}
|
|
40053
40639
|
for (const cacheRoot of candidates) {
|
|
40054
|
-
const directory =
|
|
40055
|
-
const version = readPackageVersion(
|
|
40640
|
+
const directory = join32(cacheRoot, "node_modules", ...PACKAGE_PATH_SEGMENTS);
|
|
40641
|
+
const version = readPackageVersion(join32(directory, "package.json"));
|
|
40056
40642
|
if (!version)
|
|
40057
40643
|
continue;
|
|
40058
40644
|
if (cacheRoot === directCacheRoot || EXACT_VERSION_PATTERN.test(requestedVersion) && version === requestedVersion) {
|
|
@@ -40246,13 +40832,13 @@ var init_storage_versions = __esm(async () => {
|
|
|
40246
40832
|
});
|
|
40247
40833
|
|
|
40248
40834
|
// src/commands/doctor-opencode-cache.ts
|
|
40249
|
-
import { existsSync as
|
|
40835
|
+
import { existsSync as existsSync37, readFileSync as readFileSync27, rmSync as rmSync4 } from "node:fs";
|
|
40250
40836
|
function readCachedPluginVersion(pluginCacheDir) {
|
|
40251
40837
|
try {
|
|
40252
40838
|
const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
|
|
40253
|
-
if (!
|
|
40839
|
+
if (!existsSync37(installedPkgPath))
|
|
40254
40840
|
return;
|
|
40255
|
-
const pkg = JSON.parse(
|
|
40841
|
+
const pkg = JSON.parse(readFileSync27(installedPkgPath, "utf-8"));
|
|
40256
40842
|
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
40257
40843
|
} catch {
|
|
40258
40844
|
return;
|
|
@@ -40261,7 +40847,7 @@ function readCachedPluginVersion(pluginCacheDir) {
|
|
|
40261
40847
|
async function clearPluginCache(options = {}, deps = {}) {
|
|
40262
40848
|
const remove = deps.remove ?? ((path) => rmSync4(path, { recursive: true, force: true }));
|
|
40263
40849
|
const pluginCacheRoots = getOpenCodePluginCacheRoots();
|
|
40264
|
-
const existingRoots = pluginCacheRoots.filter((root) =>
|
|
40850
|
+
const existingRoots = pluginCacheRoots.filter((root) => existsSync37(root));
|
|
40265
40851
|
if (existingRoots.length === 0) {
|
|
40266
40852
|
return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
|
|
40267
40853
|
}
|
|
@@ -40328,19 +40914,19 @@ var init_doctor_opencode_cache = __esm(() => {
|
|
|
40328
40914
|
});
|
|
40329
40915
|
|
|
40330
40916
|
// src/commands/doctor-cached-plugin-fence.ts
|
|
40331
|
-
import { existsSync as
|
|
40332
|
-
import { dirname as
|
|
40917
|
+
import { existsSync as existsSync38 } from "node:fs";
|
|
40918
|
+
import { dirname as dirname19 } from "node:path";
|
|
40333
40919
|
function listCachedOpenCodePluginFences(sources = {}) {
|
|
40334
40920
|
const fences = [];
|
|
40335
40921
|
for (const root of sources.openCodeV1Roots ?? getOpenCodePluginCacheRoots()) {
|
|
40336
40922
|
const packageJson = getOpenCodePluginPackageJsonPath(root);
|
|
40337
|
-
if (!
|
|
40923
|
+
if (!existsSync38(packageJson))
|
|
40338
40924
|
continue;
|
|
40339
40925
|
fences.push({
|
|
40340
40926
|
host: "opencode1",
|
|
40341
40927
|
directory: root,
|
|
40342
40928
|
version: readCachedPluginVersion(root),
|
|
40343
|
-
supportedVersion: readFenceFromDist(
|
|
40929
|
+
supportedVersion: readFenceFromDist(dirname19(packageJson))
|
|
40344
40930
|
});
|
|
40345
40931
|
}
|
|
40346
40932
|
for (const slot of listOpenCodeV2PluginCacheSlots(sources.openCodeV2NpmCacheDir)) {
|
|
@@ -40354,7 +40940,7 @@ function listCachedOpenCodePluginFences(sources = {}) {
|
|
|
40354
40940
|
directory: slot.slot,
|
|
40355
40941
|
spec: slot.spec,
|
|
40356
40942
|
version: slot.version,
|
|
40357
|
-
supportedVersion: readFenceFromDist(
|
|
40943
|
+
supportedVersion: readFenceFromDist(dirname19(getOpenCodePluginPackageJsonPath(generation)))
|
|
40358
40944
|
});
|
|
40359
40945
|
}
|
|
40360
40946
|
return fences;
|
|
@@ -40429,11 +41015,11 @@ function mcMarkerPredicate(column = "data") {
|
|
|
40429
41015
|
AND json_extract(${data}, '$.summary') = 1
|
|
40430
41016
|
AND json_extract(${data}, '$.providerID') = 'magic-context'`;
|
|
40431
41017
|
}
|
|
40432
|
-
function
|
|
41018
|
+
function tableExists5(db, table) {
|
|
40433
41019
|
return db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ? LIMIT 1").get(table) != null;
|
|
40434
41020
|
}
|
|
40435
41021
|
function countMissingCompleted(db) {
|
|
40436
|
-
if (!
|
|
41022
|
+
if (!tableExists5(db, "message"))
|
|
40437
41023
|
return 0;
|
|
40438
41024
|
const row = db.prepare(`SELECT COUNT(*) AS count
|
|
40439
41025
|
FROM message
|
|
@@ -40442,7 +41028,7 @@ function countMissingCompleted(db) {
|
|
|
40442
41028
|
return Number(row?.count ?? 0);
|
|
40443
41029
|
}
|
|
40444
41030
|
function migrationV1ToV2Completed(db) {
|
|
40445
|
-
if (!
|
|
41031
|
+
if (!tableExists5(db, "kv"))
|
|
40446
41032
|
return false;
|
|
40447
41033
|
const columns = db.prepare("PRAGMA table_info(kv)").all();
|
|
40448
41034
|
const names = new Set(columns.flatMap((column) => typeof column.name === "string" ? [column.name] : []));
|
|
@@ -40459,7 +41045,7 @@ function migrationV1ToV2Completed(db) {
|
|
|
40459
41045
|
}
|
|
40460
41046
|
}
|
|
40461
41047
|
function countUnmatchedConvertedMarkers(db, migratedV2Schema) {
|
|
40462
|
-
if (!migratedV2Schema || !
|
|
41048
|
+
if (!migratedV2Schema || !tableExists5(db, "message"))
|
|
40463
41049
|
return 0;
|
|
40464
41050
|
const row = db.prepare(`SELECT COUNT(DISTINCT json_extract(${safeData("marker.data")}, '$.parentID')) AS count
|
|
40465
41051
|
FROM message marker
|
|
@@ -40474,7 +41060,7 @@ function countUnmatchedConvertedMarkers(db, migratedV2Schema) {
|
|
|
40474
41060
|
return Number(row?.count ?? 0);
|
|
40475
41061
|
}
|
|
40476
41062
|
function countPostConversionMessages(db, migratedV2Schema) {
|
|
40477
|
-
if (!migratedV2Schema || !
|
|
41063
|
+
if (!migratedV2Schema || !tableExists5(db, "message") || !tableExists5(db, "session")) {
|
|
40478
41064
|
return { messages: 0, sessions: 0 };
|
|
40479
41065
|
}
|
|
40480
41066
|
const row = db.prepare(`SELECT COUNT(*) AS messages, COUNT(DISTINCT converted.session_id) AS sessions
|
|
@@ -40491,7 +41077,7 @@ function countPostConversionMessages(db, migratedV2Schema) {
|
|
|
40491
41077
|
function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
|
|
40492
41078
|
const missingBefore = countMissingCompleted(db);
|
|
40493
41079
|
let repaired = 0;
|
|
40494
|
-
if (options.fix && missingBefore > 0 &&
|
|
41080
|
+
if (options.fix && missingBefore > 0 && tableExists5(db, "message")) {
|
|
40495
41081
|
repaired = db.transaction(() => {
|
|
40496
41082
|
const result = db.prepare(`UPDATE message
|
|
40497
41083
|
SET data = json_set(
|
|
@@ -40505,7 +41091,7 @@ function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
|
|
|
40505
41091
|
})();
|
|
40506
41092
|
}
|
|
40507
41093
|
const missingAfter = countMissingCompleted(db);
|
|
40508
|
-
const migratedV2Schema =
|
|
41094
|
+
const migratedV2Schema = tableExists5(db, "session_v2") && tableExists5(db, "session_message");
|
|
40509
41095
|
const migrationCompleted = migrationV1ToV2Completed(db);
|
|
40510
41096
|
const unmatchedConvertedMarkers = countUnmatchedConvertedMarkers(db, migratedV2Schema);
|
|
40511
41097
|
const postConversion = countPostConversionMessages(db, migratedV2Schema);
|
|
@@ -40616,6 +41202,182 @@ var init_doctor_harness_relabel = __esm(async () => {
|
|
|
40616
41202
|
await init_opencode2_relabel();
|
|
40617
41203
|
});
|
|
40618
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
|
+
|
|
40619
41381
|
// src/commands/doctor-opencode-plugin-duplicates.ts
|
|
40620
41382
|
import { isDeepStrictEqual } from "node:util";
|
|
40621
41383
|
function entryOptions(entry) {
|
|
@@ -40842,11 +41604,11 @@ function formatUnresolvedCompartmentSession(session) {
|
|
|
40842
41604
|
}
|
|
40843
41605
|
|
|
40844
41606
|
// src/commands/doctor-opencode.ts
|
|
40845
|
-
import { spawnSync as
|
|
40846
|
-
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";
|
|
40847
41609
|
import { createRequire as createRequire6 } from "node:module";
|
|
40848
|
-
import { homedir as
|
|
40849
|
-
import { join as
|
|
41610
|
+
import { homedir as homedir17, tmpdir as tmpdir3 } from "node:os";
|
|
41611
|
+
import { join as join33 } from "node:path";
|
|
40850
41612
|
function formatSharedDbRowCounts(db) {
|
|
40851
41613
|
return SHARED_DB_ROW_COUNT_TABLES.map((table) => {
|
|
40852
41614
|
try {
|
|
@@ -40877,7 +41639,8 @@ function findUnknownConfiguredModels(configured, catalog) {
|
|
|
40877
41639
|
return [];
|
|
40878
41640
|
});
|
|
40879
41641
|
}
|
|
40880
|
-
function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args, cwd) =>
|
|
41642
|
+
function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args, cwd) => spawnSync9("opencode", args, {
|
|
41643
|
+
windowsHide: true,
|
|
40881
41644
|
cwd,
|
|
40882
41645
|
encoding: "utf8",
|
|
40883
41646
|
timeout: hostGeneration === "v2" ? 90000 : 45000,
|
|
@@ -40914,7 +41677,7 @@ function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args
|
|
|
40914
41677
|
}
|
|
40915
41678
|
if (models.length === 0)
|
|
40916
41679
|
return;
|
|
40917
|
-
const tempRoot =
|
|
41680
|
+
const tempRoot = mkdtempSync2(join33(tmpdir3(), "magic-context-opencode-catalog-"));
|
|
40918
41681
|
try {
|
|
40919
41682
|
const command = hostGeneration === "v2" ? ["api", "model.list", "--param", `directory=${projectDir}`] : ["models", "--verbose"];
|
|
40920
41683
|
const guidance = `opencode ${command.join(" ")}`;
|
|
@@ -41090,7 +41853,7 @@ function getSelfVersion2() {
|
|
|
41090
41853
|
function describeAutoUpdateStall(specifier, autoUpdateEnabled, storageDir = getMagicContextStorageDir()) {
|
|
41091
41854
|
if (!autoUpdateEnabled || !isPinnedOpenCodePluginSpecifier(specifier))
|
|
41092
41855
|
return null;
|
|
41093
|
-
const state = readAutoUpdateCheckState(
|
|
41856
|
+
const state = readAutoUpdateCheckState(join33(storageDir, AUTO_UPDATE_CHECK_STATE_FILENAME));
|
|
41094
41857
|
const owner = isUpdaterPinnedSpec(state, specifier) ? "updater" : "you";
|
|
41095
41858
|
return `auto-update: stalled — config pinned to ${specifier} (by ${owner})`;
|
|
41096
41859
|
}
|
|
@@ -41099,15 +41862,15 @@ function getUserNpmrcPath() {
|
|
|
41099
41862
|
if (custom)
|
|
41100
41863
|
return custom;
|
|
41101
41864
|
const home = process.env.HOME?.trim();
|
|
41102
|
-
return
|
|
41865
|
+
return join33(home || homedir17(), ".npmrc");
|
|
41103
41866
|
}
|
|
41104
41867
|
function collectNpmReleaseAgeWarnings() {
|
|
41105
41868
|
const ageWarnings = [];
|
|
41106
41869
|
const npmrcPath = getUserNpmrcPath();
|
|
41107
|
-
if (!
|
|
41870
|
+
if (!existsSync40(npmrcPath))
|
|
41108
41871
|
return ageWarnings;
|
|
41109
41872
|
try {
|
|
41110
|
-
const npmrc =
|
|
41873
|
+
const npmrc = readFileSync28(npmrcPath, "utf-8");
|
|
41111
41874
|
for (const line of npmrc.split(`
|
|
41112
41875
|
`)) {
|
|
41113
41876
|
const trimmed = line.trim();
|
|
@@ -41140,15 +41903,18 @@ function compareVersions(a, b) {
|
|
|
41140
41903
|
function openBrowser(url) {
|
|
41141
41904
|
try {
|
|
41142
41905
|
if (process.platform === "darwin") {
|
|
41143
|
-
const child =
|
|
41906
|
+
const child = spawnSync9("open", [url], { windowsHide: true, stdio: "ignore" });
|
|
41144
41907
|
if (child.status === 0)
|
|
41145
41908
|
return;
|
|
41146
41909
|
} else if (process.platform === "linux") {
|
|
41147
|
-
const child =
|
|
41910
|
+
const child = spawnSync9("xdg-open", [url], { windowsHide: true, stdio: "ignore" });
|
|
41148
41911
|
if (child.status === 0)
|
|
41149
41912
|
return;
|
|
41150
41913
|
} else if (process.platform === "win32") {
|
|
41151
|
-
const child =
|
|
41914
|
+
const child = spawnSync9("cmd", ["/c", "start", "", url], {
|
|
41915
|
+
windowsHide: true,
|
|
41916
|
+
stdio: "ignore"
|
|
41917
|
+
});
|
|
41152
41918
|
if (child.status === 0)
|
|
41153
41919
|
return;
|
|
41154
41920
|
}
|
|
@@ -41241,7 +42007,7 @@ function checkLocalEmbeddingRuntimeForDoctor(runtimePreference = "auto") {
|
|
|
41241
42007
|
return { issues: 0 };
|
|
41242
42008
|
}
|
|
41243
42009
|
async function checkEmbeddingConfig(magicContextConfigPath) {
|
|
41244
|
-
if (!
|
|
42010
|
+
if (!existsSync40(magicContextConfigPath)) {
|
|
41245
42011
|
return checkLocalEmbeddingRuntimeForDoctor();
|
|
41246
42012
|
}
|
|
41247
42013
|
let rawText;
|
|
@@ -41398,7 +42164,7 @@ async function runDoctor2(options = {}) {
|
|
|
41398
42164
|
const v22Result = await runV22BackfillCommands({
|
|
41399
42165
|
name: "OpenCode",
|
|
41400
42166
|
openDatabase: (readonly = true) => {
|
|
41401
|
-
const dbPath =
|
|
42167
|
+
const dbPath = join33(getMagicContextStorageDir(), "context.db");
|
|
41402
42168
|
v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
|
|
41403
42169
|
return v22Db;
|
|
41404
42170
|
},
|
|
@@ -41430,7 +42196,7 @@ async function runDoctor2(options = {}) {
|
|
|
41430
42196
|
failCount++;
|
|
41431
42197
|
issues++;
|
|
41432
42198
|
};
|
|
41433
|
-
const authorityDbPath =
|
|
42199
|
+
const authorityDbPath = join33(getMagicContextStorageDir(), "context.db");
|
|
41434
42200
|
let authorityDb = null;
|
|
41435
42201
|
try {
|
|
41436
42202
|
authorityDb = openExistingContextDatabase(authorityDbPath, { readonly: true });
|
|
@@ -41484,6 +42250,19 @@ async function runDoctor2(options = {}) {
|
|
|
41484
42250
|
else
|
|
41485
42251
|
fail(openCodeDbCheck.message);
|
|
41486
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
|
+
}
|
|
41487
42266
|
let markerDb = null;
|
|
41488
42267
|
try {
|
|
41489
42268
|
markerDb = new Database(openCodeDbResolution.path, {
|
|
@@ -41591,7 +42370,7 @@ async function runDoctor2(options = {}) {
|
|
|
41591
42370
|
pass(`OpenCode config: ${paths.opencodeConfig}`);
|
|
41592
42371
|
}
|
|
41593
42372
|
let autoUpdateEnabled = true;
|
|
41594
|
-
if (
|
|
42373
|
+
if (existsSync40(paths.magicContextConfig)) {
|
|
41595
42374
|
pass(`Magic Context config: ${paths.magicContextConfig}`);
|
|
41596
42375
|
try {
|
|
41597
42376
|
const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
|
|
@@ -41627,7 +42406,7 @@ async function runDoctor2(options = {}) {
|
|
|
41627
42406
|
warn(`No magic-context.jsonc found — using defaults`);
|
|
41628
42407
|
log2.info(" Run 'setup' to create one with model recommendations");
|
|
41629
42408
|
}
|
|
41630
|
-
if (
|
|
42409
|
+
if (existsSync40(paths.magicContextConfig)) {
|
|
41631
42410
|
try {
|
|
41632
42411
|
const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
|
|
41633
42412
|
if (!raw)
|
|
@@ -41757,7 +42536,7 @@ async function runDoctor2(options = {}) {
|
|
|
41757
42536
|
};
|
|
41758
42537
|
if (paths.opencodeConfigFormat !== "none") {
|
|
41759
42538
|
try {
|
|
41760
|
-
const raw =
|
|
42539
|
+
const raw = readFileSync28(paths.opencodeConfig, "utf-8");
|
|
41761
42540
|
const config = import_comment_json11.parse(raw);
|
|
41762
42541
|
const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
|
|
41763
42542
|
if (checkPluginDuplicates(config, configName, options, {
|
|
@@ -41826,9 +42605,9 @@ async function runDoctor2(options = {}) {
|
|
|
41826
42605
|
pass("Added TUI sidebar plugin to tui.json");
|
|
41827
42606
|
warn("Restart OpenCode to see the sidebar");
|
|
41828
42607
|
fixed++;
|
|
41829
|
-
} else if (
|
|
42608
|
+
} else if (existsSync40(paths.tuiConfig)) {
|
|
41830
42609
|
try {
|
|
41831
|
-
const tuiRaw =
|
|
42610
|
+
const tuiRaw = readFileSync28(paths.tuiConfig, "utf-8");
|
|
41832
42611
|
const tuiConfig = import_comment_json11.parse(tuiRaw);
|
|
41833
42612
|
const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
|
|
41834
42613
|
const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
|
|
@@ -41866,7 +42645,7 @@ async function runDoctor2(options = {}) {
|
|
|
41866
42645
|
fail("Could not create or verify the TUI sidebar config");
|
|
41867
42646
|
}
|
|
41868
42647
|
}
|
|
41869
|
-
if (
|
|
42648
|
+
if (existsSync40(paths.magicContextConfig)) {
|
|
41870
42649
|
try {
|
|
41871
42650
|
const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
|
|
41872
42651
|
if (!raw)
|
|
@@ -41888,9 +42667,9 @@ async function runDoctor2(options = {}) {
|
|
|
41888
42667
|
else
|
|
41889
42668
|
passCount++;
|
|
41890
42669
|
const storage = getMagicContextStorageResolution();
|
|
41891
|
-
const dbPath =
|
|
42670
|
+
const dbPath = join33(storage.path, "context.db");
|
|
41892
42671
|
log2.info(`Shared storage: ${storage.path} (source: ${storage.source})`);
|
|
41893
|
-
if (!
|
|
42672
|
+
if (!existsSync40(dbPath)) {
|
|
41894
42673
|
log2.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
|
|
41895
42674
|
} else {
|
|
41896
42675
|
log2.info(`Shared context DB exists at ${dbPath}`);
|
|
@@ -41992,7 +42771,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
41992
42771
|
let v2DistTag;
|
|
41993
42772
|
if (paths.opencodeConfigFormat !== "none") {
|
|
41994
42773
|
try {
|
|
41995
|
-
v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(
|
|
42774
|
+
v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(readFileSync28(paths.opencodeConfig, "utf-8")));
|
|
41996
42775
|
} catch {}
|
|
41997
42776
|
}
|
|
41998
42777
|
const v2Cache = reportOpenCodeV2PluginCache(checkOpenCodeV2PluginCache({
|
|
@@ -42119,16 +42898,17 @@ var init_doctor_opencode = __esm(async () => {
|
|
|
42119
42898
|
init_v22_backfill_commands(),
|
|
42120
42899
|
init_doctor_authority(),
|
|
42121
42900
|
init_doctor_cached_plugin_fence(),
|
|
42122
|
-
init_doctor_harness_relabel()
|
|
42901
|
+
init_doctor_harness_relabel(),
|
|
42902
|
+
init_doctor_hidden_children()
|
|
42123
42903
|
]);
|
|
42124
42904
|
import_comment_json11 = __toESM(require_src3(), 1);
|
|
42125
42905
|
SHARED_DB_ROW_COUNT_TABLES = ["tags", "compartments", "memories", "notes", "dream_runs"];
|
|
42126
42906
|
});
|
|
42127
42907
|
|
|
42128
42908
|
// src/lib/diagnostics-pi.ts
|
|
42129
|
-
import { existsSync as
|
|
42909
|
+
import { existsSync as existsSync41, readdirSync as readdirSync8, readFileSync as readFileSync29, statSync as statSync16 } from "node:fs";
|
|
42130
42910
|
import { createRequire as createRequire7 } from "node:module";
|
|
42131
|
-
import { join as
|
|
42911
|
+
import { join as join34 } from "node:path";
|
|
42132
42912
|
function getSelfVersion3() {
|
|
42133
42913
|
const req = createRequire7(import.meta.url);
|
|
42134
42914
|
for (const relPath of ["../../package.json", "../package.json"]) {
|
|
@@ -42143,7 +42923,7 @@ function getSelfVersion3() {
|
|
|
42143
42923
|
}
|
|
42144
42924
|
function fileSize2(path) {
|
|
42145
42925
|
try {
|
|
42146
|
-
return
|
|
42926
|
+
return existsSync41(path) ? statSync16(path).size : 0;
|
|
42147
42927
|
} catch {
|
|
42148
42928
|
return 0;
|
|
42149
42929
|
}
|
|
@@ -42155,11 +42935,11 @@ function sanitizeValue2(value) {
|
|
|
42155
42935
|
return sanitizeConfigValue(value);
|
|
42156
42936
|
}
|
|
42157
42937
|
function readJsonc(path) {
|
|
42158
|
-
if (!
|
|
42938
|
+
if (!existsSync41(path))
|
|
42159
42939
|
return { value: {} };
|
|
42160
42940
|
try {
|
|
42161
42941
|
return {
|
|
42162
|
-
value: import_comment_json12.parse(
|
|
42942
|
+
value: import_comment_json12.parse(readFileSync29(path, "utf-8"))
|
|
42163
42943
|
};
|
|
42164
42944
|
} catch (error) {
|
|
42165
42945
|
return {
|
|
@@ -42175,7 +42955,7 @@ function readConfigDiagnostic(path) {
|
|
|
42175
42955
|
const parsed = readJsonc(path);
|
|
42176
42956
|
return {
|
|
42177
42957
|
path,
|
|
42178
|
-
exists:
|
|
42958
|
+
exists: existsSync41(path),
|
|
42179
42959
|
...parsed.parseError ? { parseError: parsed.parseError } : {},
|
|
42180
42960
|
flags: sanitizeValue2(parsed.value)
|
|
42181
42961
|
};
|
|
@@ -42193,25 +42973,25 @@ function reverseSlugToDirectory(slug) {
|
|
|
42193
42973
|
}
|
|
42194
42974
|
function collectPiRecentSessions() {
|
|
42195
42975
|
const sessionsRoot = getPiSessionsRoot();
|
|
42196
|
-
if (!
|
|
42976
|
+
if (!existsSync41(sessionsRoot))
|
|
42197
42977
|
return [];
|
|
42198
42978
|
try {
|
|
42199
|
-
const slugs =
|
|
42979
|
+
const slugs = readdirSync8(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
42200
42980
|
const candidates = [];
|
|
42201
42981
|
for (const slug of slugs) {
|
|
42202
42982
|
const directory = reverseSlugToDirectory(slug);
|
|
42203
42983
|
if (!directory)
|
|
42204
42984
|
continue;
|
|
42205
|
-
const slugDir =
|
|
42985
|
+
const slugDir = join34(sessionsRoot, slug);
|
|
42206
42986
|
let files;
|
|
42207
42987
|
try {
|
|
42208
|
-
files =
|
|
42988
|
+
files = readdirSync8(slugDir).filter((name) => name.endsWith(".jsonl"));
|
|
42209
42989
|
} catch {
|
|
42210
42990
|
continue;
|
|
42211
42991
|
}
|
|
42212
42992
|
for (const file of files) {
|
|
42213
42993
|
try {
|
|
42214
|
-
const mtime = statSync16(
|
|
42994
|
+
const mtime = statSync16(join34(slugDir, file)).mtimeMs;
|
|
42215
42995
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
42216
42996
|
candidates.push({ sessionId, directory, mtime });
|
|
42217
42997
|
} catch {}
|
|
@@ -42229,7 +43009,7 @@ function collectPiRecentSessions() {
|
|
|
42229
43009
|
}
|
|
42230
43010
|
function parseHistorianDumpMeta2(path) {
|
|
42231
43011
|
try {
|
|
42232
|
-
const xml =
|
|
43012
|
+
const xml = readFileSync29(path, "utf-8");
|
|
42233
43013
|
const parsed = parseCompartmentOutput(xml);
|
|
42234
43014
|
const factCountByCategory = {};
|
|
42235
43015
|
for (const fact of parsed.facts) {
|
|
@@ -42262,11 +43042,11 @@ function parseHistorianDumpMeta2(path) {
|
|
|
42262
43042
|
}
|
|
42263
43043
|
}
|
|
42264
43044
|
function listDumpsInDir2(dir, limit) {
|
|
42265
|
-
if (!
|
|
43045
|
+
if (!existsSync41(dir))
|
|
42266
43046
|
return { count: 0, recent: [] };
|
|
42267
43047
|
try {
|
|
42268
|
-
const entries =
|
|
42269
|
-
const stat = statSync16(
|
|
43048
|
+
const entries = readdirSync8(dir).filter((name) => name.endsWith(".xml")).map((name) => {
|
|
43049
|
+
const stat = statSync16(join34(dir, name));
|
|
42270
43050
|
return {
|
|
42271
43051
|
name,
|
|
42272
43052
|
mtime: stat.mtimeMs,
|
|
@@ -42275,7 +43055,7 @@ function listDumpsInDir2(dir, limit) {
|
|
|
42275
43055
|
}).sort((a, b) => b.mtime - a.mtime);
|
|
42276
43056
|
const now = Date.now();
|
|
42277
43057
|
const recent = entries.slice(0, limit).map((entry) => {
|
|
42278
|
-
const meta = parseHistorianDumpMeta2(
|
|
43058
|
+
const meta = parseHistorianDumpMeta2(join34(dir, entry.name));
|
|
42279
43059
|
const summary = {
|
|
42280
43060
|
name: entry.name,
|
|
42281
43061
|
ageMinutes: Math.round((now - entry.mtime) / 60000),
|
|
@@ -42339,7 +43119,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
42339
43119
|
const loaded = loadPiConfig({ cwd });
|
|
42340
43120
|
const storageResolution = getMagicContextStorageResolution();
|
|
42341
43121
|
const storageDirPath = storageResolution.path;
|
|
42342
|
-
const dbPath =
|
|
43122
|
+
const dbPath = join34(storageDirPath, "context.db");
|
|
42343
43123
|
const logFiles = inspectMagicContextLogs("pi");
|
|
42344
43124
|
const primaryLog = logFiles.find((file) => file.exists) ?? logFiles[0];
|
|
42345
43125
|
const otherPiExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
|
|
@@ -42356,7 +43136,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
42356
43136
|
piVersion: pi ? getPiVersion(pi.path) : null,
|
|
42357
43137
|
settings: {
|
|
42358
43138
|
path: settingsPath,
|
|
42359
|
-
exists:
|
|
43139
|
+
exists: existsSync41(settingsPath),
|
|
42360
43140
|
...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
|
|
42361
43141
|
hasMagicContextPackage: hasPiMagicContextPackage(packages),
|
|
42362
43142
|
packages: sanitizeValue2(packages)
|
|
@@ -42373,7 +43153,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
42373
43153
|
storageDir: {
|
|
42374
43154
|
path: storageDirPath,
|
|
42375
43155
|
source: storageResolution.source,
|
|
42376
|
-
exists:
|
|
43156
|
+
exists: existsSync41(storageDirPath),
|
|
42377
43157
|
contextDbSizeBytes: fileSize2(dbPath)
|
|
42378
43158
|
},
|
|
42379
43159
|
conflicts: {
|
|
@@ -42478,8 +43258,8 @@ var init_diagnostics_pi = __esm(() => {
|
|
|
42478
43258
|
});
|
|
42479
43259
|
|
|
42480
43260
|
// src/lib/logs-pi.ts
|
|
42481
|
-
import { mkdirSync as
|
|
42482
|
-
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";
|
|
42483
43263
|
function sanitizeLogContent2(content) {
|
|
42484
43264
|
return sanitizeString2(content);
|
|
42485
43265
|
}
|
|
@@ -42549,13 +43329,13 @@ async function bundleIssueReport2(report, description, title, options = {}) {
|
|
|
42549
43329
|
const truncated = bodyMarkdown !== rawBodyMarkdown;
|
|
42550
43330
|
const cwd = options.cwd ?? process.cwd();
|
|
42551
43331
|
const timestamp = formatTimestamp2(options.now ?? new Date);
|
|
42552
|
-
const path = options.outputPath ??
|
|
42553
|
-
|
|
42554
|
-
|
|
43332
|
+
const path = options.outputPath ?? join35(cwd, `magic-context-pi-issue-${timestamp}.md`);
|
|
43333
|
+
mkdirSync12(dirname21(path), { recursive: true });
|
|
43334
|
+
writeFileSync11(path, `${bodyMarkdown}
|
|
42555
43335
|
`);
|
|
42556
|
-
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;
|
|
42557
43337
|
if (fullPath)
|
|
42558
|
-
|
|
43338
|
+
writeFileSync11(fullPath, `${rawBodyMarkdown}
|
|
42559
43339
|
`);
|
|
42560
43340
|
return { path, bodyMarkdown, ...fullPath ? { fullPath } : {}, truncated };
|
|
42561
43341
|
}
|
|
@@ -42566,11 +43346,11 @@ var init_logs_pi = __esm(() => {
|
|
|
42566
43346
|
});
|
|
42567
43347
|
|
|
42568
43348
|
// src/commands/doctor-pi.ts
|
|
42569
|
-
import { execFileSync as
|
|
42570
|
-
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";
|
|
42571
43351
|
import { createRequire as createRequire8 } from "node:module";
|
|
42572
|
-
import { homedir as
|
|
42573
|
-
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";
|
|
42574
43354
|
function depsFrom(options) {
|
|
42575
43355
|
return {
|
|
42576
43356
|
...DEFAULT_DEPS5,
|
|
@@ -42607,7 +43387,8 @@ function selfVersion2() {
|
|
|
42607
43387
|
}
|
|
42608
43388
|
function getLatestNpmVersion(packageName) {
|
|
42609
43389
|
try {
|
|
42610
|
-
return
|
|
43390
|
+
return execFileSync7("npm", ["view", packageName, "version"], {
|
|
43391
|
+
windowsHide: true,
|
|
42611
43392
|
encoding: "utf-8",
|
|
42612
43393
|
stdio: ["ignore", "pipe", "ignore"],
|
|
42613
43394
|
timeout: 1e4
|
|
@@ -42661,7 +43442,7 @@ function summarize(results) {
|
|
|
42661
43442
|
function readJsonc2(path) {
|
|
42662
43443
|
try {
|
|
42663
43444
|
return {
|
|
42664
|
-
value: import_comment_json13.parse(
|
|
43445
|
+
value: import_comment_json13.parse(readFileSync30(path, "utf-8"))
|
|
42665
43446
|
};
|
|
42666
43447
|
} catch (error) {
|
|
42667
43448
|
return {
|
|
@@ -42711,15 +43492,15 @@ function piPluginDirCandidates(packages, cwd) {
|
|
|
42711
43492
|
if (resolved)
|
|
42712
43493
|
dirs.push(resolved);
|
|
42713
43494
|
}
|
|
42714
|
-
dirs.push(
|
|
42715
|
-
dirs.push(
|
|
42716
|
-
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")));
|
|
42717
43498
|
}
|
|
42718
43499
|
function projectConfigPath(cwd) {
|
|
42719
43500
|
return resolveCortexKitProjectConfigPath(cwd);
|
|
42720
43501
|
}
|
|
42721
43502
|
function readConfigForEmbedding(path, isProjectConfig) {
|
|
42722
|
-
if (!
|
|
43503
|
+
if (!existsSync42(path))
|
|
42723
43504
|
return null;
|
|
42724
43505
|
try {
|
|
42725
43506
|
const raw = loadRawConfigFile({
|
|
@@ -42805,22 +43586,22 @@ function pinnedVersionFromPackageSpecifier(specifier) {
|
|
|
42805
43586
|
}
|
|
42806
43587
|
function cacheRoots(cwd) {
|
|
42807
43588
|
const home = process.env.HOME?.trim();
|
|
42808
|
-
const cacheHome = process.env.XDG_CACHE_HOME ||
|
|
43589
|
+
const cacheHome = process.env.XDG_CACHE_HOME || join36(home || homedir18(), ".cache");
|
|
42809
43590
|
const piCacheRoot = getPiCacheRoot();
|
|
42810
43591
|
return [
|
|
42811
|
-
|
|
42812
|
-
|
|
42813
|
-
|
|
42814
|
-
|
|
42815
|
-
|
|
42816
|
-
|
|
42817
|
-
|
|
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)
|
|
42818
43599
|
];
|
|
42819
43600
|
}
|
|
42820
43601
|
function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
|
|
42821
43602
|
const found = new Map;
|
|
42822
43603
|
const visit = (path, depth) => {
|
|
42823
|
-
if (depth < 0 || !
|
|
43604
|
+
if (depth < 0 || !existsSync42(path))
|
|
42824
43605
|
return;
|
|
42825
43606
|
let stat;
|
|
42826
43607
|
try {
|
|
@@ -42830,10 +43611,10 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
|
|
|
42830
43611
|
}
|
|
42831
43612
|
if (!stat.isDirectory())
|
|
42832
43613
|
return;
|
|
42833
|
-
const packageJson =
|
|
42834
|
-
if (
|
|
43614
|
+
const packageJson = join36(path, "package.json");
|
|
43615
|
+
if (existsSync42(packageJson)) {
|
|
42835
43616
|
try {
|
|
42836
|
-
const pkg = JSON.parse(
|
|
43617
|
+
const pkg = JSON.parse(readFileSync30(packageJson, "utf-8"));
|
|
42837
43618
|
const name = typeof pkg.name === "string" ? pkg.name : "";
|
|
42838
43619
|
const version = typeof pkg.version === "string" ? pkg.version : undefined;
|
|
42839
43620
|
if (name === PACKAGE_NAME2) {
|
|
@@ -42848,12 +43629,12 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
|
|
|
42848
43629
|
}
|
|
42849
43630
|
let entries = [];
|
|
42850
43631
|
try {
|
|
42851
|
-
entries =
|
|
43632
|
+
entries = readdirSync9(path);
|
|
42852
43633
|
} catch {
|
|
42853
43634
|
return;
|
|
42854
43635
|
}
|
|
42855
43636
|
for (const entry of entries)
|
|
42856
|
-
visit(
|
|
43637
|
+
visit(join36(path, entry), depth - 1);
|
|
42857
43638
|
};
|
|
42858
43639
|
for (const root of cacheRoots(cwd))
|
|
42859
43640
|
visit(root, 5);
|
|
@@ -42898,7 +43679,7 @@ async function runHealthChecks2(options) {
|
|
|
42898
43679
|
}
|
|
42899
43680
|
const settingsPath = getPiUserExtensionsPath();
|
|
42900
43681
|
let packages = [];
|
|
42901
|
-
if (!
|
|
43682
|
+
if (!existsSync42(settingsPath)) {
|
|
42902
43683
|
add2(results, "fail", `Pi settings not found at ${settingsPath}`);
|
|
42903
43684
|
repairPlan.addPackageEntry = true;
|
|
42904
43685
|
} else {
|
|
@@ -42922,7 +43703,7 @@ async function runHealthChecks2(options) {
|
|
|
42922
43703
|
["user", userConfigPath, true],
|
|
42923
43704
|
["project", projectPath, false]
|
|
42924
43705
|
]) {
|
|
42925
|
-
if (!
|
|
43706
|
+
if (!existsSync42(path)) {
|
|
42926
43707
|
if (required) {
|
|
42927
43708
|
add2(results, "warn", `No ${label} magic-context.jsonc found at ${path}`);
|
|
42928
43709
|
if (userConfigMigrationRefused) {
|
|
@@ -42962,9 +43743,9 @@ async function runHealthChecks2(options) {
|
|
|
42962
43743
|
}
|
|
42963
43744
|
const storage = getMagicContextStorageResolution();
|
|
42964
43745
|
const storageDir = storage.path;
|
|
42965
|
-
const dbPath =
|
|
43746
|
+
const dbPath = join36(storageDir, "context.db");
|
|
42966
43747
|
add2(results, "info", `Shared storage: ${storageDir} (source: ${storage.source})`);
|
|
42967
|
-
const existedBeforeOpen =
|
|
43748
|
+
const existedBeforeOpen = existsSync42(dbPath);
|
|
42968
43749
|
if (existedBeforeOpen)
|
|
42969
43750
|
add2(results, "pass", `Shared context DB exists at ${dbPath}`);
|
|
42970
43751
|
else
|
|
@@ -43182,7 +43963,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
43182
43963
|
return { results, repairPlan, ...summarize(results) };
|
|
43183
43964
|
}
|
|
43184
43965
|
function writeDefaultMagicContextConfig(path) {
|
|
43185
|
-
|
|
43966
|
+
mkdirSync13(dirname22(path), { recursive: true });
|
|
43186
43967
|
const config = {
|
|
43187
43968
|
$schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
|
|
43188
43969
|
...MagicContextConfigSchema.parse({})
|
|
@@ -43204,7 +43985,7 @@ function repair2(plan, prompts) {
|
|
|
43204
43985
|
}
|
|
43205
43986
|
if (plan.writeUserConfig) {
|
|
43206
43987
|
const configPath = getPiUserConfigPath();
|
|
43207
|
-
if (!
|
|
43988
|
+
if (!existsSync42(configPath)) {
|
|
43208
43989
|
try {
|
|
43209
43990
|
writeDefaultMagicContextConfig(configPath);
|
|
43210
43991
|
prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
|
|
@@ -43228,6 +44009,7 @@ function repair2(plan, prompts) {
|
|
|
43228
44009
|
function runGhCommandWithDeps2(deps, args) {
|
|
43229
44010
|
if (args[0] === "issue") {
|
|
43230
44011
|
const result = deps.spawnSync("gh", args, {
|
|
44012
|
+
windowsHide: true,
|
|
43231
44013
|
encoding: "utf-8",
|
|
43232
44014
|
stdio: ["ignore", "pipe", "pipe"]
|
|
43233
44015
|
});
|
|
@@ -43239,6 +44021,7 @@ function runGhCommandWithDeps2(deps, args) {
|
|
|
43239
44021
|
}
|
|
43240
44022
|
try {
|
|
43241
44023
|
const output = deps.execFileSync("gh", args, {
|
|
44024
|
+
windowsHide: true,
|
|
43242
44025
|
encoding: "utf-8",
|
|
43243
44026
|
stdio: ["ignore", "pipe", "pipe"]
|
|
43244
44027
|
});
|
|
@@ -43256,7 +44039,7 @@ async function runIssueFlow3(options) {
|
|
|
43256
44039
|
if (options.reportPath) {
|
|
43257
44040
|
try {
|
|
43258
44041
|
const report = await options.deps.collectDiagnostics(options.cwd);
|
|
43259
|
-
const outputPath = isAbsolute8(options.reportPath) ? options.reportPath :
|
|
44042
|
+
const outputPath = isAbsolute8(options.reportPath) ? options.reportPath : join36(options.cwd, options.reportPath);
|
|
43260
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 });
|
|
43261
44044
|
options.prompts.log.info(`Report written to ${bundled.path}`);
|
|
43262
44045
|
return 0;
|
|
@@ -43340,7 +44123,7 @@ async function runDoctor3(options = {}) {
|
|
|
43340
44123
|
const v22Result = await runV22BackfillCommands({
|
|
43341
44124
|
name: "Pi",
|
|
43342
44125
|
openDatabase: (readonly = true) => {
|
|
43343
|
-
const dbPath =
|
|
44126
|
+
const dbPath = join36(getMagicContextStorageDir(), "context.db");
|
|
43344
44127
|
v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
|
|
43345
44128
|
return v22Db;
|
|
43346
44129
|
},
|
|
@@ -43382,7 +44165,7 @@ async function runDoctor3(options = {}) {
|
|
|
43382
44165
|
prompts.outro(first.fail > 0 ? "Doctor found failures" : "Doctor complete");
|
|
43383
44166
|
return first.fail > 0 ? 1 : 0;
|
|
43384
44167
|
}
|
|
43385
|
-
function
|
|
44168
|
+
function valueAfter2(args, flag) {
|
|
43386
44169
|
const index = args.indexOf(flag);
|
|
43387
44170
|
if (index === -1)
|
|
43388
44171
|
return null;
|
|
@@ -43392,8 +44175,8 @@ function valueAfter3(args, flag) {
|
|
|
43392
44175
|
return next;
|
|
43393
44176
|
}
|
|
43394
44177
|
function parseDoctorArgs(args) {
|
|
43395
|
-
const rekeyV22DirIdentity =
|
|
43396
|
-
const report =
|
|
44178
|
+
const rekeyV22DirIdentity = valueAfter2(args, "--rekey-v22-dir-identity");
|
|
44179
|
+
const report = valueAfter2(args, "--report");
|
|
43397
44180
|
return {
|
|
43398
44181
|
force: args.includes("--force"),
|
|
43399
44182
|
issue: args.includes("--issue") || report !== null,
|
|
@@ -43450,14 +44233,14 @@ var init_doctor_pi = __esm(async () => {
|
|
|
43450
44233
|
probeEmbeddingEndpoint,
|
|
43451
44234
|
openExistingContextDatabase,
|
|
43452
44235
|
now: () => new Date,
|
|
43453
|
-
execFileSync:
|
|
43454
|
-
spawnSync:
|
|
44236
|
+
execFileSync: execFileSync7,
|
|
44237
|
+
spawnSync: spawnSync10
|
|
43455
44238
|
};
|
|
43456
44239
|
});
|
|
43457
44240
|
|
|
43458
44241
|
// src/commands/doctor.ts
|
|
43459
|
-
import { existsSync as
|
|
43460
|
-
import { join as
|
|
44242
|
+
import { existsSync as existsSync43, rmSync as rmSync7 } from "node:fs";
|
|
44243
|
+
import { join as join37 } from "node:path";
|
|
43461
44244
|
async function runDoctor4(options) {
|
|
43462
44245
|
if (options.clear)
|
|
43463
44246
|
return runClear();
|
|
@@ -43475,7 +44258,7 @@ async function runDoctor4(options) {
|
|
|
43475
44258
|
const result = await runV22BackfillCommands({
|
|
43476
44259
|
name: "Magic Context",
|
|
43477
44260
|
openDatabase: (readonly = true) => {
|
|
43478
|
-
const dbPath =
|
|
44261
|
+
const dbPath = join37(getMagicContextStorageDir(), "context.db");
|
|
43479
44262
|
v22Db = readonly ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
|
|
43480
44263
|
return v22Db;
|
|
43481
44264
|
},
|
|
@@ -43488,8 +44271,14 @@ async function runDoctor4(options) {
|
|
|
43488
44271
|
if (result.handled)
|
|
43489
44272
|
return result.exitCode;
|
|
43490
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
|
+
}
|
|
43491
44280
|
await init_migrate();
|
|
43492
|
-
const sweepDbPath =
|
|
44281
|
+
const sweepDbPath = join37(getMagicContextStorageDir(), "context.db");
|
|
43493
44282
|
let sweepDb = null;
|
|
43494
44283
|
try {
|
|
43495
44284
|
sweepDb = openExistingContextDatabaseForMutation(sweepDbPath);
|
|
@@ -43603,7 +44392,7 @@ async function runClear() {
|
|
|
43603
44392
|
failed += 1;
|
|
43604
44393
|
continue;
|
|
43605
44394
|
}
|
|
43606
|
-
} else if (
|
|
44395
|
+
} else if (existsSync43(item.path)) {
|
|
43607
44396
|
rmSync7(item.path, { recursive: true, force: true });
|
|
43608
44397
|
}
|
|
43609
44398
|
s.stop(`Cleared ${item.path}`);
|
|
@@ -43633,6 +44422,7 @@ var init_doctor = __esm(async () => {
|
|
|
43633
44422
|
await __promiseAll([
|
|
43634
44423
|
init_database_access(),
|
|
43635
44424
|
init_v22_backfill_commands(),
|
|
44425
|
+
init_doctor_identity_splits(),
|
|
43636
44426
|
init_doctor_omp(),
|
|
43637
44427
|
init_doctor_opencode(),
|
|
43638
44428
|
init_doctor_pi()
|
|
@@ -43694,7 +44484,7 @@ var DOCTOR_HELP = [
|
|
|
43694
44484
|
" drain-authority <project> Drain module memory/note authority back to TypeScript",
|
|
43695
44485
|
" migrate Migrate an OpenCode session to Pi or OMP JSONL",
|
|
43696
44486
|
" migrate-session Re-home an OpenCode session to another directory",
|
|
43697
|
-
" merge-
|
|
44487
|
+
" merge-identities Preview or explicitly merge split identities",
|
|
43698
44488
|
" repair-db Back up and salvage a corrupted shared database",
|
|
43699
44489
|
" list-hidden-sessions List Magic Context OpenCode 2 roots",
|
|
43700
44490
|
""
|
|
@@ -43710,16 +44500,19 @@ var DRAIN_AUTHORITY_HELP = [
|
|
|
43710
44500
|
`);
|
|
43711
44501
|
var MERGE_IDENTITY_HELP = [
|
|
43712
44502
|
"",
|
|
43713
|
-
" Usage: magic-context doctor merge-
|
|
44503
|
+
" Usage: magic-context doctor merge-identities [--from <identity> --to <identity>] [--apply] [--force] [--db <path>]",
|
|
43714
44504
|
"",
|
|
43715
44505
|
" Merge every project-scoped row from one project identity into another.",
|
|
43716
44506
|
"",
|
|
43717
44507
|
" Options:",
|
|
43718
44508
|
" --from <identity> Identity whose rows are moved",
|
|
43719
44509
|
" --to <identity> Identity that receives them",
|
|
43720
|
-
"
|
|
43721
|
-
" --
|
|
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",
|
|
43722
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",
|
|
43723
44516
|
""
|
|
43724
44517
|
].join(`
|
|
43725
44518
|
`);
|
|
@@ -43743,7 +44536,7 @@ function subcommandHelp(argv) {
|
|
|
43743
44536
|
const subcommand = rest[0];
|
|
43744
44537
|
if (subcommand === "drain-authority")
|
|
43745
44538
|
return DRAIN_AUTHORITY_HELP;
|
|
43746
|
-
if (subcommand === "merge-identity")
|
|
44539
|
+
if (subcommand === "merge-identity" || subcommand === "merge-identities")
|
|
43747
44540
|
return MERGE_IDENTITY_HELP;
|
|
43748
44541
|
if (subcommand === "list-hidden-sessions")
|
|
43749
44542
|
return LIST_HIDDEN_SESSIONS_HELP;
|
|
@@ -43792,7 +44585,7 @@ function getVersion() {
|
|
|
43792
44585
|
}
|
|
43793
44586
|
return "0.0.0";
|
|
43794
44587
|
}
|
|
43795
|
-
function
|
|
44588
|
+
function valueAfter3(args, flag) {
|
|
43796
44589
|
const index = args.indexOf(flag);
|
|
43797
44590
|
if (index === -1)
|
|
43798
44591
|
return null;
|
|
@@ -43877,7 +44670,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
43877
44670
|
]);
|
|
43878
44671
|
return runDoctorDrainAuthority(projectRoot, join(getMagicContextStorageDir(), "context.db"));
|
|
43879
44672
|
}
|
|
43880
|
-
if (rest[0] === "merge-identity") {
|
|
44673
|
+
if (rest[0] === "merge-identities" || rest[0] === "merge-identity") {
|
|
43881
44674
|
await init_doctor_merge_identity();
|
|
43882
44675
|
return runMergeIdentityCli(rest.slice(1));
|
|
43883
44676
|
}
|
|
@@ -43898,8 +44691,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
43898
44691
|
return runMigrateSessionCli(rest.slice(1));
|
|
43899
44692
|
}
|
|
43900
44693
|
await init_doctor();
|
|
43901
|
-
const rekeyV22DirIdentity =
|
|
43902
|
-
const report =
|
|
44694
|
+
const rekeyV22DirIdentity = valueAfter3(rest, "--rekey-v22-dir-identity");
|
|
44695
|
+
const report = valueAfter3(rest, "--report");
|
|
43903
44696
|
return runDoctor4({
|
|
43904
44697
|
force: rest.includes("--force"),
|
|
43905
44698
|
fix: rest.includes("--fix"),
|