@cortexkit/magic-context 0.36.0 → 0.36.1
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 +2813 -560
- package/package.json +57 -56
package/dist/index.js
CHANGED
|
@@ -11569,8 +11569,156 @@ var init_opencode = __esm(() => {
|
|
|
11569
11569
|
import_comment_json = __toESM(require_src3(), 1);
|
|
11570
11570
|
});
|
|
11571
11571
|
|
|
11572
|
-
// src/
|
|
11572
|
+
// ../plugin/src/shared/jsonc-parser.ts
|
|
11573
11573
|
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "node:fs";
|
|
11574
|
+
function stripJsonComments(content) {
|
|
11575
|
+
let result = "";
|
|
11576
|
+
let inString = false;
|
|
11577
|
+
let escaped = false;
|
|
11578
|
+
let inLineComment = false;
|
|
11579
|
+
let inBlockComment = false;
|
|
11580
|
+
for (let index = 0;index < content.length; index += 1) {
|
|
11581
|
+
const char = content[index];
|
|
11582
|
+
const next = content[index + 1];
|
|
11583
|
+
if (inLineComment) {
|
|
11584
|
+
if (char === `
|
|
11585
|
+
`) {
|
|
11586
|
+
inLineComment = false;
|
|
11587
|
+
result += char;
|
|
11588
|
+
}
|
|
11589
|
+
continue;
|
|
11590
|
+
}
|
|
11591
|
+
if (inBlockComment) {
|
|
11592
|
+
if (char === "*" && next === "/") {
|
|
11593
|
+
inBlockComment = false;
|
|
11594
|
+
index += 1;
|
|
11595
|
+
}
|
|
11596
|
+
continue;
|
|
11597
|
+
}
|
|
11598
|
+
if (inString) {
|
|
11599
|
+
result += char;
|
|
11600
|
+
if (escaped) {
|
|
11601
|
+
escaped = false;
|
|
11602
|
+
} else if (char === "\\") {
|
|
11603
|
+
escaped = true;
|
|
11604
|
+
} else if (char === '"') {
|
|
11605
|
+
inString = false;
|
|
11606
|
+
}
|
|
11607
|
+
continue;
|
|
11608
|
+
}
|
|
11609
|
+
if (char === '"') {
|
|
11610
|
+
inString = true;
|
|
11611
|
+
result += char;
|
|
11612
|
+
continue;
|
|
11613
|
+
}
|
|
11614
|
+
if (char === "/" && next === "/") {
|
|
11615
|
+
inLineComment = true;
|
|
11616
|
+
index += 1;
|
|
11617
|
+
continue;
|
|
11618
|
+
}
|
|
11619
|
+
if (char === "/" && next === "*") {
|
|
11620
|
+
inBlockComment = true;
|
|
11621
|
+
index += 1;
|
|
11622
|
+
continue;
|
|
11623
|
+
}
|
|
11624
|
+
result += char;
|
|
11625
|
+
}
|
|
11626
|
+
return result;
|
|
11627
|
+
}
|
|
11628
|
+
function stripTrailingCommas(content) {
|
|
11629
|
+
let result = "";
|
|
11630
|
+
let inString = false;
|
|
11631
|
+
let escaped = false;
|
|
11632
|
+
for (let index = 0;index < content.length; index += 1) {
|
|
11633
|
+
const char = content[index];
|
|
11634
|
+
if (inString) {
|
|
11635
|
+
result += char;
|
|
11636
|
+
if (escaped) {
|
|
11637
|
+
escaped = false;
|
|
11638
|
+
} else if (char === "\\") {
|
|
11639
|
+
escaped = true;
|
|
11640
|
+
} else if (char === '"') {
|
|
11641
|
+
inString = false;
|
|
11642
|
+
}
|
|
11643
|
+
continue;
|
|
11644
|
+
}
|
|
11645
|
+
if (char === '"') {
|
|
11646
|
+
inString = true;
|
|
11647
|
+
result += char;
|
|
11648
|
+
continue;
|
|
11649
|
+
}
|
|
11650
|
+
if (char === ",") {
|
|
11651
|
+
let lookahead = index + 1;
|
|
11652
|
+
while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
|
|
11653
|
+
lookahead += 1;
|
|
11654
|
+
}
|
|
11655
|
+
const next = content[lookahead];
|
|
11656
|
+
if (next === "}" || next === "]") {
|
|
11657
|
+
continue;
|
|
11658
|
+
}
|
|
11659
|
+
}
|
|
11660
|
+
result += char;
|
|
11661
|
+
}
|
|
11662
|
+
return result;
|
|
11663
|
+
}
|
|
11664
|
+
function isPrototypePollutionKey(key) {
|
|
11665
|
+
return PROTOTYPE_POLLUTION_KEYS.has(key);
|
|
11666
|
+
}
|
|
11667
|
+
function sanitizeParsedJson(value, options = {}, path2 = []) {
|
|
11668
|
+
if (Array.isArray(value)) {
|
|
11669
|
+
return value.map((entry, index) => sanitizeParsedJson(entry, options, [...path2, index]));
|
|
11670
|
+
}
|
|
11671
|
+
if (value === null || typeof value !== "object")
|
|
11672
|
+
return value;
|
|
11673
|
+
const source = value;
|
|
11674
|
+
const sourcePrototype = Object.getPrototypeOf(source);
|
|
11675
|
+
if (sourcePrototype !== null && sourcePrototype !== Object.prototype) {
|
|
11676
|
+
options.onRejectedKey?.([...path2, "__proto__"]);
|
|
11677
|
+
}
|
|
11678
|
+
const sanitized = {};
|
|
11679
|
+
for (const key of Object.keys(source)) {
|
|
11680
|
+
if (isPrototypePollutionKey(key)) {
|
|
11681
|
+
options.onRejectedKey?.([...path2, key]);
|
|
11682
|
+
continue;
|
|
11683
|
+
}
|
|
11684
|
+
Object.defineProperty(sanitized, key, {
|
|
11685
|
+
value: sanitizeParsedJson(source[key], options, [...path2, key]),
|
|
11686
|
+
enumerable: true,
|
|
11687
|
+
configurable: true,
|
|
11688
|
+
writable: true
|
|
11689
|
+
});
|
|
11690
|
+
}
|
|
11691
|
+
return sanitized;
|
|
11692
|
+
}
|
|
11693
|
+
function parseJsonc2(content, options = {}) {
|
|
11694
|
+
const normalized = stripTrailingCommas(stripJsonComments(content));
|
|
11695
|
+
return sanitizeParsedJson(JSON.parse(normalized), options);
|
|
11696
|
+
}
|
|
11697
|
+
function readJsoncFile(filePath) {
|
|
11698
|
+
try {
|
|
11699
|
+
return parseJsonc2(readFileSync6(filePath, "utf-8"));
|
|
11700
|
+
} catch (_error) {
|
|
11701
|
+
return null;
|
|
11702
|
+
}
|
|
11703
|
+
}
|
|
11704
|
+
function detectConfigFile(basePath) {
|
|
11705
|
+
const jsoncPath = `${basePath}.jsonc`;
|
|
11706
|
+
const jsonPath = `${basePath}.json`;
|
|
11707
|
+
if (existsSync9(jsoncPath)) {
|
|
11708
|
+
return { format: "jsonc", path: jsoncPath };
|
|
11709
|
+
}
|
|
11710
|
+
if (existsSync9(jsonPath)) {
|
|
11711
|
+
return { format: "json", path: jsonPath };
|
|
11712
|
+
}
|
|
11713
|
+
return { format: "none", path: jsoncPath };
|
|
11714
|
+
}
|
|
11715
|
+
var PROTOTYPE_POLLUTION_KEYS;
|
|
11716
|
+
var init_jsonc_parser = __esm(() => {
|
|
11717
|
+
PROTOTYPE_POLLUTION_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
11718
|
+
});
|
|
11719
|
+
|
|
11720
|
+
// src/lib/jsonc-config.ts
|
|
11721
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "node:fs";
|
|
11574
11722
|
function parseErrorLocation(content, error) {
|
|
11575
11723
|
const lines = content.split(`
|
|
11576
11724
|
`);
|
|
@@ -11586,11 +11734,17 @@ function parseErrorLocation(content, error) {
|
|
|
11586
11734
|
return { line: messageLine ? Number.parseInt(messageLine, 10) : 1, column: 1 };
|
|
11587
11735
|
}
|
|
11588
11736
|
function readJsoncConfig(path2) {
|
|
11589
|
-
if (!
|
|
11737
|
+
if (!existsSync10(path2))
|
|
11590
11738
|
return { kind: "missing" };
|
|
11591
|
-
const content =
|
|
11739
|
+
const content = readFileSync7(path2, "utf-8");
|
|
11592
11740
|
try {
|
|
11593
|
-
const
|
|
11741
|
+
const rejectedKeyPaths = [];
|
|
11742
|
+
const parsed = sanitizeParsedJson(import_comment_json2.parse(content), {
|
|
11743
|
+
onRejectedKey: (keyPath) => rejectedKeyPaths.push(keyPath.join("."))
|
|
11744
|
+
});
|
|
11745
|
+
if (rejectedKeyPaths.length > 0) {
|
|
11746
|
+
throw new Error(`unsafe prototype-pollution key at ${rejectedKeyPaths.join(", ")}`);
|
|
11747
|
+
}
|
|
11594
11748
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
11595
11749
|
throw new Error("expected a JSON object at the document root");
|
|
11596
11750
|
}
|
|
@@ -11616,6 +11770,7 @@ function assertJsoncConfigsParseable(paths) {
|
|
|
11616
11770
|
}
|
|
11617
11771
|
var import_comment_json2, ConfigParseError;
|
|
11618
11772
|
var init_jsonc_config = __esm(() => {
|
|
11773
|
+
init_jsonc_parser();
|
|
11619
11774
|
import_comment_json2 = __toESM(require_src3(), 1);
|
|
11620
11775
|
ConfigParseError = class ConfigParseError extends Error {
|
|
11621
11776
|
path;
|
|
@@ -11698,7 +11853,7 @@ function describePiPackageEntry(entry) {
|
|
|
11698
11853
|
var PI_MAGIC_CONTEXT_PACKAGE_NAME = "@cortexkit/pi-magic-context";
|
|
11699
11854
|
|
|
11700
11855
|
// src/adapters/pi.ts
|
|
11701
|
-
import { existsSync as
|
|
11856
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
11702
11857
|
import { dirname as dirname5 } from "node:path";
|
|
11703
11858
|
|
|
11704
11859
|
class PiAdapter {
|
|
@@ -11835,7 +11990,7 @@ function writePiSettings(settings2) {
|
|
|
11835
11990
|
}
|
|
11836
11991
|
function ensureDir2(filePath) {
|
|
11837
11992
|
const dir = dirname5(filePath);
|
|
11838
|
-
if (!
|
|
11993
|
+
if (!existsSync11(dir)) {
|
|
11839
11994
|
const { mkdirSync: mkdirSync4 } = __require("node:fs");
|
|
11840
11995
|
mkdirSync4(dir, { recursive: true });
|
|
11841
11996
|
}
|
|
@@ -12248,10 +12403,10 @@ var init_dreamer_setup = __esm(() => {
|
|
|
12248
12403
|
});
|
|
12249
12404
|
|
|
12250
12405
|
// src/commands/setup-pi.ts
|
|
12251
|
-
import { existsSync as
|
|
12406
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync4 } from "node:fs";
|
|
12252
12407
|
import { dirname as dirname6 } from "node:path";
|
|
12253
12408
|
function ensureDir3(path2) {
|
|
12254
|
-
if (!
|
|
12409
|
+
if (!existsSync12(path2))
|
|
12255
12410
|
mkdirSync4(path2, { recursive: true });
|
|
12256
12411
|
}
|
|
12257
12412
|
async function getDefaultPrompts() {
|
|
@@ -12689,122 +12844,6 @@ Edit those files directly, then rerun setup.`);
|
|
|
12689
12844
|
};
|
|
12690
12845
|
});
|
|
12691
12846
|
|
|
12692
|
-
// ../plugin/src/shared/jsonc-parser.ts
|
|
12693
|
-
import { existsSync as existsSync12, readFileSync as readFileSync7 } from "node:fs";
|
|
12694
|
-
function stripJsonComments(content) {
|
|
12695
|
-
let result = "";
|
|
12696
|
-
let inString = false;
|
|
12697
|
-
let escaped = false;
|
|
12698
|
-
let inLineComment = false;
|
|
12699
|
-
let inBlockComment = false;
|
|
12700
|
-
for (let index = 0;index < content.length; index += 1) {
|
|
12701
|
-
const char = content[index];
|
|
12702
|
-
const next = content[index + 1];
|
|
12703
|
-
if (inLineComment) {
|
|
12704
|
-
if (char === `
|
|
12705
|
-
`) {
|
|
12706
|
-
inLineComment = false;
|
|
12707
|
-
result += char;
|
|
12708
|
-
}
|
|
12709
|
-
continue;
|
|
12710
|
-
}
|
|
12711
|
-
if (inBlockComment) {
|
|
12712
|
-
if (char === "*" && next === "/") {
|
|
12713
|
-
inBlockComment = false;
|
|
12714
|
-
index += 1;
|
|
12715
|
-
}
|
|
12716
|
-
continue;
|
|
12717
|
-
}
|
|
12718
|
-
if (inString) {
|
|
12719
|
-
result += char;
|
|
12720
|
-
if (escaped) {
|
|
12721
|
-
escaped = false;
|
|
12722
|
-
} else if (char === "\\") {
|
|
12723
|
-
escaped = true;
|
|
12724
|
-
} else if (char === '"') {
|
|
12725
|
-
inString = false;
|
|
12726
|
-
}
|
|
12727
|
-
continue;
|
|
12728
|
-
}
|
|
12729
|
-
if (char === '"') {
|
|
12730
|
-
inString = true;
|
|
12731
|
-
result += char;
|
|
12732
|
-
continue;
|
|
12733
|
-
}
|
|
12734
|
-
if (char === "/" && next === "/") {
|
|
12735
|
-
inLineComment = true;
|
|
12736
|
-
index += 1;
|
|
12737
|
-
continue;
|
|
12738
|
-
}
|
|
12739
|
-
if (char === "/" && next === "*") {
|
|
12740
|
-
inBlockComment = true;
|
|
12741
|
-
index += 1;
|
|
12742
|
-
continue;
|
|
12743
|
-
}
|
|
12744
|
-
result += char;
|
|
12745
|
-
}
|
|
12746
|
-
return result;
|
|
12747
|
-
}
|
|
12748
|
-
function stripTrailingCommas(content) {
|
|
12749
|
-
let result = "";
|
|
12750
|
-
let inString = false;
|
|
12751
|
-
let escaped = false;
|
|
12752
|
-
for (let index = 0;index < content.length; index += 1) {
|
|
12753
|
-
const char = content[index];
|
|
12754
|
-
if (inString) {
|
|
12755
|
-
result += char;
|
|
12756
|
-
if (escaped) {
|
|
12757
|
-
escaped = false;
|
|
12758
|
-
} else if (char === "\\") {
|
|
12759
|
-
escaped = true;
|
|
12760
|
-
} else if (char === '"') {
|
|
12761
|
-
inString = false;
|
|
12762
|
-
}
|
|
12763
|
-
continue;
|
|
12764
|
-
}
|
|
12765
|
-
if (char === '"') {
|
|
12766
|
-
inString = true;
|
|
12767
|
-
result += char;
|
|
12768
|
-
continue;
|
|
12769
|
-
}
|
|
12770
|
-
if (char === ",") {
|
|
12771
|
-
let lookahead = index + 1;
|
|
12772
|
-
while (lookahead < content.length && /\s/.test(content[lookahead] ?? "")) {
|
|
12773
|
-
lookahead += 1;
|
|
12774
|
-
}
|
|
12775
|
-
const next = content[lookahead];
|
|
12776
|
-
if (next === "}" || next === "]") {
|
|
12777
|
-
continue;
|
|
12778
|
-
}
|
|
12779
|
-
}
|
|
12780
|
-
result += char;
|
|
12781
|
-
}
|
|
12782
|
-
return result;
|
|
12783
|
-
}
|
|
12784
|
-
function parseJsonc3(content) {
|
|
12785
|
-
const normalized = stripTrailingCommas(stripJsonComments(content));
|
|
12786
|
-
return JSON.parse(normalized);
|
|
12787
|
-
}
|
|
12788
|
-
function readJsoncFile(filePath) {
|
|
12789
|
-
try {
|
|
12790
|
-
return parseJsonc3(readFileSync7(filePath, "utf-8"));
|
|
12791
|
-
} catch (_error) {
|
|
12792
|
-
return null;
|
|
12793
|
-
}
|
|
12794
|
-
}
|
|
12795
|
-
function detectConfigFile(basePath) {
|
|
12796
|
-
const jsoncPath = `${basePath}.jsonc`;
|
|
12797
|
-
const jsonPath = `${basePath}.json`;
|
|
12798
|
-
if (existsSync12(jsoncPath)) {
|
|
12799
|
-
return { format: "jsonc", path: jsoncPath };
|
|
12800
|
-
}
|
|
12801
|
-
if (existsSync12(jsonPath)) {
|
|
12802
|
-
return { format: "json", path: jsonPath };
|
|
12803
|
-
}
|
|
12804
|
-
return { format: "none", path: jsoncPath };
|
|
12805
|
-
}
|
|
12806
|
-
var init_jsonc_parser = () => {};
|
|
12807
|
-
|
|
12808
12847
|
// ../plugin/src/shared/logger.ts
|
|
12809
12848
|
import * as fs from "node:fs";
|
|
12810
12849
|
import * as path2 from "node:path";
|
|
@@ -27899,7 +27938,9 @@ function isValidPromptSurfaceModelKey(key) {
|
|
|
27899
27938
|
if (key.length === 0 || key.trim() !== key)
|
|
27900
27939
|
return false;
|
|
27901
27940
|
const slash = key.indexOf("/");
|
|
27902
|
-
if (slash
|
|
27941
|
+
if (slash < 0)
|
|
27942
|
+
return !key.includes("*");
|
|
27943
|
+
if (slash === 0 || slash === key.length - 1)
|
|
27903
27944
|
return false;
|
|
27904
27945
|
const provider = key.slice(0, slash);
|
|
27905
27946
|
const modelID = key.slice(slash + 1);
|
|
@@ -27971,14 +28012,14 @@ var init_magic_context = __esm(() => {
|
|
|
27971
28012
|
}).optional();
|
|
27972
28013
|
PromptSurfacePresetSchema = exports_external.enum(["full", "light"]);
|
|
27973
28014
|
PromptSurfaceModelKeySchema = exports_external.string().refine(isValidPromptSurfaceModelKey, {
|
|
27974
|
-
message: "Use a non-empty provider/model key or the literal provider/* wildcard; model IDs may contain additional slashes and matching is case-sensitive."
|
|
28015
|
+
message: "Use a non-empty bare model key, provider/model key, or the literal provider/* wildcard; model IDs may contain additional slashes and matching is case-sensitive."
|
|
27975
28016
|
});
|
|
27976
28017
|
PromptSurfaceToolKeySchema = exports_external.string().refine((value) => value.trim().length > 0, {
|
|
27977
28018
|
message: "tool description keys must not be empty or whitespace-only"
|
|
27978
28019
|
});
|
|
27979
28020
|
PromptSurfaceConfigSchema = exports_external.object({
|
|
27980
28021
|
default: PromptSurfacePresetSchema.default("full").describe('Fallback prompt-surface preset ("full" or "light").'),
|
|
27981
|
-
models: exports_external.record(PromptSurfaceModelKeySchema, PromptSurfacePresetSchema).optional().describe("Literal per-model routing. Keys are provider/model or provider/*; matching is case-sensitive and preserves additional slashes in model IDs."),
|
|
28022
|
+
models: exports_external.record(PromptSurfaceModelKeySchema, PromptSurfacePresetSchema).optional().describe("Literal per-model routing. Keys are bare model IDs, provider/model, or provider/*; matching is case-sensitive and preserves additional slashes in model IDs."),
|
|
27982
28023
|
guidance_override_path: exports_external.string().refine((value) => value.trim().length > 0, {
|
|
27983
28024
|
message: "guidance_override_path must not be empty or whitespace-only"
|
|
27984
28025
|
}).optional().describe("USER-LEVEL ONLY path to a complete primary guidance section. Relative paths resolve from the user config file."),
|
|
@@ -28155,7 +28196,7 @@ var init_magic_context = __esm(() => {
|
|
|
28155
28196
|
retina_handoff: exports_external.boolean().default(false).describe("When true, dreamer skips smart notes whose surface conditions compiled to retina provider configs at authoring time. Default false keeps both paths active until the retina consumer is deployed.")
|
|
28156
28197
|
}).default({ retina_handoff: false }).describe("Smart-note ownership transition controls."),
|
|
28157
28198
|
cache_ttl: exports_external.union([exports_external.string(), exports_external.object({ default: exports_external.string() }).catchall(exports_external.string())]).default("5m").describe('Cache TTL: string (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "model-id": "10m" }). Set to "never" for lanes kept warm by an external keepwarm proxy — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time.'),
|
|
28158
|
-
prompt_surface: PromptSurfaceConfigSchema.default({ default: "full" }).describe("Prompt-surface presets: default is full; models use
|
|
28199
|
+
prompt_surface: PromptSurfaceConfigSchema.default({ default: "full" }).describe("Prompt-surface presets: default is full; models use bare model IDs, provider/model, or provider/* routing keys. Guidance and tool-description overrides are user-level only. On OpenCode and Pi, per-model routing applies to the guidance block only: tool descriptions are registered once per process, so they follow the default preset (a v1 plugin-surface limitation; per-model tool descriptions are planned for the OpenCode v2 plugin API once the SDK stabilizes)."),
|
|
28159
28200
|
output_reserve: exports_external.union([
|
|
28160
28201
|
exports_external.number().min(0),
|
|
28161
28202
|
exports_external.object({ default: exports_external.number().min(0) }).catchall(exports_external.number().min(0))
|
|
@@ -28780,10 +28821,15 @@ function loadConfigFileDetailed(configPath, source) {
|
|
|
28780
28821
|
configPath,
|
|
28781
28822
|
isProjectConfig: source === "project"
|
|
28782
28823
|
});
|
|
28824
|
+
const rejectedKeyPaths = [];
|
|
28825
|
+
const config2 = parseJsonc2(substituted.text, {
|
|
28826
|
+
onRejectedKey: (path3) => rejectedKeyPaths.push(path3.join("."))
|
|
28827
|
+
});
|
|
28828
|
+
const unsafeKeyWarnings = rejectedKeyPaths.map((path3) => `Ignored unsafe config key "${path3}" (security: prototype-pollution keys are not allowed).`);
|
|
28783
28829
|
return {
|
|
28784
|
-
config:
|
|
28785
|
-
warnings: substituted.warnings.map((
|
|
28786
|
-
outcome: substituted.warnings.length > 0 ? "substitution-failure" : "ok",
|
|
28830
|
+
config: config2,
|
|
28831
|
+
warnings: [...substituted.warnings, ...unsafeKeyWarnings].map((warning) => `${configPath}: ${warning}`),
|
|
28832
|
+
outcome: rejectedKeyPaths.length > 0 ? "schema-recovery" : substituted.warnings.length > 0 ? "substitution-failure" : "ok",
|
|
28787
28833
|
source
|
|
28788
28834
|
};
|
|
28789
28835
|
} catch (error51) {
|
|
@@ -28797,18 +28843,35 @@ function loadConfigFileDetailed(configPath, source) {
|
|
|
28797
28843
|
};
|
|
28798
28844
|
}
|
|
28799
28845
|
}
|
|
28846
|
+
function defineOwnConfigValue(target, key, value) {
|
|
28847
|
+
Object.defineProperty(target, key, {
|
|
28848
|
+
value,
|
|
28849
|
+
enumerable: true,
|
|
28850
|
+
configurable: true,
|
|
28851
|
+
writable: true
|
|
28852
|
+
});
|
|
28853
|
+
}
|
|
28800
28854
|
function deepMergeRawConfig(base, override) {
|
|
28801
|
-
const result = {
|
|
28855
|
+
const result = {};
|
|
28856
|
+
for (const key of Object.keys(base)) {
|
|
28857
|
+
if (isPrototypePollutionKey(key))
|
|
28858
|
+
continue;
|
|
28859
|
+
defineOwnConfigValue(result, key, base[key]);
|
|
28860
|
+
}
|
|
28802
28861
|
for (const key of Object.keys(override)) {
|
|
28803
|
-
|
|
28862
|
+
if (isPrototypePollutionKey(key))
|
|
28863
|
+
continue;
|
|
28864
|
+
const baseVal = Object.hasOwn(base, key) ? base[key] : undefined;
|
|
28804
28865
|
const overrideVal = override[key];
|
|
28866
|
+
let mergedValue;
|
|
28805
28867
|
if (baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal) && overrideVal !== null && typeof overrideVal === "object" && !Array.isArray(overrideVal)) {
|
|
28806
|
-
|
|
28868
|
+
mergedValue = deepMergeRawConfig(baseVal, overrideVal);
|
|
28807
28869
|
} else if (key === "disabled_hooks" && Array.isArray(baseVal) && Array.isArray(overrideVal)) {
|
|
28808
|
-
|
|
28870
|
+
mergedValue = [...new Set([...baseVal, ...overrideVal])];
|
|
28809
28871
|
} else {
|
|
28810
|
-
|
|
28872
|
+
mergedValue = overrideVal;
|
|
28811
28873
|
}
|
|
28874
|
+
defineOwnConfigValue(result, key, mergedValue);
|
|
28812
28875
|
}
|
|
28813
28876
|
return result;
|
|
28814
28877
|
}
|
|
@@ -29313,30 +29376,242 @@ var init_conflict_detector = __esm(() => {
|
|
|
29313
29376
|
OMO_PACKAGE_NAMES = new Set(["oh-my-opencode", "oh-my-openagent"]);
|
|
29314
29377
|
});
|
|
29315
29378
|
|
|
29316
|
-
// ../plugin/src/shared/
|
|
29317
|
-
import {
|
|
29318
|
-
|
|
29319
|
-
|
|
29320
|
-
|
|
29321
|
-
|
|
29322
|
-
|
|
29323
|
-
|
|
29324
|
-
|
|
29325
|
-
|
|
29379
|
+
// ../plugin/src/shared/jsonc-edit.ts
|
|
29380
|
+
import {
|
|
29381
|
+
applyEdits,
|
|
29382
|
+
createScanner,
|
|
29383
|
+
findNodeAtLocation,
|
|
29384
|
+
getNodeValue,
|
|
29385
|
+
modify,
|
|
29386
|
+
parseTree
|
|
29387
|
+
} from "jsonc-parser";
|
|
29388
|
+
function parseDocument(text3) {
|
|
29389
|
+
const errors3 = [];
|
|
29390
|
+
const root = parseTree(text3, errors3, { allowTrailingComma: true });
|
|
29391
|
+
if (!root || errors3.length > 0) {
|
|
29392
|
+
throw new Error("Cannot edit invalid JSONC");
|
|
29393
|
+
}
|
|
29394
|
+
return root;
|
|
29395
|
+
}
|
|
29396
|
+
function findNode(text3, path3) {
|
|
29397
|
+
return findNodeAtLocation(parseDocument(text3), path3);
|
|
29398
|
+
}
|
|
29399
|
+
function findComma(text3, start, end) {
|
|
29400
|
+
const scanner = createScanner(text3, false);
|
|
29401
|
+
scanner.setPosition(start);
|
|
29402
|
+
for (;; ) {
|
|
29403
|
+
const kind = scanner.scan();
|
|
29404
|
+
const offset = scanner.getTokenOffset();
|
|
29405
|
+
if (kind === TOKEN_EOF || offset >= end)
|
|
29406
|
+
return;
|
|
29407
|
+
if (kind === TOKEN_COMMA) {
|
|
29408
|
+
return {
|
|
29409
|
+
offset,
|
|
29410
|
+
length: scanner.getTokenLength(),
|
|
29411
|
+
line: scanner.getTokenStartLine()
|
|
29412
|
+
};
|
|
29413
|
+
}
|
|
29414
|
+
}
|
|
29415
|
+
}
|
|
29416
|
+
function lineStart(text3, offset) {
|
|
29417
|
+
const previousNewline = text3.lastIndexOf(`
|
|
29418
|
+
`, offset - 1);
|
|
29419
|
+
return previousNewline === -1 ? 0 : previousNewline + 1;
|
|
29420
|
+
}
|
|
29421
|
+
function lineEnd(text3, offset) {
|
|
29422
|
+
const nextNewline = text3.indexOf(`
|
|
29423
|
+
`, offset);
|
|
29424
|
+
if (nextNewline === -1)
|
|
29425
|
+
return text3.length;
|
|
29426
|
+
return text3[nextNewline - 1] === "\r" ? nextNewline - 1 : nextNewline;
|
|
29427
|
+
}
|
|
29428
|
+
function inlineCommentEnd(text3, start, line, limit) {
|
|
29429
|
+
const scanner = createScanner(text3, false);
|
|
29430
|
+
scanner.setPosition(start);
|
|
29431
|
+
let end;
|
|
29432
|
+
for (;; ) {
|
|
29433
|
+
const kind = scanner.scan();
|
|
29434
|
+
const offset = scanner.getTokenOffset();
|
|
29435
|
+
if (kind === TOKEN_EOF || offset >= limit || scanner.getTokenStartLine() !== line) {
|
|
29436
|
+
return end;
|
|
29437
|
+
}
|
|
29438
|
+
if (kind === TOKEN_LINE_COMMENT || kind === TOKEN_BLOCK_COMMENT) {
|
|
29439
|
+
end = offset + scanner.getTokenLength();
|
|
29440
|
+
}
|
|
29441
|
+
}
|
|
29442
|
+
}
|
|
29443
|
+
function startAfterPrecedingInlineComments(text3, comma, entryOffset) {
|
|
29444
|
+
const commentEnd = inlineCommentEnd(text3, comma.offset + comma.length, comma.line, entryOffset);
|
|
29445
|
+
if (commentEnd === undefined)
|
|
29446
|
+
return comma.offset + comma.length;
|
|
29447
|
+
const nextNewline = text3.indexOf(`
|
|
29448
|
+
`, commentEnd);
|
|
29449
|
+
return nextNewline === -1 ? commentEnd : nextNewline + 1;
|
|
29450
|
+
}
|
|
29451
|
+
function endAfterFollowingInlineComments(text3, comma, nextEntryOffset) {
|
|
29452
|
+
const commentEnd = inlineCommentEnd(text3, comma.offset + comma.length, comma.line, nextEntryOffset);
|
|
29453
|
+
return commentEnd === undefined ? comma.offset + comma.length : lineEnd(text3, commentEnd);
|
|
29454
|
+
}
|
|
29455
|
+
function closingWhitespace(text3, entryEnd, closingBracket) {
|
|
29456
|
+
const trailing = text3.slice(entryEnd, closingBracket);
|
|
29457
|
+
const finalNewline = trailing.lastIndexOf(`
|
|
29458
|
+
`);
|
|
29459
|
+
if (finalNewline === -1)
|
|
29460
|
+
return "";
|
|
29461
|
+
const newlineStart = trailing[finalNewline - 1] === "\r" ? finalNewline - 1 : finalNewline;
|
|
29462
|
+
return trailing.slice(newlineStart);
|
|
29463
|
+
}
|
|
29464
|
+
function removeArrayEntry(text3, array2, index) {
|
|
29465
|
+
const entries = array2.children ?? [];
|
|
29466
|
+
const entry = entries[index];
|
|
29467
|
+
if (!entry)
|
|
29468
|
+
return text3;
|
|
29469
|
+
const closingBracket = array2.offset + array2.length - 1;
|
|
29470
|
+
if (entries.length === 1) {
|
|
29471
|
+
const start2 = array2.offset + 1;
|
|
29472
|
+
const replacement = closingWhitespace(text3, entry.offset + entry.length, closingBracket);
|
|
29473
|
+
return text3.slice(0, start2) + replacement + text3.slice(closingBracket);
|
|
29474
|
+
}
|
|
29475
|
+
if (index === entries.length - 1) {
|
|
29476
|
+
const previous = entries[index - 1];
|
|
29477
|
+
if (!previous)
|
|
29478
|
+
return text3;
|
|
29479
|
+
const comma = findComma(text3, previous.offset + previous.length, entry.offset);
|
|
29480
|
+
if (!comma)
|
|
29481
|
+
return text3;
|
|
29482
|
+
const replacement = closingWhitespace(text3, entry.offset + entry.length, closingBracket);
|
|
29483
|
+
return text3.slice(0, comma.offset) + replacement + text3.slice(closingBracket);
|
|
29484
|
+
}
|
|
29485
|
+
const next = entries[index + 1];
|
|
29486
|
+
if (!next)
|
|
29487
|
+
return text3;
|
|
29488
|
+
const followingComma = findComma(text3, entry.offset + entry.length, next.offset);
|
|
29489
|
+
if (!followingComma)
|
|
29490
|
+
return text3;
|
|
29491
|
+
const start = index === 0 ? array2.offset + 1 : (() => {
|
|
29492
|
+
const previous = entries[index - 1];
|
|
29493
|
+
if (!previous)
|
|
29494
|
+
return entry.offset;
|
|
29495
|
+
const precedingComma = findComma(text3, previous.offset + previous.length, entry.offset);
|
|
29496
|
+
return precedingComma ? startAfterPrecedingInlineComments(text3, precedingComma, entry.offset) : entry.offset;
|
|
29497
|
+
})();
|
|
29498
|
+
const end = endAfterFollowingInlineComments(text3, followingComma, next.offset);
|
|
29499
|
+
return text3.slice(0, start) + text3.slice(end);
|
|
29500
|
+
}
|
|
29501
|
+
function indentationAt(text3, offset) {
|
|
29502
|
+
const prefix = text3.slice(lineStart(text3, offset), offset);
|
|
29503
|
+
return /^[\t ]*$/.test(prefix) ? prefix : "";
|
|
29504
|
+
}
|
|
29505
|
+
function inferIndent(text3, array2) {
|
|
29506
|
+
const firstEntry = array2.children?.[0];
|
|
29507
|
+
if (firstEntry)
|
|
29508
|
+
return indentationAt(text3, firstEntry.offset);
|
|
29509
|
+
const closingBracket = array2.offset + array2.length - 1;
|
|
29510
|
+
const closingIndent = indentationAt(text3, closingBracket);
|
|
29511
|
+
return `${closingIndent}${closingIndent.includes("\t") ? "\t" : " "}`;
|
|
29512
|
+
}
|
|
29513
|
+
function appendArrayValue(text3, array2, value) {
|
|
29514
|
+
const entries = array2.children ?? [];
|
|
29515
|
+
const closingBracket = array2.offset + array2.length - 1;
|
|
29516
|
+
const serialized = JSON.stringify(value);
|
|
29517
|
+
if (entries.length === 0) {
|
|
29518
|
+
if (!text3.slice(array2.offset, closingBracket).includes(`
|
|
29519
|
+
`)) {
|
|
29520
|
+
return text3.slice(0, closingBracket) + serialized + text3.slice(closingBracket);
|
|
29521
|
+
}
|
|
29522
|
+
const indent = inferIndent(text3, array2);
|
|
29523
|
+
const closingLineStart2 = lineStart(text3, closingBracket);
|
|
29524
|
+
const eol2 = text3.includes(`\r
|
|
29525
|
+
`) ? `\r
|
|
29526
|
+
` : `
|
|
29527
|
+
`;
|
|
29528
|
+
return text3.slice(0, closingLineStart2) + indent + serialized + eol2 + text3.slice(closingLineStart2);
|
|
29529
|
+
}
|
|
29530
|
+
const lastEntry = entries.at(-1);
|
|
29531
|
+
if (!lastEntry)
|
|
29532
|
+
return text3;
|
|
29533
|
+
const trailingComma = findComma(text3, lastEntry.offset + lastEntry.length, closingBracket);
|
|
29534
|
+
const isMultiline = text3.slice(array2.offset, closingBracket).includes(`
|
|
29535
|
+
`);
|
|
29536
|
+
if (!isMultiline) {
|
|
29537
|
+
return text3.slice(0, lastEntry.offset + lastEntry.length) + `,${serialized}` + text3.slice(lastEntry.offset + lastEntry.length);
|
|
29538
|
+
}
|
|
29539
|
+
const closingLineStart = lineStart(text3, closingBracket);
|
|
29540
|
+
const eol = text3.includes(`\r
|
|
29541
|
+
`) ? `\r
|
|
29542
|
+
` : `
|
|
29543
|
+
`;
|
|
29544
|
+
const inserted = `${inferIndent(text3, array2)}${serialized}${trailingComma ? "," : ""}${eol}`;
|
|
29545
|
+
const withValue = text3.slice(0, closingLineStart) + inserted + text3.slice(closingLineStart);
|
|
29546
|
+
if (trailingComma)
|
|
29547
|
+
return withValue;
|
|
29548
|
+
return withValue.slice(0, lastEntry.offset + lastEntry.length) + "," + withValue.slice(lastEntry.offset + lastEntry.length);
|
|
29549
|
+
}
|
|
29550
|
+
function setJsoncValue(text3, path3, value) {
|
|
29551
|
+
const node = findNode(text3, path3);
|
|
29552
|
+
if (node) {
|
|
29553
|
+
if (Object.is(getNodeValue(node), value))
|
|
29554
|
+
return text3;
|
|
29555
|
+
const serialized = JSON.stringify(value);
|
|
29556
|
+
return text3.slice(0, node.offset) + serialized + text3.slice(node.offset + node.length);
|
|
29557
|
+
}
|
|
29558
|
+
return applyEdits(text3, modify(text3, path3, value, {}));
|
|
29559
|
+
}
|
|
29560
|
+
function removeJsoncArrayEntries(text3, path3, shouldRemove) {
|
|
29561
|
+
let nextText = text3;
|
|
29562
|
+
let removed = false;
|
|
29563
|
+
for (;; ) {
|
|
29564
|
+
const array2 = findNode(nextText, path3);
|
|
29565
|
+
if (array2?.type !== "array")
|
|
29566
|
+
return { text: nextText, removed };
|
|
29567
|
+
const index = (array2.children ?? []).findIndex((entry) => shouldRemove(getNodeValue(entry)));
|
|
29568
|
+
if (index === -1)
|
|
29569
|
+
return { text: nextText, removed };
|
|
29570
|
+
const updated = removeArrayEntry(nextText, array2, index);
|
|
29571
|
+
if (updated === nextText)
|
|
29572
|
+
return { text: nextText, removed };
|
|
29573
|
+
nextText = updated;
|
|
29574
|
+
removed = true;
|
|
29575
|
+
}
|
|
29576
|
+
}
|
|
29577
|
+
function appendJsoncArrayValues(text3, path3, values) {
|
|
29578
|
+
let nextText = text3;
|
|
29579
|
+
for (const value of values) {
|
|
29580
|
+
const array2 = findNode(nextText, path3);
|
|
29581
|
+
if (array2?.type !== "array") {
|
|
29582
|
+
return setJsoncValue(nextText, path3, values);
|
|
29583
|
+
}
|
|
29584
|
+
nextText = appendArrayValue(nextText, array2, value);
|
|
29585
|
+
}
|
|
29586
|
+
return nextText;
|
|
29587
|
+
}
|
|
29588
|
+
var TOKEN_COMMA = 5, TOKEN_LINE_COMMENT = 12, TOKEN_BLOCK_COMMENT = 13, TOKEN_EOF = 17;
|
|
29589
|
+
var init_jsonc_edit = () => {};
|
|
29590
|
+
|
|
29591
|
+
// ../plugin/src/shared/conflict-fixer.ts
|
|
29592
|
+
import { existsSync as existsSync15, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "node:fs";
|
|
29593
|
+
import { homedir as homedir11 } from "node:os";
|
|
29594
|
+
import { join as join12 } from "node:path";
|
|
29595
|
+
function isRecord(value) {
|
|
29596
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
29597
|
+
}
|
|
29598
|
+
function asStringArray(value) {
|
|
29599
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
29600
|
+
}
|
|
29326
29601
|
function readConfig(filePath) {
|
|
29327
29602
|
if (!existsSync15(filePath)) {
|
|
29328
29603
|
return null;
|
|
29329
29604
|
}
|
|
29330
29605
|
try {
|
|
29331
|
-
const
|
|
29332
|
-
|
|
29606
|
+
const text3 = readFileSync10(filePath, "utf-8");
|
|
29607
|
+
const parsed = import_comment_json5.parse(text3);
|
|
29608
|
+
return isRecord(parsed) ? { config: parsed, text: text3 } : null;
|
|
29333
29609
|
} catch {
|
|
29334
29610
|
return null;
|
|
29335
29611
|
}
|
|
29336
29612
|
}
|
|
29337
|
-
function writeConfig(filePath,
|
|
29338
|
-
writeFileSync4(filePath,
|
|
29339
|
-
`);
|
|
29613
|
+
function writeConfig(filePath, text3) {
|
|
29614
|
+
writeFileSync4(filePath, text3);
|
|
29340
29615
|
}
|
|
29341
29616
|
function resolveUserOpenCodeConfigPath() {
|
|
29342
29617
|
const paths = getOpenCodeConfigPaths({ binary: "opencode" });
|
|
@@ -29395,21 +29670,24 @@ function isUnifiedOmoPath(configPath) {
|
|
|
29395
29670
|
const basename2 = configPath.split("/").pop() ?? "";
|
|
29396
29671
|
return basename2 === "omo.jsonc" || basename2 === "omo.json";
|
|
29397
29672
|
}
|
|
29398
|
-
function
|
|
29399
|
-
|
|
29400
|
-
|
|
29401
|
-
|
|
29673
|
+
function disableCompactionFlags(text3, config2) {
|
|
29674
|
+
if (!isRecord(config2.compaction)) {
|
|
29675
|
+
return {
|
|
29676
|
+
text: setJsoncValue(text3, ["compaction"], { auto: false, prune: false }),
|
|
29677
|
+
changed: true
|
|
29678
|
+
};
|
|
29402
29679
|
}
|
|
29403
|
-
|
|
29404
|
-
|
|
29405
|
-
|
|
29406
|
-
|
|
29407
|
-
|
|
29408
|
-
|
|
29409
|
-
|
|
29410
|
-
|
|
29411
|
-
|
|
29412
|
-
|
|
29680
|
+
let updated = text3;
|
|
29681
|
+
let changed = false;
|
|
29682
|
+
if (config2.compaction.auto !== false) {
|
|
29683
|
+
updated = setJsoncValue(updated, ["compaction", "auto"], false);
|
|
29684
|
+
changed = true;
|
|
29685
|
+
}
|
|
29686
|
+
if (config2.compaction.prune !== false) {
|
|
29687
|
+
updated = setJsoncValue(updated, ["compaction", "prune"], false);
|
|
29688
|
+
changed = true;
|
|
29689
|
+
}
|
|
29690
|
+
return { text: updated, changed };
|
|
29413
29691
|
}
|
|
29414
29692
|
function fixConflicts(directory, conflicts, options) {
|
|
29415
29693
|
const compactionEnabled = options?.compactionEnabled ?? true;
|
|
@@ -29420,36 +29698,33 @@ function fixConflicts(directory, conflicts, options) {
|
|
|
29420
29698
|
const repairCompaction = compactionEnabled && (conflicts.compactionAuto || conflicts.compactionPrune);
|
|
29421
29699
|
if (repairCompaction || conflicts.dcpPlugin) {
|
|
29422
29700
|
for (const configPath of collectOpenCodeConfigPaths(directory)) {
|
|
29423
|
-
const
|
|
29424
|
-
if (!
|
|
29701
|
+
const document = readConfig(configPath);
|
|
29702
|
+
if (!document) {
|
|
29425
29703
|
continue;
|
|
29426
29704
|
}
|
|
29705
|
+
let text3 = document.text;
|
|
29427
29706
|
let changed = false;
|
|
29428
29707
|
if (repairCompaction) {
|
|
29429
|
-
const
|
|
29430
|
-
if (
|
|
29431
|
-
|
|
29432
|
-
changed = true;
|
|
29433
|
-
updatedCompaction = true;
|
|
29434
|
-
}
|
|
29435
|
-
if (compaction.prune !== false) {
|
|
29436
|
-
compaction.prune = false;
|
|
29708
|
+
const result = disableCompactionFlags(text3, document.config);
|
|
29709
|
+
if (result.changed) {
|
|
29710
|
+
text3 = result.text;
|
|
29437
29711
|
changed = true;
|
|
29438
29712
|
updatedCompaction = true;
|
|
29439
29713
|
}
|
|
29440
|
-
config2.compaction = compaction;
|
|
29441
29714
|
}
|
|
29442
29715
|
if (conflicts.dcpPlugin) {
|
|
29443
|
-
const
|
|
29444
|
-
|
|
29445
|
-
|
|
29446
|
-
|
|
29716
|
+
const result = removeJsoncArrayEntries(text3, ["plugin"], (entry) => {
|
|
29717
|
+
const name = extractPluginName(entry);
|
|
29718
|
+
return name ? matchesPackageName(name, DCP_PACKAGE_NAMES) : false;
|
|
29719
|
+
});
|
|
29720
|
+
if (result.removed) {
|
|
29721
|
+
text3 = result.text;
|
|
29447
29722
|
changed = true;
|
|
29448
29723
|
removedDcpPlugin = true;
|
|
29449
29724
|
}
|
|
29450
29725
|
}
|
|
29451
29726
|
if (changed) {
|
|
29452
|
-
writeConfig(configPath,
|
|
29727
|
+
writeConfig(configPath, text3);
|
|
29453
29728
|
}
|
|
29454
29729
|
}
|
|
29455
29730
|
}
|
|
@@ -29465,26 +29740,19 @@ function fixConflicts(directory, conflicts, options) {
|
|
|
29465
29740
|
hooksToDisable.add("anthropic-context-window-limit-recovery");
|
|
29466
29741
|
}
|
|
29467
29742
|
for (const configPath of collectOmoConfigPaths(directory)) {
|
|
29468
|
-
const
|
|
29469
|
-
if (!
|
|
29743
|
+
const document = readConfig(configPath);
|
|
29744
|
+
if (!document) {
|
|
29470
29745
|
continue;
|
|
29471
29746
|
}
|
|
29472
|
-
const
|
|
29747
|
+
const unifiedPath = isUnifiedOmoPath(configPath);
|
|
29748
|
+
const target = unifiedPath && isRecord(document.config["[opencode]"]) ? document.config["[opencode]"] : unifiedPath ? {} : document.config;
|
|
29473
29749
|
const disabledHooks = new Set(asStringArray(target.disabled_hooks));
|
|
29474
|
-
|
|
29475
|
-
|
|
29476
|
-
|
|
29477
|
-
|
|
29478
|
-
|
|
29479
|
-
|
|
29480
|
-
}
|
|
29481
|
-
}
|
|
29482
|
-
if (changed) {
|
|
29483
|
-
target.disabled_hooks = [
|
|
29484
|
-
...CONFLICTING_OMO_HOOKS.filter((hook) => disabledHooks.has(hook)),
|
|
29485
|
-
...[...disabledHooks].filter((hook) => !CONFLICTING_OMO_HOOKS.includes(hook))
|
|
29486
|
-
];
|
|
29487
|
-
writeConfig(configPath, config2);
|
|
29750
|
+
const hooksToAdd = CONFLICTING_OMO_HOOKS.filter((hook) => hooksToDisable.has(hook) && !disabledHooks.has(hook));
|
|
29751
|
+
if (hooksToAdd.length > 0) {
|
|
29752
|
+
const path3 = unifiedPath ? ["[opencode]", "disabled_hooks"] : ["disabled_hooks"];
|
|
29753
|
+
const text3 = Array.isArray(target.disabled_hooks) ? appendJsoncArrayValues(document.text, path3, hooksToAdd) : setJsoncValue(document.text, path3, hooksToAdd);
|
|
29754
|
+
writeConfig(configPath, text3);
|
|
29755
|
+
disabledOmoHooks = true;
|
|
29488
29756
|
}
|
|
29489
29757
|
}
|
|
29490
29758
|
}
|
|
@@ -29502,6 +29770,7 @@ function fixConflicts(directory, conflicts, options) {
|
|
|
29502
29770
|
var import_comment_json5, CONFLICTING_OMO_HOOKS, OMO_CONFIG_NAMES, OMO_UNIFIED_NAMES;
|
|
29503
29771
|
var init_conflict_fixer = __esm(() => {
|
|
29504
29772
|
init_conflict_detector();
|
|
29773
|
+
init_jsonc_edit();
|
|
29505
29774
|
init_opencode_config_dir();
|
|
29506
29775
|
import_comment_json5 = __toESM(require_src3(), 1);
|
|
29507
29776
|
CONFLICTING_OMO_HOOKS = [
|
|
@@ -29572,7 +29841,7 @@ var OPENCODE_BINARY_ENV = "MAGIC_CONTEXT_OPENCODE_BINARY", OPENCODE_VERSION_PROB
|
|
|
29572
29841
|
var init_opencode_helpers = () => {};
|
|
29573
29842
|
|
|
29574
29843
|
// src/commands/setup-opencode.ts
|
|
29575
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync6 } from "node:fs";
|
|
29844
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync6, readFileSync as readFileSync11 } from "node:fs";
|
|
29576
29845
|
import { basename as basename2, dirname as dirname9 } from "node:path";
|
|
29577
29846
|
function resolveCompactionEnabledForWriter() {
|
|
29578
29847
|
try {
|
|
@@ -29591,47 +29860,81 @@ function ensureDir5(dir) {
|
|
|
29591
29860
|
function addPluginToOpenCodeConfig(configPath, _format, removeDcp = false, compactionEnabled = true) {
|
|
29592
29861
|
const existsAtCommit = existsSync16(configPath);
|
|
29593
29862
|
const existing = existsAtCommit ? readJsoncConfigForUpdate(configPath) : {};
|
|
29594
|
-
if (!existsAtCommit)
|
|
29863
|
+
if (!existsAtCommit) {
|
|
29595
29864
|
ensureDir5(dirname9(configPath));
|
|
29596
|
-
|
|
29597
|
-
|
|
29598
|
-
|
|
29865
|
+
const created = { plugin: [OPENCODE_PLUGIN_ENTRY_WITH_VERSION] };
|
|
29866
|
+
if (compactionEnabled) {
|
|
29867
|
+
created.compaction = { auto: false, prune: false };
|
|
29868
|
+
}
|
|
29869
|
+
writeFileAtomic(configPath, `${import_comment_json6.stringify(created, null, 2)}
|
|
29870
|
+
`);
|
|
29871
|
+
return;
|
|
29599
29872
|
}
|
|
29600
|
-
|
|
29601
|
-
|
|
29602
|
-
|
|
29873
|
+
let text3 = readFileSync11(configPath, "utf-8");
|
|
29874
|
+
let changed = false;
|
|
29875
|
+
const rawPlugins = Array.isArray(existing.plugin) ? existing.plugin : [];
|
|
29876
|
+
const retainedPlugins = removeDcp ? rawPlugins.filter((plugin) => !matchesPluginEntry(plugin, DCP_PLUGIN_NAME)) : rawPlugins;
|
|
29877
|
+
if (retainedPlugins.some((plugin) => isLocalPathPluginEntry(plugin) && String(plugin).includes("magic-context") && !isDevPathPluginEntry(plugin))) {
|
|
29603
29878
|
log2.warn("An unverifiable local OpenCode plugin path was ignored; its package name is not Magic Context.");
|
|
29604
29879
|
}
|
|
29605
|
-
if (
|
|
29606
|
-
|
|
29880
|
+
if (Array.isArray(existing.plugin)) {
|
|
29881
|
+
if (removeDcp) {
|
|
29882
|
+
const result = removeJsoncArrayEntries(text3, ["plugin"], (plugin) => matchesPluginEntry(plugin, DCP_PLUGIN_NAME));
|
|
29883
|
+
if (result.removed) {
|
|
29884
|
+
text3 = result.text;
|
|
29885
|
+
changed = true;
|
|
29886
|
+
}
|
|
29887
|
+
}
|
|
29888
|
+
const hasNpmEntry = retainedPlugins.some((plugin) => matchesPluginEntry(plugin, OPENCODE_PLUGIN_NAME));
|
|
29889
|
+
const hasDevEntry = retainedPlugins.some((plugin) => isDevPathPluginEntry(plugin));
|
|
29890
|
+
if (!hasNpmEntry && !hasDevEntry) {
|
|
29891
|
+
text3 = appendJsoncArrayValues(text3, ["plugin"], [OPENCODE_PLUGIN_ENTRY_WITH_VERSION]);
|
|
29892
|
+
changed = true;
|
|
29893
|
+
}
|
|
29894
|
+
} else {
|
|
29895
|
+
text3 = setJsoncValue(text3, ["plugin"], [OPENCODE_PLUGIN_ENTRY_WITH_VERSION]);
|
|
29896
|
+
changed = true;
|
|
29607
29897
|
}
|
|
29608
|
-
existing.plugin = rawPlugins;
|
|
29609
29898
|
if (compactionEnabled) {
|
|
29610
|
-
const compaction = existing.compaction
|
|
29611
|
-
|
|
29612
|
-
|
|
29613
|
-
|
|
29899
|
+
const compaction = existing.compaction;
|
|
29900
|
+
const hasCompactionObject = typeof compaction === "object" && compaction !== null && !Array.isArray(compaction);
|
|
29901
|
+
if (!hasCompactionObject) {
|
|
29902
|
+
text3 = setJsoncValue(text3, ["compaction"], { auto: false, prune: false });
|
|
29903
|
+
changed = true;
|
|
29904
|
+
} else {
|
|
29905
|
+
const fields = compaction;
|
|
29906
|
+
if (fields.auto !== false) {
|
|
29907
|
+
text3 = setJsoncValue(text3, ["compaction", "auto"], false);
|
|
29908
|
+
changed = true;
|
|
29909
|
+
}
|
|
29910
|
+
if (fields.prune !== false) {
|
|
29911
|
+
text3 = setJsoncValue(text3, ["compaction", "prune"], false);
|
|
29912
|
+
changed = true;
|
|
29913
|
+
}
|
|
29914
|
+
}
|
|
29614
29915
|
}
|
|
29615
|
-
|
|
29616
|
-
|
|
29916
|
+
if (changed)
|
|
29917
|
+
writeFileAtomic(configPath, text3);
|
|
29617
29918
|
}
|
|
29618
29919
|
function addPluginToTuiConfig(configPath, _format) {
|
|
29619
29920
|
const existsAtCommit = existsSync16(configPath);
|
|
29620
29921
|
const existing = existsAtCommit ? readJsoncConfigForUpdate(configPath) : {};
|
|
29621
|
-
if (!existsAtCommit)
|
|
29922
|
+
if (!existsAtCommit) {
|
|
29622
29923
|
ensureDir5(dirname9(configPath));
|
|
29924
|
+
writeFileAtomic(configPath, `${import_comment_json6.stringify({ plugin: [OPENCODE_PLUGIN_ENTRY_WITH_VERSION] }, null, 2)}
|
|
29925
|
+
`);
|
|
29926
|
+
return;
|
|
29927
|
+
}
|
|
29623
29928
|
const rawPlugins = Array.isArray(existing.plugin) ? existing.plugin : [];
|
|
29624
|
-
|
|
29625
|
-
const hasDevEntry = rawPlugins.some((p2) => isDevPathPluginEntry(p2));
|
|
29626
|
-
if (rawPlugins.some((p2) => isLocalPathPluginEntry(p2) && String(p2).includes("magic-context") && !isDevPathPluginEntry(p2))) {
|
|
29929
|
+
if (rawPlugins.some((plugin) => isLocalPathPluginEntry(plugin) && String(plugin).includes("magic-context") && !isDevPathPluginEntry(plugin))) {
|
|
29627
29930
|
log2.warn("An unverifiable local TUI plugin path was ignored; its package name is not Magic Context.");
|
|
29628
29931
|
}
|
|
29629
|
-
|
|
29630
|
-
|
|
29631
|
-
|
|
29632
|
-
|
|
29633
|
-
|
|
29634
|
-
|
|
29932
|
+
const hasNpmEntry = rawPlugins.some((plugin) => matchesPluginEntry(plugin, OPENCODE_PLUGIN_NAME));
|
|
29933
|
+
const hasDevEntry = rawPlugins.some((plugin) => isDevPathPluginEntry(plugin));
|
|
29934
|
+
if (hasNpmEntry || hasDevEntry)
|
|
29935
|
+
return;
|
|
29936
|
+
const text3 = Array.isArray(existing.plugin) ? appendJsoncArrayValues(readFileSync11(configPath, "utf-8"), ["plugin"], [OPENCODE_PLUGIN_ENTRY_WITH_VERSION]) : setJsoncValue(readFileSync11(configPath, "utf-8"), ["plugin"], [OPENCODE_PLUGIN_ENTRY_WITH_VERSION]);
|
|
29937
|
+
writeFileAtomic(configPath, text3);
|
|
29635
29938
|
}
|
|
29636
29939
|
function findDcpPluginIndexes(plugins) {
|
|
29637
29940
|
return plugins.map((plugin, index) => matchesPluginEntry(plugin, DCP_PLUGIN_NAME) ? index : -1).filter((index) => index >= 0);
|
|
@@ -29920,6 +30223,7 @@ var init_setup_opencode = __esm(() => {
|
|
|
29920
30223
|
init_agent_disable();
|
|
29921
30224
|
init_conflict_detector();
|
|
29922
30225
|
init_conflict_fixer();
|
|
30226
|
+
init_jsonc_edit();
|
|
29923
30227
|
init_opencode();
|
|
29924
30228
|
init_atomic_write();
|
|
29925
30229
|
init_config_location_migration();
|
|
@@ -30412,7 +30716,8 @@ function prepareMirrorPageStatements(db) {
|
|
|
30412
30716
|
deleteNote: db.prepare("DELETE FROM notes WHERE id = ?"),
|
|
30413
30717
|
deleteNoteRevisions: db.prepare("DELETE FROM mirror_note_revisions WHERE module_project = ? AND module_row_id = ?"),
|
|
30414
30718
|
updateNote: db.prepare(`UPDATE notes SET type = ?, status = ?, project_path = ?, session_id = ?, content = ?,
|
|
30415
|
-
surface_condition = ?,
|
|
30719
|
+
surface_condition = ?, compiled_provider = ?, compiled_config = ?, compiled_at = ?, compile_status = ?,
|
|
30720
|
+
ready_at = ?, ready_reason = ?, manifest_json = ?, compiled_check = ?,
|
|
30416
30721
|
check_hash = ?, check_cron = ?, check_failure_count = ?, check_network_failure_count = ?,
|
|
30417
30722
|
check_quarantined_until = ?, check_next_due_at = ?, check_compiled_at = ?, check_false_since_at = ?,
|
|
30418
30723
|
check_last_liveness_at = ?, last_checked_at = ?, check_status = ?, check_version = ?,
|
|
@@ -30668,7 +30973,7 @@ function applyNoteRow(db, feed, statements) {
|
|
|
30668
30973
|
}
|
|
30669
30974
|
const moduleStatus = rowString(effectiveRow, "status", "active");
|
|
30670
30975
|
const contextStatus = moduleStatus === "surfaced" || moduleStatus === "surfacing" ? "ready" : moduleStatus;
|
|
30671
|
-
statements.updateNote.run(rowString(effectiveRow, "type", "smart"), contextStatus, moduleProject, rowNullableString(effectiveRow, "session_id"), rowString(effectiveRow, "content"), rowNullableString(effectiveRow, "surface_condition"), typeof effectiveRow.ready_at === "number" ? effectiveRow.ready_at : null, rowNullableString(effectiveRow, "ready_reason"), rowNullableString(effectiveRow, "manifest_json"), rowNullableString(effectiveRow, "compiled_check"), rowNullableString(effectiveRow, "check_hash"), rowNullableString(effectiveRow, "check_cron"), rowNumber(effectiveRow, "check_failure_count"), rowNumber(effectiveRow, "check_network_failure_count"), typeof effectiveRow.check_quarantined_until === "number" ? effectiveRow.check_quarantined_until : null, typeof effectiveRow.check_next_due_at === "number" ? effectiveRow.check_next_due_at : null, typeof effectiveRow.check_compiled_at === "number" ? effectiveRow.check_compiled_at : null, typeof effectiveRow.check_false_since_at === "number" ? effectiveRow.check_false_since_at : null, typeof effectiveRow.check_last_liveness_at === "number" ? effectiveRow.check_last_liveness_at : null, typeof effectiveRow.last_checked_at === "number" ? effectiveRow.last_checked_at : null, rowString(effectiveRow, "check_status", "uncompiled"), rowNumber(effectiveRow, "check_version"), rowNumber(effectiveRow, "policy_version", 1), rowNullableString(effectiveRow, "anchor_block_id"), typeof effectiveRow.anchor_ordinal === "number" ? effectiveRow.anchor_ordinal : null, rowNumber(effectiveRow, "created_at_ms"), rowNumber(effectiveRow, "updated_at_ms"), contextId);
|
|
30976
|
+
statements.updateNote.run(rowString(effectiveRow, "type", "smart"), contextStatus, moduleProject, rowNullableString(effectiveRow, "session_id"), rowString(effectiveRow, "content"), rowNullableString(effectiveRow, "surface_condition"), rowNullableString(effectiveRow, "compiled_provider"), rowNullableString(effectiveRow, "compiled_config"), typeof effectiveRow.compiled_at === "number" ? effectiveRow.compiled_at : null, rowNullableString(effectiveRow, "compile_status"), typeof effectiveRow.ready_at === "number" ? effectiveRow.ready_at : null, rowNullableString(effectiveRow, "ready_reason"), rowNullableString(effectiveRow, "manifest_json"), rowNullableString(effectiveRow, "compiled_check"), rowNullableString(effectiveRow, "check_hash"), rowNullableString(effectiveRow, "check_cron"), rowNumber(effectiveRow, "check_failure_count"), rowNumber(effectiveRow, "check_network_failure_count"), typeof effectiveRow.check_quarantined_until === "number" ? effectiveRow.check_quarantined_until : null, typeof effectiveRow.check_next_due_at === "number" ? effectiveRow.check_next_due_at : null, typeof effectiveRow.check_compiled_at === "number" ? effectiveRow.check_compiled_at : null, typeof effectiveRow.check_false_since_at === "number" ? effectiveRow.check_false_since_at : null, typeof effectiveRow.check_last_liveness_at === "number" ? effectiveRow.check_last_liveness_at : null, typeof effectiveRow.last_checked_at === "number" ? effectiveRow.last_checked_at : null, rowString(effectiveRow, "check_status", "uncompiled"), rowNumber(effectiveRow, "check_version"), rowNumber(effectiveRow, "policy_version", 1), rowNullableString(effectiveRow, "anchor_block_id"), typeof effectiveRow.anchor_ordinal === "number" ? effectiveRow.anchor_ordinal : null, rowNumber(effectiveRow, "created_at_ms"), rowNumber(effectiveRow, "updated_at_ms"), contextId);
|
|
30672
30977
|
statements.upsertNoteRevision.run(moduleProject, feed.module_row_id, contextId, rowNumber(effectiveRow, "status_version"));
|
|
30673
30978
|
}
|
|
30674
30979
|
function applyMirrorPage(args) {
|
|
@@ -33368,10 +33673,13 @@ class SubcModuleTransport {
|
|
|
33368
33673
|
routeSessionPrefix;
|
|
33369
33674
|
client = null;
|
|
33370
33675
|
routes = new Map;
|
|
33676
|
+
routeOpenings = new Map;
|
|
33371
33677
|
canonicalRootCache = new Map;
|
|
33372
|
-
|
|
33678
|
+
sessionLanes = new Map;
|
|
33679
|
+
queuedLaneWaiters = 0;
|
|
33680
|
+
wrapupSessions = new Map;
|
|
33373
33681
|
nextProbeMs = 0;
|
|
33374
|
-
|
|
33682
|
+
connectionPromise = null;
|
|
33375
33683
|
authorityProjectRoot = "";
|
|
33376
33684
|
authorityBindRoot = "";
|
|
33377
33685
|
backoffMs = CONNECT_BACKOFF_INITIAL_MS;
|
|
@@ -33417,6 +33725,11 @@ class SubcModuleTransport {
|
|
|
33417
33725
|
laneTimeoutError() {
|
|
33418
33726
|
return this.deadlineError("while queued");
|
|
33419
33727
|
}
|
|
33728
|
+
connectionChangedError(detail) {
|
|
33729
|
+
const error51 = new Error(detail);
|
|
33730
|
+
error51.code = "ECONNRESET";
|
|
33731
|
+
return error51;
|
|
33732
|
+
}
|
|
33420
33733
|
async beforeDeadline(operation, deadlineMs, detail) {
|
|
33421
33734
|
const remainingMs = deadlineMs - Date.now();
|
|
33422
33735
|
if (remainingMs <= 0)
|
|
@@ -33434,22 +33747,30 @@ class SubcModuleTransport {
|
|
|
33434
33747
|
clearTimeout(timer);
|
|
33435
33748
|
}
|
|
33436
33749
|
}
|
|
33437
|
-
|
|
33750
|
+
cleanupLane(sessionId, lane) {
|
|
33751
|
+
if (!lane.active && lane.waiters.length === 0 && this.sessionLanes.get(sessionId) === lane) {
|
|
33752
|
+
this.sessionLanes.delete(sessionId);
|
|
33753
|
+
}
|
|
33754
|
+
}
|
|
33755
|
+
laneRelease(sessionId, lane) {
|
|
33438
33756
|
let released = false;
|
|
33439
33757
|
return () => {
|
|
33440
33758
|
if (released)
|
|
33441
33759
|
return;
|
|
33442
33760
|
released = true;
|
|
33443
|
-
|
|
33444
|
-
this.dispatchNextLaneWaiter();
|
|
33761
|
+
lane.active = false;
|
|
33762
|
+
this.dispatchNextLaneWaiter(sessionId, lane);
|
|
33445
33763
|
};
|
|
33446
33764
|
}
|
|
33447
|
-
dispatchNextLaneWaiter() {
|
|
33448
|
-
if (
|
|
33765
|
+
dispatchNextLaneWaiter(sessionId, lane) {
|
|
33766
|
+
if (lane.active)
|
|
33449
33767
|
return;
|
|
33450
|
-
while (
|
|
33451
|
-
const waiter =
|
|
33452
|
-
if (!waiter
|
|
33768
|
+
while (lane.waiters.length > 0) {
|
|
33769
|
+
const waiter = lane.waiters.shift();
|
|
33770
|
+
if (!waiter)
|
|
33771
|
+
continue;
|
|
33772
|
+
this.queuedLaneWaiters = Math.max(0, this.queuedLaneWaiters - 1);
|
|
33773
|
+
if (waiter.settled)
|
|
33453
33774
|
continue;
|
|
33454
33775
|
waiter.settled = true;
|
|
33455
33776
|
clearTimeout(waiter.timer);
|
|
@@ -33462,10 +33783,16 @@ class SubcModuleTransport {
|
|
|
33462
33783
|
waiter.reject(this.laneTimeoutError());
|
|
33463
33784
|
continue;
|
|
33464
33785
|
}
|
|
33465
|
-
|
|
33466
|
-
waiter.resolve(this.laneRelease());
|
|
33786
|
+
lane.active = true;
|
|
33787
|
+
waiter.resolve(this.laneRelease(sessionId, lane));
|
|
33467
33788
|
return;
|
|
33468
33789
|
}
|
|
33790
|
+
this.cleanupLane(sessionId, lane);
|
|
33791
|
+
}
|
|
33792
|
+
queueFullError() {
|
|
33793
|
+
const error51 = new Error("module transport queue is full");
|
|
33794
|
+
error51.code = "EBUSY";
|
|
33795
|
+
return error51;
|
|
33469
33796
|
}
|
|
33470
33797
|
acquireCorrectnessLane(sessionId, signal, deadlineMs) {
|
|
33471
33798
|
if (signal?.aborted) {
|
|
@@ -33474,14 +33801,14 @@ class SubcModuleTransport {
|
|
|
33474
33801
|
if (deadlineMs - Date.now() < SERIAL_LANE_MIN_REMAINING_MS) {
|
|
33475
33802
|
return Promise.reject(this.laneTimeoutError());
|
|
33476
33803
|
}
|
|
33477
|
-
|
|
33478
|
-
|
|
33479
|
-
|
|
33804
|
+
const lane = this.sessionLanes.get(sessionId) ?? { active: false, waiters: [] };
|
|
33805
|
+
this.sessionLanes.set(sessionId, lane);
|
|
33806
|
+
if (!lane.active && lane.waiters.length === 0) {
|
|
33807
|
+
lane.active = true;
|
|
33808
|
+
return Promise.resolve(this.laneRelease(sessionId, lane));
|
|
33480
33809
|
}
|
|
33481
|
-
if (this.
|
|
33482
|
-
|
|
33483
|
-
error51.code = "EBUSY";
|
|
33484
|
-
return Promise.reject(error51);
|
|
33810
|
+
if (this.queuedLaneWaiters >= SERIAL_LANE_MAX_WAITERS || lane.waiters.length >= SERIAL_LANE_MAX_WAITERS_PER_SESSION) {
|
|
33811
|
+
return Promise.reject(this.queueFullError());
|
|
33485
33812
|
}
|
|
33486
33813
|
return new Promise((resolve5, reject) => {
|
|
33487
33814
|
const waiter = {};
|
|
@@ -33491,14 +33818,14 @@ class SubcModuleTransport {
|
|
|
33491
33818
|
waiter.settled = true;
|
|
33492
33819
|
clearTimeout(waiter.timer);
|
|
33493
33820
|
signal?.removeEventListener("abort", waiter.onAbort);
|
|
33494
|
-
const index =
|
|
33495
|
-
if (index >= 0)
|
|
33496
|
-
|
|
33821
|
+
const index = lane.waiters.indexOf(waiter);
|
|
33822
|
+
if (index >= 0) {
|
|
33823
|
+
lane.waiters.splice(index, 1);
|
|
33824
|
+
this.queuedLaneWaiters = Math.max(0, this.queuedLaneWaiters - 1);
|
|
33825
|
+
}
|
|
33497
33826
|
reject(error51);
|
|
33498
|
-
|
|
33499
|
-
this.dispatchNextLaneWaiter();
|
|
33827
|
+
this.cleanupLane(sessionId, lane);
|
|
33500
33828
|
};
|
|
33501
|
-
waiter.sessionId = sessionId;
|
|
33502
33829
|
waiter.signal = signal;
|
|
33503
33830
|
waiter.deadlineMs = deadlineMs;
|
|
33504
33831
|
waiter.resolve = resolve5;
|
|
@@ -33507,17 +33834,40 @@ class SubcModuleTransport {
|
|
|
33507
33834
|
waiter.onAbort = () => removeAndReject(signal?.reason ?? new Error("module transport call aborted"));
|
|
33508
33835
|
waiter.timer = setTimeout(() => removeAndReject(this.laneTimeoutError()), Math.max(0, deadlineMs - Date.now()));
|
|
33509
33836
|
signal?.addEventListener("abort", waiter.onAbort, { once: true });
|
|
33510
|
-
|
|
33837
|
+
lane.waiters.push(waiter);
|
|
33838
|
+
this.queuedLaneWaiters += 1;
|
|
33511
33839
|
});
|
|
33512
33840
|
}
|
|
33513
33841
|
async call(args) {
|
|
33514
|
-
const
|
|
33842
|
+
const wrapupInFlight = (this.wrapupSessions.get(args.sessionId) ?? 0) > 0;
|
|
33843
|
+
const attemptTimeoutMs = args.timeoutMs ?? (args.method === "session.wrapup" || args.method === "session.status" && wrapupInFlight ? MAX_WRAPUP_REQUEST_BUDGET_MS : args.method === "transform" ? Math.min(this.requestTimeoutMs, TRANSFORM_SEND_TIMEOUT_MS) : this.requestTimeoutMs);
|
|
33844
|
+
const tracksWrapup = args.method === "session.wrapup";
|
|
33845
|
+
if (tracksWrapup) {
|
|
33846
|
+
this.wrapupSessions.set(args.sessionId, (this.wrapupSessions.get(args.sessionId) ?? 0) + 1);
|
|
33847
|
+
}
|
|
33848
|
+
const finishWrapupTracking = () => {
|
|
33849
|
+
if (!tracksWrapup)
|
|
33850
|
+
return;
|
|
33851
|
+
const remaining = (this.wrapupSessions.get(args.sessionId) ?? 1) - 1;
|
|
33852
|
+
if (remaining > 0)
|
|
33853
|
+
this.wrapupSessions.set(args.sessionId, remaining);
|
|
33854
|
+
else
|
|
33855
|
+
this.wrapupSessions.delete(args.sessionId);
|
|
33856
|
+
};
|
|
33515
33857
|
const laneDeadlineMs = Date.now() + attemptTimeoutMs;
|
|
33516
|
-
|
|
33517
|
-
|
|
33858
|
+
let releaseLane;
|
|
33859
|
+
try {
|
|
33860
|
+
releaseLane = await this.acquireCorrectnessLane(args.sessionId, args.signal, laneDeadlineMs);
|
|
33861
|
+
} catch (error51) {
|
|
33862
|
+
finishWrapupTracking();
|
|
33863
|
+
throw error51;
|
|
33864
|
+
}
|
|
33865
|
+
let activeAttemptClient = null;
|
|
33866
|
+
const onAbort = () => this.invalidateConnection(activeAttemptClient ?? this.client);
|
|
33518
33867
|
args.signal?.addEventListener("abort", onAbort, { once: true });
|
|
33519
33868
|
try {
|
|
33520
33869
|
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
33870
|
+
activeAttemptClient = null;
|
|
33521
33871
|
let ensuredRoute = null;
|
|
33522
33872
|
try {
|
|
33523
33873
|
if (args.signal?.aborted) {
|
|
@@ -33525,22 +33875,35 @@ class SubcModuleTransport {
|
|
|
33525
33875
|
}
|
|
33526
33876
|
const attemptDeadlineMs = Date.now() + attemptTimeoutMs;
|
|
33527
33877
|
ensuredRoute = await this.ensureRoute(args.sessionId, args.projectRoot, attemptDeadlineMs);
|
|
33878
|
+
activeAttemptClient = ensuredRoute.client;
|
|
33528
33879
|
if (args.signal?.aborted) {
|
|
33529
33880
|
throw args.signal.reason ?? new Error("module transport call aborted");
|
|
33530
33881
|
}
|
|
33531
|
-
|
|
33882
|
+
const response = await this.beforeDeadline(ensuredRoute.client.request(ensuredRoute.route, args.body, {
|
|
33532
33883
|
priority: Priority.Background,
|
|
33533
33884
|
admissionClass: AdmissionClass.Normal,
|
|
33534
33885
|
timeoutMs: Math.max(1, attemptDeadlineMs - Date.now())
|
|
33535
33886
|
}), attemptDeadlineMs, "waiting for the module response");
|
|
33887
|
+
if (this.client !== ensuredRoute.client || this.connectionGeneration !== ensuredRoute.generation) {
|
|
33888
|
+
throw this.connectionChangedError("subc connection changed while awaiting the module response");
|
|
33889
|
+
}
|
|
33890
|
+
return response;
|
|
33536
33891
|
} catch (error51) {
|
|
33537
33892
|
if (isConnectionFailure(error51)) {
|
|
33893
|
+
const previousGeneration = ensuredRoute?.generation ?? this.connectionGeneration;
|
|
33538
33894
|
if (ensuredRoute) {
|
|
33539
33895
|
this.dropRoute(ensuredRoute.routeKey, ensuredRoute.route);
|
|
33540
33896
|
this.invalidateConnection(ensuredRoute.client);
|
|
33541
33897
|
} else {
|
|
33542
33898
|
this.invalidateConnection();
|
|
33543
33899
|
}
|
|
33900
|
+
if (args.generationSensitive && !args.signal?.aborted) {
|
|
33901
|
+
return {
|
|
33902
|
+
transport_status: "connection_generation_changed",
|
|
33903
|
+
previous_generation: previousGeneration,
|
|
33904
|
+
current_generation: this.connectionGeneration
|
|
33905
|
+
};
|
|
33906
|
+
}
|
|
33544
33907
|
if (attempt === 0 && !args.signal?.aborted)
|
|
33545
33908
|
continue;
|
|
33546
33909
|
}
|
|
@@ -33550,6 +33913,7 @@ class SubcModuleTransport {
|
|
|
33550
33913
|
throw new Error("module transport route retry exhausted");
|
|
33551
33914
|
} finally {
|
|
33552
33915
|
args.signal?.removeEventListener("abort", onAbort);
|
|
33916
|
+
finishWrapupTracking();
|
|
33553
33917
|
releaseLane();
|
|
33554
33918
|
}
|
|
33555
33919
|
}
|
|
@@ -33640,7 +34004,7 @@ class SubcModuleTransport {
|
|
|
33640
34004
|
});
|
|
33641
34005
|
}
|
|
33642
34006
|
}
|
|
33643
|
-
if (routes.length === 0 && this.
|
|
34007
|
+
if (routes.length === 0 && this.sessionLanes.get(sessionId)?.active) {
|
|
33644
34008
|
this.invalidateConnection(client);
|
|
33645
34009
|
}
|
|
33646
34010
|
}
|
|
@@ -33655,23 +34019,36 @@ class SubcModuleTransport {
|
|
|
33655
34019
|
}
|
|
33656
34020
|
if (existing)
|
|
33657
34021
|
this.routes.delete(routeKey2);
|
|
33658
|
-
const
|
|
33659
|
-
|
|
33660
|
-
|
|
33661
|
-
|
|
33662
|
-
|
|
33663
|
-
|
|
33664
|
-
|
|
33665
|
-
|
|
33666
|
-
|
|
33667
|
-
|
|
33668
|
-
}
|
|
33669
|
-
const
|
|
33670
|
-
|
|
33671
|
-
|
|
34022
|
+
const opening = this.routeOpenings.get(routeKey2);
|
|
34023
|
+
if (opening?.client === client && opening.generation === generation) {
|
|
34024
|
+
return await opening.promise;
|
|
34025
|
+
}
|
|
34026
|
+
const promise2 = (async () => {
|
|
34027
|
+
const target = { kind: "tool_provider", module_id: this.moduleId };
|
|
34028
|
+
const identity = {
|
|
34029
|
+
project_root: projectRoot,
|
|
34030
|
+
harness: getHarness(),
|
|
34031
|
+
session: `${this.routeSessionPrefix}${sessionId}`
|
|
34032
|
+
};
|
|
34033
|
+
const route = await this.beforeDeadline(client.routeOpen(target, identity), deadlineMs, "opening the module route");
|
|
34034
|
+
if (this.client !== client || generation !== this.connectionGeneration) {
|
|
34035
|
+
await client.closeRoute(route).catch(() => {
|
|
34036
|
+
return;
|
|
34037
|
+
});
|
|
34038
|
+
throw this.connectionChangedError("subc connection changed while opening module route");
|
|
34039
|
+
}
|
|
34040
|
+
this.routes.set(routeKey2, { route, generation });
|
|
34041
|
+
return { client, route, routeKey: routeKey2, generation };
|
|
34042
|
+
})();
|
|
34043
|
+
const routeOpening = { client, generation, promise: promise2 };
|
|
34044
|
+
this.routeOpenings.set(routeKey2, routeOpening);
|
|
34045
|
+
try {
|
|
34046
|
+
return await promise2;
|
|
34047
|
+
} finally {
|
|
34048
|
+
if (this.routeOpenings.get(routeKey2) === routeOpening) {
|
|
34049
|
+
this.routeOpenings.delete(routeKey2);
|
|
34050
|
+
}
|
|
33672
34051
|
}
|
|
33673
|
-
this.routes.set(routeKey2, { route, generation });
|
|
33674
|
-
return { client, route, routeKey: routeKey2, generation };
|
|
33675
34052
|
}
|
|
33676
34053
|
dropRoute(routeKey2, route) {
|
|
33677
34054
|
const existing = this.routes.get(routeKey2);
|
|
@@ -33699,9 +34076,17 @@ class SubcModuleTransport {
|
|
|
33699
34076
|
}
|
|
33700
34077
|
return resolved;
|
|
33701
34078
|
}
|
|
34079
|
+
connectClient() {
|
|
34080
|
+
return SubcClient.connect({
|
|
34081
|
+
connectionFile: this.connectionFile,
|
|
34082
|
+
handshakeTimeoutMs: HANDSHAKE_TIMEOUT_MS
|
|
34083
|
+
});
|
|
34084
|
+
}
|
|
33702
34085
|
async ensureConnected() {
|
|
33703
34086
|
if (this.client)
|
|
33704
34087
|
return this.client;
|
|
34088
|
+
if (this.connectionPromise)
|
|
34089
|
+
return await this.connectionPromise;
|
|
33705
34090
|
const now = Date.now();
|
|
33706
34091
|
if (now < this.nextProbeMs) {
|
|
33707
34092
|
const error51 = new Error(`subc connection backoff active until ${this.nextProbeMs}`);
|
|
@@ -33709,49 +34094,55 @@ class SubcModuleTransport {
|
|
|
33709
34094
|
throw error51;
|
|
33710
34095
|
}
|
|
33711
34096
|
const generation = this.connectionGeneration;
|
|
33712
|
-
|
|
33713
|
-
|
|
33714
|
-
|
|
33715
|
-
|
|
33716
|
-
|
|
33717
|
-
|
|
33718
|
-
|
|
33719
|
-
|
|
33720
|
-
|
|
33721
|
-
|
|
34097
|
+
const connecting = (async () => {
|
|
34098
|
+
let candidate = null;
|
|
34099
|
+
try {
|
|
34100
|
+
candidate = await this.connectClient();
|
|
34101
|
+
if (generation !== this.connectionGeneration) {
|
|
34102
|
+
candidate.close();
|
|
34103
|
+
throw this.connectionChangedError("subc connection attempt was superseded");
|
|
34104
|
+
}
|
|
34105
|
+
this.client = candidate;
|
|
34106
|
+
this.routes.clear();
|
|
34107
|
+
this.backoffMs = CONNECT_BACKOFF_INITIAL_MS;
|
|
34108
|
+
this.nextProbeMs = 0;
|
|
34109
|
+
return candidate;
|
|
34110
|
+
} catch (error51) {
|
|
34111
|
+
candidate?.close();
|
|
34112
|
+
if (generation === this.connectionGeneration)
|
|
34113
|
+
this.invalidateConnection();
|
|
34114
|
+
this.nextProbeMs = Date.now() + this.backoffMs;
|
|
34115
|
+
this.backoffMs = Math.min(this.backoffMs * 2, CONNECT_BACKOFF_MAX_MS);
|
|
33722
34116
|
throw error51;
|
|
33723
34117
|
}
|
|
33724
|
-
|
|
33725
|
-
|
|
33726
|
-
|
|
33727
|
-
|
|
33728
|
-
|
|
33729
|
-
|
|
33730
|
-
|
|
33731
|
-
this.invalidateConnection();
|
|
33732
|
-
this.nextProbeMs = Date.now() + this.backoffMs;
|
|
33733
|
-
this.backoffMs = Math.min(this.backoffMs * 2, CONNECT_BACKOFF_MAX_MS);
|
|
33734
|
-
throw error51;
|
|
34118
|
+
})();
|
|
34119
|
+
this.connectionPromise = connecting;
|
|
34120
|
+
try {
|
|
34121
|
+
return await connecting;
|
|
34122
|
+
} finally {
|
|
34123
|
+
if (this.connectionPromise === connecting)
|
|
34124
|
+
this.connectionPromise = null;
|
|
33735
34125
|
}
|
|
33736
34126
|
}
|
|
33737
34127
|
invalidateConnection(client = this.client) {
|
|
33738
|
-
if (client && this.client
|
|
34128
|
+
if (client && this.client !== client)
|
|
33739
34129
|
return;
|
|
33740
34130
|
this.connectionGeneration += 1;
|
|
33741
34131
|
this.invalidateStateSyncCapabilities();
|
|
33742
34132
|
this.client = null;
|
|
33743
34133
|
this.routes.clear();
|
|
34134
|
+
this.routeOpenings.clear();
|
|
33744
34135
|
client?.close();
|
|
33745
34136
|
}
|
|
33746
34137
|
}
|
|
33747
|
-
var DEFAULT_MODULE_ID = "magic-context", CONNECT_BACKOFF_INITIAL_MS = 1000, CONNECT_BACKOFF_MAX_MS = 30000, HANDSHAKE_TIMEOUT_MS = 2000, MODULE_SEND_TIMEOUT_MS = 15000, TRANSFORM_SEND_TIMEOUT_MS = 5000, SERIAL_LANE_MAX_WAITERS = 16, SERIAL_LANE_MIN_REMAINING_MS = 25, CANONICAL_ROOT_CACHE_MAX_ENTRIES = 256;
|
|
34138
|
+
var DEFAULT_MODULE_ID = "magic-context", CONNECT_BACKOFF_INITIAL_MS = 1000, CONNECT_BACKOFF_MAX_MS = 30000, HANDSHAKE_TIMEOUT_MS = 2000, MODULE_SEND_TIMEOUT_MS = 15000, TRANSFORM_SEND_TIMEOUT_MS = 5000, MAX_WRAPUP_REQUEST_BUDGET_MS = 3800000, SERIAL_LANE_MAX_WAITERS = 16, SERIAL_LANE_MAX_WAITERS_PER_SESSION = 8, SERIAL_LANE_MIN_REMAINING_MS = 25, CANONICAL_ROOT_CACHE_MAX_ENTRIES = 256;
|
|
33748
34139
|
var init_module_transport = __esm(() => {
|
|
33749
34140
|
init_dist5();
|
|
33750
34141
|
init_data_path();
|
|
33751
34142
|
});
|
|
33752
34143
|
// ../plugin/src/shared/rpc-utils.ts
|
|
33753
34144
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
33754
|
-
import { readFileSync as
|
|
34145
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
33755
34146
|
function isPidAlive(pid) {
|
|
33756
34147
|
if (!Number.isInteger(pid) || pid <= 0)
|
|
33757
34148
|
return false;
|
|
@@ -33832,6 +34223,49 @@ function isPidIdentityPlausible(record2) {
|
|
|
33832
34223
|
return true;
|
|
33833
34224
|
return commandLooksLikeOpenCode(command);
|
|
33834
34225
|
}
|
|
34226
|
+
function commandLooksLikePi(command) {
|
|
34227
|
+
const normalized = command.trim().toLowerCase().replaceAll("\\", "/");
|
|
34228
|
+
const tokens = normalized.split(/\s+/).filter(Boolean);
|
|
34229
|
+
const executableName = (token) => (token ?? "").split("/").at(-1) ?? "";
|
|
34230
|
+
const first = executableName(tokens[0]).replace(/\.exe$/, "");
|
|
34231
|
+
if (["pi", "pi.cmd", "omp", "oh-my-pi"].includes(first))
|
|
34232
|
+
return true;
|
|
34233
|
+
if (["node", "bun", "deno"].includes(first)) {
|
|
34234
|
+
const script = executableName(tokens[1]);
|
|
34235
|
+
return ["pi", "pi.js", "pi.mjs", "pi.cjs"].includes(script) || normalized.includes("pi-coding-agent");
|
|
34236
|
+
}
|
|
34237
|
+
return false;
|
|
34238
|
+
}
|
|
34239
|
+
function inspectLivePiProcesses() {
|
|
34240
|
+
if (false) {}
|
|
34241
|
+
try {
|
|
34242
|
+
const output = String(rpcProcessListExecFileSync("ps", ["-axo", "pid=,command="], {
|
|
34243
|
+
encoding: "utf8",
|
|
34244
|
+
timeout: PS_PROBE_TIMEOUT_MS
|
|
34245
|
+
}));
|
|
34246
|
+
const pids = new Set;
|
|
34247
|
+
for (const line of output.split(/\r?\n/)) {
|
|
34248
|
+
const match = /^\s*(\d+)\s+(.+)$/.exec(line);
|
|
34249
|
+
if (!match)
|
|
34250
|
+
continue;
|
|
34251
|
+
const pid = Number(match[1]);
|
|
34252
|
+
if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid)
|
|
34253
|
+
continue;
|
|
34254
|
+
if (commandLooksLikePi(match[2]))
|
|
34255
|
+
pids.add(pid);
|
|
34256
|
+
}
|
|
34257
|
+
return { state: "known", processIds: [...pids].sort((left, right) => left - right) };
|
|
34258
|
+
} catch (error51) {
|
|
34259
|
+
return {
|
|
34260
|
+
state: "unreadable",
|
|
34261
|
+
processIds: [],
|
|
34262
|
+
error: error51 instanceof Error ? error51.message : String(error51)
|
|
34263
|
+
};
|
|
34264
|
+
}
|
|
34265
|
+
}
|
|
34266
|
+
function discoverLivePiProcessIds() {
|
|
34267
|
+
return inspectLivePiProcesses().processIds;
|
|
34268
|
+
}
|
|
33835
34269
|
function parseRpcPortFile(content, fallbackPid = 0) {
|
|
33836
34270
|
const trimmed = content.trim();
|
|
33837
34271
|
if (!trimmed)
|
|
@@ -33863,11 +34297,12 @@ function parseRpcPortFile(content, fallbackPid = 0) {
|
|
|
33863
34297
|
function isValidPort(port) {
|
|
33864
34298
|
return Number.isInteger(port) && port > 0 && port <= 65535;
|
|
33865
34299
|
}
|
|
33866
|
-
var RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, OPEN_CODE_COMMAND_MARKERS, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now();
|
|
34300
|
+
var RPC_IDENTITY_SKEW_TOLERANCE_MS = 120000, LINUX_CLOCK_TICKS_PER_SECOND = 100, PS_PROBE_TIMEOUT_MS = 1000, OPEN_CODE_COMMAND_MARKERS, rpcIdentityReadFileSync, rpcIdentityExecFileSync, rpcProcessListExecFileSync, rpcIdentityPlatform, rpcIdentityNowMs = () => Date.now();
|
|
33867
34301
|
var init_rpc_utils = __esm(() => {
|
|
33868
34302
|
OPEN_CODE_COMMAND_MARKERS = ["opencode", "node", "bun", "electron"];
|
|
33869
|
-
rpcIdentityReadFileSync =
|
|
34303
|
+
rpcIdentityReadFileSync = readFileSync12;
|
|
33870
34304
|
rpcIdentityExecFileSync = execFileSync4;
|
|
34305
|
+
rpcProcessListExecFileSync = execFileSync4;
|
|
33871
34306
|
rpcIdentityPlatform = process.platform;
|
|
33872
34307
|
});
|
|
33873
34308
|
// ../plugin/src/hooks/magic-context/compartment-parser.ts
|
|
@@ -34227,6 +34662,14 @@ var init_workspaces = __esm(() => {
|
|
|
34227
34662
|
});
|
|
34228
34663
|
|
|
34229
34664
|
// ../plugin/src/features/magic-context/migrations.ts
|
|
34665
|
+
function isSqliteLockError(error51) {
|
|
34666
|
+
if (!error51 || typeof error51 !== "object")
|
|
34667
|
+
return false;
|
|
34668
|
+
const candidate = error51;
|
|
34669
|
+
if (candidate.code === "SQLITE_BUSY" || candidate.code === "SQLITE_LOCKED")
|
|
34670
|
+
return true;
|
|
34671
|
+
return typeof candidate.message === "string" && /database is locked|sqlite_(busy|locked)/i.test(candidate.message);
|
|
34672
|
+
}
|
|
34230
34673
|
function tableExists(db, name) {
|
|
34231
34674
|
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name));
|
|
34232
34675
|
}
|
|
@@ -34330,11 +34773,106 @@ function installLatestAuthorityTriggers(db) {
|
|
|
34330
34773
|
`);
|
|
34331
34774
|
}
|
|
34332
34775
|
}
|
|
34333
|
-
|
|
34776
|
+
function ensureMigrationsTable(db) {
|
|
34777
|
+
db.exec(`
|
|
34778
|
+
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
34779
|
+
version INTEGER PRIMARY KEY,
|
|
34780
|
+
description TEXT NOT NULL,
|
|
34781
|
+
applied_at INTEGER NOT NULL
|
|
34782
|
+
)
|
|
34783
|
+
`);
|
|
34784
|
+
}
|
|
34785
|
+
function getCurrentVersion(db) {
|
|
34786
|
+
const row = db.prepare("SELECT COALESCE(MAX(version), 0) AS version FROM schema_migrations WHERE version < ?").get(FORK_MIGRATION_VERSION_FLOOR);
|
|
34787
|
+
return row?.version ?? 0;
|
|
34788
|
+
}
|
|
34789
|
+
function isMigrationApplied(db, version2) {
|
|
34790
|
+
return db.prepare("SELECT 1 FROM schema_migrations WHERE version = ?").get(version2) != null;
|
|
34791
|
+
}
|
|
34792
|
+
function isSiblingMigrationConflict(db, error51, version2) {
|
|
34793
|
+
if (!(error51 instanceof Error))
|
|
34794
|
+
return false;
|
|
34795
|
+
const msg = error51.message;
|
|
34796
|
+
if (!msg.includes("schema_migrations"))
|
|
34797
|
+
return false;
|
|
34798
|
+
if (!msg.toLowerCase().includes("version"))
|
|
34799
|
+
return false;
|
|
34800
|
+
const confirmed = db.prepare("SELECT 1 FROM schema_migrations WHERE version = ?").get(version2);
|
|
34801
|
+
return confirmed != null;
|
|
34802
|
+
}
|
|
34803
|
+
function runMigrations(db) {
|
|
34804
|
+
try {
|
|
34805
|
+
ensureMigrationsTable(db);
|
|
34806
|
+
} catch (error51) {
|
|
34807
|
+
if (isSqliteLockError(error51)) {
|
|
34808
|
+
throw new MigrationLockBusyError(`failed to prepare migration lock: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
34809
|
+
}
|
|
34810
|
+
throw error51;
|
|
34811
|
+
}
|
|
34812
|
+
let loggedPlan = false;
|
|
34813
|
+
let touchedLegacyAuthorityBatch = false;
|
|
34814
|
+
while (true) {
|
|
34815
|
+
let migration;
|
|
34816
|
+
let currentVersion = 0;
|
|
34817
|
+
try {
|
|
34818
|
+
const applied = db.transaction(() => {
|
|
34819
|
+
currentVersion = getCurrentVersion(db);
|
|
34820
|
+
migration = MIGRATIONS.find((candidate) => candidate.version > currentVersion && !isMigrationApplied(db, candidate.version));
|
|
34821
|
+
if (!migration)
|
|
34822
|
+
return false;
|
|
34823
|
+
if (!loggedPlan) {
|
|
34824
|
+
const pendingCount = MIGRATIONS.filter((candidate) => candidate.version > currentVersion && !isMigrationApplied(db, candidate.version)).length;
|
|
34825
|
+
log3(`[migrations] current upstream migration lane: ${currentVersion}, applying ${pendingCount} migration(s)`);
|
|
34826
|
+
loggedPlan = true;
|
|
34827
|
+
}
|
|
34828
|
+
migration.up(db);
|
|
34829
|
+
db.prepare("INSERT INTO schema_migrations (version, description, applied_at) VALUES (?, ?, ?)").run(migration.version, migration.description, Date.now());
|
|
34830
|
+
return true;
|
|
34831
|
+
}).immediate();
|
|
34832
|
+
if (!applied || !migration)
|
|
34833
|
+
break;
|
|
34834
|
+
if (migration.version <= 61)
|
|
34835
|
+
touchedLegacyAuthorityBatch = true;
|
|
34836
|
+
log3(`[migrations] applied v${migration.version}: ${migration.description}`);
|
|
34837
|
+
} catch (error51) {
|
|
34838
|
+
if (!migration && isSqliteLockError(error51)) {
|
|
34839
|
+
throw new MigrationLockBusyError(`failed to acquire migration write lock: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
34840
|
+
}
|
|
34841
|
+
if (migration && isSiblingMigrationConflict(db, error51, migration.version)) {
|
|
34842
|
+
log3(`[migrations] v${migration.version} already applied by sibling instance — resuming with re-read version`);
|
|
34843
|
+
const reReadVersion = getCurrentVersion(db);
|
|
34844
|
+
if (reReadVersion > currentVersion)
|
|
34845
|
+
continue;
|
|
34846
|
+
throw new Error(`Migration v${migration.version} failed: sibling conflict reported but version did not advance. Database may need manual repair.`);
|
|
34847
|
+
}
|
|
34848
|
+
const version2 = migration?.version ?? currentVersion + 1;
|
|
34849
|
+
const description = migration?.description ?? "acquire migration write lock";
|
|
34850
|
+
log3(`[migrations] FAILED v${version2}: ${description} — ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
34851
|
+
throw new Error(`Migration v${version2} failed: ${error51 instanceof Error ? error51.message : String(error51)}. Database may need manual repair.`);
|
|
34852
|
+
}
|
|
34853
|
+
}
|
|
34854
|
+
if (touchedLegacyAuthorityBatch) {
|
|
34855
|
+
try {
|
|
34856
|
+
db.transaction(() => installLatestAuthorityTriggers(db)).immediate();
|
|
34857
|
+
} catch (error51) {
|
|
34858
|
+
throw new Error(`Migration authority-trigger postcondition failed: ${error51 instanceof Error ? error51.message : String(error51)}. Database may need manual repair.`);
|
|
34859
|
+
}
|
|
34860
|
+
}
|
|
34861
|
+
if (loggedPlan) {
|
|
34862
|
+
log3(`[migrations] upstream migration lane now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
|
|
34863
|
+
}
|
|
34864
|
+
}
|
|
34865
|
+
var FORK_MIGRATION_VERSION_FLOOR = 1e4, MigrationLockBusyError, MIGRATIONS, LATEST_MIGRATION_VERSION;
|
|
34334
34866
|
var init_migrations = __esm(() => {
|
|
34335
34867
|
init_compartment_parser();
|
|
34336
34868
|
init_logger();
|
|
34337
34869
|
init_workspaces();
|
|
34870
|
+
MigrationLockBusyError = class MigrationLockBusyError extends Error {
|
|
34871
|
+
constructor(message) {
|
|
34872
|
+
super(message);
|
|
34873
|
+
this.name = "MigrationLockBusyError";
|
|
34874
|
+
}
|
|
34875
|
+
};
|
|
34338
34876
|
MIGRATIONS = [
|
|
34339
34877
|
{
|
|
34340
34878
|
version: 1,
|
|
@@ -36289,11 +36827,8 @@ var init_commit_detection = __esm(() => {
|
|
|
36289
36827
|
COMMIT_HASH_TEST_PATTERN = new RegExp(`\\b${HASH_HEX}\\b`, "i");
|
|
36290
36828
|
});
|
|
36291
36829
|
// ../plugin/src/hooks/magic-context/read-session-formatting.ts
|
|
36292
|
-
import { createRequire as createRequire2 } from "node:module";
|
|
36293
|
-
var requireFromThisModule;
|
|
36294
36830
|
var init_read_session_formatting = __esm(() => {
|
|
36295
36831
|
init_commit_detection();
|
|
36296
|
-
requireFromThisModule = createRequire2(import.meta.url);
|
|
36297
36832
|
});
|
|
36298
36833
|
// ../plugin/src/features/magic-context/tool-definition-tokens.ts
|
|
36299
36834
|
var measurements, fingerprints;
|
|
@@ -36320,7 +36855,7 @@ import {
|
|
|
36320
36855
|
existsSync as existsSync18,
|
|
36321
36856
|
mkdirSync as mkdirSync7,
|
|
36322
36857
|
readdirSync as readdirSync2,
|
|
36323
|
-
readFileSync as
|
|
36858
|
+
readFileSync as readFileSync13,
|
|
36324
36859
|
statSync as statSync7,
|
|
36325
36860
|
unlinkSync as unlinkSync2
|
|
36326
36861
|
} from "node:fs";
|
|
@@ -36448,11 +36983,1113 @@ function inspectRpcServerDiscovery(storageDir) {
|
|
|
36448
36983
|
}
|
|
36449
36984
|
function getLiveMigrationBlockingProcesses(storageDir) {
|
|
36450
36985
|
const discovery = inspectRpcServerDiscovery(storageDir);
|
|
36451
|
-
|
|
36452
|
-
|
|
36453
|
-
return
|
|
36986
|
+
const openCode = discovery.state === "live" ? discovery.serverPids.map((pid) => ({ harness: "OpenCode server", pid })) : [];
|
|
36987
|
+
const pi = discoverLivePiProcessIds().map((pid) => ({ harness: "Pi harness", pid }));
|
|
36988
|
+
return [...openCode, ...pi];
|
|
36454
36989
|
}
|
|
36455
|
-
|
|
36990
|
+
function applySqliteTuningPragmas(db) {
|
|
36991
|
+
db.exec(`PRAGMA cache_size=-${Math.round(sqlitePragmaConfig.cacheSizeMb * 1024)}`);
|
|
36992
|
+
db.exec(`PRAGMA mmap_size=${Math.round(sqlitePragmaConfig.mmapSizeMb * 1024 * 1024)}`);
|
|
36993
|
+
db.exec("PRAGMA analysis_limit=400");
|
|
36994
|
+
}
|
|
36995
|
+
function initializeDatabase(db) {
|
|
36996
|
+
db.exec("PRAGMA busy_timeout=5000");
|
|
36997
|
+
db.exec("PRAGMA foreign_keys=ON");
|
|
36998
|
+
db.exec("PRAGMA journal_mode=WAL");
|
|
36999
|
+
applySqliteTuningPragmas(db);
|
|
37000
|
+
db.exec(`
|
|
37001
|
+
CREATE TABLE IF NOT EXISTS tags (
|
|
37002
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37003
|
+
session_id TEXT,
|
|
37004
|
+
message_id TEXT,
|
|
37005
|
+
type TEXT,
|
|
37006
|
+
status TEXT DEFAULT 'active',
|
|
37007
|
+
byte_size INTEGER,
|
|
37008
|
+
tag_number INTEGER,
|
|
37009
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37010
|
+
entry_fingerprint TEXT,
|
|
37011
|
+
token_count INTEGER,
|
|
37012
|
+
input_token_count INTEGER,
|
|
37013
|
+
reasoning_token_count INTEGER,
|
|
37014
|
+
UNIQUE(session_id, tag_number)
|
|
37015
|
+
);
|
|
37016
|
+
|
|
37017
|
+
CREATE TABLE IF NOT EXISTS pending_ops (
|
|
37018
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37019
|
+
session_id TEXT,
|
|
37020
|
+
tag_id INTEGER,
|
|
37021
|
+
operation TEXT,
|
|
37022
|
+
queued_at INTEGER,
|
|
37023
|
+
harness TEXT NOT NULL DEFAULT 'opencode'
|
|
37024
|
+
);
|
|
37025
|
+
|
|
37026
|
+
CREATE TABLE IF NOT EXISTS source_contents (
|
|
37027
|
+
tag_id INTEGER,
|
|
37028
|
+
session_id TEXT,
|
|
37029
|
+
content TEXT,
|
|
37030
|
+
created_at INTEGER,
|
|
37031
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37032
|
+
PRIMARY KEY(session_id, tag_id)
|
|
37033
|
+
);
|
|
37034
|
+
|
|
37035
|
+
CREATE TABLE IF NOT EXISTS compartments (
|
|
37036
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37037
|
+
session_id TEXT NOT NULL,
|
|
37038
|
+
sequence INTEGER NOT NULL,
|
|
37039
|
+
start_message INTEGER NOT NULL,
|
|
37040
|
+
end_message INTEGER NOT NULL,
|
|
37041
|
+
start_message_id TEXT DEFAULT '',
|
|
37042
|
+
end_message_id TEXT DEFAULT '',
|
|
37043
|
+
title TEXT NOT NULL,
|
|
37044
|
+
content TEXT NOT NULL,
|
|
37045
|
+
p1 TEXT,
|
|
37046
|
+
p2 TEXT,
|
|
37047
|
+
p3 TEXT,
|
|
37048
|
+
p4 TEXT,
|
|
37049
|
+
importance INTEGER NOT NULL DEFAULT 50,
|
|
37050
|
+
episode_type TEXT,
|
|
37051
|
+
p1_embedding BLOB,
|
|
37052
|
+
p1_embedding_model_id TEXT,
|
|
37053
|
+
legacy INTEGER NOT NULL DEFAULT 0,
|
|
37054
|
+
created_at INTEGER NOT NULL,
|
|
37055
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37056
|
+
UNIQUE(session_id, sequence)
|
|
37057
|
+
);
|
|
37058
|
+
CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
|
|
37059
|
+
|
|
37060
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
37061
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37062
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
37063
|
+
session_id TEXT NOT NULL,
|
|
37064
|
+
project_path TEXT NOT NULL,
|
|
37065
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37066
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
37067
|
+
start_ordinal INTEGER NOT NULL,
|
|
37068
|
+
end_ordinal INTEGER NOT NULL,
|
|
37069
|
+
chunk_hash TEXT NOT NULL,
|
|
37070
|
+
model_id TEXT NOT NULL,
|
|
37071
|
+
dims INTEGER NOT NULL,
|
|
37072
|
+
vector BLOB NOT NULL,
|
|
37073
|
+
created_at INTEGER NOT NULL,
|
|
37074
|
+
UNIQUE(compartment_id, model_id, window_index)
|
|
37075
|
+
);
|
|
37076
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session ON compartment_chunk_embeddings(session_id);
|
|
37077
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model ON compartment_chunk_embeddings(project_path, model_id);
|
|
37078
|
+
|
|
37079
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
37080
|
+
session_id TEXT NOT NULL,
|
|
37081
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37082
|
+
project_path TEXT NOT NULL,
|
|
37083
|
+
updated_at INTEGER NOT NULL,
|
|
37084
|
+
PRIMARY KEY(session_id, harness)
|
|
37085
|
+
);
|
|
37086
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
37087
|
+
ON session_projects(project_path);
|
|
37088
|
+
|
|
37089
|
+
CREATE TABLE IF NOT EXISTS compartment_events (
|
|
37090
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37091
|
+
session_id TEXT NOT NULL,
|
|
37092
|
+
compartment_id INTEGER,
|
|
37093
|
+
kind TEXT NOT NULL,
|
|
37094
|
+
at_compartment INTEGER,
|
|
37095
|
+
fields_json TEXT NOT NULL DEFAULT '{}',
|
|
37096
|
+
created_at INTEGER NOT NULL,
|
|
37097
|
+
harness TEXT NOT NULL DEFAULT 'opencode'
|
|
37098
|
+
);
|
|
37099
|
+
CREATE INDEX IF NOT EXISTS idx_compartment_events_session
|
|
37100
|
+
ON compartment_events(session_id);
|
|
37101
|
+
|
|
37102
|
+
CREATE TABLE IF NOT EXISTS compartment_state_lease (
|
|
37103
|
+
session_id TEXT PRIMARY KEY NOT NULL,
|
|
37104
|
+
holder_id TEXT NOT NULL,
|
|
37105
|
+
acquired_at INTEGER NOT NULL,
|
|
37106
|
+
expires_at INTEGER NOT NULL
|
|
37107
|
+
);
|
|
37108
|
+
CREATE INDEX IF NOT EXISTS idx_compartment_state_lease_expires
|
|
37109
|
+
ON compartment_state_lease(expires_at);
|
|
37110
|
+
|
|
37111
|
+
CREATE TABLE IF NOT EXISTS compression_depth (
|
|
37112
|
+
session_id TEXT NOT NULL,
|
|
37113
|
+
message_ordinal INTEGER NOT NULL,
|
|
37114
|
+
depth INTEGER NOT NULL DEFAULT 0,
|
|
37115
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37116
|
+
PRIMARY KEY(session_id, message_ordinal)
|
|
37117
|
+
);
|
|
37118
|
+
CREATE INDEX IF NOT EXISTS idx_compression_depth_session ON compression_depth(session_id);
|
|
37119
|
+
|
|
37120
|
+
CREATE TABLE IF NOT EXISTS session_facts (
|
|
37121
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37122
|
+
session_id TEXT NOT NULL,
|
|
37123
|
+
category TEXT NOT NULL,
|
|
37124
|
+
content TEXT NOT NULL,
|
|
37125
|
+
created_at INTEGER NOT NULL,
|
|
37126
|
+
updated_at INTEGER NOT NULL,
|
|
37127
|
+
harness TEXT NOT NULL DEFAULT 'opencode'
|
|
37128
|
+
);
|
|
37129
|
+
|
|
37130
|
+
CREATE TABLE IF NOT EXISTS primer_candidates (
|
|
37131
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37132
|
+
project_path TEXT NOT NULL,
|
|
37133
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37134
|
+
session_id TEXT NOT NULL,
|
|
37135
|
+
question TEXT NOT NULL,
|
|
37136
|
+
normalized_question TEXT NOT NULL,
|
|
37137
|
+
source_compartment_start INTEGER,
|
|
37138
|
+
source_compartment_end INTEGER,
|
|
37139
|
+
source_start_message_id TEXT NOT NULL DEFAULT '',
|
|
37140
|
+
source_end_message_id TEXT NOT NULL DEFAULT '',
|
|
37141
|
+
source_message_time INTEGER NOT NULL,
|
|
37142
|
+
question_embedding BLOB,
|
|
37143
|
+
question_embedding_model_id TEXT,
|
|
37144
|
+
created_at INTEGER NOT NULL,
|
|
37145
|
+
UNIQUE(project_path, harness, session_id, source_start_message_id, source_end_message_id)
|
|
37146
|
+
);
|
|
37147
|
+
CREATE INDEX IF NOT EXISTS idx_primer_candidates_project_time
|
|
37148
|
+
ON primer_candidates(project_path, source_message_time);
|
|
37149
|
+
CREATE INDEX IF NOT EXISTS idx_primer_candidates_session
|
|
37150
|
+
ON primer_candidates(session_id, harness);
|
|
37151
|
+
CREATE INDEX IF NOT EXISTS idx_primer_candidates_embedding_model
|
|
37152
|
+
ON primer_candidates(project_path, question_embedding_model_id);
|
|
37153
|
+
|
|
37154
|
+
CREATE TABLE IF NOT EXISTS primers (
|
|
37155
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37156
|
+
project_path TEXT NOT NULL,
|
|
37157
|
+
question TEXT NOT NULL,
|
|
37158
|
+
question_embedding BLOB,
|
|
37159
|
+
question_embedding_model_id TEXT,
|
|
37160
|
+
answer TEXT NOT NULL DEFAULT '',
|
|
37161
|
+
status TEXT NOT NULL DEFAULT 'active' CHECK(status IN ('active', 'archived')),
|
|
37162
|
+
total_support INTEGER NOT NULL DEFAULT 0,
|
|
37163
|
+
last_observed_at INTEGER,
|
|
37164
|
+
answer_refreshed_at INTEGER,
|
|
37165
|
+
source_candidate_ids TEXT NOT NULL DEFAULT '[]',
|
|
37166
|
+
created_at INTEGER NOT NULL,
|
|
37167
|
+
updated_at INTEGER NOT NULL
|
|
37168
|
+
);
|
|
37169
|
+
CREATE INDEX IF NOT EXISTS idx_primers_project_status_observed
|
|
37170
|
+
ON primers(project_path, status, last_observed_at DESC);
|
|
37171
|
+
CREATE INDEX IF NOT EXISTS idx_primers_embedding_model
|
|
37172
|
+
ON primers(project_path, question_embedding_model_id);
|
|
37173
|
+
|
|
37174
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS primers_fts USING fts5(
|
|
37175
|
+
question,
|
|
37176
|
+
answer,
|
|
37177
|
+
project_path UNINDEXED,
|
|
37178
|
+
content='primers',
|
|
37179
|
+
content_rowid='id',
|
|
37180
|
+
tokenize='porter unicode61'
|
|
37181
|
+
);
|
|
37182
|
+
|
|
37183
|
+
CREATE TRIGGER IF NOT EXISTS primers_ai AFTER INSERT ON primers BEGIN
|
|
37184
|
+
INSERT INTO primers_fts(rowid, question, answer, project_path)
|
|
37185
|
+
VALUES (new.id, new.question, new.answer, new.project_path);
|
|
37186
|
+
END;
|
|
37187
|
+
|
|
37188
|
+
CREATE TRIGGER IF NOT EXISTS primers_ad AFTER DELETE ON primers BEGIN
|
|
37189
|
+
INSERT INTO primers_fts(primers_fts, rowid, question, answer, project_path)
|
|
37190
|
+
VALUES ('delete', old.id, old.question, old.answer, old.project_path);
|
|
37191
|
+
END;
|
|
37192
|
+
|
|
37193
|
+
CREATE TRIGGER IF NOT EXISTS primers_au AFTER UPDATE ON primers BEGIN
|
|
37194
|
+
INSERT INTO primers_fts(primers_fts, rowid, question, answer, project_path)
|
|
37195
|
+
VALUES ('delete', old.id, old.question, old.answer, old.project_path);
|
|
37196
|
+
INSERT INTO primers_fts(rowid, question, answer, project_path)
|
|
37197
|
+
VALUES (new.id, new.question, new.answer, new.project_path);
|
|
37198
|
+
END;
|
|
37199
|
+
|
|
37200
|
+
-- session_notes and smart_notes were merged into the unified notes table
|
|
37201
|
+
-- by migration v1 (see features/magic-context/migrations.ts). The old tables
|
|
37202
|
+
-- are never recreated; fresh DBs create only notes, upgraded DBs have
|
|
37203
|
+
-- their old tables migrated and dropped by the migration runner.
|
|
37204
|
+
|
|
37205
|
+
CREATE TABLE IF NOT EXISTS memories (
|
|
37206
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37207
|
+
project_path TEXT NOT NULL,
|
|
37208
|
+
category TEXT NOT NULL,
|
|
37209
|
+
content TEXT NOT NULL,
|
|
37210
|
+
normalized_hash TEXT NOT NULL,
|
|
37211
|
+
importance INTEGER,
|
|
37212
|
+
scope TEXT NOT NULL DEFAULT 'project',
|
|
37213
|
+
shareable INTEGER NOT NULL DEFAULT 0,
|
|
37214
|
+
source_session_id TEXT,
|
|
37215
|
+
source_type TEXT DEFAULT 'historian',
|
|
37216
|
+
seen_count INTEGER DEFAULT 1,
|
|
37217
|
+
retrieval_count INTEGER DEFAULT 0,
|
|
37218
|
+
first_seen_at INTEGER NOT NULL,
|
|
37219
|
+
created_at INTEGER NOT NULL,
|
|
37220
|
+
updated_at INTEGER NOT NULL,
|
|
37221
|
+
last_seen_at INTEGER NOT NULL,
|
|
37222
|
+
last_retrieved_at INTEGER,
|
|
37223
|
+
status TEXT DEFAULT 'active',
|
|
37224
|
+
expires_at INTEGER,
|
|
37225
|
+
verification_status TEXT DEFAULT 'unverified',
|
|
37226
|
+
verified_at INTEGER,
|
|
37227
|
+
classified_at INTEGER,
|
|
37228
|
+
superseded_by_memory_id INTEGER,
|
|
37229
|
+
merged_from TEXT,
|
|
37230
|
+
metadata_json TEXT,
|
|
37231
|
+
mural_cue TEXT,
|
|
37232
|
+
mural_cue_hash TEXT,
|
|
37233
|
+
mural_cue_at INTEGER,
|
|
37234
|
+
mural_cue_rejection_count INTEGER NOT NULL DEFAULT 0,
|
|
37235
|
+
UNIQUE(project_path, category, normalized_hash)
|
|
37236
|
+
);
|
|
37237
|
+
|
|
37238
|
+
CREATE TABLE IF NOT EXISTS memory_embeddings (
|
|
37239
|
+
-- FK-cascade audit (v12): memory_embeddings.memory_id -> memories.id
|
|
37240
|
+
-- uses ON DELETE CASCADE, so SQLite PRAGMA foreign_keys must be ON on
|
|
37241
|
+
-- every connection and v12 cleans historical orphan rows.
|
|
37242
|
+
memory_id INTEGER NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
37243
|
+
embedding BLOB NOT NULL,
|
|
37244
|
+
model_id TEXT NOT NULL,
|
|
37245
|
+
PRIMARY KEY(memory_id, model_id)
|
|
37246
|
+
);
|
|
37247
|
+
|
|
37248
|
+
CREATE TABLE IF NOT EXISTS embedding_identity_active (
|
|
37249
|
+
project_path TEXT NOT NULL,
|
|
37250
|
+
scope TEXT NOT NULL CHECK(scope IN ('memory', 'commit', 'chunk')),
|
|
37251
|
+
model_id TEXT NOT NULL,
|
|
37252
|
+
last_active_at INTEGER NOT NULL,
|
|
37253
|
+
PRIMARY KEY(project_path, scope, model_id)
|
|
37254
|
+
);
|
|
37255
|
+
|
|
37256
|
+
CREATE TABLE IF NOT EXISTS embedding_registrations (
|
|
37257
|
+
project_path TEXT PRIMARY KEY,
|
|
37258
|
+
provider_identity TEXT NOT NULL DEFAULT '',
|
|
37259
|
+
model_id TEXT NOT NULL DEFAULT '',
|
|
37260
|
+
chunk_model_id TEXT NOT NULL DEFAULT '',
|
|
37261
|
+
fingerprint TEXT NOT NULL DEFAULT '',
|
|
37262
|
+
table_epoch INTEGER NOT NULL DEFAULT 0,
|
|
37263
|
+
dims INTEGER NOT NULL DEFAULT 0,
|
|
37264
|
+
provenance_json TEXT NOT NULL DEFAULT '{}',
|
|
37265
|
+
generation INTEGER NOT NULL DEFAULT 0,
|
|
37266
|
+
updated_at INTEGER NOT NULL DEFAULT 0
|
|
37267
|
+
);
|
|
37268
|
+
|
|
37269
|
+
CREATE TABLE IF NOT EXISTS synapse_batch_ledger (
|
|
37270
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37271
|
+
session_id TEXT NOT NULL,
|
|
37272
|
+
project_path TEXT NOT NULL DEFAULT '',
|
|
37273
|
+
scope TEXT NOT NULL DEFAULT '',
|
|
37274
|
+
manifest_json TEXT NOT NULL DEFAULT '{}',
|
|
37275
|
+
request_key TEXT NOT NULL DEFAULT '',
|
|
37276
|
+
job_id TEXT,
|
|
37277
|
+
cursor TEXT,
|
|
37278
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
37279
|
+
created_at INTEGER NOT NULL DEFAULT 0,
|
|
37280
|
+
updated_at INTEGER NOT NULL DEFAULT 0,
|
|
37281
|
+
UNIQUE(session_id, request_key)
|
|
37282
|
+
);
|
|
37283
|
+
CREATE INDEX IF NOT EXISTS idx_synapse_batch_ledger_session
|
|
37284
|
+
ON synapse_batch_ledger(session_id, updated_at);
|
|
37285
|
+
|
|
37286
|
+
CREATE TABLE IF NOT EXISTS shadow_embedding_registrations (
|
|
37287
|
+
project_path TEXT NOT NULL,
|
|
37288
|
+
scope TEXT NOT NULL CHECK(scope IN ('memory', 'commit', 'chunk')),
|
|
37289
|
+
model_id TEXT NOT NULL,
|
|
37290
|
+
generation INTEGER NOT NULL DEFAULT 0,
|
|
37291
|
+
fingerprint TEXT NOT NULL DEFAULT '',
|
|
37292
|
+
table_epoch INTEGER NOT NULL DEFAULT 0,
|
|
37293
|
+
dims INTEGER NOT NULL DEFAULT 0,
|
|
37294
|
+
provenance_json TEXT NOT NULL DEFAULT '{}',
|
|
37295
|
+
updated_at INTEGER NOT NULL DEFAULT 0,
|
|
37296
|
+
PRIMARY KEY(project_path, scope, model_id)
|
|
37297
|
+
);
|
|
37298
|
+
|
|
37299
|
+
CREATE TABLE IF NOT EXISTS embedding_measurement_corpus (
|
|
37300
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37301
|
+
session_id TEXT NOT NULL,
|
|
37302
|
+
project_path TEXT NOT NULL DEFAULT '',
|
|
37303
|
+
dedup_key TEXT NOT NULL DEFAULT '',
|
|
37304
|
+
cohort_key TEXT NOT NULL DEFAULT '',
|
|
37305
|
+
query_text_hash TEXT NOT NULL DEFAULT '',
|
|
37306
|
+
primary_result_ids_json TEXT NOT NULL DEFAULT '[]',
|
|
37307
|
+
shadow_result_ids_json TEXT NOT NULL DEFAULT '[]',
|
|
37308
|
+
primary_latency_ms INTEGER,
|
|
37309
|
+
shadow_latency_ms INTEGER,
|
|
37310
|
+
primary_failed INTEGER NOT NULL DEFAULT 0,
|
|
37311
|
+
shadow_failed INTEGER NOT NULL DEFAULT 0,
|
|
37312
|
+
primary_model_id TEXT NOT NULL DEFAULT '',
|
|
37313
|
+
shadow_model_id TEXT NOT NULL DEFAULT '',
|
|
37314
|
+
primary_fingerprint TEXT NOT NULL DEFAULT '',
|
|
37315
|
+
shadow_fingerprint TEXT NOT NULL DEFAULT '',
|
|
37316
|
+
primary_epoch INTEGER NOT NULL DEFAULT 0,
|
|
37317
|
+
shadow_epoch INTEGER NOT NULL DEFAULT 0,
|
|
37318
|
+
corpus_hash TEXT NOT NULL DEFAULT '',
|
|
37319
|
+
coverage_json TEXT NOT NULL DEFAULT '{}',
|
|
37320
|
+
created_at INTEGER NOT NULL DEFAULT 0,
|
|
37321
|
+
UNIQUE(dedup_key, cohort_key)
|
|
37322
|
+
);
|
|
37323
|
+
CREATE INDEX IF NOT EXISTS idx_embedding_measurement_session
|
|
37324
|
+
ON embedding_measurement_corpus(session_id, created_at);
|
|
37325
|
+
|
|
37326
|
+
CREATE TABLE IF NOT EXISTS memory_verifications (
|
|
37327
|
+
memory_id INTEGER NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
|
|
37328
|
+
file_path TEXT NOT NULL,
|
|
37329
|
+
-- verified_at=0 means "mapped (files known) but not yet content-verified".
|
|
37330
|
+
-- map-memories sets mapped_at + verified_at=0; verify sets verified_at=now.
|
|
37331
|
+
verified_at INTEGER NOT NULL,
|
|
37332
|
+
mapped_at INTEGER NOT NULL DEFAULT 0,
|
|
37333
|
+
PRIMARY KEY (memory_id, file_path)
|
|
37334
|
+
);
|
|
37335
|
+
CREATE INDEX IF NOT EXISTS idx_memory_verifications_memory ON memory_verifications(memory_id);
|
|
37336
|
+
|
|
37337
|
+
CREATE TABLE IF NOT EXISTS memory_mutation_log (
|
|
37338
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37339
|
+
project_path TEXT NOT NULL,
|
|
37340
|
+
mutation_type TEXT NOT NULL CHECK (mutation_type IN ('archive', 'delete', 'update', 'superseded')),
|
|
37341
|
+
target_memory_id INTEGER NOT NULL,
|
|
37342
|
+
superseded_by_id INTEGER,
|
|
37343
|
+
category TEXT,
|
|
37344
|
+
new_content TEXT,
|
|
37345
|
+
queued_at INTEGER NOT NULL
|
|
37346
|
+
);
|
|
37347
|
+
CREATE INDEX IF NOT EXISTS idx_memory_mutation_log_project
|
|
37348
|
+
ON memory_mutation_log(project_path, id);
|
|
37349
|
+
CREATE INDEX IF NOT EXISTS idx_memory_mutation_log_visibility
|
|
37350
|
+
ON memory_mutation_log(project_path, category, id, target_memory_id);
|
|
37351
|
+
CREATE INDEX IF NOT EXISTS idx_memory_mutation_log_target
|
|
37352
|
+
ON memory_mutation_log(project_path, target_memory_id, id);
|
|
37353
|
+
|
|
37354
|
+
CREATE TABLE IF NOT EXISTS dream_state (
|
|
37355
|
+
key TEXT PRIMARY KEY,
|
|
37356
|
+
value TEXT NOT NULL
|
|
37357
|
+
);
|
|
37358
|
+
|
|
37359
|
+
CREATE TABLE IF NOT EXISTS dream_queue (
|
|
37360
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37361
|
+
project_path TEXT NOT NULL,
|
|
37362
|
+
reason TEXT NOT NULL,
|
|
37363
|
+
enqueued_at INTEGER NOT NULL,
|
|
37364
|
+
started_at INTEGER,
|
|
37365
|
+
retry_count INTEGER DEFAULT 0
|
|
37366
|
+
);
|
|
37367
|
+
CREATE INDEX IF NOT EXISTS idx_dream_queue_project ON dream_queue(project_path);
|
|
37368
|
+
CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, enqueued_at);
|
|
37369
|
+
|
|
37370
|
+
CREATE TABLE IF NOT EXISTS dream_runs (
|
|
37371
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37372
|
+
project_path TEXT NOT NULL,
|
|
37373
|
+
started_at INTEGER NOT NULL,
|
|
37374
|
+
finished_at INTEGER NOT NULL,
|
|
37375
|
+
holder_id TEXT NOT NULL,
|
|
37376
|
+
tasks_json TEXT NOT NULL,
|
|
37377
|
+
tasks_succeeded INTEGER NOT NULL DEFAULT 0,
|
|
37378
|
+
tasks_failed INTEGER NOT NULL DEFAULT 0,
|
|
37379
|
+
smart_notes_surfaced INTEGER NOT NULL DEFAULT 0,
|
|
37380
|
+
smart_notes_pending INTEGER NOT NULL DEFAULT 0,
|
|
37381
|
+
memory_changes_json TEXT,
|
|
37382
|
+
parent_session_id TEXT
|
|
37383
|
+
);
|
|
37384
|
+
CREATE INDEX IF NOT EXISTS idx_dream_runs_project ON dream_runs(project_path, finished_at DESC);
|
|
37385
|
+
|
|
37386
|
+
CREATE TABLE IF NOT EXISTS task_schedule_state (
|
|
37387
|
+
project_path TEXT NOT NULL,
|
|
37388
|
+
task TEXT NOT NULL,
|
|
37389
|
+
last_run_at INTEGER,
|
|
37390
|
+
next_due_at INTEGER,
|
|
37391
|
+
schedule TEXT,
|
|
37392
|
+
last_status TEXT,
|
|
37393
|
+
last_error TEXT,
|
|
37394
|
+
last_checked_commit TEXT,
|
|
37395
|
+
last_broad_run_at INTEGER,
|
|
37396
|
+
retrospective_watermark_ms INTEGER,
|
|
37397
|
+
retry_count INTEGER NOT NULL DEFAULT 0,
|
|
37398
|
+
PRIMARY KEY (project_path, task)
|
|
37399
|
+
);
|
|
37400
|
+
CREATE INDEX IF NOT EXISTS idx_task_schedule_due ON task_schedule_state(next_due_at);
|
|
37401
|
+
|
|
37402
|
+
CREATE TABLE IF NOT EXISTS retrospective_processed_windows (
|
|
37403
|
+
project_path TEXT NOT NULL,
|
|
37404
|
+
window_key TEXT NOT NULL,
|
|
37405
|
+
processed_at INTEGER NOT NULL,
|
|
37406
|
+
PRIMARY KEY (project_path, window_key)
|
|
37407
|
+
);
|
|
37408
|
+
|
|
37409
|
+
CREATE TABLE IF NOT EXISTS project_key_files (
|
|
37410
|
+
project_path TEXT NOT NULL,
|
|
37411
|
+
path TEXT NOT NULL,
|
|
37412
|
+
content TEXT NOT NULL,
|
|
37413
|
+
content_hash TEXT NOT NULL,
|
|
37414
|
+
local_token_estimate INTEGER NOT NULL,
|
|
37415
|
+
generated_at INTEGER NOT NULL,
|
|
37416
|
+
generated_by_model TEXT,
|
|
37417
|
+
generation_config_hash TEXT NOT NULL,
|
|
37418
|
+
stale_reason TEXT,
|
|
37419
|
+
PRIMARY KEY (project_path, path)
|
|
37420
|
+
);
|
|
37421
|
+
CREATE INDEX IF NOT EXISTS idx_project_key_files_project ON project_key_files(project_path);
|
|
37422
|
+
CREATE INDEX IF NOT EXISTS idx_project_key_files_generated_at ON project_key_files(project_path, generated_at);
|
|
37423
|
+
|
|
37424
|
+
CREATE TABLE IF NOT EXISTS project_key_files_version (
|
|
37425
|
+
project_path TEXT PRIMARY KEY,
|
|
37426
|
+
version INTEGER NOT NULL DEFAULT 0
|
|
37427
|
+
);
|
|
37428
|
+
|
|
37429
|
+
CREATE TABLE IF NOT EXISTS schema_migrations_meta (
|
|
37430
|
+
key TEXT PRIMARY KEY,
|
|
37431
|
+
value TEXT NOT NULL
|
|
37432
|
+
);
|
|
37433
|
+
|
|
37434
|
+
CREATE TABLE IF NOT EXISTS project_state (
|
|
37435
|
+
project_path TEXT PRIMARY KEY,
|
|
37436
|
+
project_memory_epoch INTEGER NOT NULL DEFAULT 0,
|
|
37437
|
+
project_user_profile_version INTEGER NOT NULL DEFAULT 0,
|
|
37438
|
+
updated_at INTEGER NOT NULL DEFAULT 0
|
|
37439
|
+
);
|
|
37440
|
+
|
|
37441
|
+
CREATE TABLE IF NOT EXISTS git_sweep_coordinator (
|
|
37442
|
+
project_path TEXT PRIMARY KEY,
|
|
37443
|
+
lease_holder TEXT,
|
|
37444
|
+
lease_expires_at INTEGER,
|
|
37445
|
+
last_swept_at INTEGER
|
|
37446
|
+
);
|
|
37447
|
+
CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_lease_expires
|
|
37448
|
+
ON git_sweep_coordinator(lease_expires_at);
|
|
37449
|
+
CREATE INDEX IF NOT EXISTS idx_git_sweep_coordinator_last_swept
|
|
37450
|
+
ON git_sweep_coordinator(last_swept_at);
|
|
37451
|
+
|
|
37452
|
+
CREATE TABLE IF NOT EXISTS m0_mutation_log (
|
|
37453
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37454
|
+
session_id TEXT NOT NULL,
|
|
37455
|
+
mutation_type TEXT NOT NULL CHECK (mutation_type IN (
|
|
37456
|
+
'compartment_delete', 'compartment_merge', 'recomp_boundary_change', 'compartment_upgrade'
|
|
37457
|
+
)),
|
|
37458
|
+
target_id INTEGER,
|
|
37459
|
+
queued_at INTEGER NOT NULL
|
|
37460
|
+
);
|
|
37461
|
+
CREATE INDEX IF NOT EXISTS idx_m0_mutation_log_session ON m0_mutation_log(session_id);
|
|
37462
|
+
|
|
37463
|
+
CREATE TABLE IF NOT EXISTS v22_identity_rekey_map (
|
|
37464
|
+
old_project_path TEXT PRIMARY KEY,
|
|
37465
|
+
new_project_path TEXT NOT NULL,
|
|
37466
|
+
rekeyed_at INTEGER NOT NULL
|
|
37467
|
+
);
|
|
37468
|
+
|
|
37469
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
37470
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37471
|
+
name TEXT NOT NULL UNIQUE,
|
|
37472
|
+
created_at INTEGER NOT NULL,
|
|
37473
|
+
updated_at INTEGER NOT NULL,
|
|
37474
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
37475
|
+
);
|
|
37476
|
+
|
|
37477
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
37478
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
37479
|
+
project_path TEXT NOT NULL,
|
|
37480
|
+
display_name TEXT NOT NULL,
|
|
37481
|
+
display_path TEXT NOT NULL,
|
|
37482
|
+
added_at INTEGER NOT NULL,
|
|
37483
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
37484
|
+
);
|
|
37485
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
37486
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
37487
|
+
|
|
37488
|
+
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
37489
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37490
|
+
table_name TEXT NOT NULL,
|
|
37491
|
+
row_id INTEGER NOT NULL,
|
|
37492
|
+
raw_project_path TEXT NOT NULL,
|
|
37493
|
+
error_class TEXT NOT NULL CHECK (error_class IN ('not_git_repo', 'git_missing', 'git_timeout', 'permission_denied', 'unknown')),
|
|
37494
|
+
error_message TEXT,
|
|
37495
|
+
failed_at INTEGER NOT NULL,
|
|
37496
|
+
UNIQUE(table_name, row_id)
|
|
37497
|
+
);
|
|
37498
|
+
|
|
37499
|
+
-- (smart_notes: see note above; merged into unified notes table by migration v1)
|
|
37500
|
+
|
|
37501
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
37502
|
+
content,
|
|
37503
|
+
category,
|
|
37504
|
+
content='memories',
|
|
37505
|
+
content_rowid='id',
|
|
37506
|
+
tokenize='porter unicode61'
|
|
37507
|
+
);
|
|
37508
|
+
|
|
37509
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS message_history_fts USING fts5(
|
|
37510
|
+
session_id UNINDEXED,
|
|
37511
|
+
message_ordinal UNINDEXED,
|
|
37512
|
+
message_id UNINDEXED,
|
|
37513
|
+
role,
|
|
37514
|
+
content,
|
|
37515
|
+
tokenize='porter unicode61'
|
|
37516
|
+
);
|
|
37517
|
+
|
|
37518
|
+
CREATE TABLE IF NOT EXISTS message_history_index (
|
|
37519
|
+
session_id TEXT PRIMARY KEY,
|
|
37520
|
+
last_indexed_ordinal INTEGER NOT NULL DEFAULT 0,
|
|
37521
|
+
dirty_floor_ordinal INTEGER NOT NULL DEFAULT 0,
|
|
37522
|
+
updated_at INTEGER NOT NULL,
|
|
37523
|
+
harness TEXT NOT NULL DEFAULT 'opencode'
|
|
37524
|
+
);
|
|
37525
|
+
CREATE INDEX IF NOT EXISTS idx_message_history_index_orphan_sweep
|
|
37526
|
+
ON message_history_index(harness, session_id, updated_at);
|
|
37527
|
+
|
|
37528
|
+
CREATE TABLE IF NOT EXISTS message_history_source (
|
|
37529
|
+
session_id TEXT NOT NULL,
|
|
37530
|
+
message_id TEXT NOT NULL,
|
|
37531
|
+
message_ordinal INTEGER NOT NULL,
|
|
37532
|
+
source_version TEXT NOT NULL,
|
|
37533
|
+
normalized_content_hash TEXT NOT NULL,
|
|
37534
|
+
role TEXT NOT NULL,
|
|
37535
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37536
|
+
updated_at INTEGER NOT NULL,
|
|
37537
|
+
PRIMARY KEY(session_id, message_id)
|
|
37538
|
+
);
|
|
37539
|
+
CREATE INDEX IF NOT EXISTS idx_message_history_source_session_ordinal
|
|
37540
|
+
ON message_history_source(session_id, message_ordinal);
|
|
37541
|
+
|
|
37542
|
+
CREATE TABLE IF NOT EXISTS pending_session_cleanup (
|
|
37543
|
+
session_id TEXT PRIMARY KEY,
|
|
37544
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37545
|
+
requested_at INTEGER NOT NULL,
|
|
37546
|
+
last_attempt_at INTEGER
|
|
37547
|
+
);
|
|
37548
|
+
|
|
37549
|
+
CREATE TABLE IF NOT EXISTS message_history_orphan_sweep (
|
|
37550
|
+
harness TEXT PRIMARY KEY,
|
|
37551
|
+
cursor_session_id TEXT NOT NULL DEFAULT '',
|
|
37552
|
+
last_swept_at INTEGER
|
|
37553
|
+
);
|
|
37554
|
+
|
|
37555
|
+
CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
|
|
37556
|
+
INSERT INTO memories_fts(rowid, content, category) VALUES (new.id, new.content, new.category);
|
|
37557
|
+
END;
|
|
37558
|
+
|
|
37559
|
+
CREATE TRIGGER IF NOT EXISTS memories_ad AFTER DELETE ON memories BEGIN
|
|
37560
|
+
INSERT INTO memories_fts(memories_fts, rowid, content, category) VALUES ('delete', old.id, old.content, old.category);
|
|
37561
|
+
END;
|
|
37562
|
+
|
|
37563
|
+
CREATE TRIGGER IF NOT EXISTS memories_au AFTER UPDATE ON memories BEGIN
|
|
37564
|
+
INSERT INTO memories_fts(memories_fts, rowid, content, category) VALUES ('delete', old.id, old.content, old.category);
|
|
37565
|
+
INSERT INTO memories_fts(rowid, content, category) VALUES (new.id, new.content, new.category);
|
|
37566
|
+
END;
|
|
37567
|
+
|
|
37568
|
+
CREATE TABLE IF NOT EXISTS session_meta (
|
|
37569
|
+
session_id TEXT PRIMARY KEY,
|
|
37570
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37571
|
+
last_response_time INTEGER,
|
|
37572
|
+
cache_ttl TEXT,
|
|
37573
|
+
counter INTEGER DEFAULT 0,
|
|
37574
|
+
last_nudge_tokens INTEGER DEFAULT 0,
|
|
37575
|
+
last_nudge_band TEXT DEFAULT '',
|
|
37576
|
+
last_nudge_undropped INTEGER DEFAULT 0,
|
|
37577
|
+
last_nudge_level TEXT DEFAULT '',
|
|
37578
|
+
channel2_nudge_state TEXT DEFAULT '',
|
|
37579
|
+
channel2_nudge_claimed_at INTEGER DEFAULT 0,
|
|
37580
|
+
channel2_nudge_claim_token TEXT DEFAULT '',
|
|
37581
|
+
last_emergency_input_sample INTEGER DEFAULT 0,
|
|
37582
|
+
last_transform_error TEXT DEFAULT '',
|
|
37583
|
+
nudge_anchor_message_id TEXT DEFAULT '',
|
|
37584
|
+
nudge_anchor_text TEXT DEFAULT '',
|
|
37585
|
+
sticky_turn_reminder_text TEXT DEFAULT '',
|
|
37586
|
+
sticky_turn_reminder_message_id TEXT DEFAULT '',
|
|
37587
|
+
note_nudge_trigger_pending INTEGER DEFAULT 0,
|
|
37588
|
+
note_nudge_trigger_message_id TEXT DEFAULT '',
|
|
37589
|
+
note_nudge_sticky_text TEXT DEFAULT '',
|
|
37590
|
+
note_nudge_sticky_message_id TEXT DEFAULT '',
|
|
37591
|
+
note_nudge_anchors TEXT NOT NULL DEFAULT '[]',
|
|
37592
|
+
auto_search_hint_decisions TEXT NOT NULL DEFAULT '[]',
|
|
37593
|
+
last_todo_state TEXT DEFAULT '',
|
|
37594
|
+
todo_permission_denied INTEGER NOT NULL DEFAULT 2,
|
|
37595
|
+
todo_synthetic_call_id TEXT DEFAULT '',
|
|
37596
|
+
todo_synthetic_anchor_message_id TEXT DEFAULT '',
|
|
37597
|
+
todo_synthetic_state_json TEXT DEFAULT '',
|
|
37598
|
+
is_subagent INTEGER DEFAULT 0,
|
|
37599
|
+
last_context_percentage REAL DEFAULT 0,
|
|
37600
|
+
last_input_tokens INTEGER DEFAULT 0,
|
|
37601
|
+
detected_context_limit_provenance TEXT NOT NULL DEFAULT 'unknown',
|
|
37602
|
+
observed_safe_input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
37603
|
+
cache_alert_sent INTEGER NOT NULL DEFAULT 0,
|
|
37604
|
+
times_execute_threshold_reached INTEGER DEFAULT 0,
|
|
37605
|
+
compartment_in_progress INTEGER DEFAULT 0,
|
|
37606
|
+
historian_failure_count INTEGER DEFAULT 0,
|
|
37607
|
+
historian_last_error TEXT DEFAULT NULL,
|
|
37608
|
+
historian_last_failure_at INTEGER DEFAULT NULL,
|
|
37609
|
+
system_prompt_hash TEXT DEFAULT '',
|
|
37610
|
+
memory_block_cache TEXT DEFAULT '',
|
|
37611
|
+
memory_block_count INTEGER DEFAULT 0,
|
|
37612
|
+
memory_block_ids TEXT DEFAULT '',
|
|
37613
|
+
-- pending_compaction_marker_state: intentionally NULLABLE without a
|
|
37614
|
+
-- default. Absence of a deferred marker is SQL NULL; presence is a
|
|
37615
|
+
-- valid JSON blob written via setPendingCompactionMarkerState.
|
|
37616
|
+
-- Excluded from the healAllNullColumns fallback list. Readers filter
|
|
37617
|
+
-- IS NOT NULL AND != empty-string defensively. Plan v6 section 3.
|
|
37618
|
+
pending_compaction_marker_state TEXT,
|
|
37619
|
+
-- Target OpenCode message id used to inject the current compaction marker.
|
|
37620
|
+
-- Nullable for legacy persisted markers; repaired on the next marker move.
|
|
37621
|
+
compaction_marker_target_end_message_id TEXT,
|
|
37622
|
+
-- pending_pi_compaction_marker_state: intentionally NULLABLE without a
|
|
37623
|
+
-- default. Absence of a deferred Pi-native marker is SQL NULL; presence
|
|
37624
|
+
-- is a valid JSON blob written via setPendingPiCompactionMarkerState.
|
|
37625
|
+
-- Excluded from the healAllNullColumns fallback list.
|
|
37626
|
+
pending_pi_compaction_marker_state TEXT,
|
|
37627
|
+
new_work_tokens INTEGER NOT NULL DEFAULT 0,
|
|
37628
|
+
total_input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
37629
|
+
-- deferred_execute_state: intentionally NULLABLE without a default.
|
|
37630
|
+
-- Absence is SQL NULL; presence is a JSON blob written via
|
|
37631
|
+
-- setDeferredExecutePendingIfAbsent. Excluded from the
|
|
37632
|
+
-- healAllNullColumns fallback list.
|
|
37633
|
+
deferred_execute_state TEXT,
|
|
37634
|
+
cached_m0_bytes BLOB,
|
|
37635
|
+
cached_m0_project_memory_epoch INTEGER,
|
|
37636
|
+
cached_m0_workspace_fingerprint TEXT,
|
|
37637
|
+
cached_m0_project_user_profile_version INTEGER,
|
|
37638
|
+
cached_m0_max_compartment_seq INTEGER,
|
|
37639
|
+
cached_m0_max_memory_id INTEGER,
|
|
37640
|
+
cached_m0_max_mutation_id INTEGER,
|
|
37641
|
+
cached_m0_max_memory_mutation_id INTEGER,
|
|
37642
|
+
cached_m0_project_docs_hash TEXT,
|
|
37643
|
+
cached_m1_bytes BLOB,
|
|
37644
|
+
last_observed_model_key TEXT,
|
|
37645
|
+
last_usage_context_limit INTEGER NOT NULL DEFAULT 0,
|
|
37646
|
+
prior_boundary_ordinal INTEGER NOT NULL DEFAULT 1,
|
|
37647
|
+
protected_tail_policy_version INTEGER NOT NULL DEFAULT 0,
|
|
37648
|
+
protected_tail_drain_window_started_at INTEGER NOT NULL DEFAULT 0,
|
|
37649
|
+
protected_tail_drain_tokens INTEGER NOT NULL DEFAULT 0,
|
|
37650
|
+
recovery_no_eligible_head_count INTEGER NOT NULL DEFAULT 0,
|
|
37651
|
+
force_emergency_bypass_window_start INTEGER NOT NULL DEFAULT 0,
|
|
37652
|
+
force_emergency_bypass_used INTEGER NOT NULL DEFAULT 0,
|
|
37653
|
+
emergency_drain_active INTEGER NOT NULL DEFAULT 0,
|
|
37654
|
+
historian_drain_failure_at INTEGER NOT NULL DEFAULT 0,
|
|
37655
|
+
wrapup_in_progress_state TEXT,
|
|
37656
|
+
compaction_mode_record TEXT,
|
|
37657
|
+
cached_m0_materialized_at INTEGER,
|
|
37658
|
+
cached_m0_session_facts_version INTEGER,
|
|
37659
|
+
cached_m0_upgrade_state TEXT,
|
|
37660
|
+
cached_m0_system_hash TEXT,
|
|
37661
|
+
cached_m0_tool_set_hash TEXT,
|
|
37662
|
+
cached_m0_model_key TEXT,
|
|
37663
|
+
cached_m0_project_identity TEXT,
|
|
37664
|
+
cached_m0_last_baseline_end_message_id TEXT,
|
|
37665
|
+
upgrade_reminded_at INTEGER,
|
|
37666
|
+
pi_stable_id_scheme INTEGER
|
|
37667
|
+
);
|
|
37668
|
+
|
|
37669
|
+
CREATE TABLE IF NOT EXISTS tool_owner_backfill_state (
|
|
37670
|
+
session_id TEXT PRIMARY KEY,
|
|
37671
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'running', 'completed', 'skipped')),
|
|
37672
|
+
started_at INTEGER,
|
|
37673
|
+
lease_expires_at INTEGER,
|
|
37674
|
+
completed_at INTEGER,
|
|
37675
|
+
last_error TEXT
|
|
37676
|
+
);
|
|
37677
|
+
CREATE INDEX IF NOT EXISTS idx_tool_owner_backfill_state_status
|
|
37678
|
+
ON tool_owner_backfill_state(status);
|
|
37679
|
+
|
|
37680
|
+
CREATE TABLE IF NOT EXISTS subagent_invocations (
|
|
37681
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37682
|
+
session_id TEXT NOT NULL,
|
|
37683
|
+
harness TEXT NOT NULL,
|
|
37684
|
+
subagent TEXT NOT NULL,
|
|
37685
|
+
task TEXT,
|
|
37686
|
+
provider_id TEXT,
|
|
37687
|
+
model_id TEXT,
|
|
37688
|
+
started_at INTEGER NOT NULL,
|
|
37689
|
+
ended_at INTEGER,
|
|
37690
|
+
status TEXT NOT NULL,
|
|
37691
|
+
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
37692
|
+
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
37693
|
+
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
|
|
37694
|
+
cache_write_tokens INTEGER NOT NULL DEFAULT 0,
|
|
37695
|
+
error TEXT,
|
|
37696
|
+
parent_invocation_id INTEGER
|
|
37697
|
+
);
|
|
37698
|
+
CREATE INDEX IF NOT EXISTS idx_sai_session_started
|
|
37699
|
+
ON subagent_invocations(session_id, started_at DESC);
|
|
37700
|
+
CREATE INDEX IF NOT EXISTS idx_sai_subagent
|
|
37701
|
+
ON subagent_invocations(subagent, started_at DESC);
|
|
37702
|
+
|
|
37703
|
+
CREATE TABLE IF NOT EXISTS historian_runs (
|
|
37704
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37705
|
+
session_id TEXT NOT NULL,
|
|
37706
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37707
|
+
subagent_invocation_id INTEGER,
|
|
37708
|
+
run_kind TEXT NOT NULL,
|
|
37709
|
+
status TEXT NOT NULL,
|
|
37710
|
+
failure_reason TEXT,
|
|
37711
|
+
chunk_start_ordinal INTEGER,
|
|
37712
|
+
chunk_end_ordinal INTEGER,
|
|
37713
|
+
unprocessed_from INTEGER,
|
|
37714
|
+
compartments_produced INTEGER NOT NULL DEFAULT 0,
|
|
37715
|
+
compartment_id_min INTEGER,
|
|
37716
|
+
compartment_id_max INTEGER,
|
|
37717
|
+
facts_emitted INTEGER NOT NULL DEFAULT 0,
|
|
37718
|
+
facts_by_category_json TEXT,
|
|
37719
|
+
events_emitted INTEGER NOT NULL DEFAULT 0,
|
|
37720
|
+
importance_min INTEGER,
|
|
37721
|
+
importance_max INTEGER,
|
|
37722
|
+
importance_avg REAL,
|
|
37723
|
+
discarded_last INTEGER NOT NULL DEFAULT 0,
|
|
37724
|
+
legacy INTEGER NOT NULL DEFAULT 0,
|
|
37725
|
+
created_at INTEGER NOT NULL
|
|
37726
|
+
);
|
|
37727
|
+
CREATE INDEX IF NOT EXISTS idx_historian_runs_session
|
|
37728
|
+
ON historian_runs(session_id, created_at DESC);
|
|
37729
|
+
CREATE INDEX IF NOT EXISTS idx_historian_runs_status
|
|
37730
|
+
ON historian_runs(status, created_at DESC);
|
|
37731
|
+
|
|
37732
|
+
CREATE TABLE IF NOT EXISTS transform_decisions (
|
|
37733
|
+
session_id TEXT NOT NULL,
|
|
37734
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37735
|
+
message_id TEXT NOT NULL,
|
|
37736
|
+
ts_ms INTEGER NOT NULL,
|
|
37737
|
+
decision TEXT NOT NULL,
|
|
37738
|
+
materialized INTEGER NOT NULL DEFAULT 0,
|
|
37739
|
+
materialize_reason TEXT,
|
|
37740
|
+
emergency INTEGER NOT NULL DEFAULT 0,
|
|
37741
|
+
dropped_tokens INTEGER NOT NULL DEFAULT 0,
|
|
37742
|
+
dropped_count INTEGER NOT NULL DEFAULT 0,
|
|
37743
|
+
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
37744
|
+
PRIMARY KEY (session_id, harness, message_id)
|
|
37745
|
+
);
|
|
37746
|
+
CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
|
|
37747
|
+
ON transform_decisions(session_id, harness);
|
|
37748
|
+
|
|
37749
|
+
CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
|
|
37750
|
+
CREATE INDEX IF NOT EXISTS idx_tags_session_message_id ON tags(session_id, message_id);
|
|
37751
|
+
CREATE INDEX IF NOT EXISTS idx_pending_ops_session ON pending_ops(session_id);
|
|
37752
|
+
CREATE INDEX IF NOT EXISTS idx_pending_ops_session_tag_id ON pending_ops(session_id, tag_id);
|
|
37753
|
+
CREATE INDEX IF NOT EXISTS idx_source_contents_session ON source_contents(session_id);
|
|
37754
|
+
|
|
37755
|
+
CREATE TABLE IF NOT EXISTS recomp_compartments (
|
|
37756
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37757
|
+
session_id TEXT NOT NULL,
|
|
37758
|
+
sequence INTEGER NOT NULL,
|
|
37759
|
+
start_message INTEGER NOT NULL,
|
|
37760
|
+
end_message INTEGER NOT NULL,
|
|
37761
|
+
start_message_id TEXT DEFAULT '',
|
|
37762
|
+
end_message_id TEXT DEFAULT '',
|
|
37763
|
+
title TEXT NOT NULL,
|
|
37764
|
+
content TEXT NOT NULL,
|
|
37765
|
+
p1 TEXT,
|
|
37766
|
+
p2 TEXT,
|
|
37767
|
+
p3 TEXT,
|
|
37768
|
+
p4 TEXT,
|
|
37769
|
+
importance INTEGER NOT NULL DEFAULT 50,
|
|
37770
|
+
episode_type TEXT,
|
|
37771
|
+
pass_number INTEGER NOT NULL,
|
|
37772
|
+
created_at INTEGER NOT NULL,
|
|
37773
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37774
|
+
UNIQUE(session_id, sequence)
|
|
37775
|
+
);
|
|
37776
|
+
|
|
37777
|
+
CREATE TABLE IF NOT EXISTS recomp_facts (
|
|
37778
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37779
|
+
session_id TEXT NOT NULL,
|
|
37780
|
+
category TEXT NOT NULL,
|
|
37781
|
+
content TEXT NOT NULL,
|
|
37782
|
+
pass_number INTEGER NOT NULL,
|
|
37783
|
+
created_at INTEGER NOT NULL,
|
|
37784
|
+
harness TEXT NOT NULL DEFAULT 'opencode'
|
|
37785
|
+
);
|
|
37786
|
+
|
|
37787
|
+
CREATE INDEX IF NOT EXISTS idx_session_facts_session ON session_facts(session_id);
|
|
37788
|
+
CREATE INDEX IF NOT EXISTS idx_recomp_compartments_session ON recomp_compartments(session_id);
|
|
37789
|
+
CREATE INDEX IF NOT EXISTS idx_recomp_facts_session ON recomp_facts(session_id);
|
|
37790
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_status_category ON memories(project_path, status, category);
|
|
37791
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_status_expires ON memories(project_path, status, expires_at);
|
|
37792
|
+
CREATE INDEX IF NOT EXISTS idx_memories_project_category_hash ON memories(project_path, category, normalized_hash);
|
|
37793
|
+
CREATE INDEX IF NOT EXISTS idx_message_history_index_updated_at ON message_history_index(updated_at);
|
|
37794
|
+
`);
|
|
37795
|
+
ensureColumn(db, "primer_candidates", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
37796
|
+
ensureColumn(db, "primer_candidates", "source_start_message_id", "TEXT NOT NULL DEFAULT ''");
|
|
37797
|
+
ensureColumn(db, "primer_candidates", "source_end_message_id", "TEXT NOT NULL DEFAULT ''");
|
|
37798
|
+
ensureColumn(db, "primer_candidates", "question_embedding", "BLOB");
|
|
37799
|
+
ensureColumn(db, "primer_candidates", "question_embedding_model_id", "TEXT");
|
|
37800
|
+
ensureColumn(db, "primers", "question_embedding_model_id", "TEXT");
|
|
37801
|
+
db.exec(`
|
|
37802
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_primer_candidates_occurrence
|
|
37803
|
+
ON primer_candidates(project_path, harness, session_id, source_start_message_id, source_end_message_id);
|
|
37804
|
+
CREATE INDEX IF NOT EXISTS idx_primer_candidates_project_time
|
|
37805
|
+
ON primer_candidates(project_path, source_message_time);
|
|
37806
|
+
CREATE INDEX IF NOT EXISTS idx_primer_candidates_session
|
|
37807
|
+
ON primer_candidates(session_id, harness);
|
|
37808
|
+
CREATE INDEX IF NOT EXISTS idx_primer_candidates_embedding_model
|
|
37809
|
+
ON primer_candidates(project_path, question_embedding_model_id);
|
|
37810
|
+
CREATE INDEX IF NOT EXISTS idx_primers_project_status_observed
|
|
37811
|
+
ON primers(project_path, status, last_observed_at DESC);
|
|
37812
|
+
CREATE INDEX IF NOT EXISTS idx_primers_embedding_model
|
|
37813
|
+
ON primers(project_path, question_embedding_model_id);
|
|
37814
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS primers_fts USING fts5(
|
|
37815
|
+
question,
|
|
37816
|
+
answer,
|
|
37817
|
+
project_path UNINDEXED,
|
|
37818
|
+
content='primers',
|
|
37819
|
+
content_rowid='id',
|
|
37820
|
+
tokenize='porter unicode61'
|
|
37821
|
+
);
|
|
37822
|
+
CREATE TRIGGER IF NOT EXISTS primers_ai AFTER INSERT ON primers BEGIN
|
|
37823
|
+
INSERT INTO primers_fts(rowid, question, answer, project_path)
|
|
37824
|
+
VALUES (new.id, new.question, new.answer, new.project_path);
|
|
37825
|
+
END;
|
|
37826
|
+
CREATE TRIGGER IF NOT EXISTS primers_ad AFTER DELETE ON primers BEGIN
|
|
37827
|
+
INSERT INTO primers_fts(primers_fts, rowid, question, answer, project_path)
|
|
37828
|
+
VALUES ('delete', old.id, old.question, old.answer, old.project_path);
|
|
37829
|
+
END;
|
|
37830
|
+
CREATE TRIGGER IF NOT EXISTS primers_au AFTER UPDATE ON primers BEGIN
|
|
37831
|
+
INSERT INTO primers_fts(primers_fts, rowid, question, answer, project_path)
|
|
37832
|
+
VALUES ('delete', old.id, old.question, old.answer, old.project_path);
|
|
37833
|
+
INSERT INTO primers_fts(rowid, question, answer, project_path)
|
|
37834
|
+
VALUES (new.id, new.question, new.answer, new.project_path);
|
|
37835
|
+
END;
|
|
37836
|
+
`);
|
|
37837
|
+
ensureColumn(db, "session_meta", "last_nudge_band", "TEXT DEFAULT ''");
|
|
37838
|
+
ensureColumn(db, "session_meta", "last_nudge_undropped", "INTEGER DEFAULT 0");
|
|
37839
|
+
ensureColumn(db, "session_meta", "last_nudge_level", "TEXT DEFAULT ''");
|
|
37840
|
+
ensureColumn(db, "session_meta", "channel2_nudge_state", "TEXT DEFAULT ''");
|
|
37841
|
+
ensureColumn(db, "session_meta", "channel2_nudge_claimed_at", "INTEGER DEFAULT 0");
|
|
37842
|
+
ensureColumn(db, "session_meta", "channel2_nudge_claim_token", "TEXT DEFAULT ''");
|
|
37843
|
+
ensureColumn(db, "session_meta", "last_emergency_input_sample", "INTEGER DEFAULT 0");
|
|
37844
|
+
ensureColumn(db, "session_meta", "last_transform_error", "TEXT DEFAULT ''");
|
|
37845
|
+
ensureColumn(db, "session_meta", "nudge_anchor_message_id", "TEXT DEFAULT ''");
|
|
37846
|
+
ensureColumn(db, "session_meta", "nudge_anchor_text", "TEXT DEFAULT ''");
|
|
37847
|
+
ensureColumn(db, "session_meta", "sticky_turn_reminder_text", "TEXT DEFAULT ''");
|
|
37848
|
+
ensureColumn(db, "session_meta", "sticky_turn_reminder_message_id", "TEXT DEFAULT ''");
|
|
37849
|
+
ensureColumn(db, "session_meta", "note_nudge_trigger_pending", "INTEGER DEFAULT 0");
|
|
37850
|
+
ensureColumn(db, "session_meta", "note_nudge_trigger_message_id", "TEXT DEFAULT ''");
|
|
37851
|
+
ensureColumn(db, "session_meta", "note_nudge_sticky_text", "TEXT DEFAULT ''");
|
|
37852
|
+
ensureColumn(db, "session_meta", "note_nudge_sticky_message_id", "TEXT DEFAULT ''");
|
|
37853
|
+
ensureColumn(db, "session_meta", "note_nudge_anchors", "TEXT NOT NULL DEFAULT '[]'");
|
|
37854
|
+
ensureColumn(db, "session_meta", "auto_search_hint_decisions", "TEXT NOT NULL DEFAULT '[]'");
|
|
37855
|
+
ensureColumn(db, "session_meta", "last_todo_state", "TEXT DEFAULT ''");
|
|
37856
|
+
ensureColumn(db, "session_meta", "todo_permission_denied", "INTEGER NOT NULL DEFAULT 2");
|
|
37857
|
+
ensureColumn(db, "session_meta", "todo_synthetic_call_id", "TEXT DEFAULT ''");
|
|
37858
|
+
ensureColumn(db, "session_meta", "todo_synthetic_anchor_message_id", "TEXT DEFAULT ''");
|
|
37859
|
+
ensureColumn(db, "session_meta", "todo_synthetic_state_json", "TEXT DEFAULT ''");
|
|
37860
|
+
ensureColumn(db, "session_meta", "note_last_read_at", "INTEGER DEFAULT 0");
|
|
37861
|
+
ensureColumn(db, "session_meta", "times_execute_threshold_reached", "INTEGER DEFAULT 0");
|
|
37862
|
+
ensureColumn(db, "session_meta", "observed_safe_input_tokens", "INTEGER NOT NULL DEFAULT 0");
|
|
37863
|
+
ensureColumn(db, "session_meta", "cache_alert_sent", "INTEGER NOT NULL DEFAULT 0");
|
|
37864
|
+
ensureColumn(db, "session_meta", "compartment_in_progress", "INTEGER DEFAULT 0");
|
|
37865
|
+
ensureColumn(db, "session_meta", "historian_failure_count", "INTEGER DEFAULT 0");
|
|
37866
|
+
ensureColumn(db, "session_meta", "historian_last_error", "TEXT DEFAULT NULL");
|
|
37867
|
+
ensureColumn(db, "session_meta", "historian_last_failure_at", "INTEGER DEFAULT NULL");
|
|
37868
|
+
ensureColumn(db, "session_meta", "system_prompt_hash", "TEXT DEFAULT ''");
|
|
37869
|
+
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
37870
|
+
ensureColumn(db, "session_meta", "tool_reclaim_watermark", "INTEGER DEFAULT 0");
|
|
37871
|
+
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
37872
|
+
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
37873
|
+
ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
|
|
37874
|
+
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
37875
|
+
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
37876
|
+
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
37877
|
+
ensureColumn(db, "session_meta", "memory_block_cache", "TEXT DEFAULT ''");
|
|
37878
|
+
ensureColumn(db, "session_meta", "memory_block_count", "INTEGER DEFAULT 0");
|
|
37879
|
+
ensureColumn(db, "session_meta", "pi_stable_id_scheme", "INTEGER");
|
|
37880
|
+
ensureColumn(db, "session_meta", "memory_block_ids", "TEXT DEFAULT ''");
|
|
37881
|
+
ensureColumn(db, "dream_queue", "retry_count", "INTEGER DEFAULT 0");
|
|
37882
|
+
ensureColumn(db, "tags", "reasoning_byte_size", "INTEGER DEFAULT 0");
|
|
37883
|
+
ensureColumn(db, "tags", "drop_mode", "TEXT DEFAULT 'full'");
|
|
37884
|
+
ensureColumn(db, "tags", "tool_name", "TEXT");
|
|
37885
|
+
ensureColumn(db, "tags", "input_byte_size", "INTEGER DEFAULT 0");
|
|
37886
|
+
ensureColumn(db, "tags", "caveman_depth", "INTEGER DEFAULT 0");
|
|
37887
|
+
ensureColumn(db, "tags", "tool_owner_message_id", "TEXT DEFAULT NULL");
|
|
37888
|
+
ensureColumn(db, "tags", "entry_fingerprint", "TEXT");
|
|
37889
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_tags_pi_adopt
|
|
37890
|
+
ON tags(session_id, entry_fingerprint)
|
|
37891
|
+
WHERE type='message' AND entry_fingerprint IS NOT NULL`);
|
|
37892
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_tags_pi_fallback_tool_owner
|
|
37893
|
+
ON tags(session_id, tool_owner_message_id)
|
|
37894
|
+
WHERE type='tool'`);
|
|
37895
|
+
ensureColumn(db, "tags", "token_count", "INTEGER");
|
|
37896
|
+
ensureColumn(db, "tags", "input_token_count", "INTEGER");
|
|
37897
|
+
ensureColumn(db, "tags", "reasoning_token_count", "INTEGER");
|
|
37898
|
+
ensureColumn(db, "task_schedule_state", "schedule", "TEXT");
|
|
37899
|
+
ensureColumn(db, "task_schedule_state", "last_checked_commit", "TEXT");
|
|
37900
|
+
ensureColumn(db, "task_schedule_state", "last_broad_run_at", "INTEGER");
|
|
37901
|
+
ensureColumn(db, "task_schedule_state", "retrospective_watermark_ms", "INTEGER");
|
|
37902
|
+
ensureColumn(db, "dream_runs", "parent_session_id", "TEXT");
|
|
37903
|
+
ensureColumn(db, "session_meta", "system_prompt_tokens", "INTEGER DEFAULT 0");
|
|
37904
|
+
ensureColumn(db, "session_meta", "compaction_marker_state", "TEXT DEFAULT ''");
|
|
37905
|
+
ensureColumn(db, "session_meta", "compaction_marker_target_end_message_id", "TEXT");
|
|
37906
|
+
ensureColumn(db, "session_meta", "key_files", "TEXT DEFAULT ''");
|
|
37907
|
+
ensureColumn(db, "session_meta", "conversation_tokens", "INTEGER DEFAULT 0");
|
|
37908
|
+
ensureColumn(db, "session_meta", "tool_call_tokens", "INTEGER DEFAULT 0");
|
|
37909
|
+
ensureColumn(db, "session_meta", "recomp_partial_range_start", "INTEGER DEFAULT 0");
|
|
37910
|
+
ensureColumn(db, "session_meta", "recomp_partial_range_end", "INTEGER DEFAULT 0");
|
|
37911
|
+
ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
|
|
37912
|
+
ensureColumn(db, "session_meta", "detected_context_limit_model_key", "TEXT");
|
|
37913
|
+
ensureColumn(db, "session_meta", "detected_context_limit_provenance", "TEXT NOT NULL DEFAULT 'unknown'");
|
|
37914
|
+
ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
|
|
37915
|
+
ensureColumn(db, "session_meta", "emergency_recovery_origin", "TEXT DEFAULT ''");
|
|
37916
|
+
ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
|
|
37917
|
+
ensureColumn(db, "session_meta", "pending_pi_compaction_marker_state", "TEXT");
|
|
37918
|
+
ensureColumn(db, "session_meta", "new_work_tokens", "INTEGER NOT NULL DEFAULT 0");
|
|
37919
|
+
ensureColumn(db, "session_meta", "total_input_tokens", "INTEGER NOT NULL DEFAULT 0");
|
|
37920
|
+
ensureColumn(db, "session_meta", "deferred_execute_state", "TEXT");
|
|
37921
|
+
ensureColumn(db, "compartments", "p1", "TEXT");
|
|
37922
|
+
ensureColumn(db, "compartments", "p2", "TEXT");
|
|
37923
|
+
ensureColumn(db, "compartments", "p3", "TEXT");
|
|
37924
|
+
ensureColumn(db, "compartments", "p4", "TEXT");
|
|
37925
|
+
ensureColumn(db, "compartments", "importance", "INTEGER NOT NULL DEFAULT 50");
|
|
37926
|
+
ensureColumn(db, "compartments", "episode_type", "TEXT");
|
|
37927
|
+
ensureColumn(db, "compartments", "p1_embedding", "BLOB");
|
|
37928
|
+
ensureColumn(db, "compartments", "p1_embedding_model_id", "TEXT");
|
|
37929
|
+
ensureColumn(db, "compartments", "legacy", "INTEGER NOT NULL DEFAULT 0");
|
|
37930
|
+
ensureColumn(db, "recomp_compartments", "p1", "TEXT");
|
|
37931
|
+
ensureColumn(db, "recomp_compartments", "p2", "TEXT");
|
|
37932
|
+
ensureColumn(db, "recomp_compartments", "p3", "TEXT");
|
|
37933
|
+
ensureColumn(db, "recomp_compartments", "p4", "TEXT");
|
|
37934
|
+
ensureColumn(db, "recomp_compartments", "importance", "INTEGER NOT NULL DEFAULT 50");
|
|
37935
|
+
ensureColumn(db, "recomp_compartments", "episode_type", "TEXT");
|
|
37936
|
+
ensureColumn(db, "memories", "importance", "INTEGER");
|
|
37937
|
+
ensureColumn(db, "memories", "classified_at", "INTEGER");
|
|
37938
|
+
ensureColumn(db, "memories", "mural_cue", "TEXT");
|
|
37939
|
+
ensureColumn(db, "memories", "mural_cue_hash", "TEXT");
|
|
37940
|
+
ensureColumn(db, "memories", "mural_cue_at", "INTEGER");
|
|
37941
|
+
ensureColumn(db, "memory_verifications", "mapped_at", "INTEGER NOT NULL DEFAULT 0");
|
|
37942
|
+
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
37943
|
+
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
37944
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
37945
|
+
ensureColumn(db, "session_meta", "cached_m0_project_user_profile_version", "INTEGER");
|
|
37946
|
+
ensureColumn(db, "session_meta", "cached_m0_max_compartment_seq", "INTEGER");
|
|
37947
|
+
ensureColumn(db, "session_meta", "cached_m0_max_memory_id", "INTEGER");
|
|
37948
|
+
ensureColumn(db, "session_meta", "cached_m0_max_mutation_id", "INTEGER");
|
|
37949
|
+
ensureColumn(db, "session_meta", "cached_m0_max_memory_mutation_id", "INTEGER");
|
|
37950
|
+
ensureColumn(db, "session_meta", "cached_m0_project_docs_hash", "TEXT");
|
|
37951
|
+
ensureColumn(db, "session_meta", "cached_m1_bytes", "BLOB");
|
|
37952
|
+
ensureColumn(db, "session_meta", "last_observed_model_key", "TEXT");
|
|
37953
|
+
ensureColumn(db, "session_meta", "last_usage_context_limit", "INTEGER NOT NULL DEFAULT 0");
|
|
37954
|
+
ensureColumn(db, "session_meta", "prior_boundary_ordinal", "INTEGER NOT NULL DEFAULT 1");
|
|
37955
|
+
ensureColumn(db, "session_meta", "protected_tail_policy_version", "INTEGER NOT NULL DEFAULT 0");
|
|
37956
|
+
ensureColumn(db, "session_meta", "protected_tail_drain_window_started_at", "INTEGER NOT NULL DEFAULT 0");
|
|
37957
|
+
ensureColumn(db, "session_meta", "protected_tail_drain_tokens", "INTEGER NOT NULL DEFAULT 0");
|
|
37958
|
+
ensureColumn(db, "session_meta", "recovery_no_eligible_head_count", "INTEGER NOT NULL DEFAULT 0");
|
|
37959
|
+
ensureColumn(db, "session_meta", "force_emergency_bypass_window_start", "INTEGER NOT NULL DEFAULT 0");
|
|
37960
|
+
ensureColumn(db, "session_meta", "force_emergency_bypass_used", "INTEGER NOT NULL DEFAULT 0");
|
|
37961
|
+
ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
|
|
37962
|
+
ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
|
|
37963
|
+
ensureColumn(db, "session_meta", "wrapup_in_progress_state", "TEXT");
|
|
37964
|
+
ensureColumn(db, "session_meta", "compaction_mode_record", "TEXT");
|
|
37965
|
+
ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
|
|
37966
|
+
ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
|
|
37967
|
+
ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
|
|
37968
|
+
ensureColumn(db, "session_meta", "cached_m0_system_hash", "TEXT");
|
|
37969
|
+
ensureColumn(db, "session_meta", "cached_m0_tool_set_hash", "TEXT");
|
|
37970
|
+
ensureColumn(db, "session_meta", "cached_m0_model_key", "TEXT");
|
|
37971
|
+
ensureColumn(db, "session_meta", "cached_m0_project_identity", "TEXT");
|
|
37972
|
+
ensureColumn(db, "session_meta", "cached_m0_last_baseline_end_message_id", "TEXT");
|
|
37973
|
+
ensureColumn(db, "session_meta", "upgrade_reminded_at", "INTEGER");
|
|
37974
|
+
ensureColumn(db, "session_meta", "upgrade_reminder_last_sent_at", "INTEGER");
|
|
37975
|
+
ensureColumn(db, "session_meta", "upgrade_reminder_count", "INTEGER NOT NULL DEFAULT 0");
|
|
37976
|
+
ensureColumn(db, "session_meta", "cached_m0_mural_data_url", "TEXT");
|
|
37977
|
+
ensureColumn(db, "session_meta", "cached_m0_mural_hash", "TEXT");
|
|
37978
|
+
db.exec(`
|
|
37979
|
+
CREATE TABLE IF NOT EXISTS project_state (
|
|
37980
|
+
project_path TEXT PRIMARY KEY,
|
|
37981
|
+
project_memory_epoch INTEGER NOT NULL DEFAULT 0,
|
|
37982
|
+
project_user_profile_version INTEGER NOT NULL DEFAULT 0,
|
|
37983
|
+
updated_at INTEGER NOT NULL DEFAULT 0
|
|
37984
|
+
);
|
|
37985
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
37986
|
+
session_id TEXT NOT NULL,
|
|
37987
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
37988
|
+
project_path TEXT NOT NULL,
|
|
37989
|
+
updated_at INTEGER NOT NULL,
|
|
37990
|
+
PRIMARY KEY(session_id, harness)
|
|
37991
|
+
);
|
|
37992
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
37993
|
+
ON session_projects(project_path);
|
|
37994
|
+
CREATE TABLE IF NOT EXISTS m0_mutation_log (
|
|
37995
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
37996
|
+
session_id TEXT NOT NULL,
|
|
37997
|
+
mutation_type TEXT NOT NULL CHECK (mutation_type IN (
|
|
37998
|
+
'compartment_delete', 'compartment_merge', 'recomp_boundary_change', 'compartment_upgrade'
|
|
37999
|
+
)),
|
|
38000
|
+
target_id INTEGER,
|
|
38001
|
+
queued_at INTEGER NOT NULL
|
|
38002
|
+
);
|
|
38003
|
+
CREATE INDEX IF NOT EXISTS idx_m0_mutation_log_session ON m0_mutation_log(session_id);
|
|
38004
|
+
CREATE TABLE IF NOT EXISTS memory_mutation_log (
|
|
38005
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
38006
|
+
project_path TEXT NOT NULL,
|
|
38007
|
+
mutation_type TEXT NOT NULL CHECK (mutation_type IN ('archive', 'delete', 'update', 'superseded')),
|
|
38008
|
+
target_memory_id INTEGER NOT NULL,
|
|
38009
|
+
superseded_by_id INTEGER,
|
|
38010
|
+
category TEXT,
|
|
38011
|
+
new_content TEXT,
|
|
38012
|
+
queued_at INTEGER NOT NULL
|
|
38013
|
+
);
|
|
38014
|
+
CREATE INDEX IF NOT EXISTS idx_memory_mutation_log_project
|
|
38015
|
+
ON memory_mutation_log(project_path, id);
|
|
38016
|
+
CREATE TABLE IF NOT EXISTS v22_identity_rekey_map (
|
|
38017
|
+
old_project_path TEXT PRIMARY KEY,
|
|
38018
|
+
new_project_path TEXT NOT NULL,
|
|
38019
|
+
rekeyed_at INTEGER NOT NULL
|
|
38020
|
+
);
|
|
38021
|
+
CREATE TABLE IF NOT EXISTS identity_merge_log (
|
|
38022
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
38023
|
+
from_identity TEXT NOT NULL,
|
|
38024
|
+
to_identity TEXT NOT NULL,
|
|
38025
|
+
table_name TEXT NOT NULL,
|
|
38026
|
+
row_id TEXT NOT NULL,
|
|
38027
|
+
action TEXT NOT NULL,
|
|
38028
|
+
target_row_id TEXT,
|
|
38029
|
+
merged_at INTEGER NOT NULL
|
|
38030
|
+
);
|
|
38031
|
+
CREATE INDEX IF NOT EXISTS idx_identity_merge_log_identities
|
|
38032
|
+
ON identity_merge_log(from_identity, to_identity, merged_at);
|
|
38033
|
+
CREATE INDEX IF NOT EXISTS idx_identity_merge_log_table_row
|
|
38034
|
+
ON identity_merge_log(table_name, row_id);
|
|
38035
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
38036
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
38037
|
+
name TEXT NOT NULL UNIQUE,
|
|
38038
|
+
created_at INTEGER NOT NULL,
|
|
38039
|
+
updated_at INTEGER NOT NULL,
|
|
38040
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
38041
|
+
);
|
|
38042
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
38043
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
38044
|
+
project_path TEXT NOT NULL,
|
|
38045
|
+
display_name TEXT NOT NULL,
|
|
38046
|
+
display_path TEXT NOT NULL,
|
|
38047
|
+
added_at INTEGER NOT NULL,
|
|
38048
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
38049
|
+
);
|
|
38050
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
38051
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
38052
|
+
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
38053
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
38054
|
+
table_name TEXT NOT NULL,
|
|
38055
|
+
row_id INTEGER NOT NULL,
|
|
38056
|
+
raw_project_path TEXT NOT NULL,
|
|
38057
|
+
error_class TEXT NOT NULL CHECK (error_class IN ('not_git_repo', 'git_missing', 'git_timeout', 'permission_denied', 'unknown')),
|
|
38058
|
+
error_message TEXT,
|
|
38059
|
+
failed_at INTEGER NOT NULL,
|
|
38060
|
+
UNIQUE(table_name, row_id)
|
|
38061
|
+
);
|
|
38062
|
+
CREATE TABLE IF NOT EXISTS transform_decisions (
|
|
38063
|
+
session_id TEXT NOT NULL,
|
|
38064
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
38065
|
+
message_id TEXT NOT NULL,
|
|
38066
|
+
ts_ms INTEGER NOT NULL,
|
|
38067
|
+
decision TEXT NOT NULL,
|
|
38068
|
+
materialized INTEGER NOT NULL DEFAULT 0,
|
|
38069
|
+
materialize_reason TEXT,
|
|
38070
|
+
emergency INTEGER NOT NULL DEFAULT 0,
|
|
38071
|
+
dropped_tokens INTEGER NOT NULL DEFAULT 0,
|
|
38072
|
+
dropped_count INTEGER NOT NULL DEFAULT 0,
|
|
38073
|
+
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
38074
|
+
PRIMARY KEY (session_id, harness, message_id)
|
|
38075
|
+
);
|
|
38076
|
+
CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
|
|
38077
|
+
ON transform_decisions(session_id, harness);
|
|
38078
|
+
`);
|
|
38079
|
+
ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
38080
|
+
ensureColumn(db, "message_history_index", "dirty_floor_ordinal", "INTEGER NOT NULL DEFAULT 0");
|
|
38081
|
+
ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
38082
|
+
ensureColumn(db, "source_contents", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
38083
|
+
ensureColumn(db, "compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
38084
|
+
ensureColumn(db, "compression_depth", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
38085
|
+
ensureColumn(db, "session_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
38086
|
+
ensureColumn(db, "session_meta", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
38087
|
+
ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
38088
|
+
ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
38089
|
+
ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
38090
|
+
ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
38091
|
+
}
|
|
38092
|
+
var databases, pendingAsyncOpens, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, LATEST_SUPPORTED_VERSION = 76, PERMISSIONS_ENFORCEABLE, RPC_DISCOVERY_PARSE_GRACE_MS, defaultRpcDiscoveryFs, rpcDiscoveryFs, sqlitePragmaConfig;
|
|
36456
38093
|
var init_storage_db = __esm(async () => {
|
|
36457
38094
|
init_data_path();
|
|
36458
38095
|
init_logger();
|
|
@@ -36473,11 +38110,15 @@ var init_storage_db = __esm(async () => {
|
|
|
36473
38110
|
RPC_DISCOVERY_PARSE_GRACE_MS = 10 * 60 * 1000;
|
|
36474
38111
|
defaultRpcDiscoveryFs = {
|
|
36475
38112
|
readdirSync: (path4, options) => options?.withFileTypes ? readdirSync2(path4, { withFileTypes: true }) : readdirSync2(path4),
|
|
36476
|
-
readFileSync: (path4, encoding) => String(
|
|
38113
|
+
readFileSync: (path4, encoding) => String(readFileSync13(path4, encoding)),
|
|
36477
38114
|
statSync: (path4) => ({ mtimeMs: statSync7(path4).mtimeMs }),
|
|
36478
38115
|
unlinkSync: (path4) => unlinkSync2(path4)
|
|
36479
38116
|
};
|
|
36480
38117
|
rpcDiscoveryFs = defaultRpcDiscoveryFs;
|
|
38118
|
+
sqlitePragmaConfig = {
|
|
38119
|
+
cacheSizeMb: 64,
|
|
38120
|
+
mmapSizeMb: 0
|
|
38121
|
+
};
|
|
36481
38122
|
});
|
|
36482
38123
|
|
|
36483
38124
|
// src/lib/database-access.ts
|
|
@@ -36784,13 +38425,39 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
|
|
|
36784
38425
|
const sourceId = row.id;
|
|
36785
38426
|
if (typeof sourceId !== "number")
|
|
36786
38427
|
return false;
|
|
36787
|
-
const collision = db.prepare(`SELECT
|
|
38428
|
+
const collision = db.prepare(`SELECT *
|
|
36788
38429
|
FROM memories
|
|
36789
38430
|
WHERE project_path = ? AND category = ? AND normalized_hash = ? AND id <> ?
|
|
36790
38431
|
LIMIT 1`).get(toIdentity, row.category, row.normalized_hash, sourceId);
|
|
36791
38432
|
if (collision && typeof collision.id === "number") {
|
|
38433
|
+
const targetId = collision.id;
|
|
36792
38434
|
const mergedSeen = Math.max(Number(collision.seen_count ?? 1), Number(row.seen_count ?? 1));
|
|
36793
|
-
|
|
38435
|
+
const sourceClassifiedAt = Number(row.classified_at ?? 0);
|
|
38436
|
+
const targetClassifiedAt = Number(collision.classified_at ?? 0);
|
|
38437
|
+
if (sourceClassifiedAt > targetClassifiedAt) {
|
|
38438
|
+
db.prepare(`UPDATE memories
|
|
38439
|
+
SET importance = ?, scope = ?, shareable = ?, classified_at = ?
|
|
38440
|
+
WHERE id = ?`).run(row.importance, row.scope, row.shareable, row.classified_at, targetId);
|
|
38441
|
+
}
|
|
38442
|
+
const sourceHasCue = typeof row.mural_cue === "string" && row.mural_cue.length > 0;
|
|
38443
|
+
const targetHasCue = typeof collision.mural_cue === "string" && collision.mural_cue.length > 0;
|
|
38444
|
+
const sourceCueAt = Number(row.mural_cue_at ?? 0);
|
|
38445
|
+
const targetCueAt = Number(collision.mural_cue_at ?? 0);
|
|
38446
|
+
if (sourceHasCue && (!targetHasCue || sourceCueAt > targetCueAt)) {
|
|
38447
|
+
db.prepare(`UPDATE memories
|
|
38448
|
+
SET mural_cue = ?, mural_cue_hash = ?, mural_cue_at = ?,
|
|
38449
|
+
mural_cue_rejection_count = ?
|
|
38450
|
+
WHERE id = ?`).run(row.mural_cue, row.mural_cue_hash, row.mural_cue_at, row.mural_cue_rejection_count, targetId);
|
|
38451
|
+
}
|
|
38452
|
+
db.prepare(`INSERT INTO memory_verifications (memory_id, file_path, verified_at, mapped_at)
|
|
38453
|
+
SELECT ?, file_path, verified_at, mapped_at
|
|
38454
|
+
FROM memory_verifications
|
|
38455
|
+
WHERE memory_id = ?
|
|
38456
|
+
ON CONFLICT(memory_id, file_path) DO UPDATE SET
|
|
38457
|
+
verified_at = MAX(memory_verifications.verified_at, excluded.verified_at),
|
|
38458
|
+
mapped_at = MAX(memory_verifications.mapped_at, excluded.mapped_at)`).run(targetId, sourceId);
|
|
38459
|
+
db.prepare("DELETE FROM memory_verifications WHERE memory_id = ?").run(sourceId);
|
|
38460
|
+
db.prepare("UPDATE memories SET seen_count = ?, status = COALESCE(status, 'active') WHERE id = ?").run(mergedSeen, targetId);
|
|
36794
38461
|
db.prepare(`UPDATE memories
|
|
36795
38462
|
SET status = 'archived',
|
|
36796
38463
|
superseded_by_memory_id = ?,
|
|
@@ -36799,11 +38466,11 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
|
|
|
36799
38466
|
ELSE merged_from || ',' || ?
|
|
36800
38467
|
END,
|
|
36801
38468
|
updated_at = ?
|
|
36802
|
-
WHERE id = ? AND project_path = ?`).run(
|
|
38469
|
+
WHERE id = ? AND project_path = ?`).run(targetId, String(sourceId), "identity-merge", mergedAt, sourceId, fromIdentity);
|
|
36803
38470
|
db.prepare(`INSERT INTO memory_mutation_log
|
|
36804
38471
|
(project_path, mutation_type, target_memory_id, superseded_by_id, category, queued_at)
|
|
36805
|
-
VALUES (?, 'superseded', ?, ?, ?, ?)`).run(fromIdentity, sourceId,
|
|
36806
|
-
logRow(db, fromIdentity, toIdentity, "memories", String(sourceId), "superseded", String(
|
|
38472
|
+
VALUES (?, 'superseded', ?, ?, ?, ?)`).run(fromIdentity, sourceId, targetId, row.category, mergedAt);
|
|
38473
|
+
logRow(db, fromIdentity, toIdentity, "memories", String(sourceId), "superseded", String(targetId), mergedAt);
|
|
36807
38474
|
return true;
|
|
36808
38475
|
}
|
|
36809
38476
|
const result = db.prepare("UPDATE memories SET project_path = ? WHERE id = ? AND project_path = ?").run(toIdentity, sourceId, fromIdentity);
|
|
@@ -36812,10 +38479,30 @@ function mergeMemoryRow(db, row, fromIdentity, toIdentity, mergedAt) {
|
|
|
36812
38479
|
logRow(db, fromIdentity, toIdentity, "memories", String(sourceId), "rekeyed", null, mergedAt);
|
|
36813
38480
|
return true;
|
|
36814
38481
|
}
|
|
38482
|
+
function nullableMaximum(left, right) {
|
|
38483
|
+
const values = [left, right].filter((value) => typeof value === "number");
|
|
38484
|
+
return values.length > 0 ? Math.max(...values) : null;
|
|
38485
|
+
}
|
|
38486
|
+
function oldestOpenCycleStart(left, right) {
|
|
38487
|
+
const values = [left, right].filter((value) => typeof value === "number" && value > 0);
|
|
38488
|
+
return values.length > 0 ? Math.min(...values) : null;
|
|
38489
|
+
}
|
|
38490
|
+
function reconcileTaskScheduleCollision(db, source, target) {
|
|
38491
|
+
const sourceIsNewer = typeof source.last_run_at === "number" && (typeof target.last_run_at !== "number" || source.last_run_at > target.last_run_at);
|
|
38492
|
+
const latest = sourceIsNewer ? source : target;
|
|
38493
|
+
db.prepare(`UPDATE task_schedule_state
|
|
38494
|
+
SET last_run_at = ?, next_due_at = ?, schedule = ?, last_status = ?,
|
|
38495
|
+
last_error = ?, retry_count = ?, last_checked_commit = ?,
|
|
38496
|
+
last_broad_run_at = ?, retrospective_watermark_ms = ?
|
|
38497
|
+
WHERE project_path = ? AND task = ?`).run(nullableMaximum(source.last_run_at, target.last_run_at), latest.next_due_at, latest.schedule, latest.last_status, latest.last_error, latest.retry_count, latest.last_checked_commit, oldestOpenCycleStart(source.last_broad_run_at, target.last_broad_run_at), nullableMaximum(source.retrospective_watermark_ms, target.retrospective_watermark_ms), target.project_path, target.task);
|
|
38498
|
+
}
|
|
36815
38499
|
function rekeyGenericRow(db, table, row, fromIdentity, toIdentity, mergedAt) {
|
|
36816
38500
|
const rowId = rowKey(db, table.name, row);
|
|
36817
38501
|
const collision = findUniqueCollision(db, table, row, fromIdentity, toIdentity);
|
|
36818
38502
|
if (collision) {
|
|
38503
|
+
if (table.name === "task_schedule_state") {
|
|
38504
|
+
reconcileTaskScheduleCollision(db, row, collision);
|
|
38505
|
+
}
|
|
36819
38506
|
const sourcePredicate = rowPredicate(db, table.name, row);
|
|
36820
38507
|
const result2 = db.prepare(`DELETE FROM ${quoteIdentifier(table.name)} WHERE ${sourcePredicate.sql}`).run(...sourcePredicate.values);
|
|
36821
38508
|
if ((result2.changes ?? 0) === 0)
|
|
@@ -37010,12 +38697,522 @@ var init_doctor_merge_identity = __esm(async () => {
|
|
|
37010
38697
|
await init_database_access();
|
|
37011
38698
|
});
|
|
37012
38699
|
|
|
38700
|
+
// src/commands/doctor-repair-db.ts
|
|
38701
|
+
var exports_doctor_repair_db = {};
|
|
38702
|
+
__export(exports_doctor_repair_db, {
|
|
38703
|
+
runRepairDbCli: () => runRepairDbCli,
|
|
38704
|
+
runRepairDb: () => runRepairDb,
|
|
38705
|
+
defaultSqliteExecutable: () => defaultSqliteExecutable,
|
|
38706
|
+
REPAIR_DB_EXIT: () => REPAIR_DB_EXIT
|
|
38707
|
+
});
|
|
38708
|
+
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
38709
|
+
import {
|
|
38710
|
+
chmodSync as chmodSync3,
|
|
38711
|
+
closeSync as closeSync2,
|
|
38712
|
+
constants as constants2,
|
|
38713
|
+
copyFileSync as copyFileSync2,
|
|
38714
|
+
existsSync as existsSync20,
|
|
38715
|
+
openSync as openSync2,
|
|
38716
|
+
renameSync as renameSync3,
|
|
38717
|
+
rmSync as rmSync2,
|
|
38718
|
+
statSync as statSync8
|
|
38719
|
+
} from "node:fs";
|
|
38720
|
+
import { dirname as dirname11, join as join16 } from "node:path";
|
|
38721
|
+
function defaultInspectHolders(storageDir) {
|
|
38722
|
+
const rpc = inspectRpcServerDiscovery(storageDir);
|
|
38723
|
+
if (rpc.state === "unreadable") {
|
|
38724
|
+
const arm = rpc.unreadableArm === "parse" ? "could not be parsed" : "could not be read";
|
|
38725
|
+
return {
|
|
38726
|
+
safe: false,
|
|
38727
|
+
blockers: [],
|
|
38728
|
+
uncertainty: `RPC discovery ${rpc.unreadableFile ?? join16(storageDir, "rpc")} ${arm}`
|
|
38729
|
+
};
|
|
38730
|
+
}
|
|
38731
|
+
const blockers = rpc.state === "live" ? rpc.serverPids.map((pid) => `OpenCode server (PID ${pid})`) : [];
|
|
38732
|
+
const pi = inspectLivePiProcesses();
|
|
38733
|
+
if (pi.state === "unreadable") {
|
|
38734
|
+
return {
|
|
38735
|
+
safe: false,
|
|
38736
|
+
blockers,
|
|
38737
|
+
uncertainty: `Pi/OMP process liveness could not be determined: ${pi.error ?? "process list unavailable"}`
|
|
38738
|
+
};
|
|
38739
|
+
}
|
|
38740
|
+
blockers.push(...pi.processIds.map((pid) => `Pi/OMP harness (PID ${pid})`));
|
|
38741
|
+
return { safe: blockers.length === 0, blockers };
|
|
38742
|
+
}
|
|
38743
|
+
function defaultSqliteExecutable() {
|
|
38744
|
+
return process.env.MAGIC_CONTEXT_SQLITE3 ?? "sqlite3";
|
|
38745
|
+
}
|
|
38746
|
+
function timestamp(date5) {
|
|
38747
|
+
return date5.toISOString().replaceAll("-", "").replaceAll(":", "").replace(".", "");
|
|
38748
|
+
}
|
|
38749
|
+
function uniqueBase(preferred) {
|
|
38750
|
+
if (!DATABASE_SUFFIXES.some((suffix) => existsSync20(`${preferred}${suffix}`)))
|
|
38751
|
+
return preferred;
|
|
38752
|
+
for (let attempt = 1;attempt < 1e4; attempt++) {
|
|
38753
|
+
const candidate = `${preferred}-${attempt}`;
|
|
38754
|
+
if (!DATABASE_SUFFIXES.some((suffix) => existsSync20(`${candidate}${suffix}`)))
|
|
38755
|
+
return candidate;
|
|
38756
|
+
}
|
|
38757
|
+
throw new Error(`Could not allocate a unique recovery path beside ${preferred}`);
|
|
38758
|
+
}
|
|
38759
|
+
function copyBackupBundle(dbPath, stamp) {
|
|
38760
|
+
const basePath = uniqueBase(`${dbPath}.corrupt-backup-${stamp}`);
|
|
38761
|
+
const copiedPaths = copyDatabaseBundle(dbPath, basePath);
|
|
38762
|
+
return { basePath, copiedPaths };
|
|
38763
|
+
}
|
|
38764
|
+
function copyDatabaseBundle(sourceBase, destinationBase) {
|
|
38765
|
+
const copiedPaths = [];
|
|
38766
|
+
for (const suffix of DATABASE_SUFFIXES) {
|
|
38767
|
+
const source = `${sourceBase}${suffix}`;
|
|
38768
|
+
if (!existsSync20(source))
|
|
38769
|
+
continue;
|
|
38770
|
+
const destination = `${destinationBase}${suffix}`;
|
|
38771
|
+
copyFileSync2(source, destination, constants2.COPYFILE_EXCL);
|
|
38772
|
+
copiedPaths.push(destination);
|
|
38773
|
+
}
|
|
38774
|
+
return copiedPaths;
|
|
38775
|
+
}
|
|
38776
|
+
function readRowCounts(path4) {
|
|
38777
|
+
const counts = Object.fromEntries(ROW_COUNT_TABLES.map((table) => [table, null]));
|
|
38778
|
+
let db = null;
|
|
38779
|
+
try {
|
|
38780
|
+
db = new Database(path4, { readonly: true });
|
|
38781
|
+
for (const table of ROW_COUNT_TABLES) {
|
|
38782
|
+
try {
|
|
38783
|
+
const row = db.prepare(`SELECT COUNT(*) AS count FROM ${table}`).get();
|
|
38784
|
+
counts[table] = typeof row?.count === "number" ? row.count : null;
|
|
38785
|
+
} catch {
|
|
38786
|
+
counts[table] = null;
|
|
38787
|
+
}
|
|
38788
|
+
}
|
|
38789
|
+
} catch {} finally {
|
|
38790
|
+
db?.close();
|
|
38791
|
+
}
|
|
38792
|
+
return counts;
|
|
38793
|
+
}
|
|
38794
|
+
function reportCounts(prompts, label, counts) {
|
|
38795
|
+
prompts.log.info(`Row counts ${label} recovery:`);
|
|
38796
|
+
for (const table of ROW_COUNT_TABLES) {
|
|
38797
|
+
prompts.log.info(` ${table}=${counts[table] ?? "n/a"}`);
|
|
38798
|
+
}
|
|
38799
|
+
}
|
|
38800
|
+
function reportSchemaTransition(prompts, result) {
|
|
38801
|
+
prompts.log.info(`Schema migration: v${result.schemaVersionBefore ?? "unknown"} → v${result.schemaVersionAfter ?? "unknown"}`);
|
|
38802
|
+
}
|
|
38803
|
+
function reportSalvageRates(prompts, before, after) {
|
|
38804
|
+
prompts.log.info("Salvage rates (readable rows before → rows after):");
|
|
38805
|
+
for (const table of ROW_COUNT_TABLES) {
|
|
38806
|
+
const beforeCount = before[table];
|
|
38807
|
+
const afterCount = after[table];
|
|
38808
|
+
if (beforeCount === null || afterCount === null) {
|
|
38809
|
+
prompts.log.info(` ${table}: n/a`);
|
|
38810
|
+
continue;
|
|
38811
|
+
}
|
|
38812
|
+
const rate = beforeCount === 0 ? afterCount === 0 ? 100 : 0 : afterCount / beforeCount * 100;
|
|
38813
|
+
const lost = Math.max(0, beforeCount - afterCount);
|
|
38814
|
+
prompts.log.info(` ${table}: ${beforeCount} → ${afterCount} (${rate.toFixed(1)}%, lost ${lost})`);
|
|
38815
|
+
}
|
|
38816
|
+
}
|
|
38817
|
+
function integrityErrors(db) {
|
|
38818
|
+
const rows = db.prepare("PRAGMA integrity_check").all();
|
|
38819
|
+
return rows.map((row) => String(row.integrity_check ?? "unknown")).filter((result) => result !== "ok");
|
|
38820
|
+
}
|
|
38821
|
+
function sqliteError(result) {
|
|
38822
|
+
if (result.error)
|
|
38823
|
+
return result.error.message;
|
|
38824
|
+
const stderr = String(result.stderr ?? "").trim();
|
|
38825
|
+
if (stderr)
|
|
38826
|
+
return stderr;
|
|
38827
|
+
return `sqlite3 exited with status ${String(result.status)}`;
|
|
38828
|
+
}
|
|
38829
|
+
function isRecoverCapabilityMissing(errorDetail) {
|
|
38830
|
+
return RECOVER_UNAVAILABLE_PATTERNS.some((pattern) => pattern.test(errorDetail));
|
|
38831
|
+
}
|
|
38832
|
+
function runRecoverShell(sqliteExecutable, sourcePath, recoveredPath, dumpPath) {
|
|
38833
|
+
let dumpWriteFd = null;
|
|
38834
|
+
try {
|
|
38835
|
+
dumpWriteFd = openSync2(dumpPath, "wx", 384);
|
|
38836
|
+
const recovered = spawnSync3(sqliteExecutable, [sourcePath, ".recover"], {
|
|
38837
|
+
stdio: ["ignore", dumpWriteFd, "pipe"],
|
|
38838
|
+
encoding: "utf8",
|
|
38839
|
+
windowsHide: true
|
|
38840
|
+
});
|
|
38841
|
+
closeSync2(dumpWriteFd);
|
|
38842
|
+
dumpWriteFd = null;
|
|
38843
|
+
if (recovered.error || recovered.status !== 0) {
|
|
38844
|
+
const errorDetail = sqliteError(recovered);
|
|
38845
|
+
const attempted = recovered.error === undefined;
|
|
38846
|
+
return {
|
|
38847
|
+
ok: false,
|
|
38848
|
+
detail: `.recover failed: ${errorDetail}`,
|
|
38849
|
+
attempted,
|
|
38850
|
+
unavailable: attempted && isRecoverCapabilityMissing(errorDetail)
|
|
38851
|
+
};
|
|
38852
|
+
}
|
|
38853
|
+
const dumpReadFd = openSync2(dumpPath, "r");
|
|
38854
|
+
try {
|
|
38855
|
+
const replayed = spawnSync3(sqliteExecutable, [recoveredPath], {
|
|
38856
|
+
stdio: [dumpReadFd, "ignore", "pipe"],
|
|
38857
|
+
encoding: "utf8",
|
|
38858
|
+
windowsHide: true
|
|
38859
|
+
});
|
|
38860
|
+
if (replayed.error || replayed.status !== 0) {
|
|
38861
|
+
return {
|
|
38862
|
+
ok: false,
|
|
38863
|
+
detail: `replaying .recover output failed: ${sqliteError(replayed)}`,
|
|
38864
|
+
attempted: true,
|
|
38865
|
+
unavailable: false
|
|
38866
|
+
};
|
|
38867
|
+
}
|
|
38868
|
+
} finally {
|
|
38869
|
+
closeSync2(dumpReadFd);
|
|
38870
|
+
}
|
|
38871
|
+
return { ok: true };
|
|
38872
|
+
} catch (error51) {
|
|
38873
|
+
return {
|
|
38874
|
+
ok: false,
|
|
38875
|
+
detail: error51 instanceof Error ? error51.message : String(error51),
|
|
38876
|
+
attempted: false,
|
|
38877
|
+
unavailable: false
|
|
38878
|
+
};
|
|
38879
|
+
} finally {
|
|
38880
|
+
if (dumpWriteFd !== null)
|
|
38881
|
+
closeSync2(dumpWriteFd);
|
|
38882
|
+
rmSync2(dumpPath, { force: true });
|
|
38883
|
+
}
|
|
38884
|
+
}
|
|
38885
|
+
function migrateAndCheckRecoveredDatabase(path4) {
|
|
38886
|
+
let db = null;
|
|
38887
|
+
try {
|
|
38888
|
+
db = new Database(path4);
|
|
38889
|
+
const recognized = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name IN (${RECOGNIZABLE_TABLES.map(() => "?").join(",")})`).all(...RECOGNIZABLE_TABLES);
|
|
38890
|
+
if (recognized.length === 0) {
|
|
38891
|
+
return {
|
|
38892
|
+
ok: false,
|
|
38893
|
+
detail: ".recover found no recognizable Magic Context schema or user tables"
|
|
38894
|
+
};
|
|
38895
|
+
}
|
|
38896
|
+
const schemaVersionBefore = getPersistedSchemaVersion(db);
|
|
38897
|
+
initializeDatabase(db);
|
|
38898
|
+
runMigrations(db);
|
|
38899
|
+
ensureContextStoreUuid(db);
|
|
38900
|
+
const schemaVersionAfter = getPersistedSchemaVersion(db);
|
|
38901
|
+
const errors3 = integrityErrors(db);
|
|
38902
|
+
if (errors3.length > 0) {
|
|
38903
|
+
return {
|
|
38904
|
+
ok: false,
|
|
38905
|
+
detail: `recovered database integrity_check failed: ${errors3.slice(0, 3).join("; ")}`
|
|
38906
|
+
};
|
|
38907
|
+
}
|
|
38908
|
+
const afterCounts = readCountsFromOpenDatabase(db);
|
|
38909
|
+
db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
38910
|
+
db.exec("PRAGMA journal_mode=DELETE");
|
|
38911
|
+
return { ok: true, afterCounts, schemaVersionBefore, schemaVersionAfter };
|
|
38912
|
+
} catch (error51) {
|
|
38913
|
+
return {
|
|
38914
|
+
ok: false,
|
|
38915
|
+
detail: error51 instanceof Error ? error51.message : String(error51)
|
|
38916
|
+
};
|
|
38917
|
+
} finally {
|
|
38918
|
+
db?.close();
|
|
38919
|
+
}
|
|
38920
|
+
}
|
|
38921
|
+
function readCountsFromOpenDatabase(db) {
|
|
38922
|
+
const counts = Object.fromEntries(ROW_COUNT_TABLES.map((table) => [table, null]));
|
|
38923
|
+
for (const table of ROW_COUNT_TABLES) {
|
|
38924
|
+
try {
|
|
38925
|
+
const row = db.prepare(`SELECT COUNT(*) AS count FROM ${table}`).get();
|
|
38926
|
+
counts[table] = typeof row?.count === "number" ? row.count : null;
|
|
38927
|
+
} catch {
|
|
38928
|
+
counts[table] = null;
|
|
38929
|
+
}
|
|
38930
|
+
}
|
|
38931
|
+
return counts;
|
|
38932
|
+
}
|
|
38933
|
+
function prepareFreshDatabase(path4) {
|
|
38934
|
+
let db = null;
|
|
38935
|
+
try {
|
|
38936
|
+
db = new Database(path4);
|
|
38937
|
+
const schemaVersionBefore = getPersistedSchemaVersion(db);
|
|
38938
|
+
initializeDatabase(db);
|
|
38939
|
+
runMigrations(db);
|
|
38940
|
+
ensureContextStoreUuid(db);
|
|
38941
|
+
const schemaVersionAfter = getPersistedSchemaVersion(db);
|
|
38942
|
+
const errors3 = integrityErrors(db);
|
|
38943
|
+
if (errors3.length > 0) {
|
|
38944
|
+
return {
|
|
38945
|
+
ok: false,
|
|
38946
|
+
detail: `fresh database integrity_check failed: ${errors3.join("; ")}`
|
|
38947
|
+
};
|
|
38948
|
+
}
|
|
38949
|
+
const afterCounts = readCountsFromOpenDatabase(db);
|
|
38950
|
+
db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
38951
|
+
db.exec("PRAGMA journal_mode=DELETE");
|
|
38952
|
+
return { ok: true, afterCounts, schemaVersionBefore, schemaVersionAfter };
|
|
38953
|
+
} catch (error51) {
|
|
38954
|
+
return { ok: false, detail: error51 instanceof Error ? error51.message : String(error51) };
|
|
38955
|
+
} finally {
|
|
38956
|
+
db?.close();
|
|
38957
|
+
}
|
|
38958
|
+
}
|
|
38959
|
+
function removeRecoveryBundle(basePath) {
|
|
38960
|
+
for (const suffix of DATABASE_SUFFIXES)
|
|
38961
|
+
rmSync2(`${basePath}${suffix}`, { force: true });
|
|
38962
|
+
}
|
|
38963
|
+
function activateReplacement(dbPath, replacementPath, originalAsidePath) {
|
|
38964
|
+
const movedOriginals = [];
|
|
38965
|
+
try {
|
|
38966
|
+
for (const suffix of DATABASE_SUFFIXES) {
|
|
38967
|
+
const from = `${dbPath}${suffix}`;
|
|
38968
|
+
if (!existsSync20(from))
|
|
38969
|
+
continue;
|
|
38970
|
+
const to = `${originalAsidePath}${suffix}`;
|
|
38971
|
+
renameSync3(from, to);
|
|
38972
|
+
movedOriginals.push({ from, to });
|
|
38973
|
+
}
|
|
38974
|
+
renameSync3(replacementPath, dbPath);
|
|
38975
|
+
return movedOriginals.map(({ to }) => to);
|
|
38976
|
+
} catch (error51) {
|
|
38977
|
+
for (const moved of movedOriginals.reverse()) {
|
|
38978
|
+
if (existsSync20(moved.to) && !existsSync20(moved.from))
|
|
38979
|
+
renameSync3(moved.to, moved.from);
|
|
38980
|
+
}
|
|
38981
|
+
throw error51;
|
|
38982
|
+
}
|
|
38983
|
+
}
|
|
38984
|
+
function reportSafetyRefusal(prompts, dbPath, inspection, backupBase) {
|
|
38985
|
+
prompts.log.error(`Refusing to repair the live database: ${dbPath}`);
|
|
38986
|
+
if (inspection.blockers.length > 0) {
|
|
38987
|
+
prompts.log.error(`Active database holder(s): ${inspection.blockers.join(", ")}`);
|
|
38988
|
+
}
|
|
38989
|
+
if (inspection.uncertainty)
|
|
38990
|
+
prompts.log.error(inspection.uncertainty);
|
|
38991
|
+
prompts.log.info("Close every OpenCode, Pi, and OMP process, then run the command again.");
|
|
38992
|
+
if (backupBase)
|
|
38993
|
+
prompts.log.info(`Backup base: ${backupBase}`);
|
|
38994
|
+
else
|
|
38995
|
+
prompts.log.info("Backup: not created (repair refused before database access)");
|
|
38996
|
+
prompts.outro("Database repair refused; the original database files were not modified");
|
|
38997
|
+
return REPAIR_DB_EXIT.refused;
|
|
38998
|
+
}
|
|
38999
|
+
function printHelp() {
|
|
39000
|
+
console.log("Usage: magic-context doctor repair-db");
|
|
39001
|
+
console.log("");
|
|
39002
|
+
console.log("Back up and salvage the shared context.db using SQLite .recover.");
|
|
39003
|
+
console.log("If salvage is impossible, an empty reset is offered with a separate confirmation.");
|
|
39004
|
+
console.log("Salvage needs a sqlite3 shell built with SQLITE_ENABLE_DBPAGE_VTAB; without one, the command backs up and stops without modifying the database.");
|
|
39005
|
+
}
|
|
39006
|
+
async function runRepairDb(options = {}) {
|
|
39007
|
+
const prompts = options.prompts ?? promptIO;
|
|
39008
|
+
const deps = { ...DEFAULT_DEPS, ...options.deps };
|
|
39009
|
+
const storageDir = options.storageDir ?? dirname11(options.dbPath ?? join16(getMagicContextStorageDir(), "context.db"));
|
|
39010
|
+
const dbPath = options.dbPath ?? join16(storageDir, "context.db");
|
|
39011
|
+
const stamp = timestamp(deps.now());
|
|
39012
|
+
prompts.intro("Magic Context — Repair shared database");
|
|
39013
|
+
prompts.log.info(`Database: ${dbPath}`);
|
|
39014
|
+
if (!existsSync20(dbPath)) {
|
|
39015
|
+
prompts.log.error(`Database not found: ${dbPath}`);
|
|
39016
|
+
prompts.log.info("Backup: not created (database does not exist)");
|
|
39017
|
+
prompts.outro("Database repair failed");
|
|
39018
|
+
return REPAIR_DB_EXIT.failed;
|
|
39019
|
+
}
|
|
39020
|
+
const initialInspection = deps.inspectHolders(storageDir);
|
|
39021
|
+
if (!initialInspection.safe)
|
|
39022
|
+
return reportSafetyRefusal(prompts, dbPath, initialInspection);
|
|
39023
|
+
let backup;
|
|
39024
|
+
try {
|
|
39025
|
+
backup = copyBackupBundle(dbPath, stamp);
|
|
39026
|
+
} catch (error51) {
|
|
39027
|
+
prompts.log.error(`Could not complete the required backup: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
39028
|
+
prompts.log.info(`Backup base: ${dbPath}.corrupt-backup-${stamp}`);
|
|
39029
|
+
prompts.outro("Database repair stopped before salvage");
|
|
39030
|
+
return REPAIR_DB_EXIT.failed;
|
|
39031
|
+
}
|
|
39032
|
+
for (const path4 of backup.copiedPaths)
|
|
39033
|
+
prompts.log.info(`Backup: ${path4}`);
|
|
39034
|
+
const workingBase = uniqueBase(`${dbPath}.recovering-${stamp}-${process.pid}`);
|
|
39035
|
+
const countSourcePath = `${workingBase}.count-source`;
|
|
39036
|
+
const recoverSourcePath = `${workingBase}.recover-source`;
|
|
39037
|
+
try {
|
|
39038
|
+
copyDatabaseBundle(backup.basePath, countSourcePath);
|
|
39039
|
+
} catch (error51) {
|
|
39040
|
+
removeRecoveryBundle(countSourcePath);
|
|
39041
|
+
prompts.log.error(`Could not prepare the isolated row-count snapshot: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
39042
|
+
prompts.log.info(`Database remains unchanged: ${dbPath}`);
|
|
39043
|
+
prompts.log.info(`Backup base: ${backup.basePath}`);
|
|
39044
|
+
prompts.outro("Database repair stopped before salvage");
|
|
39045
|
+
return REPAIR_DB_EXIT.failed;
|
|
39046
|
+
}
|
|
39047
|
+
const beforeCounts = readRowCounts(countSourcePath);
|
|
39048
|
+
removeRecoveryBundle(countSourcePath);
|
|
39049
|
+
reportCounts(prompts, "BEFORE", beforeCounts);
|
|
39050
|
+
try {
|
|
39051
|
+
copyDatabaseBundle(backup.basePath, recoverSourcePath);
|
|
39052
|
+
} catch (error51) {
|
|
39053
|
+
removeRecoveryBundle(recoverSourcePath);
|
|
39054
|
+
prompts.log.error(`Could not prepare the isolated salvage snapshot: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
39055
|
+
prompts.log.info(`Database remains unchanged: ${dbPath}`);
|
|
39056
|
+
prompts.log.info(`Backup base: ${backup.basePath}`);
|
|
39057
|
+
prompts.outro("Database repair stopped before salvage");
|
|
39058
|
+
return REPAIR_DB_EXIT.failed;
|
|
39059
|
+
}
|
|
39060
|
+
const recoveredPath = `${workingBase}.db`;
|
|
39061
|
+
const dumpPath = `${workingBase}.sql`;
|
|
39062
|
+
prompts.log.info(`Attempting SQLite .recover into fresh database: ${recoveredPath}`);
|
|
39063
|
+
const salvage = runRecoverShell(deps.sqliteExecutable, recoverSourcePath, recoveredPath, dumpPath);
|
|
39064
|
+
removeRecoveryBundle(recoverSourcePath);
|
|
39065
|
+
if (!salvage.ok && !salvage.attempted) {
|
|
39066
|
+
removeRecoveryBundle(recoveredPath);
|
|
39067
|
+
const unavailableAfter2 = Object.fromEntries(ROW_COUNT_TABLES.map((table) => [table, null]));
|
|
39068
|
+
reportCounts(prompts, "AFTER", unavailableAfter2);
|
|
39069
|
+
reportSalvageRates(prompts, beforeCounts, unavailableAfter2);
|
|
39070
|
+
prompts.log.error(`SQLite .recover could not be started: ${salvage.detail}`);
|
|
39071
|
+
prompts.log.info("Install the SQLite command-line shell (sqlite3), then rerun this command. Reset was not offered because salvage did not run.");
|
|
39072
|
+
prompts.log.info(`Database remains unchanged: ${dbPath}`);
|
|
39073
|
+
prompts.log.info(`Backup base: ${backup.basePath}`);
|
|
39074
|
+
prompts.outro("Database repair stopped before salvage could run");
|
|
39075
|
+
return REPAIR_DB_EXIT.failed;
|
|
39076
|
+
}
|
|
39077
|
+
if (!salvage.ok && salvage.unavailable) {
|
|
39078
|
+
removeRecoveryBundle(recoveredPath);
|
|
39079
|
+
const unavailableAfter2 = Object.fromEntries(ROW_COUNT_TABLES.map((table) => [table, null]));
|
|
39080
|
+
reportCounts(prompts, "AFTER", unavailableAfter2);
|
|
39081
|
+
reportSalvageRates(prompts, beforeCounts, unavailableAfter2);
|
|
39082
|
+
prompts.log.error(`SQLite .recover is unavailable on this machine: ${salvage.detail}`);
|
|
39083
|
+
prompts.log.info("This sqlite3 was built without SQLITE_ENABLE_DBPAGE_VTAB, the compile-time option .recover needs. That is a limitation of the tool, not a verdict about your data: the database may be perfectly salvageable with a full sqlite3 build. Install the official SQLite command-line binary (sqlite.org/download.html) or a distro package built with SQLITE_ENABLE_DBPAGE_VTAB, then rerun this command. Reset was not offered because salvage did not run.");
|
|
39084
|
+
prompts.log.info(`Database remains unchanged: ${dbPath}`);
|
|
39085
|
+
prompts.log.info(`Backup base: ${backup.basePath}`);
|
|
39086
|
+
prompts.outro("Database repair stopped: this sqlite3 cannot run .recover");
|
|
39087
|
+
return REPAIR_DB_EXIT.failed;
|
|
39088
|
+
}
|
|
39089
|
+
let salvageResult;
|
|
39090
|
+
if (salvage.ok) {
|
|
39091
|
+
salvageResult = migrateAndCheckRecoveredDatabase(recoveredPath);
|
|
39092
|
+
} else {
|
|
39093
|
+
salvageResult = salvage;
|
|
39094
|
+
}
|
|
39095
|
+
if (salvageResult.ok && salvageResult.afterCounts) {
|
|
39096
|
+
const finalInspection = deps.inspectHolders(storageDir);
|
|
39097
|
+
if (!finalInspection.safe) {
|
|
39098
|
+
removeRecoveryBundle(recoveredPath);
|
|
39099
|
+
return reportSafetyRefusal(prompts, dbPath, finalInspection, backup.basePath);
|
|
39100
|
+
}
|
|
39101
|
+
try {
|
|
39102
|
+
const originalMode = statSync8(dbPath).mode & 511;
|
|
39103
|
+
chmodSync3(recoveredPath, originalMode);
|
|
39104
|
+
const originalAsidePath = uniqueBase(`${dbPath}.corrupt-original-${stamp}`);
|
|
39105
|
+
const moved = activateReplacement(dbPath, recoveredPath, originalAsidePath);
|
|
39106
|
+
reportSchemaTransition(prompts, salvageResult);
|
|
39107
|
+
reportCounts(prompts, "AFTER", salvageResult.afterCounts);
|
|
39108
|
+
reportSalvageRates(prompts, beforeCounts, salvageResult.afterCounts);
|
|
39109
|
+
for (const path4 of moved)
|
|
39110
|
+
prompts.log.info(`Corrupt original preserved: ${path4}`);
|
|
39111
|
+
prompts.log.success(`Salvaged database installed: ${dbPath}`);
|
|
39112
|
+
prompts.log.info(`Backup base: ${backup.basePath}`);
|
|
39113
|
+
prompts.outro("Database salvage complete; restart your harness");
|
|
39114
|
+
return REPAIR_DB_EXIT.salvaged;
|
|
39115
|
+
} catch (error51) {
|
|
39116
|
+
salvageResult = {
|
|
39117
|
+
ok: false,
|
|
39118
|
+
detail: `could not install recovered database: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
39119
|
+
};
|
|
39120
|
+
}
|
|
39121
|
+
}
|
|
39122
|
+
removeRecoveryBundle(recoveredPath);
|
|
39123
|
+
const unavailableAfter = Object.fromEntries(ROW_COUNT_TABLES.map((table) => [table, null]));
|
|
39124
|
+
reportCounts(prompts, "AFTER", unavailableAfter);
|
|
39125
|
+
reportSalvageRates(prompts, beforeCounts, unavailableAfter);
|
|
39126
|
+
prompts.log.error(`SQLite salvage was unsuccessful: ${salvageResult.detail ?? "unknown error"}`);
|
|
39127
|
+
prompts.log.info(`Database remains unchanged: ${dbPath}`);
|
|
39128
|
+
prompts.log.info(`Backup base: ${backup.basePath}`);
|
|
39129
|
+
const confirmed = await prompts.confirm("Salvage failed. Move the corrupt database aside and create a fresh empty database? This discards all unrecovered data from the active database.", false);
|
|
39130
|
+
if (!confirmed) {
|
|
39131
|
+
prompts.log.info("Reset declined. The corrupt database remains in place.");
|
|
39132
|
+
prompts.outro("Database is unsalvageable by this command; backup retained");
|
|
39133
|
+
return REPAIR_DB_EXIT.unsalvageable;
|
|
39134
|
+
}
|
|
39135
|
+
const resetInspection = deps.inspectHolders(storageDir);
|
|
39136
|
+
if (!resetInspection.safe) {
|
|
39137
|
+
return reportSafetyRefusal(prompts, dbPath, resetInspection, backup.basePath);
|
|
39138
|
+
}
|
|
39139
|
+
const freshPath = `${workingBase}.fresh.db`;
|
|
39140
|
+
const fresh = prepareFreshDatabase(freshPath);
|
|
39141
|
+
if (!fresh.ok || !fresh.afterCounts) {
|
|
39142
|
+
removeRecoveryBundle(freshPath);
|
|
39143
|
+
prompts.log.error(`Could not create a fresh database: ${fresh.detail ?? "unknown error"}`);
|
|
39144
|
+
prompts.log.info(`Database remains unchanged: ${dbPath}`);
|
|
39145
|
+
prompts.log.info(`Backup base: ${backup.basePath}`);
|
|
39146
|
+
prompts.outro("Database reset failed");
|
|
39147
|
+
return REPAIR_DB_EXIT.failed;
|
|
39148
|
+
}
|
|
39149
|
+
try {
|
|
39150
|
+
const originalMode = statSync8(dbPath).mode & 511;
|
|
39151
|
+
chmodSync3(freshPath, originalMode);
|
|
39152
|
+
const originalAsidePath = uniqueBase(`${dbPath}.corrupt-original-${stamp}`);
|
|
39153
|
+
const moved = activateReplacement(dbPath, freshPath, originalAsidePath);
|
|
39154
|
+
reportSchemaTransition(prompts, fresh);
|
|
39155
|
+
reportCounts(prompts, "AFTER", fresh.afterCounts);
|
|
39156
|
+
reportSalvageRates(prompts, beforeCounts, fresh.afterCounts);
|
|
39157
|
+
for (const path4 of moved)
|
|
39158
|
+
prompts.log.info(`Corrupt original preserved: ${path4}`);
|
|
39159
|
+
prompts.log.success(`Fresh database installed after explicit reset confirmation: ${dbPath}`);
|
|
39160
|
+
prompts.log.info(`Backup base: ${backup.basePath}`);
|
|
39161
|
+
prompts.outro("Database reset complete; restart your harness");
|
|
39162
|
+
return REPAIR_DB_EXIT.salvaged;
|
|
39163
|
+
} catch (error51) {
|
|
39164
|
+
prompts.log.error(`Could not install the fresh database: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
39165
|
+
prompts.log.info(`Database remains unchanged: ${dbPath}`);
|
|
39166
|
+
prompts.log.info(`Backup base: ${backup.basePath}`);
|
|
39167
|
+
prompts.outro("Database reset failed");
|
|
39168
|
+
return REPAIR_DB_EXIT.failed;
|
|
39169
|
+
}
|
|
39170
|
+
}
|
|
39171
|
+
async function runRepairDbCli(args, options = {}) {
|
|
39172
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
39173
|
+
printHelp();
|
|
39174
|
+
return REPAIR_DB_EXIT.salvaged;
|
|
39175
|
+
}
|
|
39176
|
+
return runRepairDb(options);
|
|
39177
|
+
}
|
|
39178
|
+
var ROW_COUNT_TABLES, DATABASE_SUFFIXES, RECOGNIZABLE_TABLES, REPAIR_DB_EXIT, DEFAULT_DEPS, RECOVER_UNAVAILABLE_PATTERNS;
|
|
39179
|
+
var init_doctor_repair_db = __esm(async () => {
|
|
39180
|
+
init_migrations();
|
|
39181
|
+
init_data_path();
|
|
39182
|
+
init_rpc_utils();
|
|
39183
|
+
init_prompts();
|
|
39184
|
+
await __promiseAll([
|
|
39185
|
+
init_context_authority(),
|
|
39186
|
+
init_storage_db(),
|
|
39187
|
+
init_sqlite()
|
|
39188
|
+
]);
|
|
39189
|
+
ROW_COUNT_TABLES = ["tags", "compartments", "memories", "notes", "dream_runs"];
|
|
39190
|
+
DATABASE_SUFFIXES = ["", "-wal", "-shm"];
|
|
39191
|
+
RECOGNIZABLE_TABLES = [...ROW_COUNT_TABLES, "schema_migrations"];
|
|
39192
|
+
REPAIR_DB_EXIT = {
|
|
39193
|
+
salvaged: 0,
|
|
39194
|
+
failed: 1,
|
|
39195
|
+
unsalvageable: 2,
|
|
39196
|
+
refused: 3
|
|
39197
|
+
};
|
|
39198
|
+
DEFAULT_DEPS = {
|
|
39199
|
+
now: () => new Date,
|
|
39200
|
+
sqliteExecutable: defaultSqliteExecutable(),
|
|
39201
|
+
inspectHolders: defaultInspectHolders
|
|
39202
|
+
};
|
|
39203
|
+
RECOVER_UNAVAILABLE_PATTERNS = [
|
|
39204
|
+
/no such table: sqlite_dbpage/i,
|
|
39205
|
+
/no such module: sqlite_dbpage/i,
|
|
39206
|
+
/unknown command[^\n]*\.recover/i
|
|
39207
|
+
];
|
|
39208
|
+
});
|
|
39209
|
+
|
|
37013
39210
|
// src/lib/migration-paths.ts
|
|
37014
39211
|
import { homedir as homedir12 } from "node:os";
|
|
37015
|
-
import { join as
|
|
39212
|
+
import { join as join17 } from "node:path";
|
|
37016
39213
|
function getOpenCodeDatabasePath() {
|
|
37017
39214
|
const dataHome = process.env.XDG_DATA_HOME?.trim();
|
|
37018
|
-
return
|
|
39215
|
+
return join17(dataHome || join17(homedir12(), ".local", "share"), "opencode", "opencode.db");
|
|
37019
39216
|
}
|
|
37020
39217
|
function projectPathToPiSessionSlug(projectPath, platform = process.platform) {
|
|
37021
39218
|
const separators = platform === "win32" ? /[:\\/]+/g : /\/+/g;
|
|
@@ -37038,12 +39235,12 @@ __export(exports_migrate, {
|
|
|
37038
39235
|
});
|
|
37039
39236
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
37040
39237
|
import { unlinkSync as unlinkSync3 } from "node:fs";
|
|
37041
|
-
import { join as
|
|
39238
|
+
import { join as join18 } from "node:path";
|
|
37042
39239
|
function defaultOpenCodeDbPath() {
|
|
37043
39240
|
return getOpenCodeDatabasePath();
|
|
37044
39241
|
}
|
|
37045
39242
|
function defaultCortexkitDbPath() {
|
|
37046
|
-
return
|
|
39243
|
+
return join18(getMagicContextStorageDir(), "context.db");
|
|
37047
39244
|
}
|
|
37048
39245
|
function defaultPiSessionsRoot() {
|
|
37049
39246
|
return getPiSessionsRoot();
|
|
@@ -37138,11 +39335,11 @@ function tokensToPiUsage(tokens) {
|
|
|
37138
39335
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
37139
39336
|
};
|
|
37140
39337
|
}
|
|
37141
|
-
function makeMessageEntry(role, text3,
|
|
39338
|
+
function makeMessageEntry(role, text3, timestamp2, parentId, usage) {
|
|
37142
39339
|
const message = {
|
|
37143
39340
|
role,
|
|
37144
39341
|
content: [{ type: "text", text: text3 }],
|
|
37145
|
-
timestamp: Date.parse(
|
|
39342
|
+
timestamp: Date.parse(timestamp2)
|
|
37146
39343
|
};
|
|
37147
39344
|
if (role === "assistant") {
|
|
37148
39345
|
message.usage = usage;
|
|
@@ -37151,30 +39348,30 @@ function makeMessageEntry(role, text3, timestamp, parentId, usage) {
|
|
|
37151
39348
|
type: "message",
|
|
37152
39349
|
id: shortId(),
|
|
37153
39350
|
parentId,
|
|
37154
|
-
timestamp,
|
|
39351
|
+
timestamp: timestamp2,
|
|
37155
39352
|
message
|
|
37156
39353
|
};
|
|
37157
39354
|
}
|
|
37158
|
-
function makeThinkingEntry(text3,
|
|
39355
|
+
function makeThinkingEntry(text3, timestamp2, parentId, usage) {
|
|
37159
39356
|
return {
|
|
37160
39357
|
type: "message",
|
|
37161
39358
|
id: shortId(),
|
|
37162
39359
|
parentId,
|
|
37163
|
-
timestamp,
|
|
39360
|
+
timestamp: timestamp2,
|
|
37164
39361
|
message: {
|
|
37165
39362
|
role: "assistant",
|
|
37166
39363
|
content: [{ type: "thinking", thinking: text3, thinkingSignature: null }],
|
|
37167
|
-
timestamp: Date.parse(
|
|
39364
|
+
timestamp: Date.parse(timestamp2),
|
|
37168
39365
|
usage
|
|
37169
39366
|
}
|
|
37170
39367
|
};
|
|
37171
39368
|
}
|
|
37172
|
-
function makeToolCallEntry(tool,
|
|
39369
|
+
function makeToolCallEntry(tool, timestamp2, parentId, usage) {
|
|
37173
39370
|
return {
|
|
37174
39371
|
type: "message",
|
|
37175
39372
|
id: shortId(),
|
|
37176
39373
|
parentId,
|
|
37177
|
-
timestamp,
|
|
39374
|
+
timestamp: timestamp2,
|
|
37178
39375
|
message: {
|
|
37179
39376
|
role: "assistant",
|
|
37180
39377
|
content: [
|
|
@@ -37185,24 +39382,24 @@ function makeToolCallEntry(tool, timestamp, parentId, usage) {
|
|
|
37185
39382
|
arguments: tool.input ?? {}
|
|
37186
39383
|
}
|
|
37187
39384
|
],
|
|
37188
|
-
timestamp: Date.parse(
|
|
39385
|
+
timestamp: Date.parse(timestamp2),
|
|
37189
39386
|
usage
|
|
37190
39387
|
}
|
|
37191
39388
|
};
|
|
37192
39389
|
}
|
|
37193
|
-
function makeToolResultEntry(tool,
|
|
39390
|
+
function makeToolResultEntry(tool, timestamp2, parentId) {
|
|
37194
39391
|
return {
|
|
37195
39392
|
type: "message",
|
|
37196
39393
|
id: shortId(),
|
|
37197
39394
|
parentId,
|
|
37198
|
-
timestamp,
|
|
39395
|
+
timestamp: timestamp2,
|
|
37199
39396
|
message: {
|
|
37200
39397
|
role: "toolResult",
|
|
37201
39398
|
toolCallId: tool.callId,
|
|
37202
39399
|
toolName: tool.name,
|
|
37203
39400
|
content: [{ type: "text", text: textFromUnknown(tool.output) }],
|
|
37204
39401
|
isError: false,
|
|
37205
|
-
timestamp: Date.parse(
|
|
39402
|
+
timestamp: Date.parse(timestamp2)
|
|
37206
39403
|
}
|
|
37207
39404
|
};
|
|
37208
39405
|
}
|
|
@@ -37277,7 +39474,7 @@ The following conversation was migrated from a different harness. Reasoning cont
|
|
|
37277
39474
|
const role = roleFromMessage(message);
|
|
37278
39475
|
if (!role)
|
|
37279
39476
|
continue;
|
|
37280
|
-
const
|
|
39477
|
+
const timestamp2 = isoFromMs(message.time_created, params.now);
|
|
37281
39478
|
const tokens = tokensFromMessage(message);
|
|
37282
39479
|
const usage = tokensToPiUsage(tokens);
|
|
37283
39480
|
let lastEntryIdForMessage = null;
|
|
@@ -37285,7 +39482,7 @@ The following conversation was migrated from a different harness. Reasoning cont
|
|
|
37285
39482
|
const newEntries = convertPartToEntries({
|
|
37286
39483
|
role,
|
|
37287
39484
|
row: part,
|
|
37288
|
-
timestamp,
|
|
39485
|
+
timestamp: timestamp2,
|
|
37289
39486
|
parentId,
|
|
37290
39487
|
usage
|
|
37291
39488
|
});
|
|
@@ -37509,7 +39706,7 @@ function migrateOpenCodeSessionToPi(opts) {
|
|
|
37509
39706
|
const provider = opts.provider ?? model.provider;
|
|
37510
39707
|
const modelId = opts.modelId ?? model.modelId;
|
|
37511
39708
|
const cwd = session.directory ?? session.path ?? process.cwd();
|
|
37512
|
-
const outputDir =
|
|
39709
|
+
const outputDir = join18(piSessionsRoot, projectPathToPiDirSlug(cwd));
|
|
37513
39710
|
const buildResult = buildPiEntries({
|
|
37514
39711
|
session,
|
|
37515
39712
|
messages,
|
|
@@ -37538,7 +39735,7 @@ function migrateOpenCodeSessionToPi(opts) {
|
|
|
37538
39735
|
commitMagicContextState = plan.commit;
|
|
37539
39736
|
}
|
|
37540
39737
|
const compactionMarker = insertCompactionMarker(buildResult.entries, copyResult.lastCompartmentEndPiEntryId);
|
|
37541
|
-
const outputPath =
|
|
39738
|
+
const outputPath = join18(outputDir, `${formatPiFilenameTimestamp(now)}_${buildResult.piSessionId}.jsonl`);
|
|
37542
39739
|
const jsonl = `${buildResult.entries.map((entry) => JSON.stringify(entry)).join(`
|
|
37543
39740
|
`)}
|
|
37544
39741
|
`;
|
|
@@ -37784,9 +39981,9 @@ __export(exports_migrate_session, {
|
|
|
37784
39981
|
planMigrateSession: () => planMigrateSession,
|
|
37785
39982
|
applyMigrateSession: () => applyMigrateSession
|
|
37786
39983
|
});
|
|
37787
|
-
import { existsSync as
|
|
39984
|
+
import { existsSync as existsSync21, realpathSync as realpathSync4 } from "node:fs";
|
|
37788
39985
|
import { homedir as homedir13 } from "node:os";
|
|
37789
|
-
import path4, { join as
|
|
39986
|
+
import path4, { join as join19 } from "node:path";
|
|
37790
39987
|
function existingSessionColumns(db) {
|
|
37791
39988
|
const rows = db.prepare("PRAGMA table_info(session)").all();
|
|
37792
39989
|
return new Set(rows.map((r2) => r2.name).filter((n2) => typeof n2 === "string"));
|
|
@@ -37940,14 +40137,14 @@ function defaultOpenCodeDbPath2() {
|
|
|
37940
40137
|
return getOpenCodeDatabasePath();
|
|
37941
40138
|
}
|
|
37942
40139
|
function defaultContextDbPath() {
|
|
37943
|
-
return
|
|
40140
|
+
return join19(getMagicContextStorageDir(), "context.db");
|
|
37944
40141
|
}
|
|
37945
40142
|
function realDeps(opencodeDb, contextDb) {
|
|
37946
40143
|
return {
|
|
37947
40144
|
opencodeDb,
|
|
37948
40145
|
contextDb,
|
|
37949
40146
|
resolveIdentity: resolveProjectIdentity,
|
|
37950
|
-
hasGitDir: (dir) =>
|
|
40147
|
+
hasGitDir: (dir) => existsSync21(join19(dir, ".git")),
|
|
37951
40148
|
realpath: (p2) => realpathSync4(p2)
|
|
37952
40149
|
};
|
|
37953
40150
|
}
|
|
@@ -38025,8 +40222,8 @@ async function runMigrateSessionCli(args) {
|
|
|
38025
40222
|
printMigrateSessionHelp();
|
|
38026
40223
|
return 1;
|
|
38027
40224
|
}
|
|
38028
|
-
const expandedTo = toDir.startsWith("~") ?
|
|
38029
|
-
if (!
|
|
40225
|
+
const expandedTo = toDir.startsWith("~") ? join19(homedir13(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
|
|
40226
|
+
if (!existsSync21(expandedTo)) {
|
|
38030
40227
|
console.error(`Target directory does not exist: ${expandedTo}`);
|
|
38031
40228
|
return 1;
|
|
38032
40229
|
}
|
|
@@ -38383,7 +40580,7 @@ var init_v22_backfill_commands = __esm(async () => {
|
|
|
38383
40580
|
});
|
|
38384
40581
|
|
|
38385
40582
|
// ../pi-plugin/src/config/index.ts
|
|
38386
|
-
import { existsSync as
|
|
40583
|
+
import { existsSync as existsSync22, readFileSync as readFileSync14 } from "node:fs";
|
|
38387
40584
|
function getProjectConfigPaths(cwd) {
|
|
38388
40585
|
const basePath = cortexKitProjectConfigBasePath(cwd);
|
|
38389
40586
|
return [`${basePath}.jsonc`, `${basePath}.json`];
|
|
@@ -38393,25 +40590,28 @@ function getUserConfigPaths() {
|
|
|
38393
40590
|
return [`${basePath}.jsonc`, `${basePath}.json`];
|
|
38394
40591
|
}
|
|
38395
40592
|
function resolveFirstExisting(paths) {
|
|
38396
|
-
return paths.find((path6) =>
|
|
40593
|
+
return paths.find((path6) => existsSync22(path6));
|
|
38397
40594
|
}
|
|
38398
40595
|
function resolvePiLegacyFallback(sources) {
|
|
38399
|
-
return sources.find((source) =>
|
|
40596
|
+
return sources.find((source) => existsSync22(source.path)) ?? null;
|
|
38400
40597
|
}
|
|
38401
40598
|
function loadConfigFile(path6, scope) {
|
|
38402
40599
|
try {
|
|
38403
|
-
const rawText =
|
|
40600
|
+
const rawText = readFileSync14(path6, "utf-8");
|
|
38404
40601
|
const substituted = substituteConfigVariables({
|
|
38405
40602
|
text: rawText,
|
|
38406
40603
|
configPath: path6,
|
|
38407
40604
|
isProjectConfig: scope === "project"
|
|
38408
40605
|
});
|
|
40606
|
+
const rejectedKeyPaths = [];
|
|
40607
|
+
const config2 = sanitizeParsedJson(import_comment_json7.parse(substituted.text), { onRejectedKey: (keyPath) => rejectedKeyPaths.push(keyPath.join(".")) });
|
|
40608
|
+
const unsafeKeyWarnings = rejectedKeyPaths.map((keyPath) => `Ignored unsafe config key "${keyPath}" (security: prototype-pollution keys are not allowed).`);
|
|
38409
40609
|
return {
|
|
38410
40610
|
path: path6,
|
|
38411
40611
|
scope,
|
|
38412
|
-
config:
|
|
38413
|
-
warnings: substituted.warnings.map((warning) => `${path6}: ${warning}`),
|
|
38414
|
-
loadOutcome: substituted.warnings.length > 0 ? "substitution-failure" : "ok"
|
|
40612
|
+
config: config2,
|
|
40613
|
+
warnings: [...substituted.warnings, ...unsafeKeyWarnings].map((warning) => `${path6}: ${warning}`),
|
|
40614
|
+
loadOutcome: rejectedKeyPaths.length > 0 ? "schema-recovery" : substituted.warnings.length > 0 ? "substitution-failure" : "ok"
|
|
38415
40615
|
};
|
|
38416
40616
|
} catch (error51) {
|
|
38417
40617
|
const message = error51 instanceof Error ? error51.message : String(error51);
|
|
@@ -38449,11 +40649,28 @@ function redactConfigValue2(value) {
|
|
|
38449
40649
|
function isPlainObject4(value) {
|
|
38450
40650
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38451
40651
|
}
|
|
40652
|
+
function defineOwnConfigValue2(target, key, value) {
|
|
40653
|
+
Object.defineProperty(target, key, {
|
|
40654
|
+
value,
|
|
40655
|
+
enumerable: true,
|
|
40656
|
+
configurable: true,
|
|
40657
|
+
writable: true
|
|
40658
|
+
});
|
|
40659
|
+
}
|
|
38452
40660
|
function mergeRawConfigs(base, override) {
|
|
38453
|
-
const merged = {
|
|
38454
|
-
for (const
|
|
38455
|
-
|
|
38456
|
-
|
|
40661
|
+
const merged = {};
|
|
40662
|
+
for (const key of Object.keys(base)) {
|
|
40663
|
+
if (isPrototypePollutionKey(key))
|
|
40664
|
+
continue;
|
|
40665
|
+
defineOwnConfigValue2(merged, key, base[key]);
|
|
40666
|
+
}
|
|
40667
|
+
for (const key of Object.keys(override)) {
|
|
40668
|
+
if (isPrototypePollutionKey(key))
|
|
40669
|
+
continue;
|
|
40670
|
+
const overrideValue = override[key];
|
|
40671
|
+
const baseValue = Object.hasOwn(base, key) ? base[key] : undefined;
|
|
40672
|
+
const mergedValue = isPlainObject4(baseValue) && isPlainObject4(overrideValue) ? mergeRawConfigs(baseValue, overrideValue) : overrideValue;
|
|
40673
|
+
defineOwnConfigValue2(merged, key, mergedValue);
|
|
38457
40674
|
}
|
|
38458
40675
|
return merged;
|
|
38459
40676
|
}
|
|
@@ -38533,7 +40750,7 @@ function loadPiConfig(opts = {}) {
|
|
|
38533
40750
|
if (loaded)
|
|
38534
40751
|
loadedFiles.push(loaded);
|
|
38535
40752
|
}
|
|
38536
|
-
const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) =>
|
|
40753
|
+
const legacyProjectUnmigrated = !projectPath && !projectLegacyFallback && legacySources.project.some((source) => existsSync22(source.path));
|
|
38537
40754
|
const userPath = resolveFirstExisting(getUserConfigPaths());
|
|
38538
40755
|
const userLegacyFallback = userPath ? null : resolvePiLegacyFallback(harnessLegacy.user);
|
|
38539
40756
|
const userReadPath = userPath ?? userLegacyFallback?.path;
|
|
@@ -38542,7 +40759,7 @@ function loadPiConfig(opts = {}) {
|
|
|
38542
40759
|
if (loaded)
|
|
38543
40760
|
loadedFiles.push(loaded);
|
|
38544
40761
|
}
|
|
38545
|
-
const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) =>
|
|
40762
|
+
const legacyUserUnmigrated = !userPath && !userLegacyFallback && legacySources.user.some((source) => existsSync22(source.path));
|
|
38546
40763
|
if (userLegacyFallback) {
|
|
38547
40764
|
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.`);
|
|
38548
40765
|
} else if (legacyUserUnmigrated) {
|
|
@@ -38602,10 +40819,17 @@ var init_config2 = __esm(() => {
|
|
|
38602
40819
|
init_project_security();
|
|
38603
40820
|
init_magic_context();
|
|
38604
40821
|
init_variable();
|
|
40822
|
+
init_jsonc_parser();
|
|
38605
40823
|
init_models_dev_cache();
|
|
38606
40824
|
import_comment_json7 = __toESM(require_src3(), 1);
|
|
38607
40825
|
});
|
|
38608
40826
|
|
|
40827
|
+
// src/lib/database-repair-guidance.ts
|
|
40828
|
+
function formatDatabaseRepairGuidance(dbPath) {
|
|
40829
|
+
return `Database: ${dbPath}. Recovery: run \`${DATABASE_REPAIR_COMMAND}\` (salvage needs a sqlite3 shell built with SQLITE_ENABLE_DBPAGE_VTAB; without one, the command backs up and stops without modifying the database).`;
|
|
40830
|
+
}
|
|
40831
|
+
var DATABASE_REPAIR_COMMAND = "bunx @cortexkit/magic-context@latest doctor repair-db";
|
|
40832
|
+
|
|
38609
40833
|
// ../plugin/src/shared/redaction.ts
|
|
38610
40834
|
import { homedir as homedir14, userInfo } from "node:os";
|
|
38611
40835
|
function escapeRegex2(value) {
|
|
@@ -38815,10 +41039,10 @@ var init_redaction2 = __esm(() => {
|
|
|
38815
41039
|
});
|
|
38816
41040
|
|
|
38817
41041
|
// src/commands/doctor-omp.ts
|
|
38818
|
-
import { execFileSync as execFileSync5, spawnSync as
|
|
38819
|
-
import { existsSync as
|
|
38820
|
-
import { createRequire as
|
|
38821
|
-
import { dirname as
|
|
41042
|
+
import { execFileSync as execFileSync5, spawnSync as spawnSync4 } from "node:child_process";
|
|
41043
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync8, readFileSync as readFileSync15 } from "node:fs";
|
|
41044
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
41045
|
+
import { dirname as dirname12, join as join20, resolve as resolve5 } from "node:path";
|
|
38822
41046
|
function parseSemver(value) {
|
|
38823
41047
|
const match = value?.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
38824
41048
|
return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
|
|
@@ -38849,7 +41073,7 @@ function printResult(prompts, result) {
|
|
|
38849
41073
|
prompts.log.error(line);
|
|
38850
41074
|
}
|
|
38851
41075
|
function selfVersion() {
|
|
38852
|
-
const req =
|
|
41076
|
+
const req = createRequire2(import.meta.url);
|
|
38853
41077
|
for (const path6 of ["../../package.json", "../package.json"]) {
|
|
38854
41078
|
try {
|
|
38855
41079
|
const value = req(path6);
|
|
@@ -38860,10 +41084,10 @@ function selfVersion() {
|
|
|
38860
41084
|
return "unknown";
|
|
38861
41085
|
}
|
|
38862
41086
|
function readConfig2(path6) {
|
|
38863
|
-
if (!
|
|
41087
|
+
if (!existsSync23(path6))
|
|
38864
41088
|
return {};
|
|
38865
41089
|
try {
|
|
38866
|
-
const parsed = import_comment_json8.parse(
|
|
41090
|
+
const parsed = import_comment_json8.parse(readFileSync15(path6, "utf-8"));
|
|
38867
41091
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? {} : { error: "top level is not an object" };
|
|
38868
41092
|
} catch (error51) {
|
|
38869
41093
|
return { error: error51 instanceof Error ? error51.message : String(error51) };
|
|
@@ -38873,7 +41097,7 @@ function pluginDeclaresOmp(path6) {
|
|
|
38873
41097
|
if (!path6)
|
|
38874
41098
|
return null;
|
|
38875
41099
|
try {
|
|
38876
|
-
const pkg = JSON.parse(
|
|
41100
|
+
const pkg = JSON.parse(readFileSync15(join20(path6, "package.json"), "utf-8"));
|
|
38877
41101
|
return Array.isArray(pkg.omp?.extensions) || Array.isArray(pkg.pi?.extensions);
|
|
38878
41102
|
} catch {
|
|
38879
41103
|
return null;
|
|
@@ -38954,7 +41178,7 @@ async function runHealthChecks(options) {
|
|
|
38954
41178
|
}
|
|
38955
41179
|
}
|
|
38956
41180
|
const userConfigPath = getOmpUserConfigPath();
|
|
38957
|
-
if (!
|
|
41181
|
+
if (!existsSync23(userConfigPath)) {
|
|
38958
41182
|
add(results, "warn", `No Magic Context user config at ${userConfigPath}`);
|
|
38959
41183
|
repairPlan.writeUserConfig = true;
|
|
38960
41184
|
} else {
|
|
@@ -38970,8 +41194,8 @@ async function runHealthChecks(options) {
|
|
|
38970
41194
|
else
|
|
38971
41195
|
for (const warning of loaded.warnings.slice(0, 5))
|
|
38972
41196
|
add(results, "warn", warning);
|
|
38973
|
-
const dbPath =
|
|
38974
|
-
if (!
|
|
41197
|
+
const dbPath = join20(getMagicContextStorageDir(), "context.db");
|
|
41198
|
+
if (!existsSync23(dbPath))
|
|
38975
41199
|
add(results, "info", `Shared context DB will be created at ${dbPath}`);
|
|
38976
41200
|
else {
|
|
38977
41201
|
let db = null;
|
|
@@ -38981,9 +41205,11 @@ async function runHealthChecks(options) {
|
|
|
38981
41205
|
if (integrity?.integrity_check === "ok")
|
|
38982
41206
|
add(results, "pass", "SQLite integrity_check: ok");
|
|
38983
41207
|
else
|
|
38984
|
-
add(results, "fail", `SQLite integrity_check: ${String(integrity?.integrity_check)}
|
|
41208
|
+
add(results, "fail", `SQLite integrity_check: ${String(integrity?.integrity_check)}
|
|
41209
|
+
${formatDatabaseRepairGuidance(dbPath)}`);
|
|
38985
41210
|
} catch (error51) {
|
|
38986
|
-
add(results, "fail", `Could not inspect shared DB: ${String(error51)}
|
|
41211
|
+
add(results, "fail", `Could not inspect shared DB: ${String(error51)}
|
|
41212
|
+
${formatDatabaseRepairGuidance(dbPath)}`);
|
|
38987
41213
|
} finally {
|
|
38988
41214
|
db?.close();
|
|
38989
41215
|
}
|
|
@@ -38998,7 +41224,7 @@ async function runHealthChecks(options) {
|
|
|
38998
41224
|
add(results, "info", `OMP non-global config: ${source}`);
|
|
38999
41225
|
}
|
|
39000
41226
|
const logPath = getMagicContextLogPath2("pi");
|
|
39001
|
-
add(results, "info", `Pi-compatible runtime log: ${logPath}${
|
|
41227
|
+
add(results, "info", `Pi-compatible runtime log: ${logPath}${existsSync23(logPath) ? "" : " (not created yet)"}`);
|
|
39002
41228
|
if (!options.quiet)
|
|
39003
41229
|
for (const result of results)
|
|
39004
41230
|
printResult(options.prompts, result);
|
|
@@ -39011,7 +41237,7 @@ async function runHealthChecks(options) {
|
|
|
39011
41237
|
};
|
|
39012
41238
|
}
|
|
39013
41239
|
function writeDefaultConfig(path6) {
|
|
39014
|
-
mkdirSync8(
|
|
41240
|
+
mkdirSync8(dirname12(path6), { recursive: true });
|
|
39015
41241
|
const config2 = {
|
|
39016
41242
|
$schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
|
|
39017
41243
|
...MagicContextConfigSchema.parse({})
|
|
@@ -39021,7 +41247,7 @@ function writeDefaultConfig(path6) {
|
|
|
39021
41247
|
}
|
|
39022
41248
|
async function repair(plan, deps, prompts, cwd) {
|
|
39023
41249
|
let fixed = 0;
|
|
39024
|
-
if (plan.writeUserConfig && !
|
|
41250
|
+
if (plan.writeUserConfig && !existsSync23(getOmpUserConfigPath())) {
|
|
39025
41251
|
writeDefaultConfig(getOmpUserConfigPath());
|
|
39026
41252
|
prompts.log.success(`Wrote default Magic Context config to ${getOmpUserConfigPath()}`);
|
|
39027
41253
|
fixed += 1;
|
|
@@ -39057,7 +41283,7 @@ async function repair(plan, deps, prompts, cwd) {
|
|
|
39057
41283
|
}
|
|
39058
41284
|
return fixed;
|
|
39059
41285
|
}
|
|
39060
|
-
function
|
|
41286
|
+
function timestamp2(date5) {
|
|
39061
41287
|
return date5.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
39062
41288
|
}
|
|
39063
41289
|
async function runIssueFlow(options) {
|
|
@@ -39079,7 +41305,7 @@ async function runIssueFlow(options) {
|
|
|
39079
41305
|
...report.results.map((result) => `- ${result.status.toUpperCase()}: ${sanitizeDiagnosticText(result.message)}`)
|
|
39080
41306
|
].join(`
|
|
39081
41307
|
`);
|
|
39082
|
-
const path6 =
|
|
41308
|
+
const path6 = join20(options.cwd, `magic-context-omp-issue-${timestamp2(options.deps.now())}.md`);
|
|
39083
41309
|
writeFileAtomic(path6, `${body}
|
|
39084
41310
|
`);
|
|
39085
41311
|
options.prompts.log.success(`Sanitized report written to ${path6}`);
|
|
@@ -39115,8 +41341,8 @@ async function runIssueFlow(options) {
|
|
|
39115
41341
|
}
|
|
39116
41342
|
async function runDoctor(options = {}) {
|
|
39117
41343
|
const deps = {
|
|
39118
|
-
...
|
|
39119
|
-
prompts: options.prompts ??
|
|
41344
|
+
...DEFAULT_DEPS2,
|
|
41345
|
+
prompts: options.prompts ?? DEFAULT_DEPS2.prompts,
|
|
39120
41346
|
...options.deps
|
|
39121
41347
|
};
|
|
39122
41348
|
const prompts = options.prompts ?? deps.prompts;
|
|
@@ -39142,7 +41368,7 @@ async function runDoctor(options = {}) {
|
|
|
39142
41368
|
prompts.log.message(`Summary: PASS ${second.pass} / WARN ${second.warn} / FAIL ${second.fail}`);
|
|
39143
41369
|
return second.fail === 0 ? 0 : 1;
|
|
39144
41370
|
}
|
|
39145
|
-
var import_comment_json8, MIN_OMP_VERSION = "17.1.7",
|
|
41371
|
+
var import_comment_json8, MIN_OMP_VERSION = "17.1.7", DEFAULT_DEPS2;
|
|
39146
41372
|
var init_doctor_omp = __esm(async () => {
|
|
39147
41373
|
init_magic_context();
|
|
39148
41374
|
init_data_path();
|
|
@@ -39156,7 +41382,7 @@ var init_doctor_omp = __esm(async () => {
|
|
|
39156
41382
|
init_redaction2();
|
|
39157
41383
|
await init_database_access();
|
|
39158
41384
|
import_comment_json8 = __toESM(require_src3(), 1);
|
|
39159
|
-
|
|
41385
|
+
DEFAULT_DEPS2 = {
|
|
39160
41386
|
prompts: promptIO,
|
|
39161
41387
|
detectOmpBinary,
|
|
39162
41388
|
getOmpVersion,
|
|
@@ -39166,7 +41392,7 @@ var init_doctor_omp = __esm(async () => {
|
|
|
39166
41392
|
openExistingContextDatabase,
|
|
39167
41393
|
now: () => new Date,
|
|
39168
41394
|
execFileSync: execFileSync5,
|
|
39169
|
-
spawnSync:
|
|
41395
|
+
spawnSync: spawnSync4
|
|
39170
41396
|
};
|
|
39171
41397
|
});
|
|
39172
41398
|
|
|
@@ -39283,15 +41509,15 @@ var DEFAULT_TIMEOUT_MS = 1e4, MAX_PREVIEW_CHARS = 240;
|
|
|
39283
41509
|
|
|
39284
41510
|
// ../plugin/src/shared/tui-config.ts
|
|
39285
41511
|
import {
|
|
39286
|
-
chmodSync as
|
|
39287
|
-
existsSync as
|
|
41512
|
+
chmodSync as chmodSync4,
|
|
41513
|
+
existsSync as existsSync24,
|
|
39288
41514
|
mkdirSync as mkdirSync9,
|
|
39289
|
-
readFileSync as
|
|
39290
|
-
renameSync as
|
|
39291
|
-
statSync as
|
|
41515
|
+
readFileSync as readFileSync16,
|
|
41516
|
+
renameSync as renameSync4,
|
|
41517
|
+
statSync as statSync9,
|
|
39292
41518
|
writeFileSync as writeFileSync6
|
|
39293
41519
|
} from "node:fs";
|
|
39294
|
-
import { dirname as
|
|
41520
|
+
import { dirname as dirname13, join as join21 } from "node:path";
|
|
39295
41521
|
function pluginEntryId(entry) {
|
|
39296
41522
|
if (typeof entry === "string")
|
|
39297
41523
|
return entry;
|
|
@@ -39324,19 +41550,19 @@ function writeTuiConfigAtomic(configPath, config2) {
|
|
|
39324
41550
|
const tmpPath = `${configPath}.tmp`;
|
|
39325
41551
|
writeFileSync6(tmpPath, body);
|
|
39326
41552
|
try {
|
|
39327
|
-
if (
|
|
39328
|
-
|
|
41553
|
+
if (statSync9(configPath, { throwIfNoEntry: false })?.isFile()) {
|
|
41554
|
+
chmodSync4(tmpPath, statSync9(configPath).mode & 511);
|
|
39329
41555
|
}
|
|
39330
41556
|
} catch {}
|
|
39331
|
-
|
|
41557
|
+
renameSync4(tmpPath, configPath);
|
|
39332
41558
|
}
|
|
39333
41559
|
function resolveTuiConfigPath(configDirOverride) {
|
|
39334
41560
|
const configDir = configDirOverride ?? getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
|
|
39335
|
-
const jsoncPath =
|
|
39336
|
-
const jsonPath =
|
|
39337
|
-
if (
|
|
41561
|
+
const jsoncPath = join21(configDir, "tui.jsonc");
|
|
41562
|
+
const jsonPath = join21(configDir, "tui.json");
|
|
41563
|
+
if (existsSync24(jsoncPath))
|
|
39338
41564
|
return jsoncPath;
|
|
39339
|
-
if (
|
|
41565
|
+
if (existsSync24(jsonPath))
|
|
39340
41566
|
return jsonPath;
|
|
39341
41567
|
return jsoncPath;
|
|
39342
41568
|
}
|
|
@@ -39344,8 +41570,8 @@ function ensureTuiPluginEntry(options = {}) {
|
|
|
39344
41570
|
try {
|
|
39345
41571
|
const configPath = resolveTuiConfigPath(options.configDir);
|
|
39346
41572
|
let config2 = {};
|
|
39347
|
-
if (
|
|
39348
|
-
const raw =
|
|
41573
|
+
if (existsSync24(configPath)) {
|
|
41574
|
+
const raw = readFileSync16(configPath, "utf-8");
|
|
39349
41575
|
config2 = import_comment_json9.parse(raw) ?? {};
|
|
39350
41576
|
}
|
|
39351
41577
|
const plugins = Array.isArray(config2.plugin) ? [...config2.plugin] : [];
|
|
@@ -39379,7 +41605,7 @@ function ensureTuiPluginEntry(options = {}) {
|
|
|
39379
41605
|
}
|
|
39380
41606
|
}
|
|
39381
41607
|
config2.plugin = plugins;
|
|
39382
|
-
mkdirSync9(
|
|
41608
|
+
mkdirSync9(dirname13(configPath), { recursive: true });
|
|
39383
41609
|
writeTuiConfigAtomic(configPath, config2);
|
|
39384
41610
|
log3(`[magic-context] updated TUI plugin entry in ${configPath}`);
|
|
39385
41611
|
return true;
|
|
@@ -39397,12 +41623,12 @@ var init_tui_config = __esm(() => {
|
|
|
39397
41623
|
});
|
|
39398
41624
|
|
|
39399
41625
|
// src/lib/diagnostics-opencode.ts
|
|
39400
|
-
import { existsSync as
|
|
39401
|
-
import { createRequire as
|
|
41626
|
+
import { existsSync as existsSync25, readdirSync as readdirSync3, readFileSync as readFileSync17, statSync as statSync10 } from "node:fs";
|
|
41627
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
39402
41628
|
import { homedir as homedir15 } from "node:os";
|
|
39403
|
-
import { join as
|
|
41629
|
+
import { join as join22 } from "node:path";
|
|
39404
41630
|
function getSelfVersion() {
|
|
39405
|
-
const require2 =
|
|
41631
|
+
const require2 = createRequire3(import.meta.url);
|
|
39406
41632
|
for (const relPath of ["../../package.json", "../package.json"]) {
|
|
39407
41633
|
try {
|
|
39408
41634
|
const pkg = require2(relPath);
|
|
@@ -39418,8 +41644,8 @@ function getPluginCacheInfo() {
|
|
|
39418
41644
|
let cached2;
|
|
39419
41645
|
for (const installedPkgPath of getOpenCodePluginPackageJsonPaths()) {
|
|
39420
41646
|
try {
|
|
39421
|
-
if (
|
|
39422
|
-
const pkg = JSON.parse(
|
|
41647
|
+
if (existsSync25(installedPkgPath)) {
|
|
41648
|
+
const pkg = JSON.parse(readFileSync17(installedPkgPath, "utf-8"));
|
|
39423
41649
|
cached2 = typeof pkg.version === "string" ? pkg.version : undefined;
|
|
39424
41650
|
if (cached2)
|
|
39425
41651
|
break;
|
|
@@ -39431,12 +41657,12 @@ function getPluginCacheInfo() {
|
|
|
39431
41657
|
return { path: path6, cached: cached2, latest: getSelfVersion() };
|
|
39432
41658
|
}
|
|
39433
41659
|
function getStorageDir() {
|
|
39434
|
-
const dataHome = process.env.XDG_DATA_HOME ||
|
|
39435
|
-
return
|
|
41660
|
+
const dataHome = process.env.XDG_DATA_HOME || join22(homedir15(), ".local", "share");
|
|
41661
|
+
return join22(dataHome, "cortexkit", "magic-context");
|
|
39436
41662
|
}
|
|
39437
41663
|
function fileSize(path6) {
|
|
39438
41664
|
try {
|
|
39439
|
-
return
|
|
41665
|
+
return existsSync25(path6) ? statSync10(path6).size : 0;
|
|
39440
41666
|
} catch {
|
|
39441
41667
|
return 0;
|
|
39442
41668
|
}
|
|
@@ -39448,10 +41674,10 @@ function sanitizeValue(value) {
|
|
|
39448
41674
|
return sanitizeConfigValue(value);
|
|
39449
41675
|
}
|
|
39450
41676
|
function readConfig3(path6) {
|
|
39451
|
-
if (!
|
|
41677
|
+
if (!existsSync25(path6))
|
|
39452
41678
|
return { value: null };
|
|
39453
41679
|
try {
|
|
39454
|
-
const raw =
|
|
41680
|
+
const raw = readFileSync17(path6, "utf-8");
|
|
39455
41681
|
const value = import_comment_json10.parse(raw);
|
|
39456
41682
|
return { value };
|
|
39457
41683
|
} catch (error51) {
|
|
@@ -39476,7 +41702,7 @@ function configHasPluginEntry(config2) {
|
|
|
39476
41702
|
}
|
|
39477
41703
|
function parseHistorianDumpMeta(path6) {
|
|
39478
41704
|
try {
|
|
39479
|
-
const xml =
|
|
41705
|
+
const xml = readFileSync17(path6, "utf-8");
|
|
39480
41706
|
const parsed = parseCompartmentOutput(xml);
|
|
39481
41707
|
const factCountByCategory = {};
|
|
39482
41708
|
for (const fact of parsed.facts) {
|
|
@@ -39509,11 +41735,11 @@ function parseHistorianDumpMeta(path6) {
|
|
|
39509
41735
|
}
|
|
39510
41736
|
}
|
|
39511
41737
|
function listDumpsInDir(dir, limit) {
|
|
39512
|
-
if (!
|
|
41738
|
+
if (!existsSync25(dir))
|
|
39513
41739
|
return { count: 0, recent: [] };
|
|
39514
41740
|
try {
|
|
39515
41741
|
const entries = readdirSync3(dir).filter((name) => name.endsWith(".xml")).map((name) => {
|
|
39516
|
-
const stat =
|
|
41742
|
+
const stat = statSync10(join22(dir, name));
|
|
39517
41743
|
return {
|
|
39518
41744
|
name,
|
|
39519
41745
|
mtime: stat.mtimeMs,
|
|
@@ -39522,7 +41748,7 @@ function listDumpsInDir(dir, limit) {
|
|
|
39522
41748
|
}).sort((a3, b2) => b2.mtime - a3.mtime);
|
|
39523
41749
|
const now = Date.now();
|
|
39524
41750
|
const recent = entries.slice(0, limit).map((entry) => {
|
|
39525
|
-
const meta3 = parseHistorianDumpMeta(
|
|
41751
|
+
const meta3 = parseHistorianDumpMeta(join22(dir, entry.name));
|
|
39526
41752
|
const summary = {
|
|
39527
41753
|
name: entry.name,
|
|
39528
41754
|
ageMinutes: Math.round((now - entry.mtime) / 60000),
|
|
@@ -39577,9 +41803,9 @@ function collectHistorianDumps(recentSessions) {
|
|
|
39577
41803
|
};
|
|
39578
41804
|
}
|
|
39579
41805
|
async function collectRecentSessions() {
|
|
39580
|
-
const dataHome = process.env.XDG_DATA_HOME ||
|
|
39581
|
-
const opencodeDbPath =
|
|
39582
|
-
if (!
|
|
41806
|
+
const dataHome = process.env.XDG_DATA_HOME || join22(process.env.HOME || homedir15(), ".local", "share");
|
|
41807
|
+
const opencodeDbPath = join22(dataHome, "opencode", "opencode.db");
|
|
41808
|
+
if (!existsSync25(opencodeDbPath))
|
|
39583
41809
|
return [];
|
|
39584
41810
|
if (typeof globalThis.Bun === "undefined") {
|
|
39585
41811
|
return [];
|
|
@@ -39613,8 +41839,8 @@ async function collectRecentSessions() {
|
|
|
39613
41839
|
}
|
|
39614
41840
|
}
|
|
39615
41841
|
async function collectHistorianFailures(storageDirPath) {
|
|
39616
|
-
const contextDbPath =
|
|
39617
|
-
if (!
|
|
41842
|
+
const contextDbPath = join22(storageDirPath, "context.db");
|
|
41843
|
+
if (!existsSync25(contextDbPath))
|
|
39618
41844
|
return [];
|
|
39619
41845
|
if (typeof globalThis.Bun === "undefined") {
|
|
39620
41846
|
return [];
|
|
@@ -39647,8 +41873,8 @@ async function collectHistorianFailures(storageDirPath) {
|
|
|
39647
41873
|
}
|
|
39648
41874
|
}
|
|
39649
41875
|
async function collectHistorianRuns(storageDirPath) {
|
|
39650
|
-
const contextDbPath =
|
|
39651
|
-
if (!
|
|
41876
|
+
const contextDbPath = join22(storageDirPath, "context.db");
|
|
41877
|
+
if (!existsSync25(contextDbPath))
|
|
39652
41878
|
return [];
|
|
39653
41879
|
if (typeof globalThis.Bun === "undefined")
|
|
39654
41880
|
return [];
|
|
@@ -39717,9 +41943,9 @@ async function collectDiagnostics() {
|
|
|
39717
41943
|
const tuiConfig = readConfig3(configPaths.tuiConfig);
|
|
39718
41944
|
const magicContextConfig = readConfig3(configPaths.magicContextConfig);
|
|
39719
41945
|
const storageDirPath = getStorageDir();
|
|
39720
|
-
const contextDbPath =
|
|
41946
|
+
const contextDbPath = join22(storageDirPath, "context.db");
|
|
39721
41947
|
const logPath = getMagicContextLogPath2("opencode");
|
|
39722
|
-
const logFileSize =
|
|
41948
|
+
const logFileSize = existsSync25(logPath) ? statSync10(logPath).size : 0;
|
|
39723
41949
|
let compactionEnabled = false;
|
|
39724
41950
|
try {
|
|
39725
41951
|
compactionEnabled = isCompactionEnabled(loadPluginConfig(process.cwd()));
|
|
@@ -39747,14 +41973,14 @@ async function collectDiagnostics() {
|
|
|
39747
41973
|
opencodeConfigHasPlugin: configHasPluginEntry(opencodeConfig.value),
|
|
39748
41974
|
tuiConfigHasPlugin: configHasPluginEntry(tuiConfig.value),
|
|
39749
41975
|
magicContextConfig: {
|
|
39750
|
-
exists:
|
|
41976
|
+
exists: existsSync25(configPaths.magicContextConfig),
|
|
39751
41977
|
...magicContextConfig.error ? { parseError: magicContextConfig.error } : {},
|
|
39752
41978
|
flags: sanitizeValue(magicContextConfig.value ?? {}) ?? {}
|
|
39753
41979
|
},
|
|
39754
41980
|
pluginCache: getPluginCacheInfo(),
|
|
39755
41981
|
storageDir: {
|
|
39756
41982
|
path: storageDirPath,
|
|
39757
|
-
exists:
|
|
41983
|
+
exists: existsSync25(storageDirPath),
|
|
39758
41984
|
contextDbSizeBytes: fileSize(contextDbPath)
|
|
39759
41985
|
},
|
|
39760
41986
|
conflicts: {
|
|
@@ -39765,7 +41991,7 @@ async function collectDiagnostics() {
|
|
|
39765
41991
|
},
|
|
39766
41992
|
logFile: {
|
|
39767
41993
|
path: logPath,
|
|
39768
|
-
exists:
|
|
41994
|
+
exists: existsSync25(logPath),
|
|
39769
41995
|
sizeKb: Math.round(logFileSize / 1024)
|
|
39770
41996
|
},
|
|
39771
41997
|
recentSessions,
|
|
@@ -39917,17 +42143,17 @@ var init_diagnostics_opencode = __esm(() => {
|
|
|
39917
42143
|
});
|
|
39918
42144
|
|
|
39919
42145
|
// src/lib/embedding-runtime.ts
|
|
39920
|
-
import { spawnSync as
|
|
39921
|
-
import { existsSync as
|
|
39922
|
-
import { createRequire as
|
|
39923
|
-
import { dirname as
|
|
42146
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
42147
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
42148
|
+
import { createRequire as createRequire4 } from "node:module";
|
|
42149
|
+
import { dirname as dirname14, join as join23, sep } from "node:path";
|
|
39924
42150
|
function describeError(error51) {
|
|
39925
42151
|
const message = error51 instanceof Error ? error51.message : String(error51 ?? "unknown error");
|
|
39926
42152
|
const code = error51?.code;
|
|
39927
42153
|
return typeof code === "string" && code.length > 0 ? `${code}: ${message}` : message;
|
|
39928
42154
|
}
|
|
39929
42155
|
function runOnnxRuntimeNodeLoadProbeChild(packageDir) {
|
|
39930
|
-
return
|
|
42156
|
+
return spawnSync5(process.execPath, ["-e", ONNX_RUNTIME_NODE_LOAD_PROBE_SCRIPT], {
|
|
39931
42157
|
encoding: "utf8",
|
|
39932
42158
|
env: { ...process.env, [ONNX_LOAD_PROBE_PACKAGE_DIR_ENV]: packageDir },
|
|
39933
42159
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -40029,25 +42255,25 @@ function expectedBinaryRelPath(platform, arch) {
|
|
|
40029
42255
|
const supportedArch = arch === "x64" || arch === "arm64";
|
|
40030
42256
|
if (!supportedPlatform || !supportedArch)
|
|
40031
42257
|
return null;
|
|
40032
|
-
return
|
|
42258
|
+
return join23("bin", "napi-v6", platform, arch, "onnxruntime_binding.node");
|
|
40033
42259
|
}
|
|
40034
42260
|
function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform, arch = process.arch) {
|
|
40035
|
-
const packageDir =
|
|
40036
|
-
if (!
|
|
42261
|
+
const packageDir = join23(installRoot, "node_modules", "onnxruntime-node");
|
|
42262
|
+
if (!existsSync26(join23(packageDir, "package.json"))) {
|
|
40037
42263
|
return { state: "package-missing", packageDir };
|
|
40038
42264
|
}
|
|
40039
42265
|
const rel = expectedBinaryRelPath(platform, arch);
|
|
40040
42266
|
if (rel === null) {
|
|
40041
42267
|
return probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath: packageDir };
|
|
40042
42268
|
}
|
|
40043
|
-
const binaryPath =
|
|
40044
|
-
if (!
|
|
42269
|
+
const binaryPath = join23(packageDir, rel);
|
|
42270
|
+
if (!existsSync26(binaryPath)) {
|
|
40045
42271
|
return { state: "binary-missing", packageDir, expectedBinary: binaryPath };
|
|
40046
42272
|
}
|
|
40047
42273
|
return probeOnnxRuntimeNodeLoad(packageDir) ?? { state: "ok", binaryPath };
|
|
40048
42274
|
}
|
|
40049
42275
|
function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, arch = process.arch) {
|
|
40050
|
-
const existing = installRoots.filter((root) =>
|
|
42276
|
+
const existing = installRoots.filter((root) => existsSync26(root));
|
|
40051
42277
|
if (existing.length === 0) {
|
|
40052
42278
|
return {
|
|
40053
42279
|
state: "unknown",
|
|
@@ -40067,22 +42293,22 @@ function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, a
|
|
|
40067
42293
|
function packageDirFromResolved(resolvedPath, packageName) {
|
|
40068
42294
|
const marker = `node_modules${sep}${packageName.split("/").join(sep)}`;
|
|
40069
42295
|
const idx = resolvedPath.indexOf(marker);
|
|
40070
|
-
return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) :
|
|
42296
|
+
return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) : dirname14(resolvedPath);
|
|
40071
42297
|
}
|
|
40072
42298
|
function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.platform, arch = process.arch) {
|
|
40073
|
-
if (!
|
|
42299
|
+
if (!existsSync26(join23(pluginDir, "package.json"))) {
|
|
40074
42300
|
return { state: "unknown", reason: "plugin package dir not found" };
|
|
40075
42301
|
}
|
|
40076
42302
|
let onnxDir = null;
|
|
40077
42303
|
let resolveError;
|
|
40078
42304
|
try {
|
|
40079
|
-
const reqPlugin =
|
|
42305
|
+
const reqPlugin = createRequire4(join23(pluginDir, "package.json"));
|
|
40080
42306
|
try {
|
|
40081
42307
|
onnxDir = packageDirFromResolved(reqPlugin.resolve("onnxruntime-node"), "onnxruntime-node");
|
|
40082
42308
|
} catch {
|
|
40083
42309
|
const tfResolved = reqPlugin.resolve("@huggingface/transformers");
|
|
40084
42310
|
const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
|
|
40085
|
-
const reqTf =
|
|
42311
|
+
const reqTf = createRequire4(join23(tfDir, "package.json"));
|
|
40086
42312
|
onnxDir = packageDirFromResolved(reqTf.resolve("onnxruntime-node"), "onnxruntime-node");
|
|
40087
42313
|
}
|
|
40088
42314
|
} catch (error51) {
|
|
@@ -40090,7 +42316,7 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
|
|
|
40090
42316
|
if (resolveError === "ERR_MODULE_NOT_FOUND" || resolveError === "MODULE_NOT_FOUND") {
|
|
40091
42317
|
return {
|
|
40092
42318
|
state: "package-missing",
|
|
40093
|
-
packageDir:
|
|
42319
|
+
packageDir: join23(pluginDir, "node_modules", "onnxruntime-node")
|
|
40094
42320
|
};
|
|
40095
42321
|
}
|
|
40096
42322
|
return {
|
|
@@ -40105,8 +42331,8 @@ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.pl
|
|
|
40105
42331
|
if (rel === null) {
|
|
40106
42332
|
return probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath: onnxDir };
|
|
40107
42333
|
}
|
|
40108
|
-
const binaryPath =
|
|
40109
|
-
if (!
|
|
42334
|
+
const binaryPath = join23(onnxDir, rel);
|
|
42335
|
+
if (!existsSync26(binaryPath)) {
|
|
40110
42336
|
return { state: "binary-missing", packageDir: onnxDir, expectedBinary: binaryPath };
|
|
40111
42337
|
}
|
|
40112
42338
|
return probeOnnxRuntimeNodeLoad(onnxDir) ?? { state: "ok", binaryPath };
|
|
@@ -40235,8 +42461,8 @@ var init_issue_body = __esm(() => {
|
|
|
40235
42461
|
});
|
|
40236
42462
|
|
|
40237
42463
|
// src/lib/logs-opencode.ts
|
|
40238
|
-
import { readFileSync as
|
|
40239
|
-
import { join as
|
|
42464
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync7 } from "node:fs";
|
|
42465
|
+
import { join as join24 } from "node:path";
|
|
40240
42466
|
function sanitizeLogContent(content) {
|
|
40241
42467
|
return sanitizeDiagnosticText(content);
|
|
40242
42468
|
}
|
|
@@ -40278,7 +42504,7 @@ function filterLogLinesBySession(lines, sessionId) {
|
|
|
40278
42504
|
}
|
|
40279
42505
|
async function bundleIssueReport(report, description, title, sessionFilter = null) {
|
|
40280
42506
|
const LOG_TAIL_LINES = 400;
|
|
40281
|
-
const allLogLines = report.logFile.exists ?
|
|
42507
|
+
const allLogLines = report.logFile.exists ? readFileSync18(report.logFile.path, "utf-8").split(/\r?\n/) : [];
|
|
40282
42508
|
const logLines = filterLogLinesBySession(allLogLines, sessionFilter);
|
|
40283
42509
|
const recentLog = sanitizeLogContent(logLines.slice(-LOG_TAIL_LINES).join(`
|
|
40284
42510
|
`)).trim();
|
|
@@ -40329,7 +42555,7 @@ async function bundleIssueReport(report, description, title, sessionFilter = nul
|
|
|
40329
42555
|
].join(`
|
|
40330
42556
|
`);
|
|
40331
42557
|
const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
|
|
40332
|
-
const path6 =
|
|
42558
|
+
const path6 = join24(process.cwd(), `magic-context-issue-${formatTimestamp(new Date)}.md`);
|
|
40333
42559
|
writeFileSync7(path6, `${bodyMarkdown}
|
|
40334
42560
|
`);
|
|
40335
42561
|
return { path: path6, bodyMarkdown };
|
|
@@ -40701,22 +42927,22 @@ var init_storage_versions = __esm(async () => {
|
|
|
40701
42927
|
});
|
|
40702
42928
|
|
|
40703
42929
|
// src/commands/doctor-opencode-cache.ts
|
|
40704
|
-
import { existsSync as
|
|
42930
|
+
import { existsSync as existsSync27, readFileSync as readFileSync19, rmSync as rmSync3 } from "node:fs";
|
|
40705
42931
|
function readCachedPluginVersion(pluginCacheDir) {
|
|
40706
42932
|
try {
|
|
40707
42933
|
const installedPkgPath = getOpenCodePluginPackageJsonPath(pluginCacheDir);
|
|
40708
|
-
if (!
|
|
42934
|
+
if (!existsSync27(installedPkgPath))
|
|
40709
42935
|
return;
|
|
40710
|
-
const pkg = JSON.parse(
|
|
42936
|
+
const pkg = JSON.parse(readFileSync19(installedPkgPath, "utf-8"));
|
|
40711
42937
|
return typeof pkg.version === "string" ? pkg.version : undefined;
|
|
40712
42938
|
} catch {
|
|
40713
42939
|
return;
|
|
40714
42940
|
}
|
|
40715
42941
|
}
|
|
40716
42942
|
async function clearPluginCache(options = {}, deps = {}) {
|
|
40717
|
-
const remove = deps.remove ?? ((path6) =>
|
|
42943
|
+
const remove = deps.remove ?? ((path6) => rmSync3(path6, { recursive: true, force: true }));
|
|
40718
42944
|
const pluginCacheRoots = getOpenCodePluginCacheRoots();
|
|
40719
|
-
const existingRoots = pluginCacheRoots.filter((root) =>
|
|
42945
|
+
const existingRoots = pluginCacheRoots.filter((root) => existsSync27(root));
|
|
40720
42946
|
if (existingRoots.length === 0) {
|
|
40721
42947
|
return { action: "not_found", path: pluginCacheRoots[0] ?? "" };
|
|
40722
42948
|
}
|
|
@@ -40783,11 +43009,11 @@ var init_doctor_opencode_cache = __esm(() => {
|
|
|
40783
43009
|
});
|
|
40784
43010
|
|
|
40785
43011
|
// src/commands/doctor-opencode.ts
|
|
40786
|
-
import { execSync as execSync2, spawnSync as
|
|
40787
|
-
import { existsSync as
|
|
40788
|
-
import { createRequire as
|
|
43012
|
+
import { execSync as execSync2, spawnSync as spawnSync6 } from "node:child_process";
|
|
43013
|
+
import { existsSync as existsSync28, readFileSync as readFileSync20, statSync as statSync11 } from "node:fs";
|
|
43014
|
+
import { createRequire as createRequire5 } from "node:module";
|
|
40789
43015
|
import { homedir as homedir16 } from "node:os";
|
|
40790
|
-
import { join as
|
|
43016
|
+
import { join as join25 } from "node:path";
|
|
40791
43017
|
function resolveCompactionEnabledForDoctor() {
|
|
40792
43018
|
try {
|
|
40793
43019
|
const config2 = loadPluginConfig(process.cwd());
|
|
@@ -40866,7 +43092,7 @@ async function fetchNpmLatest(pkg, timeoutMs = 5000) {
|
|
|
40866
43092
|
}
|
|
40867
43093
|
}
|
|
40868
43094
|
function getSelfVersion2() {
|
|
40869
|
-
const req =
|
|
43095
|
+
const req = createRequire5(import.meta.url);
|
|
40870
43096
|
for (const relPath of ["../../package.json", "../package.json"]) {
|
|
40871
43097
|
try {
|
|
40872
43098
|
const pkg = req(relPath);
|
|
@@ -40886,15 +43112,15 @@ function getUserNpmrcPath() {
|
|
|
40886
43112
|
if (custom2)
|
|
40887
43113
|
return custom2;
|
|
40888
43114
|
const home = process.env.HOME?.trim();
|
|
40889
|
-
return
|
|
43115
|
+
return join25(home || homedir16(), ".npmrc");
|
|
40890
43116
|
}
|
|
40891
43117
|
function collectNpmReleaseAgeWarnings() {
|
|
40892
43118
|
const ageWarnings = [];
|
|
40893
43119
|
const npmrcPath = getUserNpmrcPath();
|
|
40894
|
-
if (!
|
|
43120
|
+
if (!existsSync28(npmrcPath))
|
|
40895
43121
|
return ageWarnings;
|
|
40896
43122
|
try {
|
|
40897
|
-
const npmrc =
|
|
43123
|
+
const npmrc = readFileSync20(npmrcPath, "utf-8");
|
|
40898
43124
|
for (const line of npmrc.split(`
|
|
40899
43125
|
`)) {
|
|
40900
43126
|
const trimmed = line.trim();
|
|
@@ -40935,15 +43161,15 @@ function isGhInstalled() {
|
|
|
40935
43161
|
function openBrowser(url2) {
|
|
40936
43162
|
try {
|
|
40937
43163
|
if (process.platform === "darwin") {
|
|
40938
|
-
const child =
|
|
43164
|
+
const child = spawnSync6("open", [url2], { stdio: "ignore" });
|
|
40939
43165
|
if (child.status === 0)
|
|
40940
43166
|
return;
|
|
40941
43167
|
} else if (process.platform === "linux") {
|
|
40942
|
-
const child =
|
|
43168
|
+
const child = spawnSync6("xdg-open", [url2], { stdio: "ignore" });
|
|
40943
43169
|
if (child.status === 0)
|
|
40944
43170
|
return;
|
|
40945
43171
|
} else if (process.platform === "win32") {
|
|
40946
|
-
const child =
|
|
43172
|
+
const child = spawnSync6("cmd", ["/c", "start", "", url2], { stdio: "ignore" });
|
|
40947
43173
|
if (child.status === 0)
|
|
40948
43174
|
return;
|
|
40949
43175
|
}
|
|
@@ -40987,7 +43213,7 @@ async function runIssueFlow2() {
|
|
|
40987
43213
|
s.stop(`Report written to ${bundled.path}`);
|
|
40988
43214
|
const shouldSubmit = await confirm2("Submit this issue on GitHub now?", true);
|
|
40989
43215
|
if (shouldSubmit && isGhInstalled()) {
|
|
40990
|
-
const result =
|
|
43216
|
+
const result = spawnSync6("gh", [
|
|
40991
43217
|
"issue",
|
|
40992
43218
|
"create",
|
|
40993
43219
|
"-R",
|
|
@@ -41033,12 +43259,12 @@ function checkLocalEmbeddingRuntimeForDoctor() {
|
|
|
41033
43259
|
return { issues: 0 };
|
|
41034
43260
|
}
|
|
41035
43261
|
async function checkEmbeddingConfig(magicContextConfigPath) {
|
|
41036
|
-
if (!
|
|
43262
|
+
if (!existsSync28(magicContextConfigPath)) {
|
|
41037
43263
|
return checkLocalEmbeddingRuntimeForDoctor();
|
|
41038
43264
|
}
|
|
41039
43265
|
let rawText;
|
|
41040
43266
|
try {
|
|
41041
|
-
rawText =
|
|
43267
|
+
rawText = readFileSync20(magicContextConfigPath, "utf-8");
|
|
41042
43268
|
} catch {
|
|
41043
43269
|
log2.warn("Could not read magic-context.jsonc for embedding check");
|
|
41044
43270
|
return { issues: 1 };
|
|
@@ -41161,7 +43387,7 @@ async function runDoctor2(options = {}) {
|
|
|
41161
43387
|
const v22Result = await runV22BackfillCommands({
|
|
41162
43388
|
name: "OpenCode",
|
|
41163
43389
|
openDatabase: (readonly2 = true) => {
|
|
41164
|
-
const dbPath2 =
|
|
43390
|
+
const dbPath2 = join25(getMagicContextStorageDir(), "context.db");
|
|
41165
43391
|
v22Db = readonly2 ? openExistingContextDatabase(dbPath2, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath2);
|
|
41166
43392
|
return v22Db;
|
|
41167
43393
|
},
|
|
@@ -41193,7 +43419,7 @@ async function runDoctor2(options = {}) {
|
|
|
41193
43419
|
failCount++;
|
|
41194
43420
|
issues++;
|
|
41195
43421
|
};
|
|
41196
|
-
const authorityDbPath =
|
|
43422
|
+
const authorityDbPath = join25(getMagicContextStorageDir(), "context.db");
|
|
41197
43423
|
let authorityDb = null;
|
|
41198
43424
|
try {
|
|
41199
43425
|
authorityDb = openExistingContextDatabase(authorityDbPath, { readonly: true });
|
|
@@ -41244,10 +43470,10 @@ async function runDoctor2(options = {}) {
|
|
|
41244
43470
|
} else {
|
|
41245
43471
|
pass(`OpenCode config: ${paths.opencodeConfig}`);
|
|
41246
43472
|
}
|
|
41247
|
-
if (
|
|
43473
|
+
if (existsSync28(paths.magicContextConfig)) {
|
|
41248
43474
|
pass(`Magic Context config: ${paths.magicContextConfig}`);
|
|
41249
43475
|
try {
|
|
41250
|
-
const raw =
|
|
43476
|
+
const raw = readFileSync20(paths.magicContextConfig, "utf-8");
|
|
41251
43477
|
const substituted = substituteConfigVariables({
|
|
41252
43478
|
text: raw,
|
|
41253
43479
|
configPath: paths.magicContextConfig
|
|
@@ -41272,9 +43498,9 @@ async function runDoctor2(options = {}) {
|
|
|
41272
43498
|
warn(`No magic-context.jsonc found — using defaults`);
|
|
41273
43499
|
log2.info(" Run 'setup' to create one with model recommendations");
|
|
41274
43500
|
}
|
|
41275
|
-
if (
|
|
43501
|
+
if (existsSync28(paths.magicContextConfig)) {
|
|
41276
43502
|
try {
|
|
41277
|
-
const mcRaw =
|
|
43503
|
+
const mcRaw = readFileSync20(paths.magicContextConfig, "utf-8");
|
|
41278
43504
|
const mcConfig = import_comment_json11.parse(mcRaw);
|
|
41279
43505
|
let mcChanged = false;
|
|
41280
43506
|
const experimental = mcConfig.experimental;
|
|
@@ -41392,7 +43618,7 @@ async function runDoctor2(options = {}) {
|
|
|
41392
43618
|
}
|
|
41393
43619
|
if (paths.opencodeConfigFormat !== "none") {
|
|
41394
43620
|
try {
|
|
41395
|
-
const raw =
|
|
43621
|
+
const raw = readFileSync20(paths.opencodeConfig, "utf-8");
|
|
41396
43622
|
const config2 = import_comment_json11.parse(raw);
|
|
41397
43623
|
const rawPlugins = Array.isArray(config2?.plugin) ? config2.plugin : [];
|
|
41398
43624
|
const existingIdx = rawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
|
|
@@ -41476,9 +43702,9 @@ async function runDoctor2(options = {}) {
|
|
|
41476
43702
|
pass("Added TUI sidebar plugin to tui.json");
|
|
41477
43703
|
warn("Restart OpenCode to see the sidebar");
|
|
41478
43704
|
fixed++;
|
|
41479
|
-
} else if (
|
|
43705
|
+
} else if (existsSync28(paths.tuiConfig)) {
|
|
41480
43706
|
try {
|
|
41481
|
-
const tuiRaw =
|
|
43707
|
+
const tuiRaw = readFileSync20(paths.tuiConfig, "utf-8");
|
|
41482
43708
|
const tuiConfig = import_comment_json11.parse(tuiRaw);
|
|
41483
43709
|
const tuiRawPlugins = Array.isArray(tuiConfig?.plugin) ? tuiConfig.plugin : [];
|
|
41484
43710
|
const tuiIdx = tuiRawPlugins.findIndex((entry) => matchesPluginEntry(entry, OPENCODE_PLUGIN_NAME) || isDevPathPluginEntry(entry));
|
|
@@ -41527,9 +43753,9 @@ async function runDoctor2(options = {}) {
|
|
|
41527
43753
|
} else {
|
|
41528
43754
|
fail("Could not create or verify the TUI sidebar config");
|
|
41529
43755
|
}
|
|
41530
|
-
if (
|
|
43756
|
+
if (existsSync28(paths.magicContextConfig)) {
|
|
41531
43757
|
try {
|
|
41532
|
-
const mcRaw =
|
|
43758
|
+
const mcRaw = readFileSync20(paths.magicContextConfig, "utf-8");
|
|
41533
43759
|
const mcConfig = import_comment_json11.parse(mcRaw);
|
|
41534
43760
|
const warning = checkUserMemoriesDreamerCompatibility(mcConfig);
|
|
41535
43761
|
if (warning) {
|
|
@@ -41546,8 +43772,8 @@ async function runDoctor2(options = {}) {
|
|
|
41546
43772
|
warnCount++;
|
|
41547
43773
|
else
|
|
41548
43774
|
passCount++;
|
|
41549
|
-
const dbPath =
|
|
41550
|
-
if (!
|
|
43775
|
+
const dbPath = join25(getMagicContextStorageDir(), "context.db");
|
|
43776
|
+
if (!existsSync28(dbPath)) {
|
|
41551
43777
|
log2.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
|
|
41552
43778
|
} else {
|
|
41553
43779
|
log2.info(`Shared context DB exists at ${dbPath}`);
|
|
@@ -41573,9 +43799,11 @@ async function runDoctor2(options = {}) {
|
|
|
41573
43799
|
if (result === "ok")
|
|
41574
43800
|
pass("SQLite integrity_check: ok");
|
|
41575
43801
|
else
|
|
41576
|
-
fail(`SQLite integrity_check reported: ${result}
|
|
43802
|
+
fail(`SQLite integrity_check reported: ${result}
|
|
43803
|
+
${formatDatabaseRepairGuidance(dbPath)}`);
|
|
41577
43804
|
} catch (err) {
|
|
41578
|
-
fail(`SQLite integrity_check failed: ${err instanceof Error ? err.message : String(err)}
|
|
43805
|
+
fail(`SQLite integrity_check failed: ${err instanceof Error ? err.message : String(err)}
|
|
43806
|
+
${formatDatabaseRepairGuidance(dbPath)}`);
|
|
41579
43807
|
}
|
|
41580
43808
|
try {
|
|
41581
43809
|
const counts = {};
|
|
@@ -41606,7 +43834,8 @@ async function runDoctor2(options = {}) {
|
|
|
41606
43834
|
plugin_supported_version: err.supportedVersion
|
|
41607
43835
|
}).message);
|
|
41608
43836
|
} else {
|
|
41609
|
-
fail(`Could not open shared DB: ${err instanceof Error ? err.message : String(err)}
|
|
43837
|
+
fail(`Could not open shared DB: ${err instanceof Error ? err.message : String(err)}
|
|
43838
|
+
${formatDatabaseRepairGuidance(dbPath)}`);
|
|
41610
43839
|
}
|
|
41611
43840
|
}
|
|
41612
43841
|
}
|
|
@@ -41651,8 +43880,8 @@ async function runDoctor2(options = {}) {
|
|
|
41651
43880
|
}
|
|
41652
43881
|
}
|
|
41653
43882
|
const logPath = getMagicContextLogPath2("opencode");
|
|
41654
|
-
if (
|
|
41655
|
-
const logStat =
|
|
43883
|
+
if (existsSync28(logPath)) {
|
|
43884
|
+
const logStat = statSync11(logPath);
|
|
41656
43885
|
const sizeKb = (logStat.size / 1024).toFixed(0);
|
|
41657
43886
|
log2.info(`Log file: ${logPath} (${sizeKb} KB)`);
|
|
41658
43887
|
} else {
|
|
@@ -41732,12 +43961,12 @@ var init_doctor_opencode = __esm(async () => {
|
|
|
41732
43961
|
|
|
41733
43962
|
// src/lib/diagnostics-pi.ts
|
|
41734
43963
|
import { createHash as createHash4 } from "node:crypto";
|
|
41735
|
-
import { existsSync as
|
|
41736
|
-
import { createRequire as
|
|
43964
|
+
import { existsSync as existsSync29, readdirSync as readdirSync4, readFileSync as readFileSync21, statSync as statSync12 } from "node:fs";
|
|
43965
|
+
import { createRequire as createRequire6 } from "node:module";
|
|
41737
43966
|
import { homedir as homedir17, userInfo as userInfo2 } from "node:os";
|
|
41738
|
-
import { join as
|
|
43967
|
+
import { join as join26 } from "node:path";
|
|
41739
43968
|
function getSelfVersion3() {
|
|
41740
|
-
const req =
|
|
43969
|
+
const req = createRequire6(import.meta.url);
|
|
41741
43970
|
for (const relPath of ["../../package.json", "../package.json"]) {
|
|
41742
43971
|
try {
|
|
41743
43972
|
const pkg = req(relPath);
|
|
@@ -41750,7 +43979,7 @@ function getSelfVersion3() {
|
|
|
41750
43979
|
}
|
|
41751
43980
|
function fileSize2(path6) {
|
|
41752
43981
|
try {
|
|
41753
|
-
return
|
|
43982
|
+
return existsSync29(path6) ? statSync12(path6).size : 0;
|
|
41754
43983
|
} catch {
|
|
41755
43984
|
return 0;
|
|
41756
43985
|
}
|
|
@@ -41802,11 +44031,11 @@ function sanitizeValue2(value, key = "") {
|
|
|
41802
44031
|
return value;
|
|
41803
44032
|
}
|
|
41804
44033
|
function readJsonc(path6) {
|
|
41805
|
-
if (!
|
|
44034
|
+
if (!existsSync29(path6))
|
|
41806
44035
|
return { value: {} };
|
|
41807
44036
|
try {
|
|
41808
44037
|
return {
|
|
41809
|
-
value: import_comment_json12.parse(
|
|
44038
|
+
value: import_comment_json12.parse(readFileSync21(path6, "utf-8"))
|
|
41810
44039
|
};
|
|
41811
44040
|
} catch (error51) {
|
|
41812
44041
|
return {
|
|
@@ -41822,7 +44051,7 @@ function readConfigDiagnostic(path6) {
|
|
|
41822
44051
|
const parsed = readJsonc(path6);
|
|
41823
44052
|
return {
|
|
41824
44053
|
path: path6,
|
|
41825
|
-
exists:
|
|
44054
|
+
exists: existsSync29(path6),
|
|
41826
44055
|
...parsed.parseError ? { parseError: parsed.parseError } : {},
|
|
41827
44056
|
flags: sanitizeValue2(parsed.value)
|
|
41828
44057
|
};
|
|
@@ -41840,7 +44069,7 @@ function reverseSlugToDirectory(slug) {
|
|
|
41840
44069
|
}
|
|
41841
44070
|
function collectPiRecentSessions() {
|
|
41842
44071
|
const sessionsRoot = getPiSessionsRoot();
|
|
41843
|
-
if (!
|
|
44072
|
+
if (!existsSync29(sessionsRoot))
|
|
41844
44073
|
return [];
|
|
41845
44074
|
try {
|
|
41846
44075
|
const slugs = readdirSync4(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
@@ -41849,7 +44078,7 @@ function collectPiRecentSessions() {
|
|
|
41849
44078
|
const directory = reverseSlugToDirectory(slug);
|
|
41850
44079
|
if (!directory)
|
|
41851
44080
|
continue;
|
|
41852
|
-
const slugDir =
|
|
44081
|
+
const slugDir = join26(sessionsRoot, slug);
|
|
41853
44082
|
let files;
|
|
41854
44083
|
try {
|
|
41855
44084
|
files = readdirSync4(slugDir).filter((name) => name.endsWith(".jsonl"));
|
|
@@ -41858,7 +44087,7 @@ function collectPiRecentSessions() {
|
|
|
41858
44087
|
}
|
|
41859
44088
|
for (const file2 of files) {
|
|
41860
44089
|
try {
|
|
41861
|
-
const mtime =
|
|
44090
|
+
const mtime = statSync12(join26(slugDir, file2)).mtimeMs;
|
|
41862
44091
|
const sessionId = file2.replace(/\.jsonl$/, "");
|
|
41863
44092
|
candidates.push({ sessionId, directory, mtime });
|
|
41864
44093
|
} catch {}
|
|
@@ -41876,7 +44105,7 @@ function collectPiRecentSessions() {
|
|
|
41876
44105
|
}
|
|
41877
44106
|
function parseHistorianDumpMeta2(path6) {
|
|
41878
44107
|
try {
|
|
41879
|
-
const xml =
|
|
44108
|
+
const xml = readFileSync21(path6, "utf-8");
|
|
41880
44109
|
const parsed = parseCompartmentOutput(xml);
|
|
41881
44110
|
const factCountByCategory = {};
|
|
41882
44111
|
for (const fact of parsed.facts) {
|
|
@@ -41909,11 +44138,11 @@ function parseHistorianDumpMeta2(path6) {
|
|
|
41909
44138
|
}
|
|
41910
44139
|
}
|
|
41911
44140
|
function listDumpsInDir2(dir, limit) {
|
|
41912
|
-
if (!
|
|
44141
|
+
if (!existsSync29(dir))
|
|
41913
44142
|
return { count: 0, recent: [] };
|
|
41914
44143
|
try {
|
|
41915
44144
|
const entries = readdirSync4(dir).filter((name) => name.endsWith(".xml")).map((name) => {
|
|
41916
|
-
const stat =
|
|
44145
|
+
const stat = statSync12(join26(dir, name));
|
|
41917
44146
|
return {
|
|
41918
44147
|
name,
|
|
41919
44148
|
mtime: stat.mtimeMs,
|
|
@@ -41922,7 +44151,7 @@ function listDumpsInDir2(dir, limit) {
|
|
|
41922
44151
|
}).sort((a3, b2) => b2.mtime - a3.mtime);
|
|
41923
44152
|
const now = Date.now();
|
|
41924
44153
|
const recent = entries.slice(0, limit).map((entry) => {
|
|
41925
|
-
const meta3 = parseHistorianDumpMeta2(
|
|
44154
|
+
const meta3 = parseHistorianDumpMeta2(join26(dir, entry.name));
|
|
41926
44155
|
const summary = {
|
|
41927
44156
|
name: entry.name,
|
|
41928
44157
|
ageMinutes: Math.round((now - entry.mtime) / 60000),
|
|
@@ -41985,9 +44214,9 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
41985
44214
|
const projectConfigPath = getProjectConfigPath(cwd);
|
|
41986
44215
|
const loaded = loadPiConfig({ cwd });
|
|
41987
44216
|
const storageDirPath = getMagicContextStorageDir();
|
|
41988
|
-
const dbPath =
|
|
44217
|
+
const dbPath = join26(storageDirPath, "context.db");
|
|
41989
44218
|
const logPath = getMagicContextLogPath2("pi");
|
|
41990
|
-
const logFileSize =
|
|
44219
|
+
const logFileSize = existsSync29(logPath) ? statSync12(logPath).size : 0;
|
|
41991
44220
|
const otherPiExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
|
|
41992
44221
|
const recentSessions = collectPiRecentSessions();
|
|
41993
44222
|
const historianDumps = collectPiHistorianDumps(recentSessions);
|
|
@@ -42002,7 +44231,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
42002
44231
|
piVersion: pi ? getPiVersion(pi.path) : null,
|
|
42003
44232
|
settings: {
|
|
42004
44233
|
path: settingsPath,
|
|
42005
|
-
exists:
|
|
44234
|
+
exists: existsSync29(settingsPath),
|
|
42006
44235
|
...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
|
|
42007
44236
|
hasMagicContextPackage: hasPiMagicContextPackage(packages),
|
|
42008
44237
|
packages: sanitizeValue2(packages)
|
|
@@ -42018,7 +44247,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
42018
44247
|
loadWarnings: loaded.warnings.map(sanitizeString2),
|
|
42019
44248
|
storageDir: {
|
|
42020
44249
|
path: storageDirPath,
|
|
42021
|
-
exists:
|
|
44250
|
+
exists: existsSync29(storageDirPath),
|
|
42022
44251
|
contextDbSizeBytes: fileSize2(dbPath)
|
|
42023
44252
|
},
|
|
42024
44253
|
conflicts: {
|
|
@@ -42027,7 +44256,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
|
|
|
42027
44256
|
},
|
|
42028
44257
|
logFile: {
|
|
42029
44258
|
path: logPath,
|
|
42030
|
-
exists:
|
|
44259
|
+
exists: existsSync29(logPath),
|
|
42031
44260
|
sizeKb: Math.round(logFileSize / 1024)
|
|
42032
44261
|
},
|
|
42033
44262
|
recentSessions,
|
|
@@ -42121,8 +44350,8 @@ var init_diagnostics_pi = __esm(() => {
|
|
|
42121
44350
|
});
|
|
42122
44351
|
|
|
42123
44352
|
// src/lib/logs-pi.ts
|
|
42124
|
-
import { readFileSync as
|
|
42125
|
-
import { join as
|
|
44353
|
+
import { readFileSync as readFileSync22, writeFileSync as writeFileSync8 } from "node:fs";
|
|
44354
|
+
import { join as join27 } from "node:path";
|
|
42126
44355
|
function sanitizeLogContent2(content) {
|
|
42127
44356
|
return sanitizeString2(content);
|
|
42128
44357
|
}
|
|
@@ -42151,7 +44380,7 @@ function filterLogLinesBySession2(lines, sessionId) {
|
|
|
42151
44380
|
}
|
|
42152
44381
|
async function bundleIssueReport2(report, description, title, options = {}) {
|
|
42153
44382
|
const LOG_TAIL_LINES = 400;
|
|
42154
|
-
const allLogLines = report.logFile.exists ?
|
|
44383
|
+
const allLogLines = report.logFile.exists ? readFileSync22(report.logFile.path, "utf-8").split(/\r?\n/) : [];
|
|
42155
44384
|
const logLines = filterLogLinesBySession2(allLogLines, options.sessionFilter ?? null);
|
|
42156
44385
|
const recentLog = sanitizeLogContent2(logLines.slice(-LOG_TAIL_LINES).join(`
|
|
42157
44386
|
`)).trim();
|
|
@@ -42187,7 +44416,7 @@ async function bundleIssueReport2(report, description, title, options = {}) {
|
|
|
42187
44416
|
`);
|
|
42188
44417
|
const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
|
|
42189
44418
|
const cwd = options.cwd ?? process.cwd();
|
|
42190
|
-
const path6 =
|
|
44419
|
+
const path6 = join27(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
|
|
42191
44420
|
writeFileSync8(path6, `${bodyMarkdown}
|
|
42192
44421
|
`);
|
|
42193
44422
|
return { path: path6, bodyMarkdown };
|
|
@@ -42198,15 +44427,15 @@ var init_logs_pi = __esm(() => {
|
|
|
42198
44427
|
});
|
|
42199
44428
|
|
|
42200
44429
|
// src/commands/doctor-pi.ts
|
|
42201
|
-
import { execFileSync as execFileSync6, spawnSync as
|
|
42202
|
-
import { existsSync as
|
|
42203
|
-
import { createRequire as
|
|
44430
|
+
import { execFileSync as execFileSync6, spawnSync as spawnSync7 } from "node:child_process";
|
|
44431
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync10, readdirSync as readdirSync5, readFileSync as readFileSync23, rmSync as rmSync4, statSync as statSync13 } from "node:fs";
|
|
44432
|
+
import { createRequire as createRequire7 } from "node:module";
|
|
42204
44433
|
import { homedir as homedir18 } from "node:os";
|
|
42205
|
-
import { dirname as
|
|
44434
|
+
import { dirname as dirname15, isAbsolute as isAbsolute4, join as join28 } from "node:path";
|
|
42206
44435
|
function depsFrom(options) {
|
|
42207
44436
|
return {
|
|
42208
|
-
...
|
|
42209
|
-
prompts: options.prompts ??
|
|
44437
|
+
...DEFAULT_DEPS3,
|
|
44438
|
+
prompts: options.prompts ?? DEFAULT_DEPS3.prompts,
|
|
42210
44439
|
...options.deps
|
|
42211
44440
|
};
|
|
42212
44441
|
}
|
|
@@ -42226,7 +44455,7 @@ function printDoctorHelp() {
|
|
|
42226
44455
|
console.log("");
|
|
42227
44456
|
}
|
|
42228
44457
|
function selfVersion2() {
|
|
42229
|
-
const req =
|
|
44458
|
+
const req = createRequire7(import.meta.url);
|
|
42230
44459
|
for (const relPath of ["../../package.json", "../package.json"]) {
|
|
42231
44460
|
try {
|
|
42232
44461
|
const pkg = req(relPath);
|
|
@@ -42292,7 +44521,7 @@ function summarize(results) {
|
|
|
42292
44521
|
function readJsonc2(path6) {
|
|
42293
44522
|
try {
|
|
42294
44523
|
return {
|
|
42295
|
-
value: import_comment_json13.parse(
|
|
44524
|
+
value: import_comment_json13.parse(readFileSync23(path6, "utf-8"))
|
|
42296
44525
|
};
|
|
42297
44526
|
} catch (error51) {
|
|
42298
44527
|
return {
|
|
@@ -42311,27 +44540,34 @@ function piPluginDirCandidates(packages, cwd) {
|
|
|
42311
44540
|
const spec = typeof entry === "string" ? entry.trim() : "";
|
|
42312
44541
|
if (!spec || spec.startsWith("npm:"))
|
|
42313
44542
|
continue;
|
|
42314
|
-
const resolved = isAbsolute4(spec) ? spec :
|
|
44543
|
+
const resolved = isAbsolute4(spec) ? spec : join28(agentDir, spec);
|
|
42315
44544
|
dirs.push(resolved);
|
|
42316
44545
|
}
|
|
42317
|
-
dirs.push(
|
|
42318
|
-
dirs.push(
|
|
42319
|
-
return dirs.filter((dir) =>
|
|
44546
|
+
dirs.push(join28(agentDir, "npm", "node_modules", PACKAGE_NAME));
|
|
44547
|
+
dirs.push(join28(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME));
|
|
44548
|
+
return dirs.filter((dir) => existsSync30(join28(dir, "package.json")));
|
|
42320
44549
|
}
|
|
42321
44550
|
function projectConfigPath(cwd) {
|
|
42322
44551
|
return resolveCortexKitProjectConfigPath(cwd);
|
|
42323
44552
|
}
|
|
42324
44553
|
function readConfigForEmbedding(path6, isProjectConfig) {
|
|
42325
|
-
if (!
|
|
44554
|
+
if (!existsSync30(path6))
|
|
42326
44555
|
return null;
|
|
42327
44556
|
try {
|
|
42328
|
-
const rawText =
|
|
44557
|
+
const rawText = readFileSync23(path6, "utf-8");
|
|
42329
44558
|
const substituted = substituteConfigVariables({
|
|
42330
44559
|
text: rawText,
|
|
42331
44560
|
configPath: path6,
|
|
42332
44561
|
isProjectConfig
|
|
42333
44562
|
});
|
|
42334
|
-
|
|
44563
|
+
const rejectedKeyPaths = [];
|
|
44564
|
+
const parsed = sanitizeParsedJson(import_comment_json13.parse(substituted.text), {
|
|
44565
|
+
onRejectedKey: (keyPath) => rejectedKeyPaths.push(keyPath.join("."))
|
|
44566
|
+
});
|
|
44567
|
+
if (rejectedKeyPaths.length > 0) {
|
|
44568
|
+
throw new Error("unsafe prototype-pollution key in config");
|
|
44569
|
+
}
|
|
44570
|
+
return parsed;
|
|
42335
44571
|
} catch {
|
|
42336
44572
|
return null;
|
|
42337
44573
|
}
|
|
@@ -42396,35 +44632,35 @@ function pinnedVersionFromPackageSpecifier(specifier) {
|
|
|
42396
44632
|
}
|
|
42397
44633
|
function cacheRoots(cwd) {
|
|
42398
44634
|
const home = process.env.HOME?.trim();
|
|
42399
|
-
const cacheHome = process.env.XDG_CACHE_HOME ||
|
|
44635
|
+
const cacheHome = process.env.XDG_CACHE_HOME || join28(home || homedir18(), ".cache");
|
|
42400
44636
|
const piCacheRoot = getPiCacheRoot();
|
|
42401
44637
|
return [
|
|
42402
|
-
|
|
42403
|
-
|
|
42404
|
-
|
|
42405
|
-
|
|
42406
|
-
|
|
42407
|
-
|
|
42408
|
-
|
|
44638
|
+
join28(piCacheRoot, "extensions"),
|
|
44639
|
+
join28(piCacheRoot, "packages"),
|
|
44640
|
+
join28(cacheHome, "pi", "extensions"),
|
|
44641
|
+
join28(cacheHome, "pi", "packages"),
|
|
44642
|
+
join28(getPiAgentConfigDir(), "cache", "extensions"),
|
|
44643
|
+
join28(getPiAgentConfigDir(), "npm", "node_modules", PACKAGE_NAME),
|
|
44644
|
+
join28(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME)
|
|
42409
44645
|
];
|
|
42410
44646
|
}
|
|
42411
44647
|
function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
|
|
42412
44648
|
const found = new Map;
|
|
42413
44649
|
const visit = (path6, depth) => {
|
|
42414
|
-
if (depth < 0 || !
|
|
44650
|
+
if (depth < 0 || !existsSync30(path6))
|
|
42415
44651
|
return;
|
|
42416
44652
|
let stat;
|
|
42417
44653
|
try {
|
|
42418
|
-
stat =
|
|
44654
|
+
stat = statSync13(path6);
|
|
42419
44655
|
} catch {
|
|
42420
44656
|
return;
|
|
42421
44657
|
}
|
|
42422
44658
|
if (!stat.isDirectory())
|
|
42423
44659
|
return;
|
|
42424
|
-
const packageJson =
|
|
42425
|
-
if (
|
|
44660
|
+
const packageJson = join28(path6, "package.json");
|
|
44661
|
+
if (existsSync30(packageJson)) {
|
|
42426
44662
|
try {
|
|
42427
|
-
const pkg = JSON.parse(
|
|
44663
|
+
const pkg = JSON.parse(readFileSync23(packageJson, "utf-8"));
|
|
42428
44664
|
const name = typeof pkg.name === "string" ? pkg.name : "";
|
|
42429
44665
|
const version2 = typeof pkg.version === "string" ? pkg.version : undefined;
|
|
42430
44666
|
if (name === PACKAGE_NAME) {
|
|
@@ -42444,7 +44680,7 @@ function findPiMagicContextCacheDirs(cwd, expectedVersion, force = false) {
|
|
|
42444
44680
|
return;
|
|
42445
44681
|
}
|
|
42446
44682
|
for (const entry of entries)
|
|
42447
|
-
visit(
|
|
44683
|
+
visit(join28(path6, entry), depth - 1);
|
|
42448
44684
|
};
|
|
42449
44685
|
for (const root of cacheRoots(cwd))
|
|
42450
44686
|
visit(root, 5);
|
|
@@ -42489,7 +44725,7 @@ async function runHealthChecks2(options) {
|
|
|
42489
44725
|
}
|
|
42490
44726
|
const settingsPath = getPiUserExtensionsPath();
|
|
42491
44727
|
let packages = [];
|
|
42492
|
-
if (!
|
|
44728
|
+
if (!existsSync30(settingsPath)) {
|
|
42493
44729
|
add2(results, "fail", `Pi settings not found at ${settingsPath}`);
|
|
42494
44730
|
repairPlan.addPackageEntry = true;
|
|
42495
44731
|
} else {
|
|
@@ -42513,7 +44749,7 @@ async function runHealthChecks2(options) {
|
|
|
42513
44749
|
["user", userConfigPath, true],
|
|
42514
44750
|
["project", projectPath, false]
|
|
42515
44751
|
]) {
|
|
42516
|
-
if (!
|
|
44752
|
+
if (!existsSync30(path6)) {
|
|
42517
44753
|
if (required2) {
|
|
42518
44754
|
add2(results, "warn", `No ${label} magic-context.jsonc found at ${path6}`);
|
|
42519
44755
|
if (userConfigMigrationRefused) {
|
|
@@ -42550,8 +44786,8 @@ async function runHealthChecks2(options) {
|
|
|
42550
44786
|
add2(results, "pass", `historian.model "${historianModel}" has thinking_level "${historianThinkingLevel}" configured`);
|
|
42551
44787
|
}
|
|
42552
44788
|
const storageDir = getMagicContextStorageDir();
|
|
42553
|
-
const dbPath =
|
|
42554
|
-
const existedBeforeOpen =
|
|
44789
|
+
const dbPath = join28(storageDir, "context.db");
|
|
44790
|
+
const existedBeforeOpen = existsSync30(dbPath);
|
|
42555
44791
|
if (existedBeforeOpen)
|
|
42556
44792
|
add2(results, "pass", `Shared context DB exists at ${dbPath}`);
|
|
42557
44793
|
else
|
|
@@ -42574,8 +44810,9 @@ async function runHealthChecks2(options) {
|
|
|
42574
44810
|
if (integrity?.integrity_check === "ok")
|
|
42575
44811
|
add2(results, "pass", "SQLite integrity_check: ok");
|
|
42576
44812
|
else
|
|
42577
|
-
add2(results, "fail", `SQLite integrity_check: ${String(integrity?.integrity_check ?? "unknown")}
|
|
42578
|
-
|
|
44813
|
+
add2(results, "fail", `SQLite integrity_check: ${String(integrity?.integrity_check ?? "unknown")}
|
|
44814
|
+
${formatDatabaseRepairGuidance(dbPath)}`);
|
|
44815
|
+
const counts = ROW_COUNT_TABLES2.map((table) => `${table}=${countTable(db, table) ?? "n/a"}`).join(", ");
|
|
42579
44816
|
add2(results, "info", `Shared DB row counts: ${counts}`);
|
|
42580
44817
|
}
|
|
42581
44818
|
} catch (error51) {
|
|
@@ -42585,7 +44822,8 @@ async function runHealthChecks2(options) {
|
|
|
42585
44822
|
plugin_supported_version: error51.supportedVersion
|
|
42586
44823
|
}).message);
|
|
42587
44824
|
} else {
|
|
42588
|
-
add2(results, "fail", `Could not open shared context DB: ${error51 instanceof Error ? error51.message : String(error51)}
|
|
44825
|
+
add2(results, "fail", `Could not open shared context DB: ${error51 instanceof Error ? error51.message : String(error51)}
|
|
44826
|
+
${formatDatabaseRepairGuidance(dbPath)}`);
|
|
42589
44827
|
}
|
|
42590
44828
|
} finally {
|
|
42591
44829
|
db?.close();
|
|
@@ -42600,7 +44838,16 @@ async function runHealthChecks2(options) {
|
|
|
42600
44838
|
for (const config2 of [userRaw, projectRaw]) {
|
|
42601
44839
|
const embedding = config2?.embedding;
|
|
42602
44840
|
if (embedding && typeof embedding === "object" && !Array.isArray(embedding)) {
|
|
42603
|
-
Object.
|
|
44841
|
+
for (const key of Object.keys(embedding)) {
|
|
44842
|
+
if (isPrototypePollutionKey(key))
|
|
44843
|
+
continue;
|
|
44844
|
+
Object.defineProperty(mergedEmbedding, key, {
|
|
44845
|
+
value: embedding[key],
|
|
44846
|
+
enumerable: true,
|
|
44847
|
+
configurable: true,
|
|
44848
|
+
writable: true
|
|
44849
|
+
});
|
|
44850
|
+
}
|
|
42604
44851
|
}
|
|
42605
44852
|
}
|
|
42606
44853
|
if (projectRaw) {
|
|
@@ -42677,10 +44924,10 @@ async function runHealthChecks2(options) {
|
|
|
42677
44924
|
add2(results, "pass", "Pi extension cache clean (no stale cached package found)");
|
|
42678
44925
|
}
|
|
42679
44926
|
const logPath = getMagicContextLogPath2("pi");
|
|
42680
|
-
if (
|
|
42681
|
-
const stat =
|
|
44927
|
+
if (existsSync30(logPath)) {
|
|
44928
|
+
const stat = statSync13(logPath);
|
|
42682
44929
|
const sizeKb = (stat.size / 1024).toFixed(0);
|
|
42683
|
-
const lines =
|
|
44930
|
+
const lines = readFileSync23(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
42684
44931
|
add2(results, "info", `Log file: ${logPath} (${sizeKb} KB)`);
|
|
42685
44932
|
const lastLine = lines.at(-1);
|
|
42686
44933
|
add2(results, "info", `Last plugin log line: ${lastLine ? sanitizeDiagnosticText(lastLine) : "<empty log>"}`);
|
|
@@ -42715,7 +44962,7 @@ async function runHealthChecks2(options) {
|
|
|
42715
44962
|
return { results, repairPlan, ...summarize(results) };
|
|
42716
44963
|
}
|
|
42717
44964
|
function writeDefaultMagicContextConfig(path6) {
|
|
42718
|
-
mkdirSync10(
|
|
44965
|
+
mkdirSync10(dirname15(path6), { recursive: true });
|
|
42719
44966
|
const config2 = {
|
|
42720
44967
|
$schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
|
|
42721
44968
|
...MagicContextConfigSchema.parse({})
|
|
@@ -42737,7 +44984,7 @@ function repair2(plan, prompts) {
|
|
|
42737
44984
|
}
|
|
42738
44985
|
if (plan.writeUserConfig) {
|
|
42739
44986
|
const configPath = getPiUserConfigPath();
|
|
42740
|
-
if (!
|
|
44987
|
+
if (!existsSync30(configPath)) {
|
|
42741
44988
|
try {
|
|
42742
44989
|
writeDefaultMagicContextConfig(configPath);
|
|
42743
44990
|
prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
|
|
@@ -42749,7 +44996,7 @@ function repair2(plan, prompts) {
|
|
|
42749
44996
|
}
|
|
42750
44997
|
for (const path6 of plan.clearCachePaths) {
|
|
42751
44998
|
try {
|
|
42752
|
-
|
|
44999
|
+
rmSync4(path6, { recursive: true, force: true });
|
|
42753
45000
|
prompts.log.success(`Cleared stale Pi extension cache: ${path6}`);
|
|
42754
45001
|
fixed += 1;
|
|
42755
45002
|
} catch (error51) {
|
|
@@ -42857,7 +45104,7 @@ async function runDoctor3(options = {}) {
|
|
|
42857
45104
|
const v22Result = await runV22BackfillCommands({
|
|
42858
45105
|
name: "Pi",
|
|
42859
45106
|
openDatabase: (readonly2 = true) => {
|
|
42860
|
-
const dbPath =
|
|
45107
|
+
const dbPath = join28(getMagicContextStorageDir(), "context.db");
|
|
42861
45108
|
v22Db = readonly2 ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
|
|
42862
45109
|
return v22Db;
|
|
42863
45110
|
},
|
|
@@ -42922,13 +45169,14 @@ function parseDoctorArgs(args) {
|
|
|
42922
45169
|
function doctor(args = []) {
|
|
42923
45170
|
return runDoctor3(parseDoctorArgs(args));
|
|
42924
45171
|
}
|
|
42925
|
-
var import_comment_json13, PACKAGE_NAME = "@cortexkit/pi-magic-context", MIN_PI_VERSION = "0.74.0",
|
|
45172
|
+
var import_comment_json13, PACKAGE_NAME = "@cortexkit/pi-magic-context", MIN_PI_VERSION = "0.74.0", ROW_COUNT_TABLES2, DEFAULT_DEPS3;
|
|
42926
45173
|
var init_doctor_pi = __esm(async () => {
|
|
42927
45174
|
init_migrate_config_location();
|
|
42928
45175
|
init_project_security();
|
|
42929
45176
|
init_magic_context();
|
|
42930
45177
|
init_variable();
|
|
42931
45178
|
init_data_path();
|
|
45179
|
+
init_jsonc_parser();
|
|
42932
45180
|
init_config2();
|
|
42933
45181
|
init_atomic_write();
|
|
42934
45182
|
init_config_location_migration();
|
|
@@ -42947,8 +45195,8 @@ var init_doctor_pi = __esm(async () => {
|
|
|
42947
45195
|
init_v22_backfill_commands()
|
|
42948
45196
|
]);
|
|
42949
45197
|
import_comment_json13 = __toESM(require_src3(), 1);
|
|
42950
|
-
|
|
42951
|
-
|
|
45198
|
+
ROW_COUNT_TABLES2 = ["tags", "compartments", "memories", "notes", "dream_runs"];
|
|
45199
|
+
DEFAULT_DEPS3 = {
|
|
42952
45200
|
prompts: promptIO,
|
|
42953
45201
|
collectDiagnostics: collectDiagnostics2,
|
|
42954
45202
|
detectPiBinary,
|
|
@@ -42959,7 +45207,7 @@ var init_doctor_pi = __esm(async () => {
|
|
|
42959
45207
|
openExistingContextDatabase,
|
|
42960
45208
|
now: () => new Date,
|
|
42961
45209
|
execFileSync: execFileSync6,
|
|
42962
|
-
spawnSync:
|
|
45210
|
+
spawnSync: spawnSync7
|
|
42963
45211
|
};
|
|
42964
45212
|
});
|
|
42965
45213
|
|
|
@@ -42968,8 +45216,8 @@ var exports_doctor = {};
|
|
|
42968
45216
|
__export(exports_doctor, {
|
|
42969
45217
|
runDoctor: () => runDoctor4
|
|
42970
45218
|
});
|
|
42971
|
-
import { existsSync as
|
|
42972
|
-
import { join as
|
|
45219
|
+
import { existsSync as existsSync31, rmSync as rmSync5 } from "node:fs";
|
|
45220
|
+
import { join as join29 } from "node:path";
|
|
42973
45221
|
async function runDoctor4(options) {
|
|
42974
45222
|
if (options.clear)
|
|
42975
45223
|
return runClear();
|
|
@@ -42987,7 +45235,7 @@ async function runDoctor4(options) {
|
|
|
42987
45235
|
const result = await runV22BackfillCommands({
|
|
42988
45236
|
name: "Magic Context",
|
|
42989
45237
|
openDatabase: (readonly2 = true) => {
|
|
42990
|
-
const dbPath =
|
|
45238
|
+
const dbPath = join29(getMagicContextStorageDir(), "context.db");
|
|
42991
45239
|
v22Db = readonly2 ? openExistingContextDatabase(dbPath, { readonly: true }) : openExistingContextDatabaseForMutation(dbPath);
|
|
42992
45240
|
return v22Db;
|
|
42993
45241
|
},
|
|
@@ -43076,8 +45324,8 @@ async function runClear() {
|
|
|
43076
45324
|
const s = spinner2();
|
|
43077
45325
|
s.start(`Clearing ${item.path}`);
|
|
43078
45326
|
try {
|
|
43079
|
-
if (
|
|
43080
|
-
|
|
45327
|
+
if (existsSync31(item.path)) {
|
|
45328
|
+
rmSync5(item.path, { recursive: true, force: true });
|
|
43081
45329
|
}
|
|
43082
45330
|
s.stop(`Cleared ${item.path}`);
|
|
43083
45331
|
} catch (err) {
|
|
@@ -43114,7 +45362,7 @@ var init_doctor = __esm(async () => {
|
|
|
43114
45362
|
|
|
43115
45363
|
// src/index.ts
|
|
43116
45364
|
init_prompts();
|
|
43117
|
-
import { createRequire as
|
|
45365
|
+
import { createRequire as createRequire8 } from "node:module";
|
|
43118
45366
|
|
|
43119
45367
|
// src/lib/sqlite-preflight.ts
|
|
43120
45368
|
async function probeSqliteBackend() {
|
|
@@ -43142,7 +45390,7 @@ async function runSqlitePreflight(probe = probeSqliteBackend, report = (message)
|
|
|
43142
45390
|
|
|
43143
45391
|
// src/index.ts
|
|
43144
45392
|
function getVersion() {
|
|
43145
|
-
const req =
|
|
45393
|
+
const req = createRequire8(import.meta.url);
|
|
43146
45394
|
for (const relPath of ["../../package.json", "../package.json"]) {
|
|
43147
45395
|
try {
|
|
43148
45396
|
const pkg = req(relPath);
|
|
@@ -43180,6 +45428,7 @@ function printUsage() {
|
|
|
43180
45428
|
console.log(" doctor migrate Migrate OpenCode session to Pi or OMP JSONL");
|
|
43181
45429
|
console.log(" doctor migrate-session Re-home an OpenCode session to another directory");
|
|
43182
45430
|
console.log(" doctor merge-identity Merge project rows (--from ID --to ID [--dry-run] [--yes])");
|
|
45431
|
+
console.log(" doctor repair-db Back up and salvage a corrupted shared database");
|
|
43183
45432
|
console.log("");
|
|
43184
45433
|
console.log(" Harness selection:");
|
|
43185
45434
|
console.log(" --harness opencode Target OpenCode only");
|
|
@@ -43221,17 +45470,21 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
43221
45470
|
console.error("Usage: magic-context doctor drain-authority <project>");
|
|
43222
45471
|
return 1;
|
|
43223
45472
|
}
|
|
43224
|
-
const [{ runDoctorDrainAuthority: runDoctorDrainAuthority2 }, { getMagicContextStorageDir: getMagicContextStorageDir2 }, { join:
|
|
45473
|
+
const [{ runDoctorDrainAuthority: runDoctorDrainAuthority2 }, { getMagicContextStorageDir: getMagicContextStorageDir2 }, { join: join30 }] = await Promise.all([
|
|
43225
45474
|
init_doctor_authority().then(() => exports_doctor_authority),
|
|
43226
45475
|
Promise.resolve().then(() => (init_data_path(), exports_data_path)),
|
|
43227
45476
|
import("node:path")
|
|
43228
45477
|
]);
|
|
43229
|
-
return runDoctorDrainAuthority2(projectRoot,
|
|
45478
|
+
return runDoctorDrainAuthority2(projectRoot, join30(getMagicContextStorageDir2(), "context.db"));
|
|
43230
45479
|
}
|
|
43231
45480
|
if (rest[0] === "merge-identity") {
|
|
43232
45481
|
const { runMergeIdentityCli: runMergeIdentityCli2 } = await init_doctor_merge_identity().then(() => exports_doctor_merge_identity);
|
|
43233
45482
|
return runMergeIdentityCli2(rest.slice(1));
|
|
43234
45483
|
}
|
|
45484
|
+
if (rest[0] === "repair-db") {
|
|
45485
|
+
const { runRepairDbCli: runRepairDbCli2 } = await init_doctor_repair_db().then(() => exports_doctor_repair_db);
|
|
45486
|
+
return runRepairDbCli2(rest.slice(1));
|
|
45487
|
+
}
|
|
43235
45488
|
if (rest[0] === "migrate") {
|
|
43236
45489
|
const { runMigrateCli: runMigrateCli2 } = await init_migrate().then(() => exports_migrate);
|
|
43237
45490
|
return runMigrateCli2(rest.slice(1));
|