@mrciphersmith/keryx 0.2.124 → 0.2.125
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/README.md +2 -2
- package/dist/cli.js +1937 -664
- package/dist/core.js +579 -546
- package/package.json +3 -3
package/dist/core.js
CHANGED
|
@@ -27,7 +27,7 @@ var __esm = (fn, res, err) => () => {
|
|
|
27
27
|
|
|
28
28
|
// src/lib/fs.ts
|
|
29
29
|
import { randomUUID } from "crypto";
|
|
30
|
-
import { access, mkdir, readFile, rename, rm, stat, utimes, writeFile } from "fs/promises";
|
|
30
|
+
import { access, chmod, mkdir, readFile, rename, rm, stat, utimes, writeFile } from "fs/promises";
|
|
31
31
|
import path from "path";
|
|
32
32
|
async function pathExists(filePath) {
|
|
33
33
|
try {
|
|
@@ -47,12 +47,18 @@ function isPathInside(root, candidate) {
|
|
|
47
47
|
const relative = path.relative(path.resolve(root), path.resolve(candidate));
|
|
48
48
|
return relative === "" || relative.length > 0 && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
49
49
|
}
|
|
50
|
-
async function writeFileAtomic(filePath, content) {
|
|
50
|
+
async function writeFileAtomic(filePath, content, options = {}) {
|
|
51
51
|
const dir = path.dirname(filePath);
|
|
52
52
|
await mkdir(dir, { recursive: true });
|
|
53
53
|
const tmp = path.join(dir, `.${path.basename(filePath)}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`);
|
|
54
54
|
try {
|
|
55
|
-
|
|
55
|
+
if (options.mode === undefined) {
|
|
56
|
+
await writeFile(tmp, content, "utf8");
|
|
57
|
+
} else {
|
|
58
|
+
await writeFile(tmp, content, { encoding: "utf8", mode: options.mode });
|
|
59
|
+
if (process.platform !== "win32")
|
|
60
|
+
await chmod(tmp, options.mode);
|
|
61
|
+
}
|
|
56
62
|
await rename(tmp, filePath);
|
|
57
63
|
} catch (error) {
|
|
58
64
|
await rm(tmp, { force: true }).catch(() => {});
|
|
@@ -71,10 +77,14 @@ async function withFileLock(lockPath, fn, options = {}) {
|
|
|
71
77
|
while (true) {
|
|
72
78
|
try {
|
|
73
79
|
await mkdir(lockPath);
|
|
80
|
+
const createdIno = (await stat(lockPath)).ino;
|
|
81
|
+
await options.raceHook?.("created");
|
|
74
82
|
try {
|
|
75
83
|
await writeFile(ownerPath, JSON.stringify(owner), { encoding: "utf8", flag: "wx", mode: 384 });
|
|
76
84
|
} catch (error) {
|
|
77
|
-
await
|
|
85
|
+
if (await isSameEmptyOrOwnerlessDir(lockPath, createdIno)) {
|
|
86
|
+
await rm(lockPath, { recursive: true, force: true }).catch(() => {});
|
|
87
|
+
}
|
|
78
88
|
throw error;
|
|
79
89
|
}
|
|
80
90
|
break;
|
|
@@ -82,7 +92,7 @@ async function withFileLock(lockPath, fn, options = {}) {
|
|
|
82
92
|
if (!isAlreadyExistsError(error)) {
|
|
83
93
|
throw error;
|
|
84
94
|
}
|
|
85
|
-
await removeStaleLock(lockPath, staleMs);
|
|
95
|
+
await removeStaleLock(lockPath, staleMs, options.raceHook);
|
|
86
96
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
87
97
|
throw new Error(`Timed out waiting for lock: ${lockPath}`);
|
|
88
98
|
}
|
|
@@ -106,7 +116,16 @@ async function withFileLock(lockPath, fn, options = {}) {
|
|
|
106
116
|
function isAlreadyExistsError(error) {
|
|
107
117
|
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
108
118
|
}
|
|
109
|
-
async function
|
|
119
|
+
async function isSameEmptyOrOwnerlessDir(dir, ino) {
|
|
120
|
+
try {
|
|
121
|
+
if ((await stat(dir)).ino !== ino)
|
|
122
|
+
return false;
|
|
123
|
+
return await readLockOwner(path.join(dir, "owner.json")) === undefined;
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async function removeStaleLock(lockPath, staleMs, raceHook) {
|
|
110
129
|
try {
|
|
111
130
|
const stats = await stat(lockPath);
|
|
112
131
|
if (Date.now() - stats.mtimeMs <= staleMs)
|
|
@@ -114,8 +133,17 @@ async function removeStaleLock(lockPath, staleMs) {
|
|
|
114
133
|
const owner = await readLockOwner(path.join(lockPath, "owner.json"));
|
|
115
134
|
if (owner && processIsAlive(owner.pid))
|
|
116
135
|
return;
|
|
136
|
+
await raceHook?.("stale-judged");
|
|
117
137
|
const stalePath = `${lockPath}.stale.${process.pid}.${randomUUID()}`;
|
|
118
138
|
await rename(lockPath, stalePath);
|
|
139
|
+
await raceHook?.("moved-aside");
|
|
140
|
+
const movedIno = (await stat(stalePath)).ino;
|
|
141
|
+
const moved = await readLockOwner(path.join(stalePath, "owner.json"));
|
|
142
|
+
if (movedIno !== stats.ino || moved?.token !== owner?.token) {
|
|
143
|
+
await rename(stalePath, lockPath).catch(() => {});
|
|
144
|
+
await raceHook?.("restored");
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
119
147
|
await rm(stalePath, { recursive: true, force: true });
|
|
120
148
|
} catch {}
|
|
121
149
|
}
|
|
@@ -718,9 +746,9 @@ var init_lifecycle = __esm(() => {
|
|
|
718
746
|
});
|
|
719
747
|
|
|
720
748
|
// src/assets/lock.ts
|
|
721
|
-
import
|
|
749
|
+
import path16 from "path";
|
|
722
750
|
function lockPath(cwd) {
|
|
723
|
-
return
|
|
751
|
+
return path16.join(cwd, ".metaproject", "assets.lock.json");
|
|
724
752
|
}
|
|
725
753
|
function normalizeLock(parsed) {
|
|
726
754
|
const assets = {};
|
|
@@ -775,16 +803,16 @@ var init_lock = __esm(() => {
|
|
|
775
803
|
import { createHash as createHash2 } from "crypto";
|
|
776
804
|
import { readFile as readFile11 } from "fs/promises";
|
|
777
805
|
import os from "os";
|
|
778
|
-
import
|
|
806
|
+
import path17 from "path";
|
|
779
807
|
function assetCacheDir() {
|
|
780
808
|
const override = process.env.KERYX_ASSET_CACHE;
|
|
781
809
|
if (override && override.length > 0) {
|
|
782
810
|
return override;
|
|
783
811
|
}
|
|
784
|
-
return
|
|
812
|
+
return path17.join(os.homedir(), ".cache", "keryx", "assets");
|
|
785
813
|
}
|
|
786
814
|
function cacheAssetPath(id) {
|
|
787
|
-
return
|
|
815
|
+
return path17.join(assetCacheDir(), id);
|
|
788
816
|
}
|
|
789
817
|
async function sha256File(file) {
|
|
790
818
|
const buffer = await readFile11(file);
|
|
@@ -836,9 +864,9 @@ var init_warn_once = __esm(() => {
|
|
|
836
864
|
});
|
|
837
865
|
|
|
838
866
|
// src/capability/seam.ts
|
|
839
|
-
import
|
|
867
|
+
import path18 from "path";
|
|
840
868
|
async function isCapabilityEnabled(cwd, id) {
|
|
841
|
-
const manifestPath =
|
|
869
|
+
const manifestPath = path18.join(cwd, ".metaproject", "metaproject.json");
|
|
842
870
|
if (!await pathExists(manifestPath)) {
|
|
843
871
|
return false;
|
|
844
872
|
}
|
|
@@ -919,9 +947,9 @@ var init_seam = __esm(() => {
|
|
|
919
947
|
});
|
|
920
948
|
|
|
921
949
|
// src/gdgraph/config.ts
|
|
922
|
-
import
|
|
950
|
+
import path19 from "path";
|
|
923
951
|
function gdgraphConfigPath(cwd) {
|
|
924
|
-
return
|
|
952
|
+
return path19.join(cwd, ".metaproject", "gdgraph.config.json");
|
|
925
953
|
}
|
|
926
954
|
function mergeGdgraphConfig(parsed) {
|
|
927
955
|
const base = DEFAULT_GDGRAPH_CONFIG;
|
|
@@ -1526,7 +1554,7 @@ var init_extract = __esm(() => {
|
|
|
1526
1554
|
});
|
|
1527
1555
|
|
|
1528
1556
|
// src/gdgraph/treesitter/grammars.ts
|
|
1529
|
-
import
|
|
1557
|
+
import path20 from "path";
|
|
1530
1558
|
function grammarAssetId(language) {
|
|
1531
1559
|
return `tree-sitter-${language}`;
|
|
1532
1560
|
}
|
|
@@ -1542,7 +1570,7 @@ function symbolLanguage(language) {
|
|
|
1542
1570
|
async function resolveGrammar(cwd, language, grammarsPath) {
|
|
1543
1571
|
const id = grammarAssetId(language);
|
|
1544
1572
|
const lock = await loadAssetsLock(cwd);
|
|
1545
|
-
const overrides = grammarsPath ? { [id]: { path:
|
|
1573
|
+
const overrides = grammarsPath ? { [id]: { path: path20.join(grammarsPath, `${id}.wasm`) } } : undefined;
|
|
1546
1574
|
const registry = registryFromLock(lock, overrides);
|
|
1547
1575
|
const resolved = await resolveAsset(registry, id);
|
|
1548
1576
|
if (!resolved) {
|
|
@@ -1572,7 +1600,7 @@ function toGrammarLanguages(languages) {
|
|
|
1572
1600
|
return out;
|
|
1573
1601
|
}
|
|
1574
1602
|
function grammarForFile(file, available) {
|
|
1575
|
-
const ext =
|
|
1603
|
+
const ext = path20.extname(file);
|
|
1576
1604
|
const preference = ext === ".tsx" ? ["tsx", "typescript"] : ext === ".ts" ? ["typescript"] : ext === ".jsx" || ext === ".js" || ext === ".mjs" || ext === ".cjs" ? ["javascript"] : ext === ".java" ? ["java"] : ext === ".py" ? ["python"] : [];
|
|
1577
1605
|
for (const language of preference) {
|
|
1578
1606
|
if (available.includes(language)) {
|
|
@@ -1834,7 +1862,7 @@ var init_adapter = __esm(() => {
|
|
|
1834
1862
|
|
|
1835
1863
|
// src/gdgraph/enrich.ts
|
|
1836
1864
|
import { mkdir as mkdir6, writeFile as writeFile3 } from "fs/promises";
|
|
1837
|
-
import
|
|
1865
|
+
import path21 from "path";
|
|
1838
1866
|
async function enrichBuildWithSymbols(cwd, files, resolve) {
|
|
1839
1867
|
const config = await loadGdgraphConfig(cwd);
|
|
1840
1868
|
const treesitterConfig = {
|
|
@@ -1850,12 +1878,12 @@ async function enrichBuildWithSymbols(cwd, files, resolve) {
|
|
|
1850
1878
|
return { enriched: true, symbols: layer.symbols.length, calls: layer.calls.length };
|
|
1851
1879
|
}
|
|
1852
1880
|
async function writeSymbolLayer(cwd, layer) {
|
|
1853
|
-
const storageDir =
|
|
1881
|
+
const storageDir = path21.join(cwd, ".metaproject", "data", "gdgraph", "storage");
|
|
1854
1882
|
await mkdir6(storageDir, { recursive: true });
|
|
1855
|
-
await writeFile3(
|
|
1883
|
+
await writeFile3(path21.join(storageDir, "symbols.jsonl"), layer.symbols.map((symbol) => JSON.stringify(symbol)).join(`
|
|
1856
1884
|
`) + `
|
|
1857
1885
|
`, "utf8");
|
|
1858
|
-
await writeFile3(
|
|
1886
|
+
await writeFile3(path21.join(storageDir, "calls.jsonl"), layer.calls.map((call) => JSON.stringify(call)).join(`
|
|
1859
1887
|
`) + `
|
|
1860
1888
|
`, "utf8");
|
|
1861
1889
|
}
|
|
@@ -2045,10 +2073,10 @@ var init_describes = __esm(() => {
|
|
|
2045
2073
|
|
|
2046
2074
|
// src/sync/provenance.ts
|
|
2047
2075
|
import { mkdir as mkdir7, readFile as readFile12, writeFile as writeFile4 } from "fs/promises";
|
|
2048
|
-
import
|
|
2076
|
+
import path22 from "path";
|
|
2049
2077
|
import { spawn } from "child_process";
|
|
2050
2078
|
function provenancePath(cwd, module) {
|
|
2051
|
-
return
|
|
2079
|
+
return path22.join(cwd, ".metaproject", "data", module, ".provenance.json");
|
|
2052
2080
|
}
|
|
2053
2081
|
function gitCmdResult(cwd, args) {
|
|
2054
2082
|
return new Promise((resolve) => {
|
|
@@ -2093,7 +2121,7 @@ async function recordProvenance(cwd, module, at) {
|
|
|
2093
2121
|
if (!head)
|
|
2094
2122
|
return;
|
|
2095
2123
|
const file = provenancePath(cwd, module);
|
|
2096
|
-
await mkdir7(
|
|
2124
|
+
await mkdir7(path22.dirname(file), { recursive: true });
|
|
2097
2125
|
const provenance = { commit: head.commit, branch: head.branch, builtAt: at };
|
|
2098
2126
|
await writeFile4(file, `${JSON.stringify(provenance, null, 2)}
|
|
2099
2127
|
`, "utf8");
|
|
@@ -2117,12 +2145,12 @@ var init_provenance = __esm(() => {
|
|
|
2117
2145
|
|
|
2118
2146
|
// src/gdgraph/staleness.ts
|
|
2119
2147
|
import { stat as stat3 } from "fs/promises";
|
|
2120
|
-
import
|
|
2148
|
+
import path23 from "path";
|
|
2121
2149
|
function nodesJsonlPath(cwd) {
|
|
2122
|
-
return
|
|
2150
|
+
return path23.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
|
|
2123
2151
|
}
|
|
2124
2152
|
function gdgraphConfigPath2(cwd) {
|
|
2125
|
-
return
|
|
2153
|
+
return path23.join(cwd, ".metaproject", "gdgraph.config.json");
|
|
2126
2154
|
}
|
|
2127
2155
|
function categorizeStatusLines(porcelain, rootPrefix) {
|
|
2128
2156
|
const lines = porcelain.split(`
|
|
@@ -2169,7 +2197,7 @@ async function checkGraphStaleness(cwd) {
|
|
|
2169
2197
|
reasons.push(`HEAD moved since the graph was built (built at ${provenance.commit.slice(0, 12)}, now ${head.commit.slice(0, 12)})`);
|
|
2170
2198
|
}
|
|
2171
2199
|
} else {
|
|
2172
|
-
const logsHeadStat = await stat3(
|
|
2200
|
+
const logsHeadStat = await stat3(path23.join(cwd, ".git", "logs", "HEAD")).catch(() => null);
|
|
2173
2201
|
if (logsHeadStat && logsHeadStat.mtimeMs > nodesStat.mtimeMs) {
|
|
2174
2202
|
reasons.push("repo HEAD moved since the graph was built (no build provenance recorded; inferred from .git/logs/HEAD)");
|
|
2175
2203
|
}
|
|
@@ -2303,15 +2331,15 @@ var init_types2 = __esm(() => {
|
|
|
2303
2331
|
|
|
2304
2332
|
// src/wiki/collect.ts
|
|
2305
2333
|
import { readFile as readFile13, readdir as readdir6 } from "fs/promises";
|
|
2306
|
-
import
|
|
2334
|
+
import path24 from "path";
|
|
2307
2335
|
function wikiRootPath(cwd) {
|
|
2308
|
-
return
|
|
2336
|
+
return path24.join(cwd, ".metaproject", "wiki");
|
|
2309
2337
|
}
|
|
2310
2338
|
async function collectPages(cwd) {
|
|
2311
2339
|
const root = wikiRootPath(cwd);
|
|
2312
2340
|
const pages = [];
|
|
2313
2341
|
for (const { type, folder } of WIKI_PAGE_TYPES) {
|
|
2314
|
-
const dir =
|
|
2342
|
+
const dir = path24.join(root, folder);
|
|
2315
2343
|
let names;
|
|
2316
2344
|
try {
|
|
2317
2345
|
names = await readdir6(dir);
|
|
@@ -2326,7 +2354,7 @@ async function collectPages(cwd) {
|
|
|
2326
2354
|
if (!entry.endsWith(".md")) {
|
|
2327
2355
|
continue;
|
|
2328
2356
|
}
|
|
2329
|
-
const absolutePath =
|
|
2357
|
+
const absolutePath = path24.join(dir, entry);
|
|
2330
2358
|
let content;
|
|
2331
2359
|
try {
|
|
2332
2360
|
content = await readFile13(absolutePath, "utf8");
|
|
@@ -4634,16 +4662,16 @@ var init_exfil = __esm(() => {
|
|
|
4634
4662
|
|
|
4635
4663
|
// src/lib/contained-path.ts
|
|
4636
4664
|
import { existsSync, lstatSync, realpathSync } from "fs";
|
|
4637
|
-
import
|
|
4665
|
+
import path25 from "path";
|
|
4638
4666
|
function resolveProjectRoot(startDir) {
|
|
4639
|
-
let current =
|
|
4667
|
+
let current = path25.resolve(startDir);
|
|
4640
4668
|
for (;; ) {
|
|
4641
|
-
if (existsSync(
|
|
4669
|
+
if (existsSync(path25.join(current, ".metaproject")) || existsSync(path25.join(current, ".git"))) {
|
|
4642
4670
|
return current;
|
|
4643
4671
|
}
|
|
4644
|
-
const parent =
|
|
4672
|
+
const parent = path25.dirname(current);
|
|
4645
4673
|
if (parent === current) {
|
|
4646
|
-
return
|
|
4674
|
+
return path25.resolve(startDir);
|
|
4647
4675
|
}
|
|
4648
4676
|
current = parent;
|
|
4649
4677
|
}
|
|
@@ -4973,16 +5001,16 @@ var init_schemas = __esm(() => {
|
|
|
4973
5001
|
});
|
|
4974
5002
|
|
|
4975
5003
|
// src/security/config.ts
|
|
4976
|
-
import
|
|
5004
|
+
import path26 from "path";
|
|
4977
5005
|
import { createHash as createHash4 } from "crypto";
|
|
4978
5006
|
function securityProjectRoot(cwd) {
|
|
4979
5007
|
return resolveProjectRoot(cwd);
|
|
4980
5008
|
}
|
|
4981
5009
|
function securityDataRoot(cwd) {
|
|
4982
|
-
return
|
|
5010
|
+
return path26.join(securityProjectRoot(cwd), ".metaproject", "data", "security");
|
|
4983
5011
|
}
|
|
4984
5012
|
function configPath(cwd) {
|
|
4985
|
-
return
|
|
5013
|
+
return path26.join(securityProjectRoot(cwd), ".metaproject", "security.config.json");
|
|
4986
5014
|
}
|
|
4987
5015
|
function mergePolicy(base, override) {
|
|
4988
5016
|
const merged = {
|
|
@@ -5146,9 +5174,9 @@ var init_config3 = __esm(() => {
|
|
|
5146
5174
|
});
|
|
5147
5175
|
|
|
5148
5176
|
// src/security/redact.ts
|
|
5149
|
-
import
|
|
5177
|
+
import path27 from "path";
|
|
5150
5178
|
import { createHmac, randomBytes } from "crypto";
|
|
5151
|
-
import { mkdir as mkdir8, readFile as readFile14, writeFile as writeFile5, chmod } from "fs/promises";
|
|
5179
|
+
import { mkdir as mkdir8, readFile as readFile14, writeFile as writeFile5, chmod as chmod2 } from "fs/promises";
|
|
5152
5180
|
function maskFor(match) {
|
|
5153
5181
|
return `[REDACTED:${match.mask ?? "sensitive"}]`;
|
|
5154
5182
|
}
|
|
@@ -5221,11 +5249,11 @@ function redactSensitiveText(text) {
|
|
|
5221
5249
|
return applyRedaction(text, matches);
|
|
5222
5250
|
}
|
|
5223
5251
|
function keyDir(cwd) {
|
|
5224
|
-
return
|
|
5252
|
+
return path27.join(securityDataRoot(cwd), "raw");
|
|
5225
5253
|
}
|
|
5226
5254
|
async function getHmacKey(cwd) {
|
|
5227
5255
|
const dir = keyDir(cwd);
|
|
5228
|
-
const file =
|
|
5256
|
+
const file = path27.join(dir, KEY_FILE);
|
|
5229
5257
|
if (await pathExists(file)) {
|
|
5230
5258
|
const existing = (await readFile14(file, "utf8")).trim();
|
|
5231
5259
|
if (existing.length > 0) {
|
|
@@ -5237,7 +5265,7 @@ async function getHmacKey(cwd) {
|
|
|
5237
5265
|
await writeFile5(file, `${key}
|
|
5238
5266
|
`, "utf8");
|
|
5239
5267
|
try {
|
|
5240
|
-
await
|
|
5268
|
+
await chmod2(file, 384);
|
|
5241
5269
|
} catch {}
|
|
5242
5270
|
return key;
|
|
5243
5271
|
}
|
|
@@ -6270,7 +6298,7 @@ var init_resolve = __esm(() => {
|
|
|
6270
6298
|
});
|
|
6271
6299
|
|
|
6272
6300
|
// src/security/report.ts
|
|
6273
|
-
import
|
|
6301
|
+
import path28 from "path";
|
|
6274
6302
|
import { mkdir as mkdir9, writeFile as writeFile6 } from "fs/promises";
|
|
6275
6303
|
function tally(values) {
|
|
6276
6304
|
const counts = {};
|
|
@@ -6387,26 +6415,26 @@ function renderFindings(findings) {
|
|
|
6387
6415
|
`);
|
|
6388
6416
|
}
|
|
6389
6417
|
function artifactsDir(cwd) {
|
|
6390
|
-
return
|
|
6418
|
+
return path28.join(securityDataRoot(cwd), "artifacts");
|
|
6391
6419
|
}
|
|
6392
6420
|
async function writeSecurityArtifacts(cwd, report, config) {
|
|
6393
6421
|
const dir = artifactsDir(cwd);
|
|
6394
6422
|
await mkdir9(dir, { recursive: true });
|
|
6395
6423
|
const committable = toCommittableReport(report);
|
|
6396
|
-
const markdown =
|
|
6397
|
-
const json =
|
|
6424
|
+
const markdown = path28.join(dir, "latest.md");
|
|
6425
|
+
const json = path28.join(dir, "latest.json");
|
|
6398
6426
|
await writeFile6(markdown, renderReportMarkdown(committable), "utf8");
|
|
6399
6427
|
await writeFile6(json, `${JSON.stringify(committable, null, 2)}
|
|
6400
6428
|
`, "utf8");
|
|
6401
6429
|
if (config.storeHashes) {
|
|
6402
|
-
const rawDir =
|
|
6430
|
+
const rawDir = path28.join(securityDataRoot(cwd), "raw");
|
|
6403
6431
|
await mkdir9(rawDir, { recursive: true });
|
|
6404
|
-
await writeFile6(
|
|
6432
|
+
await writeFile6(path28.join(rawDir, "report.local.json"), `${JSON.stringify(report, null, 2)}
|
|
6405
6433
|
`, "utf8");
|
|
6406
6434
|
}
|
|
6407
6435
|
return {
|
|
6408
|
-
markdownPath:
|
|
6409
|
-
jsonPath:
|
|
6436
|
+
markdownPath: path28.relative(cwd, markdown),
|
|
6437
|
+
jsonPath: path28.relative(cwd, json)
|
|
6410
6438
|
};
|
|
6411
6439
|
}
|
|
6412
6440
|
var SCHEMA_VERSION = 1;
|
|
@@ -6415,13 +6443,13 @@ var init_report = __esm(() => {
|
|
|
6415
6443
|
});
|
|
6416
6444
|
|
|
6417
6445
|
// src/security/incidents.ts
|
|
6418
|
-
import
|
|
6446
|
+
import path29 from "path";
|
|
6419
6447
|
import { appendFile as appendFile3, mkdir as mkdir10, readFile as readFile15 } from "fs/promises";
|
|
6420
6448
|
function incidentsDir(cwd) {
|
|
6421
|
-
return
|
|
6449
|
+
return path29.join(securityDataRoot(cwd), "incidents");
|
|
6422
6450
|
}
|
|
6423
6451
|
function incidentsFile(cwd) {
|
|
6424
|
-
return
|
|
6452
|
+
return path29.join(incidentsDir(cwd), "incidents.jsonl");
|
|
6425
6453
|
}
|
|
6426
6454
|
async function appendIncident(cwd, entry) {
|
|
6427
6455
|
const dir = incidentsDir(cwd);
|
|
@@ -6440,7 +6468,7 @@ var init_incidents = __esm(() => {
|
|
|
6440
6468
|
});
|
|
6441
6469
|
|
|
6442
6470
|
// src/security/self-protect.ts
|
|
6443
|
-
import
|
|
6471
|
+
import path30 from "path";
|
|
6444
6472
|
import { mkdir as mkdir11, readFile as readFile16, writeFile as writeFile7 } from "fs/promises";
|
|
6445
6473
|
function currentState(config) {
|
|
6446
6474
|
const policies = {};
|
|
@@ -6499,7 +6527,7 @@ function evaluateSelfProtection(config, previous, now = new Date().toISOString()
|
|
|
6499
6527
|
return { warnings, incidents, findings, checksumMatch: checksum.match };
|
|
6500
6528
|
}
|
|
6501
6529
|
function stateFile(cwd) {
|
|
6502
|
-
return
|
|
6530
|
+
return path30.join(securityDataRoot(cwd), "raw", "state.json");
|
|
6503
6531
|
}
|
|
6504
6532
|
async function readState(cwd) {
|
|
6505
6533
|
const file = stateFile(cwd);
|
|
@@ -6514,7 +6542,7 @@ async function readState(cwd) {
|
|
|
6514
6542
|
}
|
|
6515
6543
|
async function writeState(cwd, state) {
|
|
6516
6544
|
const file = stateFile(cwd);
|
|
6517
|
-
await mkdir11(
|
|
6545
|
+
await mkdir11(path30.dirname(file), { recursive: true });
|
|
6518
6546
|
await writeFile7(file, `${JSON.stringify(state, null, 2)}
|
|
6519
6547
|
`, "utf8");
|
|
6520
6548
|
}
|
|
@@ -6532,12 +6560,12 @@ var init_self_protect = __esm(() => {
|
|
|
6532
6560
|
|
|
6533
6561
|
// src/lib/descriptor-read.ts
|
|
6534
6562
|
import { constants, fstatSync, lstatSync as lstatSync2, statSync } from "fs";
|
|
6535
|
-
import
|
|
6563
|
+
import path31 from "path";
|
|
6536
6564
|
import { dlopen, FFIType, ptr } from "bun:ffi";
|
|
6537
6565
|
function readDescriptorChain(workspaceRoot, absolutePath, options = {}) {
|
|
6538
|
-
const relativePath =
|
|
6539
|
-
const components = relativePath.split(
|
|
6540
|
-
if (!relativePath ||
|
|
6566
|
+
const relativePath = path31.relative(workspaceRoot, absolutePath);
|
|
6567
|
+
const components = relativePath.split(path31.sep);
|
|
6568
|
+
if (!relativePath || path31.isAbsolute(relativePath) || components.some((component) => !component || component === "." || component === "..")) {
|
|
6541
6569
|
throw new DescriptorReadError("invalid-path", "safe source path is not workspace-relative");
|
|
6542
6570
|
}
|
|
6543
6571
|
if (options.maxBytes !== undefined && (!Number.isSafeInteger(options.maxBytes) || options.maxBytes < 0)) {
|
|
@@ -6660,7 +6688,7 @@ var init_descriptor_read = __esm(() => {
|
|
|
6660
6688
|
|
|
6661
6689
|
// src/lib/contained-read.ts
|
|
6662
6690
|
import { lstat, realpath, stat as stat4 } from "fs/promises";
|
|
6663
|
-
import
|
|
6691
|
+
import path32 from "path";
|
|
6664
6692
|
async function readContainedFile(ownerRoot, candidatePath, options = {}) {
|
|
6665
6693
|
if (options.backend === "unsupported") {
|
|
6666
6694
|
throw new ContainedReadError("CONTAINED_READ_UNAVAILABLE", "safe descriptor source reads are unavailable on this platform");
|
|
@@ -6709,8 +6737,8 @@ async function readContainedFile(ownerRoot, candidatePath, options = {}) {
|
|
|
6709
6737
|
}
|
|
6710
6738
|
}
|
|
6711
6739
|
function isInside(root, candidate) {
|
|
6712
|
-
const relative =
|
|
6713
|
-
return relative === "" || !
|
|
6740
|
+
const relative = path32.relative(root, candidate);
|
|
6741
|
+
return relative === "" || !path32.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path32.sep}`);
|
|
6714
6742
|
}
|
|
6715
6743
|
function mapDescriptorError(error) {
|
|
6716
6744
|
if (!(error instanceof DescriptorReadError))
|
|
@@ -6735,16 +6763,16 @@ var init_contained_read = __esm(() => {
|
|
|
6735
6763
|
|
|
6736
6764
|
// src/security/path-scan.ts
|
|
6737
6765
|
import { readdir as readdir7, realpath as realpath2, stat as stat5 } from "fs/promises";
|
|
6738
|
-
import
|
|
6766
|
+
import path33 from "path";
|
|
6739
6767
|
function isInside2(root, candidate) {
|
|
6740
|
-
const relative =
|
|
6741
|
-
return relative === "" || !
|
|
6768
|
+
const relative = path33.relative(root, candidate);
|
|
6769
|
+
return relative === "" || !path33.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path33.sep}`);
|
|
6742
6770
|
}
|
|
6743
6771
|
function identityFor(value) {
|
|
6744
6772
|
return `${String(value.dev)}:${String(value.ino)}`;
|
|
6745
6773
|
}
|
|
6746
6774
|
function relativePath(root, candidate) {
|
|
6747
|
-
const relative =
|
|
6775
|
+
const relative = path33.relative(root, candidate);
|
|
6748
6776
|
return relative === "" ? "." : relative;
|
|
6749
6777
|
}
|
|
6750
6778
|
function safeReason(error) {
|
|
@@ -6781,14 +6809,14 @@ async function scanContainedPath(input) {
|
|
|
6781
6809
|
throw new Error("security scan target is outside the project root");
|
|
6782
6810
|
}
|
|
6783
6811
|
const exclusions = (input.exclusions ?? []).map((entry) => {
|
|
6784
|
-
const absolute =
|
|
6812
|
+
const absolute = path33.resolve(ownerRoot, entry);
|
|
6785
6813
|
return isInside2(ownerRoot, absolute) ? absolute : null;
|
|
6786
6814
|
}).filter((entry) => entry !== null);
|
|
6787
6815
|
const scope = {
|
|
6788
6816
|
path: relativePath(ownerRoot, targetReal),
|
|
6789
6817
|
recursive: input.recursive ?? true,
|
|
6790
6818
|
exclusions: (input.exclusions ?? []).map((entry) => {
|
|
6791
|
-
const absolute =
|
|
6819
|
+
const absolute = path33.resolve(ownerRoot, entry);
|
|
6792
6820
|
return isInside2(ownerRoot, absolute) ? relativePath(ownerRoot, absolute) : "[external exclusion omitted]";
|
|
6793
6821
|
}),
|
|
6794
6822
|
limits
|
|
@@ -6806,7 +6834,7 @@ async function scanContainedPath(input) {
|
|
|
6806
6834
|
if (!coverage.reasons.includes(reason))
|
|
6807
6835
|
coverage.reasons.push(reason);
|
|
6808
6836
|
};
|
|
6809
|
-
const excluded = (candidate) => exclusions.some((entry) => candidate === entry || candidate.startsWith(`${entry}${
|
|
6837
|
+
const excluded = (candidate) => exclusions.some((entry) => candidate === entry || candidate.startsWith(`${entry}${path33.sep}`));
|
|
6810
6838
|
const visit = async (candidate, depth) => {
|
|
6811
6839
|
if (stoppedByLimit)
|
|
6812
6840
|
return;
|
|
@@ -6869,7 +6897,7 @@ async function scanContainedPath(input) {
|
|
|
6869
6897
|
return;
|
|
6870
6898
|
}
|
|
6871
6899
|
for (const entry of entries) {
|
|
6872
|
-
await visit(
|
|
6900
|
+
await visit(path33.join(canonical, entry), depth + 1);
|
|
6873
6901
|
if (stoppedByLimit)
|
|
6874
6902
|
break;
|
|
6875
6903
|
}
|
|
@@ -6933,7 +6961,7 @@ __export(exports_service2, {
|
|
|
6933
6961
|
runScanPath: () => runScanPath,
|
|
6934
6962
|
validateSerializedOutput: () => validateSerializedOutput
|
|
6935
6963
|
});
|
|
6936
|
-
import
|
|
6964
|
+
import path34 from "path";
|
|
6937
6965
|
import { readFile as readFile17 } from "fs/promises";
|
|
6938
6966
|
function validateSerializedOutput(content) {
|
|
6939
6967
|
return validateSerializedContentForTransport(content);
|
|
@@ -7035,7 +7063,7 @@ function hasRecognizedGate(value) {
|
|
|
7035
7063
|
return typeof gate === "string" && RECOGNIZED_GATES.has(gate);
|
|
7036
7064
|
}
|
|
7037
7065
|
async function readLatestReport(cwd) {
|
|
7038
|
-
const file =
|
|
7066
|
+
const file = path34.join(artifactsDir(cwd), "latest.json");
|
|
7039
7067
|
if (!await pathExists(file)) {
|
|
7040
7068
|
return { kind: "absent" };
|
|
7041
7069
|
}
|
|
@@ -7152,7 +7180,7 @@ var init_service = __esm(() => {
|
|
|
7152
7180
|
});
|
|
7153
7181
|
|
|
7154
7182
|
// src/security/guard.ts
|
|
7155
|
-
import
|
|
7183
|
+
import path35 from "path";
|
|
7156
7184
|
function prepareOutputForPersistence(guard, original) {
|
|
7157
7185
|
if (!guard.allowed) {
|
|
7158
7186
|
return { allowed: false, reason: guard.reason ?? "security gate blocked" };
|
|
@@ -7170,7 +7198,7 @@ function prepareOutputForPersistence(guard, original) {
|
|
|
7170
7198
|
};
|
|
7171
7199
|
}
|
|
7172
7200
|
async function resolveManifestSecurityState(cwd) {
|
|
7173
|
-
const manifestPath =
|
|
7201
|
+
const manifestPath = path35.join(securityProjectRoot(cwd), ".metaproject", "metaproject.json");
|
|
7174
7202
|
if (!await pathExists(manifestPath)) {
|
|
7175
7203
|
return { enabled: false, manifestUnreadable: false };
|
|
7176
7204
|
}
|
|
@@ -7368,9 +7396,9 @@ var MEMORY_EMBEDDING_ID = "memory.embedding", DEFAULT_EMBED_DIMS = 96;
|
|
|
7368
7396
|
// src/memory/embedding/index.ts
|
|
7369
7397
|
import { createHash as createHash5 } from "crypto";
|
|
7370
7398
|
import { mkdir as mkdir12, readFile as readFile18, writeFile as writeFile8 } from "fs/promises";
|
|
7371
|
-
import
|
|
7399
|
+
import path36 from "path";
|
|
7372
7400
|
function embeddingsDir(cwd) {
|
|
7373
|
-
return
|
|
7401
|
+
return path36.join(cwd, ".metaproject", "data", "memory", "embeddings");
|
|
7374
7402
|
}
|
|
7375
7403
|
function entryText(entry) {
|
|
7376
7404
|
return `${entry.title}
|
|
@@ -7399,17 +7427,17 @@ async function buildEmbeddingIndex(cwd, entries, embedder, model, now) {
|
|
|
7399
7427
|
};
|
|
7400
7428
|
const dir = embeddingsDir(cwd);
|
|
7401
7429
|
await mkdir12(dir, { recursive: true });
|
|
7402
|
-
await writeFile8(
|
|
7430
|
+
await writeFile8(path36.join(dir, "index.meta.json"), `${JSON.stringify(meta, null, 2)}
|
|
7403
7431
|
`, "utf8");
|
|
7404
|
-
await writeFile8(
|
|
7432
|
+
await writeFile8(path36.join(dir, "vectors.jsonl"), records.map((record) => JSON.stringify(record)).join(`
|
|
7405
7433
|
`) + (records.length > 0 ? `
|
|
7406
7434
|
` : ""), "utf8");
|
|
7407
7435
|
return toIndex(meta, records);
|
|
7408
7436
|
}
|
|
7409
7437
|
async function loadEmbeddingIndex(cwd) {
|
|
7410
7438
|
const dir = embeddingsDir(cwd);
|
|
7411
|
-
const metaPath =
|
|
7412
|
-
const vectorsPath =
|
|
7439
|
+
const metaPath = path36.join(dir, "index.meta.json");
|
|
7440
|
+
const vectorsPath = path36.join(dir, "vectors.jsonl");
|
|
7413
7441
|
if (!await pathExists(metaPath) || !await pathExists(vectorsPath)) {
|
|
7414
7442
|
return null;
|
|
7415
7443
|
}
|
|
@@ -7860,7 +7888,7 @@ var init_ask = __esm(() => {
|
|
|
7860
7888
|
});
|
|
7861
7889
|
|
|
7862
7890
|
// src/wiki/backlinks.ts
|
|
7863
|
-
import
|
|
7891
|
+
import path37 from "path";
|
|
7864
7892
|
function extractCodePaths(content) {
|
|
7865
7893
|
const out = [];
|
|
7866
7894
|
let match;
|
|
@@ -7890,8 +7918,8 @@ function resolveLink(fromRepoPath, raw) {
|
|
|
7890
7918
|
const clean = (raw.split("#")[0] ?? "").trim();
|
|
7891
7919
|
if (!clean)
|
|
7892
7920
|
return "";
|
|
7893
|
-
const fromDir =
|
|
7894
|
-
return
|
|
7921
|
+
const fromDir = path37.posix.dirname(fromRepoPath.split(path37.sep).join("/"));
|
|
7922
|
+
return path37.posix.normalize(path37.posix.join(fromDir, clean));
|
|
7895
7923
|
}
|
|
7896
7924
|
function buildBacklinkIndex(pages) {
|
|
7897
7925
|
const index = new Map;
|
|
@@ -7905,18 +7933,18 @@ function buildBacklinkIndex(pages) {
|
|
|
7905
7933
|
}
|
|
7906
7934
|
};
|
|
7907
7935
|
for (const page of pages) {
|
|
7908
|
-
const from = page.repoPath.split(
|
|
7936
|
+
const from = page.repoPath.split(path37.sep).join("/");
|
|
7909
7937
|
for (const raw of extractLinks(page.content))
|
|
7910
7938
|
add(resolveLink(from, raw), from);
|
|
7911
7939
|
for (const raw of extractCodePaths(page.content))
|
|
7912
|
-
add(
|
|
7940
|
+
add(path37.posix.normalize(raw), from);
|
|
7913
7941
|
}
|
|
7914
7942
|
for (const list of index.values())
|
|
7915
7943
|
list.sort();
|
|
7916
7944
|
return index;
|
|
7917
7945
|
}
|
|
7918
7946
|
function backlinksFor(index, targetRepoPath) {
|
|
7919
|
-
const key =
|
|
7947
|
+
const key = path37.posix.normalize(targetRepoPath.split(path37.sep).join("/"));
|
|
7920
7948
|
return index.get(key) ?? [];
|
|
7921
7949
|
}
|
|
7922
7950
|
var LINK, CODE_SPAN, FILE_LIKE;
|
|
@@ -7929,7 +7957,7 @@ var init_backlinks = __esm(() => {
|
|
|
7929
7957
|
// src/ctx/assembly.ts
|
|
7930
7958
|
import { createHash as createHash6 } from "crypto";
|
|
7931
7959
|
import { mkdir as mkdir13, rename as rename4, writeFile as writeFile9 } from "fs/promises";
|
|
7932
|
-
import
|
|
7960
|
+
import path38 from "path";
|
|
7933
7961
|
function assembleContext(input) {
|
|
7934
7962
|
let items = 0;
|
|
7935
7963
|
let tokens = 0;
|
|
@@ -7973,9 +8001,9 @@ async function recordNoContentContext(input) {
|
|
|
7973
8001
|
return assembly;
|
|
7974
8002
|
}
|
|
7975
8003
|
async function recordContextAssembly(input) {
|
|
7976
|
-
const directory =
|
|
8004
|
+
const directory = path38.join(input.workspaceRoot, ".metaproject", "context-operations", "traces");
|
|
7977
8005
|
await mkdir13(directory, { recursive: true });
|
|
7978
|
-
const target =
|
|
8006
|
+
const target = path38.join(directory, path38.basename(input.assembly.traceRef));
|
|
7979
8007
|
const temporary = `${target}.${process.pid}.tmp`;
|
|
7980
8008
|
await writeFile9(temporary, `${JSON.stringify({ schemaVersion: "1.0", correlationId: input.correlationId, outcome: input.outcome, configurationRevision: input.assembly.configurationRevision, policy: { ref: input.assembly.policyRef, revision: input.assembly.policyRevision }, selected: input.assembly.selected, omittedOptional: input.assembly.omittedOptional, partial: input.assembly.partial })}
|
|
7981
8009
|
`, { mode: 384 });
|
|
@@ -7990,10 +8018,10 @@ function traceRefFor(traceId) {
|
|
|
7990
8018
|
var init_assembly = () => {};
|
|
7991
8019
|
|
|
7992
8020
|
// src/wiki/section-tombstone.ts
|
|
7993
|
-
import
|
|
8021
|
+
import path39 from "path";
|
|
7994
8022
|
import { stat as stat6 } from "fs/promises";
|
|
7995
8023
|
function sectionRegistryPath(cwd) {
|
|
7996
|
-
return
|
|
8024
|
+
return path39.join(cwd, ".metaproject", "wiki", ".sections.json");
|
|
7997
8025
|
}
|
|
7998
8026
|
function emptySectionRegistry() {
|
|
7999
8027
|
return { version: SECTION_REGISTRY_VERSION, entries: [], tombstones: [], lifted: [] };
|
|
@@ -9130,15 +9158,15 @@ __export(exports_service3, {
|
|
|
9130
9158
|
import { spawn as spawn2 } from "child_process";
|
|
9131
9159
|
import { createHash as createHash8 } from "crypto";
|
|
9132
9160
|
import { mkdir as mkdir14, readFile as readFile20, readdir as readdir8, rm as rm3, writeFile as writeFile10 } from "fs/promises";
|
|
9133
|
-
import
|
|
9161
|
+
import path40 from "path";
|
|
9134
9162
|
function wikiRootPath2(cwd) {
|
|
9135
|
-
return
|
|
9163
|
+
return path40.join(cwd, ".metaproject", "wiki");
|
|
9136
9164
|
}
|
|
9137
9165
|
function dataRootPath(cwd) {
|
|
9138
|
-
return
|
|
9166
|
+
return path40.join(cwd, ".metaproject", "data", "gdwiki");
|
|
9139
9167
|
}
|
|
9140
9168
|
function linkCheckReportPath(cwd) {
|
|
9141
|
-
return
|
|
9169
|
+
return path40.join(dataRootPath(cwd), "link-check", "latest.md");
|
|
9142
9170
|
}
|
|
9143
9171
|
async function wikiStatus(cwd) {
|
|
9144
9172
|
const root = wikiRootPath2(cwd);
|
|
@@ -9146,7 +9174,7 @@ async function wikiStatus(cwd) {
|
|
|
9146
9174
|
const pages = enabled ? await collectPages(cwd) : [];
|
|
9147
9175
|
return {
|
|
9148
9176
|
enabled,
|
|
9149
|
-
wikiRoot:
|
|
9177
|
+
wikiRoot: path40.relative(cwd, root),
|
|
9150
9178
|
totalPages: pages.length,
|
|
9151
9179
|
countsByType: WIKI_PAGE_TYPES.map(({ type }) => ({
|
|
9152
9180
|
type,
|
|
@@ -9177,9 +9205,9 @@ async function wikiCreatePage(input) {
|
|
|
9177
9205
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(input.slug)) {
|
|
9178
9206
|
throw new Error(`Invalid slug: ${input.slug}. Use lowercase letters, digits, and hyphens.`);
|
|
9179
9207
|
}
|
|
9180
|
-
const dir =
|
|
9181
|
-
const filePath =
|
|
9182
|
-
const relativePath =
|
|
9208
|
+
const dir = path40.join(wikiRootPath2(input.cwd), typeConfig.folder);
|
|
9209
|
+
const filePath = path40.join(dir, `${input.slug}.md`);
|
|
9210
|
+
const relativePath = path40.relative(input.cwd, filePath);
|
|
9183
9211
|
if (await pathExists(filePath) && !input.force) {
|
|
9184
9212
|
throw new Error(`Page already exists: ${relativePath}. Use --force to overwrite.`);
|
|
9185
9213
|
}
|
|
@@ -9190,7 +9218,7 @@ async function wikiCreatePage(input) {
|
|
|
9190
9218
|
}
|
|
9191
9219
|
async function wikiGenerateIndex(cwd) {
|
|
9192
9220
|
const root = wikiRootPath2(cwd);
|
|
9193
|
-
const indexPath =
|
|
9221
|
+
const indexPath = path40.join(root, "index.md");
|
|
9194
9222
|
const pages = await collectPages(cwd);
|
|
9195
9223
|
const generatedAt = new Date().toISOString();
|
|
9196
9224
|
const managedBlock = `${WIKI_INDEX_BEGIN}
|
|
@@ -9208,7 +9236,7 @@ ${managedBlock}
|
|
|
9208
9236
|
await mkdir14(root, { recursive: true });
|
|
9209
9237
|
await writeFile10(indexPath, next, "utf8");
|
|
9210
9238
|
return {
|
|
9211
|
-
path:
|
|
9239
|
+
path: path40.relative(cwd, indexPath),
|
|
9212
9240
|
pageCount: pages.length,
|
|
9213
9241
|
generatedAt
|
|
9214
9242
|
};
|
|
@@ -9216,13 +9244,13 @@ ${managedBlock}
|
|
|
9216
9244
|
async function wikiCheckLinks(cwd) {
|
|
9217
9245
|
const root = wikiRootPath2(cwd);
|
|
9218
9246
|
const allFiles = await pathExists(root) ? await walkMarkdown(root) : [];
|
|
9219
|
-
const files = allFiles.filter((absolutePath) => !
|
|
9247
|
+
const files = allFiles.filter((absolutePath) => !path40.relative(root, absolutePath).startsWith(`templates${path40.sep}`));
|
|
9220
9248
|
const broken = [];
|
|
9221
9249
|
let checkedLinks = 0;
|
|
9222
9250
|
let skippedExternal = 0;
|
|
9223
9251
|
for (const absolutePath of files) {
|
|
9224
9252
|
const content = await readFile20(absolutePath, "utf8");
|
|
9225
|
-
const pageRelative =
|
|
9253
|
+
const pageRelative = path40.relative(cwd, absolutePath);
|
|
9226
9254
|
for (const target of extractLinkTargets(content)) {
|
|
9227
9255
|
if (EXTERNAL_LINK.test(target)) {
|
|
9228
9256
|
skippedExternal += 1;
|
|
@@ -9233,7 +9261,7 @@ async function wikiCheckLinks(cwd) {
|
|
|
9233
9261
|
continue;
|
|
9234
9262
|
}
|
|
9235
9263
|
checkedLinks += 1;
|
|
9236
|
-
const resolved =
|
|
9264
|
+
const resolved = path40.resolve(path40.dirname(absolutePath), filePart);
|
|
9237
9265
|
if (!await pathExists(resolved)) {
|
|
9238
9266
|
broken.push({
|
|
9239
9267
|
page: pageRelative,
|
|
@@ -9245,7 +9273,7 @@ async function wikiCheckLinks(cwd) {
|
|
|
9245
9273
|
}
|
|
9246
9274
|
const generatedAt = new Date().toISOString();
|
|
9247
9275
|
const reportPath = linkCheckReportPath(cwd);
|
|
9248
|
-
await mkdir14(
|
|
9276
|
+
await mkdir14(path40.dirname(reportPath), { recursive: true });
|
|
9249
9277
|
await writeFile10(reportPath, renderLinkCheckReport({
|
|
9250
9278
|
generatedAt,
|
|
9251
9279
|
checkedPages: files.length,
|
|
@@ -9254,7 +9282,7 @@ async function wikiCheckLinks(cwd) {
|
|
|
9254
9282
|
broken
|
|
9255
9283
|
}), "utf8");
|
|
9256
9284
|
return {
|
|
9257
|
-
reportPath:
|
|
9285
|
+
reportPath: path40.relative(cwd, reportPath),
|
|
9258
9286
|
checkedPages: files.length,
|
|
9259
9287
|
checkedLinks,
|
|
9260
9288
|
skippedExternal,
|
|
@@ -9304,7 +9332,7 @@ async function wikiValidate(cwd) {
|
|
|
9304
9332
|
}
|
|
9305
9333
|
if (await isIndexStale(cwd, pages)) {
|
|
9306
9334
|
issues.push({
|
|
9307
|
-
page:
|
|
9335
|
+
page: path40.join(path40.relative(cwd, wikiRootPath2(cwd)), "index.md"),
|
|
9308
9336
|
kind: "index",
|
|
9309
9337
|
message: "index out of date, run `keryx wiki index`"
|
|
9310
9338
|
});
|
|
@@ -9341,7 +9369,7 @@ async function wikiCollect(input) {
|
|
|
9341
9369
|
};
|
|
9342
9370
|
}
|
|
9343
9371
|
async function wikiPruneOrphans(cwd) {
|
|
9344
|
-
const componentsDir =
|
|
9372
|
+
const componentsDir = path40.join(wikiRootPath2(cwd), "components");
|
|
9345
9373
|
if (!await pathExists(componentsDir)) {
|
|
9346
9374
|
return { pruned: [], orphanedAccepted: [] };
|
|
9347
9375
|
}
|
|
@@ -9358,20 +9386,20 @@ async function wikiPruneOrphans(cwd) {
|
|
|
9358
9386
|
if (validSlugs.has(slug)) {
|
|
9359
9387
|
continue;
|
|
9360
9388
|
}
|
|
9361
|
-
const filePath =
|
|
9389
|
+
const filePath = path40.join(componentsDir, entry);
|
|
9362
9390
|
const current = await readFile20(filePath, "utf8");
|
|
9363
9391
|
const isUnmodifiedDraft = /\nStatus:\s*draft\s*\n/.test(current) && current.includes("Generated by `keryx wiki collect`");
|
|
9364
9392
|
if (isUnmodifiedDraft) {
|
|
9365
9393
|
await rm3(filePath);
|
|
9366
|
-
pruned.push(
|
|
9394
|
+
pruned.push(path40.relative(cwd, filePath));
|
|
9367
9395
|
} else {
|
|
9368
|
-
orphanedAccepted.push(
|
|
9396
|
+
orphanedAccepted.push(path40.relative(cwd, filePath));
|
|
9369
9397
|
}
|
|
9370
9398
|
}
|
|
9371
9399
|
return { pruned, orphanedAccepted };
|
|
9372
9400
|
}
|
|
9373
9401
|
async function validModuleNames(cwd) {
|
|
9374
|
-
const nodesPath =
|
|
9402
|
+
const nodesPath = path40.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
|
|
9375
9403
|
if (!await pathExists(nodesPath)) {
|
|
9376
9404
|
return;
|
|
9377
9405
|
}
|
|
@@ -9440,9 +9468,9 @@ async function wikiEvidence(input) {
|
|
|
9440
9468
|
});
|
|
9441
9469
|
}
|
|
9442
9470
|
function resolveEvidenceScope(cwd, override) {
|
|
9443
|
-
const absolute =
|
|
9471
|
+
const absolute = path40.resolve(cwd);
|
|
9444
9472
|
return {
|
|
9445
|
-
projectId: override?.projectId ?? (
|
|
9473
|
+
projectId: override?.projectId ?? (path40.basename(absolute) || "project"),
|
|
9446
9474
|
checkoutId: override?.checkoutId ?? `checkout:${createHash8("sha256").update(absolute).digest("hex").slice(0, 16)}`,
|
|
9447
9475
|
...override?.workspaceId ? { workspaceId: override.workspaceId } : {},
|
|
9448
9476
|
...override?.taskId ? { taskId: override.taskId } : {}
|
|
@@ -9457,7 +9485,7 @@ function isMachineAuthoredPage(pageType, relativePath, content) {
|
|
|
9457
9485
|
if (source === null) {
|
|
9458
9486
|
return false;
|
|
9459
9487
|
}
|
|
9460
|
-
const normalised = relativePath.split(
|
|
9488
|
+
const normalised = relativePath.split(path40.sep).join("/").replace(/^wiki\//, "");
|
|
9461
9489
|
return WIKI_PAGE_PRODUCERS.some((producer) => producer.source === source && producer.pageType === pageType && producer.path.test(normalised) && /^-[ \t]+Link:.*\bsha256\b/m.test(content));
|
|
9462
9490
|
}
|
|
9463
9491
|
function createGdWikiService() {
|
|
@@ -9473,8 +9501,8 @@ function createGdWikiService() {
|
|
|
9473
9501
|
};
|
|
9474
9502
|
}
|
|
9475
9503
|
async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules) {
|
|
9476
|
-
const nodesPath =
|
|
9477
|
-
const edgesPath =
|
|
9504
|
+
const nodesPath = path40.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
|
|
9505
|
+
const edgesPath = path40.join(cwd, ".metaproject", "data", "gdgraph", "storage", "edges.jsonl");
|
|
9478
9506
|
if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
|
|
9479
9507
|
return [];
|
|
9480
9508
|
}
|
|
@@ -9658,7 +9686,7 @@ function topCounts(bucket, limit) {
|
|
|
9658
9686
|
return [...bucket.entries()].sort((a, b) => b[1] - a[1]).slice(0, limit);
|
|
9659
9687
|
}
|
|
9660
9688
|
async function readModuleReadme(cwd, moduleName) {
|
|
9661
|
-
const readmePath =
|
|
9689
|
+
const readmePath = path40.join(cwd, ...moduleName.split("/"), "README.md");
|
|
9662
9690
|
if (!await pathExists(readmePath)) {
|
|
9663
9691
|
return null;
|
|
9664
9692
|
}
|
|
@@ -9679,7 +9707,7 @@ async function extractModuleExports(cwd, files) {
|
|
|
9679
9707
|
const declRe = /export\s+(?:async\s+)?(?:default\s+)?(?:const|let|var|function|class|type|interface|enum)\s+([A-Za-z_$][\w$]*)/g;
|
|
9680
9708
|
const braceRe = /export\s*\{([^}]+)\}/g;
|
|
9681
9709
|
for (const file of files.slice(0, 4)) {
|
|
9682
|
-
const filePath =
|
|
9710
|
+
const filePath = path40.join(cwd, ...file.split("/"));
|
|
9683
9711
|
if (!await pathExists(filePath)) {
|
|
9684
9712
|
continue;
|
|
9685
9713
|
}
|
|
@@ -9710,7 +9738,7 @@ async function extractModuleExports(cwd, files) {
|
|
|
9710
9738
|
}
|
|
9711
9739
|
async function extractModuleApi(cwd, files) {
|
|
9712
9740
|
const names = await extractModuleExports(cwd, files);
|
|
9713
|
-
const symbolsPath =
|
|
9741
|
+
const symbolsPath = path40.join(cwd, ".metaproject", "data", "gdgraph", "storage", "symbols.jsonl");
|
|
9714
9742
|
if (names.length === 0 || !await pathExists(symbolsPath)) {
|
|
9715
9743
|
return names.map((name) => "`" + name + "`");
|
|
9716
9744
|
}
|
|
@@ -9736,7 +9764,7 @@ async function extractModuleApi(cwd, files) {
|
|
|
9736
9764
|
});
|
|
9737
9765
|
}
|
|
9738
9766
|
async function collectHealthWikiCandidates(cwd, generatedAt) {
|
|
9739
|
-
const healthPath =
|
|
9767
|
+
const healthPath = path40.join(cwd, ".metaproject", "data", "health", "artifacts", "latest.json");
|
|
9740
9768
|
if (!await pathExists(healthPath)) {
|
|
9741
9769
|
return [];
|
|
9742
9770
|
}
|
|
@@ -9778,7 +9806,7 @@ async function collectHealthWikiCandidates(cwd, generatedAt) {
|
|
|
9778
9806
|
}];
|
|
9779
9807
|
}
|
|
9780
9808
|
async function collectTestingWikiCandidates(cwd, generatedAt) {
|
|
9781
|
-
const contextPath =
|
|
9809
|
+
const contextPath = path40.join(cwd, ".metaproject", "data", "testing", "context.md");
|
|
9782
9810
|
if (!await pathExists(contextPath)) {
|
|
9783
9811
|
return [];
|
|
9784
9812
|
}
|
|
@@ -9809,8 +9837,8 @@ async function writeCollectedPage(cwd, candidate, force) {
|
|
|
9809
9837
|
if (!folder) {
|
|
9810
9838
|
throw new Error(`Unsupported collected wiki type: ${candidate.type}`);
|
|
9811
9839
|
}
|
|
9812
|
-
const filePath =
|
|
9813
|
-
const relativePath =
|
|
9840
|
+
const filePath = path40.join(wikiRootPath2(cwd), folder, `${candidate.slug}.md`);
|
|
9841
|
+
const relativePath = path40.relative(cwd, filePath);
|
|
9814
9842
|
const exists = await pathExists(filePath);
|
|
9815
9843
|
if (exists && !force) {
|
|
9816
9844
|
return { path: relativePath, type: candidate.type, source: candidate.source, action: "skipped" };
|
|
@@ -9838,7 +9866,7 @@ async function writeCollectedPage(cwd, candidate, force) {
|
|
|
9838
9866
|
securityReason: output.reason
|
|
9839
9867
|
};
|
|
9840
9868
|
}
|
|
9841
|
-
await mkdir14(
|
|
9869
|
+
await mkdir14(path40.dirname(filePath), { recursive: true });
|
|
9842
9870
|
await writeFile10(filePath, output.content, "utf8");
|
|
9843
9871
|
return {
|
|
9844
9872
|
path: relativePath,
|
|
@@ -9850,7 +9878,7 @@ async function writeCollectedPage(cwd, candidate, force) {
|
|
|
9850
9878
|
async function wikiPagesForFile(cwd, targetRepoPath) {
|
|
9851
9879
|
const pages = await collectPages(cwd);
|
|
9852
9880
|
const refs = await Promise.all(pages.map(async (page) => ({
|
|
9853
|
-
repoPath:
|
|
9881
|
+
repoPath: path40.relative(cwd, page.absolutePath).split(path40.sep).join("/"),
|
|
9854
9882
|
content: await readFile20(page.absolutePath, "utf8")
|
|
9855
9883
|
})));
|
|
9856
9884
|
return backlinksFor(buildBacklinkIndex(refs), targetRepoPath);
|
|
@@ -9889,7 +9917,7 @@ function renderIndexBody(pages, generatedAt) {
|
|
|
9889
9917
|
`).trimEnd();
|
|
9890
9918
|
}
|
|
9891
9919
|
async function isIndexStale(cwd, pages) {
|
|
9892
|
-
const indexPath =
|
|
9920
|
+
const indexPath = path40.join(wikiRootPath2(cwd), "index.md");
|
|
9893
9921
|
if (!await pathExists(indexPath)) {
|
|
9894
9922
|
return true;
|
|
9895
9923
|
}
|
|
@@ -9907,7 +9935,7 @@ async function walkMarkdown(root) {
|
|
|
9907
9935
|
const results = [];
|
|
9908
9936
|
const entries = await readdir8(root, { withFileTypes: true });
|
|
9909
9937
|
for (const entry of entries) {
|
|
9910
|
-
const absolutePath =
|
|
9938
|
+
const absolutePath = path40.join(root, entry.name);
|
|
9911
9939
|
if (entry.isDirectory()) {
|
|
9912
9940
|
results.push(...await walkMarkdown(absolutePath));
|
|
9913
9941
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -9964,7 +9992,7 @@ ${JSON.stringify(state, null, 2)}
|
|
|
9964
9992
|
`;
|
|
9965
9993
|
}
|
|
9966
9994
|
async function readIndexGeneratedAt(cwd) {
|
|
9967
|
-
const indexPath =
|
|
9995
|
+
const indexPath = path40.join(wikiRootPath2(cwd), "index.md");
|
|
9968
9996
|
if (!await pathExists(indexPath)) {
|
|
9969
9997
|
return null;
|
|
9970
9998
|
}
|
|
@@ -10201,7 +10229,7 @@ async function validateStructure(cwd, pages, issues) {
|
|
|
10201
10229
|
if (pattern.includes("*")) {
|
|
10202
10230
|
continue;
|
|
10203
10231
|
}
|
|
10204
|
-
if (!await pathExists(
|
|
10232
|
+
if (!await pathExists(path40.join(cwd, pattern))) {
|
|
10205
10233
|
issues.push({
|
|
10206
10234
|
page: page.relativePath,
|
|
10207
10235
|
kind: "describes",
|
|
@@ -10272,9 +10300,9 @@ var init_service2 = __esm(() => {
|
|
|
10272
10300
|
// src/gdgraph/wiki-layer.ts
|
|
10273
10301
|
import { createHash as createHash9 } from "crypto";
|
|
10274
10302
|
import { mkdir as mkdir15, stat as stat7, writeFile as writeFile11 } from "fs/promises";
|
|
10275
|
-
import
|
|
10303
|
+
import path41 from "path";
|
|
10276
10304
|
function storageDir(projectRoot) {
|
|
10277
|
-
return
|
|
10305
|
+
return path41.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
|
|
10278
10306
|
}
|
|
10279
10307
|
function wikiPageId(relativePath) {
|
|
10280
10308
|
return `wiki:${relativePath}`;
|
|
@@ -10340,11 +10368,11 @@ async function enrichBuildWithWikiLayer(input) {
|
|
|
10340
10368
|
const mtimes = new Map;
|
|
10341
10369
|
for (const record of input.fileRecords) {
|
|
10342
10370
|
try {
|
|
10343
|
-
const info = await stat7(
|
|
10371
|
+
const info = await stat7(path41.join(input.projectRoot, record.path));
|
|
10344
10372
|
mtimes.set(record.path, info.mtimeMs);
|
|
10345
10373
|
} catch {}
|
|
10346
10374
|
}
|
|
10347
|
-
await writeFile11(
|
|
10375
|
+
await writeFile11(path41.join(dir, BUILD_MANIFEST_FILE), `${JSON.stringify({ version: 1, files: computeFingerprints(input.fileRecords, mtimes) }, null, 2)}
|
|
10348
10376
|
`, "utf8");
|
|
10349
10377
|
const validModules = input.validModules !== undefined ? input.validModules : await (input.loadValidModules ?? defaultLoadValidModules)(input.projectRoot);
|
|
10350
10378
|
const wikiPages = await collectPages(input.projectRoot);
|
|
@@ -10369,8 +10397,8 @@ async function enrichBuildWithWikiLayer(input) {
|
|
|
10369
10397
|
version: page.version
|
|
10370
10398
|
}))
|
|
10371
10399
|
});
|
|
10372
|
-
await writeJsonl(
|
|
10373
|
-
await writeJsonl(
|
|
10400
|
+
await writeJsonl(path41.join(dir, WIKI_PAGES_FILE), layer.pages);
|
|
10401
|
+
await writeJsonl(path41.join(dir, DESCRIBES_FILE), layer.describes);
|
|
10374
10402
|
return layer;
|
|
10375
10403
|
}
|
|
10376
10404
|
async function defaultLoadValidModules(projectRoot) {
|
|
@@ -10393,7 +10421,7 @@ __export(exports_service, {
|
|
|
10393
10421
|
createFlowService: () => createFlowService
|
|
10394
10422
|
});
|
|
10395
10423
|
import { mkdir as mkdir5, readFile as readFile10 } from "fs/promises";
|
|
10396
|
-
import
|
|
10424
|
+
import path15 from "path";
|
|
10397
10425
|
|
|
10398
10426
|
// src/contracts/resolver.ts
|
|
10399
10427
|
import { readFileSync } from "fs";
|
|
@@ -13083,8 +13111,10 @@ var DEFAULT_TASKS = [
|
|
|
13083
13111
|
];
|
|
13084
13112
|
|
|
13085
13113
|
// src/flow/allocation.ts
|
|
13086
|
-
init_fs();
|
|
13087
13114
|
import { appendFile as appendFile2, mkdir as mkdir4, readFile as readFile9 } from "fs/promises";
|
|
13115
|
+
import path14 from "path";
|
|
13116
|
+
|
|
13117
|
+
// src/lib/clone-scope.ts
|
|
13088
13118
|
import path13 from "path";
|
|
13089
13119
|
async function gitCommonDir(cwd) {
|
|
13090
13120
|
try {
|
|
@@ -13115,27 +13145,30 @@ async function gitToplevel(cwd) {
|
|
|
13115
13145
|
return null;
|
|
13116
13146
|
}
|
|
13117
13147
|
}
|
|
13148
|
+
|
|
13149
|
+
// src/flow/allocation.ts
|
|
13150
|
+
init_fs();
|
|
13118
13151
|
function projectKey(toplevel, cwd) {
|
|
13119
13152
|
if (!toplevel) {
|
|
13120
13153
|
return "root";
|
|
13121
13154
|
}
|
|
13122
|
-
const relative =
|
|
13155
|
+
const relative = path14.relative(toplevel, cwd);
|
|
13123
13156
|
return relative === "" ? "root" : slugify(relative);
|
|
13124
13157
|
}
|
|
13125
13158
|
async function resolveAllocationScope(cwd) {
|
|
13126
13159
|
const commonDir = await gitCommonDir(cwd);
|
|
13127
13160
|
if (!commonDir) {
|
|
13128
13161
|
return {
|
|
13129
|
-
lockPath:
|
|
13162
|
+
lockPath: path14.join(flowsRoot(cwd), ".flow-init.lock"),
|
|
13130
13163
|
ledgerPath: null,
|
|
13131
13164
|
project: "root"
|
|
13132
13165
|
};
|
|
13133
13166
|
}
|
|
13134
13167
|
const key = projectKey(await gitToplevel(cwd), cwd);
|
|
13135
|
-
const dir =
|
|
13168
|
+
const dir = path14.join(commonDir, "keryx", "flow-ids");
|
|
13136
13169
|
return {
|
|
13137
|
-
lockPath:
|
|
13138
|
-
ledgerPath:
|
|
13170
|
+
lockPath: path14.join(dir, `${key}.lock`),
|
|
13171
|
+
ledgerPath: path14.join(dir, `${key}.jsonl`),
|
|
13139
13172
|
project: key
|
|
13140
13173
|
};
|
|
13141
13174
|
}
|
|
@@ -13168,7 +13201,7 @@ async function recordAllocation(scope, record) {
|
|
|
13168
13201
|
if (!scope.ledgerPath) {
|
|
13169
13202
|
return;
|
|
13170
13203
|
}
|
|
13171
|
-
await mkdir4(
|
|
13204
|
+
await mkdir4(path14.dirname(scope.ledgerPath), { recursive: true });
|
|
13172
13205
|
await appendFile2(scope.ledgerPath, `${JSON.stringify(record)}
|
|
13173
13206
|
`, "utf8");
|
|
13174
13207
|
}
|
|
@@ -13274,7 +13307,7 @@ function createFlowService(deps) {
|
|
|
13274
13307
|
return flow;
|
|
13275
13308
|
}
|
|
13276
13309
|
function flowLockPath(cwd, dir) {
|
|
13277
|
-
return
|
|
13310
|
+
return path15.join(flowsRoot(cwd), `.flow-lock-${dir}`);
|
|
13278
13311
|
}
|
|
13279
13312
|
async function mutate(cwd, id, run) {
|
|
13280
13313
|
const dir = await resolveFlowDir(cwd, id);
|
|
@@ -13316,7 +13349,7 @@ function createFlowService(deps) {
|
|
|
13316
13349
|
const date = now().slice(0, 10);
|
|
13317
13350
|
const slug = slugify(input.slug ?? title);
|
|
13318
13351
|
const dir = `${id}-${date}-${slug}`;
|
|
13319
|
-
const absolute =
|
|
13352
|
+
const absolute = path15.join(flowsRoot(input.cwd), dir);
|
|
13320
13353
|
if (await pathExists(absolute)) {
|
|
13321
13354
|
throw new Error(`Flow directory already exists: ${dir}`);
|
|
13322
13355
|
}
|
|
@@ -13343,15 +13376,15 @@ function createFlowService(deps) {
|
|
|
13343
13376
|
history: [{ at: createdAt, event: "created" }]
|
|
13344
13377
|
};
|
|
13345
13378
|
const sourceLabel = input.issue ?? "user description";
|
|
13346
|
-
await writeFileAtomic(
|
|
13347
|
-
await writeFileAtomic(
|
|
13348
|
-
await writeFileAtomic(
|
|
13349
|
-
await writeFileAtomic(
|
|
13350
|
-
await writeFileAtomic(
|
|
13351
|
-
await writeFileAtomic(
|
|
13379
|
+
await writeFileAtomic(path15.join(absolute, "description.md"), renderDescription(title, sourceLabel));
|
|
13380
|
+
await writeFileAtomic(path15.join(absolute, "context.md"), context.markdown);
|
|
13381
|
+
await writeFileAtomic(path15.join(absolute, "plan.md"), renderPlan());
|
|
13382
|
+
await writeFileAtomic(path15.join(absolute, "tasks.md"), renderTasksDoc());
|
|
13383
|
+
await writeFileAtomic(path15.join(absolute, "acceptance-criteria.md"), renderAcceptanceCriteria());
|
|
13384
|
+
await writeFileAtomic(path15.join(absolute, "journal.md"), renderJournal(createdAt));
|
|
13352
13385
|
await writeFlow(input.cwd, dir, flow);
|
|
13353
13386
|
await recordAllocation(scope, { id, dir, at: createdAt, project: scope.project });
|
|
13354
|
-
return { flow, dir:
|
|
13387
|
+
return { flow, dir: path15.relative(input.cwd, absolute), contextNotes: context.notes };
|
|
13355
13388
|
});
|
|
13356
13389
|
},
|
|
13357
13390
|
async list({ cwd }) {
|
|
@@ -13749,7 +13782,7 @@ function createFlowService(deps) {
|
|
|
13749
13782
|
issues.push({ flow: dir, kind: "schema", message: `unknown schemaVersion ${flow.schemaVersion}` });
|
|
13750
13783
|
}
|
|
13751
13784
|
try {
|
|
13752
|
-
const raw = JSON.parse(await Bun.file(
|
|
13785
|
+
const raw = JSON.parse(await Bun.file(path15.join(flowsRoot(cwd), dir, "flow.json")).text());
|
|
13753
13786
|
const validation = validateAgainstSchemaObject(flowStateSchema(), raw);
|
|
13754
13787
|
if (!validation.valid) {
|
|
13755
13788
|
issues.push({
|
|
@@ -13760,7 +13793,7 @@ function createFlowService(deps) {
|
|
|
13760
13793
|
}
|
|
13761
13794
|
} catch {}
|
|
13762
13795
|
for (const file of ["description.md", "context.md", "plan.md", "tasks.md", "acceptance-criteria.md", "journal.md"]) {
|
|
13763
|
-
if (!await pathExists(
|
|
13796
|
+
if (!await pathExists(path15.join(flowsRoot(cwd), dir, file))) {
|
|
13764
13797
|
issues.push({ flow: dir, kind: "structure", message: `missing ${file}` });
|
|
13765
13798
|
}
|
|
13766
13799
|
}
|
|
@@ -13799,7 +13832,7 @@ function createFlowService(deps) {
|
|
|
13799
13832
|
};
|
|
13800
13833
|
}
|
|
13801
13834
|
async function appendIdMap(cwd, entry) {
|
|
13802
|
-
const file =
|
|
13835
|
+
const file = path15.join(flowsRoot(cwd), "id-map.json");
|
|
13803
13836
|
let entries = [];
|
|
13804
13837
|
if (await pathExists(file)) {
|
|
13805
13838
|
const raw = await readFile10(file, "utf8");
|
|
@@ -13810,7 +13843,7 @@ async function appendIdMap(cwd, entry) {
|
|
|
13810
13843
|
}
|
|
13811
13844
|
entries = parsed;
|
|
13812
13845
|
} catch (error) {
|
|
13813
|
-
throw new Error(`Cannot read ${
|
|
13846
|
+
throw new Error(`Cannot read ${path15.relative(cwd, file)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
13814
13847
|
}
|
|
13815
13848
|
}
|
|
13816
13849
|
entries.push(entry);
|
|
@@ -13992,7 +14025,7 @@ __export(exports_service4, {
|
|
|
13992
14025
|
// src/gdgraph/build.ts
|
|
13993
14026
|
import { mkdir as mkdir16, readdir as readdir9, readFile as readFile21, writeFile as writeFile12 } from "fs/promises";
|
|
13994
14027
|
import { existsSync as existsSync2 } from "fs";
|
|
13995
|
-
import
|
|
14028
|
+
import path42 from "path";
|
|
13996
14029
|
|
|
13997
14030
|
// src/gdgraph/types.ts
|
|
13998
14031
|
var UNKNOWN_IMPORT_KIND = "unknown-static";
|
|
@@ -14057,7 +14090,7 @@ async function buildGraph(projectRoot) {
|
|
|
14057
14090
|
const assetNodes = new Map;
|
|
14058
14091
|
const fileRecords = [];
|
|
14059
14092
|
for (const file of files) {
|
|
14060
|
-
const absolutePath =
|
|
14093
|
+
const absolutePath = path42.join(projectRoot, file);
|
|
14061
14094
|
const content = await readFile21(absolutePath, "utf8");
|
|
14062
14095
|
fileRecords.push({ path: file, content });
|
|
14063
14096
|
const language = getLanguage(file);
|
|
@@ -14110,24 +14143,24 @@ async function collectSourceFiles(projectRoot) {
|
|
|
14110
14143
|
const result = [];
|
|
14111
14144
|
const skippedDirectories = [];
|
|
14112
14145
|
async function walk(relativeDir) {
|
|
14113
|
-
const absoluteDir =
|
|
14146
|
+
const absoluteDir = path42.join(projectRoot, relativeDir);
|
|
14114
14147
|
const entries = await readdir9(absoluteDir, { withFileTypes: true });
|
|
14115
14148
|
for (const entry of entries) {
|
|
14116
14149
|
if (entry.isDirectory()) {
|
|
14117
14150
|
if (IGNORE_DIRS.has(entry.name)) {
|
|
14118
|
-
skippedDirectories.push(normalizePath2(
|
|
14151
|
+
skippedDirectories.push(normalizePath2(path42.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
|
|
14119
14152
|
continue;
|
|
14120
14153
|
}
|
|
14121
|
-
await walk(normalizePath2(
|
|
14154
|
+
await walk(normalizePath2(path42.posix.join(relativeDir, entry.name)));
|
|
14122
14155
|
continue;
|
|
14123
14156
|
}
|
|
14124
14157
|
if (!entry.isFile()) {
|
|
14125
14158
|
continue;
|
|
14126
14159
|
}
|
|
14127
|
-
if (!SOURCE_EXTENSIONS.includes(
|
|
14160
|
+
if (!SOURCE_EXTENSIONS.includes(path42.extname(entry.name))) {
|
|
14128
14161
|
continue;
|
|
14129
14162
|
}
|
|
14130
|
-
result.push(normalizePath2(
|
|
14163
|
+
result.push(normalizePath2(path42.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
|
|
14131
14164
|
}
|
|
14132
14165
|
}
|
|
14133
14166
|
await walk(".");
|
|
@@ -14209,8 +14242,8 @@ function resolveImport(projectRoot, fromFile, specifier, fileSet, resolver) {
|
|
|
14209
14242
|
}
|
|
14210
14243
|
function resolveAssetImport(projectRoot, fromFile, specifier, resolver) {
|
|
14211
14244
|
for (const candidate of importCandidateBases(projectRoot, fromFile, specifier, resolver)) {
|
|
14212
|
-
const extension =
|
|
14213
|
-
if (ASSET_EXTENSIONS.includes(extension) && existsSync2(
|
|
14245
|
+
const extension = path42.posix.extname(candidate);
|
|
14246
|
+
if (ASSET_EXTENSIONS.includes(extension) && existsSync2(path42.join(projectRoot, candidate))) {
|
|
14214
14247
|
return candidate;
|
|
14215
14248
|
}
|
|
14216
14249
|
}
|
|
@@ -14219,17 +14252,17 @@ function resolveAssetImport(projectRoot, fromFile, specifier, resolver) {
|
|
|
14219
14252
|
function importCandidateBases(projectRoot, fromFile, specifier, resolver) {
|
|
14220
14253
|
const normalizedSpecifier = stripImportSuffix(specifier);
|
|
14221
14254
|
if (normalizedSpecifier.startsWith(".") && getLanguage(fromFile) !== "python") {
|
|
14222
|
-
const fromDir =
|
|
14223
|
-
return [normalizePath2(
|
|
14255
|
+
const fromDir = path42.posix.dirname(fromFile);
|
|
14256
|
+
return [normalizePath2(path42.posix.normalize(path42.posix.join(fromDir, normalizedSpecifier)))];
|
|
14224
14257
|
}
|
|
14225
|
-
return resolver.candidateBases(normalizedSpecifier, fromFile).map((candidate) => normalizePath2(
|
|
14258
|
+
return resolver.candidateBases(normalizedSpecifier, fromFile).map((candidate) => normalizePath2(path42.relative(projectRoot, path42.join(projectRoot, candidate))));
|
|
14226
14259
|
}
|
|
14227
14260
|
function resolveSourceCandidate(base, fileSet) {
|
|
14228
14261
|
const candidates = [
|
|
14229
14262
|
base,
|
|
14230
14263
|
...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => `${base}${extension}`),
|
|
14231
|
-
...SOURCE_RESOLUTION_EXTENSIONS.map((extension) =>
|
|
14232
|
-
|
|
14264
|
+
...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => path42.posix.join(base, `index${extension}`)),
|
|
14265
|
+
path42.posix.join(base, "__init__.py")
|
|
14233
14266
|
];
|
|
14234
14267
|
return candidates.find((candidate) => fileSet.has(candidate)) ?? null;
|
|
14235
14268
|
}
|
|
@@ -14259,7 +14292,7 @@ async function loadJavaResolver(projectRoot) {
|
|
|
14259
14292
|
return createJavaResolver(roots);
|
|
14260
14293
|
}
|
|
14261
14294
|
async function discoverJavaSourceRoots(projectRoot) {
|
|
14262
|
-
const pomPath =
|
|
14295
|
+
const pomPath = path42.join(projectRoot, "pom.xml");
|
|
14263
14296
|
if (existsSync2(pomPath)) {
|
|
14264
14297
|
try {
|
|
14265
14298
|
const roots = parseMavenSourceRoots(await readFile21(pomPath, "utf8"));
|
|
@@ -14269,7 +14302,7 @@ async function discoverJavaSourceRoots(projectRoot) {
|
|
|
14269
14302
|
} catch {}
|
|
14270
14303
|
}
|
|
14271
14304
|
for (const gradleName of ["build.gradle", "build.gradle.kts"]) {
|
|
14272
|
-
const gradlePath =
|
|
14305
|
+
const gradlePath = path42.join(projectRoot, gradleName);
|
|
14273
14306
|
if (existsSync2(gradlePath)) {
|
|
14274
14307
|
try {
|
|
14275
14308
|
const roots = parseGradleSourceRoots(await readFile21(gradlePath, "utf8"));
|
|
@@ -14291,12 +14324,12 @@ function createJavaResolver(sourceRoots) {
|
|
|
14291
14324
|
return [];
|
|
14292
14325
|
}
|
|
14293
14326
|
const relative = specifier.split(".").join("/");
|
|
14294
|
-
return sourceRoots.map((root) => normalizePath2(
|
|
14327
|
+
return sourceRoots.map((root) => normalizePath2(path42.posix.join(root, relative)));
|
|
14295
14328
|
}
|
|
14296
14329
|
};
|
|
14297
14330
|
}
|
|
14298
14331
|
function loadPythonResolver(projectRoot) {
|
|
14299
|
-
const hasSrc = existsSync2(
|
|
14332
|
+
const hasSrc = existsSync2(path42.join(projectRoot, "src"));
|
|
14300
14333
|
return createPythonResolver(hasSrc);
|
|
14301
14334
|
}
|
|
14302
14335
|
function createPythonResolver(hasSrc) {
|
|
@@ -14309,16 +14342,16 @@ function createPythonResolver(hasSrc) {
|
|
|
14309
14342
|
if (specifier.startsWith(".")) {
|
|
14310
14343
|
const dots = /^\.+/.exec(specifier)?.[0].length ?? 0;
|
|
14311
14344
|
const rest = specifier.slice(dots);
|
|
14312
|
-
let baseDir =
|
|
14345
|
+
let baseDir = path42.posix.dirname(fromFile);
|
|
14313
14346
|
for (let level = 1;level < dots; level += 1) {
|
|
14314
|
-
baseDir =
|
|
14347
|
+
baseDir = path42.posix.dirname(baseDir);
|
|
14315
14348
|
}
|
|
14316
14349
|
const suffix = rest ? rest.split(".").join("/") : "";
|
|
14317
|
-
const base = suffix ?
|
|
14350
|
+
const base = suffix ? path42.posix.join(baseDir, suffix) : baseDir;
|
|
14318
14351
|
return [normalizePath2(base)];
|
|
14319
14352
|
}
|
|
14320
14353
|
const relative = specifier.split(".").join("/");
|
|
14321
|
-
return roots.map((root) => normalizePath2(root ?
|
|
14354
|
+
return roots.map((root) => normalizePath2(root ? path42.posix.join(root, relative) : relative));
|
|
14322
14355
|
}
|
|
14323
14356
|
};
|
|
14324
14357
|
}
|
|
@@ -14327,8 +14360,8 @@ function parseMavenSourceRoots(pomXml) {
|
|
|
14327
14360
|
for (const match of pomXml.matchAll(/<module>\s*([^<]+?)\s*<\/module>/g)) {
|
|
14328
14361
|
const moduleDir = match[1]?.trim();
|
|
14329
14362
|
if (moduleDir && !moduleDir.includes("${")) {
|
|
14330
|
-
roots.add(normalizePath2(
|
|
14331
|
-
roots.add(normalizePath2(
|
|
14363
|
+
roots.add(normalizePath2(path42.posix.join(moduleDir, "src/main/java")));
|
|
14364
|
+
roots.add(normalizePath2(path42.posix.join(moduleDir, "src/test/java")));
|
|
14332
14365
|
}
|
|
14333
14366
|
}
|
|
14334
14367
|
for (const tag of ["sourceDirectory", "testSourceDirectory"]) {
|
|
@@ -14360,7 +14393,7 @@ function parseGradleSourceRoots(buildGradle) {
|
|
|
14360
14393
|
}
|
|
14361
14394
|
async function loadTsconfigResolver(projectRoot) {
|
|
14362
14395
|
const empty = createTsconfigResolver(null, []);
|
|
14363
|
-
const tsconfigPath =
|
|
14396
|
+
const tsconfigPath = path42.join(projectRoot, "tsconfig.json");
|
|
14364
14397
|
if (!existsSync2(tsconfigPath)) {
|
|
14365
14398
|
return empty;
|
|
14366
14399
|
}
|
|
@@ -14368,7 +14401,7 @@ async function loadTsconfigResolver(projectRoot) {
|
|
|
14368
14401
|
const raw = await readFile21(tsconfigPath, "utf8");
|
|
14369
14402
|
const parsed = JSON.parse(stripJsonComments(raw));
|
|
14370
14403
|
const options = parsed.compilerOptions ?? {};
|
|
14371
|
-
const baseUrl = typeof options.baseUrl === "string" ? normalizePath2(
|
|
14404
|
+
const baseUrl = typeof options.baseUrl === "string" ? normalizePath2(path42.posix.normalize(options.baseUrl)).replace(/^\.\//, "") : null;
|
|
14372
14405
|
const paths = isRecord2(options.paths) ? Object.entries(options.paths).filter((entry) => Array.isArray(entry[1])).map(([pattern, targets]) => ({
|
|
14373
14406
|
pattern,
|
|
14374
14407
|
targets: targets.filter((target) => typeof target === "string")
|
|
@@ -14397,7 +14430,7 @@ function createTsconfigResolver(baseUrl, mappings) {
|
|
|
14397
14430
|
}
|
|
14398
14431
|
}
|
|
14399
14432
|
if (baseUrl !== null) {
|
|
14400
|
-
candidates.push(normalizePath2(
|
|
14433
|
+
candidates.push(normalizePath2(path42.posix.join(baseUrl, normalizedSpecifier)));
|
|
14401
14434
|
}
|
|
14402
14435
|
return [...new Set(candidates.map((candidate) => candidate.replace(/^\.\//, "")))];
|
|
14403
14436
|
}
|
|
@@ -14417,7 +14450,7 @@ function matchPathPattern(pattern, specifier) {
|
|
|
14417
14450
|
}
|
|
14418
14451
|
function applyPathTarget(baseUrl, target, wildcard) {
|
|
14419
14452
|
const replaced = target.includes("*") ? target.replace("*", wildcard) : target;
|
|
14420
|
-
return normalizePath2(
|
|
14453
|
+
return normalizePath2(path42.posix.normalize(path42.posix.join(baseUrl ?? "", replaced)));
|
|
14421
14454
|
}
|
|
14422
14455
|
function stripJsonComments(source) {
|
|
14423
14456
|
let out = "";
|
|
@@ -14470,21 +14503,21 @@ function isRecord2(value) {
|
|
|
14470
14503
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14471
14504
|
}
|
|
14472
14505
|
async function writeGraph(projectRoot, graph) {
|
|
14473
|
-
const storageDir =
|
|
14474
|
-
const artifactsDir =
|
|
14506
|
+
const storageDir = path42.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
|
|
14507
|
+
const artifactsDir = path42.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
|
|
14475
14508
|
await mkdir16(storageDir, { recursive: true });
|
|
14476
14509
|
await mkdir16(artifactsDir, { recursive: true });
|
|
14477
|
-
await writeFile12(
|
|
14510
|
+
await writeFile12(path42.join(storageDir, "nodes.jsonl"), graph.nodes.map((node) => JSON.stringify(node)).join(`
|
|
14478
14511
|
`) + `
|
|
14479
14512
|
`, "utf8");
|
|
14480
|
-
await writeFile12(
|
|
14513
|
+
await writeFile12(path42.join(storageDir, "edges.jsonl"), graph.edges.map((edge) => JSON.stringify(edge)).join(`
|
|
14481
14514
|
`) + `
|
|
14482
14515
|
`, "utf8");
|
|
14483
|
-
await writeFile12(
|
|
14516
|
+
await writeFile12(path42.join(artifactsDir, "module-map.json"), JSON.stringify(buildModuleMap(graph), null, 2) + `
|
|
14484
14517
|
`, "utf8");
|
|
14485
14518
|
}
|
|
14486
14519
|
async function writeSummary(projectRoot, graph, collection) {
|
|
14487
|
-
const artifactsDir =
|
|
14520
|
+
const artifactsDir = path42.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
|
|
14488
14521
|
await mkdir16(artifactsDir, { recursive: true });
|
|
14489
14522
|
const unresolved = graph.edges.filter((edge) => edge.kind === "unresolved");
|
|
14490
14523
|
const imports = graph.edges.filter((edge) => edge.kind === "imports");
|
|
@@ -14499,7 +14532,7 @@ async function writeSummary(projectRoot, graph, collection) {
|
|
|
14499
14532
|
`);
|
|
14500
14533
|
const skippedList = collection.skippedDirectories.length > 0 ? collection.skippedDirectories.slice(0, 30).map((dir) => `- \`${dir}\``).join(`
|
|
14501
14534
|
`) : "- none";
|
|
14502
|
-
const summaryPath =
|
|
14535
|
+
const summaryPath = path42.join(artifactsDir, "summary.md");
|
|
14503
14536
|
const content = `# gdgraph Summary
|
|
14504
14537
|
|
|
14505
14538
|
## Stats
|
|
@@ -14580,7 +14613,7 @@ function groupBy(items, getKey) {
|
|
|
14580
14613
|
}
|
|
14581
14614
|
function unresolvedType(specifier) {
|
|
14582
14615
|
const stripped = stripImportSuffix(specifier);
|
|
14583
|
-
const extension =
|
|
14616
|
+
const extension = path42.posix.extname(stripped);
|
|
14584
14617
|
if (extension) {
|
|
14585
14618
|
return extension;
|
|
14586
14619
|
}
|
|
@@ -14590,13 +14623,13 @@ function unresolvedType(specifier) {
|
|
|
14590
14623
|
return "package";
|
|
14591
14624
|
}
|
|
14592
14625
|
function normalizePath2(value) {
|
|
14593
|
-
return value.split(
|
|
14626
|
+
return value.split(path42.sep).join("/");
|
|
14594
14627
|
}
|
|
14595
14628
|
|
|
14596
14629
|
// src/gdgraph/target.ts
|
|
14597
|
-
import
|
|
14630
|
+
import path43 from "path";
|
|
14598
14631
|
function normalizeTarget(target) {
|
|
14599
|
-
return target.replace(/^\.\//, "").split(
|
|
14632
|
+
return target.replace(/^\.\//, "").split(path43.sep).join("/");
|
|
14600
14633
|
}
|
|
14601
14634
|
function resolveGraphTarget(graph, target) {
|
|
14602
14635
|
const normalized = normalizeTarget(target);
|
|
@@ -14689,15 +14722,15 @@ init_config2();
|
|
|
14689
14722
|
|
|
14690
14723
|
// src/gdgraph/query.ts
|
|
14691
14724
|
import { readFile as readFile22 } from "fs/promises";
|
|
14692
|
-
import
|
|
14725
|
+
import path44 from "path";
|
|
14693
14726
|
async function loadGraph(projectRoot) {
|
|
14694
|
-
const storageDir =
|
|
14695
|
-
const nodes = await readJsonl(
|
|
14696
|
-
const edges = await readJsonl(
|
|
14697
|
-
const symbols = await readJsonl(
|
|
14698
|
-
const calls = await readJsonl(
|
|
14699
|
-
const wikiPages = await readJsonl(
|
|
14700
|
-
const describes = await readJsonl(
|
|
14727
|
+
const storageDir = path44.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
|
|
14728
|
+
const nodes = await readJsonl(path44.join(storageDir, "nodes.jsonl"));
|
|
14729
|
+
const edges = await readJsonl(path44.join(storageDir, "edges.jsonl"));
|
|
14730
|
+
const symbols = await readJsonl(path44.join(storageDir, "symbols.jsonl"));
|
|
14731
|
+
const calls = await readJsonl(path44.join(storageDir, "calls.jsonl"));
|
|
14732
|
+
const wikiPages = await readJsonl(path44.join(storageDir, "wiki-pages.jsonl"));
|
|
14733
|
+
const describes = await readJsonl(path44.join(storageDir, "describes.jsonl"));
|
|
14701
14734
|
const graph = { nodes, edges };
|
|
14702
14735
|
if (symbols.length > 0) {
|
|
14703
14736
|
graph.symbols = symbols;
|
|
@@ -14785,7 +14818,7 @@ function canonicalCycle(cycle) {
|
|
|
14785
14818
|
|
|
14786
14819
|
// src/gdgraph/repomap.ts
|
|
14787
14820
|
import { mkdir as mkdir17, writeFile as writeFile13 } from "fs/promises";
|
|
14788
|
-
import
|
|
14821
|
+
import path45 from "path";
|
|
14789
14822
|
|
|
14790
14823
|
// src/gdgraph/pagerank.ts
|
|
14791
14824
|
function personalizedPageRank(nodes, edges, options) {
|
|
@@ -14896,7 +14929,7 @@ function overflowContent(required, missing, budget) {
|
|
|
14896
14929
|
`);
|
|
14897
14930
|
}
|
|
14898
14931
|
function repomapArtifactPath(cwd) {
|
|
14899
|
-
return
|
|
14932
|
+
return path45.join(cwd, ".metaproject", "data", "gdgraph", "artifacts", "repomap.md");
|
|
14900
14933
|
}
|
|
14901
14934
|
function buildRankEdges(graph, config) {
|
|
14902
14935
|
const edges = [];
|
|
@@ -15041,7 +15074,7 @@ function computeRepomap(graph, config, options = {}) {
|
|
|
15041
15074
|
async function writeRepomap(cwd, graph, config, options = {}) {
|
|
15042
15075
|
const result = computeRepomap(graph, config, options);
|
|
15043
15076
|
const artifactPath = repomapArtifactPath(cwd);
|
|
15044
|
-
await mkdir17(
|
|
15077
|
+
await mkdir17(path45.dirname(artifactPath), { recursive: true });
|
|
15045
15078
|
await writeFile13(artifactPath, result.content, "utf8");
|
|
15046
15079
|
return { ...result, path: artifactPath };
|
|
15047
15080
|
}
|
|
@@ -15093,12 +15126,12 @@ __export(exports_service6, {
|
|
|
15093
15126
|
createCodeHealthService: () => createCodeHealthService,
|
|
15094
15127
|
gateExitCode: () => gateExitCode
|
|
15095
15128
|
});
|
|
15096
|
-
import
|
|
15129
|
+
import path65 from "path";
|
|
15097
15130
|
|
|
15098
15131
|
// src/health/config.ts
|
|
15099
15132
|
init_fs();
|
|
15100
15133
|
init_json();
|
|
15101
|
-
import
|
|
15134
|
+
import path46 from "path";
|
|
15102
15135
|
var DEFAULT_HEALTH_CONFIG = {
|
|
15103
15136
|
schemaVersion: 2,
|
|
15104
15137
|
ignore: {
|
|
@@ -15154,7 +15187,7 @@ var DEFAULT_HEALTH_CONFIG = {
|
|
|
15154
15187
|
}
|
|
15155
15188
|
};
|
|
15156
15189
|
function configPath2(cwd) {
|
|
15157
|
-
return
|
|
15190
|
+
return path46.join(cwd, ".metaproject", "health.config.json");
|
|
15158
15191
|
}
|
|
15159
15192
|
var STRICTEST_GATE = {
|
|
15160
15193
|
failOnPriorities: ["P0", "P1", "P2", "P3"],
|
|
@@ -15205,7 +15238,7 @@ async function loadHealthConfig(cwd) {
|
|
|
15205
15238
|
// src/health/run.ts
|
|
15206
15239
|
init_fs();
|
|
15207
15240
|
import { mkdir as mkdir22, writeFile as writeFile18 } from "fs/promises";
|
|
15208
|
-
import
|
|
15241
|
+
import path64 from "path";
|
|
15209
15242
|
|
|
15210
15243
|
// src/metrics/provenance.ts
|
|
15211
15244
|
async function collectGitProvenance(cwd) {
|
|
@@ -15304,12 +15337,12 @@ function computeGate2(input) {
|
|
|
15304
15337
|
}
|
|
15305
15338
|
|
|
15306
15339
|
// src/health/scopes.ts
|
|
15307
|
-
import
|
|
15340
|
+
import path49 from "path";
|
|
15308
15341
|
|
|
15309
15342
|
// src/health/util.ts
|
|
15310
15343
|
init_fs();
|
|
15311
15344
|
import { mkdir as mkdir18, readFile as readFile23, readdir as readdir10, writeFile as writeFile14 } from "fs/promises";
|
|
15312
|
-
import
|
|
15345
|
+
import path47 from "path";
|
|
15313
15346
|
var IGNORED_DIRS = new Set([
|
|
15314
15347
|
"node_modules",
|
|
15315
15348
|
".git",
|
|
@@ -15353,14 +15386,14 @@ async function toolVersion(command, cwd) {
|
|
|
15353
15386
|
}
|
|
15354
15387
|
}
|
|
15355
15388
|
function dataRoot(cwd) {
|
|
15356
|
-
return
|
|
15389
|
+
return path47.join(cwd, ".metaproject", "data", "health");
|
|
15357
15390
|
}
|
|
15358
15391
|
async function writeRaw(cwd, source, content, stamp) {
|
|
15359
|
-
const dir =
|
|
15392
|
+
const dir = path47.join(dataRoot(cwd), "raw", source);
|
|
15360
15393
|
await mkdir18(dir, { recursive: true });
|
|
15361
|
-
const file =
|
|
15394
|
+
const file = path47.join(dir, `${stamp}.log`);
|
|
15362
15395
|
await writeFile14(file, content, "utf8");
|
|
15363
|
-
return
|
|
15396
|
+
return path47.relative(cwd, file);
|
|
15364
15397
|
}
|
|
15365
15398
|
async function listSourceFiles(cwd, ignorePaths = []) {
|
|
15366
15399
|
const { files } = await listSourceFilesWithReasons(cwd, ignorePaths);
|
|
@@ -15380,7 +15413,7 @@ async function walk2(root, dir, out, incompleteReasons) {
|
|
|
15380
15413
|
try {
|
|
15381
15414
|
entries = await readdir10(dir, { withFileTypes: true });
|
|
15382
15415
|
} catch (error) {
|
|
15383
|
-
incompleteReasons.push(`${
|
|
15416
|
+
incompleteReasons.push(`${path47.relative(root, dir) || "."}: ${error instanceof Error ? error.message : String(error)}`);
|
|
15384
15417
|
return;
|
|
15385
15418
|
}
|
|
15386
15419
|
for (const entry of entries) {
|
|
@@ -15388,14 +15421,14 @@ async function walk2(root, dir, out, incompleteReasons) {
|
|
|
15388
15421
|
if (entry.isDirectory() && !IGNORED_DIRS.has(entry.name)) {}
|
|
15389
15422
|
continue;
|
|
15390
15423
|
}
|
|
15391
|
-
const abs =
|
|
15424
|
+
const abs = path47.join(dir, entry.name);
|
|
15392
15425
|
if (entry.isDirectory()) {
|
|
15393
15426
|
if (IGNORED_DIRS.has(entry.name)) {
|
|
15394
15427
|
continue;
|
|
15395
15428
|
}
|
|
15396
15429
|
await walk2(root, abs, out, incompleteReasons);
|
|
15397
|
-
} else if (entry.isFile() && SOURCE_EXT.has(
|
|
15398
|
-
out.push(
|
|
15430
|
+
} else if (entry.isFile() && SOURCE_EXT.has(path47.extname(entry.name))) {
|
|
15431
|
+
out.push(path47.relative(root, abs));
|
|
15399
15432
|
}
|
|
15400
15433
|
}
|
|
15401
15434
|
}
|
|
@@ -15410,7 +15443,7 @@ function moduleOfFile(file) {
|
|
|
15410
15443
|
return null;
|
|
15411
15444
|
}
|
|
15412
15445
|
function isSourceFile(file) {
|
|
15413
|
-
return SOURCE_EXT.has(
|
|
15446
|
+
return SOURCE_EXT.has(path47.extname(file));
|
|
15414
15447
|
}
|
|
15415
15448
|
function matchesAnyPattern(file, patterns) {
|
|
15416
15449
|
const normalized = file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
@@ -15510,7 +15543,7 @@ function rankHotspots(files, churn, sourceAnalysis) {
|
|
|
15510
15543
|
// src/health/source-analysis.ts
|
|
15511
15544
|
init_fs();
|
|
15512
15545
|
import { readFile as readFile24 } from "fs/promises";
|
|
15513
|
-
import
|
|
15546
|
+
import path48 from "path";
|
|
15514
15547
|
|
|
15515
15548
|
// src/health/metrics/complexity.ts
|
|
15516
15549
|
var CONTROL_KEYWORDS = new Set([
|
|
@@ -15744,7 +15777,7 @@ async function analyzeSourceFiles(cwd, sourceFiles) {
|
|
|
15744
15777
|
return new Map(entries.filter((entry) => entry !== null));
|
|
15745
15778
|
}
|
|
15746
15779
|
async function analyzeSourceFile(cwd, file) {
|
|
15747
|
-
const abs =
|
|
15780
|
+
const abs = path48.join(cwd, file);
|
|
15748
15781
|
if (!await pathExists(abs)) {
|
|
15749
15782
|
return null;
|
|
15750
15783
|
}
|
|
@@ -15817,14 +15850,14 @@ async function computeMetrics(input) {
|
|
|
15817
15850
|
}
|
|
15818
15851
|
const components = new Map;
|
|
15819
15852
|
for (const file of sourceFiles) {
|
|
15820
|
-
const dir =
|
|
15853
|
+
const dir = path49.posix.dirname(file);
|
|
15821
15854
|
if (dir === "." || dir === moduleOfFile(file)) {
|
|
15822
15855
|
continue;
|
|
15823
15856
|
}
|
|
15824
15857
|
components.set(dir, [...components.get(dir) ?? [], file]);
|
|
15825
15858
|
}
|
|
15826
15859
|
for (const [name, files] of [...components.entries()].sort()) {
|
|
15827
|
-
const compFindings = findings.filter((f) => f.file &&
|
|
15860
|
+
const compFindings = findings.filter((f) => f.file && path49.posix.dirname(f.file) === name);
|
|
15828
15861
|
scopes.push(build("component", `component:${name}`, name, files, compFindings, averageCoverage(files, coverage)));
|
|
15829
15862
|
}
|
|
15830
15863
|
const findingFiles = findings.map((f) => f.file).filter((f) => Boolean(f));
|
|
@@ -15869,9 +15902,9 @@ function tally2(values) {
|
|
|
15869
15902
|
// src/health/baseline.ts
|
|
15870
15903
|
init_fs();
|
|
15871
15904
|
import { mkdir as mkdir19, readFile as readFile25, writeFile as writeFile15 } from "fs/promises";
|
|
15872
|
-
import
|
|
15905
|
+
import path50 from "path";
|
|
15873
15906
|
function baselinePath(cwd) {
|
|
15874
|
-
return
|
|
15907
|
+
return path50.join(cwd, ".metaproject", "health", "baselines", "scores.json");
|
|
15875
15908
|
}
|
|
15876
15909
|
async function loadBaseline(cwd) {
|
|
15877
15910
|
const file = baselinePath(cwd);
|
|
@@ -15903,7 +15936,7 @@ async function writeBaseline(cwd, metrics, generatedAt, selector) {
|
|
|
15903
15936
|
scopes[key] = value;
|
|
15904
15937
|
}
|
|
15905
15938
|
const file = baselinePath(cwd);
|
|
15906
|
-
await mkdir19(
|
|
15939
|
+
await mkdir19(path50.dirname(file), { recursive: true });
|
|
15907
15940
|
await writeFile15(file, `${JSON.stringify({ generatedAt, scopes }, null, 2)}
|
|
15908
15941
|
`, "utf8");
|
|
15909
15942
|
return updated;
|
|
@@ -15957,10 +15990,10 @@ async function getChurn(cwd, windowDays) {
|
|
|
15957
15990
|
|
|
15958
15991
|
// src/health/metrics/wiki-freshness.ts
|
|
15959
15992
|
import { readFile as readFile26, stat as stat8 } from "fs/promises";
|
|
15960
|
-
import
|
|
15993
|
+
import path51 from "path";
|
|
15961
15994
|
var DEFAULT_STALE_EVIDENCE_DAYS = 7;
|
|
15962
15995
|
function freshnessReportPath(cwd) {
|
|
15963
|
-
return
|
|
15996
|
+
return path51.join(cwd, ".metaproject", "data", "wiki", "freshness", "latest.json");
|
|
15964
15997
|
}
|
|
15965
15998
|
async function readWikiFreshnessMetric(cwd, options = {}) {
|
|
15966
15999
|
const file = freshnessReportPath(cwd);
|
|
@@ -15981,7 +16014,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
|
|
|
15981
16014
|
} catch {
|
|
15982
16015
|
return {
|
|
15983
16016
|
status: "unreadable-report",
|
|
15984
|
-
reason: `${
|
|
16017
|
+
reason: `${path51.relative(cwd, file)} is not valid JSON; re-run \`keryx wiki freshness\`.`
|
|
15985
16018
|
};
|
|
15986
16019
|
}
|
|
15987
16020
|
const report = parsed;
|
|
@@ -15991,7 +16024,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
|
|
|
15991
16024
|
if (pagesTotal === null || pagesFresh === null) {
|
|
15992
16025
|
return {
|
|
15993
16026
|
status: "unreadable-report",
|
|
15994
|
-
reason: `${
|
|
16027
|
+
reason: `${path51.relative(cwd, file)} is missing its totals; re-run \`keryx wiki freshness\`.`
|
|
15995
16028
|
};
|
|
15996
16029
|
}
|
|
15997
16030
|
const pagesUndecidable = numberOr2(totals.pagesUndecidable) ?? 0;
|
|
@@ -16045,12 +16078,12 @@ function renderWikiFreshnessLine(metric) {
|
|
|
16045
16078
|
}
|
|
16046
16079
|
|
|
16047
16080
|
// src/health/sources/helpers.ts
|
|
16048
|
-
import
|
|
16081
|
+
import path52 from "path";
|
|
16049
16082
|
import { existsSync as existsSync3 } from "fs";
|
|
16050
16083
|
class NoImportError extends Error {
|
|
16051
16084
|
}
|
|
16052
16085
|
function resolveBin(cwd, name) {
|
|
16053
|
-
const local =
|
|
16086
|
+
const local = path52.join(cwd, "node_modules", ".bin", name);
|
|
16054
16087
|
if (existsSync3(local)) {
|
|
16055
16088
|
return local;
|
|
16056
16089
|
}
|
|
@@ -16131,13 +16164,13 @@ async function getComplexityFindings(cwd, sourceFiles, config, sourceAnalysis) {
|
|
|
16131
16164
|
|
|
16132
16165
|
// src/health/metrics/coverage.ts
|
|
16133
16166
|
import { existsSync as existsSync4 } from "fs";
|
|
16134
|
-
import
|
|
16167
|
+
import path53 from "path";
|
|
16135
16168
|
var SUMMARY_PATHS = [
|
|
16136
16169
|
"coverage/coverage-summary.json",
|
|
16137
16170
|
"coverage/coverage-final.json"
|
|
16138
16171
|
];
|
|
16139
16172
|
async function getCoverage(cwd) {
|
|
16140
|
-
const summary = SUMMARY_PATHS.map((rel) =>
|
|
16173
|
+
const summary = SUMMARY_PATHS.map((rel) => path53.join(cwd, rel)).find((abs) => existsSync4(abs));
|
|
16141
16174
|
if (!summary) {
|
|
16142
16175
|
return { status: "missing", total: null, byFile: new Map };
|
|
16143
16176
|
}
|
|
@@ -16158,7 +16191,7 @@ async function getCoverage(cwd) {
|
|
|
16158
16191
|
total = pct;
|
|
16159
16192
|
continue;
|
|
16160
16193
|
}
|
|
16161
|
-
const relative =
|
|
16194
|
+
const relative = path53.isAbsolute(key) ? path53.relative(cwd, key) : key;
|
|
16162
16195
|
byFile.set(relative.replace(/\\/g, "/"), pct);
|
|
16163
16196
|
}
|
|
16164
16197
|
return { status: "available", total, byFile };
|
|
@@ -16291,10 +16324,10 @@ function renderWikiFreshness(metric) {
|
|
|
16291
16324
|
// src/health/skills.ts
|
|
16292
16325
|
init_fs();
|
|
16293
16326
|
import { readFile as readFile27 } from "fs/promises";
|
|
16294
|
-
import
|
|
16327
|
+
import path54 from "path";
|
|
16295
16328
|
var EMPTY = { skills: [], skillForFile: () => null };
|
|
16296
16329
|
async function loadSkillOwnership(cwd) {
|
|
16297
|
-
const manifestPath =
|
|
16330
|
+
const manifestPath = path54.join(cwd, ".metaproject", "metaproject.json");
|
|
16298
16331
|
if (!await pathExists(manifestPath)) {
|
|
16299
16332
|
return EMPTY;
|
|
16300
16333
|
}
|
|
@@ -16332,7 +16365,7 @@ function normalize(value) {
|
|
|
16332
16365
|
|
|
16333
16366
|
// src/health/sources/eslint.ts
|
|
16334
16367
|
import { existsSync as existsSync5 } from "fs";
|
|
16335
|
-
import
|
|
16368
|
+
import path55 from "path";
|
|
16336
16369
|
var CONFIG_FILES = [
|
|
16337
16370
|
".eslintrc",
|
|
16338
16371
|
".eslintrc.js",
|
|
@@ -16346,7 +16379,7 @@ var CONFIG_FILES = [
|
|
|
16346
16379
|
"eslint.config.ts"
|
|
16347
16380
|
];
|
|
16348
16381
|
function hasConfig(cwd) {
|
|
16349
|
-
return CONFIG_FILES.some((file) => existsSync5(
|
|
16382
|
+
return CONFIG_FILES.some((file) => existsSync5(path55.join(cwd, file)));
|
|
16350
16383
|
}
|
|
16351
16384
|
var eslintAdapter = {
|
|
16352
16385
|
id: "eslint",
|
|
@@ -16371,7 +16404,7 @@ var eslintAdapter = {
|
|
|
16371
16404
|
};
|
|
16372
16405
|
},
|
|
16373
16406
|
async import(ctx) {
|
|
16374
|
-
const report =
|
|
16407
|
+
const report = path55.join(ctx.cwd, "eslint-report.json");
|
|
16375
16408
|
if (!existsSync5(report)) {
|
|
16376
16409
|
throw new NoImportError("no eslint-report.json");
|
|
16377
16410
|
}
|
|
@@ -16398,7 +16431,7 @@ var eslintAdapter = {
|
|
|
16398
16431
|
}
|
|
16399
16432
|
const findings = [];
|
|
16400
16433
|
for (const file of data) {
|
|
16401
|
-
const relative =
|
|
16434
|
+
const relative = path55.isAbsolute(file.filePath) ? path55.relative(ctx.cwd, file.filePath) : file.filePath;
|
|
16402
16435
|
for (const message of file.messages ?? []) {
|
|
16403
16436
|
const isError = message.severity === 2;
|
|
16404
16437
|
findings.push(makeFinding({
|
|
@@ -16430,9 +16463,9 @@ var eslintAdapter = {
|
|
|
16430
16463
|
|
|
16431
16464
|
// src/health/sources/typescript.ts
|
|
16432
16465
|
import { existsSync as existsSync6 } from "fs";
|
|
16433
|
-
import
|
|
16466
|
+
import path56 from "path";
|
|
16434
16467
|
function hasTsconfig(cwd) {
|
|
16435
|
-
return existsSync6(
|
|
16468
|
+
return existsSync6(path56.join(cwd, "tsconfig.json"));
|
|
16436
16469
|
}
|
|
16437
16470
|
var typescriptAdapter = {
|
|
16438
16471
|
id: "typescript",
|
|
@@ -16506,7 +16539,7 @@ __export(exports_service5, {
|
|
|
16506
16539
|
});
|
|
16507
16540
|
import { existsSync as existsSync7 } from "fs";
|
|
16508
16541
|
import { mkdir as mkdir21, readFile as readFile30, readdir as readdir11, writeFile as writeFile17 } from "fs/promises";
|
|
16509
|
-
import
|
|
16542
|
+
import path61 from "path";
|
|
16510
16543
|
|
|
16511
16544
|
// src/lib/git-env.ts
|
|
16512
16545
|
var GIT_DISCOVERY_OVERRIDE_VARS = [
|
|
@@ -16531,7 +16564,7 @@ function withoutGitDiscoveryOverrides(env) {
|
|
|
16531
16564
|
init_fs();
|
|
16532
16565
|
init_guard();
|
|
16533
16566
|
import { readFile as readFile28 } from "fs/promises";
|
|
16534
|
-
import
|
|
16567
|
+
import path57 from "path";
|
|
16535
16568
|
|
|
16536
16569
|
// src/metrics/record.ts
|
|
16537
16570
|
var RELIABILITIES = new Set(["exact", "estimated", "unknown"]);
|
|
@@ -16546,7 +16579,7 @@ var RETRY_TYPES = new Set([
|
|
|
16546
16579
|
|
|
16547
16580
|
// src/metrics/lifecycle.ts
|
|
16548
16581
|
async function readArtifactPointer(root, expected) {
|
|
16549
|
-
const pointerFile =
|
|
16582
|
+
const pointerFile = path57.join(root, "latest.json");
|
|
16550
16583
|
if (!await pathExists(pointerFile))
|
|
16551
16584
|
return { status: "missing", pointer: null };
|
|
16552
16585
|
let pointer;
|
|
@@ -16555,7 +16588,7 @@ async function readArtifactPointer(root, expected) {
|
|
|
16555
16588
|
} catch {
|
|
16556
16589
|
return { status: "stale", pointer: null, reason: "latest pointer is invalid JSON" };
|
|
16557
16590
|
}
|
|
16558
|
-
const recordFile = pointer.record ?
|
|
16591
|
+
const recordFile = pointer.record ? path57.join(root, pointer.record) : null;
|
|
16559
16592
|
if (!recordFile || !isPathInside(root, recordFile) || !await pathExists(recordFile)) {
|
|
16560
16593
|
return { status: "stale", pointer, reason: "pointer record is missing" };
|
|
16561
16594
|
}
|
|
@@ -16571,9 +16604,9 @@ init_guard();
|
|
|
16571
16604
|
// src/testing/capability.ts
|
|
16572
16605
|
init_fs();
|
|
16573
16606
|
init_json();
|
|
16574
|
-
import
|
|
16607
|
+
import path58 from "path";
|
|
16575
16608
|
async function isTestingCapabilityEnabled(cwd, capability) {
|
|
16576
|
-
const manifestPath =
|
|
16609
|
+
const manifestPath = path58.join(cwd, ".metaproject", "metaproject.json");
|
|
16577
16610
|
if (!await pathExists(manifestPath)) {
|
|
16578
16611
|
return false;
|
|
16579
16612
|
}
|
|
@@ -16599,10 +16632,10 @@ async function isTestingCapabilityEnabled(cwd, capability) {
|
|
|
16599
16632
|
init_fs();
|
|
16600
16633
|
init_guard();
|
|
16601
16634
|
import { readFile as readFile29, mkdir as mkdir20, writeFile as writeFile16 } from "fs/promises";
|
|
16602
|
-
import
|
|
16635
|
+
import path59 from "path";
|
|
16603
16636
|
var COVERAGE_MAP_SCHEMA_VERSION = 1;
|
|
16604
16637
|
function coverageMapPath(cwd, cfg) {
|
|
16605
|
-
return
|
|
16638
|
+
return path59.isAbsolute(cfg.coverageMap.artifact) ? cfg.coverageMap.artifact : path59.join(cwd, cfg.coverageMap.artifact);
|
|
16606
16639
|
}
|
|
16607
16640
|
async function loadCoverageMap(cwd, cfg) {
|
|
16608
16641
|
const file = coverageMapPath(cwd, cfg);
|
|
@@ -16676,20 +16709,20 @@ function normalizePath4(file) {
|
|
|
16676
16709
|
}
|
|
16677
16710
|
|
|
16678
16711
|
// src/testing/selection.ts
|
|
16679
|
-
import
|
|
16712
|
+
import path60 from "path";
|
|
16680
16713
|
var TEST_FILE_RE = /(^|\/)(__tests__\/.*|.*\.(test|spec)\.[cm]?[tj]sx?$|e2e\/.*\.[cm]?[tj]sx?$|tests\/.*\.[cm]?[tj]sx?$)/;
|
|
16681
16714
|
function normalizePath5(file) {
|
|
16682
16715
|
return file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
16683
16716
|
}
|
|
16684
16717
|
function relatedByNamingAndDirectory(target, testFiles) {
|
|
16685
16718
|
const normalized = normalizePath5(target);
|
|
16686
|
-
const ext =
|
|
16719
|
+
const ext = path60.extname(normalized);
|
|
16687
16720
|
const withoutExt = ext ? normalized.slice(0, -ext.length) : normalized;
|
|
16688
|
-
const base =
|
|
16689
|
-
const dir =
|
|
16721
|
+
const base = path60.basename(withoutExt);
|
|
16722
|
+
const dir = path60.dirname(normalized);
|
|
16690
16723
|
return testFiles.filter((file) => {
|
|
16691
|
-
const fileDir =
|
|
16692
|
-
const fileBase =
|
|
16724
|
+
const fileDir = path60.dirname(file);
|
|
16725
|
+
const fileBase = path60.basename(file);
|
|
16693
16726
|
return file.startsWith(`${withoutExt}.`) || file.includes(`${withoutExt}.`) || fileDir === dir && fileBase.startsWith(`${base}.`) || fileDir.startsWith(dir) && fileBase.includes(base);
|
|
16694
16727
|
}).sort();
|
|
16695
16728
|
}
|
|
@@ -16804,7 +16837,7 @@ var DEFAULT_TESTING_CONFIG = {
|
|
|
16804
16837
|
}
|
|
16805
16838
|
};
|
|
16806
16839
|
function testingDataRoot(cwd) {
|
|
16807
|
-
return
|
|
16840
|
+
return path61.join(cwd, ".metaproject", "data", "testing");
|
|
16808
16841
|
}
|
|
16809
16842
|
async function computeTestingContext(cwd) {
|
|
16810
16843
|
const { files, incompleteReasons } = await listProjectFiles(cwd);
|
|
@@ -16979,7 +17012,7 @@ async function runTesting(input) {
|
|
|
16979
17012
|
return runResult;
|
|
16980
17013
|
}
|
|
16981
17014
|
async function loadTestingContext(cwd) {
|
|
16982
|
-
const file =
|
|
17015
|
+
const file = path61.join(testingDataRoot(cwd), "context.json");
|
|
16983
17016
|
if (!await pathExists(file)) {
|
|
16984
17017
|
return null;
|
|
16985
17018
|
}
|
|
@@ -16990,18 +17023,18 @@ async function loadTestingContext(cwd) {
|
|
|
16990
17023
|
}
|
|
16991
17024
|
}
|
|
16992
17025
|
async function loadTestingReport(cwd) {
|
|
16993
|
-
const file =
|
|
17026
|
+
const file = path61.join(testingDataRoot(cwd), "artifacts", "latest.json");
|
|
16994
17027
|
if (!await pathExists(file)) {
|
|
16995
17028
|
return null;
|
|
16996
17029
|
}
|
|
16997
17030
|
try {
|
|
16998
17031
|
const latest = JSON.parse(await readFile30(file, "utf8"));
|
|
16999
17032
|
if (typeof latest.record === "string") {
|
|
17000
|
-
const pointer = await readArtifactPointer(
|
|
17033
|
+
const pointer = await readArtifactPointer(path61.join(testingDataRoot(cwd), "artifacts"), await collectGitProvenance(cwd));
|
|
17001
17034
|
if (pointer.status !== "fresh")
|
|
17002
17035
|
return null;
|
|
17003
|
-
const recordFile =
|
|
17004
|
-
if (!isPathInside(
|
|
17036
|
+
const recordFile = path61.join(testingDataRoot(cwd), "artifacts", latest.record);
|
|
17037
|
+
if (!isPathInside(path61.join(testingDataRoot(cwd), "artifacts"), recordFile))
|
|
17005
17038
|
return null;
|
|
17006
17039
|
if (!await pathExists(recordFile))
|
|
17007
17040
|
return null;
|
|
@@ -17049,25 +17082,25 @@ async function ensureContext(cwd) {
|
|
|
17049
17082
|
async function writeContext(cwd, context) {
|
|
17050
17083
|
const root = testingDataRoot(cwd);
|
|
17051
17084
|
await mkdir21(root, { recursive: true });
|
|
17052
|
-
await writeFile17(
|
|
17085
|
+
await writeFile17(path61.join(root, "context.json"), `${JSON.stringify(context, null, 2)}
|
|
17053
17086
|
`, "utf8");
|
|
17054
|
-
await writeFile17(
|
|
17055
|
-
await writeFile17(
|
|
17087
|
+
await writeFile17(path61.join(root, "context.md"), renderContextMarkdown(context), "utf8");
|
|
17088
|
+
await writeFile17(path61.join(root, "recommendations.md"), renderRecommendationsMarkdown(context), "utf8");
|
|
17056
17089
|
}
|
|
17057
17090
|
async function writeReport(cwd, report) {
|
|
17058
17091
|
const root = testingDataRoot(cwd);
|
|
17059
|
-
const artifacts =
|
|
17060
|
-
const history =
|
|
17092
|
+
const artifacts = path61.join(root, "artifacts");
|
|
17093
|
+
const history = path61.join(root, "history");
|
|
17061
17094
|
await mkdir21(artifacts, { recursive: true });
|
|
17062
17095
|
await mkdir21(history, { recursive: true });
|
|
17063
17096
|
const stamp = report.generatedAt.replace(/[:.]/g, "-");
|
|
17064
|
-
const json =
|
|
17065
|
-
const markdown =
|
|
17097
|
+
const json = path61.join(artifacts, "latest.json");
|
|
17098
|
+
const markdown = path61.join(artifacts, "latest.md");
|
|
17066
17099
|
const serialized = `${JSON.stringify(report, null, 2)}
|
|
17067
17100
|
`;
|
|
17068
17101
|
if (report.runId) {
|
|
17069
|
-
const runJson =
|
|
17070
|
-
const runMarkdown =
|
|
17102
|
+
const runJson = path61.join(artifacts, "runs", `${report.runId}.json`);
|
|
17103
|
+
const runMarkdown = path61.join(artifacts, "runs", `${report.runId}.md`);
|
|
17071
17104
|
if (await pathExists(runJson))
|
|
17072
17105
|
throw new Error(`immutable testing run already exists: ${report.runId}`);
|
|
17073
17106
|
await writeFileAtomic(runJson, serialized);
|
|
@@ -17078,25 +17111,25 @@ async function writeReport(cwd, report) {
|
|
|
17078
17111
|
branch: report.provenance?.branch ?? null,
|
|
17079
17112
|
worktree: report.provenance?.worktree ?? null,
|
|
17080
17113
|
generated_at: report.generatedAt,
|
|
17081
|
-
record:
|
|
17114
|
+
record: path61.posix.join("runs", `${report.runId}.json`)
|
|
17082
17115
|
}, null, 2)}
|
|
17083
17116
|
`);
|
|
17084
17117
|
} else {
|
|
17085
17118
|
await writeFile17(json, serialized, "utf8");
|
|
17086
17119
|
}
|
|
17087
17120
|
await writeFile17(markdown, renderReportMarkdown3(report), "utf8");
|
|
17088
|
-
await writeFile17(
|
|
17121
|
+
await writeFile17(path61.join(history, `${stamp}.json`), serialized, "utf8");
|
|
17089
17122
|
return {
|
|
17090
|
-
markdownPath:
|
|
17091
|
-
jsonPath:
|
|
17123
|
+
markdownPath: path61.relative(cwd, markdown),
|
|
17124
|
+
jsonPath: path61.relative(cwd, json)
|
|
17092
17125
|
};
|
|
17093
17126
|
}
|
|
17094
17127
|
async function writeRawLog(cwd, raw) {
|
|
17095
|
-
const logs =
|
|
17128
|
+
const logs = path61.join(testingDataRoot(cwd), "logs");
|
|
17096
17129
|
await mkdir21(logs, { recursive: true });
|
|
17097
|
-
const latest =
|
|
17130
|
+
const latest = path61.join(logs, "latest.raw.log");
|
|
17098
17131
|
await writeFile17(latest, raw, "utf8");
|
|
17099
|
-
return
|
|
17132
|
+
return path61.relative(cwd, latest);
|
|
17100
17133
|
}
|
|
17101
17134
|
async function listProjectFiles(cwd) {
|
|
17102
17135
|
const out = [];
|
|
@@ -17109,11 +17142,11 @@ async function walk3(root, dir, out, incompleteReasons) {
|
|
|
17109
17142
|
try {
|
|
17110
17143
|
entries = await readdir11(dir, { withFileTypes: true });
|
|
17111
17144
|
} catch (error) {
|
|
17112
|
-
incompleteReasons.push(`${normalizePath6(
|
|
17145
|
+
incompleteReasons.push(`${normalizePath6(path61.relative(root, dir)) || "."}: ${error instanceof Error ? error.message : String(error)}`);
|
|
17113
17146
|
return;
|
|
17114
17147
|
}
|
|
17115
17148
|
for (const entry of entries) {
|
|
17116
|
-
const abs =
|
|
17149
|
+
const abs = path61.join(dir, entry.name);
|
|
17117
17150
|
if (entry.isDirectory()) {
|
|
17118
17151
|
if (IGNORED_DIRS2.has(entry.name) || entry.name.startsWith(".tmp-")) {
|
|
17119
17152
|
continue;
|
|
@@ -17122,12 +17155,12 @@ async function walk3(root, dir, out, incompleteReasons) {
|
|
|
17122
17155
|
continue;
|
|
17123
17156
|
}
|
|
17124
17157
|
if (entry.isFile()) {
|
|
17125
|
-
out.push(normalizePath6(
|
|
17158
|
+
out.push(normalizePath6(path61.relative(root, abs)));
|
|
17126
17159
|
}
|
|
17127
17160
|
}
|
|
17128
17161
|
}
|
|
17129
17162
|
async function readPackageJson(cwd) {
|
|
17130
|
-
const file =
|
|
17163
|
+
const file = path61.join(cwd, "package.json");
|
|
17131
17164
|
if (!await pathExists(file)) {
|
|
17132
17165
|
return null;
|
|
17133
17166
|
}
|
|
@@ -17138,7 +17171,7 @@ async function readPackageJson(cwd) {
|
|
|
17138
17171
|
}
|
|
17139
17172
|
}
|
|
17140
17173
|
async function loadTestingConfig(cwd) {
|
|
17141
|
-
const file =
|
|
17174
|
+
const file = path61.join(cwd, ".metaproject", "testing.config.json");
|
|
17142
17175
|
if (!await pathExists(file)) {
|
|
17143
17176
|
return DEFAULT_TESTING_CONFIG;
|
|
17144
17177
|
}
|
|
@@ -17203,7 +17236,7 @@ function detectFrameworks(input) {
|
|
|
17203
17236
|
async function extractConventions(cwd, files) {
|
|
17204
17237
|
const conventions = new Set;
|
|
17205
17238
|
for (const file of files.slice(0, 40)) {
|
|
17206
|
-
const abs =
|
|
17239
|
+
const abs = path61.join(cwd, file);
|
|
17207
17240
|
if (!await pathExists(abs)) {
|
|
17208
17241
|
continue;
|
|
17209
17242
|
}
|
|
@@ -17333,7 +17366,7 @@ async function findTestsByImportedTargets(cwd, targets, testFiles) {
|
|
|
17333
17366
|
const targetKeys = new Set(targets.map((target) => modulePathKey(normalizePath6(target))));
|
|
17334
17367
|
const selected = new Set;
|
|
17335
17368
|
for (const testFile of testFiles) {
|
|
17336
|
-
const absoluteTest =
|
|
17369
|
+
const absoluteTest = path61.join(cwd, testFile);
|
|
17337
17370
|
if (!await pathExists(absoluteTest)) {
|
|
17338
17371
|
continue;
|
|
17339
17372
|
}
|
|
@@ -17367,10 +17400,10 @@ function resolveImportPath(cwd, testFile, importPath) {
|
|
|
17367
17400
|
if (!importPath.startsWith(".")) {
|
|
17368
17401
|
return null;
|
|
17369
17402
|
}
|
|
17370
|
-
const importerDir =
|
|
17371
|
-
const absoluteResolved =
|
|
17372
|
-
const relative =
|
|
17373
|
-
if (relative.startsWith(`..${
|
|
17403
|
+
const importerDir = path61.dirname(testFile);
|
|
17404
|
+
const absoluteResolved = path61.resolve(path61.join(cwd, importerDir), importPath);
|
|
17405
|
+
const relative = path61.relative(cwd, absoluteResolved);
|
|
17406
|
+
if (relative.startsWith(`..${path61.sep}`) || relative === "..") {
|
|
17374
17407
|
return null;
|
|
17375
17408
|
}
|
|
17376
17409
|
const relativeNormalized = normalizePath6(relative);
|
|
@@ -17422,13 +17455,13 @@ function resolveTestCommand(cwd, context, input) {
|
|
|
17422
17455
|
}
|
|
17423
17456
|
var BUN_LOCKFILES = ["bun.lock", "bun.lockb"];
|
|
17424
17457
|
function detectPackageManager(cwd) {
|
|
17425
|
-
if (resolveBunBin() && BUN_LOCKFILES.some((name) => pathExistsSync(
|
|
17458
|
+
if (resolveBunBin() && BUN_LOCKFILES.some((name) => pathExistsSync(path61.join(cwd, name)))) {
|
|
17426
17459
|
return "bun";
|
|
17427
17460
|
}
|
|
17428
|
-
if (Bun.which("pnpm") && pathExistsSync(
|
|
17461
|
+
if (Bun.which("pnpm") && pathExistsSync(path61.join(cwd, "pnpm-lock.yaml"))) {
|
|
17429
17462
|
return "pnpm";
|
|
17430
17463
|
}
|
|
17431
|
-
if (Bun.which("yarn") && pathExistsSync(
|
|
17464
|
+
if (Bun.which("yarn") && pathExistsSync(path61.join(cwd, "yarn.lock"))) {
|
|
17432
17465
|
return "yarn";
|
|
17433
17466
|
}
|
|
17434
17467
|
return "npm";
|
|
@@ -17768,7 +17801,7 @@ async function compatibleReportForHealth(ctx) {
|
|
|
17768
17801
|
|
|
17769
17802
|
// src/health/sources/dependency-audit.ts
|
|
17770
17803
|
import { existsSync as existsSync8 } from "fs";
|
|
17771
|
-
import
|
|
17804
|
+
import path62 from "path";
|
|
17772
17805
|
function auditSeverityToPriority(severity) {
|
|
17773
17806
|
if (severity === "critical" || severity === "high")
|
|
17774
17807
|
return "P0";
|
|
@@ -17887,7 +17920,7 @@ var LOCKFILE_COMMANDS = [
|
|
|
17887
17920
|
];
|
|
17888
17921
|
function auditCommand(cwd) {
|
|
17889
17922
|
for (const entry of LOCKFILE_COMMANDS) {
|
|
17890
|
-
if (!entry.lockfiles.some((name) => existsSync8(
|
|
17923
|
+
if (!entry.lockfiles.some((name) => existsSync8(path62.join(cwd, name))))
|
|
17891
17924
|
continue;
|
|
17892
17925
|
const bin = resolveBin(cwd, entry.bin);
|
|
17893
17926
|
if (bin)
|
|
@@ -17946,13 +17979,13 @@ var dependencyAuditAdapter = {
|
|
|
17946
17979
|
|
|
17947
17980
|
// src/health/sources/sonarqube.ts
|
|
17948
17981
|
import { existsSync as existsSync9 } from "fs";
|
|
17949
|
-
import
|
|
17982
|
+
import path63 from "path";
|
|
17950
17983
|
var REPORT_FILES = ["sonar-issues.json", ".metaproject/data/health/sonar-issues.json"];
|
|
17951
17984
|
function reportPath(cwd) {
|
|
17952
17985
|
const fromEnv = process.env.SONAR_ISSUES_FILE;
|
|
17953
17986
|
const candidates = fromEnv ? [fromEnv, ...REPORT_FILES] : REPORT_FILES;
|
|
17954
17987
|
for (const rel of candidates) {
|
|
17955
|
-
const abs =
|
|
17988
|
+
const abs = path63.isAbsolute(rel) ? rel : path63.join(cwd, rel);
|
|
17956
17989
|
if (existsSync9(abs)) {
|
|
17957
17990
|
return abs;
|
|
17958
17991
|
}
|
|
@@ -18036,7 +18069,7 @@ var sonarqubeAdapter = {
|
|
|
18036
18069
|
function relativizeComponent(component, cwd) {
|
|
18037
18070
|
const colon = component.indexOf(":");
|
|
18038
18071
|
const value = colon >= 0 ? component.slice(colon + 1) : component;
|
|
18039
|
-
return
|
|
18072
|
+
return path63.isAbsolute(value) ? path63.relative(cwd, value) : value;
|
|
18040
18073
|
}
|
|
18041
18074
|
|
|
18042
18075
|
// src/health/sources/index.ts
|
|
@@ -18366,19 +18399,19 @@ function filteredInfo(source, cfg) {
|
|
|
18366
18399
|
};
|
|
18367
18400
|
}
|
|
18368
18401
|
async function writeOutputs(cwd, report, config, stamp) {
|
|
18369
|
-
const artifacts =
|
|
18370
|
-
const history =
|
|
18402
|
+
const artifacts = path64.join(dataRoot(cwd), "artifacts");
|
|
18403
|
+
const history = path64.join(dataRoot(cwd), "history");
|
|
18371
18404
|
await mkdir22(artifacts, { recursive: true });
|
|
18372
18405
|
await mkdir22(history, { recursive: true });
|
|
18373
|
-
const markdown =
|
|
18374
|
-
const json =
|
|
18375
|
-
const historyJson =
|
|
18406
|
+
const markdown = path64.join(artifacts, "latest.md");
|
|
18407
|
+
const json = path64.join(artifacts, "latest.json");
|
|
18408
|
+
const historyJson = path64.join(history, `${stamp}.json`);
|
|
18376
18409
|
const serialized = `${JSON.stringify(report, null, 2)}
|
|
18377
18410
|
`;
|
|
18378
18411
|
await writeFile18(markdown, renderReportMarkdown2(report, config), "utf8");
|
|
18379
18412
|
if (report.runId) {
|
|
18380
|
-
const runJson =
|
|
18381
|
-
const runMarkdown =
|
|
18413
|
+
const runJson = path64.join(artifacts, "runs", `${report.runId}.json`);
|
|
18414
|
+
const runMarkdown = path64.join(artifacts, "runs", `${report.runId}.md`);
|
|
18382
18415
|
if (await pathExists(runJson))
|
|
18383
18416
|
throw new Error(`immutable health run already exists: ${report.runId}`);
|
|
18384
18417
|
await writeFileAtomic(runJson, serialized);
|
|
@@ -18389,7 +18422,7 @@ async function writeOutputs(cwd, report, config, stamp) {
|
|
|
18389
18422
|
branch: report.provenance?.branch ?? null,
|
|
18390
18423
|
worktree: report.provenance?.worktree ?? null,
|
|
18391
18424
|
generated_at: report.generatedAt,
|
|
18392
|
-
record:
|
|
18425
|
+
record: path64.posix.join("runs", `${report.runId}.json`)
|
|
18393
18426
|
}, null, 2)}
|
|
18394
18427
|
`);
|
|
18395
18428
|
} else {
|
|
@@ -18397,8 +18430,8 @@ async function writeOutputs(cwd, report, config, stamp) {
|
|
|
18397
18430
|
}
|
|
18398
18431
|
await writeFile18(historyJson, serialized, "utf8");
|
|
18399
18432
|
return {
|
|
18400
|
-
markdownPath:
|
|
18401
|
-
jsonPath:
|
|
18433
|
+
markdownPath: path64.relative(cwd, markdown),
|
|
18434
|
+
jsonPath: path64.relative(cwd, json)
|
|
18402
18435
|
};
|
|
18403
18436
|
}
|
|
18404
18437
|
async function resolveChanged(cwd, selector) {
|
|
@@ -18451,7 +18484,7 @@ function hasGateShape(value) {
|
|
|
18451
18484
|
return Array.isArray(report.metrics) && Array.isArray(report.sources) && Array.isArray(report.findings);
|
|
18452
18485
|
}
|
|
18453
18486
|
async function readLatest(cwd) {
|
|
18454
|
-
const file =
|
|
18487
|
+
const file = path65.join(dataRoot(cwd), "artifacts", "latest.json");
|
|
18455
18488
|
if (!await pathExists(file)) {
|
|
18456
18489
|
return null;
|
|
18457
18490
|
}
|
|
@@ -18462,11 +18495,11 @@ async function readLatest(cwd) {
|
|
|
18462
18495
|
const latest = read.value;
|
|
18463
18496
|
const record = latest.record;
|
|
18464
18497
|
if (typeof record === "string") {
|
|
18465
|
-
const pointer = await readArtifactPointer(
|
|
18498
|
+
const pointer = await readArtifactPointer(path65.join(dataRoot(cwd), "artifacts"), await collectGitProvenance(cwd));
|
|
18466
18499
|
if (pointer.status !== "fresh")
|
|
18467
18500
|
return null;
|
|
18468
|
-
const recordFile =
|
|
18469
|
-
if (!isPathInside(
|
|
18501
|
+
const recordFile = path65.join(dataRoot(cwd), "artifacts", record);
|
|
18502
|
+
if (!isPathInside(path65.join(dataRoot(cwd), "artifacts"), recordFile))
|
|
18470
18503
|
return null;
|
|
18471
18504
|
if (!await pathExists(recordFile))
|
|
18472
18505
|
return null;
|
|
@@ -18539,7 +18572,7 @@ function createCodeHealthService() {
|
|
|
18539
18572
|
return {
|
|
18540
18573
|
run: (input) => runHealth(input),
|
|
18541
18574
|
async status(input) {
|
|
18542
|
-
const enabled = await pathExists(
|
|
18575
|
+
const enabled = await pathExists(path65.join(input.cwd, ".metaproject", "health.config.json"));
|
|
18543
18576
|
const latest = await readLatest(input.cwd);
|
|
18544
18577
|
const project = latest?.metrics.find((m) => m.key === "project") ?? null;
|
|
18545
18578
|
const decliningScopes = latest ? latest.metrics.filter((m) => m.regression_score > 0).length : 0;
|
|
@@ -18607,7 +18640,7 @@ __export(exports_service7, {
|
|
|
18607
18640
|
createJobService: () => createJobService
|
|
18608
18641
|
});
|
|
18609
18642
|
import { copyFile, mkdir as mkdir24 } from "fs/promises";
|
|
18610
|
-
import
|
|
18643
|
+
import path68 from "path";
|
|
18611
18644
|
|
|
18612
18645
|
// src/job/types.ts
|
|
18613
18646
|
var JOB_INTENTS = ["implement", "analyze", "review", "custom"];
|
|
@@ -18745,12 +18778,12 @@ function defaultPlan(intent) {
|
|
|
18745
18778
|
|
|
18746
18779
|
// src/job/store.ts
|
|
18747
18780
|
import { appendFile as appendFile4, mkdir as mkdir23, readFile as readFile32, readdir as readdir12 } from "fs/promises";
|
|
18748
|
-
import
|
|
18781
|
+
import path67 from "path";
|
|
18749
18782
|
|
|
18750
18783
|
// src/gdskills/contracts.ts
|
|
18751
18784
|
import { readFile as readFile31 } from "fs/promises";
|
|
18752
18785
|
import { existsSync as existsSync10 } from "fs";
|
|
18753
|
-
import
|
|
18786
|
+
import path66 from "path";
|
|
18754
18787
|
import { fileURLToPath } from "url";
|
|
18755
18788
|
var CONTRACTS = [
|
|
18756
18789
|
{
|
|
@@ -18873,10 +18906,10 @@ async function loadSchema(name) {
|
|
|
18873
18906
|
return JSON.parse(raw);
|
|
18874
18907
|
}
|
|
18875
18908
|
function contractPath(contract) {
|
|
18876
|
-
const here =
|
|
18909
|
+
const here = path66.dirname(fileURLToPath(import.meta.url));
|
|
18877
18910
|
if (contract.sourcePath) {
|
|
18878
|
-
for (const root of [
|
|
18879
|
-
const candidate =
|
|
18911
|
+
for (const root of [path66.join(here, "..", ".."), path66.join(here, ".."), here]) {
|
|
18912
|
+
const candidate = path66.resolve(root, contract.sourcePath);
|
|
18880
18913
|
if (existsSync10(candidate)) {
|
|
18881
18914
|
return candidate;
|
|
18882
18915
|
}
|
|
@@ -18886,7 +18919,7 @@ function contractPath(contract) {
|
|
|
18886
18919
|
if (existsSync10(directPath)) {
|
|
18887
18920
|
return directPath;
|
|
18888
18921
|
}
|
|
18889
|
-
const packagedSourcePath =
|
|
18922
|
+
const packagedSourcePath = path66.join(here, "..", "src", "gdskills", "contracts", contract.fileName);
|
|
18890
18923
|
if (existsSync10(packagedSourcePath)) {
|
|
18891
18924
|
return packagedSourcePath;
|
|
18892
18925
|
}
|
|
@@ -18900,13 +18933,13 @@ var SCHEMA_ROOTS = [
|
|
|
18900
18933
|
// src/job/store.ts
|
|
18901
18934
|
init_fs();
|
|
18902
18935
|
function jobsRoot(cwd) {
|
|
18903
|
-
return
|
|
18936
|
+
return path67.join(cwd, ".metaproject", "jobs");
|
|
18904
18937
|
}
|
|
18905
18938
|
function jobDir(cwd, name) {
|
|
18906
|
-
return
|
|
18939
|
+
return path67.join(jobsRoot(cwd), name);
|
|
18907
18940
|
}
|
|
18908
18941
|
function jobStatePath(cwd, name) {
|
|
18909
|
-
return
|
|
18942
|
+
return path67.join(jobDir(cwd, name), "state.json");
|
|
18910
18943
|
}
|
|
18911
18944
|
var JOB_NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
18912
18945
|
function assertJobName(name) {
|
|
@@ -18943,12 +18976,12 @@ async function writeJob(cwd, name, state) {
|
|
|
18943
18976
|
`));
|
|
18944
18977
|
}
|
|
18945
18978
|
const file = jobStatePath(cwd, name);
|
|
18946
|
-
await mkdir23(
|
|
18979
|
+
await mkdir23(path67.dirname(file), { recursive: true });
|
|
18947
18980
|
await writeFileAtomic(file, `${JSON.stringify(state, null, 2)}
|
|
18948
18981
|
`);
|
|
18949
18982
|
}
|
|
18950
18983
|
async function appendJournal2(cwd, name, at, line) {
|
|
18951
|
-
await appendFile4(
|
|
18984
|
+
await appendFile4(path67.join(jobDir(cwd, name), "journal.md"), `- ${at} - ${line}
|
|
18952
18985
|
`, "utf8");
|
|
18953
18986
|
}
|
|
18954
18987
|
function renderJournal2(name, at) {
|
|
@@ -18969,7 +19002,7 @@ function assertDocumentType(raw) {
|
|
|
18969
19002
|
return raw;
|
|
18970
19003
|
}
|
|
18971
19004
|
function documentFileName(type, sourcePath) {
|
|
18972
|
-
const extension =
|
|
19005
|
+
const extension = path67.extname(sourcePath) || ".md";
|
|
18973
19006
|
return `${type}${extension}`;
|
|
18974
19007
|
}
|
|
18975
19008
|
|
|
@@ -18977,7 +19010,7 @@ function documentFileName(type, sourcePath) {
|
|
|
18977
19010
|
function createJobService(deps) {
|
|
18978
19011
|
const now = () => deps.now().toISOString();
|
|
18979
19012
|
function lockPath(cwd, name) {
|
|
18980
|
-
return
|
|
19013
|
+
return path68.join(jobsRoot(cwd), `.job-lock-${name}`);
|
|
18981
19014
|
}
|
|
18982
19015
|
async function mutate(cwd, name, run) {
|
|
18983
19016
|
assertJobName(name);
|
|
@@ -19026,20 +19059,20 @@ function createJobService(deps) {
|
|
|
19026
19059
|
},
|
|
19027
19060
|
plan: { steps: defaultPlan(intent) },
|
|
19028
19061
|
documentation: {
|
|
19029
|
-
job_path:
|
|
19062
|
+
job_path: path68.join(".metaproject", "jobs", name),
|
|
19030
19063
|
documents_created: []
|
|
19031
19064
|
},
|
|
19032
19065
|
metrics: { steps: [] },
|
|
19033
|
-
jobs_root:
|
|
19066
|
+
jobs_root: path68.join(".metaproject", "jobs"),
|
|
19034
19067
|
updated_at: createdAt
|
|
19035
19068
|
};
|
|
19036
19069
|
const first = firstOpenStep(state.plan.steps);
|
|
19037
19070
|
if (first) {
|
|
19038
19071
|
state.plan.current_step = first.id;
|
|
19039
19072
|
}
|
|
19040
|
-
await writeFileAtomic(
|
|
19073
|
+
await writeFileAtomic(path68.join(absolute, "journal.md"), renderJournal2(name, createdAt));
|
|
19041
19074
|
await writeJob(input.cwd, name, state);
|
|
19042
|
-
return { state, dir:
|
|
19075
|
+
return { state, dir: path68.relative(input.cwd, absolute) };
|
|
19043
19076
|
},
|
|
19044
19077
|
async status({ cwd, name }) {
|
|
19045
19078
|
assertJobName(name);
|
|
@@ -19051,7 +19084,7 @@ function createJobService(deps) {
|
|
|
19051
19084
|
}
|
|
19052
19085
|
return {
|
|
19053
19086
|
state,
|
|
19054
|
-
dir:
|
|
19087
|
+
dir: path68.join(".metaproject", "jobs", name),
|
|
19055
19088
|
stepsDone: state.plan.steps.filter((step) => isTerminalStep(step.status)).length,
|
|
19056
19089
|
stepsTotal: state.plan.steps.length,
|
|
19057
19090
|
nextStep: firstOpenStep(state.plan.steps),
|
|
@@ -19108,23 +19141,23 @@ function createJobService(deps) {
|
|
|
19108
19141
|
if (!input.file) {
|
|
19109
19142
|
throw new Error("Missing --file. Usage: keryx job document <name> --type <type> --file <path>");
|
|
19110
19143
|
}
|
|
19111
|
-
const source =
|
|
19144
|
+
const source = path68.isAbsolute(input.file) ? input.file : path68.join(input.cwd, input.file);
|
|
19112
19145
|
if (!await pathExists(source)) {
|
|
19113
19146
|
throw new Error(`--file not found: ${input.file}. Write the document first, then record it.`);
|
|
19114
19147
|
}
|
|
19115
19148
|
let recorded;
|
|
19116
19149
|
await mutate(input.cwd, input.name, async (state) => {
|
|
19117
19150
|
const fileName = documentFileName(type, source);
|
|
19118
|
-
const target =
|
|
19151
|
+
const target = path68.join(jobDir(input.cwd, state.job_name), fileName);
|
|
19119
19152
|
await copyFile(source, target);
|
|
19120
19153
|
state.documentation ??= {};
|
|
19121
|
-
state.documentation.job_path ??=
|
|
19154
|
+
state.documentation.job_path ??= path68.join(".metaproject", "jobs", state.job_name);
|
|
19122
19155
|
const created = state.documentation.documents_created ?? [];
|
|
19123
19156
|
state.documentation.documents_created = created.includes(fileName) ? created : [...created, fileName];
|
|
19124
19157
|
recorded = {
|
|
19125
19158
|
state,
|
|
19126
19159
|
document: fileName,
|
|
19127
|
-
path:
|
|
19160
|
+
path: path68.join(".metaproject", "jobs", state.job_name, fileName)
|
|
19128
19161
|
};
|
|
19129
19162
|
return { state, event: "document", detail: `${type} -> ${fileName}` };
|
|
19130
19163
|
});
|
|
@@ -19159,7 +19192,7 @@ function createJobService(deps) {
|
|
|
19159
19192
|
name: state.job_name,
|
|
19160
19193
|
phase: state.phase,
|
|
19161
19194
|
intent: state.intent,
|
|
19162
|
-
dir:
|
|
19195
|
+
dir: path68.join(".metaproject", "jobs", name),
|
|
19163
19196
|
stepsDone: state.plan.steps.filter((step) => isTerminalStep(step.status)).length,
|
|
19164
19197
|
stepsTotal: state.plan.steps.length,
|
|
19165
19198
|
nextStep: firstOpenStep(state.plan.steps)?.id ?? null
|
|
@@ -19180,24 +19213,24 @@ __export(exports_service8, {
|
|
|
19180
19213
|
});
|
|
19181
19214
|
import { createHash as createHash10 } from "crypto";
|
|
19182
19215
|
import { mkdir as mkdir26, readFile as readFile37, writeFile as writeFile20 } from "fs/promises";
|
|
19183
|
-
import
|
|
19216
|
+
import path74 from "path";
|
|
19184
19217
|
|
|
19185
19218
|
// src/memory/check.ts
|
|
19186
19219
|
init_fs();
|
|
19187
19220
|
init_store();
|
|
19188
|
-
import
|
|
19221
|
+
import path70 from "path";
|
|
19189
19222
|
|
|
19190
19223
|
// src/memory/cross-layer.ts
|
|
19191
19224
|
init_collect();
|
|
19192
19225
|
init_section_index();
|
|
19193
19226
|
init_section_tombstone();
|
|
19194
19227
|
import { readFile as readFile33 } from "fs/promises";
|
|
19195
|
-
import
|
|
19228
|
+
import path69 from "path";
|
|
19196
19229
|
var MARKDOWN_LINK_RE = /\[[^\]]*\]\(([^)\s]+)\)/g;
|
|
19197
19230
|
var SECTION_REF_RE = /keryx:page\/[a-z0-9][a-z0-9._-]*(?:#[a-z0-9][a-z0-9._-]*)?/gi;
|
|
19198
19231
|
function extractWikiReferences(entryRelativePath, entryAbsolutePath, content, wikiRoot) {
|
|
19199
19232
|
const references = [];
|
|
19200
|
-
const entryDir =
|
|
19233
|
+
const entryDir = path69.dirname(entryAbsolutePath);
|
|
19201
19234
|
const lines = content.split(`
|
|
19202
19235
|
`);
|
|
19203
19236
|
for (let index = 0;index < lines.length; index += 1) {
|
|
@@ -19212,16 +19245,16 @@ function extractWikiReferences(entryRelativePath, entryAbsolutePath, content, wi
|
|
|
19212
19245
|
if (withoutAnchor.length === 0) {
|
|
19213
19246
|
continue;
|
|
19214
19247
|
}
|
|
19215
|
-
const absolute =
|
|
19216
|
-
const relativeToWiki =
|
|
19217
|
-
if (relativeToWiki.startsWith("..") ||
|
|
19248
|
+
const absolute = path69.resolve(entryDir, withoutAnchor);
|
|
19249
|
+
const relativeToWiki = path69.relative(wikiRoot, absolute);
|
|
19250
|
+
if (relativeToWiki.startsWith("..") || path69.isAbsolute(relativeToWiki)) {
|
|
19218
19251
|
continue;
|
|
19219
19252
|
}
|
|
19220
19253
|
references.push({
|
|
19221
19254
|
entry: entryRelativePath,
|
|
19222
19255
|
kind: "page-path",
|
|
19223
19256
|
raw: href,
|
|
19224
|
-
target: relativeToWiki.split(
|
|
19257
|
+
target: relativeToWiki.split(path69.sep).join("/"),
|
|
19225
19258
|
line
|
|
19226
19259
|
});
|
|
19227
19260
|
}
|
|
@@ -19241,7 +19274,7 @@ function isDangling(finding) {
|
|
|
19241
19274
|
return finding.state !== "intact";
|
|
19242
19275
|
}
|
|
19243
19276
|
async function loadWikiKnowledgeView(cwd) {
|
|
19244
|
-
const wikiRoot =
|
|
19277
|
+
const wikiRoot = path69.join(cwd, ".metaproject", "wiki");
|
|
19245
19278
|
const pages = await collectPages(cwd);
|
|
19246
19279
|
const index = buildSectionIndex(await Promise.all(pages.map(async (page) => ({
|
|
19247
19280
|
page,
|
|
@@ -19466,7 +19499,7 @@ async function checkMemory(cwd, config) {
|
|
|
19466
19499
|
}
|
|
19467
19500
|
for (const file of entry.scopes.files) {
|
|
19468
19501
|
const clean = file.replace(/^`|`$/g, "");
|
|
19469
|
-
if (!await pathExists(
|
|
19502
|
+
if (!await pathExists(path70.resolve(cwd, clean))) {
|
|
19470
19503
|
issues.push({ path: entry.relativePath, kind: "link", message: `related file not found: ${clean}` });
|
|
19471
19504
|
}
|
|
19472
19505
|
}
|
|
@@ -19518,19 +19551,19 @@ init_types();
|
|
|
19518
19551
|
init_store();
|
|
19519
19552
|
import { existsSync as existsSync11 } from "fs";
|
|
19520
19553
|
import { readFile as readFile35 } from "fs/promises";
|
|
19521
|
-
import
|
|
19554
|
+
import path72 from "path";
|
|
19522
19555
|
|
|
19523
19556
|
// src/memory/write.ts
|
|
19524
19557
|
init_guard();
|
|
19525
19558
|
init_store();
|
|
19526
19559
|
init_types();
|
|
19527
19560
|
import { mkdir as mkdir25, open, readFile as readFile34, rename as rename5, rm as rm4, writeFile as writeFile19 } from "fs/promises";
|
|
19528
|
-
import
|
|
19561
|
+
import path71 from "path";
|
|
19529
19562
|
async function resolveCanonicalEntryPath(cwd, relativePath) {
|
|
19530
|
-
const root =
|
|
19531
|
-
const absolutePath =
|
|
19532
|
-
const normalized = toPosix2(
|
|
19533
|
-
if (!normalized || normalized.startsWith("../") ||
|
|
19563
|
+
const root = path71.resolve(memoryRoot(cwd));
|
|
19564
|
+
const absolutePath = path71.resolve(root, relativePath);
|
|
19565
|
+
const normalized = toPosix2(path71.relative(root, absolutePath));
|
|
19566
|
+
if (!normalized || normalized.startsWith("../") || path71.isAbsolute(normalized) || !normalized.endsWith(".md")) {
|
|
19534
19567
|
return null;
|
|
19535
19568
|
}
|
|
19536
19569
|
return { absolutePath, relativePath: normalized };
|
|
@@ -19626,9 +19659,9 @@ function validateNextEntry(relativePath, content) {
|
|
|
19626
19659
|
return null;
|
|
19627
19660
|
}
|
|
19628
19661
|
async function replaceAtomically(target, content) {
|
|
19629
|
-
const dir =
|
|
19662
|
+
const dir = path71.dirname(target);
|
|
19630
19663
|
await mkdir25(dir, { recursive: true });
|
|
19631
|
-
const tmp =
|
|
19664
|
+
const tmp = path71.join(dir, `.${path71.basename(target)}.keryx-tmp-${process.pid}-${Math.random().toString(16).slice(2)}`);
|
|
19632
19665
|
try {
|
|
19633
19666
|
await writeFile19(tmp, content, "utf8");
|
|
19634
19667
|
const file = await open(tmp, "r");
|
|
@@ -19664,7 +19697,7 @@ function header(content, name) {
|
|
|
19664
19697
|
return content.match(new RegExp(`^${name}:\\s*(.+)$`, "mi"))?.[1]?.trim() ?? null;
|
|
19665
19698
|
}
|
|
19666
19699
|
function toPosix2(value) {
|
|
19667
|
-
return value.split(
|
|
19700
|
+
return value.split(path71.sep).join("/");
|
|
19668
19701
|
}
|
|
19669
19702
|
function message(cause) {
|
|
19670
19703
|
return cause instanceof Error ? cause.message : String(cause);
|
|
@@ -19684,7 +19717,7 @@ var SOURCE_CONFIDENCE = {
|
|
|
19684
19717
|
"skill-verifier": "medium"
|
|
19685
19718
|
};
|
|
19686
19719
|
async function ingestMemory(cwd, source, filePath, config, now) {
|
|
19687
|
-
const absolute =
|
|
19720
|
+
const absolute = path72.resolve(cwd, filePath);
|
|
19688
19721
|
if (!await pathExists(absolute)) {
|
|
19689
19722
|
throw new Error(`Ingest source not found: ${filePath}`);
|
|
19690
19723
|
}
|
|
@@ -19701,8 +19734,8 @@ async function ingestMemory(cwd, source, filePath, config, now) {
|
|
|
19701
19734
|
const securityWarnings = [];
|
|
19702
19735
|
const securitySkipped = [];
|
|
19703
19736
|
let skippedDuplicates = 0;
|
|
19704
|
-
const dir =
|
|
19705
|
-
const link =
|
|
19737
|
+
const dir = path72.join(memoryRoot(cwd), folder);
|
|
19738
|
+
const link = path72.relative(cwd, absolute);
|
|
19706
19739
|
const date = dateString(now);
|
|
19707
19740
|
for (const text of candidates) {
|
|
19708
19741
|
const title = toTitle(text);
|
|
@@ -19883,7 +19916,7 @@ function uniqueSlug(dir, title) {
|
|
|
19883
19916
|
const base = slugify3(title) || "entry";
|
|
19884
19917
|
let slug = base;
|
|
19885
19918
|
let counter = 2;
|
|
19886
|
-
while (existsSync11(
|
|
19919
|
+
while (existsSync11(path72.join(dir, `${slug}.md`))) {
|
|
19887
19920
|
slug = `${base}-${counter}`;
|
|
19888
19921
|
counter += 1;
|
|
19889
19922
|
}
|
|
@@ -19903,7 +19936,7 @@ init_store();
|
|
|
19903
19936
|
init_fs();
|
|
19904
19937
|
init_store();
|
|
19905
19938
|
import { readFile as readFile36 } from "fs/promises";
|
|
19906
|
-
import
|
|
19939
|
+
import path73 from "path";
|
|
19907
19940
|
async function supersedeEntry(input, now) {
|
|
19908
19941
|
const date = input.date ?? now.toISOString().slice(0, 10);
|
|
19909
19942
|
const today = now.toISOString().slice(0, 10);
|
|
@@ -19963,12 +19996,12 @@ async function supersedeEntry(input, now) {
|
|
|
19963
19996
|
async function resolveEntryPath(cwd, raw) {
|
|
19964
19997
|
const root = memoryRoot(cwd);
|
|
19965
19998
|
const candidates = [
|
|
19966
|
-
|
|
19967
|
-
|
|
19968
|
-
|
|
19999
|
+
path73.resolve(cwd, raw),
|
|
20000
|
+
path73.resolve(root, raw),
|
|
20001
|
+
path73.isAbsolute(raw) ? raw : path73.join(cwd, raw)
|
|
19969
20002
|
];
|
|
19970
20003
|
for (const absolute of candidates) {
|
|
19971
|
-
const confined = await resolveCanonicalEntryPath(cwd,
|
|
20004
|
+
const confined = await resolveCanonicalEntryPath(cwd, path73.relative(root, absolute));
|
|
19972
20005
|
if (confined && await pathExists(confined.absolutePath)) {
|
|
19973
20006
|
return { absolute: confined.absolutePath, relative: confined.relativePath };
|
|
19974
20007
|
}
|
|
@@ -20102,7 +20135,7 @@ Main memory content.
|
|
|
20102
20135
|
init_embedding();
|
|
20103
20136
|
init_types();
|
|
20104
20137
|
function dataRoot2(cwd) {
|
|
20105
|
-
return
|
|
20138
|
+
return path74.join(cwd, ".metaproject", "data", "memory");
|
|
20106
20139
|
}
|
|
20107
20140
|
function createMemoryService() {
|
|
20108
20141
|
const reportStore = createMemoryReportStore();
|
|
@@ -20117,9 +20150,9 @@ function createMemoryService() {
|
|
|
20117
20150
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(slug)) {
|
|
20118
20151
|
throw new Error(`Invalid slug: ${slug}. Use lowercase letters, digits, and hyphens.`);
|
|
20119
20152
|
}
|
|
20120
|
-
const dir =
|
|
20121
|
-
const filePath =
|
|
20122
|
-
const relativePath =
|
|
20153
|
+
const dir = path74.join(memoryRoot(input.cwd), typeConfig.folder);
|
|
20154
|
+
const filePath = path74.join(dir, `${slug}.md`);
|
|
20155
|
+
const relativePath = path74.relative(input.cwd, filePath);
|
|
20123
20156
|
if (await pathExists(filePath) && !input.force) {
|
|
20124
20157
|
throw new Error(`Entry already exists: ${relativePath}. Use --force to overwrite.`);
|
|
20125
20158
|
}
|
|
@@ -20150,9 +20183,9 @@ function createMemoryService() {
|
|
|
20150
20183
|
async index(input) {
|
|
20151
20184
|
const entries = await collectEntries(input.cwd);
|
|
20152
20185
|
const generatedAt = new Date().toISOString();
|
|
20153
|
-
const indexDir =
|
|
20186
|
+
const indexDir = path74.join(dataRoot2(input.cwd), "index");
|
|
20154
20187
|
await mkdir26(indexDir, { recursive: true });
|
|
20155
|
-
const indexPath =
|
|
20188
|
+
const indexPath = path74.join(indexDir, "index.json");
|
|
20156
20189
|
await writeFile20(indexPath, `${JSON.stringify({
|
|
20157
20190
|
catalogVersion: 1,
|
|
20158
20191
|
sourceFingerprint: createHash10("sha256").update(JSON.stringify(entries.map((e) => ({
|
|
@@ -20173,7 +20206,7 @@ function createMemoryService() {
|
|
|
20173
20206
|
}, null, 2)}
|
|
20174
20207
|
`, "utf8");
|
|
20175
20208
|
const result = {
|
|
20176
|
-
path:
|
|
20209
|
+
path: path74.relative(input.cwd, indexPath),
|
|
20177
20210
|
entryCount: entries.length,
|
|
20178
20211
|
generatedAt
|
|
20179
20212
|
};
|
|
@@ -20186,7 +20219,7 @@ function createMemoryService() {
|
|
|
20186
20219
|
const built = await buildEmbeddingIndex(input.cwd, entries, embedder.embed, embedder.model, new Date);
|
|
20187
20220
|
result.embeddings = {
|
|
20188
20221
|
built: true,
|
|
20189
|
-
path:
|
|
20222
|
+
path: path74.relative(input.cwd, embeddingsDir(input.cwd)),
|
|
20190
20223
|
vectorCount: built.meta.entryCount,
|
|
20191
20224
|
model: built.meta.model
|
|
20192
20225
|
};
|
|
@@ -20371,12 +20404,12 @@ __export(exports_service9, {
|
|
|
20371
20404
|
init_assembly();
|
|
20372
20405
|
import { createHash as createHash15, randomUUID as randomUUID4 } from "crypto";
|
|
20373
20406
|
import { appendFile as appendFile5, mkdir as mkdir28, open as open2, readFile as readFile40, rename as rename6, rm as rm5, stat as stat9, writeFile as writeFile21 } from "fs/promises";
|
|
20374
|
-
import
|
|
20407
|
+
import path78 from "path";
|
|
20375
20408
|
|
|
20376
20409
|
// src/sac/index.ts
|
|
20377
20410
|
import { access as access3, readFile as readFile38, realpath as realpath3 } from "fs/promises";
|
|
20378
20411
|
import { createHash as createHash11 } from "crypto";
|
|
20379
|
-
import
|
|
20412
|
+
import path75 from "path";
|
|
20380
20413
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20381
20414
|
var idPattern = /^[a-z][a-z0-9-]{2,63}$/;
|
|
20382
20415
|
var subjectPattern = /^(?:user|team|service|agent):[a-z0-9][a-z0-9._-]{0,127}$/;
|
|
@@ -20394,21 +20427,21 @@ var normativeSchemaFiles = {
|
|
|
20394
20427
|
"review-decision": "review-decision.schema.json"
|
|
20395
20428
|
};
|
|
20396
20429
|
var normativeSchemas = new Map;
|
|
20397
|
-
var NORMATIVE_SCHEMA_DIR =
|
|
20430
|
+
var NORMATIVE_SCHEMA_DIR = path75.join("docs", "requirements", "shared-agent-context", "schemas");
|
|
20398
20431
|
async function resolveSacNormativeSchemaPath(fileName, searchFrom = [fileURLToPath2(new URL(".", import.meta.url)), process.cwd()]) {
|
|
20399
20432
|
const seen = new Set;
|
|
20400
20433
|
for (const start of searchFrom) {
|
|
20401
|
-
let dir =
|
|
20434
|
+
let dir = path75.resolve(start);
|
|
20402
20435
|
for (let i = 0;i < 10; i++) {
|
|
20403
20436
|
if (seen.has(dir))
|
|
20404
20437
|
break;
|
|
20405
20438
|
seen.add(dir);
|
|
20406
|
-
const candidate =
|
|
20439
|
+
const candidate = path75.join(dir, NORMATIVE_SCHEMA_DIR, fileName);
|
|
20407
20440
|
try {
|
|
20408
20441
|
await access3(candidate);
|
|
20409
20442
|
return candidate;
|
|
20410
20443
|
} catch {}
|
|
20411
|
-
const parent =
|
|
20444
|
+
const parent = path75.dirname(dir);
|
|
20412
20445
|
if (parent === dir)
|
|
20413
20446
|
break;
|
|
20414
20447
|
dir = parent;
|
|
@@ -21077,12 +21110,12 @@ class SacReferenceError extends Error {
|
|
|
21077
21110
|
code = "unsafe_workspace_reference";
|
|
21078
21111
|
}
|
|
21079
21112
|
async function resolveWorkspaceReference(input) {
|
|
21080
|
-
if (!workspacePathPattern.test(input.uri) ||
|
|
21113
|
+
if (!workspacePathPattern.test(input.uri) || path75.isAbsolute(input.uri) || /^[a-z][a-z0-9+.-]*:/i.test(input.uri) || input.uri.includes("\\"))
|
|
21081
21114
|
throw new SacReferenceError("unsafe workspace reference");
|
|
21082
|
-
const lexicalRoot =
|
|
21115
|
+
const lexicalRoot = path75.resolve(input.workspaceRoot);
|
|
21083
21116
|
const root = await realpath3(lexicalRoot);
|
|
21084
|
-
const candidate =
|
|
21085
|
-
if (candidate !== lexicalRoot && !candidate.startsWith(`${lexicalRoot}${
|
|
21117
|
+
const candidate = path75.resolve(lexicalRoot, input.uri.slice(2));
|
|
21118
|
+
if (candidate !== lexicalRoot && !candidate.startsWith(`${lexicalRoot}${path75.sep}`))
|
|
21086
21119
|
throw new SacReferenceError("workspace reference escapes root");
|
|
21087
21120
|
let resolved;
|
|
21088
21121
|
try {
|
|
@@ -21090,7 +21123,7 @@ async function resolveWorkspaceReference(input) {
|
|
|
21090
21123
|
} catch {
|
|
21091
21124
|
throw new SacReferenceError("workspace reference is not resolvable");
|
|
21092
21125
|
}
|
|
21093
|
-
if (resolved !== root && !resolved.startsWith(`${root}${
|
|
21126
|
+
if (resolved !== root && !resolved.startsWith(`${root}${path75.sep}`))
|
|
21094
21127
|
throw new SacReferenceError("workspace reference escapes root after realpath");
|
|
21095
21128
|
return candidate;
|
|
21096
21129
|
}
|
|
@@ -21146,16 +21179,16 @@ async function evaluateStrictSacGuard(input) {
|
|
|
21146
21179
|
init_fs();
|
|
21147
21180
|
import { mkdir as mkdir27, readdir as readdir13, readFile as readFile39 } from "fs/promises";
|
|
21148
21181
|
import { createHash as createHash12, randomUUID as randomUUID3 } from "crypto";
|
|
21149
|
-
import
|
|
21182
|
+
import path77 from "path";
|
|
21150
21183
|
|
|
21151
21184
|
// src/sac/secure-resource-read.ts
|
|
21152
21185
|
init_contained_read();
|
|
21153
21186
|
init_descriptor_read();
|
|
21154
|
-
import
|
|
21187
|
+
import path76 from "path";
|
|
21155
21188
|
function readWorkspaceFileNoFollow(workspaceRoot, absolutePath) {
|
|
21156
|
-
const relativePath =
|
|
21157
|
-
const components = relativePath.split(
|
|
21158
|
-
if (!relativePath ||
|
|
21189
|
+
const relativePath = path76.relative(workspaceRoot, absolutePath);
|
|
21190
|
+
const components = relativePath.split(path76.sep);
|
|
21191
|
+
if (!relativePath || path76.isAbsolute(relativePath) || components.some((component) => !component || component === "." || component === "..")) {
|
|
21159
21192
|
throw new Error("safe source path is not workspace-relative");
|
|
21160
21193
|
}
|
|
21161
21194
|
return readDescriptorChain(workspaceRoot, absolutePath, {
|
|
@@ -21182,8 +21215,8 @@ class WorkspaceService {
|
|
|
21182
21215
|
now;
|
|
21183
21216
|
constructor(options) {
|
|
21184
21217
|
this.options = options;
|
|
21185
|
-
this.root =
|
|
21186
|
-
this.storageRoot =
|
|
21218
|
+
this.root = path77.resolve(options.workspaceRoot);
|
|
21219
|
+
this.storageRoot = path77.resolve(options.storageRoot ?? path77.join(this.root, ".metaproject", "workspaces"));
|
|
21187
21220
|
this.now = options.now ?? (() => new Date);
|
|
21188
21221
|
}
|
|
21189
21222
|
async create(input) {
|
|
@@ -21508,13 +21541,13 @@ class WorkspaceService {
|
|
|
21508
21541
|
return parsed;
|
|
21509
21542
|
}
|
|
21510
21543
|
workspaceDir(id) {
|
|
21511
|
-
return
|
|
21544
|
+
return path77.join(this.storageRoot, id);
|
|
21512
21545
|
}
|
|
21513
21546
|
manifestPath(id) {
|
|
21514
|
-
return
|
|
21547
|
+
return path77.join(this.workspaceDir(id), "workspace.json");
|
|
21515
21548
|
}
|
|
21516
21549
|
lockPath(id) {
|
|
21517
|
-
return
|
|
21550
|
+
return path77.join(this.storageRoot, `.${id}.lock`);
|
|
21518
21551
|
}
|
|
21519
21552
|
timestamp() {
|
|
21520
21553
|
return this.now().toISOString();
|
|
@@ -22303,7 +22336,7 @@ function hasReportIntegrity(report) {
|
|
|
22303
22336
|
return reportHashPattern.test(reportDigest) && sha2563(body) === reportDigest;
|
|
22304
22337
|
}
|
|
22305
22338
|
async function resolvePolicySelection(workspaceRoot, canonicalFallback) {
|
|
22306
|
-
const configPath =
|
|
22339
|
+
const configPath = path78.join(workspaceRoot, ...policyExperimentConfigPath);
|
|
22307
22340
|
let configJson;
|
|
22308
22341
|
try {
|
|
22309
22342
|
const raw = await readFile40(configPath, "utf8").catch((error) => {
|
|
@@ -22501,9 +22534,9 @@ class FwkReadService {
|
|
|
22501
22534
|
const recordedAt = nowIso(now);
|
|
22502
22535
|
const id = `receipt-${randomUUID4().replace(/-/g, "").slice(0, 16)}`;
|
|
22503
22536
|
const base = { schemaVersion: "1.0", id, workspaceId, actor, action, decision, recordedAt, cost: { tokens: 0, toolCalls: 1, elapsedMs: 0 }, contextAssembly: { traceRef: assembly.traceRef, configurationRevision: assembly.configurationRevision, selected: assembly.selected.map((id) => `./ids/${id}`), omittedOptional: assembly.omittedOptional.map((id) => `./ids/${id}`) }, policy: { ref: assembly.policyRef, revision: assembly.policyRevision }, ...action === "resource" ? { resourceRef: `./ids/${resourceId ?? "unknown"}` } : {} };
|
|
22504
|
-
const ledger =
|
|
22505
|
-
const checkpointPath =
|
|
22506
|
-
await mkdir28(
|
|
22537
|
+
const ledger = path78.join(this.options.canonical.workspaceRoot, ".metaproject", "context-operations", "access-receipts.jsonl");
|
|
22538
|
+
const checkpointPath = path78.join(path78.dirname(ledger), "access-receipts.checkpoint.json");
|
|
22539
|
+
await mkdir28(path78.dirname(ledger), { recursive: true, mode: 448 });
|
|
22507
22540
|
return withFileLock(`${ledger}.lock`, async () => {
|
|
22508
22541
|
const state = await resolveLedgerState(ledger, checkpointPath, this.options.verifyReceiptLedger ?? verifyAccessReceiptLedger);
|
|
22509
22542
|
const receipt = sealAccessReceipt(base, state.headHash);
|
|
@@ -22607,7 +22640,7 @@ function normalizeFwkResult(result) {
|
|
|
22607
22640
|
init_fs();
|
|
22608
22641
|
import { createHash as createHash22, randomUUID as randomUUID7 } from "crypto";
|
|
22609
22642
|
import { appendFile as appendFile6, mkdir as mkdir32, readdir as readdir15, readFile as readFile49 } from "fs/promises";
|
|
22610
|
-
import
|
|
22643
|
+
import path88 from "path";
|
|
22611
22644
|
|
|
22612
22645
|
// src/sac/trusted-wrap-up.ts
|
|
22613
22646
|
import { createHash as createHash16, randomUUID as randomUUID5 } from "crypto";
|
|
@@ -22679,7 +22712,7 @@ function bindingHash(owner, intent) {
|
|
|
22679
22712
|
// src/sac/session-wrap-up.ts
|
|
22680
22713
|
import { createHash as createHash18 } from "crypto";
|
|
22681
22714
|
import { mkdir as mkdir30, writeFile as writeFile22 } from "fs/promises";
|
|
22682
|
-
import
|
|
22715
|
+
import path82 from "path";
|
|
22683
22716
|
|
|
22684
22717
|
// src/session/store.ts
|
|
22685
22718
|
import {
|
|
@@ -22690,7 +22723,7 @@ import {
|
|
|
22690
22723
|
renameSync as renameSync2,
|
|
22691
22724
|
writeFileSync as writeFileSync2
|
|
22692
22725
|
} from "fs";
|
|
22693
|
-
import
|
|
22726
|
+
import path81 from "path";
|
|
22694
22727
|
|
|
22695
22728
|
// src/lib/config-dir.ts
|
|
22696
22729
|
import {
|
|
@@ -22735,7 +22768,7 @@ function readTranscriptFile(file) {
|
|
|
22735
22768
|
// src/session/paths.ts
|
|
22736
22769
|
import { existsSync as existsSync12 } from "fs";
|
|
22737
22770
|
import { homedir } from "os";
|
|
22738
|
-
import
|
|
22771
|
+
import path79 from "path";
|
|
22739
22772
|
function keryxDataDir(override) {
|
|
22740
22773
|
if (override !== undefined && override.length > 0) {
|
|
22741
22774
|
return override;
|
|
@@ -22747,22 +22780,22 @@ function keryxDataDir(override) {
|
|
|
22747
22780
|
const home = homedir();
|
|
22748
22781
|
if (process.platform === "win32") {
|
|
22749
22782
|
const appData = process.env.APPDATA;
|
|
22750
|
-
const base = appData !== undefined && appData.length > 0 ? appData :
|
|
22751
|
-
return
|
|
22783
|
+
const base = appData !== undefined && appData.length > 0 ? appData : path79.join(home, "AppData", "Roaming");
|
|
22784
|
+
return path79.join(base, "keryx");
|
|
22752
22785
|
}
|
|
22753
22786
|
const xdg = process.env.XDG_DATA_HOME;
|
|
22754
|
-
const base = xdg !== undefined && xdg.length > 0 ? xdg :
|
|
22755
|
-
return
|
|
22787
|
+
const base = xdg !== undefined && xdg.length > 0 ? xdg : path79.join(home, ".local", "share");
|
|
22788
|
+
return path79.join(base, "keryx");
|
|
22756
22789
|
}
|
|
22757
22790
|
function resolveProjectRoot2(cwd) {
|
|
22758
|
-
const abs =
|
|
22791
|
+
const abs = path79.resolve(cwd);
|
|
22759
22792
|
let dir = abs;
|
|
22760
22793
|
for (;; ) {
|
|
22761
|
-
const gitPath =
|
|
22794
|
+
const gitPath = path79.join(dir, ".git");
|
|
22762
22795
|
if (existsSync12(gitPath)) {
|
|
22763
22796
|
return dir;
|
|
22764
22797
|
}
|
|
22765
|
-
const parent =
|
|
22798
|
+
const parent = path79.dirname(dir);
|
|
22766
22799
|
if (parent === dir) {
|
|
22767
22800
|
break;
|
|
22768
22801
|
}
|
|
@@ -22771,12 +22804,12 @@ function resolveProjectRoot2(cwd) {
|
|
|
22771
22804
|
return abs;
|
|
22772
22805
|
}
|
|
22773
22806
|
function projectKeyFromPath(projectPath) {
|
|
22774
|
-
const abs =
|
|
22807
|
+
const abs = path79.resolve(projectPath);
|
|
22775
22808
|
const encoded = encodeURIComponent(abs);
|
|
22776
22809
|
if (encoded.length <= 200) {
|
|
22777
22810
|
return encoded;
|
|
22778
22811
|
}
|
|
22779
|
-
const base =
|
|
22812
|
+
const base = path79.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40);
|
|
22780
22813
|
let h = 0;
|
|
22781
22814
|
for (let i = 0;i < abs.length; i++) {
|
|
22782
22815
|
h = Math.imul(31, h) + abs.charCodeAt(i) | 0;
|
|
@@ -22786,17 +22819,17 @@ function projectKeyFromPath(projectPath) {
|
|
|
22786
22819
|
}
|
|
22787
22820
|
function projectSessionsDir(projectPath, dataDir) {
|
|
22788
22821
|
const key = projectKeyFromPath(resolveProjectRoot2(projectPath));
|
|
22789
|
-
return
|
|
22822
|
+
return path79.join(keryxDataDir(dataDir), "sessions", key);
|
|
22790
22823
|
}
|
|
22791
22824
|
function sessionDir(projectPath, sessionId, dataDir) {
|
|
22792
|
-
return
|
|
22825
|
+
return path79.join(projectSessionsDir(projectPath, dataDir), sessionId);
|
|
22793
22826
|
}
|
|
22794
22827
|
|
|
22795
22828
|
// src/session/slate.ts
|
|
22796
22829
|
init_fs();
|
|
22797
22830
|
init_assembly();
|
|
22798
22831
|
import { mkdir as mkdir29, readFile as readFile41, rm as rm6 } from "fs/promises";
|
|
22799
|
-
import
|
|
22832
|
+
import path80 from "path";
|
|
22800
22833
|
init_redact();
|
|
22801
22834
|
var SLATE_SEED_KINDS = [
|
|
22802
22835
|
"decision",
|
|
@@ -22811,7 +22844,7 @@ function isSlateSeedKind(value) {
|
|
|
22811
22844
|
}
|
|
22812
22845
|
var SEED_TEXT_MAX_LENGTH = 4000;
|
|
22813
22846
|
function slatePath(dir) {
|
|
22814
|
-
return
|
|
22847
|
+
return path80.join(dir, "slate.json");
|
|
22815
22848
|
}
|
|
22816
22849
|
function slateLockPath(dir) {
|
|
22817
22850
|
return `${slatePath(dir)}.lock`;
|
|
@@ -23014,11 +23047,11 @@ function listSessions(cwd, dataDir) {
|
|
|
23014
23047
|
if (name.startsWith(".")) {
|
|
23015
23048
|
continue;
|
|
23016
23049
|
}
|
|
23017
|
-
const summary = readSummaryFile(
|
|
23050
|
+
const summary = readSummaryFile(path81.join(root, name, "summary.json"));
|
|
23018
23051
|
if (summary === undefined) {
|
|
23019
23052
|
continue;
|
|
23020
23053
|
}
|
|
23021
|
-
if (
|
|
23054
|
+
if (path81.resolve(summary.projectPath) !== path81.resolve(projectPath)) {
|
|
23022
23055
|
continue;
|
|
23023
23056
|
}
|
|
23024
23057
|
out.push(summary);
|
|
@@ -23051,15 +23084,15 @@ async function readSessionSlate(cwd, sessionId, dataDir) {
|
|
|
23051
23084
|
}
|
|
23052
23085
|
function loadContext(cwd, sessionId, dataDir) {
|
|
23053
23086
|
const dir = sessionDir(resolveProjectRoot2(cwd), sessionId, dataDir);
|
|
23054
|
-
const contextPath =
|
|
23087
|
+
const contextPath = path81.join(dir, "context.jsonl");
|
|
23055
23088
|
if (existsSync13(contextPath)) {
|
|
23056
23089
|
return readJsonl2(contextPath);
|
|
23057
23090
|
}
|
|
23058
|
-
return readJsonl2(
|
|
23091
|
+
return readJsonl2(path81.join(dir, "transcript.jsonl"));
|
|
23059
23092
|
}
|
|
23060
23093
|
function loadArchive(cwd, sessionId, dataDir, onDegraded) {
|
|
23061
23094
|
const dir = sessionDir(resolveProjectRoot2(cwd), sessionId, dataDir);
|
|
23062
|
-
const archivePath =
|
|
23095
|
+
const archivePath = path81.join(dir, "archive.jsonl");
|
|
23063
23096
|
if (existsSync13(archivePath)) {
|
|
23064
23097
|
try {
|
|
23065
23098
|
const archive = readJsonl2(archivePath);
|
|
@@ -23243,7 +23276,7 @@ function sessionEvidenceRef(workspaceId, sessionId) {
|
|
|
23243
23276
|
}
|
|
23244
23277
|
async function resolveSessionWrapUp(input) {
|
|
23245
23278
|
const now = input.now ?? (() => new Date);
|
|
23246
|
-
const sessionId =
|
|
23279
|
+
const sessionId = path82.posix.basename(input.sourceRef, ".md");
|
|
23247
23280
|
const summary = findSession(input.cwd, sessionId);
|
|
23248
23281
|
if (summary === undefined || input.sourceRef !== sessionEvidenceRef(input.workspaceId, summary.id)) {
|
|
23249
23282
|
throw new SessionWrapUpError("session_not_found", `no session matching "${input.sourceRef}" in this project \u2014 use \`keryx sessions list\``);
|
|
@@ -23260,7 +23293,7 @@ async function resolveSessionWrapUp(input) {
|
|
|
23260
23293
|
throw new SessionWrapUpError("session_unreadable", `session "${summary.id}" could not be read: ${cause.message}`);
|
|
23261
23294
|
}
|
|
23262
23295
|
const relPath = sessionEvidenceRef(input.workspaceId, summary.id).slice(2);
|
|
23263
|
-
const evidenceDir =
|
|
23296
|
+
const evidenceDir = path82.dirname(relPath);
|
|
23264
23297
|
const slate = await readSessionSlate(input.cwd, summary.id);
|
|
23265
23298
|
const diff = await gitDiff(input.cwd);
|
|
23266
23299
|
const diffBody = diff.kind === "measured" ? diff.text : unmeasurableDiffBody(diff.detail);
|
|
@@ -23282,23 +23315,23 @@ async function resolveSessionWrapUp(input) {
|
|
|
23282
23315
|
""
|
|
23283
23316
|
].join(`
|
|
23284
23317
|
`);
|
|
23285
|
-
const wrapUpRelPath =
|
|
23286
|
-
const diffRelPath =
|
|
23287
|
-
const noticeRelPath =
|
|
23318
|
+
const wrapUpRelPath = path82.join(evidenceDir, `${summary.id}.wrap-up.md`);
|
|
23319
|
+
const diffRelPath = path82.join(evidenceDir, `${summary.id}.diff.txt`);
|
|
23320
|
+
const noticeRelPath = path82.join(evidenceDir, `${summary.id}.redaction.md`);
|
|
23288
23321
|
const floor = await applyEvidenceRedactionFloor(input.cwd, [
|
|
23289
|
-
{ name:
|
|
23290
|
-
{ name:
|
|
23291
|
-
{ name:
|
|
23322
|
+
{ name: path82.basename(relPath), content: markdown, path: relPath, source: "generated" },
|
|
23323
|
+
{ name: path82.basename(wrapUpRelPath), content: wrapUpMarkdown, path: wrapUpRelPath, source: "generated" },
|
|
23324
|
+
{ name: path82.basename(diffRelPath), content: diffBody, path: diffRelPath, source: "tool-output" }
|
|
23292
23325
|
]);
|
|
23293
23326
|
if (!floor.ok)
|
|
23294
23327
|
throw new SessionWrapUpError("security_denied", floor.reason);
|
|
23295
23328
|
const [safeSession, safeWrapUp, safeDiff] = floor.bodies;
|
|
23296
|
-
await mkdir30(
|
|
23297
|
-
await writeFile22(
|
|
23298
|
-
await writeFile22(
|
|
23299
|
-
await writeFile22(
|
|
23329
|
+
await mkdir30(path82.join(input.cwd, evidenceDir), { recursive: true });
|
|
23330
|
+
await writeFile22(path82.join(input.cwd, relPath), safeSession.content, "utf8");
|
|
23331
|
+
await writeFile22(path82.join(input.cwd, wrapUpRelPath), safeWrapUp.content, "utf8");
|
|
23332
|
+
await writeFile22(path82.join(input.cwd, diffRelPath), safeDiff.content, "utf8");
|
|
23300
23333
|
if (floor.notice !== undefined)
|
|
23301
|
-
await writeFile22(
|
|
23334
|
+
await writeFile22(path82.join(input.cwd, noticeRelPath), floor.notice, "utf8");
|
|
23302
23335
|
const observedAt = now().toISOString();
|
|
23303
23336
|
const evidence = [
|
|
23304
23337
|
{ kind: "wrap-up", uri: `./${wrapUpRelPath}`, revision: createHash18("sha256").update(safeWrapUp.content).digest("hex"), observedAt },
|
|
@@ -23321,13 +23354,13 @@ async function resolveSessionWrapUp(input) {
|
|
|
23321
23354
|
init_fs();
|
|
23322
23355
|
import { createHash as createHash19, randomBytes as randomBytes2 } from "crypto";
|
|
23323
23356
|
import { readFile as readFile42 } from "fs/promises";
|
|
23324
|
-
import
|
|
23357
|
+
import path83 from "path";
|
|
23325
23358
|
var CONFIRM_TOKEN_TTL_MS = 2 * 60000;
|
|
23326
23359
|
function confirmTokenPath(cwd, workspaceId, proposalId) {
|
|
23327
|
-
return
|
|
23360
|
+
return path83.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.confirm-token.json`);
|
|
23328
23361
|
}
|
|
23329
23362
|
function confirmReceiptPath(cwd, workspaceId, proposalId, idempotencyKey) {
|
|
23330
|
-
return
|
|
23363
|
+
return path83.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${sha2564(idempotencyKey)}.confirm-receipt.json`);
|
|
23331
23364
|
}
|
|
23332
23365
|
function sha2564(text) {
|
|
23333
23366
|
return createHash19("sha256").update(text).digest("hex");
|
|
@@ -23365,7 +23398,7 @@ async function consumeConfirmToken(cwd, workspaceId, proposalId, idempotencyKey,
|
|
|
23365
23398
|
// src/sac/decision-dedup.ts
|
|
23366
23399
|
import { readFile as readFile44, readdir as readdir14 } from "fs/promises";
|
|
23367
23400
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
23368
|
-
import
|
|
23401
|
+
import path85 from "path";
|
|
23369
23402
|
init_store();
|
|
23370
23403
|
init_config();
|
|
23371
23404
|
|
|
@@ -23373,15 +23406,15 @@ init_config();
|
|
|
23373
23406
|
init_fs();
|
|
23374
23407
|
import { createHash as createHash20 } from "crypto";
|
|
23375
23408
|
import { readFile as readFile43, rm as rm7 } from "fs/promises";
|
|
23376
|
-
import
|
|
23409
|
+
import path84 from "path";
|
|
23377
23410
|
function proposalPath(cwd, workspaceId, proposalId) {
|
|
23378
|
-
return
|
|
23411
|
+
return path84.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
|
|
23379
23412
|
}
|
|
23380
23413
|
function ownerReceiptPath(cwd, owner, workspaceId, idempotencyKey) {
|
|
23381
|
-
return
|
|
23414
|
+
return path84.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-receipts`, `${idempotencyKey}.json`);
|
|
23382
23415
|
}
|
|
23383
23416
|
function proposalNotePath(cwd, workspaceId, proposalId) {
|
|
23384
|
-
return
|
|
23417
|
+
return path84.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.note.txt`);
|
|
23385
23418
|
}
|
|
23386
23419
|
async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
|
|
23387
23420
|
let proposal;
|
|
@@ -23395,7 +23428,7 @@ async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
|
|
|
23395
23428
|
return { ok: false, code: "no_evidence_to_write" };
|
|
23396
23429
|
let content;
|
|
23397
23430
|
try {
|
|
23398
|
-
content = await readFile43(
|
|
23431
|
+
content = await readFile43(path84.join(cwd, evidence.uri), "utf8");
|
|
23399
23432
|
} catch {
|
|
23400
23433
|
return { ok: false, code: "evidence_file_unreadable" };
|
|
23401
23434
|
}
|
|
@@ -23425,22 +23458,22 @@ function targetRelPath(targetRef) {
|
|
|
23425
23458
|
return targetRef.replace(/^\.\//, "");
|
|
23426
23459
|
}
|
|
23427
23460
|
function targetAbsolutePath(cwd, targetRef) {
|
|
23428
|
-
return
|
|
23461
|
+
return path84.join(cwd, ".metaproject", targetRelPath(targetRef));
|
|
23429
23462
|
}
|
|
23430
23463
|
function targetKey(targetRef) {
|
|
23431
23464
|
return digestOf2(targetRelPath(targetRef)).slice(0, 32);
|
|
23432
23465
|
}
|
|
23433
23466
|
function ownerTargetVersionPath(cwd, owner, workspaceId, targetRef) {
|
|
23434
|
-
return
|
|
23467
|
+
return path84.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-target-versions`, `${targetKey(targetRef)}.json`);
|
|
23435
23468
|
}
|
|
23436
23469
|
function ownerTargetLockPath(cwd, owner, targetRef) {
|
|
23437
|
-
return
|
|
23470
|
+
return path84.join(cwd, ".metaproject", "data", "sac", "target-locks", owner, `${targetKey(targetRef)}.lock`);
|
|
23438
23471
|
}
|
|
23439
23472
|
function ownerStagingDir(cwd, owner, workspaceId, idempotencyKey) {
|
|
23440
|
-
return
|
|
23473
|
+
return path84.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-staging`, digestOf2(idempotencyKey).slice(0, 32));
|
|
23441
23474
|
}
|
|
23442
23475
|
function ownerConflictDir(cwd, owner, workspaceId, idempotencyKey) {
|
|
23443
|
-
return
|
|
23476
|
+
return path84.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-conflicts`, digestOf2(idempotencyKey).slice(0, 32));
|
|
23444
23477
|
}
|
|
23445
23478
|
async function readJson2(file) {
|
|
23446
23479
|
try {
|
|
@@ -23511,7 +23544,7 @@ async function applyGuardedTargetWrite(input) {
|
|
|
23511
23544
|
staged: input.staged,
|
|
23512
23545
|
stagedAt: receipt.completedAt
|
|
23513
23546
|
};
|
|
23514
|
-
await writeFileAtomic(
|
|
23547
|
+
await writeFileAtomic(path84.join(ownerStagingDir(cwd, owner, intent.workspaceId, intent.idempotencyKey), "plan.json"), `${JSON.stringify(staged, null, 2)}
|
|
23515
23548
|
`);
|
|
23516
23549
|
const applied = await input.apply(input.staged);
|
|
23517
23550
|
if (!applied.ok) {
|
|
@@ -23537,15 +23570,15 @@ async function recoverStagedOwnerWrite(input) {
|
|
|
23537
23570
|
});
|
|
23538
23571
|
}
|
|
23539
23572
|
async function readStagedOwnerWrite(cwd, owner, workspaceId, idempotencyKey) {
|
|
23540
|
-
return readJson2(
|
|
23573
|
+
return readJson2(path84.join(ownerStagingDir(cwd, owner, workspaceId, idempotencyKey), "plan.json"));
|
|
23541
23574
|
}
|
|
23542
23575
|
async function recordConflict(input) {
|
|
23543
23576
|
const base = { targetRef: input.targetRef, expectedVersion: input.expectedVersion, currentVersion: input.currentVersion };
|
|
23544
23577
|
if (input.proposedContent === undefined)
|
|
23545
23578
|
return base;
|
|
23546
23579
|
const dir = ownerConflictDir(input.cwd, input.owner, input.intent.workspaceId, input.intent.idempotencyKey);
|
|
23547
|
-
await writeFileAtomic(
|
|
23548
|
-
const diffRef = `./workspaces/${input.intent.workspaceId}/${input.owner}-write-conflicts/${
|
|
23580
|
+
await writeFileAtomic(path84.join(dir, "proposed"), input.proposedContent);
|
|
23581
|
+
const diffRef = `./workspaces/${input.intent.workspaceId}/${input.owner}-write-conflicts/${path84.basename(dir)}/proposed`;
|
|
23549
23582
|
return { ...base, diffRef };
|
|
23550
23583
|
}
|
|
23551
23584
|
|
|
@@ -23595,7 +23628,7 @@ async function resolveWorkspaceModule(cwd, workspaceId) {
|
|
|
23595
23628
|
}
|
|
23596
23629
|
}
|
|
23597
23630
|
async function collectWikiDecisionEntries(cwd) {
|
|
23598
|
-
const dir =
|
|
23631
|
+
const dir = path85.join(cwd, ".metaproject", "wiki", "decisions");
|
|
23599
23632
|
let files;
|
|
23600
23633
|
try {
|
|
23601
23634
|
files = (await readdir14(dir)).filter((name) => name.endsWith(".md"));
|
|
@@ -23604,12 +23637,12 @@ async function collectWikiDecisionEntries(cwd) {
|
|
|
23604
23637
|
}
|
|
23605
23638
|
const entries = [];
|
|
23606
23639
|
for (const file of files) {
|
|
23607
|
-
const absolutePath =
|
|
23640
|
+
const absolutePath = path85.join(dir, file);
|
|
23608
23641
|
try {
|
|
23609
23642
|
const content = await readFile44(absolutePath, "utf8");
|
|
23610
23643
|
entries.push({
|
|
23611
23644
|
absolutePath,
|
|
23612
|
-
relativePath:
|
|
23645
|
+
relativePath: path85.posix.join("decisions", file),
|
|
23613
23646
|
type: extractHeaderField(content, "Type") ?? "decision",
|
|
23614
23647
|
title: extractTitle(content),
|
|
23615
23648
|
version: extractHeaderField(content, "Version") ?? null,
|
|
@@ -23830,7 +23863,7 @@ function createRealMemoryOwnerWriter(cwd, opts) {
|
|
|
23830
23863
|
init_fs();
|
|
23831
23864
|
init_guard();
|
|
23832
23865
|
import { readFile as readFile46 } from "fs/promises";
|
|
23833
|
-
import
|
|
23866
|
+
import path86 from "path";
|
|
23834
23867
|
function renderWrapUpDecisionPage(input) {
|
|
23835
23868
|
const note = input.note?.trim();
|
|
23836
23869
|
return `# ${input.title}
|
|
@@ -23871,14 +23904,14 @@ export is the source of truth for what actually happened.
|
|
|
23871
23904
|
`;
|
|
23872
23905
|
}
|
|
23873
23906
|
function wikiPageRelativePath(proposalId) {
|
|
23874
|
-
return
|
|
23907
|
+
return path86.posix.join("decisions", `sac-${proposalId}.md`);
|
|
23875
23908
|
}
|
|
23876
23909
|
function createRealWikiOwnerWriter(cwd, opts) {
|
|
23877
23910
|
const now = opts?.now ?? (() => new Date);
|
|
23878
23911
|
const applyStaged = async (staged) => {
|
|
23879
23912
|
const relativePath = staged.relativePath;
|
|
23880
23913
|
const content = staged.content;
|
|
23881
|
-
await writeFileAtomic(
|
|
23914
|
+
await writeFileAtomic(path86.join(cwd, ".metaproject", "wiki", relativePath), content);
|
|
23882
23915
|
return { ok: true };
|
|
23883
23916
|
};
|
|
23884
23917
|
return {
|
|
@@ -23947,10 +23980,10 @@ init_guard();
|
|
|
23947
23980
|
import { createHash as createHash21 } from "crypto";
|
|
23948
23981
|
import { homedir as homedir2 } from "os";
|
|
23949
23982
|
import { mkdir as mkdir31, readFile as readFile47, stat as stat10 } from "fs/promises";
|
|
23950
|
-
import
|
|
23983
|
+
import path87 from "path";
|
|
23951
23984
|
var VERSION = "0.1.0";
|
|
23952
23985
|
async function createProjectSkill(projectRoot, options) {
|
|
23953
|
-
const metaprojectRoot =
|
|
23986
|
+
const metaprojectRoot = path87.join(projectRoot, ".metaproject");
|
|
23954
23987
|
if (!await pathExists(metaprojectRoot)) {
|
|
23955
23988
|
throw new Error("Metaproject is not initialized. Run: keryx init");
|
|
23956
23989
|
}
|
|
@@ -23960,8 +23993,8 @@ async function createProjectSkill(projectRoot, options) {
|
|
|
23960
23993
|
const moduleName = slugify5(options.module ?? inferModule(options.target));
|
|
23961
23994
|
const skillName = slugify5(options.name ?? inferSkillName(options.target));
|
|
23962
23995
|
const format = options.format ?? "auto";
|
|
23963
|
-
const packageRoot =
|
|
23964
|
-
const relativeSkillPath = toPosix(
|
|
23996
|
+
const packageRoot = path87.join(metaprojectRoot, "project-skills", moduleName, skillName);
|
|
23997
|
+
const relativeSkillPath = toPosix(path87.relative(projectRoot, packageRoot));
|
|
23965
23998
|
const origin = options.origin ? options.originContent !== undefined ? {
|
|
23966
23999
|
ref: options.origin.trim(),
|
|
23967
24000
|
hash: hashOriginContent(options.originContent),
|
|
@@ -23971,7 +24004,7 @@ async function createProjectSkill(projectRoot, options) {
|
|
|
23971
24004
|
const warnings = collectWarnings(evidence, format);
|
|
23972
24005
|
const files = filesForPackage(packageRoot, format);
|
|
23973
24006
|
if (!options.dryRun) {
|
|
23974
|
-
await withFileLock(
|
|
24007
|
+
await withFileLock(path87.join(metaprojectRoot, "data", "gdskills", "project-skills.lock"), async () => {
|
|
23975
24008
|
await writeProjectSkillPackage({
|
|
23976
24009
|
projectRoot,
|
|
23977
24010
|
packageRoot,
|
|
@@ -24000,7 +24033,7 @@ async function createProjectSkill(projectRoot, options) {
|
|
|
24000
24033
|
name: skillName,
|
|
24001
24034
|
target: options.target,
|
|
24002
24035
|
skillPath: relativeSkillPath,
|
|
24003
|
-
files: files.map((filePath) => toPosix(
|
|
24036
|
+
files: files.map((filePath) => toPosix(path87.relative(projectRoot, filePath))),
|
|
24004
24037
|
warnings,
|
|
24005
24038
|
dryRun: options.dryRun === true
|
|
24006
24039
|
};
|
|
@@ -24009,9 +24042,9 @@ var MAX_SKILL_TARGET_LENGTH = 80;
|
|
|
24009
24042
|
function resolveOriginPath(ref, projectRoot) {
|
|
24010
24043
|
const trimmed = ref.trim();
|
|
24011
24044
|
if (trimmed === "~" || trimmed.startsWith("~/")) {
|
|
24012
|
-
return
|
|
24045
|
+
return path87.join(homedir2(), trimmed.slice(1));
|
|
24013
24046
|
}
|
|
24014
|
-
return
|
|
24047
|
+
return path87.resolve(projectRoot, trimmed);
|
|
24015
24048
|
}
|
|
24016
24049
|
function hashOriginContent(content) {
|
|
24017
24050
|
return `sha256:${createHash21("sha256").update(content).digest("hex")}`;
|
|
@@ -24049,32 +24082,32 @@ async function writeProjectSkillPackage({
|
|
|
24049
24082
|
}) {
|
|
24050
24083
|
const packageFormat = format === "single" ? "single" : "package";
|
|
24051
24084
|
const skillContent = renderProjectSkill({ moduleName, skillName, target, note, origin, evidence, packageFormat });
|
|
24052
|
-
const relativeSkillMdPath = toPosix(
|
|
24085
|
+
const relativeSkillMdPath = toPosix(path87.join(path87.relative(projectRoot, packageRoot), "SKILL.md"));
|
|
24053
24086
|
const guard = await guardOutput({ cwd: projectRoot, content: skillContent, target: "skill", source: "generated", path: relativeSkillMdPath });
|
|
24054
24087
|
const output = prepareOutputForPersistence(guard, skillContent);
|
|
24055
24088
|
if (!output.allowed) {
|
|
24056
24089
|
throw new Error(`Project skill blocked by the security gate: ${output.reason}`);
|
|
24057
24090
|
}
|
|
24058
24091
|
await mkdir31(packageRoot, { recursive: true });
|
|
24059
|
-
const skillPath =
|
|
24092
|
+
const skillPath = path87.join(packageRoot, "SKILL.md");
|
|
24060
24093
|
await writeFileAtomic(skillPath, output.content);
|
|
24061
|
-
const changelogPath =
|
|
24094
|
+
const changelogPath = path87.join(packageRoot, "skill-changelog.md");
|
|
24062
24095
|
if (!await pathExists(changelogPath)) {
|
|
24063
24096
|
await writeFileAtomic(changelogPath, renderSkillChangelog({ moduleName, skillName, target }));
|
|
24064
24097
|
}
|
|
24065
24098
|
if (packageFormat === "package") {
|
|
24066
|
-
await mkdir31(
|
|
24067
|
-
await mkdir31(
|
|
24068
|
-
await writeFileAtomic(
|
|
24069
|
-
await writeFileAtomic(
|
|
24070
|
-
await writeFileAtomic(
|
|
24099
|
+
await mkdir31(path87.join(packageRoot, "references"), { recursive: true });
|
|
24100
|
+
await mkdir31(path87.join(packageRoot, "templates"), { recursive: true });
|
|
24101
|
+
await writeFileAtomic(path87.join(packageRoot, "references", "context.md"), renderReferenceContext({ moduleName, skillName, target, evidence }));
|
|
24102
|
+
await writeFileAtomic(path87.join(packageRoot, "templates", "README.md"), renderTemplatesReadme({ moduleName, skillName }));
|
|
24103
|
+
await writeFileAtomic(path87.join(packageRoot, "verification.md"), renderVerification({ moduleName, skillName, evidence }));
|
|
24071
24104
|
}
|
|
24072
24105
|
}
|
|
24073
24106
|
async function collectEvidence(projectRoot, target) {
|
|
24074
|
-
const absoluteTarget =
|
|
24107
|
+
const absoluteTarget = path87.resolve(projectRoot, target);
|
|
24075
24108
|
const targetExists = await pathExists(absoluteTarget);
|
|
24076
24109
|
const targetKind = await classifyTarget(absoluteTarget, targetExists);
|
|
24077
|
-
const maybeRelativeTarget = targetExists ? toPosix(
|
|
24110
|
+
const maybeRelativeTarget = targetExists ? toPosix(path87.relative(projectRoot, absoluteTarget)) : undefined;
|
|
24078
24111
|
const graphArtifacts = await existingRelativePaths(projectRoot, [
|
|
24079
24112
|
".metaproject/data/gdgraph/artifacts/summary.md",
|
|
24080
24113
|
".metaproject/data/gdgraph/artifacts/module-map.json"
|
|
@@ -24104,7 +24137,7 @@ async function classifyTarget(absoluteTarget, targetExists) {
|
|
|
24104
24137
|
async function existingRelativePaths(projectRoot, candidates) {
|
|
24105
24138
|
const existing = [];
|
|
24106
24139
|
for (const candidate of candidates) {
|
|
24107
|
-
if (await pathExists(
|
|
24140
|
+
if (await pathExists(path87.join(projectRoot, candidate))) {
|
|
24108
24141
|
existing.push(candidate);
|
|
24109
24142
|
}
|
|
24110
24143
|
}
|
|
@@ -24131,17 +24164,17 @@ function collectWarnings(evidence, format) {
|
|
|
24131
24164
|
}
|
|
24132
24165
|
function filesForPackage(packageRoot, format) {
|
|
24133
24166
|
const base = [
|
|
24134
|
-
|
|
24135
|
-
|
|
24167
|
+
path87.join(packageRoot, "SKILL.md"),
|
|
24168
|
+
path87.join(packageRoot, "skill-changelog.md")
|
|
24136
24169
|
];
|
|
24137
24170
|
if (format === "single") {
|
|
24138
24171
|
return base;
|
|
24139
24172
|
}
|
|
24140
24173
|
return [
|
|
24141
24174
|
...base,
|
|
24142
|
-
|
|
24143
|
-
|
|
24144
|
-
|
|
24175
|
+
path87.join(packageRoot, "verification.md"),
|
|
24176
|
+
path87.join(packageRoot, "references", "context.md"),
|
|
24177
|
+
path87.join(packageRoot, "templates", "README.md")
|
|
24145
24178
|
];
|
|
24146
24179
|
}
|
|
24147
24180
|
function renderProjectSkill({
|
|
@@ -24369,7 +24402,7 @@ keryx skills verify ${moduleName}/${skillName}
|
|
|
24369
24402
|
`;
|
|
24370
24403
|
}
|
|
24371
24404
|
async function updateManifest(projectRoot, entry) {
|
|
24372
|
-
const manifestPath =
|
|
24405
|
+
const manifestPath = path87.join(projectRoot, ".metaproject", "metaproject.json");
|
|
24373
24406
|
const manifest = await readJsonFileOr(manifestPath, {});
|
|
24374
24407
|
manifest.modules ??= {};
|
|
24375
24408
|
manifest.modules.gdskills ??= {};
|
|
@@ -24383,8 +24416,8 @@ async function updateManifest(projectRoot, entry) {
|
|
|
24383
24416
|
`);
|
|
24384
24417
|
}
|
|
24385
24418
|
async function updateSkillsCatalog(projectRoot) {
|
|
24386
|
-
const manifestPath =
|
|
24387
|
-
const catalogPath =
|
|
24419
|
+
const manifestPath = path87.join(projectRoot, ".metaproject", "metaproject.json");
|
|
24420
|
+
const catalogPath = path87.join(projectRoot, ".metaproject", "skills", "catalog.md");
|
|
24388
24421
|
const manifest = await readJsonFileOr(manifestPath, {});
|
|
24389
24422
|
const registry = manifest.modules?.gdskills?.projectSkillRegistry ?? [];
|
|
24390
24423
|
const rows = registry.length > 0 ? registry.map((entry) => `| ${entry.module} | ${entry.name} | \`${entry.target}\` | ${entry.path}/SKILL.md |`).join(`
|
|
@@ -24424,7 +24457,7 @@ function inferModule(target) {
|
|
|
24424
24457
|
}
|
|
24425
24458
|
function inferSkillName(target) {
|
|
24426
24459
|
const normalized = target.trim().replace(/[#:]+/g, "/");
|
|
24427
|
-
const base =
|
|
24460
|
+
const base = path87.basename(normalized).replace(/\.[^.]+$/, "");
|
|
24428
24461
|
return base || "entity";
|
|
24429
24462
|
}
|
|
24430
24463
|
function slugify5(value) {
|
|
@@ -24527,7 +24560,7 @@ class ProposalLifecycleService {
|
|
|
24527
24560
|
now;
|
|
24528
24561
|
constructor(options) {
|
|
24529
24562
|
this.options = options;
|
|
24530
|
-
this.root =
|
|
24563
|
+
this.root = path88.resolve(options.workspaceRoot);
|
|
24531
24564
|
this.now = options.now ?? (() => new Date);
|
|
24532
24565
|
}
|
|
24533
24566
|
async create(input) {
|
|
@@ -24546,7 +24579,7 @@ class ProposalLifecycleService {
|
|
|
24546
24579
|
if (manifest.status === "archived")
|
|
24547
24580
|
throw new ProposalLifecycleError("guard_denied", "workspace is archived");
|
|
24548
24581
|
const file = this.proposalPath(workspaceId, proposal.id);
|
|
24549
|
-
await mkdir32(
|
|
24582
|
+
await mkdir32(path88.dirname(file), { recursive: true, mode: 448 });
|
|
24550
24583
|
return withFileLock(`${file}.lock`, async () => {
|
|
24551
24584
|
const consume = this.options.wrapUpAuthority.consume(input.wrapUp, { actor, workspaceId });
|
|
24552
24585
|
if (consume !== "ok")
|
|
@@ -24574,7 +24607,7 @@ class ProposalLifecycleService {
|
|
|
24574
24607
|
return this.options.workspaces.withAuthorizedActor({ actorContext: actor, workspaceId: input.workspaceId, action: "review", execute: async (manifest) => {
|
|
24575
24608
|
const proposal = await this.loadProposal(input.workspaceId, input.proposalId);
|
|
24576
24609
|
const ledger = this.ledgerPath(input.workspaceId);
|
|
24577
|
-
await mkdir32(
|
|
24610
|
+
await mkdir32(path88.dirname(ledger), { recursive: true, mode: 448 });
|
|
24578
24611
|
return withFileLock(`${ledger}.lock`, async () => {
|
|
24579
24612
|
const records = (await this.records(ledger)).filter((record) => record.proposalId === proposal.id);
|
|
24580
24613
|
const events = records.filter((record) => record.recordType === "proposal-transition");
|
|
@@ -24615,7 +24648,7 @@ class ProposalLifecycleService {
|
|
|
24615
24648
|
} });
|
|
24616
24649
|
}
|
|
24617
24650
|
async listProposedProposals(workspaceId) {
|
|
24618
|
-
const proposalsDir =
|
|
24651
|
+
const proposalsDir = path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals");
|
|
24619
24652
|
let entries;
|
|
24620
24653
|
try {
|
|
24621
24654
|
entries = (await readdir15(proposalsDir)).filter((name) => name.endsWith(".json"));
|
|
@@ -24627,7 +24660,7 @@ class ProposalLifecycleService {
|
|
|
24627
24660
|
const proposals = [];
|
|
24628
24661
|
for (const entry of entries) {
|
|
24629
24662
|
try {
|
|
24630
|
-
const parsed = JSON.parse(await readFile49(
|
|
24663
|
+
const parsed = JSON.parse(await readFile49(path88.join(proposalsDir, entry), "utf8"));
|
|
24631
24664
|
if (parsed.recordType === "proposal-created")
|
|
24632
24665
|
proposals.push(parsed);
|
|
24633
24666
|
} catch {}
|
|
@@ -24893,31 +24926,31 @@ class ProposalLifecycleService {
|
|
|
24893
24926
|
}
|
|
24894
24927
|
}
|
|
24895
24928
|
proposalPath(workspaceId, proposalId) {
|
|
24896
|
-
return
|
|
24929
|
+
return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
|
|
24897
24930
|
}
|
|
24898
24931
|
decisionRef(proposalId, key) {
|
|
24899
24932
|
return `./proposals/${proposalId}.${hash(key)}.decision.json`;
|
|
24900
24933
|
}
|
|
24901
24934
|
decisionPath(workspaceId, proposalId, key) {
|
|
24902
|
-
return
|
|
24935
|
+
return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.decision.json`);
|
|
24903
24936
|
}
|
|
24904
24937
|
approvalRef(proposalId, key) {
|
|
24905
24938
|
return `./proposals/${proposalId}.${hash(key)}.approval.json`;
|
|
24906
24939
|
}
|
|
24907
24940
|
approvalPath(workspaceId, proposalId, key) {
|
|
24908
|
-
return
|
|
24941
|
+
return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.approval.json`);
|
|
24909
24942
|
}
|
|
24910
24943
|
writeResultPath(workspaceId, proposalId, key) {
|
|
24911
|
-
return
|
|
24944
|
+
return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-result.json`);
|
|
24912
24945
|
}
|
|
24913
24946
|
intentRef(proposalId, key) {
|
|
24914
24947
|
return `./proposals/${proposalId}.${hash(key)}.write-intent.json`;
|
|
24915
24948
|
}
|
|
24916
24949
|
intentPath(workspaceId, proposalId, key) {
|
|
24917
|
-
return
|
|
24950
|
+
return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-intent.json`);
|
|
24918
24951
|
}
|
|
24919
24952
|
attemptPath(workspaceId, proposalId, key) {
|
|
24920
|
-
return
|
|
24953
|
+
return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.owner-write-attempt.json`);
|
|
24921
24954
|
}
|
|
24922
24955
|
async loadWriteResult(workspaceId, proposalId, key) {
|
|
24923
24956
|
try {
|
|
@@ -24944,7 +24977,7 @@ class ProposalLifecycleService {
|
|
|
24944
24977
|
}
|
|
24945
24978
|
}
|
|
24946
24979
|
ledgerPath(workspaceId) {
|
|
24947
|
-
return
|
|
24980
|
+
return path88.join(this.root, ".metaproject", "workspaces", workspaceId, "activity.jsonl");
|
|
24948
24981
|
}
|
|
24949
24982
|
timestamp() {
|
|
24950
24983
|
return this.now().toISOString();
|
|
@@ -25027,7 +25060,7 @@ function normalizeProposalLifecycleResult(value) {
|
|
|
25027
25060
|
// src/sac/collaboration-service.ts
|
|
25028
25061
|
import { appendFile as appendFile7, mkdir as mkdir33, readFile as readFile50 } from "fs/promises";
|
|
25029
25062
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
25030
|
-
import
|
|
25063
|
+
import path89 from "path";
|
|
25031
25064
|
class CollaborationServiceError extends Error {
|
|
25032
25065
|
code;
|
|
25033
25066
|
constructor(code, message) {
|
|
@@ -25042,7 +25075,7 @@ class CollaborationService {
|
|
|
25042
25075
|
this.input = input;
|
|
25043
25076
|
}
|
|
25044
25077
|
file(id) {
|
|
25045
|
-
return
|
|
25078
|
+
return path89.join(this.input.workspaceRoot, ".metaproject", "workspaces", id, "activity.jsonl");
|
|
25046
25079
|
}
|
|
25047
25080
|
async overview(input) {
|
|
25048
25081
|
const manifest = await this.input.workspaces.show(input);
|
|
@@ -25079,7 +25112,7 @@ class CollaborationService {
|
|
|
25079
25112
|
occurredAt: (this.input.now ?? (() => new Date))().toISOString(),
|
|
25080
25113
|
...suppliedHandoff ? { handoff: { ...suppliedHandoff, from: actor.subject } } : {}
|
|
25081
25114
|
});
|
|
25082
|
-
await mkdir33(
|
|
25115
|
+
await mkdir33(path89.dirname(this.file(manifest.id)), { recursive: true, mode: 448 });
|
|
25083
25116
|
await appendFile7(this.file(manifest.id), `${JSON.stringify(activity)}
|
|
25084
25117
|
`, { mode: 384 });
|
|
25085
25118
|
return normalizeCollaborationResult(activity);
|
|
@@ -25129,13 +25162,13 @@ function normalizeCollaborationResult(value) {
|
|
|
25129
25162
|
// src/session/external-slate.ts
|
|
25130
25163
|
init_fs();
|
|
25131
25164
|
import { mkdir as mkdir35, readdir as readdir16, readFile as readFile51 } from "fs/promises";
|
|
25132
|
-
import
|
|
25165
|
+
import path91 from "path";
|
|
25133
25166
|
|
|
25134
25167
|
// src/sac/machine-wrap-up.ts
|
|
25135
25168
|
init_fs();
|
|
25136
25169
|
import { createHash as createHash23, randomUUID as randomUUID10 } from "crypto";
|
|
25137
25170
|
import { mkdir as mkdir34 } from "fs/promises";
|
|
25138
|
-
import
|
|
25171
|
+
import path90 from "path";
|
|
25139
25172
|
|
|
25140
25173
|
// src/sac/workspace-resolve.ts
|
|
25141
25174
|
init_redact();
|
|
@@ -25276,11 +25309,11 @@ async function resolveMachineWrapUp(input) {
|
|
|
25276
25309
|
`;
|
|
25277
25310
|
const seedsJson = `${JSON.stringify(seedsForKind.map((seed) => ({ text: seed.text, source: describeSource(seed.source) })), null, 2)}
|
|
25278
25311
|
`;
|
|
25279
|
-
const evidenceRelBase =
|
|
25312
|
+
const evidenceRelBase = path90.posix.join(".metaproject", "workspaces", input.workspaceId, "machine-evidence");
|
|
25280
25313
|
const floor = await applyEvidenceRedactionFloor(input.cwd, [
|
|
25281
|
-
{ name: `${input.kind}.diff.txt`, content: diffBody, path:
|
|
25282
|
-
{ name: `${input.kind}.flow.json`, content: flowSnapshotJson, path:
|
|
25283
|
-
{ name: `${input.kind}.seeds.json`, content: seedsJson, path:
|
|
25314
|
+
{ name: `${input.kind}.diff.txt`, content: diffBody, path: path90.posix.join(evidenceRelBase, `${input.kind}.diff.txt`), source: "tool-output" },
|
|
25315
|
+
{ name: `${input.kind}.flow.json`, content: flowSnapshotJson, path: path90.posix.join(evidenceRelBase, `${input.kind}.flow.json`), source: "generated" },
|
|
25316
|
+
{ name: `${input.kind}.seeds.json`, content: seedsJson, path: path90.posix.join(evidenceRelBase, `${input.kind}.seeds.json`), source: "generated" }
|
|
25284
25317
|
]);
|
|
25285
25318
|
if (!floor.ok)
|
|
25286
25319
|
return { ok: false, code: "security_denied", detail: floor.reason };
|
|
@@ -25334,14 +25367,14 @@ ${safeSeeds.content}`;
|
|
|
25334
25367
|
}
|
|
25335
25368
|
summary = result.text.trim().length > 0 ? result.text.trim() : mechanicalSummary(summaryDiff, course);
|
|
25336
25369
|
}
|
|
25337
|
-
const evidenceDir =
|
|
25370
|
+
const evidenceDir = path90.join(input.cwd, ".metaproject", "workspaces", input.workspaceId, "machine-evidence");
|
|
25338
25371
|
await mkdir34(evidenceDir, { recursive: true });
|
|
25339
25372
|
const diffFile = `${input.kind}.${shortHash}.diff.txt`;
|
|
25340
25373
|
const flowFile = `${input.kind}.${shortHash}.flow.json`;
|
|
25341
25374
|
const seedsFile = `${input.kind}.${shortHash}.seeds.json`;
|
|
25342
|
-
await writeFileAtomic(
|
|
25343
|
-
await writeFileAtomic(
|
|
25344
|
-
await writeFileAtomic(
|
|
25375
|
+
await writeFileAtomic(path90.join(evidenceDir, diffFile), safeDiff.content);
|
|
25376
|
+
await writeFileAtomic(path90.join(evidenceDir, flowFile), safeFlow.content);
|
|
25377
|
+
await writeFileAtomic(path90.join(evidenceDir, seedsFile), safeSeeds.content);
|
|
25345
25378
|
const observedAt = now().toISOString();
|
|
25346
25379
|
const relBase = `./.metaproject/workspaces/${input.workspaceId}/machine-evidence`;
|
|
25347
25380
|
const evidence = [
|
|
@@ -25351,7 +25384,7 @@ ${safeSeeds.content}`;
|
|
|
25351
25384
|
];
|
|
25352
25385
|
if (floor.notice !== undefined) {
|
|
25353
25386
|
const noticeFile = `${input.kind}.${shortHash}.redaction.md`;
|
|
25354
|
-
await writeFileAtomic(
|
|
25387
|
+
await writeFileAtomic(path90.join(evidenceDir, noticeFile), floor.notice);
|
|
25355
25388
|
evidence.push({ kind: REDACTION_NOTICE_KIND, uri: `${relBase}/${noticeFile}`, revision: sha2565(floor.notice), observedAt });
|
|
25356
25389
|
}
|
|
25357
25390
|
return {
|
|
@@ -25370,18 +25403,18 @@ async function writeFlooredArchiveArtifact(params) {
|
|
|
25370
25403
|
{
|
|
25371
25404
|
name: params.filename,
|
|
25372
25405
|
content: params.content,
|
|
25373
|
-
path:
|
|
25406
|
+
path: path90.posix.join("slate-archive", params.filename),
|
|
25374
25407
|
source: "generated"
|
|
25375
25408
|
}
|
|
25376
25409
|
]);
|
|
25377
25410
|
if (!floor.ok)
|
|
25378
25411
|
return { ok: false, code: "security_denied", detail: floor.reason };
|
|
25379
25412
|
const body = floor.bodies[0];
|
|
25380
|
-
const archiveDir =
|
|
25413
|
+
const archiveDir = path90.join(params.dir, "slate-archive");
|
|
25381
25414
|
await mkdir34(archiveDir, { recursive: true });
|
|
25382
|
-
await writeFileAtomic(
|
|
25415
|
+
await writeFileAtomic(path90.join(archiveDir, params.filename), body.content);
|
|
25383
25416
|
if (floor.notice !== undefined) {
|
|
25384
|
-
await writeFileAtomic(
|
|
25417
|
+
await writeFileAtomic(path90.join(archiveDir, `${params.filename}${ARCHIVE_REDACTION_NOTICE_SUFFIX}`), floor.notice);
|
|
25385
25418
|
}
|
|
25386
25419
|
return { ok: true, altered: body.altered };
|
|
25387
25420
|
}
|
|
@@ -25417,9 +25450,9 @@ async function writeWrapUpOutcomeArtifact(cwd, dir, trigger, now, groups) {
|
|
|
25417
25450
|
return;
|
|
25418
25451
|
const refusalIso = now().toISOString();
|
|
25419
25452
|
const refusalFilename = `${refusalIso.replace(/[:.]/g, "-")}-wrap-up-outcome.json`;
|
|
25420
|
-
const archiveDir =
|
|
25453
|
+
const archiveDir = path90.join(dir, "slate-archive");
|
|
25421
25454
|
await mkdir34(archiveDir, { recursive: true });
|
|
25422
|
-
await writeFileAtomic(
|
|
25455
|
+
await writeFileAtomic(path90.join(archiveDir, refusalFilename), `${JSON.stringify({
|
|
25423
25456
|
recordType: "wrap-up-outcome",
|
|
25424
25457
|
trigger,
|
|
25425
25458
|
generatedAt: refusalIso,
|
|
@@ -25555,7 +25588,7 @@ async function runWrapUp(input) {
|
|
|
25555
25588
|
|
|
25556
25589
|
// src/session/external-slate.ts
|
|
25557
25590
|
function externalSlatesDir(cwd) {
|
|
25558
|
-
return
|
|
25591
|
+
return path91.join(cwd, ".keryx", "external-slates");
|
|
25559
25592
|
}
|
|
25560
25593
|
var EXTERNAL_SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
25561
25594
|
function assertValidExternalSessionId(externalSessionId) {
|
|
@@ -25565,14 +25598,14 @@ function assertValidExternalSessionId(externalSessionId) {
|
|
|
25565
25598
|
}
|
|
25566
25599
|
function externalSlatePath(cwd, externalSessionId) {
|
|
25567
25600
|
assertValidExternalSessionId(externalSessionId);
|
|
25568
|
-
return
|
|
25601
|
+
return path91.join(externalSlatesDir(cwd), `${externalSessionId}.json`);
|
|
25569
25602
|
}
|
|
25570
25603
|
function externalSlateLockPath(cwd, externalSessionId) {
|
|
25571
25604
|
return `${externalSlatePath(cwd, externalSessionId)}.lock`;
|
|
25572
25605
|
}
|
|
25573
25606
|
function externalSlateEvidenceDir(cwd, externalSessionId) {
|
|
25574
25607
|
assertValidExternalSessionId(externalSessionId);
|
|
25575
|
-
return
|
|
25608
|
+
return path91.join(externalSlatesDir(cwd), externalSessionId);
|
|
25576
25609
|
}
|
|
25577
25610
|
async function readExternalSlate(cwd, externalSessionId) {
|
|
25578
25611
|
try {
|
|
@@ -25661,12 +25694,12 @@ __export(exports_service10, {
|
|
|
25661
25694
|
runDoctor: () => runDoctor,
|
|
25662
25695
|
runValidate: () => runValidate
|
|
25663
25696
|
});
|
|
25664
|
-
import
|
|
25697
|
+
import path94 from "path";
|
|
25665
25698
|
import { readFile as readFile54 } from "fs/promises";
|
|
25666
25699
|
|
|
25667
25700
|
// src/standard/validate.ts
|
|
25668
25701
|
init_fs();
|
|
25669
|
-
import
|
|
25702
|
+
import path93 from "path";
|
|
25670
25703
|
import { readFile as readFile53 } from "fs/promises";
|
|
25671
25704
|
|
|
25672
25705
|
// src/standard/schemas.ts
|
|
@@ -25795,7 +25828,7 @@ var SCHEMA_REGISTRY2 = {
|
|
|
25795
25828
|
|
|
25796
25829
|
// src/standard/profiles.ts
|
|
25797
25830
|
init_fs();
|
|
25798
|
-
import
|
|
25831
|
+
import path92 from "path";
|
|
25799
25832
|
import { readFile as readFile52 } from "fs/promises";
|
|
25800
25833
|
var AGENT_MODULES = ["gdgraph", "gdctx", "gdskills", "gdwiki", "memory"];
|
|
25801
25834
|
var CI_MODULES = ["health", "testing"];
|
|
@@ -25807,7 +25840,7 @@ function enabledModuleKeys(manifest) {
|
|
|
25807
25840
|
}
|
|
25808
25841
|
async function rootEntrypointLinksIndex(cwd) {
|
|
25809
25842
|
for (const name of ROOT_ENTRYPOINTS) {
|
|
25810
|
-
const filePath =
|
|
25843
|
+
const filePath = path92.join(cwd, name);
|
|
25811
25844
|
if (!await pathExists(filePath)) {
|
|
25812
25845
|
continue;
|
|
25813
25846
|
}
|
|
@@ -25819,16 +25852,16 @@ async function rootEntrypointLinksIndex(cwd) {
|
|
|
25819
25852
|
return false;
|
|
25820
25853
|
}
|
|
25821
25854
|
async function minimalSatisfied(cwd) {
|
|
25822
|
-
const metaprojectRoot =
|
|
25855
|
+
const metaprojectRoot = path92.join(cwd, ".metaproject");
|
|
25823
25856
|
const requiredFiles = ["index.md", "README.md", "metaproject.json"];
|
|
25824
25857
|
const requiredDirs = ["modules", "rules", "skills", "data"];
|
|
25825
25858
|
for (const file of requiredFiles) {
|
|
25826
|
-
if (!await pathExists(
|
|
25859
|
+
if (!await pathExists(path92.join(metaprojectRoot, file))) {
|
|
25827
25860
|
return false;
|
|
25828
25861
|
}
|
|
25829
25862
|
}
|
|
25830
25863
|
for (const dir of requiredDirs) {
|
|
25831
|
-
if (!await pathExists(
|
|
25864
|
+
if (!await pathExists(path92.join(metaprojectRoot, dir))) {
|
|
25832
25865
|
return false;
|
|
25833
25866
|
}
|
|
25834
25867
|
}
|
|
@@ -25841,7 +25874,7 @@ async function ciSatisfied(cwd, manifest) {
|
|
|
25841
25874
|
return false;
|
|
25842
25875
|
}
|
|
25843
25876
|
for (const key of ciModules) {
|
|
25844
|
-
if (await pathExists(
|
|
25877
|
+
if (await pathExists(path92.join(cwd, ".metaproject", "data", key, "artifacts"))) {
|
|
25845
25878
|
return true;
|
|
25846
25879
|
}
|
|
25847
25880
|
}
|
|
@@ -25854,7 +25887,7 @@ async function evaluateProfiles(cwd, manifest) {
|
|
|
25854
25887
|
satisfied.push("minimal");
|
|
25855
25888
|
}
|
|
25856
25889
|
const hasAgentModule = AGENT_MODULES.some((key) => new Set(enabledModuleKeys(manifest)).has(key));
|
|
25857
|
-
const agent = minimal && hasAgentModule && await rootEntrypointLinksIndex(cwd) && await pathExists(
|
|
25890
|
+
const agent = minimal && hasAgentModule && await rootEntrypointLinksIndex(cwd) && await pathExists(path92.join(cwd, ".metaproject", "rules"));
|
|
25858
25891
|
if (agent) {
|
|
25859
25892
|
satisfied.push("agent");
|
|
25860
25893
|
}
|
|
@@ -26024,20 +26057,20 @@ var MANIFEST_TOP_LEVEL_SCHEMA = {
|
|
|
26024
26057
|
async function validateWorkspace2(cwd) {
|
|
26025
26058
|
const errors = [];
|
|
26026
26059
|
const warnings = [];
|
|
26027
|
-
const metaprojectRoot =
|
|
26060
|
+
const metaprojectRoot = path93.join(cwd, ".metaproject");
|
|
26028
26061
|
const requiredFiles = ["index.md", "README.md", "metaproject.json"];
|
|
26029
26062
|
for (const file of requiredFiles) {
|
|
26030
|
-
if (!await pathExists(
|
|
26063
|
+
if (!await pathExists(path93.join(metaprojectRoot, file))) {
|
|
26031
26064
|
errors.push(issue("missing-required-file", `Required file .metaproject/${file} is missing`, `Run \`keryx init\` to scaffold .metaproject/${file}.`));
|
|
26032
26065
|
}
|
|
26033
26066
|
}
|
|
26034
26067
|
const requiredDirs = ["modules", "rules", "skills", "data"];
|
|
26035
26068
|
for (const dir of requiredDirs) {
|
|
26036
|
-
if (!await pathExists(
|
|
26069
|
+
if (!await pathExists(path93.join(metaprojectRoot, dir))) {
|
|
26037
26070
|
errors.push(issue("missing-required-dir", `Required directory .metaproject/${dir}/ is missing`, `Run \`keryx init\` to create .metaproject/${dir}/.`));
|
|
26038
26071
|
}
|
|
26039
26072
|
}
|
|
26040
|
-
const manifestPath =
|
|
26073
|
+
const manifestPath = path93.join(metaprojectRoot, "metaproject.json");
|
|
26041
26074
|
if (!await pathExists(manifestPath)) {
|
|
26042
26075
|
return { ok: errors.length === 0, errors, warnings };
|
|
26043
26076
|
}
|
|
@@ -26069,7 +26102,7 @@ async function validateWorkspace2(cwd) {
|
|
|
26069
26102
|
if (typeof value !== "string") {
|
|
26070
26103
|
continue;
|
|
26071
26104
|
}
|
|
26072
|
-
if (!await pathExists(
|
|
26105
|
+
if (!await pathExists(path93.join(cwd, value))) {
|
|
26073
26106
|
errors.push(issue("missing-declared-path", `Declared path paths.${key} -> ${value} does not exist`, `Create ${value} or remove paths.${key} from metaproject.json.`));
|
|
26074
26107
|
}
|
|
26075
26108
|
}
|
|
@@ -26079,7 +26112,7 @@ async function validateWorkspace2(cwd) {
|
|
|
26079
26112
|
continue;
|
|
26080
26113
|
}
|
|
26081
26114
|
if (typeof entry.manifest === "string") {
|
|
26082
|
-
if (!await pathExists(
|
|
26115
|
+
if (!await pathExists(path93.join(cwd, entry.manifest))) {
|
|
26083
26116
|
errors.push(issue("missing-module-manifest", `Enabled module "${key}" manifest ${entry.manifest} is missing`, `Create ${entry.manifest} or run \`keryx update\` to regenerate module manifests.`));
|
|
26084
26117
|
}
|
|
26085
26118
|
}
|
|
@@ -26088,14 +26121,14 @@ async function validateWorkspace2(cwd) {
|
|
|
26088
26121
|
if (typeof value !== "string") {
|
|
26089
26122
|
continue;
|
|
26090
26123
|
}
|
|
26091
|
-
if (!await pathExists(
|
|
26124
|
+
if (!await pathExists(path93.join(cwd, value))) {
|
|
26092
26125
|
const sink = field === "data" ? warnings : errors;
|
|
26093
26126
|
sink.push(issue("missing-module-path", `Module "${key}" declares ${String(field)} ${value}, which does not exist`, field === "data" ? `Run the module (e.g. \`keryx ${key} ...\`) to generate ${value}, or update modules.${key}.data in metaproject.json.` : `Create ${value} or update modules.${key}.${String(field)} in metaproject.json.`));
|
|
26094
26127
|
}
|
|
26095
26128
|
}
|
|
26096
26129
|
}
|
|
26097
26130
|
for (const name of ROOT_ENTRYPOINTS2) {
|
|
26098
|
-
const filePath =
|
|
26131
|
+
const filePath = path93.join(cwd, name);
|
|
26099
26132
|
if (!await pathExists(filePath)) {
|
|
26100
26133
|
continue;
|
|
26101
26134
|
}
|
|
@@ -26149,7 +26182,7 @@ async function runDoctor(cwd) {
|
|
|
26149
26182
|
return validateWorkspace2(cwd);
|
|
26150
26183
|
}
|
|
26151
26184
|
async function readManifest(cwd) {
|
|
26152
|
-
const manifestPath =
|
|
26185
|
+
const manifestPath = path94.join(cwd, ".metaproject", "metaproject.json");
|
|
26153
26186
|
if (!await pathExists(manifestPath)) {
|
|
26154
26187
|
throw new Error("Metaproject is not initialized (missing .metaproject/metaproject.json). Run `keryx init` first.");
|
|
26155
26188
|
}
|