@cortexkit/magic-context 0.43.1 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1811 -792
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4203,6 +4203,10 @@ function getOpenCodePluginCacheDir() {
|
|
|
4203
4203
|
const xdg = process.env.XDG_CACHE_HOME || join5(homedir3(), ".cache");
|
|
4204
4204
|
return join5(xdg, "opencode", "packages");
|
|
4205
4205
|
}
|
|
4206
|
+
function getOpenCodeV2NpmCacheDir() {
|
|
4207
|
+
const xdg = process.env.XDG_CACHE_HOME || join5(homedir3(), ".cache");
|
|
4208
|
+
return join5(xdg, "opencode", "npm");
|
|
4209
|
+
}
|
|
4206
4210
|
function isDir(path) {
|
|
4207
4211
|
try {
|
|
4208
4212
|
return statSync3(path).isDirectory();
|
|
@@ -4603,7 +4607,7 @@ class OmpAdapter {
|
|
|
4603
4607
|
}
|
|
4604
4608
|
getPluginCacheInfo() {
|
|
4605
4609
|
const path = join8(getOmpPluginsDir(), "cache");
|
|
4606
|
-
return { path, exists: existsSync6(path), sizeBytes: dirSizeBytes(path) };
|
|
4610
|
+
return [{ path, exists: existsSync6(path), sizeBytes: dirSizeBytes(path) }];
|
|
4607
4611
|
}
|
|
4608
4612
|
getLogPath() {
|
|
4609
4613
|
return getMagicContextLogPath2("omp");
|
|
@@ -4646,7 +4650,7 @@ var init_omp = __esm(() => {
|
|
|
4646
4650
|
// ../plugin/src/shared/opencode-db-path.ts
|
|
4647
4651
|
import { existsSync as existsSync7, readdirSync as readdirSync2, statSync as statSync4 } from "node:fs";
|
|
4648
4652
|
import { homedir as homedir6 } from "node:os";
|
|
4649
|
-
import { isAbsolute as isAbsolute3, join as join9 } from "node:path";
|
|
4653
|
+
import { isAbsolute as isAbsolute3, join as join9, resolve as resolve3 } from "node:path";
|
|
4650
4654
|
function openCodeHostGenerationFromVersion(version) {
|
|
4651
4655
|
const text = version ?? "";
|
|
4652
4656
|
if (/(?:^|\s|v)0\.0\.0-(?:beta|dev)-/.test(text))
|
|
@@ -4733,7 +4737,7 @@ function resolveV2Fresh(dataDir, channel, env) {
|
|
|
4733
4737
|
const filename = sourceOpenCodeDatabaseFilename("v2", channel, env);
|
|
4734
4738
|
const explicit = env.OPENCODE_DB !== undefined;
|
|
4735
4739
|
return {
|
|
4736
|
-
path: filename === ":memory:" ? filename :
|
|
4740
|
+
path: filename === ":memory:" ? filename : resolve3(dataDir, filename),
|
|
4737
4741
|
source: explicit ? "OPENCODE_DB" : env.OPENCODE_CHANNEL ? "channel" : "default",
|
|
4738
4742
|
channel: explicit ? null : channel
|
|
4739
4743
|
};
|
|
@@ -12652,6 +12656,323 @@ var require_src3 = __commonJS(function(exports, module) {
|
|
|
12652
12656
|
};
|
|
12653
12657
|
});
|
|
12654
12658
|
|
|
12659
|
+
// ../plugin/src/hooks/auto-update-checker/semver.ts
|
|
12660
|
+
function isValidSemver(version) {
|
|
12661
|
+
return /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(version);
|
|
12662
|
+
}
|
|
12663
|
+
function compareSemverCore(a, b) {
|
|
12664
|
+
if (!isValidSemver(a) || !isValidSemver(b))
|
|
12665
|
+
return null;
|
|
12666
|
+
const core = (v) => v.split(/[-+]/, 1)[0].split(".").map((n) => Number.parseInt(n, 10));
|
|
12667
|
+
const [a0, a1, a2] = core(a);
|
|
12668
|
+
const [b0, b1, b2] = core(b);
|
|
12669
|
+
return a0 - b0 || a1 - b1 || a2 - b2;
|
|
12670
|
+
}
|
|
12671
|
+
|
|
12672
|
+
// src/lib/opencode-plugin-registration.ts
|
|
12673
|
+
function pluginConfigKeyFor(hostGeneration) {
|
|
12674
|
+
return hostGeneration === "v2" ? "plugins" : "plugin";
|
|
12675
|
+
}
|
|
12676
|
+
function readPluginEntries(config) {
|
|
12677
|
+
const out = [];
|
|
12678
|
+
for (const key of OPENCODE_PLUGIN_CONFIG_KEYS) {
|
|
12679
|
+
const list = config?.[key];
|
|
12680
|
+
if (!Array.isArray(list))
|
|
12681
|
+
continue;
|
|
12682
|
+
for (const [index, entry] of list.entries())
|
|
12683
|
+
out.push({ key, index, entry });
|
|
12684
|
+
}
|
|
12685
|
+
return out;
|
|
12686
|
+
}
|
|
12687
|
+
var OPENCODE_PLUGIN_CONFIG_KEYS;
|
|
12688
|
+
var init_opencode_plugin_registration = __esm(() => {
|
|
12689
|
+
OPENCODE_PLUGIN_CONFIG_KEYS = ["plugin", "plugins"];
|
|
12690
|
+
});
|
|
12691
|
+
|
|
12692
|
+
// src/lib/opencode-plugin-cache.ts
|
|
12693
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync5 } from "node:fs";
|
|
12694
|
+
import { join as join10 } from "node:path";
|
|
12695
|
+
function getOpenCodePluginCacheRoots() {
|
|
12696
|
+
const cacheDir = getOpenCodePluginCacheDir();
|
|
12697
|
+
return [
|
|
12698
|
+
join10(cacheDir, OPENCODE_PLUGIN_ENTRY_WITH_VERSION),
|
|
12699
|
+
join10(cacheDir, OPENCODE_PLUGIN_NAME)
|
|
12700
|
+
];
|
|
12701
|
+
}
|
|
12702
|
+
function getOpenCodePluginPackageJsonPath(pluginCacheRoot) {
|
|
12703
|
+
return join10(pluginCacheRoot, "node_modules", ...OPENCODE_PLUGIN_NAME.split("/"), "package.json");
|
|
12704
|
+
}
|
|
12705
|
+
function getOpenCodePluginPackageJsonPaths() {
|
|
12706
|
+
return getOpenCodePluginCacheRoots().map(getOpenCodePluginPackageJsonPath);
|
|
12707
|
+
}
|
|
12708
|
+
function getOpenCodeV2PluginCacheSlot(npmCacheDir = getOpenCodeV2NpmCacheDir(), spec = "latest") {
|
|
12709
|
+
return join10(npmCacheDir, ...`${OPENCODE_PLUGIN_NAME}@${spec}`.split("/"));
|
|
12710
|
+
}
|
|
12711
|
+
function openCodeV2PluginSpecOf(specifier) {
|
|
12712
|
+
if (specifier === OPENCODE_PLUGIN_NAME)
|
|
12713
|
+
return "latest";
|
|
12714
|
+
const prefix = `${OPENCODE_PLUGIN_NAME}@`;
|
|
12715
|
+
if (!specifier.startsWith(prefix))
|
|
12716
|
+
return;
|
|
12717
|
+
const spec = specifier.slice(prefix.length);
|
|
12718
|
+
return spec.length > 0 ? spec : "latest";
|
|
12719
|
+
}
|
|
12720
|
+
function isOpenCodePluginDistTag(spec) {
|
|
12721
|
+
return /^[A-Za-z][A-Za-z0-9._-]*$/.test(spec) && !/^(v\d|[xX]$)/.test(spec);
|
|
12722
|
+
}
|
|
12723
|
+
function readConfiguredOpenCodePluginSpec(config) {
|
|
12724
|
+
for (const { entry } of readPluginEntries(config)) {
|
|
12725
|
+
const specifier = pluginEntrySpecifier(entry);
|
|
12726
|
+
const spec = specifier === undefined ? undefined : openCodeV2PluginSpecOf(specifier);
|
|
12727
|
+
if (spec !== undefined)
|
|
12728
|
+
return spec;
|
|
12729
|
+
}
|
|
12730
|
+
return "latest";
|
|
12731
|
+
}
|
|
12732
|
+
function pluginEntrySpecifier(entry) {
|
|
12733
|
+
if (typeof entry === "string")
|
|
12734
|
+
return entry;
|
|
12735
|
+
if (Array.isArray(entry) && typeof entry[0] === "string")
|
|
12736
|
+
return entry[0];
|
|
12737
|
+
if (entry !== null && typeof entry === "object") {
|
|
12738
|
+
const pkg = entry.package;
|
|
12739
|
+
if (typeof pkg === "string")
|
|
12740
|
+
return pkg;
|
|
12741
|
+
}
|
|
12742
|
+
return;
|
|
12743
|
+
}
|
|
12744
|
+
function listOpenCodeV2PluginCacheSlots(npmCacheDir = getOpenCodeV2NpmCacheDir()) {
|
|
12745
|
+
const [scope = "", name = ""] = OPENCODE_PLUGIN_NAME.split("/");
|
|
12746
|
+
const scopeDir = join10(npmCacheDir, scope);
|
|
12747
|
+
let names;
|
|
12748
|
+
try {
|
|
12749
|
+
names = readdirSync3(scopeDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith(`${name}@`)).map((entry) => entry.name);
|
|
12750
|
+
} catch {
|
|
12751
|
+
return [];
|
|
12752
|
+
}
|
|
12753
|
+
return names.map((dirName) => {
|
|
12754
|
+
const slot = join10(scopeDir, dirName);
|
|
12755
|
+
return {
|
|
12756
|
+
spec: dirName.slice(name.length + 1),
|
|
12757
|
+
slot,
|
|
12758
|
+
version: readOpenCodeV2CachedPluginVersion(slot)
|
|
12759
|
+
};
|
|
12760
|
+
}).sort((a, b) => {
|
|
12761
|
+
if (a.spec === "latest" || b.spec === "latest")
|
|
12762
|
+
return a.spec === "latest" ? -1 : 1;
|
|
12763
|
+
return a.spec.localeCompare(b.spec);
|
|
12764
|
+
});
|
|
12765
|
+
}
|
|
12766
|
+
function getOpenCodeV2ActiveGeneration(slot) {
|
|
12767
|
+
try {
|
|
12768
|
+
const generations = readdirSync3(slot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && /^\d+$/.test(entry.name)).map((entry) => entry.name).sort((a, b) => Number(a) - Number(b));
|
|
12769
|
+
const newest = generations.at(-1);
|
|
12770
|
+
return newest === undefined ? undefined : join10(slot, newest);
|
|
12771
|
+
} catch {
|
|
12772
|
+
return;
|
|
12773
|
+
}
|
|
12774
|
+
}
|
|
12775
|
+
function readOpenCodeV2CachedPluginVersion(slot) {
|
|
12776
|
+
const generation = getOpenCodeV2ActiveGeneration(slot);
|
|
12777
|
+
if (!generation)
|
|
12778
|
+
return;
|
|
12779
|
+
try {
|
|
12780
|
+
const pkg = JSON.parse(readFileSync5(getOpenCodePluginPackageJsonPath(generation), "utf-8"));
|
|
12781
|
+
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
12782
|
+
} catch {
|
|
12783
|
+
return;
|
|
12784
|
+
}
|
|
12785
|
+
}
|
|
12786
|
+
var OPENCODE_PLUGIN_NAME = "@cortexkit/opencode-magic-context", OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
|
|
12787
|
+
var init_opencode_plugin_cache = __esm(() => {
|
|
12788
|
+
init_opencode_plugin_registration();
|
|
12789
|
+
init_paths();
|
|
12790
|
+
OPENCODE_PLUGIN_ENTRY_WITH_VERSION = `${OPENCODE_PLUGIN_NAME}@latest`;
|
|
12791
|
+
});
|
|
12792
|
+
|
|
12793
|
+
// src/commands/doctor-opencode2-cache.ts
|
|
12794
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
12795
|
+
import { existsSync as existsSync8, rmSync as rmSync2 } from "node:fs";
|
|
12796
|
+
function runLsof(args, spawn) {
|
|
12797
|
+
const result = spawn("lsof", args, { encoding: "utf-8", timeout: 15000 });
|
|
12798
|
+
if (result.error)
|
|
12799
|
+
return { error: result.error.message };
|
|
12800
|
+
if (result.status !== 0 && result.status !== 1) {
|
|
12801
|
+
return { error: `lsof exited with status ${String(result.status)}` };
|
|
12802
|
+
}
|
|
12803
|
+
const pids = (result.stdout ?? "").split(/\s+/).filter((token) => /^\d+$/.test(token)).map((token) => Number(token)).filter((pid) => pid !== process.pid);
|
|
12804
|
+
return { pids };
|
|
12805
|
+
}
|
|
12806
|
+
function probeHostProcessesUsing(targets, spawn = spawnSync3) {
|
|
12807
|
+
const files = targets.files.filter((file) => existsSync8(file));
|
|
12808
|
+
const directories = targets.directories.filter((directory) => existsSync8(directory));
|
|
12809
|
+
const queries = [];
|
|
12810
|
+
if (files.length > 0)
|
|
12811
|
+
queries.push(["-w", "-t", "--", ...files]);
|
|
12812
|
+
for (const directory of directories)
|
|
12813
|
+
queries.push(["-w", "-t", "+D", directory]);
|
|
12814
|
+
const pids = new Set;
|
|
12815
|
+
for (const args of queries) {
|
|
12816
|
+
const result = runLsof(args, spawn);
|
|
12817
|
+
if ("error" in result) {
|
|
12818
|
+
return { status: "unknown", reason: `could not run lsof (${result.error})` };
|
|
12819
|
+
}
|
|
12820
|
+
for (const pid of result.pids)
|
|
12821
|
+
pids.add(pid);
|
|
12822
|
+
}
|
|
12823
|
+
if (pids.size > 0)
|
|
12824
|
+
return { status: "in_use", pids: [...pids].sort((a, b) => a - b) };
|
|
12825
|
+
return { status: "free" };
|
|
12826
|
+
}
|
|
12827
|
+
function comparePrerelease(a, b) {
|
|
12828
|
+
if (a === b)
|
|
12829
|
+
return 0;
|
|
12830
|
+
if (a === "")
|
|
12831
|
+
return 1;
|
|
12832
|
+
if (b === "")
|
|
12833
|
+
return -1;
|
|
12834
|
+
const left = a.split(".");
|
|
12835
|
+
const right = b.split(".");
|
|
12836
|
+
for (let i = 0;i < Math.max(left.length, right.length); i++) {
|
|
12837
|
+
const x = left[i];
|
|
12838
|
+
const y = right[i];
|
|
12839
|
+
if (x === undefined)
|
|
12840
|
+
return -1;
|
|
12841
|
+
if (y === undefined)
|
|
12842
|
+
return 1;
|
|
12843
|
+
if (x === y)
|
|
12844
|
+
continue;
|
|
12845
|
+
const xNumeric = /^\d+$/.test(x);
|
|
12846
|
+
const yNumeric = /^\d+$/.test(y);
|
|
12847
|
+
if (xNumeric && yNumeric)
|
|
12848
|
+
return Number(x) - Number(y);
|
|
12849
|
+
if (xNumeric !== yNumeric)
|
|
12850
|
+
return xNumeric ? -1 : 1;
|
|
12851
|
+
return x < y ? -1 : 1;
|
|
12852
|
+
}
|
|
12853
|
+
return 0;
|
|
12854
|
+
}
|
|
12855
|
+
function prereleaseOf(version) {
|
|
12856
|
+
const withoutBuild = version.split("+", 1)[0] ?? "";
|
|
12857
|
+
const dash = withoutBuild.indexOf("-");
|
|
12858
|
+
return dash === -1 ? "" : withoutBuild.slice(dash + 1);
|
|
12859
|
+
}
|
|
12860
|
+
function isStale(cached, latest) {
|
|
12861
|
+
if (cached === undefined)
|
|
12862
|
+
return true;
|
|
12863
|
+
if (cached === latest)
|
|
12864
|
+
return false;
|
|
12865
|
+
const comparison = compareSemverCore(cached, latest);
|
|
12866
|
+
if (comparison === null)
|
|
12867
|
+
return true;
|
|
12868
|
+
if (comparison !== 0)
|
|
12869
|
+
return comparison < 0;
|
|
12870
|
+
return comparePrerelease(prereleaseOf(cached), prereleaseOf(latest)) < 0;
|
|
12871
|
+
}
|
|
12872
|
+
function removeOpenCodeV2PluginCacheSlot(slot, hostFiles, deps = {}) {
|
|
12873
|
+
const probe = deps.probe ?? probeHostProcessesUsing;
|
|
12874
|
+
const use = probe({ files: hostFiles, directories: [slot] });
|
|
12875
|
+
if (use.status === "in_use")
|
|
12876
|
+
return { action: "in_use", pids: use.pids };
|
|
12877
|
+
if (use.status === "unknown")
|
|
12878
|
+
return { action: "in_use_unknown", reason: use.reason };
|
|
12879
|
+
const remove = deps.remove ?? ((path) => rmSync2(path, { recursive: true, force: true }));
|
|
12880
|
+
try {
|
|
12881
|
+
remove(slot);
|
|
12882
|
+
} catch (err) {
|
|
12883
|
+
return { action: "error", error: err instanceof Error ? err.message : String(err) };
|
|
12884
|
+
}
|
|
12885
|
+
return { action: "cleared" };
|
|
12886
|
+
}
|
|
12887
|
+
function openCodeHostDatabaseFiles(databasePaths) {
|
|
12888
|
+
return databasePaths.filter((path) => path !== ":memory:").flatMap((path) => ["", "-wal", "-shm"].map((suffix) => `${path}${suffix}`));
|
|
12889
|
+
}
|
|
12890
|
+
function configuredOpenCodeV2DistTag(config) {
|
|
12891
|
+
const spec = readConfiguredOpenCodePluginSpec(config);
|
|
12892
|
+
return spec !== "latest" && isOpenCodePluginDistTag(spec) ? spec : undefined;
|
|
12893
|
+
}
|
|
12894
|
+
function checkOpenCodeV2PluginCache(options, deps = {}) {
|
|
12895
|
+
const distTag = options.distTag && options.distTag !== "latest" ? options.distTag : undefined;
|
|
12896
|
+
const slot = deps.slot ?? getOpenCodeV2PluginCacheSlot(undefined, distTag ?? "latest");
|
|
12897
|
+
const tagged = distTag ? { distTag } : {};
|
|
12898
|
+
if (!existsSync8(slot))
|
|
12899
|
+
return { action: "not_found", slot, ...tagged };
|
|
12900
|
+
const cached = readOpenCodeV2CachedPluginVersion(slot);
|
|
12901
|
+
const latest = options.latestVersion ?? undefined;
|
|
12902
|
+
const force = options.force === true;
|
|
12903
|
+
if (latest === undefined && !force) {
|
|
12904
|
+
return { action: "check_unavailable", slot, cached, ...tagged };
|
|
12905
|
+
}
|
|
12906
|
+
const stale = latest !== undefined && isStale(cached, latest);
|
|
12907
|
+
if (!stale && !force)
|
|
12908
|
+
return { action: "up_to_date", slot, cached, latest, ...tagged };
|
|
12909
|
+
if (!force && options.fix !== true) {
|
|
12910
|
+
return { action: "stale", slot, cached, latest, ...tagged };
|
|
12911
|
+
}
|
|
12912
|
+
const removal = removeOpenCodeV2PluginCacheSlot(slot, options.hostFiles, deps);
|
|
12913
|
+
switch (removal.action) {
|
|
12914
|
+
case "in_use":
|
|
12915
|
+
return { action: "in_use", slot, cached, latest, pids: removal.pids, ...tagged };
|
|
12916
|
+
case "in_use_unknown":
|
|
12917
|
+
return {
|
|
12918
|
+
action: "in_use_unknown",
|
|
12919
|
+
slot,
|
|
12920
|
+
cached,
|
|
12921
|
+
latest,
|
|
12922
|
+
reason: removal.reason,
|
|
12923
|
+
...tagged
|
|
12924
|
+
};
|
|
12925
|
+
case "error":
|
|
12926
|
+
return { action: "error", slot, cached, latest, error: removal.error, ...tagged };
|
|
12927
|
+
case "cleared":
|
|
12928
|
+
return { action: "cleared", slot, cached, latest, forced: !stale, ...tagged };
|
|
12929
|
+
}
|
|
12930
|
+
}
|
|
12931
|
+
function reportOpenCodeV2PluginCache(result, report, options) {
|
|
12932
|
+
const tag = result.distTag ?? "latest";
|
|
12933
|
+
const versions = `cached: ${result.cached ?? "unreadable"}${result.latest ? `, ${tag}: ${result.latest}` : ""}`;
|
|
12934
|
+
const slotName = result.distTag ? ` @${result.distTag}` : "";
|
|
12935
|
+
switch (result.action) {
|
|
12936
|
+
case "not_found":
|
|
12937
|
+
if (options.reportMissing) {
|
|
12938
|
+
report.pass(`OpenCode 2 plugin cache has no Magic Context${slotName} install yet (OpenCode installs it on next start)`);
|
|
12939
|
+
}
|
|
12940
|
+
return { fixed: false, issue: false };
|
|
12941
|
+
case "up_to_date":
|
|
12942
|
+
report.pass(`OpenCode 2 plugin cache${slotName} up to date (v${result.cached})`);
|
|
12943
|
+
return { fixed: false, issue: false };
|
|
12944
|
+
case "check_unavailable":
|
|
12945
|
+
report.warn(`OpenCode 2 plugin cache${slotName} version check unavailable; preserving cached plugin${result.cached ? ` (cached: ${result.cached})` : ""}. Use doctor --force to reinstall it.`);
|
|
12946
|
+
return { fixed: false, issue: false };
|
|
12947
|
+
case "stale":
|
|
12948
|
+
report.warn(`OpenCode 2 is running an outdated Magic Context${slotName} (${versions}); OpenCode does not install new releases on its own`);
|
|
12949
|
+
report.info(` To upgrade, ${OPENCODE_V2_PLUGIN_UPDATE_HINT},`);
|
|
12950
|
+
report.info(" or quit OpenCode (including `opencode service stop`) and run `magic-context doctor --fix`.");
|
|
12951
|
+
return { fixed: false, issue: false };
|
|
12952
|
+
case "in_use":
|
|
12953
|
+
report.warn(`Outdated Magic Context in the OpenCode 2 plugin cache (${versions}) was not cleared: OpenCode is running (pid ${result.pids?.join(", ")})`);
|
|
12954
|
+
report.info(` Quit OpenCode (and \`opencode service stop\`) and rerun doctor --fix, or ${OPENCODE_V2_PLUGIN_UPDATE_HINT}.`);
|
|
12955
|
+
report.info(` ${result.slot}`);
|
|
12956
|
+
return { fixed: false, issue: false };
|
|
12957
|
+
case "in_use_unknown":
|
|
12958
|
+
report.warn(`Outdated Magic Context in the OpenCode 2 plugin cache (${versions}) was not cleared: ${result.reason ?? "could not tell whether OpenCode is running"}`);
|
|
12959
|
+
report.info(` Quit OpenCode and delete ${result.slot} by hand, or ${OPENCODE_V2_PLUGIN_UPDATE_HINT}.`);
|
|
12960
|
+
return { fixed: false, issue: false };
|
|
12961
|
+
case "cleared":
|
|
12962
|
+
report.pass(`Cleared ${result.forced ? "" : "outdated "}Magic Context${slotName} from the OpenCode 2 plugin cache (${versions}${result.forced ? ", --force" : ""}) — OpenCode installs the ${result.distTag ? `current ${tag} release` : "latest"} on next start`);
|
|
12963
|
+
report.info(` ${result.slot}`);
|
|
12964
|
+
return { fixed: true, issue: false };
|
|
12965
|
+
case "error":
|
|
12966
|
+
report.warn(`Could not clear the OpenCode 2 plugin cache: ${result.error}`);
|
|
12967
|
+
report.info(` Manually delete: ${result.slot}`);
|
|
12968
|
+
return { fixed: false, issue: true };
|
|
12969
|
+
}
|
|
12970
|
+
}
|
|
12971
|
+
var OPENCODE_V2_PLUGIN_UPDATE_HINT = "update it from OpenCode: open /plugins, select Magic Context and press ctrl+u (ctrl+r only re-checks), or run `opencode plugin update`";
|
|
12972
|
+
var init_doctor_opencode2_cache = __esm(() => {
|
|
12973
|
+
init_opencode_plugin_cache();
|
|
12974
|
+
});
|
|
12975
|
+
|
|
12655
12976
|
// src/lib/atomic-write.ts
|
|
12656
12977
|
import { chmodSync, mkdirSync as mkdirSync2, renameSync as renameSync2, statSync as statSync5, writeFileSync as writeFileSync2 } from "node:fs";
|
|
12657
12978
|
import { dirname as dirname3 } from "node:path";
|
|
@@ -12670,13 +12991,13 @@ function writeFileAtomic(targetPath, data) {
|
|
|
12670
12991
|
var init_atomic_write = () => {};
|
|
12671
12992
|
|
|
12672
12993
|
// src/lib/opencode-detect.ts
|
|
12673
|
-
import { existsSync as
|
|
12994
|
+
import { existsSync as existsSync9, realpathSync } from "node:fs";
|
|
12674
12995
|
import { homedir as homedir7 } from "node:os";
|
|
12675
|
-
import { join as
|
|
12996
|
+
import { join as join11 } from "node:path";
|
|
12676
12997
|
function defaultDeps(overrides = {}) {
|
|
12677
12998
|
const env = overrides.env ?? process.env;
|
|
12678
12999
|
return {
|
|
12679
|
-
exists: overrides.exists ??
|
|
13000
|
+
exists: overrides.exists ?? existsSync9,
|
|
12680
13001
|
isExecutable: overrides.isExecutable ?? isExecutableFile,
|
|
12681
13002
|
home: overrides.home ?? (env.HOME?.trim() || homedir7()),
|
|
12682
13003
|
platform: overrides.platform ?? process.platform,
|
|
@@ -12686,7 +13007,7 @@ function defaultDeps(overrides = {}) {
|
|
|
12686
13007
|
};
|
|
12687
13008
|
}
|
|
12688
13009
|
function stockCliBinary(d) {
|
|
12689
|
-
return d.platform === "win32" ?
|
|
13010
|
+
return d.platform === "win32" ? join11(d.home, ".opencode", "bin", "opencode.exe") : join11(d.home, ".opencode", "bin", "opencode");
|
|
12690
13011
|
}
|
|
12691
13012
|
function extraCliCandidates(d) {
|
|
12692
13013
|
if (d.platform === "win32") {
|
|
@@ -12695,25 +13016,34 @@ function extraCliCandidates(d) {
|
|
|
12695
13016
|
const userprofile = d.env.USERPROFILE ?? d.home;
|
|
12696
13017
|
const out = [];
|
|
12697
13018
|
if (appdata) {
|
|
12698
|
-
out.push(
|
|
12699
|
-
out.push(
|
|
13019
|
+
out.push(join11(appdata, "npm", "opencode.cmd"));
|
|
13020
|
+
out.push(join11(appdata, "npm", "opencode.exe"));
|
|
12700
13021
|
}
|
|
12701
13022
|
if (localappdata) {
|
|
12702
|
-
out.push(
|
|
12703
|
-
out.push(
|
|
13023
|
+
out.push(join11(localappdata, "Microsoft", "WinGet", "Links", "opencode.exe"));
|
|
13024
|
+
out.push(join11(localappdata, "opencode", "bin", "opencode.exe"));
|
|
12704
13025
|
}
|
|
12705
13026
|
if (userprofile) {
|
|
12706
|
-
out.push(
|
|
13027
|
+
out.push(join11(userprofile, "scoop", "shims", "opencode.exe"));
|
|
12707
13028
|
}
|
|
12708
13029
|
return out;
|
|
12709
13030
|
}
|
|
12710
13031
|
return [
|
|
12711
13032
|
"/usr/local/bin/opencode",
|
|
12712
13033
|
"/opt/homebrew/bin/opencode",
|
|
12713
|
-
|
|
12714
|
-
|
|
12715
|
-
|
|
12716
|
-
|
|
13034
|
+
join11(d.home, ".local", "bin", "opencode"),
|
|
13035
|
+
join11(d.home, ".local", "share", "mise", "shims", "opencode"),
|
|
13036
|
+
join11(d.home, ".asdf", "shims", "opencode"),
|
|
13037
|
+
join11(d.home, ".volta", "bin", "opencode")
|
|
13038
|
+
];
|
|
13039
|
+
}
|
|
13040
|
+
function openChamberCliCandidates(d) {
|
|
13041
|
+
if (d.platform !== "darwin")
|
|
13042
|
+
return [];
|
|
13043
|
+
const bundled = ["Contents", "Resources", "opencode-cli", "opencode"];
|
|
13044
|
+
return [
|
|
13045
|
+
join11("/Applications", "OpenChamber.app", ...bundled),
|
|
13046
|
+
join11(d.home, "Applications", "OpenChamber.app", ...bundled)
|
|
12717
13047
|
];
|
|
12718
13048
|
}
|
|
12719
13049
|
function canonicalPath(d, path) {
|
|
@@ -12734,29 +13064,29 @@ function xdgConfigHome(d) {
|
|
|
12734
13064
|
const xdg = d.env.XDG_CONFIG_HOME;
|
|
12735
13065
|
if (xdg && xdg.length > 0)
|
|
12736
13066
|
return xdg;
|
|
12737
|
-
return
|
|
13067
|
+
return join11(d.home, ".config");
|
|
12738
13068
|
}
|
|
12739
13069
|
function desktopUserDataDir(d, appId) {
|
|
12740
13070
|
switch (d.platform) {
|
|
12741
13071
|
case "darwin":
|
|
12742
|
-
return
|
|
13072
|
+
return join11(d.home, "Library", "Application Support", appId);
|
|
12743
13073
|
case "win32":
|
|
12744
|
-
return
|
|
13074
|
+
return join11(d.env.APPDATA ?? join11(d.home, "AppData", "Roaming"), appId);
|
|
12745
13075
|
default:
|
|
12746
|
-
return
|
|
13076
|
+
return join11(xdgConfigHome(d), appId);
|
|
12747
13077
|
}
|
|
12748
13078
|
}
|
|
12749
13079
|
function desktopAppPaths(d) {
|
|
12750
13080
|
switch (d.platform) {
|
|
12751
13081
|
case "darwin":
|
|
12752
|
-
return ["/Applications/OpenCode.app",
|
|
13082
|
+
return ["/Applications/OpenCode.app", join11(d.home, "Applications", "OpenCode.app")];
|
|
12753
13083
|
case "win32": {
|
|
12754
|
-
const localappdata = d.env.LOCALAPPDATA ??
|
|
12755
|
-
return [
|
|
13084
|
+
const localappdata = d.env.LOCALAPPDATA ?? join11(d.home, "AppData", "Local");
|
|
13085
|
+
return [join11(localappdata, "Programs", "OpenCode", "OpenCode.exe")];
|
|
12756
13086
|
}
|
|
12757
13087
|
default: {
|
|
12758
|
-
const dataHome = d.env.XDG_DATA_HOME && d.env.XDG_DATA_HOME.length > 0 ? d.env.XDG_DATA_HOME :
|
|
12759
|
-
return OPENCODE_DESKTOP_APP_IDS.map((appId) =>
|
|
13088
|
+
const dataHome = d.env.XDG_DATA_HOME && d.env.XDG_DATA_HOME.length > 0 ? d.env.XDG_DATA_HOME : join11(d.home, ".local", "share");
|
|
13089
|
+
return OPENCODE_DESKTOP_APP_IDS.map((appId) => join11(dataHome, "applications", `${appId}.desktop`));
|
|
12760
13090
|
}
|
|
12761
13091
|
}
|
|
12762
13092
|
}
|
|
@@ -12777,8 +13107,13 @@ function detectOpenCodeInstallations(deps) {
|
|
|
12777
13107
|
addCandidate(installations, seenRealpaths, d, candidate, "PATH", "cli");
|
|
12778
13108
|
}
|
|
12779
13109
|
}
|
|
13110
|
+
for (const candidate of openChamberCliCandidates(d)) {
|
|
13111
|
+
if (d.isExecutable(candidate)) {
|
|
13112
|
+
addCandidate(installations, seenRealpaths, d, candidate, "openchamber", "cli");
|
|
13113
|
+
}
|
|
13114
|
+
}
|
|
12780
13115
|
for (const appId of OPENCODE_DESKTOP_APP_IDS) {
|
|
12781
|
-
const marker =
|
|
13116
|
+
const marker = join11(desktopUserDataDir(d, appId), OPENCODE_DESKTOP_SETTINGS_FILE);
|
|
12782
13117
|
if (d.exists(marker)) {
|
|
12783
13118
|
addCandidate(installations, seenRealpaths, d, marker, "desktop", "desktop");
|
|
12784
13119
|
}
|
|
@@ -12850,6 +13185,17 @@ function describeOpenCodeInstallations(installations, deps = {}) {
|
|
|
12850
13185
|
active: index === 0
|
|
12851
13186
|
}));
|
|
12852
13187
|
}
|
|
13188
|
+
function selectOpenCodeStoreHost(reports, generationOf) {
|
|
13189
|
+
const active = reports[0];
|
|
13190
|
+
if (!active)
|
|
13191
|
+
return null;
|
|
13192
|
+
const hasVersion = (report) => /\d/.test(report.version);
|
|
13193
|
+
if (!hasVersion(active) || generationOf(active.version) === "v2") {
|
|
13194
|
+
return { host: active, shadowed: false };
|
|
13195
|
+
}
|
|
13196
|
+
const v2 = reports.find((report) => report.kind === "cli" && hasVersion(report) && generationOf(report.version) === "v2");
|
|
13197
|
+
return v2 ? { host: v2, shadowed: true } : { host: active, shadowed: false };
|
|
13198
|
+
}
|
|
12853
13199
|
function getAvailableModels2(binary) {
|
|
12854
13200
|
const output = runOpenCode(["models"], binary);
|
|
12855
13201
|
if (output === null)
|
|
@@ -12860,50 +13206,9 @@ function getAvailableModels2(binary) {
|
|
|
12860
13206
|
var OPENCODE_BINARY_ENV = "MAGIC_CONTEXT_OPENCODE_BINARY", OPENCODE_VERSION_PROBE_TIMEOUT_MS = 2000;
|
|
12861
13207
|
var init_opencode_helpers = () => {};
|
|
12862
13208
|
|
|
12863
|
-
// src/lib/opencode-plugin-cache.ts
|
|
12864
|
-
import { join as join11 } from "node:path";
|
|
12865
|
-
function getOpenCodePluginCacheRoots() {
|
|
12866
|
-
const cacheDir = getOpenCodePluginCacheDir();
|
|
12867
|
-
return [
|
|
12868
|
-
join11(cacheDir, OPENCODE_PLUGIN_ENTRY_WITH_VERSION),
|
|
12869
|
-
join11(cacheDir, OPENCODE_PLUGIN_NAME)
|
|
12870
|
-
];
|
|
12871
|
-
}
|
|
12872
|
-
function getOpenCodePluginPackageJsonPath(pluginCacheRoot) {
|
|
12873
|
-
return join11(pluginCacheRoot, "node_modules", ...OPENCODE_PLUGIN_NAME.split("/"), "package.json");
|
|
12874
|
-
}
|
|
12875
|
-
function getOpenCodePluginPackageJsonPaths() {
|
|
12876
|
-
return getOpenCodePluginCacheRoots().map(getOpenCodePluginPackageJsonPath);
|
|
12877
|
-
}
|
|
12878
|
-
var OPENCODE_PLUGIN_NAME = "@cortexkit/opencode-magic-context", OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
|
|
12879
|
-
var init_opencode_plugin_cache = __esm(() => {
|
|
12880
|
-
init_paths();
|
|
12881
|
-
OPENCODE_PLUGIN_ENTRY_WITH_VERSION = `${OPENCODE_PLUGIN_NAME}@latest`;
|
|
12882
|
-
});
|
|
12883
|
-
|
|
12884
|
-
// src/lib/opencode-plugin-registration.ts
|
|
12885
|
-
function pluginConfigKeyFor(hostGeneration) {
|
|
12886
|
-
return hostGeneration === "v2" ? "plugins" : "plugin";
|
|
12887
|
-
}
|
|
12888
|
-
function readPluginEntries(config) {
|
|
12889
|
-
const out = [];
|
|
12890
|
-
for (const key of OPENCODE_PLUGIN_CONFIG_KEYS) {
|
|
12891
|
-
const list = config?.[key];
|
|
12892
|
-
if (!Array.isArray(list))
|
|
12893
|
-
continue;
|
|
12894
|
-
for (const [index, entry] of list.entries())
|
|
12895
|
-
out.push({ key, index, entry });
|
|
12896
|
-
}
|
|
12897
|
-
return out;
|
|
12898
|
-
}
|
|
12899
|
-
var OPENCODE_PLUGIN_CONFIG_KEYS;
|
|
12900
|
-
var init_opencode_plugin_registration = __esm(() => {
|
|
12901
|
-
OPENCODE_PLUGIN_CONFIG_KEYS = ["plugin", "plugins"];
|
|
12902
|
-
});
|
|
12903
|
-
|
|
12904
13209
|
// src/adapters/opencode.ts
|
|
12905
|
-
import { existsSync as
|
|
12906
|
-
import { dirname as dirname4, isAbsolute as isAbsolute4, parse as parsePath, resolve as
|
|
13210
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, statSync as statSync6 } from "node:fs";
|
|
13211
|
+
import { dirname as dirname4, isAbsolute as isAbsolute4, parse as parsePath, resolve as resolve4 } from "node:path";
|
|
12907
13212
|
import { fileURLToPath } from "node:url";
|
|
12908
13213
|
|
|
12909
13214
|
class OpenCodeAdapter {
|
|
@@ -12911,21 +13216,20 @@ class OpenCodeAdapter {
|
|
|
12911
13216
|
displayName = "OpenCode";
|
|
12912
13217
|
pluginPackageName = OPENCODE_PLUGIN_NAME;
|
|
12913
13218
|
hostGeneration;
|
|
12914
|
-
|
|
13219
|
+
probeHostUse;
|
|
12915
13220
|
constructor(options = {}) {
|
|
12916
13221
|
this.hostGeneration = options.hostGeneration;
|
|
13222
|
+
this.probeHostUse = options.probeHostUse;
|
|
13223
|
+
}
|
|
13224
|
+
get resolvedHostGeneration() {
|
|
13225
|
+
if (this.hostGeneration)
|
|
13226
|
+
return this.hostGeneration;
|
|
13227
|
+
const detection = detectOpenCode();
|
|
13228
|
+
this.hostGeneration = detection.kind === "cli" ? openCodeHostGenerationFromVersion(getOpenCodeVersion(detection.binary)) : "v1";
|
|
13229
|
+
return this.hostGeneration;
|
|
12917
13230
|
}
|
|
12918
13231
|
get writeKey() {
|
|
12919
|
-
|
|
12920
|
-
return this.resolvedWriteKey;
|
|
12921
|
-
const generation = this.hostGeneration ?? (() => {
|
|
12922
|
-
const detection = detectOpenCode();
|
|
12923
|
-
if (detection.kind !== "cli")
|
|
12924
|
-
return "v1";
|
|
12925
|
-
return openCodeHostGenerationFromVersion(getOpenCodeVersion(detection.binary));
|
|
12926
|
-
})();
|
|
12927
|
-
this.resolvedWriteKey = pluginConfigKeyFor(generation);
|
|
12928
|
-
return this.resolvedWriteKey;
|
|
13232
|
+
return pluginConfigKeyFor(this.resolvedHostGeneration);
|
|
12929
13233
|
}
|
|
12930
13234
|
isInstalled() {
|
|
12931
13235
|
return detectOpenCode().kind !== "none";
|
|
@@ -12935,7 +13239,7 @@ class OpenCodeAdapter {
|
|
|
12935
13239
|
if (paths.opencodeConfigFormat === "none")
|
|
12936
13240
|
return false;
|
|
12937
13241
|
try {
|
|
12938
|
-
const raw =
|
|
13242
|
+
const raw = readFileSync6(paths.opencodeConfig, "utf-8");
|
|
12939
13243
|
const cfg = import_comment_json.parse(raw);
|
|
12940
13244
|
return readPluginEntries(cfg).some(({ entry }) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME));
|
|
12941
13245
|
} catch {
|
|
@@ -12971,7 +13275,7 @@ class OpenCodeAdapter {
|
|
|
12971
13275
|
configPath: target
|
|
12972
13276
|
};
|
|
12973
13277
|
}
|
|
12974
|
-
const raw =
|
|
13278
|
+
const raw = readFileSync6(target, "utf-8");
|
|
12975
13279
|
const cfg = import_comment_json.parse(raw);
|
|
12976
13280
|
if (cfg === null || typeof cfg !== "object") {
|
|
12977
13281
|
return {
|
|
@@ -13046,7 +13350,7 @@ class OpenCodeAdapter {
|
|
|
13046
13350
|
};
|
|
13047
13351
|
}
|
|
13048
13352
|
try {
|
|
13049
|
-
const raw =
|
|
13353
|
+
const raw = readFileSync6(target, "utf-8");
|
|
13050
13354
|
const cfg = import_comment_json.parse(raw);
|
|
13051
13355
|
if (cfg === null || typeof cfg !== "object") {
|
|
13052
13356
|
return {
|
|
@@ -13096,22 +13400,83 @@ class OpenCodeAdapter {
|
|
|
13096
13400
|
return "Install OpenCode: curl -fsSL https://opencode.ai/install | bash";
|
|
13097
13401
|
}
|
|
13098
13402
|
getPluginCacheInfo() {
|
|
13099
|
-
const
|
|
13100
|
-
|
|
13101
|
-
|
|
13102
|
-
|
|
13103
|
-
|
|
13104
|
-
|
|
13403
|
+
const legacyPath = getOpenCodePluginCacheDir();
|
|
13404
|
+
const legacyExists = existsSync10(legacyPath);
|
|
13405
|
+
const slot = getOpenCodeV2PluginCacheSlot();
|
|
13406
|
+
const slotExists = existsSync10(slot);
|
|
13407
|
+
const caches = [];
|
|
13408
|
+
if (legacyExists || !slotExists) {
|
|
13409
|
+
caches.push({
|
|
13410
|
+
path: legacyPath,
|
|
13411
|
+
exists: legacyExists,
|
|
13412
|
+
sizeBytes: dirSizeBytes(legacyPath),
|
|
13413
|
+
label: "OpenCode 1 plugin packages"
|
|
13414
|
+
});
|
|
13415
|
+
}
|
|
13416
|
+
if (slotExists) {
|
|
13417
|
+
caches.push({
|
|
13418
|
+
path: slot,
|
|
13419
|
+
exists: true,
|
|
13420
|
+
sizeBytes: dirSizeBytes(slot),
|
|
13421
|
+
label: "OpenCode 2 Magic Context @latest install",
|
|
13422
|
+
clear: () => this.clearOpenCodeV2Slot(slot)
|
|
13423
|
+
});
|
|
13424
|
+
}
|
|
13425
|
+
return caches;
|
|
13426
|
+
}
|
|
13427
|
+
clearOpenCodeV2Slot(slot) {
|
|
13428
|
+
let databases;
|
|
13429
|
+
try {
|
|
13430
|
+
databases = [
|
|
13431
|
+
...new Set([resolveOpenCodeDbPath("v1").path, resolveOpenCodeDbPath("v2").path])
|
|
13432
|
+
];
|
|
13433
|
+
} catch (err) {
|
|
13434
|
+
return {
|
|
13435
|
+
cleared: false,
|
|
13436
|
+
reason: `could not locate the OpenCode database to check whether OpenCode is running (${err instanceof Error ? err.message : String(err)})`
|
|
13437
|
+
};
|
|
13438
|
+
}
|
|
13439
|
+
const removal = removeOpenCodeV2PluginCacheSlot(slot, openCodeHostDatabaseFiles(databases), {
|
|
13440
|
+
probe: this.probeHostUse
|
|
13441
|
+
});
|
|
13442
|
+
switch (removal.action) {
|
|
13443
|
+
case "cleared":
|
|
13444
|
+
return { cleared: true };
|
|
13445
|
+
case "in_use":
|
|
13446
|
+
return {
|
|
13447
|
+
cleared: false,
|
|
13448
|
+
reason: `OpenCode is running (pid ${removal.pids.join(", ")}); quit it (and \`opencode service stop\`) first`
|
|
13449
|
+
};
|
|
13450
|
+
case "in_use_unknown":
|
|
13451
|
+
return { cleared: false, reason: removal.reason };
|
|
13452
|
+
case "error":
|
|
13453
|
+
return { cleared: false, reason: removal.error };
|
|
13454
|
+
}
|
|
13105
13455
|
}
|
|
13106
13456
|
getLogPath() {
|
|
13107
13457
|
return getMagicContextLogPath2("opencode");
|
|
13108
13458
|
}
|
|
13459
|
+
configuredPluginSpec() {
|
|
13460
|
+
const paths = detectConfigPaths();
|
|
13461
|
+
if (paths.opencodeConfigFormat === "none")
|
|
13462
|
+
return "latest";
|
|
13463
|
+
try {
|
|
13464
|
+
const cfg = import_comment_json.parse(readFileSync6(paths.opencodeConfig, "utf-8"));
|
|
13465
|
+
return readConfiguredOpenCodePluginSpec(cfg);
|
|
13466
|
+
} catch {
|
|
13467
|
+
return "latest";
|
|
13468
|
+
}
|
|
13469
|
+
}
|
|
13109
13470
|
getInstalledPluginVersion() {
|
|
13471
|
+
if (this.resolvedHostGeneration === "v2") {
|
|
13472
|
+
const slot = getOpenCodeV2PluginCacheSlot(undefined, this.configuredPluginSpec());
|
|
13473
|
+
return readOpenCodeV2CachedPluginVersion(slot) ?? null;
|
|
13474
|
+
}
|
|
13110
13475
|
for (const candidate of getOpenCodePluginPackageJsonPaths()) {
|
|
13111
|
-
if (!
|
|
13476
|
+
if (!existsSync10(candidate))
|
|
13112
13477
|
continue;
|
|
13113
13478
|
try {
|
|
13114
|
-
const raw =
|
|
13479
|
+
const raw = readFileSync6(candidate, "utf-8");
|
|
13115
13480
|
const pkg = JSON.parse(raw);
|
|
13116
13481
|
if (typeof pkg.version === "string")
|
|
13117
13482
|
return pkg.version;
|
|
@@ -13147,15 +13512,15 @@ function isDevPathPluginEntry(entry) {
|
|
|
13147
13512
|
if (candidate.startsWith("file://")) {
|
|
13148
13513
|
localPath = fileURLToPath(candidate);
|
|
13149
13514
|
} else {
|
|
13150
|
-
localPath =
|
|
13515
|
+
localPath = resolve4(candidate);
|
|
13151
13516
|
}
|
|
13152
13517
|
if (statSync6(localPath).isFile())
|
|
13153
13518
|
localPath = dirname4(localPath);
|
|
13154
13519
|
const root = parsePath(localPath).root;
|
|
13155
13520
|
while (localPath !== root) {
|
|
13156
|
-
const packagePath =
|
|
13157
|
-
if (
|
|
13158
|
-
const pkg = JSON.parse(
|
|
13521
|
+
const packagePath = resolve4(localPath, "package.json");
|
|
13522
|
+
if (existsSync10(packagePath)) {
|
|
13523
|
+
const pkg = JSON.parse(readFileSync6(packagePath, "utf8"));
|
|
13159
13524
|
return pkg.name === OPENCODE_PLUGIN_NAME;
|
|
13160
13525
|
}
|
|
13161
13526
|
localPath = dirname4(localPath);
|
|
@@ -13175,7 +13540,7 @@ function matchesPluginEntry(entry, pkgName) {
|
|
|
13175
13540
|
}
|
|
13176
13541
|
function ensureDir(filePath) {
|
|
13177
13542
|
const dir = dirname4(filePath);
|
|
13178
|
-
if (!
|
|
13543
|
+
if (!existsSync10(dir)) {
|
|
13179
13544
|
const { mkdirSync } = __require("node:fs");
|
|
13180
13545
|
mkdirSync(dir, { recursive: true });
|
|
13181
13546
|
}
|
|
@@ -13183,6 +13548,7 @@ function ensureDir(filePath) {
|
|
|
13183
13548
|
var import_comment_json;
|
|
13184
13549
|
var init_opencode = __esm(() => {
|
|
13185
13550
|
init_opencode_db_path();
|
|
13551
|
+
init_doctor_opencode2_cache();
|
|
13186
13552
|
init_atomic_write();
|
|
13187
13553
|
init_opencode_detect();
|
|
13188
13554
|
init_opencode_helpers();
|
|
@@ -13193,7 +13559,7 @@ var init_opencode = __esm(() => {
|
|
|
13193
13559
|
});
|
|
13194
13560
|
|
|
13195
13561
|
// ../plugin/src/shared/jsonc-parser.ts
|
|
13196
|
-
import { existsSync as
|
|
13562
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7 } from "node:fs";
|
|
13197
13563
|
function stripJsonComments(content) {
|
|
13198
13564
|
let result = "";
|
|
13199
13565
|
let inString = false;
|
|
@@ -13368,7 +13734,7 @@ function parseJsonc2(content, options = {}) {
|
|
|
13368
13734
|
}
|
|
13369
13735
|
function readJsoncFile(filePath) {
|
|
13370
13736
|
try {
|
|
13371
|
-
return parseJsonc2(
|
|
13737
|
+
return parseJsonc2(readFileSync7(filePath, "utf-8"));
|
|
13372
13738
|
} catch (_error) {
|
|
13373
13739
|
return null;
|
|
13374
13740
|
}
|
|
@@ -13376,10 +13742,10 @@ function readJsoncFile(filePath) {
|
|
|
13376
13742
|
function detectConfigFile(basePath) {
|
|
13377
13743
|
const jsoncPath = `${basePath}.jsonc`;
|
|
13378
13744
|
const jsonPath = `${basePath}.json`;
|
|
13379
|
-
if (
|
|
13745
|
+
if (existsSync11(jsoncPath)) {
|
|
13380
13746
|
return { format: "jsonc", path: jsoncPath };
|
|
13381
13747
|
}
|
|
13382
|
-
if (
|
|
13748
|
+
if (existsSync11(jsonPath)) {
|
|
13383
13749
|
return { format: "json", path: jsonPath };
|
|
13384
13750
|
}
|
|
13385
13751
|
return { format: "none", path: jsoncPath };
|
|
@@ -13391,7 +13757,7 @@ var init_jsonc_parser = __esm(() => {
|
|
|
13391
13757
|
});
|
|
13392
13758
|
|
|
13393
13759
|
// src/lib/jsonc-config.ts
|
|
13394
|
-
import { existsSync as
|
|
13760
|
+
import { existsSync as existsSync12, readFileSync as readFileSync8 } from "node:fs";
|
|
13395
13761
|
function parseErrorLocation(content, error) {
|
|
13396
13762
|
const lines = content.split(`
|
|
13397
13763
|
`);
|
|
@@ -13407,9 +13773,9 @@ function parseErrorLocation(content, error) {
|
|
|
13407
13773
|
return { line: messageLine ? Number.parseInt(messageLine, 10) : 1, column: 1 };
|
|
13408
13774
|
}
|
|
13409
13775
|
function readJsoncConfig(path) {
|
|
13410
|
-
if (!
|
|
13776
|
+
if (!existsSync12(path))
|
|
13411
13777
|
return { kind: "missing" };
|
|
13412
|
-
const content =
|
|
13778
|
+
const content = readFileSync8(path, "utf-8");
|
|
13413
13779
|
try {
|
|
13414
13780
|
const rejectedKeyPaths = [];
|
|
13415
13781
|
const parsed = sanitizeParsedJson(import_comment_json2.parse(content), {
|
|
@@ -13458,7 +13824,7 @@ var init_jsonc_config = __esm(() => {
|
|
|
13458
13824
|
});
|
|
13459
13825
|
|
|
13460
13826
|
// src/lib/pi-package-entry.ts
|
|
13461
|
-
import { existsSync as
|
|
13827
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9 } from "node:fs";
|
|
13462
13828
|
import { isAbsolute as isAbsolute5, join as join12 } from "node:path";
|
|
13463
13829
|
function stripNpmPrefix(value) {
|
|
13464
13830
|
return value.startsWith("npm:") ? value.slice("npm:".length) : value;
|
|
@@ -13515,10 +13881,10 @@ function hasPiMagicContextPackage(entries, agentDir = getPiAgentConfigDir()) {
|
|
|
13515
13881
|
}
|
|
13516
13882
|
function isPiMagicContextPackageDir(dir) {
|
|
13517
13883
|
const packageJson = join12(dir, "package.json");
|
|
13518
|
-
if (!
|
|
13884
|
+
if (!existsSync13(packageJson))
|
|
13519
13885
|
return false;
|
|
13520
13886
|
try {
|
|
13521
|
-
const pkg = JSON.parse(
|
|
13887
|
+
const pkg = JSON.parse(readFileSync9(packageJson, "utf-8"));
|
|
13522
13888
|
return typeof pkg.name === "string" && pkg.name === PI_MAGIC_CONTEXT_PACKAGE_NAME;
|
|
13523
13889
|
} catch {
|
|
13524
13890
|
return false;
|
|
@@ -13554,7 +13920,7 @@ var init_pi_package_entry = __esm(() => {
|
|
|
13554
13920
|
});
|
|
13555
13921
|
|
|
13556
13922
|
// src/adapters/pi.ts
|
|
13557
|
-
import { existsSync as
|
|
13923
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
13558
13924
|
import { dirname as dirname5 } from "node:path";
|
|
13559
13925
|
|
|
13560
13926
|
class PiAdapter {
|
|
@@ -13656,7 +14022,7 @@ class PiAdapter {
|
|
|
13656
14022
|
return "Install Pi: https://pi.coding/install (npm: @earendil-works/pi-coding-agent)";
|
|
13657
14023
|
}
|
|
13658
14024
|
getPluginCacheInfo() {
|
|
13659
|
-
return { path: null, exists: false, sizeBytes: 0 };
|
|
14025
|
+
return [{ path: null, exists: false, sizeBytes: 0 }];
|
|
13660
14026
|
}
|
|
13661
14027
|
getLogPath() {
|
|
13662
14028
|
return getMagicContextLogPath2("pi");
|
|
@@ -13693,7 +14059,7 @@ function writePiSettings(settings) {
|
|
|
13693
14059
|
}
|
|
13694
14060
|
function ensureDir2(filePath) {
|
|
13695
14061
|
const dir = dirname5(filePath);
|
|
13696
|
-
if (!
|
|
14062
|
+
if (!existsSync14(dir)) {
|
|
13697
14063
|
const { mkdirSync } = __require("node:fs");
|
|
13698
14064
|
mkdirSync(dir, { recursive: true });
|
|
13699
14065
|
}
|
|
@@ -13823,10 +14189,10 @@ var init_harness_provider_map = __esm(() => {
|
|
|
13823
14189
|
// ../plugin/src/config/raw-loader.ts
|
|
13824
14190
|
import {
|
|
13825
14191
|
closeSync as closeSync2,
|
|
13826
|
-
existsSync as
|
|
14192
|
+
existsSync as existsSync15,
|
|
13827
14193
|
linkSync,
|
|
13828
14194
|
openSync as openSync2,
|
|
13829
|
-
readFileSync as
|
|
14195
|
+
readFileSync as readFileSync10,
|
|
13830
14196
|
renameSync as renameSync3,
|
|
13831
14197
|
statSync as statSync7,
|
|
13832
14198
|
unlinkSync as unlinkSync2,
|
|
@@ -14026,7 +14392,7 @@ function writeExclusiveBackup(backupPath, bytes, mode) {
|
|
|
14026
14392
|
if (error.code !== "EEXIST")
|
|
14027
14393
|
throw error;
|
|
14028
14394
|
}
|
|
14029
|
-
const existingBytes =
|
|
14395
|
+
const existingBytes = readFileSync10(backupPath);
|
|
14030
14396
|
if (existingBytes.equals(bytes))
|
|
14031
14397
|
return;
|
|
14032
14398
|
if (bytes.subarray(0, existingBytes.length).equals(existingBytes)) {
|
|
@@ -14070,11 +14436,11 @@ function migrationWarning(diagnostic) {
|
|
|
14070
14436
|
return diagnostic.message;
|
|
14071
14437
|
}
|
|
14072
14438
|
function loadRawConfigFile(options) {
|
|
14073
|
-
if (!
|
|
14439
|
+
if (!existsSync15(options.configPath))
|
|
14074
14440
|
return null;
|
|
14075
14441
|
let observedBytes;
|
|
14076
14442
|
try {
|
|
14077
|
-
observedBytes =
|
|
14443
|
+
observedBytes = readFileSync10(options.configPath);
|
|
14078
14444
|
} catch (error) {
|
|
14079
14445
|
throw new Error(`failed to read config: ${error instanceof Error ? error.message : String(error)}`);
|
|
14080
14446
|
}
|
|
@@ -14118,7 +14484,7 @@ function loadRawConfigFile(options) {
|
|
|
14118
14484
|
writeExclusiveBackup(backupPath, observedBytes, mode);
|
|
14119
14485
|
temporaryPath = writeTemporaryCandidate(options.configPath, migration.bytes, mode);
|
|
14120
14486
|
options.afterTemporaryWrite?.();
|
|
14121
|
-
const currentBytes =
|
|
14487
|
+
const currentBytes = readFileSync10(options.configPath);
|
|
14122
14488
|
if (!hasFlatKeys(currentBytes)) {
|
|
14123
14489
|
unlinkSync2(temporaryPath);
|
|
14124
14490
|
return {
|
|
@@ -14490,10 +14856,10 @@ var init_dreamer_setup = __esm(() => {
|
|
|
14490
14856
|
});
|
|
14491
14857
|
|
|
14492
14858
|
// src/commands/setup-pi.ts
|
|
14493
|
-
import { existsSync as
|
|
14859
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync3 } from "node:fs";
|
|
14494
14860
|
import { dirname as dirname7 } from "node:path";
|
|
14495
14861
|
function ensureDir3(path) {
|
|
14496
|
-
if (!
|
|
14862
|
+
if (!existsSync16(path))
|
|
14497
14863
|
mkdirSync3(path, { recursive: true });
|
|
14498
14864
|
}
|
|
14499
14865
|
async function getDefaultPrompts() {
|
|
@@ -15182,6 +15548,12 @@ var init_redaction = __esm(() => {
|
|
|
15182
15548
|
// ../plugin/src/shared/logger.ts
|
|
15183
15549
|
import * as fs from "node:fs";
|
|
15184
15550
|
import * as path2 from "node:path";
|
|
15551
|
+
function boundBuffer() {
|
|
15552
|
+
while (bufferedBytes > MAX_BUFFERED_BYTES && buffer.length > 0) {
|
|
15553
|
+
bufferedBytes -= Buffer.byteLength(buffer.shift() ?? "");
|
|
15554
|
+
droppedLines++;
|
|
15555
|
+
}
|
|
15556
|
+
}
|
|
15185
15557
|
function recordSwallowedWrite(error) {
|
|
15186
15558
|
try {
|
|
15187
15559
|
swallowedWriteCount++;
|
|
@@ -15264,12 +15636,12 @@ function flush() {
|
|
|
15264
15636
|
clearTimeout(flushTimer);
|
|
15265
15637
|
flushTimer = null;
|
|
15266
15638
|
}
|
|
15267
|
-
if (buffer.length === 0)
|
|
15639
|
+
if (buffer.length === 0 && droppedLines === 0)
|
|
15268
15640
|
return;
|
|
15269
|
-
const
|
|
15270
|
-
|
|
15641
|
+
const notice = droppedLines ? `[${new Date().toISOString()}] [magic-context][global] logger dropped ${droppedLines} ${droppedLines === 1 ? "line" : "lines"}: buffer exceeded ${MAX_BUFFERED_BYTES} bytes while writes were pending
|
|
15642
|
+
` : "";
|
|
15271
15643
|
try {
|
|
15272
|
-
const data = capLogData(
|
|
15644
|
+
const data = capLogData(notice + buffer.join(""));
|
|
15273
15645
|
const logFile = getMagicContextLogPath();
|
|
15274
15646
|
ensureDir4(logFile);
|
|
15275
15647
|
let currentSize = getCurrentLogSize(logFile);
|
|
@@ -15279,6 +15651,9 @@ function flush() {
|
|
|
15279
15651
|
currentSize = 0;
|
|
15280
15652
|
}
|
|
15281
15653
|
fs.appendFileSync(logFile, data, { encoding: "utf8", mode: 384 });
|
|
15654
|
+
buffer = [];
|
|
15655
|
+
bufferedBytes = 0;
|
|
15656
|
+
droppedLines = 0;
|
|
15282
15657
|
activeLogFile = logFile;
|
|
15283
15658
|
activeLogSize = currentSize + dataSize;
|
|
15284
15659
|
flushesSinceSizeCheck++;
|
|
@@ -15287,6 +15662,7 @@ function flush() {
|
|
|
15287
15662
|
activeLogSize = null;
|
|
15288
15663
|
flushesSinceSizeCheck = 0;
|
|
15289
15664
|
recordSwallowedWrite(error);
|
|
15665
|
+
boundBuffer();
|
|
15290
15666
|
}
|
|
15291
15667
|
}
|
|
15292
15668
|
function scheduleFlush() {
|
|
@@ -15304,8 +15680,11 @@ function log3(message, data) {
|
|
|
15304
15680
|
const timestamp = new Date().toISOString();
|
|
15305
15681
|
const serialized = data === undefined ? "" : data instanceof Error ? ` ${sanitizeDiagnosticText(`${data.message}${data.stack ? `
|
|
15306
15682
|
${data.stack}` : ""}`)}` : ` ${JSON.stringify(sanitizeConfigValue(data))}`;
|
|
15307
|
-
|
|
15308
|
-
|
|
15683
|
+
const line = `[${timestamp}] ${sanitizeDiagnosticText(message)}${serialized}
|
|
15684
|
+
`;
|
|
15685
|
+
buffer.push(line);
|
|
15686
|
+
bufferedBytes += Buffer.byteLength(line);
|
|
15687
|
+
boundBuffer();
|
|
15309
15688
|
if (buffer.length >= BUFFER_SIZE_LIMIT) {
|
|
15310
15689
|
flush();
|
|
15311
15690
|
} else {
|
|
@@ -15313,11 +15692,12 @@ ${data.stack}` : ""}`)}` : ` ${JSON.stringify(sanitizeConfigValue(data))}`;
|
|
|
15313
15692
|
}
|
|
15314
15693
|
} catch {}
|
|
15315
15694
|
}
|
|
15316
|
-
var isTestEnv = false, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50, MAX_LOG_FILE_BYTES, SIZE_CHECK_INTERVAL_FLUSHES = 64, activeLogFile = null, activeLogSize = null, flushesSinceSizeCheck = 0, swallowedWriteCount = 0, lastErrorMessage = null, lastErrorTime = null;
|
|
15695
|
+
var isTestEnv = false, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50, MAX_BUFFERED_BYTES, bufferedBytes = 0, droppedLines = 0, MAX_LOG_FILE_BYTES, SIZE_CHECK_INTERVAL_FLUSHES = 64, activeLogFile = null, activeLogSize = null, flushesSinceSizeCheck = 0, swallowedWriteCount = 0, lastErrorMessage = null, lastErrorTime = null;
|
|
15317
15696
|
var init_logger = __esm(() => {
|
|
15318
15697
|
init_data_path();
|
|
15319
15698
|
init_redaction();
|
|
15320
15699
|
buffer = [];
|
|
15700
|
+
MAX_BUFFERED_BYTES = 1024 * 1024;
|
|
15321
15701
|
MAX_LOG_FILE_BYTES = 32 * 1024 * 1024;
|
|
15322
15702
|
if (!isTestEnv) {
|
|
15323
15703
|
process.on("exit", flush);
|
|
@@ -21029,6 +21409,7 @@ var init_magic_context = __esm(() => {
|
|
|
21029
21409
|
maxTokens: true
|
|
21030
21410
|
});
|
|
21031
21411
|
DreamerConfigSchema = AgentMetadataSchema.extend({
|
|
21412
|
+
runner: _enum(["broca", "host"]).optional().describe(`Which side runs the dreamer completions the Rust module routes (classify-memories) in Rust transform mode: "host" runs them on this process's carrier, "broca" routes them to the Broca module. When unset, historian.runner applies, and when that is unset too the harness decides the same way it does for the historian. User-level config only.`),
|
|
21032
21413
|
opencode: DreamerOpenCodeHarnessBlockSchema.optional(),
|
|
21033
21414
|
pi: DreamerPiHarnessBlockSchema.optional(),
|
|
21034
21415
|
omp: DreamerOmpHarnessBlockSchema.optional(),
|
|
@@ -21039,12 +21420,16 @@ var init_magic_context = __esm(() => {
|
|
|
21039
21420
|
opencode: OpenCodeHarnessBlockSchema.optional(),
|
|
21040
21421
|
pi: PiHarnessBlockSchema.optional(),
|
|
21041
21422
|
omp: OmpHarnessBlockSchema.optional(),
|
|
21423
|
+
runner: _enum(["broca", "host"]).optional().describe('Which side runs the historian completion in Rust transform mode: "host" queues it for this process to run on the configured historian model, "broca" routes it to the Broca module. When unset the harness decides: OpenCode 1 and OpenCode 2 use "host", Claude Code (through the Thalamus gateway, which has no host to run a completion) uses "broca". User-level config only — it decides whose provider account pays for the call.'),
|
|
21424
|
+
host_runner: object({
|
|
21425
|
+
enabled: boolean2().optional().describe("Whether this process answers historian runs queued for a claimant (default true). Setting it to false stops the pull loop without changing historian.runner, so an operator can take one machine out of the lane and leave the queued runs for another claimant or for the runner setting to be changed deliberately.")
|
|
21426
|
+
}).optional().describe("Controls for this process's historian pull loop, which answers runs the Rust module queues for the host runner (`historian.runner: \"host\"`, or unset on OpenCode 1 and OpenCode 2). User-level config only — it decides whether this machine's provider account is spent on folds."),
|
|
21042
21427
|
two_pass: boolean2().default(false).describe("Run a second editor pass over historian output to clean low-signal U: lines and cross-compartment duplicates. Adds ~1 extra API call and ~1.3x cost per historian run. Useful for models without extended thinking support. (default: false)"),
|
|
21043
21428
|
disallowed_tools: array(_enum(["*", "read", "aft_outline", "aft_zoom", "aft_search"])).default([]).describe(`OpenCode only. Tools to REMOVE from the historian's default allow-list [read, aft_outline, aft_zoom, aft_search]. Applies to both historian and historian-editor agents. Use ["*"] to strip all tool definitions from the model request — this prevents weak instruction-following models (e.g. mistral-small-latest) from entering tool-calling loops. Individual tool names remove just that tool. Note: a user-supplied historian.permission override can re-allow a tool that disallowed_tools removed — disallowed_tools sets the baseline, permission overrides take precedence. (default: [])`)
|
|
21044
21429
|
}).optional();
|
|
21045
21430
|
EmbeddingFallbackProviderSchema = _enum(["local", "openai-compatible", "off"]);
|
|
21046
21431
|
BaseEmbeddingConfigSchema = object({
|
|
21047
|
-
provider: _enum(["local", "openai-compatible", "off", "synapse"]).default("local").describe("Embedding provider. 'local' uses Xenova/all-MiniLM-L6-v2, 'openai-compatible' requires endpoint and model, 'synapse' uses the certified local Synapse lane with an explicit fallback provider, and 'off' disables embeddings."),
|
|
21432
|
+
provider: _enum(["local", "openai-compatible", "off", "synapse"]).default("local").describe("Embedding provider. 'local' uses Xenova/all-MiniLM-L6-v2, 'openai-compatible' requires endpoint and model, 'synapse' uses the certified local Synapse lane with an explicit fallback provider, and 'off' disables embeddings. Session history is embedded for semantic ctx_search whenever the provider is not 'off', regardless of memory.enabled; memories are embedded only while memory.enabled is true."),
|
|
21048
21433
|
fallback_provider: EmbeddingFallbackProviderSchema.optional().describe("Fallback provider for the Synapse lane. Required when provider is 'synapse'; local, openai-compatible, and off are valid."),
|
|
21049
21434
|
model: string2().optional().describe("Embedding model name. Required for openai-compatible, ignored for local."),
|
|
21050
21435
|
endpoint: string2().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
|
|
@@ -21225,7 +21610,7 @@ var init_magic_context = __esm(() => {
|
|
|
21225
21610
|
min_chars: number2().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
|
|
21226
21611
|
}).default({ enabled: false, min_chars: 500 }).describe("Age-tier caveman compression for long user/assistant text parts. Active for primary sessions when enabled; never for subagents. Oldest 20% of eligible tags (outside protected tail) go to ultra, next 20% to full, next 20% to lite, newest 40% untouched. Graduated from experimental.caveman_text_compression; opt-in, default off (lossy)."),
|
|
21227
21612
|
memory: object({
|
|
21228
|
-
enabled: boolean2().default(true).describe("Enable cross-session memory (default: true)"),
|
|
21613
|
+
enabled: boolean2().default(true).describe("Enable cross-session memory (default: true). Does not affect history embedding or semantic ctx_search over session history; set embedding.provider to 'off' to stop all embedding."),
|
|
21229
21614
|
injection_budget_tokens: number2().min(500).max(20000).default(4000).describe("Token budget for memory injection on session start (min: 500, max: 20000, default: 4000)"),
|
|
21230
21615
|
auto_promote: boolean2().default(true).describe("Automatically promote eligible session facts into memory (default: true)"),
|
|
21231
21616
|
retrieval_count_promotion_threshold: number2().min(1).default(3).describe("retrieval_count threshold for promoting memory to permanent status (min: 1, default: 3)"),
|
|
@@ -21674,6 +22059,11 @@ function stripUnsafeProjectConfigFields(projectRaw) {
|
|
|
21674
22059
|
warnings.push(`Ignoring ${removed.map((path) => `historian.${path}`).join(", ")} from project config ` + "(security: historian model selection is user-level only; a repository cannot force extra compaction cost).");
|
|
21675
22060
|
}
|
|
21676
22061
|
}
|
|
22062
|
+
const dreamer = projectRaw.dreamer;
|
|
22063
|
+
if (isPlainObject3(dreamer) && "runner" in dreamer) {
|
|
22064
|
+
delete dreamer.runner;
|
|
22065
|
+
warnings.push("Ignoring dreamer.runner from project config (security: which process and provider account run dreamer completions is a user-level setting).");
|
|
22066
|
+
}
|
|
21677
22067
|
const mural = projectRaw.mural;
|
|
21678
22068
|
if (isPlainObject3(mural) && "model" in mural) {
|
|
21679
22069
|
delete mural.model;
|
|
@@ -21855,7 +22245,11 @@ var init_project_security = __esm(() => {
|
|
|
21855
22245
|
init_magic_context();
|
|
21856
22246
|
HIDDEN_AGENT_KEYS = ["historian", "dreamer"];
|
|
21857
22247
|
HARNESS_KEYS = PER_HARNESS_MODEL_KEYS;
|
|
21858
|
-
HISTORIAN_USER_ONLY_FIELDS =
|
|
22248
|
+
HISTORIAN_USER_ONLY_FIELDS = [
|
|
22249
|
+
...PER_HARNESS_MIGRATION_INVENTORY.historian.migrated_execution,
|
|
22250
|
+
"runner",
|
|
22251
|
+
"host_runner"
|
|
22252
|
+
];
|
|
21859
22253
|
PROMPT_SURFACE_USER_ONLY_FIELDS = ["guidance_override_path", "tool_descriptions"];
|
|
21860
22254
|
AGENT_ESCALATION_FIELDS = ["prompt", "permission", "tools"];
|
|
21861
22255
|
EMBEDDING_USER_ONLY_FIELDS = [
|
|
@@ -21919,16 +22313,16 @@ function resolveTransformMode(args) {
|
|
|
21919
22313
|
var RUST_COMPACTION_OFF_WARNING = "compaction-off mode does not support rust transform mode; using the TypeScript transform.", RUST_REQUIRES_USER_SUBC_WARNING = "rust mode requires user-level subc configuration; running ts.";
|
|
21920
22314
|
|
|
21921
22315
|
// ../plugin/src/config/variable.ts
|
|
21922
|
-
import { existsSync as
|
|
22316
|
+
import { existsSync as existsSync17, readFileSync as readFileSync11 } from "node:fs";
|
|
21923
22317
|
import { homedir as homedir10 } from "node:os";
|
|
21924
|
-
import { dirname as dirname9, isAbsolute as isAbsolute6, resolve as
|
|
22318
|
+
import { dirname as dirname9, isAbsolute as isAbsolute6, resolve as resolve5 } from "node:path";
|
|
21925
22319
|
function sensitiveFilePathReason(resolvedPath) {
|
|
21926
22320
|
const home = homedir10();
|
|
21927
22321
|
const sensitiveDirs = [
|
|
21928
|
-
{ dir:
|
|
21929
|
-
{ dir:
|
|
21930
|
-
{ dir:
|
|
21931
|
-
{ dir:
|
|
22322
|
+
{ dir: resolve5(home, ".ssh"), label: "SSH keys" },
|
|
22323
|
+
{ dir: resolve5(home, ".aws"), label: "AWS credentials" },
|
|
22324
|
+
{ dir: resolve5(home, ".gnupg"), label: "GnuPG keyring" },
|
|
22325
|
+
{ dir: resolve5(home, ".config", "gh"), label: "GitHub CLI auth" }
|
|
21932
22326
|
];
|
|
21933
22327
|
for (const { dir, label } of sensitiveDirs) {
|
|
21934
22328
|
if (resolvedPath === dir || resolvedPath.startsWith(`${dir}/`)) {
|
|
@@ -21986,21 +22380,21 @@ function substituteConfigVariables(input) {
|
|
|
21986
22380
|
}
|
|
21987
22381
|
let filePath = rawPath.trim();
|
|
21988
22382
|
if (filePath.startsWith("~/")) {
|
|
21989
|
-
filePath =
|
|
22383
|
+
filePath = resolve5(homedir10(), filePath.slice(2));
|
|
21990
22384
|
} else if (!isAbsolute6(filePath)) {
|
|
21991
|
-
filePath =
|
|
22385
|
+
filePath = resolve5(configDir, filePath);
|
|
21992
22386
|
}
|
|
21993
22387
|
const sensitiveReason = sensitiveFilePathReason(filePath);
|
|
21994
22388
|
if (sensitiveReason) {
|
|
21995
22389
|
warnings.push(`${token} resolves to a sensitive path (${sensitiveReason}: ${filePath}); ` + "inlining its contents into config — make sure this is intentional.");
|
|
21996
22390
|
}
|
|
21997
|
-
if (!
|
|
22391
|
+
if (!existsSync17(filePath)) {
|
|
21998
22392
|
warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
|
|
21999
22393
|
continue;
|
|
22000
22394
|
}
|
|
22001
22395
|
let contents;
|
|
22002
22396
|
try {
|
|
22003
|
-
contents =
|
|
22397
|
+
contents = readFileSync11(filePath, "utf-8").trim();
|
|
22004
22398
|
} catch (error) {
|
|
22005
22399
|
const message = error instanceof Error ? error.message : String(error);
|
|
22006
22400
|
warnings.push(`Failed to read file for ${token} (${filePath}): ${message}; using empty string`);
|
|
@@ -22019,7 +22413,7 @@ var init_variable = __esm(() => {
|
|
|
22019
22413
|
});
|
|
22020
22414
|
|
|
22021
22415
|
// ../plugin/src/config/index.ts
|
|
22022
|
-
import { existsSync as
|
|
22416
|
+
import { existsSync as existsSync18 } from "node:fs";
|
|
22023
22417
|
function getUserConfigBasePath() {
|
|
22024
22418
|
return cortexKitUserConfigBasePath();
|
|
22025
22419
|
}
|
|
@@ -22027,10 +22421,10 @@ function getProjectConfigBasePath(directory) {
|
|
|
22027
22421
|
return cortexKitProjectConfigBasePath(directory);
|
|
22028
22422
|
}
|
|
22029
22423
|
function resolveLegacyReadFallback(sources) {
|
|
22030
|
-
return { source: sources.find((s) =>
|
|
22424
|
+
return { source: sources.find((s) => existsSync18(s.path)) ?? null };
|
|
22031
22425
|
}
|
|
22032
22426
|
function loadConfigFileDetailed(configPath, source) {
|
|
22033
|
-
if (!
|
|
22427
|
+
if (!existsSync18(configPath)) {
|
|
22034
22428
|
return null;
|
|
22035
22429
|
}
|
|
22036
22430
|
let rawText;
|
|
@@ -22170,6 +22564,25 @@ function redactConfigValue(value) {
|
|
|
22170
22564
|
function formatProtectedTokensBelowMinWarning(value) {
|
|
22171
22565
|
return `protected_tokens is a token floor (minimum ${PROTECTED_TOKENS_MIN}, default derived from the context window); ${value} looks like the old protected_tags count. Remove the key to use the default, or set a token count such as 16000.`;
|
|
22172
22566
|
}
|
|
22567
|
+
function misplacedAgentModelWarnings(rawConfig) {
|
|
22568
|
+
const warnings = [];
|
|
22569
|
+
for (const agent of ["historian", "dreamer"]) {
|
|
22570
|
+
const block = rawConfig[agent];
|
|
22571
|
+
if (!block || typeof block !== "object" || Array.isArray(block))
|
|
22572
|
+
continue;
|
|
22573
|
+
const record = block;
|
|
22574
|
+
if (!Object.hasOwn(record, "model"))
|
|
22575
|
+
continue;
|
|
22576
|
+
const harnessWithModel = MODEL_HARNESS_BLOCKS.find((harness) => {
|
|
22577
|
+
const sub = record[harness];
|
|
22578
|
+
return sub !== null && typeof sub === "object" && !Array.isArray(sub) && Object.hasOwn(sub, "model");
|
|
22579
|
+
});
|
|
22580
|
+
if (harnessWithModel)
|
|
22581
|
+
continue;
|
|
22582
|
+
warnings.push(`${agent}.model is not read: the ${agent} model is resolved per harness, so it has to be ${agent}.opencode.model (OpenCode 1 and 2), ${agent}.pi.model, or ${agent}.omp.model. As written the ${agent} resolves to no models and never runs.`);
|
|
22583
|
+
}
|
|
22584
|
+
return warnings;
|
|
22585
|
+
}
|
|
22173
22586
|
function warnProtectedTagsDeprecationOnce() {
|
|
22174
22587
|
if (!warnedProtectedTagsDeprecation) {
|
|
22175
22588
|
warnedProtectedTagsDeprecation = true;
|
|
@@ -22183,6 +22596,7 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
22183
22596
|
warnProtectedTagsDeprecationOnce();
|
|
22184
22597
|
preMigrationWarnings.push("protected_tags is deprecated and ignored; use protected_tokens instead.");
|
|
22185
22598
|
}
|
|
22599
|
+
preMigrationWarnings.push(...misplacedAgentModelWarnings(rawConfig));
|
|
22186
22600
|
const migratedExperimental = migrateLegacyExperimental(configWithoutRemovedAgent, preMigrationWarnings);
|
|
22187
22601
|
const migratedDreamer = migrateDreamerV2(migratedExperimental, preMigrationWarnings);
|
|
22188
22602
|
const migrated = migrateLegacyAgentEnabledInMemory(migratedDreamer, preMigrationWarnings);
|
|
@@ -22343,8 +22757,8 @@ function loadPluginConfigDetailed(directory, applyRuntimeGlobals = true) {
|
|
|
22343
22757
|
const harnessLegacy = resolveLegacyConfigSourcesForHarness(directory, "opencode");
|
|
22344
22758
|
const userLegacyFallback = userDetected.format === "none" ? resolveLegacyReadFallback(harnessLegacy.user) : { source: null };
|
|
22345
22759
|
const projectLegacyFallback = projectDetected.format === "none" ? resolveLegacyReadFallback(harnessLegacy.project) : { source: null };
|
|
22346
|
-
const legacyUserUnmigrated = userDetected.format === "none" && !userLegacyFallback.source && legacySources.user.some((source) =>
|
|
22347
|
-
const legacyProjectUnmigrated = projectDetected.format === "none" && !projectLegacyFallback.source && legacySources.project.some((source) =>
|
|
22760
|
+
const legacyUserUnmigrated = userDetected.format === "none" && !userLegacyFallback.source && legacySources.user.some((source) => existsSync18(source.path));
|
|
22761
|
+
const legacyProjectUnmigrated = projectDetected.format === "none" && !projectLegacyFallback.source && legacySources.project.some((source) => existsSync18(source.path));
|
|
22348
22762
|
const userLoaded = userDetected.format !== "none" ? loadConfigFileDetailed(userDetected.path, "user") : userLegacyFallback.source ? loadConfigFileDetailed(userLegacyFallback.source.path, "user") : null;
|
|
22349
22763
|
const projectLoaded = projectDetected.format !== "none" ? loadConfigFileDetailed(projectDetected.path, "project") : projectLegacyFallback.source ? loadConfigFileDetailed(projectLegacyFallback.source.path, "project") : null;
|
|
22350
22764
|
const allWarnings = [];
|
|
@@ -22463,7 +22877,7 @@ function loadPluginConfigDetailed(directory, applyRuntimeGlobals = true) {
|
|
|
22463
22877
|
cacheTtlConfigured
|
|
22464
22878
|
};
|
|
22465
22879
|
}
|
|
22466
|
-
var warnedProtectedTagsDeprecation = false;
|
|
22880
|
+
var warnedProtectedTagsDeprecation = false, MODEL_HARNESS_BLOCKS;
|
|
22467
22881
|
var init_config = __esm(() => {
|
|
22468
22882
|
init_config_diagnostics();
|
|
22469
22883
|
init_jsonc_parser();
|
|
@@ -22478,11 +22892,12 @@ var init_config = __esm(() => {
|
|
|
22478
22892
|
init_removed_agent_config();
|
|
22479
22893
|
init_magic_context();
|
|
22480
22894
|
init_variable();
|
|
22895
|
+
MODEL_HARNESS_BLOCKS = ["opencode", "pi", "omp"];
|
|
22481
22896
|
});
|
|
22482
22897
|
|
|
22483
22898
|
// ../plugin/src/shared/opencode-config-dir.ts
|
|
22484
22899
|
import { homedir as homedir11 } from "node:os";
|
|
22485
|
-
import { join as join14, resolve as
|
|
22900
|
+
import { join as join14, resolve as resolve6 } from "node:path";
|
|
22486
22901
|
function resolveHomeDir() {
|
|
22487
22902
|
return process.env.HOME?.trim() || homedir11();
|
|
22488
22903
|
}
|
|
@@ -22494,7 +22909,7 @@ function getOpenCodeGlobalConfigDir() {
|
|
|
22494
22909
|
}
|
|
22495
22910
|
function getEnvConfigDir() {
|
|
22496
22911
|
const envConfigDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
22497
|
-
return envConfigDir ?
|
|
22912
|
+
return envConfigDir ? resolve6(envConfigDir) : undefined;
|
|
22498
22913
|
}
|
|
22499
22914
|
function getCliConfigDir() {
|
|
22500
22915
|
return getEnvConfigDir() ?? getOpenCodeGlobalConfigDir();
|
|
@@ -22781,7 +23196,7 @@ var init_conflict_detector = __esm(() => {
|
|
|
22781
23196
|
});
|
|
22782
23197
|
|
|
22783
23198
|
// ../plugin/src/shared/conflict-fixer.ts
|
|
22784
|
-
import { existsSync as
|
|
23199
|
+
import { existsSync as existsSync19, readFileSync as readFileSync12, writeFileSync as writeFileSync4 } from "node:fs";
|
|
22785
23200
|
import { homedir as homedir13 } from "node:os";
|
|
22786
23201
|
import { join as join16 } from "node:path";
|
|
22787
23202
|
function isRecord2(value) {
|
|
@@ -22791,11 +23206,11 @@ function asStringArray(value) {
|
|
|
22791
23206
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
22792
23207
|
}
|
|
22793
23208
|
function readConfig(filePath) {
|
|
22794
|
-
if (!
|
|
23209
|
+
if (!existsSync19(filePath)) {
|
|
22795
23210
|
return null;
|
|
22796
23211
|
}
|
|
22797
23212
|
try {
|
|
22798
|
-
const text =
|
|
23213
|
+
const text = readFileSync12(filePath, "utf-8");
|
|
22799
23214
|
const parsed = import_comment_json5.parse(text);
|
|
22800
23215
|
return isRecord2(parsed) ? { config: parsed, text } : null;
|
|
22801
23216
|
} catch {
|
|
@@ -22807,14 +23222,14 @@ function writeConfig(filePath, text) {
|
|
|
22807
23222
|
}
|
|
22808
23223
|
function resolveUserOpenCodeConfigPath() {
|
|
22809
23224
|
const paths = getOpenCodeConfigPaths({ binary: "opencode" });
|
|
22810
|
-
if (
|
|
23225
|
+
if (existsSync19(paths.configJsonc))
|
|
22811
23226
|
return paths.configJsonc;
|
|
22812
23227
|
return paths.configJson;
|
|
22813
23228
|
}
|
|
22814
23229
|
function collectOpenCodeConfigPaths(directory) {
|
|
22815
23230
|
const paths = new Set;
|
|
22816
23231
|
const userConfig = resolveUserOpenCodeConfigPath();
|
|
22817
|
-
if (
|
|
23232
|
+
if (existsSync19(userConfig)) {
|
|
22818
23233
|
paths.add(userConfig);
|
|
22819
23234
|
}
|
|
22820
23235
|
for (const filePath of [
|
|
@@ -22823,7 +23238,7 @@ function collectOpenCodeConfigPaths(directory) {
|
|
|
22823
23238
|
join16(directory, "opencode.jsonc"),
|
|
22824
23239
|
join16(directory, "opencode.json")
|
|
22825
23240
|
]) {
|
|
22826
|
-
if (
|
|
23241
|
+
if (existsSync19(filePath)) {
|
|
22827
23242
|
paths.add(filePath);
|
|
22828
23243
|
}
|
|
22829
23244
|
}
|
|
@@ -22835,10 +23250,10 @@ function collectOmoConfigPaths(directory) {
|
|
|
22835
23250
|
for (const fileName of OMO_CONFIG_NAMES) {
|
|
22836
23251
|
const userPath = join16(configDir, fileName);
|
|
22837
23252
|
const projectPath = join16(directory, fileName);
|
|
22838
|
-
if (
|
|
23253
|
+
if (existsSync19(userPath)) {
|
|
22839
23254
|
paths.add(userPath);
|
|
22840
23255
|
}
|
|
22841
|
-
if (
|
|
23256
|
+
if (existsSync19(projectPath)) {
|
|
22842
23257
|
paths.add(projectPath);
|
|
22843
23258
|
}
|
|
22844
23259
|
}
|
|
@@ -22846,13 +23261,13 @@ function collectOmoConfigPaths(directory) {
|
|
|
22846
23261
|
const omoHomeDir = join16(homeDir, ".omo");
|
|
22847
23262
|
for (const name of OMO_UNIFIED_NAMES) {
|
|
22848
23263
|
const userPath = join16(omoHomeDir, name);
|
|
22849
|
-
if (
|
|
23264
|
+
if (existsSync19(userPath)) {
|
|
22850
23265
|
paths.add(userPath);
|
|
22851
23266
|
}
|
|
22852
23267
|
}
|
|
22853
23268
|
for (const name of OMO_UNIFIED_NAMES) {
|
|
22854
23269
|
const projectPath = join16(directory, ".omo", name);
|
|
22855
|
-
if (
|
|
23270
|
+
if (existsSync19(projectPath)) {
|
|
22856
23271
|
paths.add(projectPath);
|
|
22857
23272
|
}
|
|
22858
23273
|
}
|
|
@@ -22980,7 +23395,7 @@ var init_conflict_fixer = __esm(() => {
|
|
|
22980
23395
|
});
|
|
22981
23396
|
|
|
22982
23397
|
// src/commands/setup-opencode.ts
|
|
22983
|
-
import { existsSync as
|
|
23398
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync13 } from "node:fs";
|
|
22984
23399
|
import { basename as basename3, dirname as dirname10 } from "node:path";
|
|
22985
23400
|
function resolveCompactionEnabledForWriter() {
|
|
22986
23401
|
try {
|
|
@@ -22992,7 +23407,7 @@ function resolveCompactionEnabledForWriter() {
|
|
|
22992
23407
|
}
|
|
22993
23408
|
}
|
|
22994
23409
|
function ensureDir5(dir) {
|
|
22995
|
-
if (!
|
|
23410
|
+
if (!existsSync20(dir)) {
|
|
22996
23411
|
mkdirSync5(dir, { recursive: true });
|
|
22997
23412
|
}
|
|
22998
23413
|
}
|
|
@@ -23021,7 +23436,7 @@ function readMagicContextConfigForSetup2(configPath) {
|
|
|
23021
23436
|
}
|
|
23022
23437
|
function addPluginToOpenCodeConfig(configPath, _format, removeDcp = false, compactionEnabled = true, hostGeneration = "v1") {
|
|
23023
23438
|
const registrationKey = pluginConfigKeyFor(hostGeneration);
|
|
23024
|
-
const existsAtCommit =
|
|
23439
|
+
const existsAtCommit = existsSync20(configPath);
|
|
23025
23440
|
const existing = existsAtCommit ? readJsoncConfigForUpdate(configPath) : {};
|
|
23026
23441
|
if (!existsAtCommit) {
|
|
23027
23442
|
ensureDir5(dirname10(configPath));
|
|
@@ -23033,7 +23448,7 @@ function addPluginToOpenCodeConfig(configPath, _format, removeDcp = false, compa
|
|
|
23033
23448
|
`);
|
|
23034
23449
|
return;
|
|
23035
23450
|
}
|
|
23036
|
-
let text =
|
|
23451
|
+
let text = readFileSync13(configPath, "utf-8");
|
|
23037
23452
|
let changed = false;
|
|
23038
23453
|
const rawPlugins = readPluginEntries(existing).map(({ entry }) => entry);
|
|
23039
23454
|
const retainedPlugins = removeDcp ? rawPlugins.filter((plugin) => !matchesPluginEntry(plugin, DCP_PLUGIN_NAME)) : rawPlugins;
|
|
@@ -23079,7 +23494,7 @@ function addPluginToOpenCodeConfig(configPath, _format, removeDcp = false, compa
|
|
|
23079
23494
|
writeFileAtomic(configPath, text);
|
|
23080
23495
|
}
|
|
23081
23496
|
function addPluginToTuiConfig(configPath, _format) {
|
|
23082
|
-
const existsAtCommit =
|
|
23497
|
+
const existsAtCommit = existsSync20(configPath);
|
|
23083
23498
|
const existing = existsAtCommit ? readJsoncConfigForUpdate(configPath) : {};
|
|
23084
23499
|
if (!existsAtCommit) {
|
|
23085
23500
|
ensureDir5(dirname10(configPath));
|
|
@@ -23095,7 +23510,7 @@ function addPluginToTuiConfig(configPath, _format) {
|
|
|
23095
23510
|
const hasDevEntry = rawPlugins.some((plugin) => isDevPathPluginEntry(plugin));
|
|
23096
23511
|
if (hasNpmEntry || hasDevEntry)
|
|
23097
23512
|
return;
|
|
23098
|
-
const text = Array.isArray(existing.plugin) ? appendJsoncArrayValues(
|
|
23513
|
+
const text = Array.isArray(existing.plugin) ? appendJsoncArrayValues(readFileSync13(configPath, "utf-8"), ["plugin"], [OPENCODE_PLUGIN_ENTRY_WITH_VERSION]) : setJsoncValue(readFileSync13(configPath, "utf-8"), ["plugin"], [OPENCODE_PLUGIN_ENTRY_WITH_VERSION]);
|
|
23099
23514
|
writeFileAtomic(configPath, text);
|
|
23100
23515
|
}
|
|
23101
23516
|
function findDcpPluginIndexes(plugins) {
|
|
@@ -23201,7 +23616,7 @@ async function runSetup3(dryRun = false) {
|
|
|
23201
23616
|
log2.warn("You can configure models manually in magic-context.jsonc later");
|
|
23202
23617
|
}
|
|
23203
23618
|
const paths = detectConfigPaths();
|
|
23204
|
-
const hadExistingSetup = paths.opencodeConfigFormat !== "none" ||
|
|
23619
|
+
const hadExistingSetup = paths.opencodeConfigFormat !== "none" || existsSync20(paths.magicContextConfig) || paths.tuiConfigFormat !== "none";
|
|
23205
23620
|
if (!dryRun) {
|
|
23206
23621
|
try {
|
|
23207
23622
|
assertJsoncConfigsParseable([
|
|
@@ -24491,7 +24906,7 @@ var init_context_authority = __esm(async () => {
|
|
|
24491
24906
|
// ../plugin/src/features/magic-context/memory/project-identity.ts
|
|
24492
24907
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
24493
24908
|
import { createHash as createHash2 } from "node:crypto";
|
|
24494
|
-
import { existsSync as
|
|
24909
|
+
import { existsSync as existsSync21, realpathSync as realpathSync2, statSync as statSync9 } from "node:fs";
|
|
24495
24910
|
import path3 from "node:path";
|
|
24496
24911
|
function asError(error) {
|
|
24497
24912
|
return error instanceof Error ? error : undefined;
|
|
@@ -24729,7 +25144,7 @@ function hasGitDir(canonical) {
|
|
|
24729
25144
|
function gitRootInAncestorChain(startDirectory) {
|
|
24730
25145
|
let current = startDirectory;
|
|
24731
25146
|
while (true) {
|
|
24732
|
-
if (
|
|
25147
|
+
if (existsSync21(path3.join(current, ".git"))) {
|
|
24733
25148
|
try {
|
|
24734
25149
|
return realpathSync2.native(current);
|
|
24735
25150
|
} catch {
|
|
@@ -26406,6 +26821,297 @@ function isRecord3(value) {
|
|
|
26406
26821
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26407
26822
|
}
|
|
26408
26823
|
|
|
26824
|
+
// ../plugin/src/shared/user-facing-codes.ts
|
|
26825
|
+
function userFacingFailureCode(key) {
|
|
26826
|
+
return USER_FACING_FAILURES[key].code;
|
|
26827
|
+
}
|
|
26828
|
+
var USER_FACING_FAILURES;
|
|
26829
|
+
var init_user_facing_codes = __esm(() => {
|
|
26830
|
+
USER_FACING_FAILURES = {
|
|
26831
|
+
historian_unavailable: {
|
|
26832
|
+
code: "MC-H01",
|
|
26833
|
+
sentence: "History compression could not finish this turn.",
|
|
26834
|
+
action: "It will retry automatically."
|
|
26835
|
+
},
|
|
26836
|
+
hidden_cleanup_unbound: {
|
|
26837
|
+
code: "MC-H02",
|
|
26838
|
+
sentence: "Some finished background sessions could not be removed from this host.",
|
|
26839
|
+
action: "They are removed automatically the next time Magic Context runs inside a registered OpenCode service."
|
|
26840
|
+
},
|
|
26841
|
+
historian_saved_history_misaligned: {
|
|
26842
|
+
code: "MC-H03",
|
|
26843
|
+
sentence: "History compression is paused because this session's saved summaries no longer line up with its messages.",
|
|
26844
|
+
action: "Run /ctx-recomp to rebuild them."
|
|
26845
|
+
},
|
|
26846
|
+
recomp_unavailable: {
|
|
26847
|
+
code: "MC-R01",
|
|
26848
|
+
sentence: "History compression could not be rebuilt.",
|
|
26849
|
+
action: "Run /ctx-recomp again."
|
|
26850
|
+
},
|
|
26851
|
+
dream_provider_timeout: {
|
|
26852
|
+
code: "MC-D01",
|
|
26853
|
+
sentence: "Memory maintenance took too long to respond.",
|
|
26854
|
+
action: "Run /ctx-dream again."
|
|
26855
|
+
},
|
|
26856
|
+
dream_provider_error: {
|
|
26857
|
+
code: "MC-D02",
|
|
26858
|
+
sentence: "Memory maintenance could not reach its model.",
|
|
26859
|
+
action: "Check the model connection, then run /ctx-dream again."
|
|
26860
|
+
},
|
|
26861
|
+
dream_step_limit: {
|
|
26862
|
+
code: "MC-D10",
|
|
26863
|
+
sentence: "Memory maintenance stopped at its hidden agent step limit.",
|
|
26864
|
+
action: "This task needs less work per run; changing the model connection will not help."
|
|
26865
|
+
},
|
|
26866
|
+
dream_empty_completion: {
|
|
26867
|
+
code: "MC-D03",
|
|
26868
|
+
sentence: "Memory maintenance received no usable response.",
|
|
26869
|
+
action: "Run /ctx-dream again."
|
|
26870
|
+
},
|
|
26871
|
+
dream_no_models: {
|
|
26872
|
+
code: "MC-D04",
|
|
26873
|
+
sentence: "Memory maintenance has no model available.",
|
|
26874
|
+
action: "Check the model settings, then run /ctx-dream again."
|
|
26875
|
+
},
|
|
26876
|
+
dream_child_aborted: {
|
|
26877
|
+
code: "MC-D05",
|
|
26878
|
+
sentence: "Memory maintenance was interrupted.",
|
|
26879
|
+
action: "Run /ctx-dream again."
|
|
26880
|
+
},
|
|
26881
|
+
dream_parse_failed: {
|
|
26882
|
+
code: "MC-D06",
|
|
26883
|
+
sentence: "Memory maintenance could not use the model response.",
|
|
26884
|
+
action: "Run /ctx-dream again."
|
|
26885
|
+
},
|
|
26886
|
+
dream_unknown: {
|
|
26887
|
+
code: "MC-D07",
|
|
26888
|
+
sentence: "Memory maintenance could not finish.",
|
|
26889
|
+
action: "Run /ctx-dream again."
|
|
26890
|
+
},
|
|
26891
|
+
dreamer_tick_blocked: {
|
|
26892
|
+
code: "MC-D09",
|
|
26893
|
+
sentence: "Background maintenance is not running: its last pass stopped before it reached the scheduled tasks.",
|
|
26894
|
+
action: "It is retried automatically; if it keeps happening, check the Magic Context log for the stage that stopped and run `npx @cortexkit/magic-context doctor`."
|
|
26895
|
+
},
|
|
26896
|
+
dream_task_needs_tool_loop: {
|
|
26897
|
+
code: "MC-D08",
|
|
26898
|
+
sentence: "Some memory maintenance tasks need a tool loop this host does not provide.",
|
|
26899
|
+
action: "The remaining tasks still run; the listed ones are skipped on this host."
|
|
26900
|
+
},
|
|
26901
|
+
embedding_substitution_rejected: {
|
|
26902
|
+
code: "MC-E01",
|
|
26903
|
+
sentence: "Search indexing could not use the selected model.",
|
|
26904
|
+
action: "Check the embedding model setting, then run /ctx-embed start again."
|
|
26905
|
+
},
|
|
26906
|
+
embedding_http_error: {
|
|
26907
|
+
code: "MC-E02",
|
|
26908
|
+
sentence: "The search indexing provider refused the request.",
|
|
26909
|
+
action: "Check the provider connection and credentials, then run /ctx-embed start again."
|
|
26910
|
+
},
|
|
26911
|
+
embedding_transport_error: {
|
|
26912
|
+
code: "MC-E03",
|
|
26913
|
+
sentence: "Search indexing could not reach its provider.",
|
|
26914
|
+
action: "Check the connection, then run /ctx-embed start again."
|
|
26915
|
+
},
|
|
26916
|
+
embedding_invalid_envelope: {
|
|
26917
|
+
code: "MC-E04",
|
|
26918
|
+
sentence: "Search indexing received an unsupported response.",
|
|
26919
|
+
action: "Check the embedding endpoint, then run /ctx-embed start again."
|
|
26920
|
+
},
|
|
26921
|
+
embedding_empty_result: {
|
|
26922
|
+
code: "MC-E05",
|
|
26923
|
+
sentence: "Search indexing received no usable result.",
|
|
26924
|
+
action: "Run /ctx-embed start again."
|
|
26925
|
+
},
|
|
26926
|
+
embedding_certification_refusal: {
|
|
26927
|
+
code: "MC-E06",
|
|
26928
|
+
sentence: "Search indexing is not ready for this provider.",
|
|
26929
|
+
action: "Finish the provider setup, or set a fallback provider in the embedding settings, then run /ctx-embed start again."
|
|
26930
|
+
},
|
|
26931
|
+
embedding_credential_required: {
|
|
26932
|
+
code: "MC-E07",
|
|
26933
|
+
sentence: "Search indexing needs provider credentials.",
|
|
26934
|
+
action: "Sign in to the provider, then run /ctx-embed start again."
|
|
26935
|
+
},
|
|
26936
|
+
embedding_local_binding_missing: {
|
|
26937
|
+
code: "MC-E08",
|
|
26938
|
+
sentence: "Local search indexing is unavailable on this system.",
|
|
26939
|
+
action: "Run `npx @cortexkit/magic-context doctor`, then retry."
|
|
26940
|
+
},
|
|
26941
|
+
embedding_local_fs_unavailable: {
|
|
26942
|
+
code: "MC-E09",
|
|
26943
|
+
sentence: "Local search indexing cannot save its model files.",
|
|
26944
|
+
action: "Update or reinstall Magic Context, then retry."
|
|
26945
|
+
},
|
|
26946
|
+
embedding_local_download_failure: {
|
|
26947
|
+
code: "MC-E10",
|
|
26948
|
+
sentence: "Local search indexing could not download its model.",
|
|
26949
|
+
action: "Check the network connection, then retry."
|
|
26950
|
+
},
|
|
26951
|
+
embedding_local_runtime_error: {
|
|
26952
|
+
code: "MC-E11",
|
|
26953
|
+
sentence: "Local search indexing could not start.",
|
|
26954
|
+
action: "Run `npx @cortexkit/magic-context doctor`, then retry."
|
|
26955
|
+
},
|
|
26956
|
+
embedding_unavailable: {
|
|
26957
|
+
code: "MC-E12",
|
|
26958
|
+
sentence: "Search indexing could not finish.",
|
|
26959
|
+
action: "Run /ctx-embed start again."
|
|
26960
|
+
},
|
|
26961
|
+
status_unavailable: {
|
|
26962
|
+
code: "MC-S01",
|
|
26963
|
+
sentence: "Magic Context status is temporarily unavailable.",
|
|
26964
|
+
action: "Retry /ctx-status in a moment."
|
|
26965
|
+
},
|
|
26966
|
+
transform_update_failed: {
|
|
26967
|
+
code: "MC-S02",
|
|
26968
|
+
sentence: "The last context update did not finish.",
|
|
26969
|
+
action: "Send another message to retry."
|
|
26970
|
+
},
|
|
26971
|
+
configuration_warning: {
|
|
26972
|
+
code: "MC-S03",
|
|
26973
|
+
sentence: "Some configuration settings could not be applied.",
|
|
26974
|
+
action: "Fix the configuration warning shown in /ctx-status, then restart."
|
|
26975
|
+
},
|
|
26976
|
+
status_log_unavailable: {
|
|
26977
|
+
code: "MC-S04",
|
|
26978
|
+
sentence: "Some diagnostic details could not be saved.",
|
|
26979
|
+
action: "Retry /ctx-status in a moment."
|
|
26980
|
+
},
|
|
26981
|
+
memory_writes_paused: {
|
|
26982
|
+
code: "MC-C01",
|
|
26983
|
+
sentence: "Memory writes are paused while the engine syncs.",
|
|
26984
|
+
action: "Retry in a moment."
|
|
26985
|
+
},
|
|
26986
|
+
memory_access_unavailable: {
|
|
26987
|
+
code: "MC-C02",
|
|
26988
|
+
sentence: "Memory access is temporarily unavailable.",
|
|
26989
|
+
action: "Retry in a moment."
|
|
26990
|
+
},
|
|
26991
|
+
note_changes_paused: {
|
|
26992
|
+
code: "MC-C03",
|
|
26993
|
+
sentence: "Note changes are paused while the engine syncs.",
|
|
26994
|
+
action: "Retry in a moment."
|
|
26995
|
+
},
|
|
26996
|
+
note_access_unavailable: {
|
|
26997
|
+
code: "MC-C04",
|
|
26998
|
+
sentence: "Notes are temporarily unavailable.",
|
|
26999
|
+
action: "Retry in a moment."
|
|
27000
|
+
},
|
|
27001
|
+
context_cleanup_paused: {
|
|
27002
|
+
code: "MC-C05",
|
|
27003
|
+
sentence: "Context cleanup is paused while the engine syncs.",
|
|
27004
|
+
action: "Retry in a moment."
|
|
27005
|
+
},
|
|
27006
|
+
partial_history_unavailable: {
|
|
27007
|
+
code: "MC-C06",
|
|
27008
|
+
sentence: "Partial history compression is not available in the current mode.",
|
|
27009
|
+
action: "Run /ctx-recomp without a range."
|
|
27010
|
+
},
|
|
27011
|
+
smart_note_conditions_unavailable: {
|
|
27012
|
+
code: "MC-C08",
|
|
27013
|
+
sentence: "Conditional notes are not available in the current mode.",
|
|
27014
|
+
action: "Save a regular note without a condition."
|
|
27015
|
+
},
|
|
27016
|
+
history_compression_paused: {
|
|
27017
|
+
code: "MC-C09",
|
|
27018
|
+
sentence: "History compression is paused while the engine syncs.",
|
|
27019
|
+
action: "Retry in a moment."
|
|
27020
|
+
},
|
|
27021
|
+
history_compression_needs_message: {
|
|
27022
|
+
code: "MC-C12",
|
|
27023
|
+
sentence: "History compression has not seen this session since Magic Context reconnected.",
|
|
27024
|
+
action: "Send a message in this session first, then run /ctx-wrapup again."
|
|
27025
|
+
},
|
|
27026
|
+
context_service_unavailable: {
|
|
27027
|
+
code: "MC-C10",
|
|
27028
|
+
sentence: "Magic Context is temporarily unavailable.",
|
|
27029
|
+
action: "Retry in a moment."
|
|
27030
|
+
},
|
|
27031
|
+
store_ahead_of_binary: {
|
|
27032
|
+
code: "MC-C13",
|
|
27033
|
+
sentence: "Magic Context refused to start: its store (store.db) was migrated by a newer ck-mc build than the one running.",
|
|
27034
|
+
action: "Update ck-mc, or roll back by restoring ck-mc together with context.db and store.db from the same backup."
|
|
27035
|
+
},
|
|
27036
|
+
compaction_marker_missing: {
|
|
27037
|
+
code: "MC-C11",
|
|
27038
|
+
sentence: "The history boundary marker is missing from the OpenCode store, so requests carry the full session.",
|
|
27039
|
+
action: "It is retried on every message; if this persists, run `/ctx-flush`."
|
|
27040
|
+
},
|
|
27041
|
+
memory_mirror_stalled: {
|
|
27042
|
+
code: "MC-M01",
|
|
27043
|
+
sentence: "Memory synchronization stopped before the host mirror caught up.",
|
|
27044
|
+
action: "Send another message to resume it, or run `ck doctor drain-authority`."
|
|
27045
|
+
},
|
|
27046
|
+
memory_authority_mismatch: {
|
|
27047
|
+
code: "MC-M02",
|
|
27048
|
+
sentence: "Memory authority is inconsistent between the host and module.",
|
|
27049
|
+
action: "Run `ck doctor drain-authority` before changing Rust mode."
|
|
27050
|
+
},
|
|
27051
|
+
dreamer_task_failing: {
|
|
27052
|
+
code: "MC-S05",
|
|
27053
|
+
sentence: "A background maintenance task keeps failing on its schedule.",
|
|
27054
|
+
action: "Check the Magic Context log for the failing task and its error."
|
|
27055
|
+
}
|
|
27056
|
+
};
|
|
27057
|
+
});
|
|
27058
|
+
|
|
27059
|
+
// ../plugin/src/hooks/magic-context/store-ahead-refusal.ts
|
|
27060
|
+
function renderStoreAheadOfBinaryRefusal(versions) {
|
|
27061
|
+
const failure = USER_FACING_FAILURES.store_ahead_of_binary;
|
|
27062
|
+
const sentence = versions ? `Magic Context refused to start: its store (store.db) is at schema v${versions.dbVersion} but this ck-mc build only knows up to v${versions.binaryMax}.` : failure.sentence;
|
|
27063
|
+
return `${sentence} ${failure.action} (${failure.code})`;
|
|
27064
|
+
}
|
|
27065
|
+
function isRecord4(value) {
|
|
27066
|
+
return value !== null && typeof value === "object";
|
|
27067
|
+
}
|
|
27068
|
+
function nonNegativeInteger(value) {
|
|
27069
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
27070
|
+
}
|
|
27071
|
+
function versionsFromDetail(detail) {
|
|
27072
|
+
if (!isRecord4(detail))
|
|
27073
|
+
return null;
|
|
27074
|
+
const dbVersion = nonNegativeInteger(detail.db_version);
|
|
27075
|
+
const binaryMax = nonNegativeInteger(detail.binary_max);
|
|
27076
|
+
return dbVersion !== null && binaryMax !== null ? { dbVersion, binaryMax } : null;
|
|
27077
|
+
}
|
|
27078
|
+
function versionsFromMessage(message) {
|
|
27079
|
+
if (typeof message !== "string")
|
|
27080
|
+
return null;
|
|
27081
|
+
const match = /db_version=(\d+) binary_max=(\d+)/.exec(message) ?? /schema v(\d+) but this ck-mc build only knows up to v(\d+)/.exec(message);
|
|
27082
|
+
if (!match)
|
|
27083
|
+
return null;
|
|
27084
|
+
return { dbVersion: Number(match[1]), binaryMax: Number(match[2]) };
|
|
27085
|
+
}
|
|
27086
|
+
function storeAheadOfBinaryFailure(error) {
|
|
27087
|
+
let current = error;
|
|
27088
|
+
const seen = new Set;
|
|
27089
|
+
while (isRecord4(current) && !seen.has(current)) {
|
|
27090
|
+
seen.add(current);
|
|
27091
|
+
if (current instanceof StoreAheadOfBinaryError)
|
|
27092
|
+
return current;
|
|
27093
|
+
if (current.code === STORE_AHEAD_OF_BINARY_CODE) {
|
|
27094
|
+
const versions = versionsFromDetail(current.detail) ?? versionsFromMessage(current.message);
|
|
27095
|
+
return new StoreAheadOfBinaryError(versions, { cause: error });
|
|
27096
|
+
}
|
|
27097
|
+
current = current.cause;
|
|
27098
|
+
}
|
|
27099
|
+
return null;
|
|
27100
|
+
}
|
|
27101
|
+
var STORE_AHEAD_OF_BINARY_CODE = "store_ahead_of_binary", StoreAheadOfBinaryError;
|
|
27102
|
+
var init_store_ahead_refusal = __esm(() => {
|
|
27103
|
+
init_user_facing_codes();
|
|
27104
|
+
StoreAheadOfBinaryError = class StoreAheadOfBinaryError extends Error {
|
|
27105
|
+
code = STORE_AHEAD_OF_BINARY_CODE;
|
|
27106
|
+
versions;
|
|
27107
|
+
constructor(versions, options) {
|
|
27108
|
+
super(renderStoreAheadOfBinaryRefusal(versions), options);
|
|
27109
|
+
this.name = "StoreAheadOfBinaryError";
|
|
27110
|
+
this.versions = versions;
|
|
27111
|
+
}
|
|
27112
|
+
};
|
|
27113
|
+
});
|
|
27114
|
+
|
|
26409
27115
|
// ../plugin/src/hooks/magic-context/module-transport.ts
|
|
26410
27116
|
import { realpathSync as realpathSync3 } from "node:fs";
|
|
26411
27117
|
import { join as join17 } from "node:path";
|
|
@@ -26676,7 +27382,8 @@ class SubcModuleTransport {
|
|
|
26676
27382
|
const laneDeadlineMs = Date.now() + attemptTimeoutMs;
|
|
26677
27383
|
let releaseLane = () => {};
|
|
26678
27384
|
try {
|
|
26679
|
-
|
|
27385
|
+
const outsideSessionOrder = args.method.startsWith("historian.");
|
|
27386
|
+
if (!args.bypassSessionLane && !outsideSessionOrder) {
|
|
26680
27387
|
releaseLane = await this.acquireCorrectnessLane(args.sessionId, args.signal, laneDeadlineMs);
|
|
26681
27388
|
}
|
|
26682
27389
|
} catch (error) {
|
|
@@ -26736,6 +27443,9 @@ class SubcModuleTransport {
|
|
|
26736
27443
|
} catch (error) {
|
|
26737
27444
|
if (args.signal?.aborted)
|
|
26738
27445
|
throw args.signal.reason ?? error;
|
|
27446
|
+
const storeAhead = storeAheadOfBinaryFailure(error);
|
|
27447
|
+
if (storeAhead)
|
|
27448
|
+
throw storeAhead;
|
|
26739
27449
|
if (args.method === "state_sync" && isDeadlineFailure(error)) {
|
|
26740
27450
|
const body = isRecord3(args.body) ? args.body : {};
|
|
26741
27451
|
throw Object.assign(new Error(`state_sync timeout stage=module_ack page=${body.seed_batch_index ?? 0}/${body.seed_batch_total ?? 1} series=${body.seed_id ?? "delta"} budget_ms=${attemptTimeoutMs}`), {
|
|
@@ -27049,6 +27759,7 @@ var DEFAULT_MODULE_ID = "magic-context", CONNECT_BACKOFF_INITIAL_MS = 1000, CONN
|
|
|
27049
27759
|
var init_module_transport = __esm(() => {
|
|
27050
27760
|
init_dist5();
|
|
27051
27761
|
init_data_path();
|
|
27762
|
+
init_store_ahead_refusal();
|
|
27052
27763
|
});
|
|
27053
27764
|
// ../plugin/src/shared/pi-executable.ts
|
|
27054
27765
|
function piHarnessKindFromExecutable(value) {
|
|
@@ -27064,7 +27775,10 @@ var init_pi_executable = __esm(() => {
|
|
|
27064
27775
|
|
|
27065
27776
|
// ../plugin/src/shared/rpc-utils.ts
|
|
27066
27777
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
27067
|
-
import { readFileSync as
|
|
27778
|
+
import { readFileSync as readFileSync14 } from "node:fs";
|
|
27779
|
+
function isOwnRpcServerRecord(record) {
|
|
27780
|
+
return record.pid === process.pid && record.instance_id !== undefined && ownRpcServerInstanceIds.has(record.instance_id);
|
|
27781
|
+
}
|
|
27068
27782
|
function isPidAlive(pid) {
|
|
27069
27783
|
if (!Number.isInteger(pid) || pid <= 0)
|
|
27070
27784
|
return "dead";
|
|
@@ -27587,10 +28301,11 @@ function parseRpcPortFile(content, fallbackPid = 0) {
|
|
|
27587
28301
|
function isValidPort(port) {
|
|
27588
28302
|
return Number.isInteger(port) && port > 0 && port <= 65535;
|
|
27589
28303
|
}
|
|
27590
|
-
var RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, WINDOWS_CIM_PROBE_TIMEOUT_MS = 5000, MAX_ANCESTOR_WALK_DEPTH = 16, OPEN_CODE_COMMAND_MARKERS, TASKLIST_NO_TASKS_PATTERN, WINDOWS_CIM_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress", PI_HARNESS_ARC_MARKERS, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcIdentityProcessKill, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now(), windowsProcessFactsCache = null;
|
|
28304
|
+
var ownRpcServerInstanceIds, RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, WINDOWS_CIM_PROBE_TIMEOUT_MS = 5000, MAX_ANCESTOR_WALK_DEPTH = 16, OPEN_CODE_COMMAND_MARKERS, TASKLIST_NO_TASKS_PATTERN, WINDOWS_CIM_COMMAND = "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress", PI_HARNESS_ARC_MARKERS, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcIdentityProcessKill, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now(), windowsProcessFactsCache = null;
|
|
27591
28305
|
var init_rpc_utils = __esm(() => {
|
|
27592
28306
|
init_logger();
|
|
27593
28307
|
init_pi_executable();
|
|
28308
|
+
ownRpcServerInstanceIds = new Set;
|
|
27594
28309
|
OPEN_CODE_COMMAND_MARKERS = ["opencode", "node", "bun", "electron"];
|
|
27595
28310
|
TASKLIST_NO_TASKS_PATTERN = /^INFO:\s+No tasks are running which match the specified criteria\.?$/im;
|
|
27596
28311
|
PI_HARNESS_ARC_MARKERS = [
|
|
@@ -27600,7 +28315,7 @@ var init_rpc_utils = __esm(() => {
|
|
|
27600
28315
|
"cljs/dist",
|
|
27601
28316
|
"dist/bundle/cli"
|
|
27602
28317
|
];
|
|
27603
|
-
rpcIdentityReadFileSync =
|
|
28318
|
+
rpcIdentityReadFileSync = readFileSync14;
|
|
27604
28319
|
rpcIdentityExecFileSync = execFileSync4;
|
|
27605
28320
|
rpcIdentityProcessKill = process.kill;
|
|
27606
28321
|
rpcProcessListExecFileSync = execFileSync4;
|
|
@@ -27720,7 +28435,9 @@ function formatFailClosedBlockingMessage(reason) {
|
|
|
27720
28435
|
}
|
|
27721
28436
|
return [
|
|
27722
28437
|
`Magic Context cannot migrate the shared database (one database serves every project on this machine) because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
|
|
28438
|
+
`The database is at upstream migration v${reason.persistedVersion}; this build needs v${reason.supportedVersion}.`,
|
|
27723
28439
|
"Restart the blocking process — even one from a different project — and it will pick up the new build and migrate on start; or shut it down and retry.",
|
|
28440
|
+
"If that host loads a pinned or cached older Magic Context build, a restart alone is not enough: stop it or update its Magic Context build, then start this host once so it migrates the database with nothing older attached.",
|
|
27724
28441
|
`Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
|
|
27725
28442
|
].join(" ");
|
|
27726
28443
|
}
|
|
@@ -27755,6 +28472,47 @@ var init_message_fts_rowid_map = __esm(() => {
|
|
|
27755
28472
|
activeBackfills = new WeakMap;
|
|
27756
28473
|
});
|
|
27757
28474
|
|
|
28475
|
+
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
28476
|
+
var V2_MEMORY_CATEGORIES, PROMOTABLE_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
28477
|
+
var init_constants = __esm(() => {
|
|
28478
|
+
V2_MEMORY_CATEGORIES = [
|
|
28479
|
+
"PROJECT_RULES",
|
|
28480
|
+
"ARCHITECTURE",
|
|
28481
|
+
"CONSTRAINTS",
|
|
28482
|
+
"CONFIG_VALUES",
|
|
28483
|
+
"NAMING"
|
|
28484
|
+
];
|
|
28485
|
+
PROMOTABLE_CATEGORIES = [
|
|
28486
|
+
...V2_MEMORY_CATEGORIES,
|
|
28487
|
+
"ARCHITECTURE_DECISIONS",
|
|
28488
|
+
"CONFIG_DEFAULTS",
|
|
28489
|
+
"USER_PREFERENCES",
|
|
28490
|
+
"USER_DIRECTIVES",
|
|
28491
|
+
"ENVIRONMENT",
|
|
28492
|
+
"WORKFLOW_RULES",
|
|
28493
|
+
"KNOWN_ISSUES"
|
|
28494
|
+
];
|
|
28495
|
+
CATEGORY_PRIORITY = [
|
|
28496
|
+
...V2_MEMORY_CATEGORIES,
|
|
28497
|
+
"USER_DIRECTIVES",
|
|
28498
|
+
"USER_PREFERENCES",
|
|
28499
|
+
"CONFIG_DEFAULTS",
|
|
28500
|
+
"ARCHITECTURE_DECISIONS",
|
|
28501
|
+
"ENVIRONMENT",
|
|
28502
|
+
"WORKFLOW_RULES",
|
|
28503
|
+
"KNOWN_ISSUES"
|
|
28504
|
+
];
|
|
28505
|
+
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
28506
|
+
acc[category] = index;
|
|
28507
|
+
return acc;
|
|
28508
|
+
}, {});
|
|
28509
|
+
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
28510
|
+
CATEGORY_DEFAULT_TTL = {
|
|
28511
|
+
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
28512
|
+
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
28513
|
+
};
|
|
28514
|
+
});
|
|
28515
|
+
|
|
27758
28516
|
// ../plugin/src/hooks/magic-context/compartment-parser.ts
|
|
27759
28517
|
function makeTierOpenRegex(n) {
|
|
27760
28518
|
return new RegExp(`<p${n}\\s*(/?)>`);
|
|
@@ -27784,6 +28542,8 @@ function extractTiersFromInner(inner) {
|
|
|
27784
28542
|
function parseCompartmentOutput(text) {
|
|
27785
28543
|
const compartments = [];
|
|
27786
28544
|
const facts = [];
|
|
28545
|
+
let droppedFactBlocks = 0;
|
|
28546
|
+
let droppedFacts = 0;
|
|
27787
28547
|
for (const match of text.matchAll(COMPARTMENT_REGEX)) {
|
|
27788
28548
|
const attrs = match[1];
|
|
27789
28549
|
const inner = match[2];
|
|
@@ -27833,16 +28593,21 @@ function parseCompartmentOutput(text) {
|
|
|
27833
28593
|
}
|
|
27834
28594
|
}
|
|
27835
28595
|
const factsBlockMatch = text.match(FACTS_BLOCK_REGEX);
|
|
27836
|
-
const factsScope = factsBlockMatch ? factsBlockMatch[1] : text.replace(EVENTS_BLOCK_REGEX, "").replace(/<compartment\s+[^>]*?\s*>.*?<\/compartment>/gs, "");
|
|
28596
|
+
const factsScope = factsBlockMatch ? factsBlockMatch[1] : text.replace(EVENTS_BLOCK_REGEX, "").replace(/<compartment\s+[^>]*?\s*>.*?<\/compartment>/gs, "").replace(/<(meta|user_observations|primer_candidates)>.*?<\/\1>/gs, "").replace(/<\/?(?:output|compartments)>/g, "");
|
|
27837
28597
|
for (const categoryMatch of factsScope.matchAll(CATEGORY_BLOCK_REGEX)) {
|
|
27838
28598
|
const category = categoryMatch[1];
|
|
27839
28599
|
const blockContent = categoryMatch[2];
|
|
27840
|
-
|
|
27841
|
-
|
|
27842
|
-
if (
|
|
27843
|
-
|
|
27844
|
-
|
|
28600
|
+
const items = [...blockContent.matchAll(FACT_ITEM_REGEX)].map((match) => unescapeXml(match[1].trim())).filter(Boolean);
|
|
28601
|
+
if (!HISTORIAN_CATEGORIES.has(category)) {
|
|
28602
|
+
if (items.length === 0)
|
|
28603
|
+
continue;
|
|
28604
|
+
droppedFactBlocks++;
|
|
28605
|
+
droppedFacts += items.length;
|
|
28606
|
+
log3(`[historian] Dropped <facts> category ${category} (${items.length} facts)`);
|
|
28607
|
+
continue;
|
|
27845
28608
|
}
|
|
28609
|
+
for (const content of items)
|
|
28610
|
+
facts.push({ category, content });
|
|
27846
28611
|
}
|
|
27847
28612
|
const unprocessedMatch = text.match(UNPROCESSED_REGEX);
|
|
27848
28613
|
const unprocessedFrom = unprocessedMatch ? parseInt(unprocessedMatch[1], 10) : null;
|
|
@@ -27880,7 +28645,16 @@ function parseCompartmentOutput(text) {
|
|
|
27880
28645
|
}
|
|
27881
28646
|
const events = parseEvents(text);
|
|
27882
28647
|
compartments.sort((a, b) => a.startMessage - b.startMessage);
|
|
27883
|
-
return {
|
|
28648
|
+
return {
|
|
28649
|
+
compartments,
|
|
28650
|
+
facts,
|
|
28651
|
+
droppedFactBlocks,
|
|
28652
|
+
droppedFacts,
|
|
28653
|
+
events,
|
|
28654
|
+
unprocessedFrom,
|
|
28655
|
+
userObservations,
|
|
28656
|
+
primerCandidates
|
|
28657
|
+
};
|
|
27884
28658
|
}
|
|
27885
28659
|
function parseEvents(text) {
|
|
27886
28660
|
const blockMatch = text.match(EVENTS_BLOCK_REGEX);
|
|
@@ -27906,8 +28680,10 @@ function parseEvents(text) {
|
|
|
27906
28680
|
function unescapeXml(s) {
|
|
27907
28681
|
return s.replace(/&/g, "&").replace(/'/g, "'").replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">");
|
|
27908
28682
|
}
|
|
27909
|
-
var COMPARTMENT_REGEX, ATTR_START_REGEX, ATTR_END_REGEX, ATTR_TITLE_REGEX, ATTR_EPISODE_REGEX, ATTR_IMPORTANCE_REGEX, TIER_OPEN_REGEXES, TIER_CLOSE_ANY_REGEX, TIER_OPEN_ANY_REGEX, CATEGORY_BLOCK_REGEX, FACT_ITEM_REGEX, UNPROCESSED_REGEX, USER_OBSERVATIONS_REGEX, USER_OBS_ITEM_REGEX, PRIMER_CANDIDATES_REGEX, PRIMER_ELEMENT_REGEX, PRIMER_ITEM_REGEX, FACTS_BLOCK_REGEX, EVENTS_BLOCK_REGEX, EVENT_ELEMENT_REGEX, EVENT_FIELD_REGEX;
|
|
28683
|
+
var COMPARTMENT_REGEX, ATTR_START_REGEX, ATTR_END_REGEX, ATTR_TITLE_REGEX, ATTR_EPISODE_REGEX, ATTR_IMPORTANCE_REGEX, TIER_OPEN_REGEXES, TIER_CLOSE_ANY_REGEX, TIER_OPEN_ANY_REGEX, CATEGORY_BLOCK_REGEX, HISTORIAN_CATEGORIES, FACT_ITEM_REGEX, UNPROCESSED_REGEX, USER_OBSERVATIONS_REGEX, USER_OBS_ITEM_REGEX, PRIMER_CANDIDATES_REGEX, PRIMER_ELEMENT_REGEX, PRIMER_ITEM_REGEX, FACTS_BLOCK_REGEX, EVENTS_BLOCK_REGEX, EVENT_ELEMENT_REGEX, EVENT_FIELD_REGEX;
|
|
27910
28684
|
var init_compartment_parser = __esm(() => {
|
|
28685
|
+
init_constants();
|
|
28686
|
+
init_logger();
|
|
27911
28687
|
COMPARTMENT_REGEX = /<compartment\s+([^>]*?)\s*>(.*?)<\/compartment>/gs;
|
|
27912
28688
|
ATTR_START_REGEX = /\bstart="(\d+)"/;
|
|
27913
28689
|
ATTR_END_REGEX = /\bend="(\d+)"/;
|
|
@@ -27922,7 +28698,8 @@ var init_compartment_parser = __esm(() => {
|
|
|
27922
28698
|
];
|
|
27923
28699
|
TIER_CLOSE_ANY_REGEX = /<\/p\d/;
|
|
27924
28700
|
TIER_OPEN_ANY_REGEX = /<p\d/;
|
|
27925
|
-
CATEGORY_BLOCK_REGEX = /<(
|
|
28701
|
+
CATEGORY_BLOCK_REGEX = /<([A-Za-z_][A-Za-z0-9_-]*)>(.*?)<\/\1>/gs;
|
|
28702
|
+
HISTORIAN_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
27926
28703
|
FACT_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
|
|
27927
28704
|
UNPROCESSED_REGEX = /<unprocessed_from>(\d+)<\/unprocessed_from>/;
|
|
27928
28705
|
USER_OBSERVATIONS_REGEX = /<user_observations>(.*?)<\/user_observations>/s;
|
|
@@ -28289,41 +29066,6 @@ function healMissingMemoryBlockIds(db, columns) {
|
|
|
28289
29066
|
db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != '' AND (memory_block_ids IS NULL OR memory_block_ids = '') AND memory_block_count > 0").run();
|
|
28290
29067
|
}
|
|
28291
29068
|
|
|
28292
|
-
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
28293
|
-
var V2_MEMORY_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
28294
|
-
var init_constants = __esm(() => {
|
|
28295
|
-
V2_MEMORY_CATEGORIES = [
|
|
28296
|
-
"PROJECT_RULES",
|
|
28297
|
-
"ARCHITECTURE",
|
|
28298
|
-
"CONSTRAINTS",
|
|
28299
|
-
"CONFIG_VALUES",
|
|
28300
|
-
"NAMING"
|
|
28301
|
-
];
|
|
28302
|
-
CATEGORY_PRIORITY = [
|
|
28303
|
-
"PROJECT_RULES",
|
|
28304
|
-
"ARCHITECTURE",
|
|
28305
|
-
"CONSTRAINTS",
|
|
28306
|
-
"CONFIG_VALUES",
|
|
28307
|
-
"NAMING",
|
|
28308
|
-
"USER_DIRECTIVES",
|
|
28309
|
-
"USER_PREFERENCES",
|
|
28310
|
-
"CONFIG_DEFAULTS",
|
|
28311
|
-
"ARCHITECTURE_DECISIONS",
|
|
28312
|
-
"ENVIRONMENT",
|
|
28313
|
-
"WORKFLOW_RULES",
|
|
28314
|
-
"KNOWN_ISSUES"
|
|
28315
|
-
];
|
|
28316
|
-
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
28317
|
-
acc[category] = index;
|
|
28318
|
-
return acc;
|
|
28319
|
-
}, {});
|
|
28320
|
-
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
28321
|
-
CATEGORY_DEFAULT_TTL = {
|
|
28322
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
28323
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
28324
|
-
};
|
|
28325
|
-
});
|
|
28326
|
-
|
|
28327
29069
|
// ../plugin/src/features/magic-context/project-identity.ts
|
|
28328
29070
|
var init_project_identity2 = __esm(() => {
|
|
28329
29071
|
init_project_identity();
|
|
@@ -30803,6 +31545,20 @@ var init_migrations = __esm(async () => {
|
|
|
30803
31545
|
return;
|
|
30804
31546
|
ensureColumn(db, "compartment_state_lease", "owner_pid", "INTEGER");
|
|
30805
31547
|
}
|
|
31548
|
+
},
|
|
31549
|
+
{
|
|
31550
|
+
version: 91,
|
|
31551
|
+
description: "per-project embedding high-water mark for memories written outside this host",
|
|
31552
|
+
up(db) {
|
|
31553
|
+
db.exec(`
|
|
31554
|
+
CREATE TABLE IF NOT EXISTS memory_embedding_watermarks (
|
|
31555
|
+
project_path TEXT PRIMARY KEY,
|
|
31556
|
+
written_memory_id INTEGER NOT NULL DEFAULT 0,
|
|
31557
|
+
embedded_memory_id INTEGER NOT NULL DEFAULT 0,
|
|
31558
|
+
updated_at INTEGER NOT NULL DEFAULT 0
|
|
31559
|
+
);
|
|
31560
|
+
`);
|
|
31561
|
+
}
|
|
30806
31562
|
}
|
|
30807
31563
|
];
|
|
30808
31564
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
@@ -30892,14 +31648,14 @@ import {
|
|
|
30892
31648
|
chmodSync as chmodSync3,
|
|
30893
31649
|
copyFileSync,
|
|
30894
31650
|
cpSync,
|
|
30895
|
-
existsSync as
|
|
31651
|
+
existsSync as existsSync22,
|
|
30896
31652
|
mkdirSync as mkdirSync6,
|
|
30897
|
-
readdirSync as
|
|
30898
|
-
readFileSync as
|
|
31653
|
+
readdirSync as readdirSync4,
|
|
31654
|
+
readFileSync as readFileSync15,
|
|
30899
31655
|
statSync as statSync10,
|
|
30900
31656
|
unlinkSync as unlinkSync3
|
|
30901
31657
|
} from "node:fs";
|
|
30902
|
-
import { basename as basename4, dirname as dirname11, join as join18, resolve as
|
|
31658
|
+
import { basename as basename4, dirname as dirname11, join as join18, resolve as resolve7 } from "node:path";
|
|
30903
31659
|
function resolveBootBusyTimeoutMs(value) {
|
|
30904
31660
|
if (value === undefined)
|
|
30905
31661
|
return BOOT_SQLITE_BUSY_TIMEOUT_MS;
|
|
@@ -31034,6 +31790,8 @@ function inspectRpcServerDiscovery(storageDir) {
|
|
|
31034
31790
|
return junk;
|
|
31035
31791
|
continue;
|
|
31036
31792
|
}
|
|
31793
|
+
if (isOwnRpcServerRecord(record))
|
|
31794
|
+
continue;
|
|
31037
31795
|
const liveness = isPidAlive(record.pid);
|
|
31038
31796
|
if (liveness === "dead") {
|
|
31039
31797
|
staleFiles.push(portFile);
|
|
@@ -31655,6 +32413,15 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
31655
32413
|
(id, cursor_session_id, cursor_ordinal, completed, updated_at)
|
|
31656
32414
|
VALUES (1, '', 0, 0, 0);
|
|
31657
32415
|
|
|
32416
|
+
-- Highest memory id another writer (the Rust module in single-store mode) put
|
|
32417
|
+
-- into memories for a project, and how far this host has embedded. Migration v91.
|
|
32418
|
+
CREATE TABLE IF NOT EXISTS memory_embedding_watermarks (
|
|
32419
|
+
project_path TEXT PRIMARY KEY,
|
|
32420
|
+
written_memory_id INTEGER NOT NULL DEFAULT 0,
|
|
32421
|
+
embedded_memory_id INTEGER NOT NULL DEFAULT 0,
|
|
32422
|
+
updated_at INTEGER NOT NULL DEFAULT 0
|
|
32423
|
+
);
|
|
32424
|
+
|
|
31658
32425
|
CREATE TABLE IF NOT EXISTS message_history_index (
|
|
31659
32426
|
session_id TEXT PRIMARY KEY,
|
|
31660
32427
|
last_indexed_ordinal INTEGER NOT NULL DEFAULT 0,
|
|
@@ -32314,7 +33081,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
32314
33081
|
`);
|
|
32315
33082
|
ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
32316
33083
|
}
|
|
32317
|
-
var databases, pendingAsyncOpens, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, LATEST_SUPPORTED_VERSION =
|
|
33084
|
+
var databases, pendingAsyncOpens, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, LATEST_SUPPORTED_VERSION = 91, BOOT_SQLITE_BUSY_TIMEOUT_MS = 5000, PERMISSIONS_ENFORCEABLE, RPC_DISCOVERY_PARSE_GRACE_MS, defaultRpcDiscoveryFs, rpcDiscoveryFs, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS;
|
|
32318
33085
|
var init_storage_db = __esm(async () => {
|
|
32319
33086
|
init_data_path();
|
|
32320
33087
|
init_logger();
|
|
@@ -32338,8 +33105,8 @@ var init_storage_db = __esm(async () => {
|
|
|
32338
33105
|
PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
|
|
32339
33106
|
RPC_DISCOVERY_PARSE_GRACE_MS = 10 * 60 * 1000;
|
|
32340
33107
|
defaultRpcDiscoveryFs = {
|
|
32341
|
-
readdirSync: (path, options) => options?.withFileTypes ?
|
|
32342
|
-
readFileSync: (path, encoding) => String(
|
|
33108
|
+
readdirSync: (path, options) => options?.withFileTypes ? readdirSync4(path, { withFileTypes: true }) : readdirSync4(path),
|
|
33109
|
+
readFileSync: (path, encoding) => String(readFileSync15(path, encoding)),
|
|
32343
33110
|
statSync: (path) => ({ mtimeMs: statSync10(path).mtimeMs }),
|
|
32344
33111
|
unlinkSync: (path) => unlinkSync3(path)
|
|
32345
33112
|
};
|
|
@@ -32352,13 +33119,13 @@ var init_storage_db = __esm(async () => {
|
|
|
32352
33119
|
});
|
|
32353
33120
|
|
|
32354
33121
|
// src/lib/database-access.ts
|
|
32355
|
-
import { existsSync as
|
|
33122
|
+
import { existsSync as existsSync23, writeFileSync as writeFileSync5 } from "node:fs";
|
|
32356
33123
|
import { pathToFileURL } from "node:url";
|
|
32357
33124
|
function getPersistedSchemaVersion2(db) {
|
|
32358
33125
|
return getPersistedSchemaVersion(db);
|
|
32359
33126
|
}
|
|
32360
33127
|
function openExistingDatabase(path, options) {
|
|
32361
|
-
if (!
|
|
33128
|
+
if (!existsSync23(path))
|
|
32362
33129
|
return null;
|
|
32363
33130
|
if (options.readonly) {
|
|
32364
33131
|
const db = new Database(path, { readonly: true });
|
|
@@ -32969,16 +33736,16 @@ var init_doctor_merge_identity = __esm(async () => {
|
|
|
32969
33736
|
});
|
|
32970
33737
|
|
|
32971
33738
|
// src/commands/doctor-repair-db.ts
|
|
32972
|
-
import { spawnSync as
|
|
33739
|
+
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
32973
33740
|
import {
|
|
32974
33741
|
chmodSync as chmodSync4,
|
|
32975
33742
|
closeSync as closeSync4,
|
|
32976
33743
|
constants as constants2,
|
|
32977
33744
|
copyFileSync as copyFileSync2,
|
|
32978
|
-
existsSync as
|
|
33745
|
+
existsSync as existsSync24,
|
|
32979
33746
|
openSync as openSync4,
|
|
32980
33747
|
renameSync as renameSync4,
|
|
32981
|
-
rmSync as
|
|
33748
|
+
rmSync as rmSync3,
|
|
32982
33749
|
statSync as statSync11
|
|
32983
33750
|
} from "node:fs";
|
|
32984
33751
|
import { dirname as dirname12, join as join20 } from "node:path";
|
|
@@ -33011,11 +33778,11 @@ function timestamp(date) {
|
|
|
33011
33778
|
return date.toISOString().replaceAll("-", "").replaceAll(":", "").replace(".", "");
|
|
33012
33779
|
}
|
|
33013
33780
|
function uniqueBase(preferred) {
|
|
33014
|
-
if (!DATABASE_SUFFIXES.some((suffix) =>
|
|
33781
|
+
if (!DATABASE_SUFFIXES.some((suffix) => existsSync24(`${preferred}${suffix}`)))
|
|
33015
33782
|
return preferred;
|
|
33016
33783
|
for (let attempt = 1;attempt < 1e4; attempt++) {
|
|
33017
33784
|
const candidate = `${preferred}-${attempt}`;
|
|
33018
|
-
if (!DATABASE_SUFFIXES.some((suffix) =>
|
|
33785
|
+
if (!DATABASE_SUFFIXES.some((suffix) => existsSync24(`${candidate}${suffix}`)))
|
|
33019
33786
|
return candidate;
|
|
33020
33787
|
}
|
|
33021
33788
|
throw new Error(`Could not allocate a unique recovery path beside ${preferred}`);
|
|
@@ -33029,7 +33796,7 @@ function copyDatabaseBundle(sourceBase, destinationBase) {
|
|
|
33029
33796
|
const copiedPaths = [];
|
|
33030
33797
|
for (const suffix of DATABASE_SUFFIXES) {
|
|
33031
33798
|
const source = `${sourceBase}${suffix}`;
|
|
33032
|
-
if (!
|
|
33799
|
+
if (!existsSync24(source))
|
|
33033
33800
|
continue;
|
|
33034
33801
|
const destination = `${destinationBase}${suffix}`;
|
|
33035
33802
|
copyFileSync2(source, destination, constants2.COPYFILE_EXCL);
|
|
@@ -33097,7 +33864,7 @@ function runRecoverShell(sqliteExecutable, sourcePath, recoveredPath, dumpPath)
|
|
|
33097
33864
|
let dumpWriteFd = null;
|
|
33098
33865
|
try {
|
|
33099
33866
|
dumpWriteFd = openSync4(dumpPath, "wx", 384);
|
|
33100
|
-
const recovered =
|
|
33867
|
+
const recovered = spawnSync4(sqliteExecutable, [sourcePath, ".recover"], {
|
|
33101
33868
|
stdio: ["ignore", dumpWriteFd, "pipe"],
|
|
33102
33869
|
encoding: "utf8",
|
|
33103
33870
|
windowsHide: true
|
|
@@ -33116,7 +33883,7 @@ function runRecoverShell(sqliteExecutable, sourcePath, recoveredPath, dumpPath)
|
|
|
33116
33883
|
}
|
|
33117
33884
|
const dumpReadFd = openSync4(dumpPath, "r");
|
|
33118
33885
|
try {
|
|
33119
|
-
const replayed =
|
|
33886
|
+
const replayed = spawnSync4(sqliteExecutable, [recoveredPath], {
|
|
33120
33887
|
stdio: [dumpReadFd, "ignore", "pipe"],
|
|
33121
33888
|
encoding: "utf8",
|
|
33122
33889
|
windowsHide: true
|
|
@@ -33143,7 +33910,7 @@ function runRecoverShell(sqliteExecutable, sourcePath, recoveredPath, dumpPath)
|
|
|
33143
33910
|
} finally {
|
|
33144
33911
|
if (dumpWriteFd !== null)
|
|
33145
33912
|
closeSync4(dumpWriteFd);
|
|
33146
|
-
|
|
33913
|
+
rmSync3(dumpPath, { force: true });
|
|
33147
33914
|
}
|
|
33148
33915
|
}
|
|
33149
33916
|
function migrateAndCheckRecoveredDatabase(path) {
|
|
@@ -33222,14 +33989,14 @@ function prepareFreshDatabase(path) {
|
|
|
33222
33989
|
}
|
|
33223
33990
|
function removeRecoveryBundle(basePath) {
|
|
33224
33991
|
for (const suffix of DATABASE_SUFFIXES)
|
|
33225
|
-
|
|
33992
|
+
rmSync3(`${basePath}${suffix}`, { force: true });
|
|
33226
33993
|
}
|
|
33227
33994
|
function activateReplacement(dbPath, replacementPath, originalAsidePath) {
|
|
33228
33995
|
const movedOriginals = [];
|
|
33229
33996
|
try {
|
|
33230
33997
|
for (const suffix of DATABASE_SUFFIXES) {
|
|
33231
33998
|
const from = `${dbPath}${suffix}`;
|
|
33232
|
-
if (!
|
|
33999
|
+
if (!existsSync24(from))
|
|
33233
34000
|
continue;
|
|
33234
34001
|
const to = `${originalAsidePath}${suffix}`;
|
|
33235
34002
|
renameSync4(from, to);
|
|
@@ -33239,7 +34006,7 @@ function activateReplacement(dbPath, replacementPath, originalAsidePath) {
|
|
|
33239
34006
|
return movedOriginals.map(({ to }) => to);
|
|
33240
34007
|
} catch (error) {
|
|
33241
34008
|
for (const moved of movedOriginals.reverse()) {
|
|
33242
|
-
if (
|
|
34009
|
+
if (existsSync24(moved.to) && !existsSync24(moved.from))
|
|
33243
34010
|
renameSync4(moved.to, moved.from);
|
|
33244
34011
|
}
|
|
33245
34012
|
throw error;
|
|
@@ -33275,7 +34042,7 @@ async function runRepairDb(options = {}) {
|
|
|
33275
34042
|
const stamp = timestamp(deps.now());
|
|
33276
34043
|
prompts.intro("Magic Context — Repair shared database");
|
|
33277
34044
|
prompts.log.info(`Database: ${dbPath}`);
|
|
33278
|
-
if (!
|
|
34045
|
+
if (!existsSync24(dbPath)) {
|
|
33279
34046
|
prompts.log.error(`Database not found: ${dbPath}`);
|
|
33280
34047
|
prompts.log.info("Backup: not created (database does not exist)");
|
|
33281
34048
|
prompts.outro("Database repair failed");
|
|
@@ -33562,7 +34329,7 @@ var init_migration_paths = __esm(() => {
|
|
|
33562
34329
|
|
|
33563
34330
|
// src/commands/migrate.ts
|
|
33564
34331
|
import { createHash as createHash4, randomBytes as randomBytes2 } from "node:crypto";
|
|
33565
|
-
import { existsSync as
|
|
34332
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync7, renameSync as renameSync5, unlinkSync as unlinkSync4 } from "node:fs";
|
|
33566
34333
|
import { dirname as dirname13, join as join21 } from "node:path";
|
|
33567
34334
|
function defaultOpenCodeDbPath() {
|
|
33568
34335
|
return getOpenCodeDatabasePath();
|
|
@@ -33574,7 +34341,7 @@ function defaultPiSessionsRoot() {
|
|
|
33574
34341
|
return getPiSessionsRoot();
|
|
33575
34342
|
}
|
|
33576
34343
|
function defaultFs() {
|
|
33577
|
-
return { writeFileAtomic, unlinkSync: unlinkSync4, existsSync:
|
|
34344
|
+
return { writeFileAtomic, unlinkSync: unlinkSync4, existsSync: existsSync25, renameSync: renameSync5, mkdirSync: mkdirSync7 };
|
|
33578
34345
|
}
|
|
33579
34346
|
function stmt(db, sql) {
|
|
33580
34347
|
return db.prepare(sql);
|
|
@@ -34522,7 +35289,7 @@ var init_relocate_memory = __esm(() => {
|
|
|
34522
35289
|
});
|
|
34523
35290
|
|
|
34524
35291
|
// src/commands/migrate-session.ts
|
|
34525
|
-
import { existsSync as
|
|
35292
|
+
import { existsSync as existsSync26, realpathSync as realpathSync4 } from "node:fs";
|
|
34526
35293
|
import { homedir as homedir14 } from "node:os";
|
|
34527
35294
|
import path4, { join as join22 } from "node:path";
|
|
34528
35295
|
function existingSessionColumns(db) {
|
|
@@ -34741,7 +35508,7 @@ function realDeps(opencodeDb, contextDb) {
|
|
|
34741
35508
|
opencodeDb,
|
|
34742
35509
|
contextDb,
|
|
34743
35510
|
resolveIdentity: resolveProjectIdentity,
|
|
34744
|
-
hasGitDir: (dir) =>
|
|
35511
|
+
hasGitDir: (dir) => existsSync26(join22(dir, ".git")),
|
|
34745
35512
|
realpath: (p) => realpathSync4(p)
|
|
34746
35513
|
};
|
|
34747
35514
|
}
|
|
@@ -34820,7 +35587,7 @@ async function runMigrateSessionCli(args) {
|
|
|
34820
35587
|
return 1;
|
|
34821
35588
|
}
|
|
34822
35589
|
const expandedTo = toDir.startsWith("~") ? join22(homedir14(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
|
|
34823
|
-
if (!
|
|
35590
|
+
if (!existsSync26(expandedTo)) {
|
|
34824
35591
|
console.error(`Target directory does not exist: ${expandedTo}`);
|
|
34825
35592
|
return 1;
|
|
34826
35593
|
}
|
|
@@ -35099,7 +35866,7 @@ async function doctorRetryV22Backfill(db) {
|
|
|
35099
35866
|
bumpProjectMemoryEpochInTransaction(db, identity, now);
|
|
35100
35867
|
succeeded += 1;
|
|
35101
35868
|
}
|
|
35102
|
-
})();
|
|
35869
|
+
}).immediate();
|
|
35103
35870
|
} catch (error) {
|
|
35104
35871
|
const classified = classifyBackfillError(error);
|
|
35105
35872
|
db.prepare(`UPDATE v22_backfill_failures
|
|
@@ -35132,7 +35899,7 @@ async function doctorRekeyV22DirIdentity(db, rawProjectPath) {
|
|
|
35132
35899
|
if (changedRows > 0) {
|
|
35133
35900
|
bumpProjectMemoryEpochInTransaction(db, newIdentity, now);
|
|
35134
35901
|
}
|
|
35135
|
-
})();
|
|
35902
|
+
}).immediate();
|
|
35136
35903
|
return { oldIdentity, newIdentity, changedRows };
|
|
35137
35904
|
}
|
|
35138
35905
|
var BACKFILL_META_KEY = "v22_legacy_memory_backfill", BACKFILL_CURSOR_META_KEY = "v22_legacy_memory_backfill_cursor", MEMORIES_TABLE = "memories";
|
|
@@ -35205,226 +35972,6 @@ var init_v22_backfill_commands = __esm(async () => {
|
|
|
35205
35972
|
await init_storage_db();
|
|
35206
35973
|
});
|
|
35207
35974
|
|
|
35208
|
-
// ../plugin/src/shared/user-facing-codes.ts
|
|
35209
|
-
function userFacingFailureCode(key) {
|
|
35210
|
-
return USER_FACING_FAILURES[key].code;
|
|
35211
|
-
}
|
|
35212
|
-
var USER_FACING_FAILURES;
|
|
35213
|
-
var init_user_facing_codes = __esm(() => {
|
|
35214
|
-
USER_FACING_FAILURES = {
|
|
35215
|
-
historian_unavailable: {
|
|
35216
|
-
code: "MC-H01",
|
|
35217
|
-
sentence: "History compression could not finish this turn.",
|
|
35218
|
-
action: "It will retry automatically."
|
|
35219
|
-
},
|
|
35220
|
-
hidden_cleanup_unbound: {
|
|
35221
|
-
code: "MC-H02",
|
|
35222
|
-
sentence: "Some finished background sessions could not be removed from this host.",
|
|
35223
|
-
action: "They are removed automatically the next time Magic Context runs inside a registered OpenCode service."
|
|
35224
|
-
},
|
|
35225
|
-
recomp_unavailable: {
|
|
35226
|
-
code: "MC-R01",
|
|
35227
|
-
sentence: "History compression could not be rebuilt.",
|
|
35228
|
-
action: "Run /ctx-recomp again."
|
|
35229
|
-
},
|
|
35230
|
-
dream_provider_timeout: {
|
|
35231
|
-
code: "MC-D01",
|
|
35232
|
-
sentence: "Memory maintenance took too long to respond.",
|
|
35233
|
-
action: "Run /ctx-dream again."
|
|
35234
|
-
},
|
|
35235
|
-
dream_provider_error: {
|
|
35236
|
-
code: "MC-D02",
|
|
35237
|
-
sentence: "Memory maintenance could not reach its model.",
|
|
35238
|
-
action: "Check the model connection, then run /ctx-dream again."
|
|
35239
|
-
},
|
|
35240
|
-
dream_empty_completion: {
|
|
35241
|
-
code: "MC-D03",
|
|
35242
|
-
sentence: "Memory maintenance received no usable response.",
|
|
35243
|
-
action: "Run /ctx-dream again."
|
|
35244
|
-
},
|
|
35245
|
-
dream_no_models: {
|
|
35246
|
-
code: "MC-D04",
|
|
35247
|
-
sentence: "Memory maintenance has no model available.",
|
|
35248
|
-
action: "Check the model settings, then run /ctx-dream again."
|
|
35249
|
-
},
|
|
35250
|
-
dream_child_aborted: {
|
|
35251
|
-
code: "MC-D05",
|
|
35252
|
-
sentence: "Memory maintenance was interrupted.",
|
|
35253
|
-
action: "Run /ctx-dream again."
|
|
35254
|
-
},
|
|
35255
|
-
dream_parse_failed: {
|
|
35256
|
-
code: "MC-D06",
|
|
35257
|
-
sentence: "Memory maintenance could not use the model response.",
|
|
35258
|
-
action: "Run /ctx-dream again."
|
|
35259
|
-
},
|
|
35260
|
-
dream_unknown: {
|
|
35261
|
-
code: "MC-D07",
|
|
35262
|
-
sentence: "Memory maintenance could not finish.",
|
|
35263
|
-
action: "Run /ctx-dream again."
|
|
35264
|
-
},
|
|
35265
|
-
dreamer_tick_blocked: {
|
|
35266
|
-
code: "MC-D09",
|
|
35267
|
-
sentence: "Background maintenance is not running: its last pass stopped before it reached the scheduled tasks.",
|
|
35268
|
-
action: "It is retried automatically; if it keeps happening, check the Magic Context log for the stage that stopped and run `npx @cortexkit/magic-context doctor`."
|
|
35269
|
-
},
|
|
35270
|
-
dream_task_needs_tool_loop: {
|
|
35271
|
-
code: "MC-D08",
|
|
35272
|
-
sentence: "Some memory maintenance tasks need a tool loop this host does not provide.",
|
|
35273
|
-
action: "The remaining tasks still run; the listed ones are skipped on this host."
|
|
35274
|
-
},
|
|
35275
|
-
embedding_substitution_rejected: {
|
|
35276
|
-
code: "MC-E01",
|
|
35277
|
-
sentence: "Search indexing could not use the selected model.",
|
|
35278
|
-
action: "Check the embedding model setting, then run /ctx-embed start again."
|
|
35279
|
-
},
|
|
35280
|
-
embedding_http_error: {
|
|
35281
|
-
code: "MC-E02",
|
|
35282
|
-
sentence: "The search indexing provider refused the request.",
|
|
35283
|
-
action: "Check the provider connection and credentials, then run /ctx-embed start again."
|
|
35284
|
-
},
|
|
35285
|
-
embedding_transport_error: {
|
|
35286
|
-
code: "MC-E03",
|
|
35287
|
-
sentence: "Search indexing could not reach its provider.",
|
|
35288
|
-
action: "Check the connection, then run /ctx-embed start again."
|
|
35289
|
-
},
|
|
35290
|
-
embedding_invalid_envelope: {
|
|
35291
|
-
code: "MC-E04",
|
|
35292
|
-
sentence: "Search indexing received an unsupported response.",
|
|
35293
|
-
action: "Check the embedding endpoint, then run /ctx-embed start again."
|
|
35294
|
-
},
|
|
35295
|
-
embedding_empty_result: {
|
|
35296
|
-
code: "MC-E05",
|
|
35297
|
-
sentence: "Search indexing received no usable result.",
|
|
35298
|
-
action: "Run /ctx-embed start again."
|
|
35299
|
-
},
|
|
35300
|
-
embedding_certification_refusal: {
|
|
35301
|
-
code: "MC-E06",
|
|
35302
|
-
sentence: "Search indexing is not ready for this provider.",
|
|
35303
|
-
action: "Finish the provider setup, or set a fallback provider in the embedding settings, then run /ctx-embed start again."
|
|
35304
|
-
},
|
|
35305
|
-
embedding_credential_required: {
|
|
35306
|
-
code: "MC-E07",
|
|
35307
|
-
sentence: "Search indexing needs provider credentials.",
|
|
35308
|
-
action: "Sign in to the provider, then run /ctx-embed start again."
|
|
35309
|
-
},
|
|
35310
|
-
embedding_local_binding_missing: {
|
|
35311
|
-
code: "MC-E08",
|
|
35312
|
-
sentence: "Local search indexing is unavailable on this system.",
|
|
35313
|
-
action: "Run `npx @cortexkit/magic-context doctor`, then retry."
|
|
35314
|
-
},
|
|
35315
|
-
embedding_local_fs_unavailable: {
|
|
35316
|
-
code: "MC-E09",
|
|
35317
|
-
sentence: "Local search indexing cannot save its model files.",
|
|
35318
|
-
action: "Update or reinstall Magic Context, then retry."
|
|
35319
|
-
},
|
|
35320
|
-
embedding_local_download_failure: {
|
|
35321
|
-
code: "MC-E10",
|
|
35322
|
-
sentence: "Local search indexing could not download its model.",
|
|
35323
|
-
action: "Check the network connection, then retry."
|
|
35324
|
-
},
|
|
35325
|
-
embedding_local_runtime_error: {
|
|
35326
|
-
code: "MC-E11",
|
|
35327
|
-
sentence: "Local search indexing could not start.",
|
|
35328
|
-
action: "Run `npx @cortexkit/magic-context doctor`, then retry."
|
|
35329
|
-
},
|
|
35330
|
-
embedding_unavailable: {
|
|
35331
|
-
code: "MC-E12",
|
|
35332
|
-
sentence: "Search indexing could not finish.",
|
|
35333
|
-
action: "Run /ctx-embed start again."
|
|
35334
|
-
},
|
|
35335
|
-
status_unavailable: {
|
|
35336
|
-
code: "MC-S01",
|
|
35337
|
-
sentence: "Magic Context status is temporarily unavailable.",
|
|
35338
|
-
action: "Retry /ctx-status in a moment."
|
|
35339
|
-
},
|
|
35340
|
-
transform_update_failed: {
|
|
35341
|
-
code: "MC-S02",
|
|
35342
|
-
sentence: "The last context update did not finish.",
|
|
35343
|
-
action: "Send another message to retry."
|
|
35344
|
-
},
|
|
35345
|
-
configuration_warning: {
|
|
35346
|
-
code: "MC-S03",
|
|
35347
|
-
sentence: "Some configuration settings could not be applied.",
|
|
35348
|
-
action: "Fix the configuration warning shown in /ctx-status, then restart."
|
|
35349
|
-
},
|
|
35350
|
-
status_log_unavailable: {
|
|
35351
|
-
code: "MC-S04",
|
|
35352
|
-
sentence: "Some diagnostic details could not be saved.",
|
|
35353
|
-
action: "Retry /ctx-status in a moment."
|
|
35354
|
-
},
|
|
35355
|
-
memory_writes_paused: {
|
|
35356
|
-
code: "MC-C01",
|
|
35357
|
-
sentence: "Memory writes are paused while the engine syncs.",
|
|
35358
|
-
action: "Retry in a moment."
|
|
35359
|
-
},
|
|
35360
|
-
memory_access_unavailable: {
|
|
35361
|
-
code: "MC-C02",
|
|
35362
|
-
sentence: "Memory access is temporarily unavailable.",
|
|
35363
|
-
action: "Retry in a moment."
|
|
35364
|
-
},
|
|
35365
|
-
note_changes_paused: {
|
|
35366
|
-
code: "MC-C03",
|
|
35367
|
-
sentence: "Note changes are paused while the engine syncs.",
|
|
35368
|
-
action: "Retry in a moment."
|
|
35369
|
-
},
|
|
35370
|
-
note_access_unavailable: {
|
|
35371
|
-
code: "MC-C04",
|
|
35372
|
-
sentence: "Notes are temporarily unavailable.",
|
|
35373
|
-
action: "Retry in a moment."
|
|
35374
|
-
},
|
|
35375
|
-
context_cleanup_paused: {
|
|
35376
|
-
code: "MC-C05",
|
|
35377
|
-
sentence: "Context cleanup is paused while the engine syncs.",
|
|
35378
|
-
action: "Retry in a moment."
|
|
35379
|
-
},
|
|
35380
|
-
partial_history_unavailable: {
|
|
35381
|
-
code: "MC-C06",
|
|
35382
|
-
sentence: "Partial history compression is not available in the current mode.",
|
|
35383
|
-
action: "Run /ctx-recomp without a range."
|
|
35384
|
-
},
|
|
35385
|
-
smart_note_conditions_unavailable: {
|
|
35386
|
-
code: "MC-C08",
|
|
35387
|
-
sentence: "Conditional notes are not available in the current mode.",
|
|
35388
|
-
action: "Save a regular note without a condition."
|
|
35389
|
-
},
|
|
35390
|
-
history_compression_paused: {
|
|
35391
|
-
code: "MC-C09",
|
|
35392
|
-
sentence: "History compression is paused while the engine syncs.",
|
|
35393
|
-
action: "Retry in a moment."
|
|
35394
|
-
},
|
|
35395
|
-
context_service_unavailable: {
|
|
35396
|
-
code: "MC-C10",
|
|
35397
|
-
sentence: "Magic Context is temporarily unavailable.",
|
|
35398
|
-
action: "Retry in a moment."
|
|
35399
|
-
},
|
|
35400
|
-
compaction_marker_missing: {
|
|
35401
|
-
code: "MC-C11",
|
|
35402
|
-
sentence: "The history boundary marker is missing from the OpenCode store, so requests carry the full session.",
|
|
35403
|
-
action: "It is retried on every message; if this persists, run `/ctx-flush`."
|
|
35404
|
-
},
|
|
35405
|
-
memory_mirror_stalled: {
|
|
35406
|
-
code: "MC-M01",
|
|
35407
|
-
sentence: "Memory synchronization stopped before the host mirror caught up.",
|
|
35408
|
-
action: "Send another message to resume it, or run `ck doctor drain-authority`."
|
|
35409
|
-
},
|
|
35410
|
-
memory_authority_mismatch: {
|
|
35411
|
-
code: "MC-M02",
|
|
35412
|
-
sentence: "Memory authority is inconsistent between the host and module.",
|
|
35413
|
-
action: "Run `ck doctor drain-authority` before changing Rust mode."
|
|
35414
|
-
},
|
|
35415
|
-
rust_mode_unsupported: {
|
|
35416
|
-
code: "MC-S06",
|
|
35417
|
-
sentence: "Experimental Rust transform mode is not available on this OpenCode host.",
|
|
35418
|
-
action: 'Magic Context is running its TypeScript mode instead; set `transform_mode` to "ts" to stop requesting Rust.'
|
|
35419
|
-
},
|
|
35420
|
-
dreamer_task_failing: {
|
|
35421
|
-
code: "MC-S05",
|
|
35422
|
-
sentence: "A background maintenance task keeps failing on its schedule.",
|
|
35423
|
-
action: "Check the Magic Context log for the failing task and its error."
|
|
35424
|
-
}
|
|
35425
|
-
};
|
|
35426
|
-
});
|
|
35427
|
-
|
|
35428
35975
|
// ../plugin/src/features/magic-context/dreamer/tick-failure.ts
|
|
35429
35976
|
function parseFailure(value) {
|
|
35430
35977
|
if (!value)
|
|
@@ -35462,7 +36009,7 @@ var init_tick_failure = __esm(() => {
|
|
|
35462
36009
|
});
|
|
35463
36010
|
|
|
35464
36011
|
// ../pi-plugin/src/config/index.ts
|
|
35465
|
-
import { existsSync as
|
|
36012
|
+
import { existsSync as existsSync27 } from "node:fs";
|
|
35466
36013
|
function getProjectConfigPaths(cwd) {
|
|
35467
36014
|
const basePath = cortexKitProjectConfigBasePath(cwd);
|
|
35468
36015
|
return [`${basePath}.jsonc`, `${basePath}.json`];
|
|
@@ -35472,10 +36019,10 @@ function getUserConfigPaths() {
|
|
|
35472
36019
|
return [`${basePath}.jsonc`, `${basePath}.json`];
|
|
35473
36020
|
}
|
|
35474
36021
|
function resolveFirstExisting(paths) {
|
|
35475
|
-
return paths.find((path) =>
|
|
36022
|
+
return paths.find((path) => existsSync27(path));
|
|
35476
36023
|
}
|
|
35477
36024
|
function resolvePiLegacyFallback(sources) {
|
|
35478
|
-
return sources.find((source) =>
|
|
36025
|
+
return sources.find((source) => existsSync27(source.path)) ?? null;
|
|
35479
36026
|
}
|
|
35480
36027
|
function loadConfigFile(path, scope) {
|
|
35481
36028
|
let raw;
|
|
@@ -35770,7 +36317,7 @@ function loadPiConfigDetailed(opts = {}, applyRuntimeGlobals = true) {
|
|
|
35770
36317
|
if (loaded)
|
|
35771
36318
|
loadedFiles.push(loaded);
|
|
35772
36319
|
}
|
|
35773
|
-
const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) =>
|
|
36320
|
+
const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) => existsSync27(source.path));
|
|
35774
36321
|
const userPath = resolveFirstExisting(getUserConfigPaths());
|
|
35775
36322
|
const userLegacyFallback = userPath ? null : resolvePiLegacyFallback(harnessLegacy.user);
|
|
35776
36323
|
const userReadPath = userPath ?? userLegacyFallback?.path;
|
|
@@ -35779,7 +36326,7 @@ function loadPiConfigDetailed(opts = {}, applyRuntimeGlobals = true) {
|
|
|
35779
36326
|
if (loaded)
|
|
35780
36327
|
loadedFiles.push(loaded);
|
|
35781
36328
|
}
|
|
35782
|
-
const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) =>
|
|
36329
|
+
const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) => existsSync27(source.path));
|
|
35783
36330
|
if (userLegacyFallback) {
|
|
35784
36331
|
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.`);
|
|
35785
36332
|
} else if (legacyUserUnmigrated) {
|
|
@@ -35900,11 +36447,11 @@ function formatDatabaseRepairGuidance(dbPath) {
|
|
|
35900
36447
|
var DATABASE_REPAIR_COMMAND = "bunx @cortexkit/magic-context@latest doctor repair-db";
|
|
35901
36448
|
|
|
35902
36449
|
// src/lib/github-issue.ts
|
|
35903
|
-
import { spawnSync as
|
|
35904
|
-
import { readFileSync as
|
|
36450
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
36451
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
35905
36452
|
function runGhCommand(args) {
|
|
35906
36453
|
try {
|
|
35907
|
-
const result =
|
|
36454
|
+
const result = spawnSync5("gh", args, {
|
|
35908
36455
|
encoding: "utf-8",
|
|
35909
36456
|
stdio: ["ignore", "pipe", "pipe"]
|
|
35910
36457
|
});
|
|
@@ -35927,7 +36474,7 @@ function failed(result) {
|
|
|
35927
36474
|
function submitGithubIssue(title, bodyPath, runner = runGhCommand) {
|
|
35928
36475
|
let body;
|
|
35929
36476
|
try {
|
|
35930
|
-
body =
|
|
36477
|
+
body = readFileSync16(bodyPath, "utf-8");
|
|
35931
36478
|
} catch (error) {
|
|
35932
36479
|
return {
|
|
35933
36480
|
ok: false,
|
|
@@ -35985,7 +36532,7 @@ var MAX_GITHUB_ISSUE_BODY_CHARS = 65536;
|
|
|
35985
36532
|
var init_github_issue = () => {};
|
|
35986
36533
|
|
|
35987
36534
|
// src/lib/log-lines.ts
|
|
35988
|
-
import { existsSync as
|
|
36535
|
+
import { existsSync as existsSync28, readFileSync as readFileSync17, statSync as statSync12 } from "node:fs";
|
|
35989
36536
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
35990
36537
|
import { join as join23 } from "node:path";
|
|
35991
36538
|
function tokenize(input, limit = Number.POSITIVE_INFINITY) {
|
|
@@ -36282,11 +36829,11 @@ function getMagicContextLogPaths(harness, options = {}) {
|
|
|
36282
36829
|
].filter((path, index, paths) => paths.indexOf(path) === index);
|
|
36283
36830
|
}
|
|
36284
36831
|
function inspectLogFile(path) {
|
|
36285
|
-
if (!
|
|
36832
|
+
if (!existsSync28(path)) {
|
|
36286
36833
|
return { path, exists: false, sizeKb: 0, lineCount: 0, grammar: "unknown" };
|
|
36287
36834
|
}
|
|
36288
36835
|
try {
|
|
36289
|
-
const content =
|
|
36836
|
+
const content = readFileSync17(path, "utf8");
|
|
36290
36837
|
const lines = content.split(/\r?\n/).filter((line) => line.length > 0);
|
|
36291
36838
|
const grammars = new Set(lines.flatMap((line) => {
|
|
36292
36839
|
const parsed = parseLogLine(line);
|
|
@@ -36313,7 +36860,7 @@ function readLogLines(files) {
|
|
|
36313
36860
|
return [];
|
|
36314
36861
|
try {
|
|
36315
36862
|
let precedingTimestamp = "";
|
|
36316
|
-
return
|
|
36863
|
+
return readFileSync17(file.path, "utf8").split(/\r?\n/).filter((line) => line.length > 0).map((line, lineIndex) => {
|
|
36317
36864
|
precedingTimestamp = parseLogLine(line)?.ts ?? precedingTimestamp;
|
|
36318
36865
|
return { line, timestamp: precedingTimestamp, fileIndex, lineIndex };
|
|
36319
36866
|
});
|
|
@@ -36362,10 +36909,10 @@ var init_redaction2 = __esm(() => {
|
|
|
36362
36909
|
});
|
|
36363
36910
|
|
|
36364
36911
|
// src/commands/doctor-omp.ts
|
|
36365
|
-
import { execFileSync as execFileSync5, spawnSync as
|
|
36366
|
-
import { existsSync as
|
|
36912
|
+
import { execFileSync as execFileSync5, spawnSync as spawnSync6 } from "node:child_process";
|
|
36913
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync8, readFileSync as readFileSync18 } from "node:fs";
|
|
36367
36914
|
import { createRequire as createRequire3 } from "node:module";
|
|
36368
|
-
import { dirname as dirname14, join as join24, resolve as
|
|
36915
|
+
import { dirname as dirname14, join as join24, resolve as resolve8 } from "node:path";
|
|
36369
36916
|
function parseSemver(value) {
|
|
36370
36917
|
const match = value?.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
36371
36918
|
return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
|
|
@@ -36407,10 +36954,10 @@ function selfVersion() {
|
|
|
36407
36954
|
return "unknown";
|
|
36408
36955
|
}
|
|
36409
36956
|
function readConfig2(path) {
|
|
36410
|
-
if (!
|
|
36957
|
+
if (!existsSync29(path))
|
|
36411
36958
|
return {};
|
|
36412
36959
|
try {
|
|
36413
|
-
const parsed = import_comment_json7.parse(
|
|
36960
|
+
const parsed = import_comment_json7.parse(readFileSync18(path, "utf-8"));
|
|
36414
36961
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? {} : { error: "top level is not an object" };
|
|
36415
36962
|
} catch (error) {
|
|
36416
36963
|
return { error: error instanceof Error ? error.message : String(error) };
|
|
@@ -36420,7 +36967,7 @@ function pluginDeclaresOmp(path) {
|
|
|
36420
36967
|
if (!path)
|
|
36421
36968
|
return null;
|
|
36422
36969
|
try {
|
|
36423
|
-
const pkg = JSON.parse(
|
|
36970
|
+
const pkg = JSON.parse(readFileSync18(join24(path, "package.json"), "utf-8"));
|
|
36424
36971
|
return Array.isArray(pkg.omp?.extensions) || Array.isArray(pkg.pi?.extensions);
|
|
36425
36972
|
} catch {
|
|
36426
36973
|
return null;
|
|
@@ -36491,8 +37038,8 @@ async function runHealthChecks(options) {
|
|
|
36491
37038
|
if (!reportedAgentDir.ok) {
|
|
36492
37039
|
add(results, "warn", "Could not verify OMP active agent directory");
|
|
36493
37040
|
} else {
|
|
36494
|
-
const reportedPath =
|
|
36495
|
-
const expectedPath =
|
|
37041
|
+
const reportedPath = resolve8(reportedAgentDir.stdout);
|
|
37042
|
+
const expectedPath = resolve8(getOmpAgentDir());
|
|
36496
37043
|
if (reportedPath === expectedPath) {
|
|
36497
37044
|
add(results, "pass", `OMP agent directory resolved to ${getOmpAgentDir()}`);
|
|
36498
37045
|
} else {
|
|
@@ -36501,7 +37048,7 @@ async function runHealthChecks(options) {
|
|
|
36501
37048
|
}
|
|
36502
37049
|
}
|
|
36503
37050
|
const userConfigPath = getOmpUserConfigPath();
|
|
36504
|
-
if (!
|
|
37051
|
+
if (!existsSync29(userConfigPath)) {
|
|
36505
37052
|
add(results, "warn", `No Magic Context user config at ${userConfigPath}`);
|
|
36506
37053
|
repairPlan.writeUserConfig = true;
|
|
36507
37054
|
} else {
|
|
@@ -36520,7 +37067,7 @@ async function runHealthChecks(options) {
|
|
|
36520
37067
|
const storage = getMagicContextStorageResolution();
|
|
36521
37068
|
const dbPath = join24(storage.path, "context.db");
|
|
36522
37069
|
add(results, "info", `Shared storage: ${storage.path} (source: ${storage.source})`);
|
|
36523
|
-
if (!
|
|
37070
|
+
if (!existsSync29(dbPath))
|
|
36524
37071
|
add(results, "info", `Shared context DB will be created at ${dbPath}`);
|
|
36525
37072
|
else {
|
|
36526
37073
|
let db = null;
|
|
@@ -36584,7 +37131,7 @@ function writeDefaultConfig(path) {
|
|
|
36584
37131
|
}
|
|
36585
37132
|
async function repair(plan, deps, prompts, cwd) {
|
|
36586
37133
|
let fixed = 0;
|
|
36587
|
-
if (plan.writeUserConfig && !
|
|
37134
|
+
if (plan.writeUserConfig && !existsSync29(getOmpUserConfigPath())) {
|
|
36588
37135
|
writeDefaultConfig(getOmpUserConfigPath());
|
|
36589
37136
|
prompts.log.success(`Wrote default Magic Context config to ${getOmpUserConfigPath()}`);
|
|
36590
37137
|
fixed += 1;
|
|
@@ -36741,7 +37288,7 @@ var init_doctor_omp = __esm(async () => {
|
|
|
36741
37288
|
now: () => new Date,
|
|
36742
37289
|
inspectMagicContextLogs,
|
|
36743
37290
|
execFileSync: execFileSync5,
|
|
36744
|
-
spawnSync:
|
|
37291
|
+
spawnSync: spawnSync6
|
|
36745
37292
|
};
|
|
36746
37293
|
});
|
|
36747
37294
|
|
|
@@ -37641,12 +38188,12 @@ function listShadowBackfillStalls(db, projectIdentity) {
|
|
|
37641
38188
|
var SHADOW_BACKFILL_PROVENANCE_KEY = "_magicContextShadowBackfill";
|
|
37642
38189
|
|
|
37643
38190
|
// ../plugin/src/shared/auto-update-provenance.ts
|
|
37644
|
-
import { existsSync as
|
|
38191
|
+
import { existsSync as existsSync30, readFileSync as readFileSync19 } from "node:fs";
|
|
37645
38192
|
function readAutoUpdateCheckState(path) {
|
|
37646
|
-
if (!
|
|
38193
|
+
if (!existsSync30(path))
|
|
37647
38194
|
return null;
|
|
37648
38195
|
try {
|
|
37649
|
-
const value = JSON.parse(
|
|
38196
|
+
const value = JSON.parse(readFileSync19(path, "utf-8"));
|
|
37650
38197
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
37651
38198
|
return null;
|
|
37652
38199
|
const raw = value;
|
|
@@ -37674,9 +38221,9 @@ var init_auto_update_provenance = () => {};
|
|
|
37674
38221
|
// ../plugin/src/shared/tui-config.ts
|
|
37675
38222
|
import {
|
|
37676
38223
|
chmodSync as chmodSync5,
|
|
37677
|
-
existsSync as
|
|
38224
|
+
existsSync as existsSync31,
|
|
37678
38225
|
mkdirSync as mkdirSync9,
|
|
37679
|
-
readFileSync as
|
|
38226
|
+
readFileSync as readFileSync20,
|
|
37680
38227
|
renameSync as renameSync6,
|
|
37681
38228
|
statSync as statSync13,
|
|
37682
38229
|
writeFileSync as writeFileSync6
|
|
@@ -37724,9 +38271,9 @@ function resolveTuiConfigPath(configDirOverride) {
|
|
|
37724
38271
|
const configDir = configDirOverride ?? getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
|
|
37725
38272
|
const jsoncPath = join25(configDir, "tui.jsonc");
|
|
37726
38273
|
const jsonPath = join25(configDir, "tui.json");
|
|
37727
|
-
if (
|
|
38274
|
+
if (existsSync31(jsoncPath))
|
|
37728
38275
|
return jsoncPath;
|
|
37729
|
-
if (
|
|
38276
|
+
if (existsSync31(jsonPath))
|
|
37730
38277
|
return jsonPath;
|
|
37731
38278
|
return jsoncPath;
|
|
37732
38279
|
}
|
|
@@ -37734,8 +38281,8 @@ function ensureTuiPluginEntry(options = {}) {
|
|
|
37734
38281
|
try {
|
|
37735
38282
|
const configPath = resolveTuiConfigPath(options.configDir);
|
|
37736
38283
|
let config = {};
|
|
37737
|
-
if (
|
|
37738
|
-
const raw =
|
|
38284
|
+
if (existsSync31(configPath)) {
|
|
38285
|
+
const raw = readFileSync20(configPath, "utf-8");
|
|
37739
38286
|
config = import_comment_json8.parse(raw) ?? {};
|
|
37740
38287
|
}
|
|
37741
38288
|
const plugins = Array.isArray(config.plugin) ? [...config.plugin] : [];
|
|
@@ -37787,7 +38334,7 @@ var init_tui_config = __esm(() => {
|
|
|
37787
38334
|
});
|
|
37788
38335
|
|
|
37789
38336
|
// src/lib/diagnostics-opencode.ts
|
|
37790
|
-
import { existsSync as
|
|
38337
|
+
import { existsSync as existsSync32, readdirSync as readdirSync5, readFileSync as readFileSync21, statSync as statSync14 } from "node:fs";
|
|
37791
38338
|
import { createRequire as createRequire4 } from "node:module";
|
|
37792
38339
|
import { join as join26 } from "node:path";
|
|
37793
38340
|
function getSelfVersion() {
|
|
@@ -37802,29 +38349,52 @@ function getSelfVersion() {
|
|
|
37802
38349
|
}
|
|
37803
38350
|
return "unknown";
|
|
37804
38351
|
}
|
|
37805
|
-
function
|
|
37806
|
-
|
|
38352
|
+
function readLegacyCachedVersion(root) {
|
|
38353
|
+
try {
|
|
38354
|
+
const pkg = JSON.parse(readFileSync21(getOpenCodePluginPackageJsonPath(root), "utf-8"));
|
|
38355
|
+
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
38356
|
+
} catch {
|
|
38357
|
+
return;
|
|
38358
|
+
}
|
|
38359
|
+
}
|
|
38360
|
+
function collectOpenCodePluginCacheReport(hostGeneration, opencodeConfig) {
|
|
38361
|
+
const installs = [];
|
|
38362
|
+
for (const root of getOpenCodePluginCacheRoots()) {
|
|
38363
|
+
if (!existsSync32(root))
|
|
38364
|
+
continue;
|
|
38365
|
+
const spec = root.endsWith("@latest") ? "latest" : "(bare)";
|
|
38366
|
+
installs.push({
|
|
38367
|
+
layout: "opencode1",
|
|
38368
|
+
spec,
|
|
38369
|
+
path: root,
|
|
38370
|
+
cached: readLegacyCachedVersion(root)
|
|
38371
|
+
});
|
|
38372
|
+
}
|
|
38373
|
+
for (const slot of listOpenCodeV2PluginCacheSlots()) {
|
|
38374
|
+
installs.push({
|
|
38375
|
+
layout: "opencode2",
|
|
38376
|
+
spec: slot.spec,
|
|
38377
|
+
path: slot.slot,
|
|
38378
|
+
cached: slot.version
|
|
38379
|
+
});
|
|
38380
|
+
}
|
|
38381
|
+
let path;
|
|
37807
38382
|
let cached;
|
|
37808
|
-
|
|
37809
|
-
|
|
37810
|
-
|
|
37811
|
-
|
|
37812
|
-
|
|
37813
|
-
|
|
37814
|
-
break;
|
|
37815
|
-
}
|
|
37816
|
-
} catch {
|
|
37817
|
-
cached = undefined;
|
|
37818
|
-
}
|
|
38383
|
+
if (hostGeneration === "v2") {
|
|
38384
|
+
path = getOpenCodeV2PluginCacheSlot(undefined, readConfiguredOpenCodePluginSpec(opencodeConfig));
|
|
38385
|
+
cached = readOpenCodeV2CachedPluginVersion(path);
|
|
38386
|
+
} else {
|
|
38387
|
+
[path = ""] = getOpenCodePluginCacheRoots();
|
|
38388
|
+
cached = installs.find((install) => install.layout === "opencode1" && install.cached)?.cached;
|
|
37819
38389
|
}
|
|
37820
|
-
return { path, cached, latest: getSelfVersion() };
|
|
38390
|
+
return { path, cached, latest: getSelfVersion(), installs };
|
|
37821
38391
|
}
|
|
37822
38392
|
function getStorageResolution() {
|
|
37823
38393
|
return getMagicContextStorageResolution();
|
|
37824
38394
|
}
|
|
37825
38395
|
function fileSize(path) {
|
|
37826
38396
|
try {
|
|
37827
|
-
return
|
|
38397
|
+
return existsSync32(path) ? statSync14(path).size : 0;
|
|
37828
38398
|
} catch {
|
|
37829
38399
|
return 0;
|
|
37830
38400
|
}
|
|
@@ -37836,10 +38406,10 @@ function sanitizeValue(value) {
|
|
|
37836
38406
|
return sanitizeConfigValue(value);
|
|
37837
38407
|
}
|
|
37838
38408
|
function readConfig3(path) {
|
|
37839
|
-
if (!
|
|
38409
|
+
if (!existsSync32(path))
|
|
37840
38410
|
return { value: null };
|
|
37841
38411
|
try {
|
|
37842
|
-
const raw =
|
|
38412
|
+
const raw = readFileSync21(path, "utf-8");
|
|
37843
38413
|
const value = import_comment_json9.parse(raw);
|
|
37844
38414
|
return { value };
|
|
37845
38415
|
} catch (error) {
|
|
@@ -37847,9 +38417,9 @@ function readConfig3(path) {
|
|
|
37847
38417
|
}
|
|
37848
38418
|
}
|
|
37849
38419
|
function configHasPluginEntry(config) {
|
|
37850
|
-
const plugins = readPluginEntries(config).map(({ entry }) => entry);
|
|
38420
|
+
const plugins = readPluginEntries(config).map(({ entry }) => pluginEntryPackage(entry));
|
|
37851
38421
|
return plugins.some((entry) => {
|
|
37852
|
-
if (
|
|
38422
|
+
if (entry === null)
|
|
37853
38423
|
return false;
|
|
37854
38424
|
if (entry === OPENCODE_PLUGIN_NAME)
|
|
37855
38425
|
return true;
|
|
@@ -37864,7 +38434,7 @@ function configHasPluginEntry(config) {
|
|
|
37864
38434
|
}
|
|
37865
38435
|
function parseHistorianDumpMeta(path) {
|
|
37866
38436
|
try {
|
|
37867
|
-
const xml =
|
|
38437
|
+
const xml = readFileSync21(path, "utf-8");
|
|
37868
38438
|
const parsed = parseCompartmentOutput(xml);
|
|
37869
38439
|
const factCountByCategory = {};
|
|
37870
38440
|
for (const fact of parsed.facts) {
|
|
@@ -37897,10 +38467,10 @@ function parseHistorianDumpMeta(path) {
|
|
|
37897
38467
|
}
|
|
37898
38468
|
}
|
|
37899
38469
|
function listDumpsInDir(dir, limit) {
|
|
37900
|
-
if (!
|
|
38470
|
+
if (!existsSync32(dir))
|
|
37901
38471
|
return { count: 0, recent: [] };
|
|
37902
38472
|
try {
|
|
37903
|
-
const entries =
|
|
38473
|
+
const entries = readdirSync5(dir).filter((name) => name.endsWith(".xml")).map((name) => {
|
|
37904
38474
|
const stat = statSync14(join26(dir, name));
|
|
37905
38475
|
return {
|
|
37906
38476
|
name,
|
|
@@ -38049,7 +38619,7 @@ async function collectRecentSessions(resolution, hostGeneration) {
|
|
|
38049
38619
|
}
|
|
38050
38620
|
async function collectHistorianFailures(storageDirPath) {
|
|
38051
38621
|
const contextDbPath = join26(storageDirPath, "context.db");
|
|
38052
|
-
if (!
|
|
38622
|
+
if (!existsSync32(contextDbPath))
|
|
38053
38623
|
return [];
|
|
38054
38624
|
if (typeof globalThis.Bun === "undefined") {
|
|
38055
38625
|
return [];
|
|
@@ -38083,7 +38653,7 @@ async function collectHistorianFailures(storageDirPath) {
|
|
|
38083
38653
|
}
|
|
38084
38654
|
async function collectHistorianRuns(storageDirPath) {
|
|
38085
38655
|
const contextDbPath = join26(storageDirPath, "context.db");
|
|
38086
|
-
if (!
|
|
38656
|
+
if (!existsSync32(contextDbPath))
|
|
38087
38657
|
return [];
|
|
38088
38658
|
if (typeof globalThis.Bun === "undefined")
|
|
38089
38659
|
return [];
|
|
@@ -38145,6 +38715,9 @@ async function collectHistorianRuns(storageDirPath) {
|
|
|
38145
38715
|
} catch {}
|
|
38146
38716
|
}
|
|
38147
38717
|
}
|
|
38718
|
+
function openCodeIssueLogHarnesses(hostGeneration) {
|
|
38719
|
+
return hostGeneration === "v2" ? ["opencode2", "opencode"] : ["opencode"];
|
|
38720
|
+
}
|
|
38148
38721
|
async function collectDiagnostics() {
|
|
38149
38722
|
const pluginVersion = getSelfVersion();
|
|
38150
38723
|
const configPaths = detectConfigPaths();
|
|
@@ -38154,8 +38727,6 @@ async function collectDiagnostics() {
|
|
|
38154
38727
|
const storageResolution = getStorageResolution();
|
|
38155
38728
|
const storageDirPath = storageResolution.path;
|
|
38156
38729
|
const contextDbPath = join26(storageDirPath, "context.db");
|
|
38157
|
-
const logFiles = inspectMagicContextLogs("opencode");
|
|
38158
|
-
const primaryLog = logFiles.find((file) => file.exists) ?? logFiles[0];
|
|
38159
38730
|
let compactionEnabled = false;
|
|
38160
38731
|
try {
|
|
38161
38732
|
compactionEnabled = isCompactionEnabled(loadPluginConfig(process.cwd()));
|
|
@@ -38165,6 +38736,8 @@ async function collectDiagnostics() {
|
|
|
38165
38736
|
const opencodeInstallations = describeOpenCodeInstallations(detectOpenCodeInstallations());
|
|
38166
38737
|
const activeInstallation = opencodeInstallations[0];
|
|
38167
38738
|
const hostGeneration = openCodeHostGenerationFromVersion(activeInstallation?.version);
|
|
38739
|
+
const logFiles = openCodeIssueLogHarnesses(hostGeneration).flatMap((harness) => inspectMagicContextLogs(harness)).filter((file, index, all) => all.findIndex((other) => other.path === file.path) === index);
|
|
38740
|
+
const primaryLog = logFiles.find((file) => file.exists) ?? logFiles[0];
|
|
38168
38741
|
const conflictResult = detectConflicts(process.cwd(), { compactionEnabled, hostGeneration });
|
|
38169
38742
|
const openCodeDatabaseResolution = resolveOpenCodeDbPath(hostGeneration);
|
|
38170
38743
|
const recentSessions = await collectRecentSessions(openCodeDatabaseResolution, hostGeneration);
|
|
@@ -38185,15 +38758,15 @@ async function collectDiagnostics() {
|
|
|
38185
38758
|
opencodeConfigHasPlugin: configHasPluginEntry(opencodeConfig.value),
|
|
38186
38759
|
tuiConfigHasPlugin: configHasPluginEntry(tuiConfig.value),
|
|
38187
38760
|
magicContextConfig: {
|
|
38188
|
-
exists:
|
|
38761
|
+
exists: existsSync32(configPaths.magicContextConfig),
|
|
38189
38762
|
...magicContextConfig.error ? { parseError: magicContextConfig.error } : {},
|
|
38190
38763
|
flags: sanitizeValue(magicContextConfig.value ?? {}) ?? {}
|
|
38191
38764
|
},
|
|
38192
|
-
pluginCache:
|
|
38765
|
+
pluginCache: collectOpenCodePluginCacheReport(hostGeneration, opencodeConfig.value),
|
|
38193
38766
|
storageDir: {
|
|
38194
38767
|
path: storageDirPath,
|
|
38195
38768
|
source: storageResolution.source,
|
|
38196
|
-
exists:
|
|
38769
|
+
exists: existsSync32(storageDirPath),
|
|
38197
38770
|
contextDbSizeBytes: fileSize(contextDbPath)
|
|
38198
38771
|
},
|
|
38199
38772
|
openCodeDatabase: {
|
|
@@ -38240,7 +38813,12 @@ function renderDiagnosticsMarkdown(report) {
|
|
|
38240
38813
|
const pluginCache = {
|
|
38241
38814
|
path: sanitizeString(report.pluginCache.path),
|
|
38242
38815
|
cached: report.pluginCache.cached ?? null,
|
|
38243
|
-
latest: report.pluginCache.latest ?? null
|
|
38816
|
+
latest: report.pluginCache.latest ?? null,
|
|
38817
|
+
installs: (report.pluginCache.installs ?? []).map((install) => ({
|
|
38818
|
+
...install,
|
|
38819
|
+
path: sanitizeString(install.path),
|
|
38820
|
+
cached: install.cached ?? null
|
|
38821
|
+
}))
|
|
38244
38822
|
};
|
|
38245
38823
|
const storage = {
|
|
38246
38824
|
path: sanitizeString(report.storageDir.path),
|
|
@@ -38356,6 +38934,7 @@ var init_diagnostics_opencode = __esm(() => {
|
|
|
38356
38934
|
init_conflict_detector();
|
|
38357
38935
|
init_data_path();
|
|
38358
38936
|
init_opencode_db_path();
|
|
38937
|
+
init_opencode();
|
|
38359
38938
|
init_log_lines();
|
|
38360
38939
|
init_opencode_detect();
|
|
38361
38940
|
init_opencode_helpers();
|
|
@@ -38419,8 +38998,8 @@ var init_embedding_local = __esm(() => {
|
|
|
38419
38998
|
});
|
|
38420
38999
|
|
|
38421
39000
|
// src/lib/embedding-runtime.ts
|
|
38422
|
-
import { spawnSync as
|
|
38423
|
-
import { existsSync as
|
|
39001
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
39002
|
+
import { existsSync as existsSync33, readFileSync as readFileSync22 } from "node:fs";
|
|
38424
39003
|
import { createRequire as createRequire5 } from "node:module";
|
|
38425
39004
|
import { dirname as dirname16, join as join27, sep } from "node:path";
|
|
38426
39005
|
function describeError(error) {
|
|
@@ -38429,7 +39008,7 @@ function describeError(error) {
|
|
|
38429
39008
|
return typeof code === "string" && code.length > 0 ? `${code}: ${message}` : message;
|
|
38430
39009
|
}
|
|
38431
39010
|
function runOnnxRuntimeNodeLoadProbeChild(packageDir) {
|
|
38432
|
-
return
|
|
39011
|
+
return spawnSync7(process.execPath, ["-e", ONNX_RUNTIME_NODE_LOAD_PROBE_SCRIPT], {
|
|
38433
39012
|
encoding: "utf8",
|
|
38434
39013
|
env: { ...process.env, [ONNX_LOAD_PROBE_PACKAGE_DIR_ENV]: packageDir },
|
|
38435
39014
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -38567,7 +39146,7 @@ function expectedBinaryRelPath(platform, arch) {
|
|
|
38567
39146
|
}
|
|
38568
39147
|
function onnxRuntimeNodeVersion(packageDir) {
|
|
38569
39148
|
try {
|
|
38570
|
-
const parsed = JSON.parse(
|
|
39149
|
+
const parsed = JSON.parse(readFileSync22(join27(packageDir, "package.json"), "utf8"));
|
|
38571
39150
|
return typeof parsed.version === "string" ? parsed.version : undefined;
|
|
38572
39151
|
} catch {
|
|
38573
39152
|
return;
|
|
@@ -38616,7 +39195,7 @@ function formatLocalEmbeddingRuntimeWasmSelected(status) {
|
|
|
38616
39195
|
function requireNodeWasmBundle(probe, candidates) {
|
|
38617
39196
|
if (probe.state === "failed")
|
|
38618
39197
|
return probe;
|
|
38619
|
-
const bundlePath = candidates.find((candidate) =>
|
|
39198
|
+
const bundlePath = candidates.find((candidate) => existsSync33(candidate));
|
|
38620
39199
|
return bundlePath ? probe : {
|
|
38621
39200
|
state: "failed",
|
|
38622
39201
|
reason: `functional Node WASM Transformers bundle is missing (checked ${candidates.join(", ")})`
|
|
@@ -38641,7 +39220,7 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
|
|
|
38641
39220
|
}
|
|
38642
39221
|
const packageDir = join27(installRoot, "node_modules", "onnxruntime-node");
|
|
38643
39222
|
let native;
|
|
38644
|
-
if (!
|
|
39223
|
+
if (!existsSync33(join27(packageDir, "package.json"))) {
|
|
38645
39224
|
native = { state: "package-missing", packageDir };
|
|
38646
39225
|
} else {
|
|
38647
39226
|
const rel = expectedBinaryRelPath(platform, arch);
|
|
@@ -38652,7 +39231,7 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
|
|
|
38652
39231
|
};
|
|
38653
39232
|
} else {
|
|
38654
39233
|
const binaryPath = join27(packageDir, rel);
|
|
38655
|
-
native =
|
|
39234
|
+
native = existsSync33(binaryPath) ? probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath } : {
|
|
38656
39235
|
state: "binary-missing",
|
|
38657
39236
|
packageDir,
|
|
38658
39237
|
expectedBinary: binaryPath,
|
|
@@ -38663,7 +39242,7 @@ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform,
|
|
|
38663
39242
|
return withWasmFallback(native, () => probeWasmRuntimeAt(installRoot));
|
|
38664
39243
|
}
|
|
38665
39244
|
function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
|
|
38666
|
-
const existing = installRoots.filter((root) =>
|
|
39245
|
+
const existing = installRoots.filter((root) => existsSync33(root));
|
|
38667
39246
|
if (existing.length === 0) {
|
|
38668
39247
|
return {
|
|
38669
39248
|
state: "unknown",
|
|
@@ -38710,7 +39289,7 @@ function probeWasmRuntimeByResolution(pluginDir) {
|
|
|
38710
39289
|
}
|
|
38711
39290
|
}
|
|
38712
39291
|
function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.platform, arch = process.arch, runtimePreference = "auto", host) {
|
|
38713
|
-
if (!
|
|
39292
|
+
if (!existsSync33(join27(pluginDir, "package.json"))) {
|
|
38714
39293
|
return { state: "unknown", reason: "plugin package dir not found" };
|
|
38715
39294
|
}
|
|
38716
39295
|
const selectedRuntime = resolveLocalEmbeddingRuntime(runtimePreference, host);
|
|
@@ -38752,7 +39331,7 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
|
|
|
38752
39331
|
native = probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath: onnxDir };
|
|
38753
39332
|
} else {
|
|
38754
39333
|
const binaryPath = join27(onnxDir, rel);
|
|
38755
|
-
native =
|
|
39334
|
+
native = existsSync33(binaryPath) ? probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath } : {
|
|
38756
39335
|
state: "binary-missing",
|
|
38757
39336
|
packageDir: onnxDir,
|
|
38758
39337
|
expectedBinary: binaryPath,
|
|
@@ -39291,6 +39870,7 @@ var init_constants2 = __esm(() => {
|
|
|
39291
39870
|
USER_OPENCODE_CONFIG = join29(getOpenCodeConfigRoot(), "opencode.json");
|
|
39292
39871
|
USER_OPENCODE_CONFIG_JSONC = join29(getOpenCodeConfigRoot(), "opencode.jsonc");
|
|
39293
39872
|
});
|
|
39873
|
+
|
|
39294
39874
|
// ../plugin/src/hooks/auto-update-checker/types.ts
|
|
39295
39875
|
var NpmPackageEnvelopeSchema, OpencodePluginTupleSchema, OpencodeConfigSchema, PackageJsonSchema;
|
|
39296
39876
|
var init_types = __esm(() => {
|
|
@@ -39312,14 +39892,14 @@ var init_types = __esm(() => {
|
|
|
39312
39892
|
// ../plugin/src/hooks/auto-update-checker/checker.ts
|
|
39313
39893
|
import {
|
|
39314
39894
|
accessSync as accessSync2,
|
|
39315
|
-
existsSync as
|
|
39895
|
+
existsSync as existsSync34,
|
|
39316
39896
|
constants as fsConstants,
|
|
39317
|
-
readFileSync as
|
|
39897
|
+
readFileSync as readFileSync23,
|
|
39318
39898
|
renameSync as renameSync7,
|
|
39319
39899
|
statSync as statSync15,
|
|
39320
39900
|
writeFileSync as writeFileSync8
|
|
39321
39901
|
} from "node:fs";
|
|
39322
|
-
import { dirname as dirname17, isAbsolute as isAbsolute7, join as join30, resolve as
|
|
39902
|
+
import { dirname as dirname17, isAbsolute as isAbsolute7, join as join30, resolve as resolve9 } from "node:path";
|
|
39323
39903
|
function warn(message) {
|
|
39324
39904
|
log3(`WARN: ${message}`);
|
|
39325
39905
|
}
|
|
@@ -39366,9 +39946,9 @@ function getWinningConfig(directory, surface) {
|
|
|
39366
39946
|
let winner = null;
|
|
39367
39947
|
for (const path of getSurfaceConfigPaths(directory, surface)) {
|
|
39368
39948
|
try {
|
|
39369
|
-
if (!
|
|
39949
|
+
if (!existsSync34(path))
|
|
39370
39950
|
continue;
|
|
39371
|
-
const parsed = parseJsonConfig(
|
|
39951
|
+
const parsed = parseJsonConfig(readFileSync23(path, "utf-8"));
|
|
39372
39952
|
const entries = getPluginEntries(parsed);
|
|
39373
39953
|
if (entries.some((entry) => entry === PACKAGE_NAME || entry.startsWith(`${PACKAGE_NAME}@`))) {
|
|
39374
39954
|
if (winner) {
|
|
@@ -39404,14 +39984,14 @@ var init_checker = __esm(() => {
|
|
|
39404
39984
|
});
|
|
39405
39985
|
|
|
39406
39986
|
// src/lib/opencode-plugin-schema-fence.ts
|
|
39407
|
-
import { existsSync as
|
|
39987
|
+
import { existsSync as existsSync35, readdirSync as readdirSync6, readFileSync as readFileSync24 } from "node:fs";
|
|
39408
39988
|
import { join as join31 } from "node:path";
|
|
39409
39989
|
import { gunzipSync } from "node:zlib";
|
|
39410
39990
|
function readPackageVersion(packageJsonPath) {
|
|
39411
39991
|
try {
|
|
39412
|
-
if (!
|
|
39992
|
+
if (!existsSync35(packageJsonPath))
|
|
39413
39993
|
return null;
|
|
39414
|
-
const packageJson = JSON.parse(
|
|
39994
|
+
const packageJson = JSON.parse(readFileSync24(packageJsonPath, "utf-8"));
|
|
39415
39995
|
if (packageJson.name !== OPENCODE_PLUGIN_NAME || typeof packageJson.version !== "string") {
|
|
39416
39996
|
return null;
|
|
39417
39997
|
}
|
|
@@ -39431,7 +40011,7 @@ function readFenceValue(text) {
|
|
|
39431
40011
|
}
|
|
39432
40012
|
function readFenceFromDist(packageDirectory) {
|
|
39433
40013
|
const distDirectory = join31(packageDirectory, "dist");
|
|
39434
|
-
if (!
|
|
40014
|
+
if (!existsSync35(distDirectory))
|
|
39435
40015
|
return null;
|
|
39436
40016
|
const pending = [distDirectory];
|
|
39437
40017
|
const fenceValues = new Set;
|
|
@@ -39440,7 +40020,7 @@ function readFenceFromDist(packageDirectory) {
|
|
|
39440
40020
|
if (!directory)
|
|
39441
40021
|
continue;
|
|
39442
40022
|
try {
|
|
39443
|
-
for (const entry of
|
|
40023
|
+
for (const entry of readdirSync6(directory, { withFileTypes: true })) {
|
|
39444
40024
|
const path = join31(directory, entry.name);
|
|
39445
40025
|
if (entry.isDirectory()) {
|
|
39446
40026
|
pending.push(path);
|
|
@@ -39448,7 +40028,7 @@ function readFenceFromDist(packageDirectory) {
|
|
|
39448
40028
|
}
|
|
39449
40029
|
if (!entry.isFile() || !/\.(?:[cm]?js|ts)$/.test(entry.name))
|
|
39450
40030
|
continue;
|
|
39451
|
-
const fence = readFenceValue(
|
|
40031
|
+
const fence = readFenceValue(readFileSync24(path, "utf-8"));
|
|
39452
40032
|
if (fence !== null)
|
|
39453
40033
|
fenceValues.add(fence);
|
|
39454
40034
|
}
|
|
@@ -39462,7 +40042,7 @@ function findInstalledPluginPackage(cacheDirectory, specifier, requestedVersion)
|
|
|
39462
40042
|
const directCacheRoot = join31(cacheDirectory, specifier);
|
|
39463
40043
|
const candidates = [directCacheRoot];
|
|
39464
40044
|
try {
|
|
39465
|
-
for (const entry of
|
|
40045
|
+
for (const entry of readdirSync6(cacheDirectory, { withFileTypes: true })) {
|
|
39466
40046
|
if (!entry.isDirectory())
|
|
39467
40047
|
continue;
|
|
39468
40048
|
const candidate = join31(cacheDirectory, entry.name);
|
|
@@ -39665,6 +40245,179 @@ var init_storage_versions = __esm(async () => {
|
|
|
39665
40245
|
await init_storage_db();
|
|
39666
40246
|
});
|
|
39667
40247
|
|
|
40248
|
+
// src/commands/doctor-opencode-cache.ts
|
|
40249
|
+
import { existsSync as existsSync36, readFileSync as readFileSync25, rmSync as rmSync4 } from "node:fs";
|
|
40250
|
+
function readCachedPluginVersion(pluginCacheDir) {
|
|
40251
|
+
try {
|
|
40252
|
+
const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
|
|
40253
|
+
if (!existsSync36(installedPkgPath))
|
|
40254
|
+
return;
|
|
40255
|
+
const pkg = JSON.parse(readFileSync25(installedPkgPath, "utf-8"));
|
|
40256
|
+
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
40257
|
+
} catch {
|
|
40258
|
+
return;
|
|
40259
|
+
}
|
|
40260
|
+
}
|
|
40261
|
+
async function clearPluginCache(options = {}, deps = {}) {
|
|
40262
|
+
const remove = deps.remove ?? ((path) => rmSync4(path, { recursive: true, force: true }));
|
|
40263
|
+
const pluginCacheRoots = getOpenCodePluginCacheRoots();
|
|
40264
|
+
const existingRoots = pluginCacheRoots.filter((root) => existsSync36(root));
|
|
40265
|
+
if (existingRoots.length === 0) {
|
|
40266
|
+
return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
|
|
40267
|
+
}
|
|
40268
|
+
const latestVersion = options.latestVersion ?? undefined;
|
|
40269
|
+
const cacheEntries = existingRoots.map((path) => ({
|
|
40270
|
+
path,
|
|
40271
|
+
cached: readCachedPluginVersion(path)
|
|
40272
|
+
}));
|
|
40273
|
+
if (options.force !== true && latestVersion === undefined) {
|
|
40274
|
+
const firstEntry = cacheEntries[0];
|
|
40275
|
+
return {
|
|
40276
|
+
action: "check_unavailable",
|
|
40277
|
+
path: firstEntry?.path ?? pluginCacheRoots[0] ?? "",
|
|
40278
|
+
paths: cacheEntries.map((entry) => entry.path),
|
|
40279
|
+
cached: firstEntry?.cached
|
|
40280
|
+
};
|
|
40281
|
+
}
|
|
40282
|
+
const clearTargets = cacheEntries.filter((entry) => options.force === true || entry.cached === undefined || entry.cached !== latestVersion);
|
|
40283
|
+
if (clearTargets.length === 0) {
|
|
40284
|
+
const firstEntry = cacheEntries[0];
|
|
40285
|
+
return {
|
|
40286
|
+
action: "up_to_date",
|
|
40287
|
+
path: firstEntry?.path ?? pluginCacheRoots[0] ?? "",
|
|
40288
|
+
paths: cacheEntries.map((entry) => entry.path),
|
|
40289
|
+
cached: firstEntry?.cached,
|
|
40290
|
+
latest: latestVersion
|
|
40291
|
+
};
|
|
40292
|
+
}
|
|
40293
|
+
const cleared = [];
|
|
40294
|
+
const failed = [];
|
|
40295
|
+
for (const entry of clearTargets) {
|
|
40296
|
+
try {
|
|
40297
|
+
remove(entry.path);
|
|
40298
|
+
cleared.push(entry);
|
|
40299
|
+
} catch (err) {
|
|
40300
|
+
failed.push({
|
|
40301
|
+
path: entry.path,
|
|
40302
|
+
error: err instanceof Error ? err.message : String(err)
|
|
40303
|
+
});
|
|
40304
|
+
}
|
|
40305
|
+
}
|
|
40306
|
+
if (failed.length > 0) {
|
|
40307
|
+
const firstFailure = failed[0];
|
|
40308
|
+
return {
|
|
40309
|
+
action: "error",
|
|
40310
|
+
path: firstFailure?.path ?? clearTargets[0]?.path ?? existingRoots[0] ?? "",
|
|
40311
|
+
paths: failed.map((entry) => entry.path),
|
|
40312
|
+
clearedPaths: cleared.map((entry) => entry.path),
|
|
40313
|
+
failedPaths: failed.map((entry) => entry.path),
|
|
40314
|
+
error: firstFailure?.error
|
|
40315
|
+
};
|
|
40316
|
+
}
|
|
40317
|
+
const firstTarget = cleared[0];
|
|
40318
|
+
return {
|
|
40319
|
+
action: "cleared",
|
|
40320
|
+
path: firstTarget?.path ?? pluginCacheRoots[0] ?? "",
|
|
40321
|
+
paths: cleared.map((entry) => entry.path),
|
|
40322
|
+
cached: firstTarget?.cached,
|
|
40323
|
+
latest: latestVersion
|
|
40324
|
+
};
|
|
40325
|
+
}
|
|
40326
|
+
var init_doctor_opencode_cache = __esm(() => {
|
|
40327
|
+
init_opencode_plugin_cache();
|
|
40328
|
+
});
|
|
40329
|
+
|
|
40330
|
+
// src/commands/doctor-cached-plugin-fence.ts
|
|
40331
|
+
import { existsSync as existsSync37 } from "node:fs";
|
|
40332
|
+
import { dirname as dirname18 } from "node:path";
|
|
40333
|
+
function listCachedOpenCodePluginFences(sources = {}) {
|
|
40334
|
+
const fences = [];
|
|
40335
|
+
for (const root of sources.openCodeV1Roots ?? getOpenCodePluginCacheRoots()) {
|
|
40336
|
+
const packageJson = getOpenCodePluginPackageJsonPath(root);
|
|
40337
|
+
if (!existsSync37(packageJson))
|
|
40338
|
+
continue;
|
|
40339
|
+
fences.push({
|
|
40340
|
+
host: "opencode1",
|
|
40341
|
+
directory: root,
|
|
40342
|
+
version: readCachedPluginVersion(root),
|
|
40343
|
+
supportedVersion: readFenceFromDist(dirname18(packageJson))
|
|
40344
|
+
});
|
|
40345
|
+
}
|
|
40346
|
+
for (const slot of listOpenCodeV2PluginCacheSlots(sources.openCodeV2NpmCacheDir)) {
|
|
40347
|
+
if (!isOpenCodePluginDistTag(slot.spec))
|
|
40348
|
+
continue;
|
|
40349
|
+
const generation = getOpenCodeV2ActiveGeneration(slot.slot);
|
|
40350
|
+
if (!generation)
|
|
40351
|
+
continue;
|
|
40352
|
+
fences.push({
|
|
40353
|
+
host: "opencode2",
|
|
40354
|
+
directory: slot.slot,
|
|
40355
|
+
spec: slot.spec,
|
|
40356
|
+
version: slot.version,
|
|
40357
|
+
supportedVersion: readFenceFromDist(dirname18(getOpenCodePluginPackageJsonPath(generation)))
|
|
40358
|
+
});
|
|
40359
|
+
}
|
|
40360
|
+
return fences;
|
|
40361
|
+
}
|
|
40362
|
+
function readContextDbSchemaVersion(path) {
|
|
40363
|
+
let db = null;
|
|
40364
|
+
try {
|
|
40365
|
+
db = openExistingDatabase(path, { readonly: true });
|
|
40366
|
+
return db === null ? null : getPersistedSchemaVersion(db);
|
|
40367
|
+
} catch {
|
|
40368
|
+
return null;
|
|
40369
|
+
} finally {
|
|
40370
|
+
db?.close();
|
|
40371
|
+
}
|
|
40372
|
+
}
|
|
40373
|
+
function compareCachedPluginFences(fences, databaseVersion) {
|
|
40374
|
+
return fences.map((fence) => ({
|
|
40375
|
+
...fence,
|
|
40376
|
+
databaseVersion,
|
|
40377
|
+
status: fence.supportedVersion === null ? "unknown" : fence.supportedVersion < databaseVersion ? "behind" : "supported"
|
|
40378
|
+
}));
|
|
40379
|
+
}
|
|
40380
|
+
function hostLabel(fence) {
|
|
40381
|
+
if (fence.host === "opencode1")
|
|
40382
|
+
return "OpenCode 1";
|
|
40383
|
+
return fence.spec && fence.spec !== "latest" ? `OpenCode 2 (@${fence.spec})` : "OpenCode 2";
|
|
40384
|
+
}
|
|
40385
|
+
function reportCachedPluginFences(findings, report) {
|
|
40386
|
+
const supported = [];
|
|
40387
|
+
let behind = 0;
|
|
40388
|
+
for (const finding of findings) {
|
|
40389
|
+
const label = hostLabel(finding);
|
|
40390
|
+
const version = finding.version ?? "unknown version";
|
|
40391
|
+
if (finding.status === "supported") {
|
|
40392
|
+
supported.push(`${label} ${version} (fence v${finding.supportedVersion})`);
|
|
40393
|
+
continue;
|
|
40394
|
+
}
|
|
40395
|
+
if (finding.status === "unknown") {
|
|
40396
|
+
report.info(`${label} plugin cache: could not read the schema fence of Magic Context ${version}, so doctor cannot tell whether it supports context.db v${finding.databaseVersion}`);
|
|
40397
|
+
report.info(` ${finding.directory}`);
|
|
40398
|
+
continue;
|
|
40399
|
+
}
|
|
40400
|
+
behind++;
|
|
40401
|
+
report.fail(`${label} has Magic Context ${version} cached, which supports context.db only through schema v${finding.supportedVersion}, but the shared context.db is at v${finding.databaseVersion}. A newer Magic Context (usually the other OpenCode host) migrated it, so ${label} fails closed on every prompt; an @latest entry does not refresh this cached copy.`);
|
|
40402
|
+
report.info(` ${finding.directory}`);
|
|
40403
|
+
report.info(finding.host === "opencode1" ? " To fix: quit OpenCode 1 and delete that directory; OpenCode 1 installs the current release on its next start." : ` To fix, ${OPENCODE_V2_PLUGIN_UPDATE_HINT}, then restart OpenCode 2.`);
|
|
40404
|
+
}
|
|
40405
|
+
if (supported.length > 0) {
|
|
40406
|
+
report.pass(`Cached Magic Context copies support context.db v${findings[0]?.databaseVersion}: ${supported.join(", ")}`);
|
|
40407
|
+
}
|
|
40408
|
+
return { behind };
|
|
40409
|
+
}
|
|
40410
|
+
var init_doctor_cached_plugin_fence = __esm(async () => {
|
|
40411
|
+
init_opencode_plugin_cache();
|
|
40412
|
+
init_opencode_plugin_schema_fence();
|
|
40413
|
+
init_doctor_opencode_cache();
|
|
40414
|
+
init_doctor_opencode2_cache();
|
|
40415
|
+
await __promiseAll([
|
|
40416
|
+
init_storage_db(),
|
|
40417
|
+
init_database_access()
|
|
40418
|
+
]);
|
|
40419
|
+
});
|
|
40420
|
+
|
|
39668
40421
|
// src/commands/doctor-compaction-markers.ts
|
|
39669
40422
|
function safeData(column = "data") {
|
|
39670
40423
|
return `CASE WHEN json_valid(${column}) THEN ${column} ELSE '{}' END`;
|
|
@@ -39720,6 +40473,21 @@ function countUnmatchedConvertedMarkers(db, migratedV2Schema) {
|
|
|
39720
40473
|
)`).get();
|
|
39721
40474
|
return Number(row?.count ?? 0);
|
|
39722
40475
|
}
|
|
40476
|
+
function countPostConversionMessages(db, migratedV2Schema) {
|
|
40477
|
+
if (!migratedV2Schema || !tableExists4(db, "message") || !tableExists4(db, "session")) {
|
|
40478
|
+
return { messages: 0, sessions: 0 };
|
|
40479
|
+
}
|
|
40480
|
+
const row = db.prepare(`SELECT COUNT(*) AS messages, COUNT(DISTINCT converted.session_id) AS sessions
|
|
40481
|
+
FROM session_message converted
|
|
40482
|
+
WHERE EXISTS (SELECT 1 FROM session legacy WHERE legacy.id = converted.session_id)
|
|
40483
|
+
AND NOT EXISTS (
|
|
40484
|
+
SELECT 1
|
|
40485
|
+
FROM message source
|
|
40486
|
+
WHERE source.session_id = converted.session_id
|
|
40487
|
+
AND source.time_created = converted.time_created
|
|
40488
|
+
)`).get();
|
|
40489
|
+
return { messages: Number(row?.messages ?? 0), sessions: Number(row?.sessions ?? 0) };
|
|
40490
|
+
}
|
|
39723
40491
|
function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
|
|
39724
40492
|
const missingBefore = countMissingCompleted(db);
|
|
39725
40493
|
let repaired = 0;
|
|
@@ -39740,6 +40508,7 @@ function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
|
|
|
39740
40508
|
const migratedV2Schema = tableExists4(db, "session_v2") && tableExists4(db, "session_message");
|
|
39741
40509
|
const migrationCompleted = migrationV1ToV2Completed(db);
|
|
39742
40510
|
const unmatchedConvertedMarkers = countUnmatchedConvertedMarkers(db, migratedV2Schema);
|
|
40511
|
+
const postConversion = countPostConversionMessages(db, migratedV2Schema);
|
|
39743
40512
|
return {
|
|
39744
40513
|
missingBefore,
|
|
39745
40514
|
missingAfter,
|
|
@@ -39747,21 +40516,23 @@ function checkOpenCodeCompactionMarkerConversion(db, options = {}) {
|
|
|
39747
40516
|
migrationCompleted,
|
|
39748
40517
|
migratedV2Schema,
|
|
39749
40518
|
unmatchedConvertedMarkers,
|
|
39750
|
-
|
|
40519
|
+
postConversionMessages: postConversion.messages,
|
|
40520
|
+
postConversionSessions: postConversion.sessions
|
|
39751
40521
|
};
|
|
39752
40522
|
}
|
|
39753
40523
|
function formatOpenCodeCompactionMarkerConversion(report) {
|
|
39754
40524
|
return `OpenCode compaction markers are convertible to OpenCode 2: before=${report.missingBefore} missing time.completed; after=${report.missingAfter}`;
|
|
39755
40525
|
}
|
|
39756
|
-
function
|
|
39757
|
-
|
|
39758
|
-
|
|
39759
|
-
|
|
39760
|
-
|
|
39761
|
-
|
|
39762
|
-
"
|
|
39763
|
-
'Wait until `SELECT value FROM kv WHERE key = \'migration.v1-v2\';` reads `{"phase":"completed"}` before stopping that manual server'
|
|
40526
|
+
function formatOpenCodeV2MissingMarkerNotice(report) {
|
|
40527
|
+
if (!report.migrationCompleted || !report.migratedV2Schema || report.unmatchedConvertedMarkers === 0) {
|
|
40528
|
+
return null;
|
|
40529
|
+
}
|
|
40530
|
+
const lines = [
|
|
40531
|
+
`OpenCode 2's conversion did not carry over ${report.unmatchedConvertedMarkers} Magic Context compaction marker(s). No action is needed.`,
|
|
40532
|
+
"Magic Context on OpenCode 2 does not use host compaction rows: it keeps its own boundary and re-derives compartment positions from the messages that survived. OpenCode reads these sessions' full history on each turn, as it does for any Magic Context session started on OpenCode 2."
|
|
39764
40533
|
];
|
|
40534
|
+
lines.push(report.postConversionMessages > 0 ? `Do not clear kv.migration.v1-v2 to reconvert: OpenCode 2 would rebuild every converted session from its OpenCode 1 rows and delete the ${report.postConversionMessages} message(s) it added after the conversion, in ${report.postConversionSessions} session(s).` : "Do not clear kv.migration.v1-v2 to reconvert: OpenCode 2 would rebuild every converted session from its OpenCode 1 rows, deleting anything added on OpenCode 2 since.", "If you already reconverted, restore opencode.db (with its -wal and -shm files) from a backup taken before the reconversion.");
|
|
40535
|
+
return lines;
|
|
39765
40536
|
}
|
|
39766
40537
|
|
|
39767
40538
|
// src/commands/doctor-compartment-boundaries.ts
|
|
@@ -39845,86 +40616,175 @@ var init_doctor_harness_relabel = __esm(async () => {
|
|
|
39845
40616
|
await init_opencode2_relabel();
|
|
39846
40617
|
});
|
|
39847
40618
|
|
|
39848
|
-
// src/commands/doctor-opencode-
|
|
39849
|
-
import {
|
|
39850
|
-
function
|
|
39851
|
-
|
|
39852
|
-
|
|
39853
|
-
|
|
39854
|
-
|
|
39855
|
-
const pkg = JSON.parse(readFileSync24(installedPkgPath, "utf-8"));
|
|
39856
|
-
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
39857
|
-
} catch {
|
|
39858
|
-
return;
|
|
40619
|
+
// src/commands/doctor-opencode-plugin-duplicates.ts
|
|
40620
|
+
import { isDeepStrictEqual } from "node:util";
|
|
40621
|
+
function entryOptions(entry) {
|
|
40622
|
+
if (Array.isArray(entry))
|
|
40623
|
+
return entry[1];
|
|
40624
|
+
if (entry !== null && typeof entry === "object") {
|
|
40625
|
+
return entry.options;
|
|
39859
40626
|
}
|
|
40627
|
+
return;
|
|
39860
40628
|
}
|
|
39861
|
-
|
|
39862
|
-
|
|
39863
|
-
|
|
39864
|
-
|
|
39865
|
-
|
|
39866
|
-
return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
|
|
40629
|
+
function hasOptions(options) {
|
|
40630
|
+
if (options === undefined || options === null)
|
|
40631
|
+
return false;
|
|
40632
|
+
if (typeof options === "object" && !Array.isArray(options)) {
|
|
40633
|
+
return Object.keys(options).length > 0;
|
|
39867
40634
|
}
|
|
39868
|
-
|
|
39869
|
-
|
|
39870
|
-
|
|
39871
|
-
|
|
39872
|
-
|
|
39873
|
-
|
|
39874
|
-
|
|
39875
|
-
|
|
39876
|
-
|
|
39877
|
-
|
|
39878
|
-
|
|
39879
|
-
|
|
39880
|
-
|
|
40635
|
+
return true;
|
|
40636
|
+
}
|
|
40637
|
+
function followsLatest(specifier) {
|
|
40638
|
+
return specifier === OPENCODE_PLUGIN_NAME || specifier === OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
|
|
40639
|
+
}
|
|
40640
|
+
function listMagicContextPluginEntries(config) {
|
|
40641
|
+
const out = [];
|
|
40642
|
+
for (const { key, index, entry } of readPluginEntries(config)) {
|
|
40643
|
+
const specifier = pluginEntryPackage(entry);
|
|
40644
|
+
if (specifier === null)
|
|
40645
|
+
continue;
|
|
40646
|
+
let kind = null;
|
|
40647
|
+
if (matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME))
|
|
40648
|
+
kind = "npm";
|
|
40649
|
+
else if (isDevPathPluginEntry(entry))
|
|
40650
|
+
kind = "dev-path";
|
|
40651
|
+
if (kind === null)
|
|
40652
|
+
continue;
|
|
40653
|
+
out.push({ key, index, entry, specifier, kind, options: entryOptions(entry) });
|
|
39881
40654
|
}
|
|
39882
|
-
|
|
39883
|
-
|
|
39884
|
-
|
|
39885
|
-
|
|
39886
|
-
|
|
39887
|
-
|
|
39888
|
-
|
|
39889
|
-
|
|
39890
|
-
latest: latestVersion
|
|
39891
|
-
};
|
|
40655
|
+
return out;
|
|
40656
|
+
}
|
|
40657
|
+
function planPluginDuplicates(config) {
|
|
40658
|
+
const entries = listMagicContextPluginEntries(config);
|
|
40659
|
+
if (entries.length <= 1)
|
|
40660
|
+
return { action: "none", entries };
|
|
40661
|
+
if (entries.some((entry) => entry.kind === "dev-path")) {
|
|
40662
|
+
return { action: "leave", reason: "dev-path", entries };
|
|
39892
40663
|
}
|
|
39893
|
-
const
|
|
39894
|
-
const
|
|
39895
|
-
|
|
39896
|
-
|
|
39897
|
-
|
|
39898
|
-
|
|
39899
|
-
} catch (err) {
|
|
39900
|
-
failed.push({
|
|
39901
|
-
path: entry.path,
|
|
39902
|
-
error: err instanceof Error ? err.message : String(err)
|
|
39903
|
-
});
|
|
40664
|
+
const optionSets = [];
|
|
40665
|
+
for (const entry of entries) {
|
|
40666
|
+
if (!hasOptions(entry.options))
|
|
40667
|
+
continue;
|
|
40668
|
+
if (!optionSets.some((seen) => isDeepStrictEqual(seen, entry.options))) {
|
|
40669
|
+
optionSets.push(entry.options);
|
|
39904
40670
|
}
|
|
39905
40671
|
}
|
|
39906
|
-
if (
|
|
39907
|
-
|
|
39908
|
-
return {
|
|
39909
|
-
action: "error",
|
|
39910
|
-
path: firstFailure?.path ?? clearTargets[0]?.path ?? existingRoots[0] ?? "",
|
|
39911
|
-
paths: failed.map((entry) => entry.path),
|
|
39912
|
-
clearedPaths: cleared.map((entry) => entry.path),
|
|
39913
|
-
failedPaths: failed.map((entry) => entry.path),
|
|
39914
|
-
error: firstFailure?.error
|
|
39915
|
-
};
|
|
40672
|
+
if (optionSets.length > 1) {
|
|
40673
|
+
return { action: "leave", reason: "conflicting-options", entries };
|
|
39916
40674
|
}
|
|
39917
|
-
const
|
|
39918
|
-
|
|
39919
|
-
|
|
39920
|
-
|
|
39921
|
-
|
|
39922
|
-
|
|
39923
|
-
|
|
39924
|
-
|
|
40675
|
+
const rank = (entry) => (followsLatest(entry.specifier) ? 2 : 0) + (hasOptions(entry.options) ? 1 : 0);
|
|
40676
|
+
let keep = entries[0];
|
|
40677
|
+
for (const entry of entries) {
|
|
40678
|
+
if (rank(entry) > rank(keep))
|
|
40679
|
+
keep = entry;
|
|
40680
|
+
}
|
|
40681
|
+
const remove = entries.filter((entry) => entry !== keep);
|
|
40682
|
+
let replacement;
|
|
40683
|
+
const carried = optionSets[0];
|
|
40684
|
+
if (!hasOptions(keep.options) && carried !== undefined) {
|
|
40685
|
+
const donor = entries.find((entry) => isDeepStrictEqual(entry.options, carried));
|
|
40686
|
+
if (Array.isArray(donor?.entry)) {
|
|
40687
|
+
const tuple = [...donor.entry];
|
|
40688
|
+
tuple[0] = keep.specifier;
|
|
40689
|
+
replacement = tuple;
|
|
40690
|
+
} else {
|
|
40691
|
+
replacement = { ...donor?.entry, package: keep.specifier };
|
|
40692
|
+
}
|
|
40693
|
+
}
|
|
40694
|
+
return { action: "dedupe", entries, keep, remove, replacement };
|
|
39925
40695
|
}
|
|
39926
|
-
|
|
40696
|
+
function applyPluginDuplicatePlan(config, plan) {
|
|
40697
|
+
if (plan.replacement !== undefined) {
|
|
40698
|
+
const list = config[plan.keep.key];
|
|
40699
|
+
list[plan.keep.index] = plan.replacement;
|
|
40700
|
+
}
|
|
40701
|
+
const removals = [...plan.remove].sort((a, b) => a.key === b.key ? b.index - a.index : a.key.localeCompare(b.key));
|
|
40702
|
+
for (const entry of removals) {
|
|
40703
|
+
config[entry.key].splice(entry.index, 1);
|
|
40704
|
+
}
|
|
40705
|
+
}
|
|
40706
|
+
function describePluginEntry(entry) {
|
|
40707
|
+
const suffix = hasOptions(entry.options) ? " (with options)" : "";
|
|
40708
|
+
const kind = entry.kind === "dev-path" ? "dev path " : "";
|
|
40709
|
+
return `${entry.key}[${entry.index}]: ${kind}${entry.specifier}${suffix}`;
|
|
40710
|
+
}
|
|
40711
|
+
function checkPluginDuplicates(config, configName, options, report) {
|
|
40712
|
+
const plan = planPluginDuplicates(config);
|
|
40713
|
+
if (plan.action === "none")
|
|
40714
|
+
return false;
|
|
40715
|
+
report.warn(`Magic Context is registered ${plan.entries.length} times in ${configName}; OpenCode loads the first and fails the rest as duplicates`);
|
|
40716
|
+
for (const entry of plan.entries)
|
|
40717
|
+
report.info(` ${describePluginEntry(entry)}`);
|
|
40718
|
+
if (plan.action === "leave") {
|
|
40719
|
+
report.warn(plan.reason === "dev-path" ? "A local development checkout is registered next to another Magic Context entry; leaving every entry in place — remove the one you do not want by hand" : "Two Magic Context entries carry different options; leaving every entry in place — merge the options into one entry by hand");
|
|
40720
|
+
return false;
|
|
40721
|
+
}
|
|
40722
|
+
if (!options.fix) {
|
|
40723
|
+
report.info(` Run 'doctor --fix' to keep ${plan.keep.key}[${plan.keep.index}] (${plan.keep.specifier}) and remove the others`);
|
|
40724
|
+
return false;
|
|
40725
|
+
}
|
|
40726
|
+
applyPluginDuplicatePlan(config, plan);
|
|
40727
|
+
report.pass(`Removed ${plan.remove.length} duplicate Magic Context ${plan.remove.length === 1 ? "entry" : "entries"} from ${configName}; kept ${plan.keep.specifier} under "${plan.keep.key}"${plan.replacement !== undefined ? " with the removed entry's options" : ""}`);
|
|
40728
|
+
return true;
|
|
40729
|
+
}
|
|
40730
|
+
var init_doctor_opencode_plugin_duplicates = __esm(() => {
|
|
40731
|
+
init_opencode();
|
|
40732
|
+
init_opencode_plugin_cache();
|
|
40733
|
+
init_opencode_plugin_registration();
|
|
40734
|
+
});
|
|
40735
|
+
|
|
40736
|
+
// src/commands/doctor-opencode-plugin-entry.ts
|
|
40737
|
+
function isPinnedOpenCodePluginSpecifier(specifier) {
|
|
40738
|
+
if (specifier === OPENCODE_PLUGIN_NAME || specifier === OPENCODE_PLUGIN_ENTRY_WITH_VERSION) {
|
|
40739
|
+
return false;
|
|
40740
|
+
}
|
|
40741
|
+
return specifier.startsWith(`${OPENCODE_PLUGIN_NAME}@`);
|
|
40742
|
+
}
|
|
40743
|
+
function withPluginEntrySpecifier(entry, specifier) {
|
|
40744
|
+
if (Array.isArray(entry) && entry.length >= 1) {
|
|
40745
|
+
const replacement = [...entry];
|
|
40746
|
+
replacement[0] = specifier;
|
|
40747
|
+
return replacement;
|
|
40748
|
+
}
|
|
40749
|
+
if (entry !== null && typeof entry === "object" && !Array.isArray(entry)) {
|
|
40750
|
+
return { ...entry, package: specifier };
|
|
40751
|
+
}
|
|
40752
|
+
return specifier;
|
|
40753
|
+
}
|
|
40754
|
+
function checkOpenCodePluginEntry(config, configName, options, report) {
|
|
40755
|
+
const allEntries = readPluginEntries(config);
|
|
40756
|
+
const found = allEntries.find(({ entry }) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
|
|
40757
|
+
if (!found) {
|
|
40758
|
+
const key = options.registrationKey;
|
|
40759
|
+
const list = Array.isArray(config[key]) ? config[key] : [];
|
|
40760
|
+
list.push(OPENCODE_PLUGIN_ENTRY_WITH_VERSION);
|
|
40761
|
+
config[key] = list;
|
|
40762
|
+
report.fixed(`Added plugin to ${configName}`);
|
|
40763
|
+
return true;
|
|
40764
|
+
}
|
|
40765
|
+
const list = config[found.key];
|
|
40766
|
+
const specifier = pluginEntryPackage(found.entry) ?? "";
|
|
40767
|
+
if (specifier === OPENCODE_PLUGIN_ENTRY_WITH_VERSION) {
|
|
40768
|
+
report.pass(`Plugin registered in ${configName}`);
|
|
40769
|
+
return false;
|
|
40770
|
+
}
|
|
40771
|
+
if (isDevPathPluginEntry(found.entry)) {
|
|
40772
|
+
report.pass(`Plugin registered in ${configName} (dev path: ${specifier})`);
|
|
40773
|
+
return false;
|
|
40774
|
+
}
|
|
40775
|
+
if (isPinnedOpenCodePluginSpecifier(specifier) && !options.force) {
|
|
40776
|
+
report.autoUpdateStall(specifier);
|
|
40777
|
+
report.warn(`Plugin pinned to ${specifier} in ${configName} — use 'doctor --force' to upgrade`);
|
|
40778
|
+
return false;
|
|
40779
|
+
}
|
|
40780
|
+
list[found.index] = withPluginEntrySpecifier(found.entry, OPENCODE_PLUGIN_ENTRY_WITH_VERSION);
|
|
40781
|
+
report.fixed(`Upgraded plugin entry in ${configName}: ${specifier} → ${OPENCODE_PLUGIN_ENTRY_WITH_VERSION}`);
|
|
40782
|
+
return true;
|
|
40783
|
+
}
|
|
40784
|
+
var init_doctor_opencode_plugin_entry = __esm(() => {
|
|
40785
|
+
init_opencode();
|
|
39927
40786
|
init_opencode_plugin_cache();
|
|
40787
|
+
init_opencode_plugin_registration();
|
|
39928
40788
|
});
|
|
39929
40789
|
|
|
39930
40790
|
// src/commands/doctor-store-generation.ts
|
|
@@ -39982,11 +40842,22 @@ function formatUnresolvedCompartmentSession(session) {
|
|
|
39982
40842
|
}
|
|
39983
40843
|
|
|
39984
40844
|
// src/commands/doctor-opencode.ts
|
|
39985
|
-
import { spawnSync as
|
|
39986
|
-
import { existsSync as
|
|
40845
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
40846
|
+
import { existsSync as existsSync38, mkdtempSync, readFileSync as readFileSync26, rmSync as rmSync5 } from "node:fs";
|
|
39987
40847
|
import { createRequire as createRequire6 } from "node:module";
|
|
39988
40848
|
import { homedir as homedir16, tmpdir as tmpdir3 } from "node:os";
|
|
39989
40849
|
import { join as join32 } from "node:path";
|
|
40850
|
+
function formatSharedDbRowCounts(db) {
|
|
40851
|
+
return SHARED_DB_ROW_COUNT_TABLES.map((table) => {
|
|
40852
|
+
try {
|
|
40853
|
+
const row = db.prepare(`SELECT COUNT(*) AS c FROM ${table}`).get();
|
|
40854
|
+
return `${table}=${typeof row?.c === "number" ? row.c : "n/a"}`;
|
|
40855
|
+
} catch (error) {
|
|
40856
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
40857
|
+
return `${table}=n/a (${sanitizeDiagnosticText(reason)})`;
|
|
40858
|
+
}
|
|
40859
|
+
}).join(", ");
|
|
40860
|
+
}
|
|
39990
40861
|
function findUndeclaredConfiguredVariants(configured, catalog) {
|
|
39991
40862
|
return configured.filter((entry) => {
|
|
39992
40863
|
const [providerID, id] = entry.model.split("/", 2);
|
|
@@ -39994,13 +40865,26 @@ function findUndeclaredConfiguredVariants(configured, catalog) {
|
|
|
39994
40865
|
return model !== undefined && !Object.hasOwn(model.variants, entry.variant);
|
|
39995
40866
|
});
|
|
39996
40867
|
}
|
|
39997
|
-
function
|
|
40868
|
+
function findUnknownConfiguredModels(configured, catalog) {
|
|
40869
|
+
return configured.flatMap((entry) => {
|
|
40870
|
+
const [providerID, id] = entry.model.split("/", 2);
|
|
40871
|
+
if (!catalog.some((item) => item.providerID === providerID)) {
|
|
40872
|
+
return [{ ...entry, unknown: "provider" }];
|
|
40873
|
+
}
|
|
40874
|
+
if (!catalog.some((item) => item.providerID === providerID && item.id === id)) {
|
|
40875
|
+
return [{ ...entry, unknown: "model" }];
|
|
40876
|
+
}
|
|
40877
|
+
return [];
|
|
40878
|
+
});
|
|
40879
|
+
}
|
|
40880
|
+
function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args, cwd) => spawnSync8("opencode", args, {
|
|
39998
40881
|
cwd,
|
|
39999
40882
|
encoding: "utf8",
|
|
40000
40883
|
timeout: hostGeneration === "v2" ? 90000 : 45000,
|
|
40001
40884
|
maxBuffer: 16 * 1024 * 1024
|
|
40002
40885
|
}), projectDir = process.cwd()) {
|
|
40003
40886
|
const configured = [];
|
|
40887
|
+
const models = [];
|
|
40004
40888
|
const root = config && typeof config === "object" ? config : {};
|
|
40005
40889
|
for (const agent of ["historian", "dreamer"]) {
|
|
40006
40890
|
const section = root[agent];
|
|
@@ -40010,21 +40894,25 @@ function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args
|
|
|
40010
40894
|
if (!block || typeof block !== "object")
|
|
40011
40895
|
continue;
|
|
40012
40896
|
const record = block;
|
|
40013
|
-
const add = (entry, defaultVariant) => {
|
|
40897
|
+
const add = (entry, defaultVariant, fallback) => {
|
|
40014
40898
|
const value = entry && typeof entry === "object" ? entry : {};
|
|
40015
40899
|
const model = typeof entry === "string" ? entry : value.model;
|
|
40016
40900
|
const variant = value.variant ?? defaultVariant;
|
|
40017
|
-
if (typeof model
|
|
40018
|
-
|
|
40901
|
+
if (typeof model !== "string" || !model.includes("/"))
|
|
40902
|
+
return;
|
|
40903
|
+
if (!models.some((known) => known.agent === agent && known.model === model)) {
|
|
40904
|
+
models.push({ agent, model, fallback });
|
|
40019
40905
|
}
|
|
40906
|
+
if (typeof variant === "string")
|
|
40907
|
+
configured.push({ agent, model, variant });
|
|
40020
40908
|
};
|
|
40021
|
-
add(record.model, record.variant);
|
|
40909
|
+
add(record.model, record.variant, false);
|
|
40022
40910
|
if (Array.isArray(record.fallback_models)) {
|
|
40023
40911
|
for (const entry of record.fallback_models)
|
|
40024
|
-
add(entry, undefined);
|
|
40912
|
+
add(entry, undefined, true);
|
|
40025
40913
|
}
|
|
40026
40914
|
}
|
|
40027
|
-
if (
|
|
40915
|
+
if (models.length === 0)
|
|
40028
40916
|
return;
|
|
40029
40917
|
const tempRoot = mkdtempSync(join32(tmpdir3(), "magic-context-opencode-catalog-"));
|
|
40030
40918
|
try {
|
|
@@ -40033,14 +40921,19 @@ function checkConfiguredVariantCatalog(config, hostGeneration, warn, run = (args
|
|
|
40033
40921
|
const result = run(command, tempRoot);
|
|
40034
40922
|
const catalog = hostGeneration === "v2" ? parseOpenCodeV2ModelCatalog(result.stdout ?? "") : parseOpenCodeModelCatalog(result.stdout ?? "");
|
|
40035
40923
|
if (result.error || result.status !== 0 || catalog.length === 0) {
|
|
40036
|
-
warn(`Could not verify configured hidden-agent variants: this OpenCode host did not provide a readable model catalog. ${hostGeneration === "v2" ? "Start the background service with opencode service start, then check" : "Check"} ${guidance}.`);
|
|
40924
|
+
warn(`Could not verify configured hidden-agent models and variants: this OpenCode host did not provide a readable model catalog. ${hostGeneration === "v2" ? "Start the background service with opencode service start, then check" : "Check"} ${guidance}.`);
|
|
40037
40925
|
return;
|
|
40038
40926
|
}
|
|
40927
|
+
for (const entry of findUnknownConfiguredModels(models, catalog)) {
|
|
40928
|
+
const [providerID] = entry.model.split("/", 1);
|
|
40929
|
+
const role = `${entry.agent}${entry.fallback ? " fallback" : ""} model ${entry.model}`;
|
|
40930
|
+
warn(entry.unknown === "provider" ? `${role} names provider '${providerID}', which this OpenCode host does not have. The ${entry.agent} cannot run on it; configure that provider in OpenCode or choose a model listed by ${guidance}.` : `${role} is not offered by provider '${providerID}' on this OpenCode host. The ${entry.agent} cannot run on it; choose a model listed by ${guidance}.`);
|
|
40931
|
+
}
|
|
40039
40932
|
for (const entry of findUndeclaredConfiguredVariants(configured, catalog)) {
|
|
40040
40933
|
warn(`${entry.agent} model ${entry.model} requests variant '${entry.variant}', which this host does not offer. Remove the variant or choose one listed by ${guidance}.`);
|
|
40041
40934
|
}
|
|
40042
40935
|
} finally {
|
|
40043
|
-
|
|
40936
|
+
rmSync5(tempRoot, { recursive: true, force: true });
|
|
40044
40937
|
}
|
|
40045
40938
|
}
|
|
40046
40939
|
function parseOpenCodeV2ModelCatalog(output) {
|
|
@@ -40159,12 +41052,12 @@ function checkUserMemoriesDreamerCompatibility(mcConfig) {
|
|
|
40159
41052
|
return null;
|
|
40160
41053
|
return 'dreamer.tasks["review-user-memories"] is scheduled but dreamer.disable=true, so new promotions will not run. Remove dreamer.disable or set dreamer.tasks["review-user-memories"].schedule="" to disable the task.';
|
|
40161
41054
|
}
|
|
40162
|
-
async function fetchNpmLatest(pkg, timeoutMs = 5000) {
|
|
41055
|
+
async function fetchNpmLatest(pkg, distTag = "latest", timeoutMs = 5000) {
|
|
40163
41056
|
try {
|
|
40164
41057
|
const controller = new AbortController;
|
|
40165
41058
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
40166
41059
|
try {
|
|
40167
|
-
const res = await fetch(
|
|
41060
|
+
const res = await fetch(`${resolveNpmRegistryUrl()}/${pkg}/${encodeURIComponent(distTag)}`, {
|
|
40168
41061
|
signal: controller.signal,
|
|
40169
41062
|
headers: { Accept: "application/json" }
|
|
40170
41063
|
});
|
|
@@ -40179,6 +41072,10 @@ async function fetchNpmLatest(pkg, timeoutMs = 5000) {
|
|
|
40179
41072
|
return null;
|
|
40180
41073
|
}
|
|
40181
41074
|
}
|
|
41075
|
+
function resolveNpmRegistryUrl(env = process.env) {
|
|
41076
|
+
const configured = (env.npm_config_registry ?? env.NPM_CONFIG_REGISTRY)?.trim();
|
|
41077
|
+
return (configured || "https://registry.npmjs.org").replace(/\/+$/, "");
|
|
41078
|
+
}
|
|
40182
41079
|
function getSelfVersion2() {
|
|
40183
41080
|
const req = createRequire6(import.meta.url);
|
|
40184
41081
|
for (const relPath of ["../../package.json", "../package.json"]) {
|
|
@@ -40190,11 +41087,6 @@ function getSelfVersion2() {
|
|
|
40190
41087
|
}
|
|
40191
41088
|
return "0.0.0";
|
|
40192
41089
|
}
|
|
40193
|
-
function isPinnedOpenCodePluginSpecifier(specifier) {
|
|
40194
|
-
if (specifier === OPENCODE_PLUGIN_NAME || specifier === OPENCODE_PLUGIN_ENTRY_WITH_VERSION)
|
|
40195
|
-
return false;
|
|
40196
|
-
return specifier.startsWith(`${OPENCODE_PLUGIN_NAME}@`);
|
|
40197
|
-
}
|
|
40198
41090
|
function describeAutoUpdateStall(specifier, autoUpdateEnabled, storageDir = getMagicContextStorageDir()) {
|
|
40199
41091
|
if (!autoUpdateEnabled || !isPinnedOpenCodePluginSpecifier(specifier))
|
|
40200
41092
|
return null;
|
|
@@ -40212,10 +41104,10 @@ function getUserNpmrcPath() {
|
|
|
40212
41104
|
function collectNpmReleaseAgeWarnings() {
|
|
40213
41105
|
const ageWarnings = [];
|
|
40214
41106
|
const npmrcPath = getUserNpmrcPath();
|
|
40215
|
-
if (!
|
|
41107
|
+
if (!existsSync38(npmrcPath))
|
|
40216
41108
|
return ageWarnings;
|
|
40217
41109
|
try {
|
|
40218
|
-
const npmrc =
|
|
41110
|
+
const npmrc = readFileSync26(npmrcPath, "utf-8");
|
|
40219
41111
|
for (const line of npmrc.split(`
|
|
40220
41112
|
`)) {
|
|
40221
41113
|
const trimmed = line.trim();
|
|
@@ -40248,15 +41140,15 @@ function compareVersions(a, b) {
|
|
|
40248
41140
|
function openBrowser(url) {
|
|
40249
41141
|
try {
|
|
40250
41142
|
if (process.platform === "darwin") {
|
|
40251
|
-
const child =
|
|
41143
|
+
const child = spawnSync8("open", [url], { stdio: "ignore" });
|
|
40252
41144
|
if (child.status === 0)
|
|
40253
41145
|
return;
|
|
40254
41146
|
} else if (process.platform === "linux") {
|
|
40255
|
-
const child =
|
|
41147
|
+
const child = spawnSync8("xdg-open", [url], { stdio: "ignore" });
|
|
40256
41148
|
if (child.status === 0)
|
|
40257
41149
|
return;
|
|
40258
41150
|
} else if (process.platform === "win32") {
|
|
40259
|
-
const child =
|
|
41151
|
+
const child = spawnSync8("cmd", ["/c", "start", "", url], { stdio: "ignore" });
|
|
40260
41152
|
if (child.status === 0)
|
|
40261
41153
|
return;
|
|
40262
41154
|
}
|
|
@@ -40349,7 +41241,7 @@ function checkLocalEmbeddingRuntimeForDoctor(runtimePreference = "auto") {
|
|
|
40349
41241
|
return { issues: 0 };
|
|
40350
41242
|
}
|
|
40351
41243
|
async function checkEmbeddingConfig(magicContextConfigPath) {
|
|
40352
|
-
if (!
|
|
41244
|
+
if (!existsSync38(magicContextConfigPath)) {
|
|
40353
41245
|
return checkLocalEmbeddingRuntimeForDoctor();
|
|
40354
41246
|
}
|
|
40355
41247
|
let rawText;
|
|
@@ -40557,7 +41449,7 @@ async function runDoctor2(options = {}) {
|
|
|
40557
41449
|
const activeInstallation = installationReports[0];
|
|
40558
41450
|
if (!activeInstallation) {
|
|
40559
41451
|
fail("OpenCode is not installed or not in PATH");
|
|
40560
|
-
log2.info("Doctor checked ~/.opencode/bin/opencode
|
|
41452
|
+
log2.info("Doctor checked ~/.opencode/bin/opencode, each entry in $PATH, and the OpenCode CLI bundled in OpenChamber.app.");
|
|
40561
41453
|
log2.info("If `which opencode` succeeds outside doctor, your wrapper or shim may not be readable by Node — please share that wrapper in the issue.");
|
|
40562
41454
|
outro2("Doctor failed — install OpenCode first");
|
|
40563
41455
|
return 1;
|
|
@@ -40573,7 +41465,19 @@ async function runDoctor2(options = {}) {
|
|
|
40573
41465
|
pass(installationReports.length > 1 ? `OpenCode ${activeInstallation.version} installed (active install marked above)` : `OpenCode ${activeInstallation.version} installed`);
|
|
40574
41466
|
}
|
|
40575
41467
|
const hostGeneration = openCodeHostGenerationFromVersion(activeInstallation.version);
|
|
40576
|
-
const
|
|
41468
|
+
const storeHostSelection = selectOpenCodeStoreHost(installationReports, openCodeHostGenerationFromVersion);
|
|
41469
|
+
const storeHost = storeHostSelection?.host ?? activeInstallation;
|
|
41470
|
+
const storeGeneration = openCodeHostGenerationFromVersion(storeHost.version);
|
|
41471
|
+
const openCodeDbResolution = resolveOpenCodeDbPath(storeGeneration);
|
|
41472
|
+
if (storeHostSelection?.shadowed) {
|
|
41473
|
+
const activeStore = resolveOpenCodeDbPath(hostGeneration).path;
|
|
41474
|
+
const shared = activeStore === openCodeDbResolution.path;
|
|
41475
|
+
const versionLabel = (version) => version.replace(/^opencode\s+v?/i, "");
|
|
41476
|
+
const activeVersion = versionLabel(activeInstallation.version);
|
|
41477
|
+
const storeVersion = versionLabel(storeHost.version);
|
|
41478
|
+
warn(`OpenCode ${activeVersion} (${activeInstallation.path}) is first on PATH, and OpenCode ${storeVersion} is also installed (${storeHost.path})${shared ? `; both use ${openCodeDbResolution.path}` : ""}.`);
|
|
41479
|
+
log2.warn(` Store and conversion checks below use OpenCode ${storeVersion}. Plugin configuration checks use OpenCode ${activeVersion}; to check OpenCode ${storeVersion}'s configuration instead, put its binary first on PATH and run doctor again.`);
|
|
41480
|
+
}
|
|
40577
41481
|
const openCodeDbCheck = describeOpenCodeDatabaseDoctorCheck(openCodeDbResolution);
|
|
40578
41482
|
if (openCodeDbCheck.ok)
|
|
40579
41483
|
pass(openCodeDbCheck.message);
|
|
@@ -40597,14 +41501,16 @@ async function runDoctor2(options = {}) {
|
|
|
40597
41501
|
fixed += report.repaired;
|
|
40598
41502
|
} else if (options.fix) {
|
|
40599
41503
|
warn(`${summary}; repaired=${report.repaired}, but some rows remain unconvertible`);
|
|
41504
|
+
} else if (report.migrationCompleted) {
|
|
41505
|
+
log2.info(`${summary}; OpenCode 2 already converted this store`);
|
|
40600
41506
|
} else {
|
|
40601
41507
|
warn(`${summary}; run \`magic-context doctor --fix\` before upgrading OpenCode`);
|
|
40602
41508
|
}
|
|
40603
|
-
|
|
40604
|
-
|
|
40605
|
-
|
|
40606
|
-
|
|
40607
|
-
|
|
41509
|
+
const notice = formatOpenCodeV2MissingMarkerNotice(report);
|
|
41510
|
+
if (notice) {
|
|
41511
|
+
for (const [index, line] of notice.entries()) {
|
|
41512
|
+
log2.info(index === 0 ? line : ` ${line}`);
|
|
41513
|
+
}
|
|
40608
41514
|
}
|
|
40609
41515
|
} catch (error) {
|
|
40610
41516
|
warn(`OpenCode compaction marker conversion check unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -40620,9 +41526,14 @@ async function runDoctor2(options = {}) {
|
|
|
40620
41526
|
readonly: true,
|
|
40621
41527
|
fileMustExist: true
|
|
40622
41528
|
});
|
|
40623
|
-
const dangling = listDanglingCompartmentBoundaries(contextDb, sessionDb, /\d/.test(
|
|
41529
|
+
const dangling = listDanglingCompartmentBoundaries(contextDb, sessionDb, /\d/.test(storeHost.version) ? storeGeneration : undefined, (line) => log2.info(line));
|
|
40624
41530
|
if (dangling.length === 0) {
|
|
40625
41531
|
pass("Compartment boundary ids resolve in the OpenCode session store");
|
|
41532
|
+
} else if (storeGeneration === "v2" && /\d/.test(storeHost.version)) {
|
|
41533
|
+
log2.info(`${dangling.length} compartment(s) point at OpenCode message ids that are not in the OpenCode 2 store. Magic Context places these from the neighbouring compartments; any it cannot place are listed as excluded from range recovery below.`);
|
|
41534
|
+
for (const boundary of dangling) {
|
|
41535
|
+
log2.info(` ${formatDanglingCompartmentBoundary(boundary)}`);
|
|
41536
|
+
}
|
|
40626
41537
|
} else {
|
|
40627
41538
|
warn(`${dangling.length} compartment(s) have dangling OpenCode boundary ids`);
|
|
40628
41539
|
for (const boundary of dangling) {
|
|
@@ -40631,11 +41542,11 @@ async function runDoctor2(options = {}) {
|
|
|
40631
41542
|
}
|
|
40632
41543
|
if (!supportsCoordinateGenerationReporting(contextDb)) {
|
|
40633
41544
|
log2.info("Store projection check: this context database predates the coordinate columns");
|
|
40634
|
-
} else if (!/\d/.test(
|
|
41545
|
+
} else if (!/\d/.test(storeHost.version)) {
|
|
40635
41546
|
log2.info("Store projection check: OpenCode reported no version, so the running projection is unknown");
|
|
40636
41547
|
} else {
|
|
40637
|
-
const pendingRebases = countPendingCoordinateRebases(contextDb,
|
|
40638
|
-
const pendingLine = formatPendingCoordinateRebases(pendingRebases,
|
|
41548
|
+
const pendingRebases = countPendingCoordinateRebases(contextDb, storeGeneration);
|
|
41549
|
+
const pendingLine = formatPendingCoordinateRebases(pendingRebases, storeGeneration);
|
|
40639
41550
|
if (pendingRebases.changed + pendingRebases.unrecorded === 0) {
|
|
40640
41551
|
pass(pendingLine);
|
|
40641
41552
|
} else {
|
|
@@ -40680,7 +41591,7 @@ async function runDoctor2(options = {}) {
|
|
|
40680
41591
|
pass(`OpenCode config: ${paths.opencodeConfig}`);
|
|
40681
41592
|
}
|
|
40682
41593
|
let autoUpdateEnabled = true;
|
|
40683
|
-
if (
|
|
41594
|
+
if (existsSync38(paths.magicContextConfig)) {
|
|
40684
41595
|
pass(`Magic Context config: ${paths.magicContextConfig}`);
|
|
40685
41596
|
try {
|
|
40686
41597
|
const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
|
|
@@ -40716,7 +41627,7 @@ async function runDoctor2(options = {}) {
|
|
|
40716
41627
|
warn(`No magic-context.jsonc found — using defaults`);
|
|
40717
41628
|
log2.info(" Run 'setup' to create one with model recommendations");
|
|
40718
41629
|
}
|
|
40719
|
-
if (
|
|
41630
|
+
if (existsSync38(paths.magicContextConfig)) {
|
|
40720
41631
|
try {
|
|
40721
41632
|
const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
|
|
40722
41633
|
if (!raw)
|
|
@@ -40846,59 +41757,35 @@ async function runDoctor2(options = {}) {
|
|
|
40846
41757
|
};
|
|
40847
41758
|
if (paths.opencodeConfigFormat !== "none") {
|
|
40848
41759
|
try {
|
|
40849
|
-
const raw =
|
|
41760
|
+
const raw = readFileSync26(paths.opencodeConfig, "utf-8");
|
|
40850
41761
|
const config = import_comment_json11.parse(raw);
|
|
40851
|
-
const
|
|
41762
|
+
const configName = paths.opencodeConfigFormat === "jsonc" ? "opencode.jsonc" : "opencode.json";
|
|
41763
|
+
if (checkPluginDuplicates(config, configName, options, {
|
|
41764
|
+
warn,
|
|
41765
|
+
pass: (message) => {
|
|
41766
|
+
pass(message);
|
|
41767
|
+
fixed++;
|
|
41768
|
+
},
|
|
41769
|
+
info: (message) => log2.info(message)
|
|
41770
|
+
})) {
|
|
41771
|
+
writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config, null, 2)}
|
|
41772
|
+
`);
|
|
41773
|
+
}
|
|
40852
41774
|
const allEntries = readPluginEntries(config);
|
|
40853
|
-
const found = allEntries.find(({ entry }) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
|
|
40854
|
-
const targetKey = found?.key ?? registrationKey;
|
|
40855
|
-
const rawPlugins = Array.isArray(config?.[targetKey]) ? config[targetKey] : [];
|
|
40856
|
-
const existingIdx = found ? found.index : -1;
|
|
40857
41775
|
if (allEntries.some(({ entry }) => isLocalPathPluginEntry(entry) && String(entry).includes("magic-context") && !isDevPathPluginEntry(entry))) {
|
|
40858
41776
|
warn("An unverifiable local OpenCode plugin path was ignored because its package name is not Magic Context");
|
|
40859
41777
|
}
|
|
40860
|
-
|
|
40861
|
-
|
|
40862
|
-
|
|
40863
|
-
|
|
40864
|
-
|
|
40865
|
-
|
|
40866
|
-
|
|
40867
|
-
|
|
40868
|
-
|
|
40869
|
-
pass(`Plugin registered in ${configName}`);
|
|
40870
|
-
} else if (existingIdx >= 0) {
|
|
40871
|
-
const oldEntry = rawPlugins[existingIdx];
|
|
40872
|
-
const oldEntryStr = entryAsString(oldEntry) ?? "";
|
|
40873
|
-
if (isDevPathPluginEntry(oldEntry)) {
|
|
40874
|
-
pass(`Plugin registered in ${configName} (dev path: ${oldEntryStr})`);
|
|
40875
|
-
} else {
|
|
40876
|
-
const isPinned = isPinnedOpenCodePluginSpecifier(oldEntryStr);
|
|
40877
|
-
if (isPinned && !options.force) {
|
|
40878
|
-
reportAutoUpdateStall(oldEntryStr);
|
|
40879
|
-
warn(`Plugin pinned to ${oldEntryStr} in ${configName} — use 'doctor --force' to upgrade`);
|
|
40880
|
-
} else {
|
|
40881
|
-
if (Array.isArray(oldEntry) && oldEntry.length >= 1) {
|
|
40882
|
-
const replacement = [...oldEntry];
|
|
40883
|
-
replacement[0] = OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
|
|
40884
|
-
rawPlugins[existingIdx] = replacement;
|
|
40885
|
-
} else {
|
|
40886
|
-
rawPlugins[existingIdx] = OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
|
|
40887
|
-
}
|
|
40888
|
-
config[targetKey] = rawPlugins;
|
|
40889
|
-
writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config, null, 2)}
|
|
40890
|
-
`);
|
|
40891
|
-
pass(`Upgraded plugin entry in ${configName}: ${oldEntryStr} → ${OPENCODE_PLUGIN_ENTRY_WITH_VERSION}`);
|
|
40892
|
-
fixed++;
|
|
40893
|
-
}
|
|
40894
|
-
}
|
|
40895
|
-
} else {
|
|
40896
|
-
rawPlugins.push(OPENCODE_PLUGIN_ENTRY_WITH_VERSION);
|
|
40897
|
-
config[targetKey] = rawPlugins;
|
|
41778
|
+
if (checkOpenCodePluginEntry(config, configName, { force: options.force, registrationKey: pluginConfigKeyFor(hostGeneration) }, {
|
|
41779
|
+
pass,
|
|
41780
|
+
warn,
|
|
41781
|
+
fixed: (message) => {
|
|
41782
|
+
pass(message);
|
|
41783
|
+
fixed++;
|
|
41784
|
+
},
|
|
41785
|
+
autoUpdateStall: reportAutoUpdateStall
|
|
41786
|
+
})) {
|
|
40898
41787
|
writeFileAtomic(paths.opencodeConfig, `${import_comment_json11.stringify(config, null, 2)}
|
|
40899
41788
|
`);
|
|
40900
|
-
pass(`Added plugin to ${configName}`);
|
|
40901
|
-
fixed++;
|
|
40902
41789
|
}
|
|
40903
41790
|
} catch {
|
|
40904
41791
|
warn("Could not parse opencode config to verify plugin entry");
|
|
@@ -40939,25 +41826,18 @@ async function runDoctor2(options = {}) {
|
|
|
40939
41826
|
pass("Added TUI sidebar plugin to tui.json");
|
|
40940
41827
|
warn("Restart OpenCode to see the sidebar");
|
|
40941
41828
|
fixed++;
|
|
40942
|
-
} else if (
|
|
41829
|
+
} else if (existsSync38(paths.tuiConfig)) {
|
|
40943
41830
|
try {
|
|
40944
|
-
const tuiRaw =
|
|
41831
|
+
const tuiRaw = readFileSync26(paths.tuiConfig, "utf-8");
|
|
40945
41832
|
const tuiConfig = import_comment_json11.parse(tuiRaw);
|
|
40946
41833
|
const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
|
|
40947
41834
|
const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
|
|
40948
41835
|
if (tuiRawPlugins.some((entry) => isLocalPathPluginEntry(entry) && String(entry).includes("magic-context") && !isDevPathPluginEntry(entry))) {
|
|
40949
41836
|
warn("An unverifiable local TUI plugin path was ignored because its package name is not Magic Context");
|
|
40950
41837
|
}
|
|
40951
|
-
const tuiEntryAsString = (entry) => {
|
|
40952
|
-
if (typeof entry === "string")
|
|
40953
|
-
return entry;
|
|
40954
|
-
if (Array.isArray(entry) && typeof entry[0] === "string")
|
|
40955
|
-
return entry[0];
|
|
40956
|
-
return "";
|
|
40957
|
-
};
|
|
40958
41838
|
if (tuiIdx >= 0) {
|
|
40959
41839
|
const tuiEntry = tuiRawPlugins[tuiIdx];
|
|
40960
|
-
const tuiEntryStr =
|
|
41840
|
+
const tuiEntryStr = pluginEntryPackage(tuiEntry) ?? "";
|
|
40961
41841
|
if (isDevPathPluginEntry(tuiEntry)) {
|
|
40962
41842
|
pass(`TUI sidebar plugin configured (dev path: ${tuiEntryStr})`);
|
|
40963
41843
|
} else {
|
|
@@ -40966,13 +41846,7 @@ async function runDoctor2(options = {}) {
|
|
|
40966
41846
|
reportAutoUpdateStall(tuiEntryStr);
|
|
40967
41847
|
warn(`TUI plugin pinned to ${tuiEntryStr} — use 'doctor --force' to upgrade`);
|
|
40968
41848
|
} else if (tuiPinned && options.force) {
|
|
40969
|
-
|
|
40970
|
-
const replacement = [...tuiEntry];
|
|
40971
|
-
replacement[0] = OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
|
|
40972
|
-
tuiRawPlugins[tuiIdx] = replacement;
|
|
40973
|
-
} else {
|
|
40974
|
-
tuiRawPlugins[tuiIdx] = OPENCODE_PLUGIN_ENTRY_WITH_VERSION;
|
|
40975
|
-
}
|
|
41849
|
+
tuiRawPlugins[tuiIdx] = withPluginEntrySpecifier(tuiEntry, OPENCODE_PLUGIN_ENTRY_WITH_VERSION);
|
|
40976
41850
|
tuiConfig.plugin = tuiRawPlugins;
|
|
40977
41851
|
writeFileAtomic(paths.tuiConfig, `${import_comment_json11.stringify(tuiConfig, null, 2)}
|
|
40978
41852
|
`);
|
|
@@ -40992,7 +41866,7 @@ async function runDoctor2(options = {}) {
|
|
|
40992
41866
|
fail("Could not create or verify the TUI sidebar config");
|
|
40993
41867
|
}
|
|
40994
41868
|
}
|
|
40995
|
-
if (
|
|
41869
|
+
if (existsSync38(paths.magicContextConfig)) {
|
|
40996
41870
|
try {
|
|
40997
41871
|
const raw = loadRawConfigFile({ configPath: paths.magicContextConfig, tier: "user" });
|
|
40998
41872
|
if (!raw)
|
|
@@ -41016,7 +41890,7 @@ async function runDoctor2(options = {}) {
|
|
|
41016
41890
|
const storage = getMagicContextStorageResolution();
|
|
41017
41891
|
const dbPath = join32(storage.path, "context.db");
|
|
41018
41892
|
log2.info(`Shared storage: ${storage.path} (source: ${storage.source})`);
|
|
41019
|
-
if (!
|
|
41893
|
+
if (!existsSync38(dbPath)) {
|
|
41020
41894
|
log2.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
|
|
41021
41895
|
} else {
|
|
41022
41896
|
log2.info(`Shared context DB exists at ${dbPath}`);
|
|
@@ -41063,25 +41937,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
41063
41937
|
fail(`SQLite integrity_check failed: ${err instanceof Error ? err.message : String(err)}
|
|
41064
41938
|
${formatDatabaseRepairGuidance(dbPath)}`);
|
|
41065
41939
|
}
|
|
41066
|
-
|
|
41067
|
-
const counts = {};
|
|
41068
|
-
for (const table of [
|
|
41069
|
-
"tags",
|
|
41070
|
-
"compartments",
|
|
41071
|
-
"memories",
|
|
41072
|
-
"notes",
|
|
41073
|
-
"dream_runs"
|
|
41074
|
-
]) {
|
|
41075
|
-
try {
|
|
41076
|
-
const row = db.prepare(`SELECT COUNT(*) as c FROM ${table}`).get();
|
|
41077
|
-
counts[table] = row?.c ?? 0;
|
|
41078
|
-
} catch {
|
|
41079
|
-
counts[table] = 0;
|
|
41080
|
-
}
|
|
41081
|
-
}
|
|
41082
|
-
const summary = Object.entries(counts).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
41083
|
-
log2.info(`Shared DB row counts: ${summary}`);
|
|
41084
|
-
} catch {}
|
|
41940
|
+
log2.info(`Shared DB row counts: ${formatSharedDbRowCounts(db)}`);
|
|
41085
41941
|
for (const stall of listShadowBackfillStalls(db)) {
|
|
41086
41942
|
warn(formatShadowBackfillStall(stall));
|
|
41087
41943
|
}
|
|
@@ -41130,9 +41986,30 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
41130
41986
|
log2.info(` Manually delete: ${cacheResult.path}`);
|
|
41131
41987
|
}
|
|
41132
41988
|
issues++;
|
|
41133
|
-
} else {
|
|
41989
|
+
} else if (hostGeneration !== "v2") {
|
|
41134
41990
|
pass("Plugin cache clean (no cached version found)");
|
|
41135
41991
|
}
|
|
41992
|
+
let v2DistTag;
|
|
41993
|
+
if (paths.opencodeConfigFormat !== "none") {
|
|
41994
|
+
try {
|
|
41995
|
+
v2DistTag = configuredOpenCodeV2DistTag(import_comment_json11.parse(readFileSync26(paths.opencodeConfig, "utf-8")));
|
|
41996
|
+
} catch {}
|
|
41997
|
+
}
|
|
41998
|
+
const v2Cache = reportOpenCodeV2PluginCache(checkOpenCodeV2PluginCache({
|
|
41999
|
+
fix: options.fix,
|
|
42000
|
+
force: options.force,
|
|
42001
|
+
latestVersion: v2DistTag ? await fetchNpmLatest(OPENCODE_PLUGIN_NAME, v2DistTag) : pluginNpmLatest,
|
|
42002
|
+
distTag: v2DistTag,
|
|
42003
|
+
hostFiles: openCodeHostDatabaseFiles([openCodeDbResolution.path])
|
|
42004
|
+
}), { pass, warn, info: (message) => log2.info(message) }, { reportMissing: hostGeneration === "v2" });
|
|
42005
|
+
if (v2Cache.fixed)
|
|
42006
|
+
fixed++;
|
|
42007
|
+
if (v2Cache.issue)
|
|
42008
|
+
issues++;
|
|
42009
|
+
const sharedDbVersion = readContextDbSchemaVersion(dbPath);
|
|
42010
|
+
if (sharedDbVersion !== null) {
|
|
42011
|
+
reportCachedPluginFences(compareCachedPluginFences(listCachedOpenCodePluginFences(), sharedDbVersion), { pass, fail, info: (message) => log2.info(message) });
|
|
42012
|
+
}
|
|
41136
42013
|
{
|
|
41137
42014
|
const ageWarnings = collectNpmReleaseAgeWarnings();
|
|
41138
42015
|
if (ageWarnings.length > 0) {
|
|
@@ -41145,7 +42022,11 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
41145
42022
|
issues++;
|
|
41146
42023
|
}
|
|
41147
42024
|
}
|
|
41148
|
-
const
|
|
42025
|
+
const logHarnesses = [
|
|
42026
|
+
...hostGeneration === "v1" ? ["opencode"] : [],
|
|
42027
|
+
...hostGeneration === "v2" || storeGeneration === "v2" ? ["opencode2"] : []
|
|
42028
|
+
];
|
|
42029
|
+
const logFiles = logHarnesses.flatMap((harness) => inspectMagicContextLogs(harness)).filter((file, index, all) => all.findIndex((other) => other.path === file.path) === index);
|
|
41149
42030
|
const existingLogFiles = logFiles.filter((file) => file.exists);
|
|
41150
42031
|
if (existingLogFiles.length === 0) {
|
|
41151
42032
|
log2.info(`No plugin log file yet; checked: ${logFiles.map((file) => file.path).join(", ")}`);
|
|
@@ -41193,7 +42074,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
41193
42074
|
}
|
|
41194
42075
|
return 0;
|
|
41195
42076
|
}
|
|
41196
|
-
var import_comment_json11, CLI_PACKAGE_NAME = "@cortexkit/magic-context";
|
|
42077
|
+
var import_comment_json11, CLI_PACKAGE_NAME = "@cortexkit/magic-context", SHARED_DB_ROW_COUNT_TABLES;
|
|
41197
42078
|
var init_doctor_opencode = __esm(async () => {
|
|
41198
42079
|
init_config();
|
|
41199
42080
|
init_agent_disable();
|
|
@@ -41227,6 +42108,9 @@ var init_doctor_opencode = __esm(async () => {
|
|
|
41227
42108
|
init_prompts();
|
|
41228
42109
|
init_redaction2();
|
|
41229
42110
|
init_doctor_opencode_cache();
|
|
42111
|
+
init_doctor_opencode_plugin_duplicates();
|
|
42112
|
+
init_doctor_opencode_plugin_entry();
|
|
42113
|
+
init_doctor_opencode2_cache();
|
|
41230
42114
|
await __promiseAll([
|
|
41231
42115
|
init_storage_db(),
|
|
41232
42116
|
init_sqlite(),
|
|
@@ -41234,13 +42118,15 @@ var init_doctor_opencode = __esm(async () => {
|
|
|
41234
42118
|
init_storage_versions(),
|
|
41235
42119
|
init_v22_backfill_commands(),
|
|
41236
42120
|
init_doctor_authority(),
|
|
42121
|
+
init_doctor_cached_plugin_fence(),
|
|
41237
42122
|
init_doctor_harness_relabel()
|
|
41238
42123
|
]);
|
|
41239
42124
|
import_comment_json11 = __toESM(require_src3(), 1);
|
|
42125
|
+
SHARED_DB_ROW_COUNT_TABLES = ["tags", "compartments", "memories", "notes", "dream_runs"];
|
|
41240
42126
|
});
|
|
41241
42127
|
|
|
41242
42128
|
// src/lib/diagnostics-pi.ts
|
|
41243
|
-
import { existsSync as
|
|
42129
|
+
import { existsSync as existsSync39, readdirSync as readdirSync7, readFileSync as readFileSync27, statSync as statSync16 } from "node:fs";
|
|
41244
42130
|
import { createRequire as createRequire7 } from "node:module";
|
|
41245
42131
|
import { join as join33 } from "node:path";
|
|
41246
42132
|
function getSelfVersion3() {
|
|
@@ -41257,7 +42143,7 @@ function getSelfVersion3() {
|
|
|
41257
42143
|
}
|
|
41258
42144
|
function fileSize2(path) {
|
|
41259
42145
|
try {
|
|
41260
|
-
return
|
|
42146
|
+
return existsSync39(path) ? statSync16(path).size : 0;
|
|
41261
42147
|
} catch {
|
|
41262
42148
|
return 0;
|
|
41263
42149
|
}
|
|
@@ -41269,11 +42155,11 @@ function sanitizeValue2(value) {
|
|
|
41269
42155
|
return sanitizeConfigValue(value);
|
|
41270
42156
|
}
|
|
41271
42157
|
function readJsonc(path) {
|
|
41272
|
-
if (!
|
|
42158
|
+
if (!existsSync39(path))
|
|
41273
42159
|
return { value: {} };
|
|
41274
42160
|
try {
|
|
41275
42161
|
return {
|
|
41276
|
-
value: import_comment_json12.parse(
|
|
42162
|
+
value: import_comment_json12.parse(readFileSync27(path, "utf-8"))
|
|
41277
42163
|
};
|
|
41278
42164
|
} catch (error) {
|
|
41279
42165
|
return {
|
|
@@ -41289,7 +42175,7 @@ function readConfigDiagnostic(path) {
|
|
|
41289
42175
|
const parsed = readJsonc(path);
|
|
41290
42176
|
return {
|
|
41291
42177
|
path,
|
|
41292
|
-
exists:
|
|
42178
|
+
exists: existsSync39(path),
|
|
41293
42179
|
...parsed.parseError ? { parseError: parsed.parseError } : {},
|
|
41294
42180
|
flags: sanitizeValue2(parsed.value)
|
|
41295
42181
|
};
|
|
@@ -41307,10 +42193,10 @@ function reverseSlugToDirectory(slug) {
|
|
|
41307
42193
|
}
|
|
41308
42194
|
function collectPiRecentSessions() {
|
|
41309
42195
|
const sessionsRoot = getPiSessionsRoot();
|
|
41310
|
-
if (!
|
|
42196
|
+
if (!existsSync39(sessionsRoot))
|
|
41311
42197
|
return [];
|
|
41312
42198
|
try {
|
|
41313
|
-
const slugs =
|
|
42199
|
+
const slugs = readdirSync7(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
41314
42200
|
const candidates = [];
|
|
41315
42201
|
for (const slug of slugs) {
|
|
41316
42202
|
const directory = reverseSlugToDirectory(slug);
|
|
@@ -41319,7 +42205,7 @@ function collectPiRecentSessions() {
|
|
|
41319
42205
|
const slugDir = join33(sessionsRoot, slug);
|
|
41320
42206
|
let files;
|
|
41321
42207
|
try {
|
|
41322
|
-
files =
|
|
42208
|
+
files = readdirSync7(slugDir).filter((name) => name.endsWith(".jsonl"));
|
|
41323
42209
|
} catch {
|
|
41324
42210
|
continue;
|
|
41325
42211
|
}
|
|
@@ -41343,7 +42229,7 @@ function collectPiRecentSessions() {
|
|
|
41343
42229
|
}
|
|
41344
42230
|
function parseHistorianDumpMeta2(path) {
|
|
41345
42231
|
try {
|
|
41346
|
-
const xml =
|
|
42232
|
+
const xml = readFileSync27(path, "utf-8");
|
|
41347
42233
|
const parsed = parseCompartmentOutput(xml);
|
|
41348
42234
|
const factCountByCategory = {};
|
|
41349
42235
|
for (const fact of parsed.facts) {
|
|
@@ -41376,10 +42262,10 @@ function parseHistorianDumpMeta2(path) {
|
|
|
41376
42262
|
}
|
|
41377
42263
|
}
|
|
41378
42264
|
function listDumpsInDir2(dir, limit) {
|
|
41379
|
-
if (!
|
|
42265
|
+
if (!existsSync39(dir))
|
|
41380
42266
|
return { count: 0, recent: [] };
|
|
41381
42267
|
try {
|
|
41382
|
-
const entries =
|
|
42268
|
+
const entries = readdirSync7(dir).filter((name) => name.endsWith(".xml")).map((name) => {
|
|
41383
42269
|
const stat = statSync16(join33(dir, name));
|
|
41384
42270
|
return {
|
|
41385
42271
|
name,
|
|
@@ -41470,7 +42356,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
41470
42356
|
piVersion: pi ? getPiVersion(pi.path) : null,
|
|
41471
42357
|
settings: {
|
|
41472
42358
|
path: settingsPath,
|
|
41473
|
-
exists:
|
|
42359
|
+
exists: existsSync39(settingsPath),
|
|
41474
42360
|
...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
|
|
41475
42361
|
hasMagicContextPackage: hasPiMagicContextPackage(packages),
|
|
41476
42362
|
packages: sanitizeValue2(packages)
|
|
@@ -41487,7 +42373,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
41487
42373
|
storageDir: {
|
|
41488
42374
|
path: storageDirPath,
|
|
41489
42375
|
source: storageResolution.source,
|
|
41490
|
-
exists:
|
|
42376
|
+
exists: existsSync39(storageDirPath),
|
|
41491
42377
|
contextDbSizeBytes: fileSize2(dbPath)
|
|
41492
42378
|
},
|
|
41493
42379
|
conflicts: {
|
|
@@ -41593,7 +42479,7 @@ var init_diagnostics_pi = __esm(() => {
|
|
|
41593
42479
|
|
|
41594
42480
|
// src/lib/logs-pi.ts
|
|
41595
42481
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "node:fs";
|
|
41596
|
-
import { dirname as
|
|
42482
|
+
import { dirname as dirname19, join as join34 } from "node:path";
|
|
41597
42483
|
function sanitizeLogContent2(content) {
|
|
41598
42484
|
return sanitizeString2(content);
|
|
41599
42485
|
}
|
|
@@ -41664,7 +42550,7 @@ async function bundleIssueReport2(report, description, title, options = {}) {
|
|
|
41664
42550
|
const cwd = options.cwd ?? process.cwd();
|
|
41665
42551
|
const timestamp = formatTimestamp2(options.now ?? new Date);
|
|
41666
42552
|
const path = options.outputPath ?? join34(cwd, `magic-context-pi-issue-${timestamp}.md`);
|
|
41667
|
-
mkdirSync10(
|
|
42553
|
+
mkdirSync10(dirname19(path), { recursive: true });
|
|
41668
42554
|
writeFileSync9(path, `${bodyMarkdown}
|
|
41669
42555
|
`);
|
|
41670
42556
|
const fullPath = truncated ? options.outputPath ? `${options.outputPath}.full.md` : join34(cwd, `magic-context-pi-issue-${timestamp}-full.md`) : undefined;
|
|
@@ -41680,11 +42566,11 @@ var init_logs_pi = __esm(() => {
|
|
|
41680
42566
|
});
|
|
41681
42567
|
|
|
41682
42568
|
// src/commands/doctor-pi.ts
|
|
41683
|
-
import { execFileSync as execFileSync6, spawnSync as
|
|
41684
|
-
import { existsSync as
|
|
42569
|
+
import { execFileSync as execFileSync6, spawnSync as spawnSync9 } from "node:child_process";
|
|
42570
|
+
import { existsSync as existsSync40, mkdirSync as mkdirSync11, readdirSync as readdirSync8, readFileSync as readFileSync28, rmSync as rmSync6, statSync as statSync17 } from "node:fs";
|
|
41685
42571
|
import { createRequire as createRequire8 } from "node:module";
|
|
41686
42572
|
import { homedir as homedir17 } from "node:os";
|
|
41687
|
-
import { dirname as
|
|
42573
|
+
import { dirname as dirname20, isAbsolute as isAbsolute8, join as join35 } from "node:path";
|
|
41688
42574
|
function depsFrom(options) {
|
|
41689
42575
|
return {
|
|
41690
42576
|
...DEFAULT_DEPS5,
|
|
@@ -41775,7 +42661,7 @@ function summarize(results) {
|
|
|
41775
42661
|
function readJsonc2(path) {
|
|
41776
42662
|
try {
|
|
41777
42663
|
return {
|
|
41778
|
-
value: import_comment_json13.parse(
|
|
42664
|
+
value: import_comment_json13.parse(readFileSync28(path, "utf-8"))
|
|
41779
42665
|
};
|
|
41780
42666
|
} catch (error) {
|
|
41781
42667
|
return {
|
|
@@ -41827,13 +42713,13 @@ function piPluginDirCandidates(packages, cwd) {
|
|
|
41827
42713
|
}
|
|
41828
42714
|
dirs.push(join35(agentDir, "npm", "node_modules", PACKAGE_NAME2));
|
|
41829
42715
|
dirs.push(join35(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME2));
|
|
41830
|
-
return dirs.filter((dir) =>
|
|
42716
|
+
return dirs.filter((dir) => existsSync40(join35(dir, "package.json")));
|
|
41831
42717
|
}
|
|
41832
42718
|
function projectConfigPath(cwd) {
|
|
41833
42719
|
return resolveCortexKitProjectConfigPath(cwd);
|
|
41834
42720
|
}
|
|
41835
42721
|
function readConfigForEmbedding(path, isProjectConfig) {
|
|
41836
|
-
if (!
|
|
42722
|
+
if (!existsSync40(path))
|
|
41837
42723
|
return null;
|
|
41838
42724
|
try {
|
|
41839
42725
|
const raw = loadRawConfigFile({
|
|
@@ -41934,7 +42820,7 @@ function cacheRoots(cwd) {
|
|
|
41934
42820
|
function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
|
|
41935
42821
|
const found = new Map;
|
|
41936
42822
|
const visit = (path, depth) => {
|
|
41937
|
-
if (depth < 0 || !
|
|
42823
|
+
if (depth < 0 || !existsSync40(path))
|
|
41938
42824
|
return;
|
|
41939
42825
|
let stat;
|
|
41940
42826
|
try {
|
|
@@ -41945,9 +42831,9 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
|
|
|
41945
42831
|
if (!stat.isDirectory())
|
|
41946
42832
|
return;
|
|
41947
42833
|
const packageJson = join35(path, "package.json");
|
|
41948
|
-
if (
|
|
42834
|
+
if (existsSync40(packageJson)) {
|
|
41949
42835
|
try {
|
|
41950
|
-
const pkg = JSON.parse(
|
|
42836
|
+
const pkg = JSON.parse(readFileSync28(packageJson, "utf-8"));
|
|
41951
42837
|
const name = typeof pkg.name === "string" ? pkg.name : "";
|
|
41952
42838
|
const version = typeof pkg.version === "string" ? pkg.version : undefined;
|
|
41953
42839
|
if (name === PACKAGE_NAME2) {
|
|
@@ -41962,7 +42848,7 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
|
|
|
41962
42848
|
}
|
|
41963
42849
|
let entries = [];
|
|
41964
42850
|
try {
|
|
41965
|
-
entries =
|
|
42851
|
+
entries = readdirSync8(path);
|
|
41966
42852
|
} catch {
|
|
41967
42853
|
return;
|
|
41968
42854
|
}
|
|
@@ -42012,7 +42898,7 @@ async function runHealthChecks2(options) {
|
|
|
42012
42898
|
}
|
|
42013
42899
|
const settingsPath = getPiUserExtensionsPath();
|
|
42014
42900
|
let packages = [];
|
|
42015
|
-
if (!
|
|
42901
|
+
if (!existsSync40(settingsPath)) {
|
|
42016
42902
|
add2(results, "fail", `Pi settings not found at ${settingsPath}`);
|
|
42017
42903
|
repairPlan.addPackageEntry = true;
|
|
42018
42904
|
} else {
|
|
@@ -42036,7 +42922,7 @@ async function runHealthChecks2(options) {
|
|
|
42036
42922
|
["user", userConfigPath, true],
|
|
42037
42923
|
["project", projectPath, false]
|
|
42038
42924
|
]) {
|
|
42039
|
-
if (!
|
|
42925
|
+
if (!existsSync40(path)) {
|
|
42040
42926
|
if (required) {
|
|
42041
42927
|
add2(results, "warn", `No ${label} magic-context.jsonc found at ${path}`);
|
|
42042
42928
|
if (userConfigMigrationRefused) {
|
|
@@ -42078,7 +42964,7 @@ async function runHealthChecks2(options) {
|
|
|
42078
42964
|
const storageDir = storage.path;
|
|
42079
42965
|
const dbPath = join35(storageDir, "context.db");
|
|
42080
42966
|
add2(results, "info", `Shared storage: ${storageDir} (source: ${storage.source})`);
|
|
42081
|
-
const existedBeforeOpen =
|
|
42967
|
+
const existedBeforeOpen = existsSync40(dbPath);
|
|
42082
42968
|
if (existedBeforeOpen)
|
|
42083
42969
|
add2(results, "pass", `Shared context DB exists at ${dbPath}`);
|
|
42084
42970
|
else
|
|
@@ -42296,7 +43182,7 @@ ${formatDatabaseRepairGuidance(dbPath)}`);
|
|
|
42296
43182
|
return { results, repairPlan, ...summarize(results) };
|
|
42297
43183
|
}
|
|
42298
43184
|
function writeDefaultMagicContextConfig(path) {
|
|
42299
|
-
mkdirSync11(
|
|
43185
|
+
mkdirSync11(dirname20(path), { recursive: true });
|
|
42300
43186
|
const config = {
|
|
42301
43187
|
$schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
|
|
42302
43188
|
...MagicContextConfigSchema.parse({})
|
|
@@ -42318,7 +43204,7 @@ function repair2(plan, prompts) {
|
|
|
42318
43204
|
}
|
|
42319
43205
|
if (plan.writeUserConfig) {
|
|
42320
43206
|
const configPath = getPiUserConfigPath();
|
|
42321
|
-
if (!
|
|
43207
|
+
if (!existsSync40(configPath)) {
|
|
42322
43208
|
try {
|
|
42323
43209
|
writeDefaultMagicContextConfig(configPath);
|
|
42324
43210
|
prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
|
|
@@ -42330,7 +43216,7 @@ function repair2(plan, prompts) {
|
|
|
42330
43216
|
}
|
|
42331
43217
|
for (const path of plan.clearCachePaths) {
|
|
42332
43218
|
try {
|
|
42333
|
-
|
|
43219
|
+
rmSync6(path, { recursive: true, force: true });
|
|
42334
43220
|
prompts.log.success(`Cleared stale Pi extension cache: ${path}`);
|
|
42335
43221
|
fixed += 1;
|
|
42336
43222
|
} catch (error) {
|
|
@@ -42565,12 +43451,12 @@ var init_doctor_pi = __esm(async () => {
|
|
|
42565
43451
|
openExistingContextDatabase,
|
|
42566
43452
|
now: () => new Date,
|
|
42567
43453
|
execFileSync: execFileSync6,
|
|
42568
|
-
spawnSync:
|
|
43454
|
+
spawnSync: spawnSync9
|
|
42569
43455
|
};
|
|
42570
43456
|
});
|
|
42571
43457
|
|
|
42572
43458
|
// src/commands/doctor.ts
|
|
42573
|
-
import { existsSync as
|
|
43459
|
+
import { existsSync as existsSync41, rmSync as rmSync7 } from "node:fs";
|
|
42574
43460
|
import { join as join36 } from "node:path";
|
|
42575
43461
|
async function runDoctor4(options) {
|
|
42576
43462
|
if (options.clear)
|
|
@@ -42668,9 +43554,16 @@ async function runClear() {
|
|
|
42668
43554
|
}
|
|
42669
43555
|
const items = [];
|
|
42670
43556
|
for (const adapter of installed) {
|
|
42671
|
-
const cache
|
|
42672
|
-
|
|
42673
|
-
|
|
43557
|
+
for (const cache of adapter.getPluginCacheInfo()) {
|
|
43558
|
+
if (cache.path && cache.exists) {
|
|
43559
|
+
items.push({
|
|
43560
|
+
adapter,
|
|
43561
|
+
path: cache.path,
|
|
43562
|
+
sizeBytes: cache.sizeBytes,
|
|
43563
|
+
label: cache.label,
|
|
43564
|
+
clear: cache.clear
|
|
43565
|
+
});
|
|
43566
|
+
}
|
|
42674
43567
|
}
|
|
42675
43568
|
}
|
|
42676
43569
|
if (items.length === 0) {
|
|
@@ -42679,7 +43572,7 @@ async function runClear() {
|
|
|
42679
43572
|
return 0;
|
|
42680
43573
|
}
|
|
42681
43574
|
const picks = await selectMany("Select caches to clear:", items.map((item, idx) => ({
|
|
42682
|
-
label: `${item.adapter.displayName}: ${formatSize(item.sizeBytes)} — ${item.path}`,
|
|
43575
|
+
label: `${item.adapter.displayName}${item.label ? ` (${item.label})` : ""}: ${formatSize(item.sizeBytes)} — ${item.path}`,
|
|
42683
43576
|
value: String(idx)
|
|
42684
43577
|
})));
|
|
42685
43578
|
if (picks.length === 0) {
|
|
@@ -42702,8 +43595,16 @@ async function runClear() {
|
|
|
42702
43595
|
const s = spinner2();
|
|
42703
43596
|
s.start(`Clearing ${item.path}`);
|
|
42704
43597
|
try {
|
|
42705
|
-
if (
|
|
42706
|
-
|
|
43598
|
+
if (item.clear) {
|
|
43599
|
+
const result = item.clear();
|
|
43600
|
+
if (!result.cleared) {
|
|
43601
|
+
s.stop(`Left in place: ${item.path}`);
|
|
43602
|
+
log2.warn(result.reason);
|
|
43603
|
+
failed += 1;
|
|
43604
|
+
continue;
|
|
43605
|
+
}
|
|
43606
|
+
} else if (existsSync41(item.path)) {
|
|
43607
|
+
rmSync7(item.path, { recursive: true, force: true });
|
|
42707
43608
|
}
|
|
42708
43609
|
s.stop(`Cleared ${item.path}`);
|
|
42709
43610
|
} catch (err) {
|
|
@@ -42739,9 +43640,121 @@ var init_doctor = __esm(async () => {
|
|
|
42739
43640
|
});
|
|
42740
43641
|
|
|
42741
43642
|
// src/index.ts
|
|
42742
|
-
init_prompts();
|
|
42743
43643
|
import { createRequire as createRequire9 } from "node:module";
|
|
42744
43644
|
|
|
43645
|
+
// src/lib/cli-help.ts
|
|
43646
|
+
var HELP_FLAGS = new Set(["--help", "-h"]);
|
|
43647
|
+
function hasHelpFlag(args) {
|
|
43648
|
+
return args.some((arg) => HELP_FLAGS.has(arg));
|
|
43649
|
+
}
|
|
43650
|
+
var DOCTOR_SUBCOMMANDS_WITH_OWN_HELP = new Set([
|
|
43651
|
+
"migrate",
|
|
43652
|
+
"migrate-session",
|
|
43653
|
+
"repair-db"
|
|
43654
|
+
]);
|
|
43655
|
+
var HARNESS_LINES = [
|
|
43656
|
+
" Harness selection:",
|
|
43657
|
+
" --harness opencode Target OpenCode only",
|
|
43658
|
+
" --harness pi Target Pi only",
|
|
43659
|
+
" --harness omp Target Oh My Pi (OMP) only",
|
|
43660
|
+
" (default: auto-detect, prompt if multiple installed)"
|
|
43661
|
+
];
|
|
43662
|
+
var SETUP_HELP = [
|
|
43663
|
+
"",
|
|
43664
|
+
" Usage: magic-context setup [--harness opencode|pi|omp] [--dry-run]",
|
|
43665
|
+
"",
|
|
43666
|
+
" Interactive setup wizard: registers the Magic Context plugin with the",
|
|
43667
|
+
" selected harness and writes its Magic Context config.",
|
|
43668
|
+
"",
|
|
43669
|
+
" Options:",
|
|
43670
|
+
" --dry-run Preview the wizard without writing any files",
|
|
43671
|
+
...HARNESS_LINES,
|
|
43672
|
+
""
|
|
43673
|
+
].join(`
|
|
43674
|
+
`);
|
|
43675
|
+
var DOCTOR_HELP = [
|
|
43676
|
+
"",
|
|
43677
|
+
" Usage: magic-context doctor [options]",
|
|
43678
|
+
" magic-context doctor <subcommand> [options]",
|
|
43679
|
+
"",
|
|
43680
|
+
" Check the installed harnesses and fix configuration issues.",
|
|
43681
|
+
"",
|
|
43682
|
+
" Options:",
|
|
43683
|
+
" --fix Repair safe, Magic Context-owned store rows and clear an outdated OpenCode 2 plugin cache",
|
|
43684
|
+
" --force Force-clear the plugin cache",
|
|
43685
|
+
" --clear Interactive cache cleanup picker",
|
|
43686
|
+
" --issue Collect diagnostics and open a GitHub issue",
|
|
43687
|
+
" --report <path> Write the issue diagnostics to <path> without prompting",
|
|
43688
|
+
" --check-v22-backfill Show v22 memory backfill status",
|
|
43689
|
+
" --retry-v22-backfill Retry failed v22 memory backfill rows",
|
|
43690
|
+
" --rekey-v22-dir-identity <path> Re-key legacy dir identity rows",
|
|
43691
|
+
...HARNESS_LINES,
|
|
43692
|
+
"",
|
|
43693
|
+
" Subcommands (each accepts --help):",
|
|
43694
|
+
" drain-authority <project> Drain module memory/note authority back to TypeScript",
|
|
43695
|
+
" migrate Migrate an OpenCode session to Pi or OMP JSONL",
|
|
43696
|
+
" migrate-session Re-home an OpenCode session to another directory",
|
|
43697
|
+
" merge-identity Merge project rows between identities",
|
|
43698
|
+
" repair-db Back up and salvage a corrupted shared database",
|
|
43699
|
+
" list-hidden-sessions List Magic Context OpenCode 2 roots",
|
|
43700
|
+
""
|
|
43701
|
+
].join(`
|
|
43702
|
+
`);
|
|
43703
|
+
var DRAIN_AUTHORITY_HELP = [
|
|
43704
|
+
"",
|
|
43705
|
+
" Usage: magic-context doctor drain-authority <project>",
|
|
43706
|
+
"",
|
|
43707
|
+
" Drain the module's memory and note authority for <project> back to TypeScript.",
|
|
43708
|
+
""
|
|
43709
|
+
].join(`
|
|
43710
|
+
`);
|
|
43711
|
+
var MERGE_IDENTITY_HELP = [
|
|
43712
|
+
"",
|
|
43713
|
+
" Usage: magic-context doctor merge-identity --from <identity> --to <identity> [--dry-run] [--yes] [--db <path>]",
|
|
43714
|
+
"",
|
|
43715
|
+
" Merge every project-scoped row from one project identity into another.",
|
|
43716
|
+
"",
|
|
43717
|
+
" Options:",
|
|
43718
|
+
" --from <identity> Identity whose rows are moved",
|
|
43719
|
+
" --to <identity> Identity that receives them",
|
|
43720
|
+
" --dry-run Report what would change without writing",
|
|
43721
|
+
" --yes Confirm the write (required unless --dry-run)",
|
|
43722
|
+
" --db <path> Use this context.db instead of the shared one",
|
|
43723
|
+
""
|
|
43724
|
+
].join(`
|
|
43725
|
+
`);
|
|
43726
|
+
var LIST_HIDDEN_SESSIONS_HELP = [
|
|
43727
|
+
"",
|
|
43728
|
+
" Usage: magic-context doctor list-hidden-sessions",
|
|
43729
|
+
"",
|
|
43730
|
+
" List the hidden OpenCode 2 root sessions Magic Context reuses for its",
|
|
43731
|
+
" historian and dreamer runs. Read-only.",
|
|
43732
|
+
""
|
|
43733
|
+
].join(`
|
|
43734
|
+
`);
|
|
43735
|
+
function subcommandHelp(argv) {
|
|
43736
|
+
const [command, ...rest] = argv;
|
|
43737
|
+
if (!hasHelpFlag(rest))
|
|
43738
|
+
return null;
|
|
43739
|
+
if (command === "setup")
|
|
43740
|
+
return SETUP_HELP;
|
|
43741
|
+
if (command !== "doctor")
|
|
43742
|
+
return null;
|
|
43743
|
+
const subcommand = rest[0];
|
|
43744
|
+
if (subcommand === "drain-authority")
|
|
43745
|
+
return DRAIN_AUTHORITY_HELP;
|
|
43746
|
+
if (subcommand === "merge-identity")
|
|
43747
|
+
return MERGE_IDENTITY_HELP;
|
|
43748
|
+
if (subcommand === "list-hidden-sessions")
|
|
43749
|
+
return LIST_HIDDEN_SESSIONS_HELP;
|
|
43750
|
+
if (subcommand !== undefined && DOCTOR_SUBCOMMANDS_WITH_OWN_HELP.has(subcommand))
|
|
43751
|
+
return null;
|
|
43752
|
+
return DOCTOR_HELP;
|
|
43753
|
+
}
|
|
43754
|
+
|
|
43755
|
+
// src/index.ts
|
|
43756
|
+
init_prompts();
|
|
43757
|
+
|
|
42745
43758
|
// src/lib/sqlite-preflight.ts
|
|
42746
43759
|
async function probeSqliteBackend() {
|
|
42747
43760
|
await init_sqlite().then(() => ({}));
|
|
@@ -42751,7 +43764,7 @@ function formatSqlitePreflightFailure(error) {
|
|
|
42751
43764
|
return [
|
|
42752
43765
|
"Magic Context doctor cannot use SQLite in this runtime.",
|
|
42753
43766
|
`SQLite probe: ${detail}`,
|
|
42754
|
-
"Remediation: install Node.js >= 24 or use a Bun build with node:sqlite.",
|
|
43767
|
+
"Remediation: install Node.js 22.16+ (22.x) or >= 24, or use a Bun build with node:sqlite.",
|
|
42755
43768
|
"For Docker, use node:24-slim or a two-runtime image."
|
|
42756
43769
|
].join(`
|
|
42757
43770
|
`);
|
|
@@ -42818,6 +43831,7 @@ function printUsage() {
|
|
|
42818
43831
|
console.log(" (default: auto-detect, prompt if multiple installed)");
|
|
42819
43832
|
console.log("");
|
|
42820
43833
|
console.log(" Usage:");
|
|
43834
|
+
console.log(" npx @cortexkit/magic-context@latest <command> --help # help for one command");
|
|
42821
43835
|
console.log(" npx @cortexkit/magic-context@latest setup");
|
|
42822
43836
|
console.log(" # add --dry-run to preview the wizard without writing any files");
|
|
42823
43837
|
console.log(" npx @cortexkit/magic-context@latest doctor");
|
|
@@ -42837,6 +43851,11 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
42837
43851
|
}
|
|
42838
43852
|
const command = argv[0];
|
|
42839
43853
|
const rest = argv.slice(1);
|
|
43854
|
+
const help = subcommandHelp(argv);
|
|
43855
|
+
if (help !== null) {
|
|
43856
|
+
console.log(help);
|
|
43857
|
+
return 0;
|
|
43858
|
+
}
|
|
42840
43859
|
try {
|
|
42841
43860
|
if (command === "setup") {
|
|
42842
43861
|
await Promise.resolve().then(() => init_setup());
|