@mrciphersmith/keryx 0.3.131 → 0.3.133
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/core.js
CHANGED
|
@@ -16164,7 +16164,7 @@ var init_guard = __esm(() => {
|
|
|
16164
16164
|
|
|
16165
16165
|
// src/lib/keryx-home.ts
|
|
16166
16166
|
import os2 from "os";
|
|
16167
|
-
import
|
|
16167
|
+
import path59 from "path";
|
|
16168
16168
|
function resolveKeryxHomeDir(env, homeDir) {
|
|
16169
16169
|
if (homeDir !== undefined)
|
|
16170
16170
|
return homeDir;
|
|
@@ -16173,24 +16173,24 @@ function resolveKeryxHomeDir(env, homeDir) {
|
|
|
16173
16173
|
}
|
|
16174
16174
|
function userStoreRoot(env = process.env, homeDir) {
|
|
16175
16175
|
const home = resolveKeryxHomeDir(env, homeDir);
|
|
16176
|
-
return
|
|
16176
|
+
return path59.join(home, USER_STORE_DIRNAME);
|
|
16177
16177
|
}
|
|
16178
16178
|
function userStorePaths(env = process.env, homeDir) {
|
|
16179
16179
|
const root = userStoreRoot(env, homeDir);
|
|
16180
|
-
const state =
|
|
16180
|
+
const state = path59.join(root, "state");
|
|
16181
16181
|
return {
|
|
16182
16182
|
root,
|
|
16183
|
-
skills:
|
|
16184
|
-
agents:
|
|
16185
|
-
memory:
|
|
16186
|
-
learning:
|
|
16187
|
-
learningPatterns:
|
|
16188
|
-
bundles:
|
|
16189
|
-
appliedState:
|
|
16190
|
-
hooksJson:
|
|
16191
|
-
externalSkillImports:
|
|
16183
|
+
skills: path59.join(root, "skills"),
|
|
16184
|
+
agents: path59.join(root, "agents"),
|
|
16185
|
+
memory: path59.join(root, "memory"),
|
|
16186
|
+
learning: path59.join(root, "learning"),
|
|
16187
|
+
learningPatterns: path59.join(root, "learning", "patterns"),
|
|
16188
|
+
bundles: path59.join(root, "bundles"),
|
|
16189
|
+
appliedState: path59.join(root, "bundles", "applied-state.json"),
|
|
16190
|
+
hooksJson: path59.join(root, "hooks.json"),
|
|
16191
|
+
externalSkillImports: path59.join(root, "skills", "external-imports.json"),
|
|
16192
16192
|
state,
|
|
16193
|
-
externalImportsKey:
|
|
16193
|
+
externalImportsKey: path59.join(state, "external-imports.key")
|
|
16194
16194
|
};
|
|
16195
16195
|
}
|
|
16196
16196
|
var USER_STORE_DIRNAME = ".keryx";
|
|
@@ -16297,12 +16297,12 @@ var init_types2 = __esm(() => {
|
|
|
16297
16297
|
|
|
16298
16298
|
// src/memory/store.ts
|
|
16299
16299
|
import { lstat as lstat8, readdir as readdir13, readFile as readFile28 } from "fs/promises";
|
|
16300
|
-
import
|
|
16300
|
+
import path60 from "path";
|
|
16301
16301
|
function decodeStrictUtf8(bytes) {
|
|
16302
16302
|
return STRICT_UTF8_DECODER.decode(bytes);
|
|
16303
16303
|
}
|
|
16304
16304
|
function memoryRoot(cwd) {
|
|
16305
|
-
return
|
|
16305
|
+
return path60.join(cwd, ".metaproject", "memory");
|
|
16306
16306
|
}
|
|
16307
16307
|
function memoryRootFor(scope, cwd, env = process.env, homeDir) {
|
|
16308
16308
|
return scope === "user" ? userStorePaths(env, homeDir).memory : memoryRoot(cwd);
|
|
@@ -16311,7 +16311,7 @@ async function collectEntries(cwd) {
|
|
|
16311
16311
|
const root = memoryRoot(cwd);
|
|
16312
16312
|
const entries = [];
|
|
16313
16313
|
for (const { type, folder } of MEMORY_TYPES) {
|
|
16314
|
-
const dir =
|
|
16314
|
+
const dir = path60.join(root, folder);
|
|
16315
16315
|
let dirStats;
|
|
16316
16316
|
try {
|
|
16317
16317
|
dirStats = await lstat8(dir);
|
|
@@ -16325,7 +16325,7 @@ async function collectEntries(cwd) {
|
|
|
16325
16325
|
if (!name.endsWith(".md")) {
|
|
16326
16326
|
continue;
|
|
16327
16327
|
}
|
|
16328
|
-
const abs =
|
|
16328
|
+
const abs = path60.join(dir, name);
|
|
16329
16329
|
let stats;
|
|
16330
16330
|
try {
|
|
16331
16331
|
stats = await lstat8(abs);
|
|
@@ -16360,7 +16360,7 @@ async function collectEntriesStrict(root) {
|
|
|
16360
16360
|
return { status: "incomplete", entries: [], problems: [{ path: ".", reason: "not-a-regular-file" }] };
|
|
16361
16361
|
}
|
|
16362
16362
|
for (const { type, folder } of MEMORY_TYPES) {
|
|
16363
|
-
const dir =
|
|
16363
|
+
const dir = path60.join(root, folder);
|
|
16364
16364
|
let dirStats;
|
|
16365
16365
|
try {
|
|
16366
16366
|
dirStats = await lstat8(dir);
|
|
@@ -16384,7 +16384,7 @@ async function collectEntriesStrict(root) {
|
|
|
16384
16384
|
}
|
|
16385
16385
|
for (const name of names) {
|
|
16386
16386
|
const relativePath = `${folder}/${name}`;
|
|
16387
|
-
const abs =
|
|
16387
|
+
const abs = path60.join(dir, name);
|
|
16388
16388
|
let entryStats;
|
|
16389
16389
|
try {
|
|
16390
16390
|
entryStats = await lstat8(abs);
|
|
@@ -16476,7 +16476,7 @@ async function collectUnexpectedMarkdown(dir, relativeDir, problems) {
|
|
|
16476
16476
|
return;
|
|
16477
16477
|
}
|
|
16478
16478
|
for (const name of names) {
|
|
16479
|
-
const abs =
|
|
16479
|
+
const abs = path60.join(dir, name);
|
|
16480
16480
|
const relativePath = `${relativeDir}/${name}`;
|
|
16481
16481
|
let stats;
|
|
16482
16482
|
try {
|
|
@@ -16510,7 +16510,7 @@ async function collectUnexpectedTopLevel(root, problems) {
|
|
|
16510
16510
|
if (MEMORY_TYPE_FOLDERS.has(name)) {
|
|
16511
16511
|
continue;
|
|
16512
16512
|
}
|
|
16513
|
-
const abs =
|
|
16513
|
+
const abs = path60.join(root, name);
|
|
16514
16514
|
let stats;
|
|
16515
16515
|
try {
|
|
16516
16516
|
stats = await lstat8(abs);
|
|
@@ -16879,9 +16879,9 @@ var init_validation = __esm(() => {
|
|
|
16879
16879
|
});
|
|
16880
16880
|
|
|
16881
16881
|
// src/memory/config.ts
|
|
16882
|
-
import
|
|
16882
|
+
import path64 from "path";
|
|
16883
16883
|
function memoryConfigPath(cwd) {
|
|
16884
|
-
return
|
|
16884
|
+
return path64.join(cwd, ".metaproject", "memory.config.json");
|
|
16885
16885
|
}
|
|
16886
16886
|
async function loadMemoryConfig(cwd) {
|
|
16887
16887
|
const file = memoryConfigPath(cwd);
|
|
@@ -17009,9 +17009,9 @@ function titleSimilarity(a, b) {
|
|
|
17009
17009
|
// src/memory/report.ts
|
|
17010
17010
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
17011
17011
|
import { access as access2, mkdir as mkdir10, readdir as readdir15, rename as rename4, rm as rm4, stat as stat10, writeFile as writeFile7 } from "fs/promises";
|
|
17012
|
-
import
|
|
17012
|
+
import path65 from "path";
|
|
17013
17013
|
function runtimeRoot(cwd) {
|
|
17014
|
-
return
|
|
17014
|
+
return path65.join(cwd, ".metaproject", "runtime", "memory");
|
|
17015
17015
|
}
|
|
17016
17016
|
function bounded(value, maximum) {
|
|
17017
17017
|
if (Buffer.byteLength(value, "utf8") <= maximum)
|
|
@@ -17048,8 +17048,8 @@ function formatScope(scopes) {
|
|
|
17048
17048
|
return parts.length > 0 ? parts.join(", ") : null;
|
|
17049
17049
|
}
|
|
17050
17050
|
function relativeMemoryPath(value) {
|
|
17051
|
-
const normalized = value.split(
|
|
17052
|
-
if (!normalized ||
|
|
17051
|
+
const normalized = value.split(path65.sep).join("/");
|
|
17052
|
+
if (!normalized || path65.isAbsolute(value) || normalized.startsWith("../") || normalized.includes("/../")) {
|
|
17053
17053
|
throw new Error("Memory report paths must be memory-root-relative");
|
|
17054
17054
|
}
|
|
17055
17055
|
return bounded(normalized, MAX_PATH_LENGTH);
|
|
@@ -17156,7 +17156,7 @@ function validateMemorySearchReport(value) {
|
|
|
17156
17156
|
for (const key of Object.keys(item))
|
|
17157
17157
|
if (!allowedResult.has(key))
|
|
17158
17158
|
errors.push(`unexpected result property: ${key}`);
|
|
17159
|
-
if (typeof item.path !== "string" || !item.path || item.path.length > MAX_PATH_LENGTH ||
|
|
17159
|
+
if (typeof item.path !== "string" || !item.path || item.path.length > MAX_PATH_LENGTH || path65.isAbsolute(item.path) || item.path.includes(".."))
|
|
17160
17160
|
errors.push("result path is invalid");
|
|
17161
17161
|
if (typeof item.title !== "string" || item.title.length > MAX_TITLE_LENGTH)
|
|
17162
17162
|
errors.push("result title is invalid");
|
|
@@ -17243,26 +17243,26 @@ class MemoryReportStore {
|
|
|
17243
17243
|
throw new Error("Invalid memory report run ID");
|
|
17244
17244
|
const report = renderMemorySearchReport({ runId, generatedAt: this.clock(), search: input.search, filters: input.filters ?? {} });
|
|
17245
17245
|
const root = runtimeRoot(input.cwd);
|
|
17246
|
-
const searchRoot =
|
|
17247
|
-
const tempRoot =
|
|
17248
|
-
const destination =
|
|
17246
|
+
const searchRoot = path65.join(root, "search");
|
|
17247
|
+
const tempRoot = path65.join(root, "tmp");
|
|
17248
|
+
const destination = path65.join(searchRoot, runId);
|
|
17249
17249
|
if (await exists(destination))
|
|
17250
17250
|
throw new Error(`Memory report run already exists: ${runId}`);
|
|
17251
17251
|
await mkdir10(searchRoot, { recursive: true });
|
|
17252
17252
|
await mkdir10(tempRoot, { recursive: true });
|
|
17253
17253
|
const staleBefore = this.clock().getTime() - STALE_STAGING_MS;
|
|
17254
17254
|
for (const name of await readdir15(tempRoot)) {
|
|
17255
|
-
const candidate =
|
|
17255
|
+
const candidate = path65.join(tempRoot, name);
|
|
17256
17256
|
if ((await stat10(candidate)).mtimeMs <= staleBefore)
|
|
17257
17257
|
await rm4(candidate, { recursive: true, force: true });
|
|
17258
17258
|
}
|
|
17259
|
-
const staging =
|
|
17259
|
+
const staging = path65.join(tempRoot, `${runId}.${randomUUID2()}`);
|
|
17260
17260
|
try {
|
|
17261
17261
|
await mkdir10(staging);
|
|
17262
17262
|
await Promise.all([
|
|
17263
|
-
writeFile7(
|
|
17263
|
+
writeFile7(path65.join(staging, "report.json"), `${JSON.stringify(report, null, 2)}
|
|
17264
17264
|
`, "utf8"),
|
|
17265
|
-
writeFile7(
|
|
17265
|
+
writeFile7(path65.join(staging, "report.md"), renderMemorySearchReportMarkdown(report), "utf8")
|
|
17266
17266
|
]);
|
|
17267
17267
|
if (await exists(destination))
|
|
17268
17268
|
throw new Error(`Memory report run already exists: ${runId}`);
|
|
@@ -17273,8 +17273,8 @@ class MemoryReportStore {
|
|
|
17273
17273
|
}
|
|
17274
17274
|
return {
|
|
17275
17275
|
runId,
|
|
17276
|
-
markdownPath:
|
|
17277
|
-
jsonPath:
|
|
17276
|
+
markdownPath: path65.relative(input.cwd, path65.join(destination, "report.md")),
|
|
17277
|
+
jsonPath: path65.relative(input.cwd, path65.join(destination, "report.json"))
|
|
17278
17278
|
};
|
|
17279
17279
|
}
|
|
17280
17280
|
}
|
|
@@ -17531,22 +17531,22 @@ var init_search = __esm(() => {
|
|
|
17531
17531
|
});
|
|
17532
17532
|
|
|
17533
17533
|
// src/gdgraph/data-dir.ts
|
|
17534
|
-
import
|
|
17534
|
+
import path79 from "path";
|
|
17535
17535
|
function gdgraphDataDir(projectRoot, dataDir) {
|
|
17536
|
-
return dataDir ??
|
|
17536
|
+
return dataDir ?? path79.join(projectRoot, ".metaproject", "data", "gdgraph");
|
|
17537
17537
|
}
|
|
17538
17538
|
function gdgraphStorageDir(projectRoot, dataDir) {
|
|
17539
|
-
return
|
|
17539
|
+
return path79.join(gdgraphDataDir(projectRoot, dataDir), "storage");
|
|
17540
17540
|
}
|
|
17541
17541
|
function gdgraphArtifactsDir(projectRoot, dataDir) {
|
|
17542
|
-
return
|
|
17542
|
+
return path79.join(gdgraphDataDir(projectRoot, dataDir), "artifacts");
|
|
17543
17543
|
}
|
|
17544
17544
|
var init_data_dir = () => {};
|
|
17545
17545
|
|
|
17546
17546
|
// src/gdgraph/config.ts
|
|
17547
|
-
import
|
|
17547
|
+
import path80 from "path";
|
|
17548
17548
|
function gdgraphConfigPath(cwd) {
|
|
17549
|
-
return
|
|
17549
|
+
return path80.join(cwd, ".metaproject", "gdgraph.config.json");
|
|
17550
17550
|
}
|
|
17551
17551
|
function mergeGdgraphConfig(parsed) {
|
|
17552
17552
|
const base = DEFAULT_GDGRAPH_CONFIG;
|
|
@@ -18151,7 +18151,7 @@ var init_extract = __esm(() => {
|
|
|
18151
18151
|
});
|
|
18152
18152
|
|
|
18153
18153
|
// src/gdgraph/treesitter/grammars.ts
|
|
18154
|
-
import
|
|
18154
|
+
import path81 from "path";
|
|
18155
18155
|
function grammarAssetId(language) {
|
|
18156
18156
|
return `tree-sitter-${language}`;
|
|
18157
18157
|
}
|
|
@@ -18167,7 +18167,7 @@ function symbolLanguage(language) {
|
|
|
18167
18167
|
async function resolveGrammar(cwd, language, grammarsPath) {
|
|
18168
18168
|
const id = grammarAssetId(language);
|
|
18169
18169
|
const lock = await loadAssetsLock(cwd);
|
|
18170
|
-
const overrides = grammarsPath ? { [id]: { path:
|
|
18170
|
+
const overrides = grammarsPath ? { [id]: { path: path81.join(grammarsPath, `${id}.wasm`) } } : undefined;
|
|
18171
18171
|
const registry = registryFromLock(lock, overrides);
|
|
18172
18172
|
const resolved = await resolveAsset(registry, id);
|
|
18173
18173
|
if (!resolved) {
|
|
@@ -18197,7 +18197,7 @@ function toGrammarLanguages(languages) {
|
|
|
18197
18197
|
return out;
|
|
18198
18198
|
}
|
|
18199
18199
|
function grammarForFile(file, available) {
|
|
18200
|
-
const ext =
|
|
18200
|
+
const ext = path81.extname(file);
|
|
18201
18201
|
const preference = ext === ".tsx" ? ["tsx", "typescript"] : ext === ".ts" ? ["typescript"] : ext === ".jsx" || ext === ".js" || ext === ".mjs" || ext === ".cjs" ? ["javascript"] : ext === ".java" ? ["java"] : ext === ".py" ? ["python"] : [];
|
|
18202
18202
|
for (const language of preference) {
|
|
18203
18203
|
if (available.includes(language)) {
|
|
@@ -18459,7 +18459,7 @@ var init_adapter = __esm(() => {
|
|
|
18459
18459
|
|
|
18460
18460
|
// src/gdgraph/enrich.ts
|
|
18461
18461
|
import { mkdir as mkdir14, writeFile as writeFile8 } from "fs/promises";
|
|
18462
|
-
import
|
|
18462
|
+
import path82 from "path";
|
|
18463
18463
|
async function enrichBuildWithSymbols(cwd, files, resolve, dataDir) {
|
|
18464
18464
|
const config = await loadGdgraphConfig(cwd);
|
|
18465
18465
|
const treesitterConfig = {
|
|
@@ -18477,10 +18477,10 @@ async function enrichBuildWithSymbols(cwd, files, resolve, dataDir) {
|
|
|
18477
18477
|
async function writeSymbolLayer(cwd, layer, dataDir) {
|
|
18478
18478
|
const storageDir = gdgraphStorageDir(cwd, dataDir);
|
|
18479
18479
|
await mkdir14(storageDir, { recursive: true });
|
|
18480
|
-
await writeFile8(
|
|
18480
|
+
await writeFile8(path82.join(storageDir, "symbols.jsonl"), layer.symbols.map((symbol) => JSON.stringify(symbol)).join(`
|
|
18481
18481
|
`) + `
|
|
18482
18482
|
`, "utf8");
|
|
18483
|
-
await writeFile8(
|
|
18483
|
+
await writeFile8(path82.join(storageDir, "calls.jsonl"), layer.calls.map((call) => JSON.stringify(call)).join(`
|
|
18484
18484
|
`) + `
|
|
18485
18485
|
`, "utf8");
|
|
18486
18486
|
}
|
|
@@ -18674,10 +18674,10 @@ var init_describes = () => {};
|
|
|
18674
18674
|
|
|
18675
18675
|
// src/sync/provenance.ts
|
|
18676
18676
|
import { mkdir as mkdir15, readFile as readFile40, writeFile as writeFile9 } from "fs/promises";
|
|
18677
|
-
import
|
|
18677
|
+
import path83 from "path";
|
|
18678
18678
|
import { spawn } from "child_process";
|
|
18679
18679
|
function provenancePath(cwd, module) {
|
|
18680
|
-
return
|
|
18680
|
+
return path83.join(cwd, ".metaproject", "data", module, ".provenance.json");
|
|
18681
18681
|
}
|
|
18682
18682
|
function gitCmdResult(cwd, args) {
|
|
18683
18683
|
return new Promise((resolve) => {
|
|
@@ -18722,7 +18722,7 @@ async function recordProvenance(cwd, module, at) {
|
|
|
18722
18722
|
if (!head)
|
|
18723
18723
|
return;
|
|
18724
18724
|
const file = provenancePath(cwd, module);
|
|
18725
|
-
await mkdir15(
|
|
18725
|
+
await mkdir15(path83.dirname(file), { recursive: true });
|
|
18726
18726
|
const provenance = { commit: head.commit, branch: head.branch, builtAt: at };
|
|
18727
18727
|
await writeFile9(file, `${JSON.stringify(provenance, null, 2)}
|
|
18728
18728
|
`, "utf8");
|
|
@@ -18748,7 +18748,7 @@ var init_provenance = __esm(() => {
|
|
|
18748
18748
|
// src/gdgraph/staleness.ts
|
|
18749
18749
|
import { spawn as spawn2 } from "child_process";
|
|
18750
18750
|
import { stat as stat11 } from "fs/promises";
|
|
18751
|
-
import
|
|
18751
|
+
import path84 from "path";
|
|
18752
18752
|
function gitStatusPorcelain(cwd) {
|
|
18753
18753
|
return new Promise((resolve) => {
|
|
18754
18754
|
try {
|
|
@@ -18771,10 +18771,10 @@ function gitStatusPorcelain(cwd) {
|
|
|
18771
18771
|
});
|
|
18772
18772
|
}
|
|
18773
18773
|
function nodesJsonlPath(cwd) {
|
|
18774
|
-
return
|
|
18774
|
+
return path84.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
|
|
18775
18775
|
}
|
|
18776
18776
|
function gdgraphConfigPath2(cwd) {
|
|
18777
|
-
return
|
|
18777
|
+
return path84.join(cwd, ".metaproject", "gdgraph.config.json");
|
|
18778
18778
|
}
|
|
18779
18779
|
function categorizeStatusEntries(entries, rootPrefix) {
|
|
18780
18780
|
const metaprojectPrefix = `${rootPrefix}.metaproject/`;
|
|
@@ -18869,7 +18869,7 @@ async function checkGraphStaleness(cwd, statusObservation) {
|
|
|
18869
18869
|
}
|
|
18870
18870
|
} else {
|
|
18871
18871
|
provenanceMissing = true;
|
|
18872
|
-
const logsHeadStat = await stat11(
|
|
18872
|
+
const logsHeadStat = await stat11(path84.join(cwd, ".git", "logs", "HEAD")).catch(() => null);
|
|
18873
18873
|
if (logsHeadStat && logsHeadStat.mtimeMs > nodesStat.mtimeMs) {
|
|
18874
18874
|
reasons.push("repo HEAD moved since the graph was built (no build provenance recorded; inferred from .git/logs/HEAD)");
|
|
18875
18875
|
}
|
|
@@ -18897,7 +18897,7 @@ async function checkGraphStaleness(cwd, statusObservation) {
|
|
|
18897
18897
|
if (projectRelative === null) {
|
|
18898
18898
|
continue;
|
|
18899
18899
|
}
|
|
18900
|
-
const fileStat = await stat11(
|
|
18900
|
+
const fileStat = await stat11(path84.join(cwd, projectRelative)).catch(() => null);
|
|
18901
18901
|
if (fileStat && fileStat.mtimeMs > nodesStat.mtimeMs) {
|
|
18902
18902
|
postBuildEdits.push(displayPath);
|
|
18903
18903
|
}
|
|
@@ -19033,15 +19033,15 @@ var init_types3 = __esm(() => {
|
|
|
19033
19033
|
|
|
19034
19034
|
// src/wiki/collect.ts
|
|
19035
19035
|
import { readFile as readFile41, readdir as readdir16 } from "fs/promises";
|
|
19036
|
-
import
|
|
19036
|
+
import path85 from "path";
|
|
19037
19037
|
function wikiRootPath(cwd) {
|
|
19038
|
-
return
|
|
19038
|
+
return path85.join(cwd, ".metaproject", "wiki");
|
|
19039
19039
|
}
|
|
19040
19040
|
async function collectPages(cwd) {
|
|
19041
19041
|
const root = wikiRootPath(cwd);
|
|
19042
19042
|
const pages = [];
|
|
19043
19043
|
for (const { type, folder } of WIKI_PAGE_TYPES) {
|
|
19044
|
-
const dir =
|
|
19044
|
+
const dir = path85.join(root, folder);
|
|
19045
19045
|
let names;
|
|
19046
19046
|
try {
|
|
19047
19047
|
names = await readdir16(dir);
|
|
@@ -19056,7 +19056,7 @@ async function collectPages(cwd) {
|
|
|
19056
19056
|
if (!entry.endsWith(".md")) {
|
|
19057
19057
|
continue;
|
|
19058
19058
|
}
|
|
19059
|
-
const absolutePath =
|
|
19059
|
+
const absolutePath = path85.join(dir, entry);
|
|
19060
19060
|
let content;
|
|
19061
19061
|
try {
|
|
19062
19062
|
content = await readFile41(absolutePath, "utf8");
|
|
@@ -19917,9 +19917,9 @@ var MEMORY_EMBEDDING_ID = "memory.embedding", DEFAULT_EMBED_DIMS = 96;
|
|
|
19917
19917
|
// src/memory/embedding/index.ts
|
|
19918
19918
|
import { createHash as createHash14 } from "crypto";
|
|
19919
19919
|
import { mkdir as mkdir16, readFile as readFile42, writeFile as writeFile10 } from "fs/promises";
|
|
19920
|
-
import
|
|
19920
|
+
import path86 from "path";
|
|
19921
19921
|
function embeddingsDir(cwd) {
|
|
19922
|
-
return
|
|
19922
|
+
return path86.join(cwd, ".metaproject", "data", "memory", "embeddings");
|
|
19923
19923
|
}
|
|
19924
19924
|
function entryText(entry) {
|
|
19925
19925
|
return `${entry.title}
|
|
@@ -19948,17 +19948,17 @@ async function buildEmbeddingIndex(cwd, entries, embedder, model, now) {
|
|
|
19948
19948
|
};
|
|
19949
19949
|
const dir = embeddingsDir(cwd);
|
|
19950
19950
|
await mkdir16(dir, { recursive: true });
|
|
19951
|
-
await writeFile10(
|
|
19951
|
+
await writeFile10(path86.join(dir, "index.meta.json"), `${JSON.stringify(meta, null, 2)}
|
|
19952
19952
|
`, "utf8");
|
|
19953
|
-
await writeFile10(
|
|
19953
|
+
await writeFile10(path86.join(dir, "vectors.jsonl"), records.map((record) => JSON.stringify(record)).join(`
|
|
19954
19954
|
`) + (records.length > 0 ? `
|
|
19955
19955
|
` : ""), "utf8");
|
|
19956
19956
|
return toIndex(meta, records);
|
|
19957
19957
|
}
|
|
19958
19958
|
async function loadEmbeddingIndex(cwd) {
|
|
19959
19959
|
const dir = embeddingsDir(cwd);
|
|
19960
|
-
const metaPath =
|
|
19961
|
-
const vectorsPath =
|
|
19960
|
+
const metaPath = path86.join(dir, "index.meta.json");
|
|
19961
|
+
const vectorsPath = path86.join(dir, "vectors.jsonl");
|
|
19962
19962
|
if (!await pathExists(metaPath) || !await pathExists(vectorsPath)) {
|
|
19963
19963
|
return null;
|
|
19964
19964
|
}
|
|
@@ -20039,10 +20039,10 @@ var init_embedding = __esm(() => {
|
|
|
20039
20039
|
});
|
|
20040
20040
|
|
|
20041
20041
|
// src/wiki/section-tombstone.ts
|
|
20042
|
-
import
|
|
20042
|
+
import path87 from "path";
|
|
20043
20043
|
import { stat as stat12 } from "fs/promises";
|
|
20044
20044
|
function sectionRegistryPath(cwd) {
|
|
20045
|
-
return
|
|
20045
|
+
return path87.join(cwd, ".metaproject", "wiki", ".sections.json");
|
|
20046
20046
|
}
|
|
20047
20047
|
function emptySectionRegistry() {
|
|
20048
20048
|
return { version: SECTION_REGISTRY_VERSION, entries: [], tombstones: [], lifted: [] };
|
|
@@ -20344,10 +20344,10 @@ var init_section_tombstone = __esm(() => {
|
|
|
20344
20344
|
|
|
20345
20345
|
// src/memory/cross-layer.ts
|
|
20346
20346
|
import { readFile as readFile43 } from "fs/promises";
|
|
20347
|
-
import
|
|
20347
|
+
import path88 from "path";
|
|
20348
20348
|
function extractWikiReferences(entryRelativePath, entryAbsolutePath, content, wikiRoot) {
|
|
20349
20349
|
const references = [];
|
|
20350
|
-
const entryDir =
|
|
20350
|
+
const entryDir = path88.dirname(entryAbsolutePath);
|
|
20351
20351
|
const lines = content.split(`
|
|
20352
20352
|
`);
|
|
20353
20353
|
for (let index = 0;index < lines.length; index += 1) {
|
|
@@ -20362,16 +20362,16 @@ function extractWikiReferences(entryRelativePath, entryAbsolutePath, content, wi
|
|
|
20362
20362
|
if (withoutAnchor.length === 0) {
|
|
20363
20363
|
continue;
|
|
20364
20364
|
}
|
|
20365
|
-
const absolute =
|
|
20366
|
-
const relativeToWiki =
|
|
20367
|
-
if (relativeToWiki.startsWith("..") ||
|
|
20365
|
+
const absolute = path88.resolve(entryDir, withoutAnchor);
|
|
20366
|
+
const relativeToWiki = path88.relative(wikiRoot, absolute);
|
|
20367
|
+
if (relativeToWiki.startsWith("..") || path88.isAbsolute(relativeToWiki)) {
|
|
20368
20368
|
continue;
|
|
20369
20369
|
}
|
|
20370
20370
|
references.push({
|
|
20371
20371
|
entry: entryRelativePath,
|
|
20372
20372
|
kind: "page-path",
|
|
20373
20373
|
raw: href,
|
|
20374
|
-
target: relativeToWiki.split(
|
|
20374
|
+
target: relativeToWiki.split(path88.sep).join("/"),
|
|
20375
20375
|
line
|
|
20376
20376
|
});
|
|
20377
20377
|
}
|
|
@@ -20391,7 +20391,7 @@ function isDangling(finding) {
|
|
|
20391
20391
|
return finding.state !== "intact";
|
|
20392
20392
|
}
|
|
20393
20393
|
async function loadWikiKnowledgeView(cwd) {
|
|
20394
|
-
const wikiRoot =
|
|
20394
|
+
const wikiRoot = path88.join(cwd, ".metaproject", "wiki");
|
|
20395
20395
|
const pages = await collectPages(cwd);
|
|
20396
20396
|
const index = buildSectionIndex(await Promise.all(pages.map(async (page) => ({
|
|
20397
20397
|
page,
|
|
@@ -20609,7 +20609,7 @@ function round2(value) {
|
|
|
20609
20609
|
var init_dedup = () => {};
|
|
20610
20610
|
|
|
20611
20611
|
// src/memory/check.ts
|
|
20612
|
-
import
|
|
20612
|
+
import path89 from "path";
|
|
20613
20613
|
async function checkMemory(cwd, config) {
|
|
20614
20614
|
const entries = await collectEntries(cwd);
|
|
20615
20615
|
const issues = [];
|
|
@@ -20625,7 +20625,7 @@ async function checkMemory(cwd, config) {
|
|
|
20625
20625
|
}
|
|
20626
20626
|
for (const file of entry.scopes.files) {
|
|
20627
20627
|
const clean = file.replace(/^`|`$/g, "");
|
|
20628
|
-
if (!await pathExists(
|
|
20628
|
+
if (!await pathExists(path89.resolve(cwd, clean))) {
|
|
20629
20629
|
issues.push({ path: entry.relativePath, kind: "link", message: `related file not found: ${clean}` });
|
|
20630
20630
|
}
|
|
20631
20631
|
}
|
|
@@ -20680,12 +20680,12 @@ var init_check = __esm(() => {
|
|
|
20680
20680
|
|
|
20681
20681
|
// src/memory/write.ts
|
|
20682
20682
|
import { mkdir as mkdir17, open as open2, readFile as readFile44, rename as rename5, rm as rm5, writeFile as writeFile11 } from "fs/promises";
|
|
20683
|
-
import
|
|
20683
|
+
import path90 from "path";
|
|
20684
20684
|
async function resolveCanonicalEntryPath(cwd, relativePath) {
|
|
20685
|
-
const root =
|
|
20686
|
-
const absolutePath =
|
|
20687
|
-
const normalized = toPosix2(
|
|
20688
|
-
if (!normalized || normalized.startsWith("../") ||
|
|
20685
|
+
const root = path90.resolve(memoryRoot(cwd));
|
|
20686
|
+
const absolutePath = path90.resolve(root, relativePath);
|
|
20687
|
+
const normalized = toPosix2(path90.relative(root, absolutePath));
|
|
20688
|
+
if (!normalized || normalized.startsWith("../") || path90.isAbsolute(normalized) || !normalized.endsWith(".md")) {
|
|
20689
20689
|
return null;
|
|
20690
20690
|
}
|
|
20691
20691
|
return { absolutePath, relativePath: normalized };
|
|
@@ -20781,9 +20781,9 @@ function validateNextEntry(relativePath, content) {
|
|
|
20781
20781
|
return null;
|
|
20782
20782
|
}
|
|
20783
20783
|
async function replaceAtomically(target, content) {
|
|
20784
|
-
const dir =
|
|
20784
|
+
const dir = path90.dirname(target);
|
|
20785
20785
|
await mkdir17(dir, { recursive: true });
|
|
20786
|
-
const tmp =
|
|
20786
|
+
const tmp = path90.join(dir, `.${path90.basename(target)}.keryx-tmp-${process.pid}-${Math.random().toString(16).slice(2)}`);
|
|
20787
20787
|
try {
|
|
20788
20788
|
await writeFile11(tmp, content, "utf8");
|
|
20789
20789
|
const file = await open2(tmp, "r");
|
|
@@ -20819,7 +20819,7 @@ function header(content, name) {
|
|
|
20819
20819
|
return content.match(new RegExp(`^${name}:\\s*(.+)$`, "mi"))?.[1]?.trim() ?? null;
|
|
20820
20820
|
}
|
|
20821
20821
|
function toPosix2(value) {
|
|
20822
|
-
return value.split(
|
|
20822
|
+
return value.split(path90.sep).join("/");
|
|
20823
20823
|
}
|
|
20824
20824
|
function message(cause) {
|
|
20825
20825
|
return cause instanceof Error ? cause.message : String(cause);
|
|
@@ -20833,9 +20833,9 @@ var init_write = __esm(() => {
|
|
|
20833
20833
|
// src/memory/ingest.ts
|
|
20834
20834
|
import { existsSync as existsSync10 } from "fs";
|
|
20835
20835
|
import { readFile as readFile45 } from "fs/promises";
|
|
20836
|
-
import
|
|
20836
|
+
import path91 from "path";
|
|
20837
20837
|
async function ingestMemory(cwd, source, filePath, config, now) {
|
|
20838
|
-
const absolute =
|
|
20838
|
+
const absolute = path91.resolve(cwd, filePath);
|
|
20839
20839
|
if (!await pathExists(absolute)) {
|
|
20840
20840
|
throw new Error(`Ingest source not found: ${filePath}`);
|
|
20841
20841
|
}
|
|
@@ -20852,8 +20852,8 @@ async function ingestMemory(cwd, source, filePath, config, now) {
|
|
|
20852
20852
|
const securityWarnings = [];
|
|
20853
20853
|
const securitySkipped = [];
|
|
20854
20854
|
let skippedDuplicates = 0;
|
|
20855
|
-
const dir =
|
|
20856
|
-
const link =
|
|
20855
|
+
const dir = path91.join(memoryRoot(cwd), folder);
|
|
20856
|
+
const link = path91.relative(cwd, absolute);
|
|
20857
20857
|
const date = dateString(now);
|
|
20858
20858
|
for (const text of candidates) {
|
|
20859
20859
|
const title = toTitle(text);
|
|
@@ -21034,7 +21034,7 @@ function uniqueSlug(dir, title) {
|
|
|
21034
21034
|
const base = slugify2(title) || "entry";
|
|
21035
21035
|
let slug = base;
|
|
21036
21036
|
let counter = 2;
|
|
21037
|
-
while (existsSync10(
|
|
21037
|
+
while (existsSync10(path91.join(dir, `${slug}.md`))) {
|
|
21038
21038
|
slug = `${base}-${counter}`;
|
|
21039
21039
|
counter += 1;
|
|
21040
21040
|
}
|
|
@@ -21069,7 +21069,7 @@ var init_ingest = __esm(() => {
|
|
|
21069
21069
|
|
|
21070
21070
|
// src/memory/supersede.ts
|
|
21071
21071
|
import { readFile as readFile46 } from "fs/promises";
|
|
21072
|
-
import
|
|
21072
|
+
import path92 from "path";
|
|
21073
21073
|
async function supersedeEntry(input, now) {
|
|
21074
21074
|
const date = input.date ?? now.toISOString().slice(0, 10);
|
|
21075
21075
|
const today = now.toISOString().slice(0, 10);
|
|
@@ -21129,12 +21129,12 @@ async function supersedeEntry(input, now) {
|
|
|
21129
21129
|
async function resolveEntryPath(cwd, raw) {
|
|
21130
21130
|
const root = memoryRoot(cwd);
|
|
21131
21131
|
const candidates = [
|
|
21132
|
-
|
|
21133
|
-
|
|
21134
|
-
|
|
21132
|
+
path92.resolve(cwd, raw),
|
|
21133
|
+
path92.resolve(root, raw),
|
|
21134
|
+
path92.isAbsolute(raw) ? raw : path92.join(cwd, raw)
|
|
21135
21135
|
];
|
|
21136
21136
|
for (const absolute of candidates) {
|
|
21137
|
-
const confined = await resolveCanonicalEntryPath(cwd,
|
|
21137
|
+
const confined = await resolveCanonicalEntryPath(cwd, path92.relative(root, absolute));
|
|
21138
21138
|
if (confined && await pathExists(confined.absolutePath)) {
|
|
21139
21139
|
return { absolute: confined.absolutePath, relative: confined.relativePath };
|
|
21140
21140
|
}
|
|
@@ -21330,9 +21330,9 @@ __export(exports_service3, {
|
|
|
21330
21330
|
});
|
|
21331
21331
|
import { createHash as createHash15 } from "crypto";
|
|
21332
21332
|
import { mkdir as mkdir18, readFile as readFile47, writeFile as writeFile12 } from "fs/promises";
|
|
21333
|
-
import
|
|
21333
|
+
import path93 from "path";
|
|
21334
21334
|
function dataRoot2(cwd) {
|
|
21335
|
-
return
|
|
21335
|
+
return path93.join(cwd, ".metaproject", "data", "memory");
|
|
21336
21336
|
}
|
|
21337
21337
|
function createMemoryService() {
|
|
21338
21338
|
const reportStore = createMemoryReportStore();
|
|
@@ -21347,9 +21347,9 @@ function createMemoryService() {
|
|
|
21347
21347
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(slug)) {
|
|
21348
21348
|
throw new Error(`Invalid slug: ${slug}. Use lowercase letters, digits, and hyphens.`);
|
|
21349
21349
|
}
|
|
21350
|
-
const dir =
|
|
21351
|
-
const filePath =
|
|
21352
|
-
const relativePath =
|
|
21350
|
+
const dir = path93.join(memoryRoot(input.cwd), typeConfig.folder);
|
|
21351
|
+
const filePath = path93.join(dir, `${slug}.md`);
|
|
21352
|
+
const relativePath = path93.relative(input.cwd, filePath);
|
|
21353
21353
|
if (await pathExists(filePath) && !input.force) {
|
|
21354
21354
|
throw new Error(`Entry already exists: ${relativePath}. Use --force to overwrite.`);
|
|
21355
21355
|
}
|
|
@@ -21380,9 +21380,9 @@ function createMemoryService() {
|
|
|
21380
21380
|
async index(input) {
|
|
21381
21381
|
const entries = await collectEntries(input.cwd);
|
|
21382
21382
|
const generatedAt = new Date().toISOString();
|
|
21383
|
-
const indexDir = input.indexDir ??
|
|
21383
|
+
const indexDir = input.indexDir ?? path93.join(dataRoot2(input.cwd), "index");
|
|
21384
21384
|
await mkdir18(indexDir, { recursive: true });
|
|
21385
|
-
const indexPath =
|
|
21385
|
+
const indexPath = path93.join(indexDir, "index.json");
|
|
21386
21386
|
await writeFile12(indexPath, `${JSON.stringify({
|
|
21387
21387
|
catalogVersion: 1,
|
|
21388
21388
|
sourceFingerprint: createHash15("sha256").update(JSON.stringify(entries.map((e) => ({
|
|
@@ -21403,7 +21403,7 @@ function createMemoryService() {
|
|
|
21403
21403
|
}, null, 2)}
|
|
21404
21404
|
`, "utf8");
|
|
21405
21405
|
const result = {
|
|
21406
|
-
path:
|
|
21406
|
+
path: path93.relative(input.cwd, indexPath),
|
|
21407
21407
|
entryCount: entries.length,
|
|
21408
21408
|
generatedAt
|
|
21409
21409
|
};
|
|
@@ -21416,7 +21416,7 @@ function createMemoryService() {
|
|
|
21416
21416
|
const built = await buildEmbeddingIndex(input.cwd, entries, embedder.embed, embedder.model, new Date);
|
|
21417
21417
|
result.embeddings = {
|
|
21418
21418
|
built: true,
|
|
21419
|
-
path:
|
|
21419
|
+
path: path93.relative(input.cwd, embeddingsDir(input.cwd)),
|
|
21420
21420
|
vectorCount: built.meta.entryCount,
|
|
21421
21421
|
model: built.meta.model
|
|
21422
21422
|
};
|
|
@@ -22018,7 +22018,7 @@ var init_ask = __esm(() => {
|
|
|
22018
22018
|
});
|
|
22019
22019
|
|
|
22020
22020
|
// src/wiki/backlinks.ts
|
|
22021
|
-
import
|
|
22021
|
+
import path94 from "path";
|
|
22022
22022
|
function extractCodePaths(content) {
|
|
22023
22023
|
const out = [];
|
|
22024
22024
|
let match;
|
|
@@ -22048,8 +22048,8 @@ function resolveLink(fromRepoPath, raw) {
|
|
|
22048
22048
|
const clean = (raw.split("#")[0] ?? "").trim();
|
|
22049
22049
|
if (!clean)
|
|
22050
22050
|
return "";
|
|
22051
|
-
const fromDir =
|
|
22052
|
-
return
|
|
22051
|
+
const fromDir = path94.posix.dirname(fromRepoPath.split(path94.sep).join("/"));
|
|
22052
|
+
return path94.posix.normalize(path94.posix.join(fromDir, clean));
|
|
22053
22053
|
}
|
|
22054
22054
|
function buildBacklinkIndex(pages) {
|
|
22055
22055
|
const index = new Map;
|
|
@@ -22063,18 +22063,18 @@ function buildBacklinkIndex(pages) {
|
|
|
22063
22063
|
}
|
|
22064
22064
|
};
|
|
22065
22065
|
for (const page of pages) {
|
|
22066
|
-
const from = page.repoPath.split(
|
|
22066
|
+
const from = page.repoPath.split(path94.sep).join("/");
|
|
22067
22067
|
for (const raw of extractLinks(page.content))
|
|
22068
22068
|
add(resolveLink(from, raw), from);
|
|
22069
22069
|
for (const raw of extractCodePaths(page.content))
|
|
22070
|
-
add(
|
|
22070
|
+
add(path94.posix.normalize(raw), from);
|
|
22071
22071
|
}
|
|
22072
22072
|
for (const list of index.values())
|
|
22073
22073
|
list.sort();
|
|
22074
22074
|
return index;
|
|
22075
22075
|
}
|
|
22076
22076
|
function backlinksFor(index, targetRepoPath) {
|
|
22077
|
-
const key =
|
|
22077
|
+
const key = path94.posix.normalize(targetRepoPath.split(path94.sep).join("/"));
|
|
22078
22078
|
return index.get(key) ?? [];
|
|
22079
22079
|
}
|
|
22080
22080
|
var LINK, CODE_SPAN, FILE_LIKE;
|
|
@@ -22087,7 +22087,7 @@ var init_backlinks = __esm(() => {
|
|
|
22087
22087
|
// src/ctx/assembly.ts
|
|
22088
22088
|
import { createHash as createHash16 } from "crypto";
|
|
22089
22089
|
import { mkdir as mkdir19, rename as rename6, writeFile as writeFile13 } from "fs/promises";
|
|
22090
|
-
import
|
|
22090
|
+
import path95 from "path";
|
|
22091
22091
|
function assembleContext(input) {
|
|
22092
22092
|
let items = 0;
|
|
22093
22093
|
let tokens = 0;
|
|
@@ -22131,9 +22131,9 @@ async function recordNoContentContext(input) {
|
|
|
22131
22131
|
return assembly;
|
|
22132
22132
|
}
|
|
22133
22133
|
async function recordContextAssembly(input) {
|
|
22134
|
-
const directory =
|
|
22134
|
+
const directory = path95.join(input.workspaceRoot, ".metaproject", "context-operations", "traces");
|
|
22135
22135
|
await mkdir19(directory, { recursive: true });
|
|
22136
|
-
const target =
|
|
22136
|
+
const target = path95.join(directory, path95.basename(input.assembly.traceRef));
|
|
22137
22137
|
const temporary = `${target}.${process.pid}.tmp`;
|
|
22138
22138
|
await writeFile13(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 })}
|
|
22139
22139
|
`, { mode: 384 });
|
|
@@ -22533,9 +22533,9 @@ var init_evidence = __esm(() => {
|
|
|
22533
22533
|
});
|
|
22534
22534
|
|
|
22535
22535
|
// src/wiki/config.ts
|
|
22536
|
-
import
|
|
22536
|
+
import path96 from "path";
|
|
22537
22537
|
function wikiConfigPath(cwd) {
|
|
22538
|
-
return
|
|
22538
|
+
return path96.join(cwd, ".metaproject", "wiki.config.json");
|
|
22539
22539
|
}
|
|
22540
22540
|
function mergeWikiConfig(parsed) {
|
|
22541
22541
|
const base = DEFAULT_WIKI_CONFIG;
|
|
@@ -22613,12 +22613,12 @@ var init_config4 = __esm(() => {
|
|
|
22613
22613
|
// src/wiki/history.ts
|
|
22614
22614
|
import { createHash as createHash17, randomBytes as randomBytes5 } from "crypto";
|
|
22615
22615
|
import { appendFile as appendFile4, mkdir as mkdir20, open as open3, readFile as readFile49, rm as rm6, stat as stat13, writeFile as writeFile14 } from "fs/promises";
|
|
22616
|
-
import
|
|
22616
|
+
import path97 from "path";
|
|
22617
22617
|
function wikiRootPath2(cwd) {
|
|
22618
|
-
return
|
|
22618
|
+
return path97.join(cwd, ".metaproject", "wiki");
|
|
22619
22619
|
}
|
|
22620
22620
|
function wikiHistoryRoot(cwd) {
|
|
22621
|
-
return
|
|
22621
|
+
return path97.join(cwd, ".metaproject", "data", "gdwiki", "history");
|
|
22622
22622
|
}
|
|
22623
22623
|
function newWikiRunId(now = new Date) {
|
|
22624
22624
|
const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
|
|
@@ -22639,29 +22639,29 @@ async function openWikiWriteContext(cwd, command) {
|
|
|
22639
22639
|
return createWikiWriteContext(cwd, command, { keep: (await loadWikiConfig(cwd)).history.keep });
|
|
22640
22640
|
}
|
|
22641
22641
|
function wikiPageKey(cwd, absolutePath) {
|
|
22642
|
-
const relative =
|
|
22643
|
-
if (relative === "" || relative.startsWith("..") ||
|
|
22642
|
+
const relative = path97.relative(wikiRootPath2(cwd), path97.resolve(absolutePath));
|
|
22643
|
+
if (relative === "" || relative.startsWith("..") || path97.isAbsolute(relative)) {
|
|
22644
22644
|
throw new Error(`not a wiki page: ${absolutePath}`);
|
|
22645
22645
|
}
|
|
22646
22646
|
return toPosix(relative);
|
|
22647
22647
|
}
|
|
22648
22648
|
function assertPageKey(page) {
|
|
22649
22649
|
const segments = page.split("/");
|
|
22650
|
-
if (page.length === 0 || page.includes("\\") ||
|
|
22650
|
+
if (page.length === 0 || page.includes("\\") || path97.isAbsolute(page) || segments.some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
22651
22651
|
throw new Error(`not a wiki page path: ${page}`);
|
|
22652
22652
|
}
|
|
22653
22653
|
return page;
|
|
22654
22654
|
}
|
|
22655
22655
|
function pageHistoryDir(cwd, page) {
|
|
22656
|
-
return
|
|
22656
|
+
return path97.join(wikiHistoryRoot(cwd), ...assertPageKey(page).replace(/\.md$/i, "").split("/"));
|
|
22657
22657
|
}
|
|
22658
22658
|
function pagePath(cwd, page) {
|
|
22659
|
-
return
|
|
22659
|
+
return path97.join(wikiRootPath2(cwd), ...assertPageKey(page).split("/"));
|
|
22660
22660
|
}
|
|
22661
22661
|
function versionFilePath(cwd, page, file) {
|
|
22662
22662
|
const dir = pageHistoryDir(cwd, page);
|
|
22663
|
-
const target =
|
|
22664
|
-
if (!VERSION_FILE.test(file) ||
|
|
22663
|
+
const target = path97.join(dir, file);
|
|
22664
|
+
if (!VERSION_FILE.test(file) || path97.dirname(target) !== dir) {
|
|
22665
22665
|
throw new Error(`history index names an invalid version file for ${page}: ${file}`);
|
|
22666
22666
|
}
|
|
22667
22667
|
return target;
|
|
@@ -22734,7 +22734,7 @@ function parsePageHistoryIndex(markdown, page) {
|
|
|
22734
22734
|
return { page, rows };
|
|
22735
22735
|
}
|
|
22736
22736
|
async function readPageHistory(cwd, page) {
|
|
22737
|
-
const indexPath =
|
|
22737
|
+
const indexPath = path97.join(pageHistoryDir(cwd, page), INDEX_FILE);
|
|
22738
22738
|
const raw = await readBufferOrNull(indexPath);
|
|
22739
22739
|
if (raw === null)
|
|
22740
22740
|
return null;
|
|
@@ -22746,8 +22746,8 @@ async function readPageHistory(cwd, page) {
|
|
|
22746
22746
|
}
|
|
22747
22747
|
async function storeVersion(cwd, page, version, at, content) {
|
|
22748
22748
|
const fileName = `${versionLabel(version)}-${at.replace(/[:.]/g, "-")}.md`;
|
|
22749
|
-
const target =
|
|
22750
|
-
await mkdir20(
|
|
22749
|
+
const target = path97.join(pageHistoryDir(cwd, page), fileName);
|
|
22750
|
+
await mkdir20(path97.dirname(target), { recursive: true });
|
|
22751
22751
|
await writeFile14(target, content);
|
|
22752
22752
|
if (sha2562(await readFile49(target)) !== sha2562(content)) {
|
|
22753
22753
|
throw new Error(`history: stored version does not match the page bytes: ${target}`);
|
|
@@ -22785,7 +22785,7 @@ function planPrune(history, keep, maxRows = MAX_INDEX_ROWS) {
|
|
|
22785
22785
|
}
|
|
22786
22786
|
async function ensureHistoryRoot(cwd) {
|
|
22787
22787
|
const root = wikiHistoryRoot(cwd);
|
|
22788
|
-
const ignore =
|
|
22788
|
+
const ignore = path97.join(root, ".gitignore");
|
|
22789
22789
|
if (await readBufferOrNull(ignore))
|
|
22790
22790
|
return;
|
|
22791
22791
|
await mkdir20(root, { recursive: true });
|
|
@@ -22815,14 +22815,14 @@ async function endsWithoutNewline(file) {
|
|
|
22815
22815
|
}
|
|
22816
22816
|
async function appendRun(cwd, entry) {
|
|
22817
22817
|
const root = wikiHistoryRoot(cwd);
|
|
22818
|
-
const file =
|
|
22818
|
+
const file = path97.join(root, RUNS_FILE);
|
|
22819
22819
|
const lead = await endsWithoutNewline(file) ? `
|
|
22820
22820
|
` : "";
|
|
22821
22821
|
await appendFile4(file, `${lead}${JSON.stringify(entry)}
|
|
22822
22822
|
`, "utf8");
|
|
22823
22823
|
if ((await stat13(file)).size <= MAX_RUNS_BYTES)
|
|
22824
22824
|
return;
|
|
22825
|
-
await withFileLock(
|
|
22825
|
+
await withFileLock(path97.join(root, ".runs.lock"), async () => {
|
|
22826
22826
|
if ((await stat13(file)).size <= MAX_RUNS_BYTES)
|
|
22827
22827
|
return;
|
|
22828
22828
|
const lines = (await readFile49(file, "utf8")).split(`
|
|
@@ -22836,7 +22836,7 @@ async function mutatePage(ctx, absolutePath, next) {
|
|
|
22836
22836
|
const page = wikiPageKey(ctx.cwd, absolutePath);
|
|
22837
22837
|
const dir = pageHistoryDir(ctx.cwd, page);
|
|
22838
22838
|
await ensureHistoryRoot(ctx.cwd);
|
|
22839
|
-
return withFileLock(
|
|
22839
|
+
return withFileLock(path97.join(path97.dirname(dir), `.${path97.basename(dir)}.lock`), async () => {
|
|
22840
22840
|
const live = await readBufferOrNull(absolutePath);
|
|
22841
22841
|
if (next === null ? live === null : live !== null && live.equals(next)) {
|
|
22842
22842
|
return { changed: false };
|
|
@@ -22860,7 +22860,7 @@ async function mutatePage(ctx, absolutePath, next) {
|
|
|
22860
22860
|
if (next === null) {
|
|
22861
22861
|
await rm6(absolutePath, { force: true });
|
|
22862
22862
|
} else {
|
|
22863
|
-
await mkdir20(
|
|
22863
|
+
await mkdir20(path97.dirname(absolutePath), { recursive: true });
|
|
22864
22864
|
await writeFile14(absolutePath, next);
|
|
22865
22865
|
}
|
|
22866
22866
|
} catch (error) {
|
|
@@ -22868,7 +22868,7 @@ async function mutatePage(ctx, absolutePath, next) {
|
|
|
22868
22868
|
await rm6(versionFilePath(ctx.cwd, page, row.file), { force: true });
|
|
22869
22869
|
throw error;
|
|
22870
22870
|
}
|
|
22871
|
-
await writeFileAtomic(
|
|
22871
|
+
await writeFileAtomic(path97.join(dir, INDEX_FILE), renderPageHistoryIndex(history));
|
|
22872
22872
|
for (const file of pruned)
|
|
22873
22873
|
await rm6(versionFilePath(ctx.cwd, page, file), { force: true });
|
|
22874
22874
|
return { changed: true, action };
|
|
@@ -22881,7 +22881,7 @@ async function deleteWikiPage(ctx, absolutePath) {
|
|
|
22881
22881
|
return mutatePage(ctx, absolutePath, null);
|
|
22882
22882
|
}
|
|
22883
22883
|
async function readWikiRuns(cwd) {
|
|
22884
|
-
const raw = await readBufferOrNull(
|
|
22884
|
+
const raw = await readBufferOrNull(path97.join(wikiHistoryRoot(cwd), RUNS_FILE));
|
|
22885
22885
|
if (raw === null)
|
|
22886
22886
|
return [];
|
|
22887
22887
|
const entries = [];
|
|
@@ -23573,7 +23573,7 @@ var init_page_invariants = __esm(() => {
|
|
|
23573
23573
|
});
|
|
23574
23574
|
|
|
23575
23575
|
// src/wiki/readme-links.ts
|
|
23576
|
-
import
|
|
23576
|
+
import path98 from "path";
|
|
23577
23577
|
function rewriteReadmeLinks(text, readmeDir, pageLink) {
|
|
23578
23578
|
return text.replace(MARKDOWN_LINK, (whole, bang, label, target) => {
|
|
23579
23579
|
if (target === "" || HAS_SCHEME.test(target)) {
|
|
@@ -23583,7 +23583,7 @@ function rewriteReadmeLinks(text, readmeDir, pageLink) {
|
|
|
23583
23583
|
if (filePart === "") {
|
|
23584
23584
|
return label;
|
|
23585
23585
|
}
|
|
23586
|
-
const resolved =
|
|
23586
|
+
const resolved = path98.posix.normalize(filePart.startsWith("/") ? filePart.replace(/^\/+/, "") : path98.posix.join(readmeDir, filePart));
|
|
23587
23587
|
const codePath = resolved.replace(/\/+$/, "");
|
|
23588
23588
|
if (codePath === "" || codePath === "." || codePath === ".." || codePath.startsWith("../")) {
|
|
23589
23589
|
return label;
|
|
@@ -23598,12 +23598,12 @@ function rewriteReadmeLinks(text, readmeDir, pageLink) {
|
|
|
23598
23598
|
});
|
|
23599
23599
|
}
|
|
23600
23600
|
function moduleOfTarget(filePart, codePath) {
|
|
23601
|
-
const base =
|
|
23601
|
+
const base = path98.posix.basename(codePath);
|
|
23602
23602
|
if (filePart.endsWith("/") || !/\.[A-Za-z0-9]+$/.test(base)) {
|
|
23603
23603
|
return codePath;
|
|
23604
23604
|
}
|
|
23605
23605
|
if (DOC_ENTRY.test(base)) {
|
|
23606
|
-
const dir =
|
|
23606
|
+
const dir = path98.posix.dirname(codePath);
|
|
23607
23607
|
return dir === "." ? null : dir;
|
|
23608
23608
|
}
|
|
23609
23609
|
return null;
|
|
@@ -24009,15 +24009,15 @@ __export(exports_service4, {
|
|
|
24009
24009
|
import { spawn as spawn3 } from "child_process";
|
|
24010
24010
|
import { createHash as createHash19 } from "crypto";
|
|
24011
24011
|
import { mkdir as mkdir21, readFile as readFile50, readdir as readdir17, writeFile as writeFile15 } from "fs/promises";
|
|
24012
|
-
import
|
|
24012
|
+
import path99 from "path";
|
|
24013
24013
|
function wikiRootPath3(cwd) {
|
|
24014
|
-
return
|
|
24014
|
+
return path99.join(cwd, ".metaproject", "wiki");
|
|
24015
24015
|
}
|
|
24016
24016
|
function dataRootPath(cwd) {
|
|
24017
|
-
return
|
|
24017
|
+
return path99.join(cwd, ".metaproject", "data", "gdwiki");
|
|
24018
24018
|
}
|
|
24019
24019
|
function linkCheckReportPath(cwd) {
|
|
24020
|
-
return
|
|
24020
|
+
return path99.join(dataRootPath(cwd), "link-check", "latest.md");
|
|
24021
24021
|
}
|
|
24022
24022
|
async function wikiStatus(cwd) {
|
|
24023
24023
|
const root = wikiRootPath3(cwd);
|
|
@@ -24025,7 +24025,7 @@ async function wikiStatus(cwd) {
|
|
|
24025
24025
|
const pages = enabled ? await collectPages(cwd) : [];
|
|
24026
24026
|
return {
|
|
24027
24027
|
enabled,
|
|
24028
|
-
wikiRoot:
|
|
24028
|
+
wikiRoot: path99.relative(cwd, root),
|
|
24029
24029
|
totalPages: pages.length,
|
|
24030
24030
|
countsByType: WIKI_PAGE_TYPES.map(({ type }) => ({
|
|
24031
24031
|
type,
|
|
@@ -24056,9 +24056,9 @@ async function wikiCreatePage(input) {
|
|
|
24056
24056
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(input.slug)) {
|
|
24057
24057
|
throw new Error(`Invalid slug: ${input.slug}. Use lowercase letters, digits, and hyphens.`);
|
|
24058
24058
|
}
|
|
24059
|
-
const dir =
|
|
24060
|
-
const filePath =
|
|
24061
|
-
const relativePath =
|
|
24059
|
+
const dir = path99.join(wikiRootPath3(input.cwd), typeConfig.folder);
|
|
24060
|
+
const filePath = path99.join(dir, `${input.slug}.md`);
|
|
24061
|
+
const relativePath = path99.relative(input.cwd, filePath);
|
|
24062
24062
|
if (await pathExists(filePath) && !input.force) {
|
|
24063
24063
|
throw new Error(`Page already exists: ${relativePath}. Use --force to overwrite.`);
|
|
24064
24064
|
}
|
|
@@ -24070,7 +24070,7 @@ async function wikiCreatePage(input) {
|
|
|
24070
24070
|
}
|
|
24071
24071
|
async function wikiGenerateIndex(cwd, history) {
|
|
24072
24072
|
const root = wikiRootPath3(cwd);
|
|
24073
|
-
const indexPath =
|
|
24073
|
+
const indexPath = path99.join(root, "index.md");
|
|
24074
24074
|
const pages = await collectPages(cwd);
|
|
24075
24075
|
const generatedAt = new Date().toISOString();
|
|
24076
24076
|
const managedBlock = `${WIKI_INDEX_BEGIN}
|
|
@@ -24087,7 +24087,7 @@ ${managedBlock}
|
|
|
24087
24087
|
`;
|
|
24088
24088
|
await writeWikiPage(history ?? await openWikiWriteContext(cwd, "wiki index"), indexPath, next);
|
|
24089
24089
|
return {
|
|
24090
|
-
path:
|
|
24090
|
+
path: path99.relative(cwd, indexPath),
|
|
24091
24091
|
pageCount: pages.length,
|
|
24092
24092
|
generatedAt
|
|
24093
24093
|
};
|
|
@@ -24095,13 +24095,13 @@ ${managedBlock}
|
|
|
24095
24095
|
async function wikiCheckLinks(cwd) {
|
|
24096
24096
|
const root = wikiRootPath3(cwd);
|
|
24097
24097
|
const allFiles = await pathExists(root) ? await walkMarkdown(root) : [];
|
|
24098
|
-
const files = allFiles.filter((absolutePath) => !
|
|
24098
|
+
const files = allFiles.filter((absolutePath) => !path99.relative(root, absolutePath).startsWith(`templates${path99.sep}`));
|
|
24099
24099
|
const broken = [];
|
|
24100
24100
|
let checkedLinks = 0;
|
|
24101
24101
|
let skippedExternal = 0;
|
|
24102
24102
|
for (const absolutePath of files) {
|
|
24103
24103
|
const content = await readFile50(absolutePath, "utf8");
|
|
24104
|
-
const pageRelative =
|
|
24104
|
+
const pageRelative = path99.relative(cwd, absolutePath);
|
|
24105
24105
|
for (const target of extractLinkTargets(content)) {
|
|
24106
24106
|
if (EXTERNAL_LINK.test(target)) {
|
|
24107
24107
|
skippedExternal += 1;
|
|
@@ -24112,7 +24112,7 @@ async function wikiCheckLinks(cwd) {
|
|
|
24112
24112
|
continue;
|
|
24113
24113
|
}
|
|
24114
24114
|
checkedLinks += 1;
|
|
24115
|
-
const resolved =
|
|
24115
|
+
const resolved = path99.resolve(path99.dirname(absolutePath), filePart);
|
|
24116
24116
|
if (!await pathExists(resolved)) {
|
|
24117
24117
|
broken.push({
|
|
24118
24118
|
page: pageRelative,
|
|
@@ -24124,7 +24124,7 @@ async function wikiCheckLinks(cwd) {
|
|
|
24124
24124
|
}
|
|
24125
24125
|
const generatedAt = new Date().toISOString();
|
|
24126
24126
|
const reportPath = linkCheckReportPath(cwd);
|
|
24127
|
-
await mkdir21(
|
|
24127
|
+
await mkdir21(path99.dirname(reportPath), { recursive: true });
|
|
24128
24128
|
await writeFile15(reportPath, renderLinkCheckReport({
|
|
24129
24129
|
generatedAt,
|
|
24130
24130
|
checkedPages: files.length,
|
|
@@ -24133,7 +24133,7 @@ async function wikiCheckLinks(cwd) {
|
|
|
24133
24133
|
broken
|
|
24134
24134
|
}), "utf8");
|
|
24135
24135
|
return {
|
|
24136
|
-
reportPath:
|
|
24136
|
+
reportPath: path99.relative(cwd, reportPath),
|
|
24137
24137
|
checkedPages: files.length,
|
|
24138
24138
|
checkedLinks,
|
|
24139
24139
|
skippedExternal,
|
|
@@ -24184,7 +24184,7 @@ async function wikiValidate(cwd) {
|
|
|
24184
24184
|
}
|
|
24185
24185
|
if (await isIndexStale(cwd, pages)) {
|
|
24186
24186
|
issues.push({
|
|
24187
|
-
page:
|
|
24187
|
+
page: path99.join(path99.relative(cwd, wikiRootPath3(cwd)), "index.md"),
|
|
24188
24188
|
kind: "index",
|
|
24189
24189
|
message: "index out of date, run `keryx wiki index`"
|
|
24190
24190
|
});
|
|
@@ -24230,7 +24230,7 @@ function collectCommandLabel(input) {
|
|
|
24230
24230
|
return ["wiki collect", ...flags].join(" ");
|
|
24231
24231
|
}
|
|
24232
24232
|
async function wikiPruneOrphans(cwd, history) {
|
|
24233
|
-
const componentsDir =
|
|
24233
|
+
const componentsDir = path99.join(wikiRootPath3(cwd), "components");
|
|
24234
24234
|
if (!await pathExists(componentsDir)) {
|
|
24235
24235
|
return { pruned: [], orphanedAccepted: [] };
|
|
24236
24236
|
}
|
|
@@ -24250,15 +24250,15 @@ async function wikiPruneOrphans(cwd, history) {
|
|
|
24250
24250
|
if (validSlugs.has(slug)) {
|
|
24251
24251
|
continue;
|
|
24252
24252
|
}
|
|
24253
|
-
const filePath =
|
|
24253
|
+
const filePath = path99.join(componentsDir, entry);
|
|
24254
24254
|
const current = await readFile50(filePath, "utf8");
|
|
24255
24255
|
const isUnmodifiedDraft = /\nStatus:\s*draft\s*\n/.test(current) && current.includes("Generated by `keryx wiki collect`");
|
|
24256
24256
|
if (isUnmodifiedDraft) {
|
|
24257
24257
|
run ??= history ?? await openWikiWriteContext(cwd, "wiki prune");
|
|
24258
24258
|
await deleteWikiPage(run, filePath);
|
|
24259
|
-
pruned.push(
|
|
24259
|
+
pruned.push(path99.relative(cwd, filePath));
|
|
24260
24260
|
} else {
|
|
24261
|
-
orphanedAccepted.push(
|
|
24261
|
+
orphanedAccepted.push(path99.relative(cwd, filePath));
|
|
24262
24262
|
}
|
|
24263
24263
|
}
|
|
24264
24264
|
return { pruned, orphanedAccepted };
|
|
@@ -24268,7 +24268,7 @@ async function validModuleNames(cwd, dataDir) {
|
|
|
24268
24268
|
return counts === undefined ? undefined : new Set(counts.keys());
|
|
24269
24269
|
}
|
|
24270
24270
|
async function moduleFileCounts(cwd, dataDir) {
|
|
24271
|
-
const nodesPath =
|
|
24271
|
+
const nodesPath = path99.join(gdgraphStorageDir(cwd, dataDir), "nodes.jsonl");
|
|
24272
24272
|
if (!await pathExists(nodesPath)) {
|
|
24273
24273
|
return;
|
|
24274
24274
|
}
|
|
@@ -24339,9 +24339,9 @@ async function wikiEvidence(input) {
|
|
|
24339
24339
|
});
|
|
24340
24340
|
}
|
|
24341
24341
|
function resolveEvidenceScope(cwd, override) {
|
|
24342
|
-
const absolute =
|
|
24342
|
+
const absolute = path99.resolve(cwd);
|
|
24343
24343
|
return {
|
|
24344
|
-
projectId: override?.projectId ?? (
|
|
24344
|
+
projectId: override?.projectId ?? (path99.basename(absolute) || "project"),
|
|
24345
24345
|
checkoutId: override?.checkoutId ?? `checkout:${createHash19("sha256").update(absolute).digest("hex").slice(0, 16)}`,
|
|
24346
24346
|
...override?.workspaceId ? { workspaceId: override.workspaceId } : {},
|
|
24347
24347
|
...override?.taskId ? { taskId: override.taskId } : {}
|
|
@@ -24356,7 +24356,7 @@ function isMachineAuthoredPage(pageType, relativePath, content) {
|
|
|
24356
24356
|
if (source === null) {
|
|
24357
24357
|
return false;
|
|
24358
24358
|
}
|
|
24359
|
-
const normalised = relativePath.split(
|
|
24359
|
+
const normalised = relativePath.split(path99.sep).join("/").replace(/^wiki\//, "");
|
|
24360
24360
|
return WIKI_PAGE_PRODUCERS.some((producer) => producer.source === source && producer.pageType === pageType && producer.path.test(normalised) && /^-[ \t]+Link:.*\bsha256\b/m.test(content));
|
|
24361
24361
|
}
|
|
24362
24362
|
function createGdWikiService() {
|
|
@@ -24372,8 +24372,8 @@ function createGdWikiService() {
|
|
|
24372
24372
|
};
|
|
24373
24373
|
}
|
|
24374
24374
|
async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules, dataDir) {
|
|
24375
|
-
const nodesPath =
|
|
24376
|
-
const edgesPath =
|
|
24375
|
+
const nodesPath = path99.join(gdgraphStorageDir(cwd, dataDir), "nodes.jsonl");
|
|
24376
|
+
const edgesPath = path99.join(gdgraphStorageDir(cwd, dataDir), "edges.jsonl");
|
|
24377
24377
|
if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
|
|
24378
24378
|
return [];
|
|
24379
24379
|
}
|
|
@@ -24460,7 +24460,7 @@ async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules,
|
|
|
24460
24460
|
};
|
|
24461
24461
|
const moduleCandidates = [];
|
|
24462
24462
|
const pageModules = new Set(topModules.map((entry) => entry.name));
|
|
24463
|
-
const componentsDir =
|
|
24463
|
+
const componentsDir = path99.join(wikiRootPath3(cwd), "components");
|
|
24464
24464
|
const existingSlugs = new Set((await pathExists(componentsDir) ? await readdir17(componentsDir) : []).filter((entry) => entry.endsWith(".md")).map((entry) => entry.slice(0, -3)));
|
|
24465
24465
|
const pageLink = (name) => {
|
|
24466
24466
|
const slug = slugifyPath(name);
|
|
@@ -24568,7 +24568,7 @@ function topCounts(bucket, limit) {
|
|
|
24568
24568
|
return [...bucket.entries()].sort((a, b) => b[1] - a[1]).slice(0, limit);
|
|
24569
24569
|
}
|
|
24570
24570
|
async function readModuleReadme(cwd, moduleName, pageLink) {
|
|
24571
|
-
const readmePath =
|
|
24571
|
+
const readmePath = path99.join(cwd, ...moduleName.split("/"), "README.md");
|
|
24572
24572
|
if (!await pathExists(readmePath)) {
|
|
24573
24573
|
return null;
|
|
24574
24574
|
}
|
|
@@ -24589,7 +24589,7 @@ async function extractModuleExports(cwd, files) {
|
|
|
24589
24589
|
const declRe = /export\s+(?:async\s+)?(?:default\s+)?(?:const|let|var|function|class|type|interface|enum)\s+([A-Za-z_$][\w$]*)/g;
|
|
24590
24590
|
const braceRe = /export\s*\{([^}]+)\}/g;
|
|
24591
24591
|
for (const file of files.slice(0, 4)) {
|
|
24592
|
-
const filePath =
|
|
24592
|
+
const filePath = path99.join(cwd, ...file.split("/"));
|
|
24593
24593
|
if (!await pathExists(filePath)) {
|
|
24594
24594
|
continue;
|
|
24595
24595
|
}
|
|
@@ -24620,7 +24620,7 @@ async function extractModuleExports(cwd, files) {
|
|
|
24620
24620
|
}
|
|
24621
24621
|
async function extractModuleApi(cwd, files, dataDir) {
|
|
24622
24622
|
const names = await extractModuleExports(cwd, files);
|
|
24623
|
-
const symbolsPath =
|
|
24623
|
+
const symbolsPath = path99.join(gdgraphStorageDir(cwd, dataDir), "symbols.jsonl");
|
|
24624
24624
|
if (names.length === 0 || !await pathExists(symbolsPath)) {
|
|
24625
24625
|
return names.map((name) => "`" + name + "`");
|
|
24626
24626
|
}
|
|
@@ -24646,7 +24646,7 @@ async function extractModuleApi(cwd, files, dataDir) {
|
|
|
24646
24646
|
});
|
|
24647
24647
|
}
|
|
24648
24648
|
async function collectHealthWikiCandidates(cwd, generatedAt) {
|
|
24649
|
-
const healthPath =
|
|
24649
|
+
const healthPath = path99.join(cwd, ".metaproject", "data", "health", "artifacts", "latest.json");
|
|
24650
24650
|
if (!await pathExists(healthPath)) {
|
|
24651
24651
|
return [];
|
|
24652
24652
|
}
|
|
@@ -24688,7 +24688,7 @@ async function collectHealthWikiCandidates(cwd, generatedAt) {
|
|
|
24688
24688
|
}];
|
|
24689
24689
|
}
|
|
24690
24690
|
async function collectTestingWikiCandidates(cwd, generatedAt) {
|
|
24691
|
-
const contextPath =
|
|
24691
|
+
const contextPath = path99.join(cwd, ".metaproject", "data", "testing", "context.md");
|
|
24692
24692
|
if (!await pathExists(contextPath)) {
|
|
24693
24693
|
return [];
|
|
24694
24694
|
}
|
|
@@ -24719,8 +24719,8 @@ async function writeCollectedPage(cwd, candidate, force, history) {
|
|
|
24719
24719
|
if (!folder) {
|
|
24720
24720
|
throw new Error(`Unsupported collected wiki type: ${candidate.type}`);
|
|
24721
24721
|
}
|
|
24722
|
-
const filePath =
|
|
24723
|
-
const relativePath =
|
|
24722
|
+
const filePath = path99.join(wikiRootPath3(cwd), folder, `${candidate.slug}.md`);
|
|
24723
|
+
const relativePath = path99.relative(cwd, filePath);
|
|
24724
24724
|
const exists = await pathExists(filePath);
|
|
24725
24725
|
if (exists && !force) {
|
|
24726
24726
|
return { path: relativePath, type: candidate.type, source: candidate.source, action: "skipped" };
|
|
@@ -24771,7 +24771,7 @@ async function writeCollectedPage(cwd, candidate, force, history) {
|
|
|
24771
24771
|
async function wikiPagesForFile(cwd, targetRepoPath) {
|
|
24772
24772
|
const pages = await collectPages(cwd);
|
|
24773
24773
|
const refs = await Promise.all(pages.map(async (page) => ({
|
|
24774
|
-
repoPath:
|
|
24774
|
+
repoPath: path99.relative(cwd, page.absolutePath).split(path99.sep).join("/"),
|
|
24775
24775
|
content: await readFile50(page.absolutePath, "utf8")
|
|
24776
24776
|
})));
|
|
24777
24777
|
return backlinksFor(buildBacklinkIndex(refs), targetRepoPath);
|
|
@@ -24810,7 +24810,7 @@ function renderIndexBody(pages, generatedAt) {
|
|
|
24810
24810
|
`).trimEnd();
|
|
24811
24811
|
}
|
|
24812
24812
|
async function isIndexStale(cwd, pages) {
|
|
24813
|
-
const indexPath =
|
|
24813
|
+
const indexPath = path99.join(wikiRootPath3(cwd), "index.md");
|
|
24814
24814
|
if (!await pathExists(indexPath)) {
|
|
24815
24815
|
return true;
|
|
24816
24816
|
}
|
|
@@ -24828,7 +24828,7 @@ async function walkMarkdown(root) {
|
|
|
24828
24828
|
const results = [];
|
|
24829
24829
|
const entries = await readdir17(root, { withFileTypes: true });
|
|
24830
24830
|
for (const entry of entries) {
|
|
24831
|
-
const absolutePath =
|
|
24831
|
+
const absolutePath = path99.join(root, entry.name);
|
|
24832
24832
|
if (entry.isDirectory()) {
|
|
24833
24833
|
results.push(...await walkMarkdown(absolutePath));
|
|
24834
24834
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -24885,7 +24885,7 @@ ${JSON.stringify(state, null, 2)}
|
|
|
24885
24885
|
`;
|
|
24886
24886
|
}
|
|
24887
24887
|
async function readIndexGeneratedAt(cwd) {
|
|
24888
|
-
const indexPath =
|
|
24888
|
+
const indexPath = path99.join(wikiRootPath3(cwd), "index.md");
|
|
24889
24889
|
if (!await pathExists(indexPath)) {
|
|
24890
24890
|
return null;
|
|
24891
24891
|
}
|
|
@@ -25125,7 +25125,7 @@ async function validateStructure(cwd, pages, issues) {
|
|
|
25125
25125
|
if (pattern.includes("*")) {
|
|
25126
25126
|
continue;
|
|
25127
25127
|
}
|
|
25128
|
-
if (!await pathExists(
|
|
25128
|
+
if (!await pathExists(path99.join(cwd, pattern))) {
|
|
25129
25129
|
issues.push({
|
|
25130
25130
|
page: page.relativePath,
|
|
25131
25131
|
kind: "describes",
|
|
@@ -25195,7 +25195,7 @@ async function validatePageInvariants(cwd, pages, issues) {
|
|
|
25195
25195
|
}
|
|
25196
25196
|
}
|
|
25197
25197
|
function toPosixPath(value) {
|
|
25198
|
-
return value.split(
|
|
25198
|
+
return value.split(path99.sep).join("/");
|
|
25199
25199
|
}
|
|
25200
25200
|
function compareSemver(a, b) {
|
|
25201
25201
|
const pa = a.split(".").map(Number);
|
|
@@ -25240,7 +25240,7 @@ var init_service4 = __esm(() => {
|
|
|
25240
25240
|
// src/gdgraph/wiki-layer.ts
|
|
25241
25241
|
import { createHash as createHash20 } from "crypto";
|
|
25242
25242
|
import { mkdir as mkdir22, stat as stat14, writeFile as writeFile16 } from "fs/promises";
|
|
25243
|
-
import
|
|
25243
|
+
import path100 from "path";
|
|
25244
25244
|
function storageDir(projectRoot, dataDir) {
|
|
25245
25245
|
return gdgraphStorageDir(projectRoot, dataDir);
|
|
25246
25246
|
}
|
|
@@ -25308,11 +25308,11 @@ async function enrichBuildWithWikiLayer(input) {
|
|
|
25308
25308
|
const mtimes = new Map;
|
|
25309
25309
|
for (const record of input.fileRecords) {
|
|
25310
25310
|
try {
|
|
25311
|
-
const info = await stat14(
|
|
25311
|
+
const info = await stat14(path100.join(input.projectRoot, record.path));
|
|
25312
25312
|
mtimes.set(record.path, info.mtimeMs);
|
|
25313
25313
|
} catch {}
|
|
25314
25314
|
}
|
|
25315
|
-
await writeFile16(
|
|
25315
|
+
await writeFile16(path100.join(dir, BUILD_MANIFEST_FILE), `${JSON.stringify({ version: 1, files: computeFingerprints(input.fileRecords, mtimes) }, null, 2)}
|
|
25316
25316
|
`, "utf8");
|
|
25317
25317
|
const validModules = input.validModules !== undefined ? input.validModules : await (input.loadValidModules ?? ((root) => defaultLoadValidModules(root, input.dataDir)))(input.projectRoot);
|
|
25318
25318
|
const wikiPages = await collectPages(input.projectRoot);
|
|
@@ -25337,8 +25337,8 @@ async function enrichBuildWithWikiLayer(input) {
|
|
|
25337
25337
|
version: page.version
|
|
25338
25338
|
}))
|
|
25339
25339
|
});
|
|
25340
|
-
await writeJsonl(
|
|
25341
|
-
await writeJsonl(
|
|
25340
|
+
await writeJsonl(path100.join(dir, WIKI_PAGES_FILE), layer.pages);
|
|
25341
|
+
await writeJsonl(path100.join(dir, DESCRIBES_FILE), layer.describes);
|
|
25342
25342
|
return layer;
|
|
25343
25343
|
}
|
|
25344
25344
|
async function defaultLoadValidModules(projectRoot, dataDir) {
|
|
@@ -25434,7 +25434,7 @@ function personalizedPageRank(nodes, edges, options) {
|
|
|
25434
25434
|
|
|
25435
25435
|
// src/gdgraph/repomap.ts
|
|
25436
25436
|
import { mkdir as mkdir24, writeFile as writeFile18 } from "fs/promises";
|
|
25437
|
-
import
|
|
25437
|
+
import path103 from "path";
|
|
25438
25438
|
function estimateTokens2(text) {
|
|
25439
25439
|
return Math.ceil(text.length / 4);
|
|
25440
25440
|
}
|
|
@@ -25465,7 +25465,7 @@ function overflowContent(required, missing, budget) {
|
|
|
25465
25465
|
`);
|
|
25466
25466
|
}
|
|
25467
25467
|
function repomapArtifactPath(cwd) {
|
|
25468
|
-
return
|
|
25468
|
+
return path103.join(cwd, ".metaproject", "data", "gdgraph", "artifacts", "repomap.md");
|
|
25469
25469
|
}
|
|
25470
25470
|
function buildRankEdges(graph, config) {
|
|
25471
25471
|
const edges = [];
|
|
@@ -25602,7 +25602,7 @@ function computeRepomap(graph, config, options = {}) {
|
|
|
25602
25602
|
async function writeRepomap(cwd, graph, config, options = {}) {
|
|
25603
25603
|
const result = computeRepomap(graph, config, options);
|
|
25604
25604
|
const artifactPath = repomapArtifactPath(cwd);
|
|
25605
|
-
await mkdir24(
|
|
25605
|
+
await mkdir24(path103.dirname(artifactPath), { recursive: true });
|
|
25606
25606
|
await writeFile18(artifactPath, result.content, "utf8");
|
|
25607
25607
|
return { ...result, path: artifactPath };
|
|
25608
25608
|
}
|
|
@@ -25622,7 +25622,7 @@ var init_repomap = __esm(() => {
|
|
|
25622
25622
|
// src/gdskills/contracts.ts
|
|
25623
25623
|
import { readFile as readFile62 } from "fs/promises";
|
|
25624
25624
|
import { existsSync as existsSync20 } from "fs";
|
|
25625
|
-
import
|
|
25625
|
+
import path127 from "path";
|
|
25626
25626
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
25627
25627
|
async function loadSchema(name) {
|
|
25628
25628
|
const contract = CONTRACTS.find((entry) => entry.name === name);
|
|
@@ -25633,10 +25633,10 @@ async function loadSchema(name) {
|
|
|
25633
25633
|
return JSON.parse(raw);
|
|
25634
25634
|
}
|
|
25635
25635
|
function contractPath(contract) {
|
|
25636
|
-
const here =
|
|
25636
|
+
const here = path127.dirname(fileURLToPath2(import.meta.url));
|
|
25637
25637
|
if (contract.sourcePath) {
|
|
25638
|
-
for (const root of [
|
|
25639
|
-
const candidate =
|
|
25638
|
+
for (const root of [path127.join(here, "..", ".."), path127.join(here, ".."), here]) {
|
|
25639
|
+
const candidate = path127.resolve(root, contract.sourcePath);
|
|
25640
25640
|
if (existsSync20(candidate)) {
|
|
25641
25641
|
return candidate;
|
|
25642
25642
|
}
|
|
@@ -25646,7 +25646,7 @@ function contractPath(contract) {
|
|
|
25646
25646
|
if (existsSync20(directPath)) {
|
|
25647
25647
|
return directPath;
|
|
25648
25648
|
}
|
|
25649
|
-
const packagedSourcePath =
|
|
25649
|
+
const packagedSourcePath = path127.join(here, "..", "src", "gdskills", "contracts", contract.fileName);
|
|
25650
25650
|
if (existsSync20(packagedSourcePath)) {
|
|
25651
25651
|
return packagedSourcePath;
|
|
25652
25652
|
}
|
|
@@ -25829,7 +25829,7 @@ var init_config_dir = __esm(() => {
|
|
|
25829
25829
|
// src/session/preservation.ts
|
|
25830
25830
|
import { createHash as createHash23, randomUUID as randomUUID3 } from "crypto";
|
|
25831
25831
|
import { closeSync, fsyncSync, mkdirSync as mkdirSync3, openSync, readdirSync as readdirSync3, readFileSync as readFileSync13, renameSync as renameSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
25832
|
-
import
|
|
25832
|
+
import path130 from "path";
|
|
25833
25833
|
function syncDir(dir) {
|
|
25834
25834
|
if (process.platform === "win32")
|
|
25835
25835
|
return;
|
|
@@ -25841,7 +25841,7 @@ function syncDir(dir) {
|
|
|
25841
25841
|
}
|
|
25842
25842
|
}
|
|
25843
25843
|
function writePreservationFile(file, body) {
|
|
25844
|
-
const dir =
|
|
25844
|
+
const dir = path130.dirname(file);
|
|
25845
25845
|
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
25846
25846
|
const tmp = `${file}.${randomUUID3()}.tmp`;
|
|
25847
25847
|
const fd = openSync(tmp, "wx", 384);
|
|
@@ -25866,11 +25866,11 @@ function writePreservationFile(file, body) {
|
|
|
25866
25866
|
}
|
|
25867
25867
|
}
|
|
25868
25868
|
function readPreservation(dir, snapshotId) {
|
|
25869
|
-
const base =
|
|
25869
|
+
const base = path130.join(dir, "preservation");
|
|
25870
25870
|
let id = snapshotId;
|
|
25871
25871
|
if (id === undefined) {
|
|
25872
25872
|
try {
|
|
25873
|
-
id = readFileSync13(
|
|
25873
|
+
id = readFileSync13(path130.join(base, "CURRENT"), "utf8");
|
|
25874
25874
|
} catch (e) {
|
|
25875
25875
|
if (e.code === "ENOENT")
|
|
25876
25876
|
return;
|
|
@@ -25879,7 +25879,7 @@ function readPreservation(dir, snapshotId) {
|
|
|
25879
25879
|
}
|
|
25880
25880
|
if (!/^[a-f0-9]{64}$/.test(id))
|
|
25881
25881
|
throw new Error("invalid preservation identity");
|
|
25882
|
-
const read = readTranscriptFile(
|
|
25882
|
+
const read = readTranscriptFile(path130.join(base, "generations", `${id}.json`));
|
|
25883
25883
|
if (!read.ok)
|
|
25884
25884
|
throw new Error(`snapshot unreadable: ${read.reason}`);
|
|
25885
25885
|
if (hash(read.text) !== id)
|
|
@@ -25897,9 +25897,9 @@ function readPreservation(dir, snapshotId) {
|
|
|
25897
25897
|
return parsed;
|
|
25898
25898
|
}
|
|
25899
25899
|
function readPendingHistory(dir) {
|
|
25900
|
-
let read = readConfigFile(
|
|
25900
|
+
let read = readConfigFile(path130.join(dir, "preservation", "HISTORY"));
|
|
25901
25901
|
if (!read.ok && read.reason === "absent") {
|
|
25902
|
-
read = readConfigFile(
|
|
25902
|
+
read = readConfigFile(path130.join(dir, "preservation", "MIRRORING"));
|
|
25903
25903
|
}
|
|
25904
25904
|
if (!read.ok) {
|
|
25905
25905
|
if (read.reason === "absent")
|
|
@@ -25923,12 +25923,12 @@ var init_preservation = __esm(() => {
|
|
|
25923
25923
|
|
|
25924
25924
|
// src/session/slate.ts
|
|
25925
25925
|
import { mkdir as mkdir33, readFile as readFile66, readdir as readdir23, stat as stat17 } from "fs/promises";
|
|
25926
|
-
import
|
|
25926
|
+
import path135 from "path";
|
|
25927
25927
|
function isSlateSeedKind(value) {
|
|
25928
25928
|
return typeof value === "string" && SLATE_SEED_KINDS.includes(value);
|
|
25929
25929
|
}
|
|
25930
25930
|
function slatePath(dir) {
|
|
25931
|
-
return
|
|
25931
|
+
return path135.join(dir, "slate.json");
|
|
25932
25932
|
}
|
|
25933
25933
|
function slateLockPath(dir) {
|
|
25934
25934
|
return `${slatePath(dir)}.lock`;
|
|
@@ -26394,7 +26394,7 @@ __export(exports_service10, {
|
|
|
26394
26394
|
init_fs();
|
|
26395
26395
|
init_validator();
|
|
26396
26396
|
import { mkdir as mkdir13, readFile as readFile39 } from "fs/promises";
|
|
26397
|
-
import
|
|
26397
|
+
import path78 from "path";
|
|
26398
26398
|
|
|
26399
26399
|
// src/flow/machine.ts
|
|
26400
26400
|
var TRANSITIONS = {
|
|
@@ -26593,7 +26593,7 @@ function evaluateTaskGate(tasks) {
|
|
|
26593
26593
|
}
|
|
26594
26594
|
|
|
26595
26595
|
// src/review/coverage-complete.ts
|
|
26596
|
-
import
|
|
26596
|
+
import path54 from "path";
|
|
26597
26597
|
|
|
26598
26598
|
// src/lib/shell-quote.ts
|
|
26599
26599
|
function shellQuote(value) {
|
|
@@ -26611,7 +26611,7 @@ init_fs();
|
|
|
26611
26611
|
import { createHash as createHash8 } from "crypto";
|
|
26612
26612
|
import { existsSync as existsSync9 } from "fs";
|
|
26613
26613
|
init_fs();
|
|
26614
|
-
import
|
|
26614
|
+
import path53 from "path";
|
|
26615
26615
|
|
|
26616
26616
|
// src/review/blast-radius.ts
|
|
26617
26617
|
init_affected();
|
|
@@ -27552,7 +27552,7 @@ var encoder = new TextEncoder;
|
|
|
27552
27552
|
// src/review/coverage.ts
|
|
27553
27553
|
import { existsSync as existsSync8 } from "fs";
|
|
27554
27554
|
import { readFile as readFile23, realpath as realpath13 } from "fs/promises";
|
|
27555
|
-
import
|
|
27555
|
+
import path52 from "path";
|
|
27556
27556
|
|
|
27557
27557
|
// src/review/git-base.ts
|
|
27558
27558
|
var SHA = /^[0-9a-f]{7,64}$/i;
|
|
@@ -29211,6 +29211,39 @@ function decisionWriters(kind, packageArg = "<review-dir>") {
|
|
|
29211
29211
|
import { existsSync as existsSync7 } from "fs";
|
|
29212
29212
|
import { cp, mkdir as mkdir9, mkdtemp, readFile as readFile22, readdir as readdir11, realpath as realpath12, rm as rm3, symlink, writeFile as writeFile6 } from "fs/promises";
|
|
29213
29213
|
import path50 from "path";
|
|
29214
|
+
|
|
29215
|
+
// src/lib/git-env.ts
|
|
29216
|
+
var GIT_DISCOVERY_OVERRIDE_VARS = [
|
|
29217
|
+
"GIT_DIR",
|
|
29218
|
+
"GIT_WORK_TREE",
|
|
29219
|
+
"GIT_INDEX_FILE",
|
|
29220
|
+
"GIT_OBJECT_DIRECTORY",
|
|
29221
|
+
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
29222
|
+
"GIT_COMMON_DIR"
|
|
29223
|
+
];
|
|
29224
|
+
function withoutGitDiscoveryOverrides(env) {
|
|
29225
|
+
const clean = {};
|
|
29226
|
+
for (const [key, value] of Object.entries(env)) {
|
|
29227
|
+
if (value !== undefined && !GIT_DISCOVERY_OVERRIDE_VARS.includes(key)) {
|
|
29228
|
+
clean[key] = value;
|
|
29229
|
+
}
|
|
29230
|
+
}
|
|
29231
|
+
return clean;
|
|
29232
|
+
}
|
|
29233
|
+
|
|
29234
|
+
// src/review/worktree-provenance.ts
|
|
29235
|
+
var REVIEW_PACKAGES_DIR = ".metaproject/reviews";
|
|
29236
|
+
var EXCLUDE_REVIEW_PACKAGES = `:(exclude)${REVIEW_PACKAGES_DIR}`;
|
|
29237
|
+
var DEFAULT_PROVENANCE_LIMITS = {
|
|
29238
|
+
maxUntrackedFiles: 20000,
|
|
29239
|
+
maxHashedFileBytes: 10 * 1024 * 1024,
|
|
29240
|
+
maxGitOutputBytes: 64 * 1024 * 1024,
|
|
29241
|
+
maxTotalBytes: 256 * 1024 * 1024,
|
|
29242
|
+
gitTimeoutMs: 60000,
|
|
29243
|
+
maxMs: 120000
|
|
29244
|
+
};
|
|
29245
|
+
|
|
29246
|
+
// src/review/mutate.ts
|
|
29214
29247
|
var MUTANT_KINDS = ["behavior", "presentation"];
|
|
29215
29248
|
var MUTANTS_SPEC = "mutants.json";
|
|
29216
29249
|
var EVIDENCE_DIR = "research-evidence";
|
|
@@ -29288,6 +29321,85 @@ async function pendingMutants(packageDir) {
|
|
|
29288
29321
|
}
|
|
29289
29322
|
return unjudgedMutants(packageDir, specs);
|
|
29290
29323
|
}
|
|
29324
|
+
// src/review/role-switches.ts
|
|
29325
|
+
init_fs();
|
|
29326
|
+
init_json();
|
|
29327
|
+
import path51 from "path";
|
|
29328
|
+
var OPTIONAL_BY_DEFAULT = ["review-clean-code", "review-style"];
|
|
29329
|
+
var ROUND_ROLES_FILE = "round-roles.json";
|
|
29330
|
+
var ROLE_LINE_PREFIX = "\u043E\u043F\u0446\u0438\u043E\u043D\u0430\u043B\u044C\u043D\u044B\u0435 \u0440\u043E\u043B\u0438 \u043D\u0435 \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u043B\u0438\u0441\u044C:";
|
|
29331
|
+
var names = (value, field, warnings) => {
|
|
29332
|
+
if (value === undefined)
|
|
29333
|
+
return [];
|
|
29334
|
+
if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
|
|
29335
|
+
warnings.push(`routing.config.json reviewRoles.${field} must be a list of role names; it is ignored`);
|
|
29336
|
+
return [];
|
|
29337
|
+
}
|
|
29338
|
+
return [...new Set(value.map((item) => item.trim()).filter(Boolean))];
|
|
29339
|
+
};
|
|
29340
|
+
async function readRoleConfig(projectRoot) {
|
|
29341
|
+
const none = { disabled: [], enabled: [], warnings: [] };
|
|
29342
|
+
const file = path51.join(projectRoot, "routing.config.json");
|
|
29343
|
+
if (!await pathExists(file))
|
|
29344
|
+
return none;
|
|
29345
|
+
const read = await readJsonObjectFile(file);
|
|
29346
|
+
if (read.state !== "object")
|
|
29347
|
+
return { ...none, warnings: [`${file} could not be read as a JSON object (${read.state}); reviewRoles is ignored`] };
|
|
29348
|
+
const own = read.value.reviewRoles;
|
|
29349
|
+
if (own === undefined)
|
|
29350
|
+
return none;
|
|
29351
|
+
if (own === null || typeof own !== "object" || Array.isArray(own))
|
|
29352
|
+
return { ...none, warnings: ["routing.config.json reviewRoles must be an object with disabled and enabled lists; it is ignored"] };
|
|
29353
|
+
const fields = own;
|
|
29354
|
+
const warnings = [];
|
|
29355
|
+
return { disabled: names(fields.disabled, "disabled", warnings), enabled: names(fields.enabled, "enabled", warnings), warnings };
|
|
29356
|
+
}
|
|
29357
|
+
function decideRoleSwitches(input) {
|
|
29358
|
+
const { roster, config, optIn, protectedRoles } = input;
|
|
29359
|
+
const known = new Set(roster);
|
|
29360
|
+
const warnings = [...config.warnings];
|
|
29361
|
+
const off = new Map;
|
|
29362
|
+
for (const name of OPTIONAL_BY_DEFAULT)
|
|
29363
|
+
off.set(name, `optional role, off by default (--style turns it on)`);
|
|
29364
|
+
if (input.configIgnored !== undefined && config.disabled.length > 0)
|
|
29365
|
+
warnings.push(`reviewRoles.disabled not applied: ${input.configIgnored}`);
|
|
29366
|
+
else {
|
|
29367
|
+
for (const name of config.disabled) {
|
|
29368
|
+
if (protectedRoles.has(name))
|
|
29369
|
+
warnings.push(`reviewRoles.disabled: ${name} is a core role that always runs; it stays on`);
|
|
29370
|
+
else if (!known.has(name))
|
|
29371
|
+
warnings.push(`reviewRoles.disabled: unknown role "${name}"; ignored`);
|
|
29372
|
+
else
|
|
29373
|
+
off.set(name, `disabled by routing.config.json reviewRoles.disabled (--with-role ${name} turns it on)`);
|
|
29374
|
+
}
|
|
29375
|
+
}
|
|
29376
|
+
for (const name of config.enabled) {
|
|
29377
|
+
if (!known.has(name) && !OPTIONAL_BY_DEFAULT.includes(name))
|
|
29378
|
+
warnings.push(`reviewRoles.enabled: unknown role "${name}"; ignored`);
|
|
29379
|
+
else
|
|
29380
|
+
off.delete(name);
|
|
29381
|
+
}
|
|
29382
|
+
for (const name of optIn) {
|
|
29383
|
+
if (!known.has(name) && !OPTIONAL_BY_DEFAULT.includes(name))
|
|
29384
|
+
warnings.push(`--with-role: unknown role "${name}"; ignored`);
|
|
29385
|
+
else
|
|
29386
|
+
off.delete(name);
|
|
29387
|
+
}
|
|
29388
|
+
for (const name of [...off.keys()])
|
|
29389
|
+
if (!known.has(name))
|
|
29390
|
+
off.delete(name);
|
|
29391
|
+
return { off, warnings };
|
|
29392
|
+
}
|
|
29393
|
+
async function packageEnabledRoles(packageDir) {
|
|
29394
|
+
const read = await readJsonObjectFile(path51.join(packageDir, ROUND_ROLES_FILE)).catch(() => {
|
|
29395
|
+
return;
|
|
29396
|
+
});
|
|
29397
|
+
if (read?.state !== "object" || !Array.isArray(read.value.enabled))
|
|
29398
|
+
return [];
|
|
29399
|
+
return read.value.enabled.filter((item) => typeof item === "string" && item.trim() !== "");
|
|
29400
|
+
}
|
|
29401
|
+
var LINE = new RegExp(`^${ROLE_LINE_PREFIX}.*$`, "m");
|
|
29402
|
+
|
|
29291
29403
|
// src/review/coverage.ts
|
|
29292
29404
|
var LIGHT_MAX_FILES = 5;
|
|
29293
29405
|
var LIGHT_MAX_CHANGED_LINES = 300;
|
|
@@ -29299,8 +29411,8 @@ function overlayChangedByRound(reviewer, context) {
|
|
|
29299
29411
|
return;
|
|
29300
29412
|
if (context.files === undefined)
|
|
29301
29413
|
return `${reviewer.name} is a project overlay and the round's changed files are not recorded, so it cannot be ruled out that this branch wrote it`;
|
|
29302
|
-
const absolute =
|
|
29303
|
-
const dir =
|
|
29414
|
+
const absolute = path52.isAbsolute(reviewer.path) ? reviewer.path : path52.resolve(context.root ?? process.cwd(), reviewer.path);
|
|
29415
|
+
const dir = path52.relative(context.root ?? process.cwd(), path52.dirname(absolute)).split(path52.sep).join("/");
|
|
29304
29416
|
const changed = context.files.find((file) => file === dir || file.startsWith(`${dir}/`));
|
|
29305
29417
|
return changed === undefined ? undefined : `${reviewer.name} is a project overlay this round changes (${changed})`;
|
|
29306
29418
|
}
|
|
@@ -29365,7 +29477,7 @@ async function autoDepth(root, input) {
|
|
|
29365
29477
|
}
|
|
29366
29478
|
var ROUND_DEPTH_FILE = "round-depth.json";
|
|
29367
29479
|
async function packageDepthBasis(packageDir) {
|
|
29368
|
-
const manifest = await readFile23(
|
|
29480
|
+
const manifest = await readFile23(path52.join(packageDir, "manifest.json"), "utf8").then((t) => JSON.parse(t)).catch(() => {
|
|
29369
29481
|
return;
|
|
29370
29482
|
});
|
|
29371
29483
|
const head = manifest?.target?.head;
|
|
@@ -29374,7 +29486,7 @@ async function packageDepthBasis(packageDir) {
|
|
|
29374
29486
|
}
|
|
29375
29487
|
async function packageChangedLines(packageDir) {
|
|
29376
29488
|
try {
|
|
29377
|
-
const parsed = JSON.parse(await readFile23(
|
|
29489
|
+
const parsed = JSON.parse(await readFile23(path52.join(packageDir, "scope-files.json"), "utf8"));
|
|
29378
29490
|
return typeof parsed?.changedLines === "number" && Number.isFinite(parsed.changedLines) && parsed.changedLines >= 0 ? parsed.changedLines : undefined;
|
|
29379
29491
|
} catch {
|
|
29380
29492
|
return;
|
|
@@ -29383,7 +29495,7 @@ async function packageChangedLines(packageDir) {
|
|
|
29383
29495
|
async function packageRoundDepth(packageDir) {
|
|
29384
29496
|
let parsed;
|
|
29385
29497
|
try {
|
|
29386
|
-
parsed = JSON.parse(await readFile23(
|
|
29498
|
+
parsed = JSON.parse(await readFile23(path52.join(packageDir, ROUND_DEPTH_FILE), "utf8"));
|
|
29387
29499
|
} catch {
|
|
29388
29500
|
return;
|
|
29389
29501
|
}
|
|
@@ -29436,7 +29548,7 @@ function derivedFromFiles(files) {
|
|
|
29436
29548
|
return picked;
|
|
29437
29549
|
}
|
|
29438
29550
|
async function readSkill(root, relativePath) {
|
|
29439
|
-
const file =
|
|
29551
|
+
const file = path52.join(root, relativePath, "SKILL.md");
|
|
29440
29552
|
return existsSync8(file) ? readFile23(file, "utf8").catch(() => {
|
|
29441
29553
|
return;
|
|
29442
29554
|
}) : undefined;
|
|
@@ -29546,6 +29658,21 @@ async function requiredReviewers(root, mode, files, options = {}) {
|
|
|
29546
29658
|
projectGates.set(reviewer.name, reviewer.paths.map(globToRegExp2));
|
|
29547
29659
|
}
|
|
29548
29660
|
const filesKnown = files !== undefined;
|
|
29661
|
+
const switches = decideRoleSwitches({
|
|
29662
|
+
roster,
|
|
29663
|
+
config: await readRoleConfig(root),
|
|
29664
|
+
optIn: options.enabledRoles ?? [],
|
|
29665
|
+
protectedRoles: NEVER_SUPERSEDED,
|
|
29666
|
+
configIgnored: files?.some((file) => file === "routing.config.json") ? "this round changes routing.config.json, so a branch cannot switch roles off for its own review" : undefined
|
|
29667
|
+
});
|
|
29668
|
+
const rolesOff = [...switches.off.keys()].sort();
|
|
29669
|
+
const warnings = switches.warnings;
|
|
29670
|
+
const switchedOff = (name) => switches.off.has(name);
|
|
29671
|
+
for (const name of roster)
|
|
29672
|
+
if (switchedOff(name))
|
|
29673
|
+
excluded.push({ reviewer: name, reason: switches.off.get(name) });
|
|
29674
|
+
roster.splice(0, roster.length, ...roster.filter((name) => !switchedOff(name)));
|
|
29675
|
+
const switchFields = { ...warnings.length === 0 ? {} : { warnings }, ...rolesOff.length === 0 ? {} : { rolesOff } };
|
|
29549
29676
|
if (options.depth === "light") {
|
|
29550
29677
|
const conventions = lightConventionsReviewer(roster, inventory);
|
|
29551
29678
|
const keep = new Set([...LIGHT_FIXED_REVIEWERS, ...conventions === undefined ? [] : [conventions]]);
|
|
@@ -29558,7 +29685,7 @@ async function requiredReviewers(root, mode, files, options = {}) {
|
|
|
29558
29685
|
excluded.push({ reviewer: name, reason: "light round: not part of the light set" });
|
|
29559
29686
|
const notes = [];
|
|
29560
29687
|
const kept = applySupersedes(light, inventory, excluded, { root, files }, notes).sort();
|
|
29561
|
-
return { mode, depth: "light", required: kept, excluded, filesKnown, ...notes.length === 0 ? {} : { notes } };
|
|
29688
|
+
return { mode, depth: "light", required: kept, excluded, filesKnown, ...notes.length === 0 ? {} : { notes }, ...switchFields };
|
|
29562
29689
|
}
|
|
29563
29690
|
const gated = (name) => {
|
|
29564
29691
|
if (!filesKnown)
|
|
@@ -29600,7 +29727,7 @@ async function requiredReviewers(root, mode, files, options = {}) {
|
|
|
29600
29727
|
}
|
|
29601
29728
|
const notes = [];
|
|
29602
29729
|
const collapsed = applyOverlapGroups(applySupersedes(required, inventory, excluded, { root, files }, notes), inventory, files, excluded, { root }, notes).sort();
|
|
29603
|
-
return { mode, depth: "full", required: collapsed, excluded, filesKnown, ...notes.length === 0 ? {} : { notes } };
|
|
29730
|
+
return { mode, depth: "full", required: collapsed, excluded, filesKnown, ...notes.length === 0 ? {} : { notes }, ...switchFields };
|
|
29604
29731
|
}
|
|
29605
29732
|
async function gitDiffAt(cwd, base, head, pathspec) {
|
|
29606
29733
|
try {
|
|
@@ -29665,7 +29792,7 @@ async function packageDiffStats(options) {
|
|
|
29665
29792
|
return packageDiffStatsCached({ packageDir: options.packageDir, root: options.root, target: { ...target, head: target.head } });
|
|
29666
29793
|
}
|
|
29667
29794
|
async function readPackageTarget(packageDir) {
|
|
29668
|
-
const manifest = await readFile23(
|
|
29795
|
+
const manifest = await readFile23(path52.join(packageDir, "manifest.json"), "utf8").then((t) => JSON.parse(t)).catch(() => {
|
|
29669
29796
|
return;
|
|
29670
29797
|
});
|
|
29671
29798
|
const target = asRecord(asRecord(manifest)?.target) ?? {};
|
|
@@ -29704,8 +29831,8 @@ async function diffOfTarget({ packageDir, root, target }) {
|
|
|
29704
29831
|
const resolved = await resolveDiffBases(cwd, target);
|
|
29705
29832
|
if ("error" in resolved)
|
|
29706
29833
|
return { error: `${UNRESOLVED}: ${resolved.error} (${where(target.recordedBase)})` };
|
|
29707
|
-
const realRoot = await realpath13(
|
|
29708
|
-
const pathspec = notReviewPackagesAt(
|
|
29834
|
+
const realRoot = await realpath13(path52.resolve(root)).catch(() => path52.resolve(root));
|
|
29835
|
+
const pathspec = notReviewPackagesAt(path52.relative(cwd, realRoot));
|
|
29709
29836
|
const results = await Promise.all(resolved.bases.map((base) => gitDiffAt(cwd, base, target.head, pathspec)));
|
|
29710
29837
|
const diffs = [];
|
|
29711
29838
|
for (const [index, result] of results.entries()) {
|
|
@@ -29737,7 +29864,7 @@ async function effectiveDepth(record, options) {
|
|
|
29737
29864
|
}
|
|
29738
29865
|
async function packageHead(packageDir) {
|
|
29739
29866
|
try {
|
|
29740
|
-
const manifest = JSON.parse(await readFile23(
|
|
29867
|
+
const manifest = JSON.parse(await readFile23(path52.join(packageDir, "manifest.json"), "utf8"));
|
|
29741
29868
|
return typeof manifest.target?.head === "string" && manifest.target.head.trim() !== "" ? manifest.target.head.trim() : undefined;
|
|
29742
29869
|
} catch {
|
|
29743
29870
|
return;
|
|
@@ -29746,7 +29873,8 @@ async function packageHead(packageDir) {
|
|
|
29746
29873
|
async function reviewersLeftOut(packageDir, selected) {
|
|
29747
29874
|
const need = await requiredReviewers(projectRootOfPackage(packageDir), "all", await packageScopeFiles(packageDir), {
|
|
29748
29875
|
blastRadius: await packageHasBlastRadius(packageDir),
|
|
29749
|
-
prContext: packageHasPrContext(packageDir)
|
|
29876
|
+
prContext: packageHasPrContext(packageDir),
|
|
29877
|
+
enabledRoles: await packageEnabledRoles(packageDir)
|
|
29750
29878
|
});
|
|
29751
29879
|
return { required: need.required, missing: selected === undefined ? need.required : need.required.filter((role) => !selected.includes(role)) };
|
|
29752
29880
|
}
|
|
@@ -29767,7 +29895,7 @@ async function unconfirmedDecision(options, kind, selected) {
|
|
|
29767
29895
|
return `${stale}${writersFor(kind, dir)}`;
|
|
29768
29896
|
}
|
|
29769
29897
|
function writersFor(kind, packageDir) {
|
|
29770
|
-
return decisionWriters(kind, packageDir === undefined ? "<review-dir>" :
|
|
29898
|
+
return decisionWriters(kind, packageDir === undefined ? "<review-dir>" : path52.relative(process.cwd(), packageDir) || ".");
|
|
29771
29899
|
}
|
|
29772
29900
|
async function mutationErrors(record, options, depth) {
|
|
29773
29901
|
const pending = options.pendingMutants ?? 0;
|
|
@@ -29793,14 +29921,14 @@ async function mutationErrors(record, options, depth) {
|
|
|
29793
29921
|
}
|
|
29794
29922
|
async function packageHasBlastRadius(packageDir, name = "blast-radius.json") {
|
|
29795
29923
|
try {
|
|
29796
|
-
const parsed = JSON.parse(await readFile23(
|
|
29924
|
+
const parsed = JSON.parse(await readFile23(path52.join(packageDir, name), "utf8"));
|
|
29797
29925
|
return Array.isArray(parsed?.files) && Array.isArray(parsed?.changedFiles);
|
|
29798
29926
|
} catch {
|
|
29799
29927
|
return false;
|
|
29800
29928
|
}
|
|
29801
29929
|
}
|
|
29802
29930
|
function packageHasPrContext(packageDir, name = "pr-context.md") {
|
|
29803
|
-
return existsSync8(
|
|
29931
|
+
return existsSync8(path52.join(packageDir, name));
|
|
29804
29932
|
}
|
|
29805
29933
|
async function coverageErrors(dispatch, options) {
|
|
29806
29934
|
const record = asRecord(dispatch);
|
|
@@ -29832,7 +29960,8 @@ async function reviewerSetErrors(dispatch, options, effective) {
|
|
|
29832
29960
|
const need = await requiredReviewers(options.root, record.mode, options.files, {
|
|
29833
29961
|
blastRadius: options.blastRadius,
|
|
29834
29962
|
prContext: options.prContext === true && dispatchKnowsRole(record, PR_CONTRACT),
|
|
29835
|
-
depth: effective?.depth ?? "full"
|
|
29963
|
+
depth: effective?.depth ?? "full",
|
|
29964
|
+
enabledRoles: options.packageDir === undefined ? [] : await packageEnabledRoles(options.packageDir)
|
|
29836
29965
|
});
|
|
29837
29966
|
const selected = new Set(Array.isArray(record.selected) ? record.selected.filter(text) : []);
|
|
29838
29967
|
const skips = dispatchSkips(record).filter((skip) => need.required.includes(skip.reviewer) && !selected.has(skip.reviewer));
|
|
@@ -29892,20 +30021,20 @@ function dispatchSkips(dispatch) {
|
|
|
29892
30021
|
}
|
|
29893
30022
|
async function packageScopeFiles(packageDir) {
|
|
29894
30023
|
try {
|
|
29895
|
-
const parsed = JSON.parse(await readFile23(
|
|
30024
|
+
const parsed = JSON.parse(await readFile23(path52.join(packageDir, "scope-files.json"), "utf8"));
|
|
29896
30025
|
return Array.isArray(parsed?.files) && parsed.files.every((f) => typeof f === "string") ? parsed.files : undefined;
|
|
29897
30026
|
} catch {
|
|
29898
30027
|
return;
|
|
29899
30028
|
}
|
|
29900
30029
|
}
|
|
29901
30030
|
function projectRootOfPackage(packageDir) {
|
|
29902
|
-
const resolved =
|
|
29903
|
-
const parts = resolved.split(
|
|
30031
|
+
const resolved = path52.resolve(packageDir);
|
|
30032
|
+
const parts = resolved.split(path52.sep);
|
|
29904
30033
|
const at = parts.lastIndexOf(".metaproject");
|
|
29905
30034
|
if (at > 0)
|
|
29906
|
-
return parts.slice(0, at).join(
|
|
30035
|
+
return parts.slice(0, at).join(path52.sep) || path52.sep;
|
|
29907
30036
|
const found = resolveProjectRoot(resolved);
|
|
29908
|
-
return found !== resolved ? found :
|
|
30037
|
+
return found !== resolved ? found : path52.resolve(resolved, "..", "..", "..");
|
|
29909
30038
|
}
|
|
29910
30039
|
|
|
29911
30040
|
// src/review/conform-state.ts
|
|
@@ -30060,14 +30189,14 @@ var CHUNK_STATE_FILE = "chunk-state.json";
|
|
|
30060
30189
|
var CHUNK_REVIEWER = BLAST_RADIUS_SCOPE_REVIEWER;
|
|
30061
30190
|
var readJson = (file) => readJsonFileOr(file, undefined);
|
|
30062
30191
|
async function readChunkPlan(packageDir) {
|
|
30063
|
-
const plan = await readJson(
|
|
30192
|
+
const plan = await readJson(path53.join(packageDir, CHUNKS_FILE));
|
|
30064
30193
|
return plan !== undefined && Array.isArray(plan.chunks) ? plan : undefined;
|
|
30065
30194
|
}
|
|
30066
30195
|
function emptyChunkState() {
|
|
30067
30196
|
return { schemaVersion: 1, retry: emptyRetryState(), derived: [], outcomes: {} };
|
|
30068
30197
|
}
|
|
30069
30198
|
async function readChunkState(packageDir) {
|
|
30070
|
-
const state = await readJson(
|
|
30199
|
+
const state = await readJson(path53.join(packageDir, CHUNK_STATE_FILE));
|
|
30071
30200
|
return state !== undefined && state.retry !== undefined && Array.isArray(state.derived) && state.outcomes !== undefined ? state : emptyChunkState();
|
|
30072
30201
|
}
|
|
30073
30202
|
var textOf = (entry) => `${entry.files.join(`
|
|
@@ -30164,7 +30293,7 @@ async function computeChunkPass(packageDir) {
|
|
|
30164
30293
|
return pass;
|
|
30165
30294
|
}
|
|
30166
30295
|
function hasChunkPlan(packageDir) {
|
|
30167
|
-
return existsSync9(
|
|
30296
|
+
return existsSync9(path53.join(packageDir, CHUNKS_FILE));
|
|
30168
30297
|
}
|
|
30169
30298
|
|
|
30170
30299
|
// src/review/coverage-complete.ts
|
|
@@ -30174,7 +30303,7 @@ var SLICE_MANIFEST_COPY = "slice-manifest.json";
|
|
|
30174
30303
|
var readJson2 = (file) => readJsonFileOr(file, undefined);
|
|
30175
30304
|
var text2 = (value) => typeof value === "string" && value.trim().length > 0;
|
|
30176
30305
|
async function readManifest(packageDir) {
|
|
30177
|
-
for (const candidate of [
|
|
30306
|
+
for (const candidate of [path54.join(packageDir, "slices", "manifest.json"), path54.join(packageDir, SLICE_MANIFEST_COPY)]) {
|
|
30178
30307
|
const found = await readJson2(candidate);
|
|
30179
30308
|
if (found !== undefined && Array.isArray(found.slices))
|
|
30180
30309
|
return found;
|
|
@@ -30212,9 +30341,9 @@ function scopeBRunComplete(dispatch) {
|
|
|
30212
30341
|
async function packageRecordsCoverage(packageDir, research) {
|
|
30213
30342
|
if (hasChunkPlan(packageDir))
|
|
30214
30343
|
return true;
|
|
30215
|
-
if (await readJson2(
|
|
30344
|
+
if (await readJson2(path54.join(packageDir, COVERAGE_FILE)) !== undefined)
|
|
30216
30345
|
return true;
|
|
30217
|
-
const ledger = research ?? await readJson2(
|
|
30346
|
+
const ledger = research ?? await readJson2(path54.join(packageDir, "research.json"));
|
|
30218
30347
|
return dispatchRunRecords(asRecord(ledger)?.dispatch).some((run) => Array.isArray(run.coveredSlices));
|
|
30219
30348
|
}
|
|
30220
30349
|
function readCoverageWaiver(dispatch) {
|
|
@@ -30228,11 +30357,11 @@ function readCoverageWaiver(dispatch) {
|
|
|
30228
30357
|
return { operatorQuote: waiver.operatorQuote, time: waiver.time, files, ...via === undefined ? {} : { confirmedVia: via }, ...cardPressFields({ pressedBy, pressedAt }) };
|
|
30229
30358
|
}
|
|
30230
30359
|
async function computeCoverage(packageDir, options = {}) {
|
|
30231
|
-
const research = options.research ?? await readJson2(
|
|
30360
|
+
const research = options.research ?? await readJson2(path54.join(packageDir, "research.json"));
|
|
30232
30361
|
const dispatch = asRecord(asRecord(research)?.dispatch);
|
|
30233
|
-
const radius = await readJson2(
|
|
30362
|
+
const radius = await readJson2(path54.join(packageDir, "blast-radius.json"));
|
|
30234
30363
|
const manifest = await readManifest(packageDir);
|
|
30235
|
-
const retry = await readJson2(
|
|
30364
|
+
const retry = await readJson2(path54.join(packageDir, "retry-state.json"));
|
|
30236
30365
|
const scopeA = await packageScopeFiles(packageDir) ?? [];
|
|
30237
30366
|
const chunkPass = hasChunkPlan(packageDir) ? await computeChunkPass(packageDir) : null;
|
|
30238
30367
|
const radiusFiles = (radius?.files ?? []).map((entry) => entry.file).filter(text2);
|
|
@@ -30320,7 +30449,7 @@ async function coverageGateErrors(packageDir, research) {
|
|
|
30320
30449
|
const uncovered = report.files.filter((entry) => entry.status === "uncovered");
|
|
30321
30450
|
const first = uncovered.slice(0, FIRST_FILES).map((entry) => entry.file);
|
|
30322
30451
|
const more = uncovered.length > FIRST_FILES ? `, \u2026 (+${uncovered.length - FIRST_FILES})` : "";
|
|
30323
|
-
const dir = shellWord(
|
|
30452
|
+
const dir = shellWord(path54.relative(process.cwd(), packageDir) || ".");
|
|
30324
30453
|
const chunkWork = uncovered.some((entry) => entry.scope === "B");
|
|
30325
30454
|
const sliceWork = uncovered.some((entry) => entry.scope === "A");
|
|
30326
30455
|
const commands = [
|
|
@@ -30389,7 +30518,7 @@ function dispatchErrors(value) {
|
|
|
30389
30518
|
|
|
30390
30519
|
// src/review/research.ts
|
|
30391
30520
|
import { readFile as readFile24 } from "fs/promises";
|
|
30392
|
-
import
|
|
30521
|
+
import path55 from "path";
|
|
30393
30522
|
function researchErrors(value, findings) {
|
|
30394
30523
|
const ledger = asRecord(value);
|
|
30395
30524
|
if (ledger === undefined)
|
|
@@ -30453,7 +30582,7 @@ async function packageResearchErrors(packageDir, artifacts, findings, options =
|
|
|
30453
30582
|
if (a.research !== "research.json")
|
|
30454
30583
|
return ["invalid research artifact locator"];
|
|
30455
30584
|
try {
|
|
30456
|
-
const ledger = JSON.parse(await readFile24(
|
|
30585
|
+
const ledger = JSON.parse(await readFile24(path55.join(packageDir, "research.json"), "utf8"));
|
|
30457
30586
|
const recorded = ledger?.dispatch !== undefined;
|
|
30458
30587
|
const checked = a.reviewerDispatch !== undefined || recorded;
|
|
30459
30588
|
const mismatch = recorded && a.reviewerDispatch === undefined ? ['research.json records a reviewer dispatch but manifest.json does not declare it: restore artifacts.reviewerDispatch "research.json"'] : [];
|
|
@@ -30516,11 +30645,11 @@ var CARRIED_PREMISE_CONTEXT = new Set(["judge", "model", "operator"]);
|
|
|
30516
30645
|
// src/flow/review-gate.ts
|
|
30517
30646
|
init_fs();
|
|
30518
30647
|
import { readFile as readFile27 } from "fs/promises";
|
|
30519
|
-
import
|
|
30648
|
+
import path58 from "path";
|
|
30520
30649
|
|
|
30521
30650
|
// src/review/package-location.ts
|
|
30522
30651
|
import { readdir as readdir12, readFile as readFile25 } from "fs/promises";
|
|
30523
|
-
import
|
|
30652
|
+
import path56 from "path";
|
|
30524
30653
|
|
|
30525
30654
|
// src/lib/map-bounded.ts
|
|
30526
30655
|
async function mapBounded(items, limit, map) {
|
|
@@ -30536,15 +30665,15 @@ async function mapBounded(items, limit, map) {
|
|
|
30536
30665
|
|
|
30537
30666
|
// src/review/package-location.ts
|
|
30538
30667
|
function reviewsRoot(cwd) {
|
|
30539
|
-
return
|
|
30668
|
+
return path56.join(cwd, ".metaproject", "reviews");
|
|
30540
30669
|
}
|
|
30541
30670
|
function flowReviewsRoot(cwd, flowDir) {
|
|
30542
|
-
return
|
|
30671
|
+
return path56.join(flowsRoot(cwd), flowDir, "reviews");
|
|
30543
30672
|
}
|
|
30544
30673
|
async function readManifestHead(packageDir) {
|
|
30545
30674
|
let manifest;
|
|
30546
30675
|
try {
|
|
30547
|
-
manifest = JSON.parse(await readFile25(
|
|
30676
|
+
manifest = JSON.parse(await readFile25(path56.join(packageDir, "manifest.json"), "utf8"));
|
|
30548
30677
|
} catch {
|
|
30549
30678
|
return;
|
|
30550
30679
|
}
|
|
@@ -30556,13 +30685,13 @@ async function readManifestHead(packageDir) {
|
|
|
30556
30685
|
return { reviewId: str(fields.reviewId), mode: str(fields.mode), status: str(fields.status), flowId: str(flow.id), flowPath: str(flow.path) };
|
|
30557
30686
|
}
|
|
30558
30687
|
function boundToFlow(head, flowDir) {
|
|
30559
|
-
if (head.flowPath !== undefined &&
|
|
30688
|
+
if (head.flowPath !== undefined && path56.posix.normalize(head.flowPath.split(path56.sep).join("/")) === path56.posix.join(".metaproject", "flows", flowDir))
|
|
30560
30689
|
return true;
|
|
30561
30690
|
return head.flowId !== undefined && head.flowId !== "" && (flowDir === head.flowId || flowDir.startsWith(`${head.flowId}-`));
|
|
30562
30691
|
}
|
|
30563
30692
|
async function dirsUnder(root) {
|
|
30564
30693
|
try {
|
|
30565
|
-
return (await readdir12(root, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) =>
|
|
30694
|
+
return (await readdir12(root, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => path56.join(root, entry.name));
|
|
30566
30695
|
} catch {
|
|
30567
30696
|
return [];
|
|
30568
30697
|
}
|
|
@@ -30582,8 +30711,8 @@ async function flowPackageDirs(cwd, flowDir, standalone) {
|
|
|
30582
30711
|
return [...own, ...heads.filter(({ head }) => boundToFlow(head, flowDir)).map(({ dir }) => dir)];
|
|
30583
30712
|
}
|
|
30584
30713
|
var REVIEW_PACKAGE_MANIFEST_GLOBS = [
|
|
30585
|
-
|
|
30586
|
-
|
|
30714
|
+
path56.posix.join(".metaproject", "reviews", "*", "manifest.json"),
|
|
30715
|
+
path56.posix.join(".metaproject", "flows", "*", "reviews", "*", "manifest.json")
|
|
30587
30716
|
];
|
|
30588
30717
|
|
|
30589
30718
|
// src/review/loop.ts
|
|
@@ -30627,12 +30756,12 @@ function normalizeText(value) {
|
|
|
30627
30756
|
// src/review/pr-comments.ts
|
|
30628
30757
|
init_fs();
|
|
30629
30758
|
import { readFile as readFile26 } from "fs/promises";
|
|
30630
|
-
import
|
|
30759
|
+
import path57 from "path";
|
|
30631
30760
|
var SEVERITY_SET = new Set(["blocker", "major", "minor", "info"]);
|
|
30632
30761
|
var KNOWN_REVIEW_STATES = new Set(["APPROVED", "CHANGES_REQUESTED", "COMMENTED", "DISMISSED", "PENDING"]);
|
|
30633
30762
|
var PR_COMMENT_STATE_VERSION = 1;
|
|
30634
30763
|
function prCommentsStatePath(cwd, repo, number) {
|
|
30635
|
-
return
|
|
30764
|
+
return path57.join(cwd, ".metaproject", "reviews", "pr-comments", `${repo.replace(/\//g, "__")}__${number}.json`);
|
|
30636
30765
|
}
|
|
30637
30766
|
function emptyPrCommentState(repo, number) {
|
|
30638
30767
|
return {
|
|
@@ -30691,7 +30820,7 @@ function safeFsErrorCode(error) {
|
|
|
30691
30820
|
return typeof code === "string" && /^[A-Z][A-Z0-9]{2,15}$/.test(code) ? code : undefined;
|
|
30692
30821
|
}
|
|
30693
30822
|
async function readReviewGateConfig(cwd) {
|
|
30694
|
-
const file =
|
|
30823
|
+
const file = path58.join(cwd, REVIEW_GATE_CONFIG_PATH);
|
|
30695
30824
|
if (!await pathExists(file)) {
|
|
30696
30825
|
return { ...DEFAULT_REVIEW_GATE_CONFIG, notes: [] };
|
|
30697
30826
|
}
|
|
@@ -30843,13 +30972,13 @@ function matchNumber(text, key) {
|
|
|
30843
30972
|
async function readReviewRounds(cwd, flowDir) {
|
|
30844
30973
|
const rounds = [];
|
|
30845
30974
|
for (const packageDir of await flowPackageDirs(cwd, flowDir)) {
|
|
30846
|
-
const name =
|
|
30975
|
+
const name = path58.basename(packageDir);
|
|
30847
30976
|
const problems = [];
|
|
30848
|
-
const manifest = readRecord(await readJson3(
|
|
30977
|
+
const manifest = readRecord(await readJson3(path58.join(packageDir, "manifest.json")));
|
|
30849
30978
|
if (manifest === null) {
|
|
30850
30979
|
problems.push("manifest.json is missing or unreadable");
|
|
30851
30980
|
}
|
|
30852
|
-
const rawFindings = await readJson3(
|
|
30981
|
+
const rawFindings = await readJson3(path58.join(packageDir, "findings.json"));
|
|
30853
30982
|
if (!Array.isArray(rawFindings)) {
|
|
30854
30983
|
problems.push("findings.json is missing, unreadable, or not an array");
|
|
30855
30984
|
}
|
|
@@ -30867,14 +30996,14 @@ async function readReviewRounds(cwd, flowDir) {
|
|
|
30867
30996
|
}
|
|
30868
30997
|
];
|
|
30869
30998
|
}) : [];
|
|
30870
|
-
const scopePath =
|
|
30999
|
+
const scopePath = path58.join(packageDir, "scope.md");
|
|
30871
31000
|
const scope = await pathExists(scopePath) ? await readScopeMarkdown(scopePath) : null;
|
|
30872
31001
|
const completeness = readString(manifest?.["status"]) !== "closed" && await packageRecordsCoverage(packageDir);
|
|
30873
31002
|
problems.push(...await packageResearchErrors(packageDir, manifest?.["artifacts"], rawFindings, { completeness }));
|
|
30874
31003
|
const findings = Array.isArray(rawFindings) ? await findingsWithHolds(rawFindings.map((item, index) => toGateFinding(item, reviewId, index)), packageDir, problems) : [];
|
|
30875
31004
|
rounds.push({
|
|
30876
31005
|
reviewId,
|
|
30877
|
-
dir:
|
|
31006
|
+
dir: path58.relative(cwd, packageDir),
|
|
30878
31007
|
sortKey: readString(manifest?.["createdAt"]) ?? name,
|
|
30879
31008
|
ingested: problems.length === 0,
|
|
30880
31009
|
problems,
|
|
@@ -31161,7 +31290,7 @@ var durableExternalCommentsGate = async (input) => {
|
|
|
31161
31290
|
return {
|
|
31162
31291
|
collected: false,
|
|
31163
31292
|
unanswered: [],
|
|
31164
|
-
detail: `nothing records whether anyone commented on ${ref.repo}#${ref.number} ` + `(\`${
|
|
31293
|
+
detail: `nothing records whether anyone commented on ${ref.repo}#${ref.number} ` + `(\`${path58.relative(input.cwd, file)}\` does not exist). Zero collected comments and no collection at ` + "all are different facts, and only one of them is clean. Run " + `\`keryx review comments collect --repo ${ref.repo} --pr ${ref.number} --sha <pr-head>\`, or inject ` + "`FlowServiceDeps.externalCommentsGate` with a collector of your own."
|
|
31165
31294
|
};
|
|
31166
31295
|
}
|
|
31167
31296
|
const state = await readPrCommentState(input.cwd, ref.repo, ref.number);
|
|
@@ -31750,14 +31879,14 @@ function describeIdentity(identity) {
|
|
|
31750
31879
|
// src/review/flow-move.ts
|
|
31751
31880
|
init_fs();
|
|
31752
31881
|
import { readdir as readdir14, readFile as readFile29, rename as rename3 } from "fs/promises";
|
|
31753
|
-
import
|
|
31882
|
+
import path62 from "path";
|
|
31754
31883
|
|
|
31755
31884
|
// src/review/review-notes.ts
|
|
31756
31885
|
init_fs();
|
|
31757
31886
|
init_store();
|
|
31758
|
-
import
|
|
31887
|
+
import path61 from "path";
|
|
31759
31888
|
function reviewNotesDir(cwd) {
|
|
31760
|
-
return
|
|
31889
|
+
return path61.join(memoryRoot(cwd), "review-notes");
|
|
31761
31890
|
}
|
|
31762
31891
|
|
|
31763
31892
|
// src/review/flow-move.ts
|
|
@@ -31765,16 +31894,16 @@ var RECORDED_FLOWS_ROOT = ".metaproject/flows";
|
|
|
31765
31894
|
var SCOPE_FLOW_LINE = /^flow: (\d{3})\b/m;
|
|
31766
31895
|
var NOTE_PATH_LINE = /^(- (?:Link|Location): `?)([^`\s]+)/gm;
|
|
31767
31896
|
async function moveFlowDirWithReviewRecords(move) {
|
|
31768
|
-
const fromRoot =
|
|
31769
|
-
const toRoot =
|
|
31770
|
-
const plan = await planReviewRecordRewrites(move, fromRoot, (file) =>
|
|
31897
|
+
const fromRoot = path62.join(flowsRoot(move.cwd), move.fromDir);
|
|
31898
|
+
const toRoot = path62.join(flowsRoot(move.cwd), move.toDir);
|
|
31899
|
+
const plan = await planReviewRecordRewrites(move, fromRoot, (file) => path62.relative(move.cwd, file.startsWith(`${fromRoot}${path62.sep}`) ? path62.join(toRoot, path62.relative(fromRoot, file)) : file));
|
|
31771
31900
|
const written = [];
|
|
31772
31901
|
try {
|
|
31773
31902
|
for (const rewrite of plan.rewrites) {
|
|
31774
31903
|
await writeFileAtomic(rewrite.current, rewrite.after);
|
|
31775
31904
|
written.push(rewrite);
|
|
31776
31905
|
}
|
|
31777
|
-
await rename3(
|
|
31906
|
+
await rename3(path62.join(flowsRoot(move.cwd), move.fromDir), path62.join(flowsRoot(move.cwd), move.toDir));
|
|
31778
31907
|
} catch (error) {
|
|
31779
31908
|
const unrestored = await restore(written);
|
|
31780
31909
|
if (unrestored.length > 0) {
|
|
@@ -31800,14 +31929,14 @@ async function planReviewRecordRewrites(move, packagesRoot, finalOf) {
|
|
|
31800
31929
|
const newPrefix = `${RECORDED_FLOWS_ROOT}/${move.toDir}`;
|
|
31801
31930
|
const movePath = (value) => value === oldPrefix || value.startsWith(`${oldPrefix}/`) ? `${newPrefix}${value.slice(oldPrefix.length)}` : value;
|
|
31802
31931
|
const plan = { rewrites: [], unreadable: [] };
|
|
31803
|
-
const reviewsDir =
|
|
31932
|
+
const reviewsDir = path62.join(packagesRoot, "reviews");
|
|
31804
31933
|
if (await pathExists(reviewsDir)) {
|
|
31805
31934
|
for (const entry of await readdir14(reviewsDir, { withFileTypes: true })) {
|
|
31806
31935
|
if (!entry.isDirectory()) {
|
|
31807
31936
|
continue;
|
|
31808
31937
|
}
|
|
31809
|
-
const packageDir =
|
|
31810
|
-
await planJson(plan,
|
|
31938
|
+
const packageDir = path62.join(reviewsDir, entry.name);
|
|
31939
|
+
await planJson(plan, path62.join(packageDir, "manifest.json"), finalOf, (value) => {
|
|
31811
31940
|
const moved = mapStrings(value, movePath);
|
|
31812
31941
|
const flow = asRecord3(asRecord3(moved)?.["flow"]);
|
|
31813
31942
|
if (flow !== null && flow["id"] === move.from) {
|
|
@@ -31815,8 +31944,8 @@ async function planReviewRecordRewrites(move, packagesRoot, finalOf) {
|
|
|
31815
31944
|
}
|
|
31816
31945
|
return moved;
|
|
31817
31946
|
});
|
|
31818
|
-
await planJson(plan,
|
|
31819
|
-
await planText(plan,
|
|
31947
|
+
await planJson(plan, path62.join(packageDir, "findings.json"), finalOf, (value) => mapStrings(value, movePath));
|
|
31948
|
+
await planText(plan, path62.join(packageDir, "scope.md"), finalOf, (text) => text.replace(SCOPE_FLOW_LINE, (line, id) => id === move.from ? `flow: ${move.to}` : line));
|
|
31820
31949
|
}
|
|
31821
31950
|
}
|
|
31822
31951
|
const notesDir = reviewNotesDir(move.cwd);
|
|
@@ -31825,7 +31954,7 @@ async function planReviewRecordRewrites(move, packagesRoot, finalOf) {
|
|
|
31825
31954
|
if (!entry.isFile() || !entry.name.endsWith(".md")) {
|
|
31826
31955
|
continue;
|
|
31827
31956
|
}
|
|
31828
|
-
await planText(plan,
|
|
31957
|
+
await planText(plan, path62.join(notesDir, entry.name), finalOf, (text) => text.replace(NOTE_PATH_LINE, (_line, lead, value) => `${lead}${movePath(value)}`));
|
|
31829
31958
|
}
|
|
31830
31959
|
}
|
|
31831
31960
|
return plan;
|
|
@@ -31876,7 +32005,7 @@ function asRecord3(value) {
|
|
|
31876
32005
|
}
|
|
31877
32006
|
|
|
31878
32007
|
// src/flow/ac-reseal.ts
|
|
31879
|
-
import
|
|
32008
|
+
import path63 from "path";
|
|
31880
32009
|
async function acFileUnchangedSinceHead(cwd, acRelativePath) {
|
|
31881
32010
|
if (!Bun.which("git")) {
|
|
31882
32011
|
return { clean: false, reason: "git is not on PATH, so the file's state cannot be established" };
|
|
@@ -31927,7 +32056,7 @@ async function acFileUnchangedSinceHead(cwd, acRelativePath) {
|
|
|
31927
32056
|
return { clean: true };
|
|
31928
32057
|
}
|
|
31929
32058
|
function acRelativePathFor(flowsRootRelative, dir) {
|
|
31930
|
-
return
|
|
32059
|
+
return path63.posix.join(flowsRootRelative, dir, "acceptance-criteria.md");
|
|
31931
32060
|
}
|
|
31932
32061
|
|
|
31933
32062
|
// src/flow/schema.ts
|
|
@@ -32273,7 +32402,7 @@ function flowStateSchema() {
|
|
|
32273
32402
|
init_fs();
|
|
32274
32403
|
init_config2();
|
|
32275
32404
|
import { readFile as readFile30 } from "fs/promises";
|
|
32276
|
-
import
|
|
32405
|
+
import path66 from "path";
|
|
32277
32406
|
|
|
32278
32407
|
// src/memory/inject.ts
|
|
32279
32408
|
init_config2();
|
|
@@ -32430,7 +32559,7 @@ ${renderMemorySearchReportMarkdown(report, { includeHeader: false }).trimEnd()}`
|
|
|
32430
32559
|
".metaproject/data/gdgraph/artifacts/summary.md",
|
|
32431
32560
|
".metaproject/data/gdgraph/artifacts/module-map.json"
|
|
32432
32561
|
]) {
|
|
32433
|
-
if (await pathExists(
|
|
32562
|
+
if (await pathExists(path66.join(cwd, rel))) {
|
|
32434
32563
|
graphRefs.push(`- \`${rel}\``);
|
|
32435
32564
|
}
|
|
32436
32565
|
}
|
|
@@ -32442,7 +32571,7 @@ ${graphRefs.join(`
|
|
|
32442
32571
|
|
|
32443
32572
|
Use \`keryx gdgraph affected <file>\` for blast radius.`);
|
|
32444
32573
|
}
|
|
32445
|
-
const healthLatest =
|
|
32574
|
+
const healthLatest = path66.join(cwd, ".metaproject", "data", "health", "artifacts", "latest.json");
|
|
32446
32575
|
if (await pathExists(healthLatest)) {
|
|
32447
32576
|
try {
|
|
32448
32577
|
const report = JSON.parse(await readFile30(healthLatest, "utf8"));
|
|
@@ -32452,7 +32581,7 @@ Use \`keryx gdgraph affected <file>\` for blast radius.`);
|
|
|
32452
32581
|
- refresh: \`keryx health run\``);
|
|
32453
32582
|
} catch {}
|
|
32454
32583
|
}
|
|
32455
|
-
const manifestPath =
|
|
32584
|
+
const manifestPath = path66.join(cwd, ".metaproject", "metaproject.json");
|
|
32456
32585
|
if (await pathExists(manifestPath)) {
|
|
32457
32586
|
try {
|
|
32458
32587
|
const manifest = JSON.parse(await readFile30(manifestPath, "utf8"));
|
|
@@ -32494,13 +32623,13 @@ var DEFAULT_TASKS = [
|
|
|
32494
32623
|
init_fs();
|
|
32495
32624
|
import { createHash as createHash10, randomBytes as randomBytes4 } from "crypto";
|
|
32496
32625
|
import { readFile as readFile31 } from "fs/promises";
|
|
32497
|
-
import
|
|
32626
|
+
import path67 from "path";
|
|
32498
32627
|
var CONFIRMATION_TOKEN_TTL_MS = 10 * 60000;
|
|
32499
32628
|
var CONFIRMATION_CAVEAT = "The token proves an interactive confirmation step ran outside the agent's tool roster, within its TTL, " + "for this criteria checksum \u2014 not that a human ran it, and not who.";
|
|
32500
32629
|
var CONFIRM_TOKEN_FILE = "confirm-token.json";
|
|
32501
32630
|
var TOKEN_REF_LENGTH = 12;
|
|
32502
32631
|
function confirmTokenPath(cwd, dir) {
|
|
32503
|
-
return
|
|
32632
|
+
return path67.join(flowsRoot(cwd), dir, CONFIRM_TOKEN_FILE);
|
|
32504
32633
|
}
|
|
32505
32634
|
function completionTarget(input) {
|
|
32506
32635
|
return input.merged ? "merged" : `pr:${input.prUrl ?? "none"}`;
|
|
@@ -32615,7 +32744,7 @@ function describeConfirmationFailure(reason, flowId) {
|
|
|
32615
32744
|
}
|
|
32616
32745
|
async function readRequireConfirmationDefault(cwd) {
|
|
32617
32746
|
try {
|
|
32618
|
-
const parsed = JSON.parse(await readFile31(
|
|
32747
|
+
const parsed = JSON.parse(await readFile31(path67.join(cwd, REVIEW_GATE_CONFIG_PATH), "utf8"));
|
|
32619
32748
|
if (typeof parsed !== "object" || parsed === null)
|
|
32620
32749
|
return false;
|
|
32621
32750
|
const completion = parsed["completion"];
|
|
@@ -32739,7 +32868,7 @@ async function githubPostReview(url, event, body) {
|
|
|
32739
32868
|
}
|
|
32740
32869
|
}
|
|
32741
32870
|
// src/flow/uncommitted-state.ts
|
|
32742
|
-
import
|
|
32871
|
+
import path68 from "path";
|
|
32743
32872
|
var UNCOMMITTED_LIST_CAP = 5;
|
|
32744
32873
|
var READ_ONLY_GIT_FLAGS = ["--no-optional-locks"];
|
|
32745
32874
|
var GIT_TIMEOUT_MS2 = 5000;
|
|
@@ -32816,7 +32945,7 @@ async function readGit(cwd, scope, git) {
|
|
|
32816
32945
|
}
|
|
32817
32946
|
async function uncommittedFlowStateNote(cwd, flowId, dir, git = spawnGit) {
|
|
32818
32947
|
try {
|
|
32819
|
-
const read = await readGit(cwd,
|
|
32948
|
+
const read = await readGit(cwd, path68.join(flowsRoot(cwd), dir), git);
|
|
32820
32949
|
return read === null ? null : noteFor(flowId, dir, read);
|
|
32821
32950
|
} catch {
|
|
32822
32951
|
return null;
|
|
@@ -33022,7 +33151,7 @@ function readAcKindRecords(value) {
|
|
|
33022
33151
|
}
|
|
33023
33152
|
// src/flow/description-intent.ts
|
|
33024
33153
|
import { readFile as readFile32 } from "fs/promises";
|
|
33025
|
-
import
|
|
33154
|
+
import path69 from "path";
|
|
33026
33155
|
var OUTCOME_HINT = 'State an outcome criterion: what you would look at afterwards to see this helped, as a bullet. Or write "- not measured \u2014 <reason>".';
|
|
33027
33156
|
var PLACEHOLDERS = ["Describe the problem precisely", "What must be true when this flow is done"];
|
|
33028
33157
|
var FLOW_STATEMENT_HEADINGS = [/^problem$/i, /^expected outcome$/i];
|
|
@@ -33135,7 +33264,7 @@ function initIntentNote(description) {
|
|
|
33135
33264
|
}
|
|
33136
33265
|
async function intentNoteForNewFlow(cwd, dir) {
|
|
33137
33266
|
try {
|
|
33138
|
-
return initIntentNote(await readFile32(
|
|
33267
|
+
return initIntentNote(await readFile32(path69.join(cwd, dir, "description.md"), "utf8"));
|
|
33139
33268
|
} catch {
|
|
33140
33269
|
return null;
|
|
33141
33270
|
}
|
|
@@ -33143,7 +33272,7 @@ async function intentNoteForNewFlow(cwd, dir) {
|
|
|
33143
33272
|
// src/flow/check-ac.ts
|
|
33144
33273
|
import { createHash as createHash11 } from "crypto";
|
|
33145
33274
|
import { chmod as chmod4, mkdir as mkdir11, readFile as readFile33 } from "fs/promises";
|
|
33146
|
-
import
|
|
33275
|
+
import path70 from "path";
|
|
33147
33276
|
init_service2();
|
|
33148
33277
|
init_fs();
|
|
33149
33278
|
var AC_LINE2 = /^\s*[-*]\s*(AC\d+)\s*:\s?(.*)$/i;
|
|
@@ -33324,7 +33453,7 @@ function factsOnlyVerdict(item) {
|
|
|
33324
33453
|
}
|
|
33325
33454
|
async function readAcCheckEnabled(cwd) {
|
|
33326
33455
|
try {
|
|
33327
|
-
const parsed = JSON.parse(await readFile33(
|
|
33456
|
+
const parsed = JSON.parse(await readFile33(path70.join(cwd, REVIEW_GATE_CONFIG_PATH), "utf8"));
|
|
33328
33457
|
if (typeof parsed !== "object" || parsed === null)
|
|
33329
33458
|
return false;
|
|
33330
33459
|
const review = parsed["review"];
|
|
@@ -33345,7 +33474,7 @@ function acCheckCacheKey(criteriaChecksum, diffText) {
|
|
|
33345
33474
|
return `${criteriaChecksum}:${hashDiff(diffText)}`;
|
|
33346
33475
|
}
|
|
33347
33476
|
function acCheckCachePath(cwd, flowDir) {
|
|
33348
|
-
return
|
|
33477
|
+
return path70.join(cwd, ".metaproject", "data", "ac-check", `${flowDir}.json`);
|
|
33349
33478
|
}
|
|
33350
33479
|
async function readAcCheckCache(cachePath) {
|
|
33351
33480
|
if (!await pathExists(cachePath))
|
|
@@ -33357,7 +33486,7 @@ async function readAcCheckCache(cachePath) {
|
|
|
33357
33486
|
}
|
|
33358
33487
|
}
|
|
33359
33488
|
async function writeAcCheckCache(cachePath, record) {
|
|
33360
|
-
await mkdir11(
|
|
33489
|
+
await mkdir11(path70.dirname(cachePath), { recursive: true });
|
|
33361
33490
|
await writeFileAtomic(cachePath, `${JSON.stringify(record, null, 2)}
|
|
33362
33491
|
`, { mode: 384 });
|
|
33363
33492
|
if (process.platform !== "win32") {
|
|
@@ -33415,10 +33544,10 @@ function renderAcCheckAdvisoryNotice(verdicts) {
|
|
|
33415
33544
|
}
|
|
33416
33545
|
// src/flow/allocation.ts
|
|
33417
33546
|
import { appendFile as appendFile3, mkdir as mkdir12, readFile as readFile34 } from "fs/promises";
|
|
33418
|
-
import
|
|
33547
|
+
import path72 from "path";
|
|
33419
33548
|
|
|
33420
33549
|
// src/lib/clone-scope.ts
|
|
33421
|
-
import
|
|
33550
|
+
import path71 from "path";
|
|
33422
33551
|
async function gitCommonDir(cwd) {
|
|
33423
33552
|
try {
|
|
33424
33553
|
const proc = Bun.spawn(["git", "rev-parse", "--git-common-dir"], {
|
|
@@ -33430,7 +33559,7 @@ async function gitCommonDir(cwd) {
|
|
|
33430
33559
|
if (await proc.exited !== 0 || output.length === 0) {
|
|
33431
33560
|
return null;
|
|
33432
33561
|
}
|
|
33433
|
-
return
|
|
33562
|
+
return path71.isAbsolute(output) ? output : path71.resolve(cwd, output);
|
|
33434
33563
|
} catch {
|
|
33435
33564
|
return null;
|
|
33436
33565
|
}
|
|
@@ -33455,23 +33584,23 @@ function projectKey(toplevel, cwd) {
|
|
|
33455
33584
|
if (!toplevel) {
|
|
33456
33585
|
return "root";
|
|
33457
33586
|
}
|
|
33458
|
-
const relative =
|
|
33587
|
+
const relative = path72.relative(toplevel, cwd);
|
|
33459
33588
|
return relative === "" ? "root" : slugify(relative);
|
|
33460
33589
|
}
|
|
33461
33590
|
async function resolveAllocationScope(cwd) {
|
|
33462
33591
|
const commonDir = await gitCommonDir(cwd);
|
|
33463
33592
|
if (!commonDir) {
|
|
33464
33593
|
return {
|
|
33465
|
-
lockPath:
|
|
33594
|
+
lockPath: path72.join(flowsRoot(cwd), ".flow-init.lock"),
|
|
33466
33595
|
ledgerPath: null,
|
|
33467
33596
|
project: "root"
|
|
33468
33597
|
};
|
|
33469
33598
|
}
|
|
33470
33599
|
const key = projectKey(await gitToplevel(cwd), cwd);
|
|
33471
|
-
const dir =
|
|
33600
|
+
const dir = path72.join(commonDir, "keryx", "flow-ids");
|
|
33472
33601
|
return {
|
|
33473
|
-
lockPath:
|
|
33474
|
-
ledgerPath:
|
|
33602
|
+
lockPath: path72.join(dir, `${key}.lock`),
|
|
33603
|
+
ledgerPath: path72.join(dir, `${key}.jsonl`),
|
|
33475
33604
|
project: key
|
|
33476
33605
|
};
|
|
33477
33606
|
}
|
|
@@ -33504,13 +33633,13 @@ async function recordAllocation(scope, record) {
|
|
|
33504
33633
|
if (!scope.ledgerPath) {
|
|
33505
33634
|
return;
|
|
33506
33635
|
}
|
|
33507
|
-
await mkdir12(
|
|
33636
|
+
await mkdir12(path72.dirname(scope.ledgerPath), { recursive: true });
|
|
33508
33637
|
await appendFile3(scope.ledgerPath, `${JSON.stringify(record)}
|
|
33509
33638
|
`, "utf8");
|
|
33510
33639
|
}
|
|
33511
33640
|
|
|
33512
33641
|
// src/flow/remote-flows.ts
|
|
33513
|
-
import
|
|
33642
|
+
import path73 from "path";
|
|
33514
33643
|
var MAX_REFS = 500;
|
|
33515
33644
|
var CONCURRENCY = 8;
|
|
33516
33645
|
async function runGit2(cwd, args) {
|
|
@@ -33591,7 +33720,7 @@ async function flowDirsOnRef(cwd, ref, flowsPath) {
|
|
|
33591
33720
|
if (result === undefined || result.code !== 0) {
|
|
33592
33721
|
return [];
|
|
33593
33722
|
}
|
|
33594
|
-
return nulSplit(result.stdout).map((entry) =>
|
|
33723
|
+
return nulSplit(result.stdout).map((entry) => path73.posix.basename(entry)).filter((name) => /^\d{3}-/.test(name));
|
|
33595
33724
|
}
|
|
33596
33725
|
async function knownRemoteFlowDirs(cwd) {
|
|
33597
33726
|
try {
|
|
@@ -33771,12 +33900,12 @@ function renderJournal(createdAt) {
|
|
|
33771
33900
|
|
|
33772
33901
|
// src/flow/task-project-context.ts
|
|
33773
33902
|
import { readFile as readFile38 } from "fs/promises";
|
|
33774
|
-
import
|
|
33903
|
+
import path77 from "path";
|
|
33775
33904
|
|
|
33776
33905
|
// src/gdskills/project-context-config.ts
|
|
33777
33906
|
init_fs();
|
|
33778
33907
|
import { readFile as readFile35 } from "fs/promises";
|
|
33779
|
-
import
|
|
33908
|
+
import path74 from "path";
|
|
33780
33909
|
var PROJECT_CONTEXT_CONFIG_PATH = ".metaproject/tasks.config.json";
|
|
33781
33910
|
var DEFAULT_MAX_BYTES = 131072;
|
|
33782
33911
|
var MAX_BYTES_FLOOR = 4096;
|
|
@@ -33786,7 +33915,7 @@ function isValidMaxBytes(value) {
|
|
|
33786
33915
|
}
|
|
33787
33916
|
async function readRoot(projectRoot) {
|
|
33788
33917
|
try {
|
|
33789
|
-
const parsed = JSON.parse(await readFile35(
|
|
33918
|
+
const parsed = JSON.parse(await readFile35(path74.join(projectRoot, PROJECT_CONTEXT_CONFIG_PATH), "utf8"));
|
|
33790
33919
|
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : undefined;
|
|
33791
33920
|
} catch {
|
|
33792
33921
|
return;
|
|
@@ -33830,7 +33959,7 @@ async function readProjectContextConfig(projectRoot) {
|
|
|
33830
33959
|
|
|
33831
33960
|
// src/gdskills/resolved-context-check.ts
|
|
33832
33961
|
import { readFile as readFile37 } from "fs/promises";
|
|
33833
|
-
import
|
|
33962
|
+
import path76 from "path";
|
|
33834
33963
|
|
|
33835
33964
|
// src/gdskills/project-rules.ts
|
|
33836
33965
|
import { createHash as createHash12 } from "crypto";
|
|
@@ -33843,7 +33972,7 @@ function sha256Hex(content) {
|
|
|
33843
33972
|
|
|
33844
33973
|
// src/gdskills/reference-proof.ts
|
|
33845
33974
|
import { readFile as readFile36 } from "fs/promises";
|
|
33846
|
-
import
|
|
33975
|
+
import path75 from "path";
|
|
33847
33976
|
|
|
33848
33977
|
// src/gdskills/references-section.ts
|
|
33849
33978
|
var FENCE = /^ {0,3}(`{3,}|~{3,})/;
|
|
@@ -33949,7 +34078,7 @@ function pickProofItem(items, pinned) {
|
|
|
33949
34078
|
return items.find((item) => item.sha256 === pinned && item.how !== "n/a") ?? items.find((item) => item.how !== "n/a") ?? items[0];
|
|
33950
34079
|
}
|
|
33951
34080
|
async function currentSection(projectRoot, entry) {
|
|
33952
|
-
const file =
|
|
34081
|
+
const file = path75.isAbsolute(entry.path) ? entry.path : path75.join(projectRoot, entry.path);
|
|
33953
34082
|
let text;
|
|
33954
34083
|
try {
|
|
33955
34084
|
text = await readFile36(file, "utf8");
|
|
@@ -34041,7 +34170,7 @@ function appliedOf(result) {
|
|
|
34041
34170
|
}
|
|
34042
34171
|
async function currentSha(projectRoot, entryPath) {
|
|
34043
34172
|
try {
|
|
34044
|
-
return sha256Hex(await readFile37(
|
|
34173
|
+
return sha256Hex(await readFile37(path76.isAbsolute(entryPath) ? entryPath : path76.join(projectRoot, entryPath), "utf8"));
|
|
34045
34174
|
} catch {
|
|
34046
34175
|
return;
|
|
34047
34176
|
}
|
|
@@ -34120,8 +34249,8 @@ async function checkTaskProjectContext(input) {
|
|
|
34120
34249
|
}
|
|
34121
34250
|
const report = await checkResolvedContext({
|
|
34122
34251
|
projectRoot: input.projectRoot,
|
|
34123
|
-
resolved: await readResolvedFile(
|
|
34124
|
-
result: await readResultFile(
|
|
34252
|
+
resolved: await readResolvedFile(path77.resolve(input.projectRoot, input.resolvedFile)),
|
|
34253
|
+
result: await readResultFile(path77.resolve(input.projectRoot, input.resultFile))
|
|
34125
34254
|
});
|
|
34126
34255
|
const lines = formatResolvedReport(report);
|
|
34127
34256
|
if (lines.length === 0)
|
|
@@ -34435,7 +34564,7 @@ function createFlowService(deps) {
|
|
|
34435
34564
|
const date = now().slice(0, 10);
|
|
34436
34565
|
const slug = slugify(input.slug ?? title);
|
|
34437
34566
|
const dir = `${id}-${date}-${slug}`;
|
|
34438
|
-
const absolute =
|
|
34567
|
+
const absolute = path78.join(flowsRoot(input.cwd), dir);
|
|
34439
34568
|
if (await pathExists(absolute)) {
|
|
34440
34569
|
throw new Error(`Flow directory already exists: ${dir}`);
|
|
34441
34570
|
}
|
|
@@ -34471,17 +34600,17 @@ function createFlowService(deps) {
|
|
|
34471
34600
|
history: [{ at: createdAt, event: "created" }]
|
|
34472
34601
|
};
|
|
34473
34602
|
const sourceLabel = input.issue ?? "user description";
|
|
34474
|
-
await writeFileAtomic(
|
|
34475
|
-
await writeFileAtomic(
|
|
34476
|
-
await writeFileAtomic(
|
|
34477
|
-
await writeFileAtomic(
|
|
34478
|
-
await writeFileAtomic(
|
|
34479
|
-
await writeFileAtomic(
|
|
34603
|
+
await writeFileAtomic(path78.join(absolute, "description.md"), renderDescription(title, originDraft === undefined ? sourceLabel : `${sourceLabel} (origin: ${originDraft.kind})`, originDraft));
|
|
34604
|
+
await writeFileAtomic(path78.join(absolute, "context.md"), context.markdown);
|
|
34605
|
+
await writeFileAtomic(path78.join(absolute, "plan.md"), renderPlan());
|
|
34606
|
+
await writeFileAtomic(path78.join(absolute, "tasks.md"), renderTasksDoc());
|
|
34607
|
+
await writeFileAtomic(path78.join(absolute, "acceptance-criteria.md"), renderAcceptanceCriteria());
|
|
34608
|
+
await writeFileAtomic(path78.join(absolute, "journal.md"), renderJournal(createdAt));
|
|
34480
34609
|
await writeFlow(input.cwd, dir, flow);
|
|
34481
34610
|
await recordAllocation(scope, { id, dir, at: createdAt, project: scope.project });
|
|
34482
34611
|
return {
|
|
34483
34612
|
flow,
|
|
34484
|
-
dir:
|
|
34613
|
+
dir: path78.relative(input.cwd, absolute),
|
|
34485
34614
|
contextNotes: context.notes,
|
|
34486
34615
|
...originNote === undefined ? {} : { originNote }
|
|
34487
34616
|
};
|
|
@@ -35122,7 +35251,7 @@ function createFlowService(deps) {
|
|
|
35122
35251
|
issues.push({ flow: dir, kind: "schema", message: `unknown schemaVersion ${flow.schemaVersion}` });
|
|
35123
35252
|
}
|
|
35124
35253
|
try {
|
|
35125
|
-
const raw = JSON.parse(await Bun.file(
|
|
35254
|
+
const raw = JSON.parse(await Bun.file(path78.join(flowsRoot(cwd), dir, "flow.json")).text());
|
|
35126
35255
|
const validation = validateAgainstSchemaObject(flowStateSchema(), raw);
|
|
35127
35256
|
if (!validation.valid) {
|
|
35128
35257
|
issues.push({
|
|
@@ -35133,7 +35262,7 @@ function createFlowService(deps) {
|
|
|
35133
35262
|
}
|
|
35134
35263
|
} catch {}
|
|
35135
35264
|
for (const file of ["description.md", "context.md", "plan.md", "tasks.md", "acceptance-criteria.md", "journal.md"]) {
|
|
35136
|
-
if (!await pathExists(
|
|
35265
|
+
if (!await pathExists(path78.join(flowsRoot(cwd), dir, file))) {
|
|
35137
35266
|
issues.push({ flow: dir, kind: "structure", message: `missing ${file}` });
|
|
35138
35267
|
}
|
|
35139
35268
|
}
|
|
@@ -35172,7 +35301,7 @@ function createFlowService(deps) {
|
|
|
35172
35301
|
};
|
|
35173
35302
|
}
|
|
35174
35303
|
async function appendIdMap(cwd, entry) {
|
|
35175
|
-
const file =
|
|
35304
|
+
const file = path78.join(flowsRoot(cwd), "id-map.json");
|
|
35176
35305
|
let entries = [];
|
|
35177
35306
|
if (await pathExists(file)) {
|
|
35178
35307
|
const raw = await readFile39(file, "utf8");
|
|
@@ -35183,7 +35312,7 @@ async function appendIdMap(cwd, entry) {
|
|
|
35183
35312
|
}
|
|
35184
35313
|
entries = parsed;
|
|
35185
35314
|
} catch (error) {
|
|
35186
|
-
throw new Error(`Cannot read ${
|
|
35315
|
+
throw new Error(`Cannot read ${path78.relative(cwd, file)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
35187
35316
|
}
|
|
35188
35317
|
}
|
|
35189
35318
|
entries.push(entry);
|
|
@@ -35471,7 +35600,7 @@ async function acCriterionKnown(input) {
|
|
|
35471
35600
|
init_data_dir();
|
|
35472
35601
|
import { mkdir as mkdir23, readdir as readdir18, readFile as readFile51, writeFile as writeFile17 } from "fs/promises";
|
|
35473
35602
|
import { existsSync as existsSync11 } from "fs";
|
|
35474
|
-
import
|
|
35603
|
+
import path101 from "path";
|
|
35475
35604
|
|
|
35476
35605
|
// src/gdgraph/types.ts
|
|
35477
35606
|
var UNKNOWN_IMPORT_KIND = "unknown-static";
|
|
@@ -35538,7 +35667,7 @@ async function buildGraph(projectRoot, options = {}) {
|
|
|
35538
35667
|
const assetNodes = new Map;
|
|
35539
35668
|
const fileRecords = [];
|
|
35540
35669
|
for (const file of files) {
|
|
35541
|
-
const absolutePath =
|
|
35670
|
+
const absolutePath = path101.join(projectRoot, file);
|
|
35542
35671
|
const content = await readFile51(absolutePath, "utf8");
|
|
35543
35672
|
fileRecords.push({ path: file, content });
|
|
35544
35673
|
const language = getLanguage(file);
|
|
@@ -35591,24 +35720,24 @@ async function collectSourceFiles(projectRoot) {
|
|
|
35591
35720
|
const result = [];
|
|
35592
35721
|
const skippedDirectories = [];
|
|
35593
35722
|
async function walk(relativeDir) {
|
|
35594
|
-
const absoluteDir =
|
|
35723
|
+
const absoluteDir = path101.join(projectRoot, relativeDir);
|
|
35595
35724
|
const entries = await readdir18(absoluteDir, { withFileTypes: true });
|
|
35596
35725
|
for (const entry of entries) {
|
|
35597
35726
|
if (entry.isDirectory()) {
|
|
35598
35727
|
if (IGNORE_DIRS.has(entry.name)) {
|
|
35599
|
-
skippedDirectories.push(normalizePath3(
|
|
35728
|
+
skippedDirectories.push(normalizePath3(path101.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
|
|
35600
35729
|
continue;
|
|
35601
35730
|
}
|
|
35602
|
-
await walk(normalizePath3(
|
|
35731
|
+
await walk(normalizePath3(path101.posix.join(relativeDir, entry.name)));
|
|
35603
35732
|
continue;
|
|
35604
35733
|
}
|
|
35605
35734
|
if (!entry.isFile()) {
|
|
35606
35735
|
continue;
|
|
35607
35736
|
}
|
|
35608
|
-
if (!SOURCE_EXTENSIONS.includes(
|
|
35737
|
+
if (!SOURCE_EXTENSIONS.includes(path101.extname(entry.name))) {
|
|
35609
35738
|
continue;
|
|
35610
35739
|
}
|
|
35611
|
-
result.push(normalizePath3(
|
|
35740
|
+
result.push(normalizePath3(path101.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
|
|
35612
35741
|
}
|
|
35613
35742
|
}
|
|
35614
35743
|
await walk(".");
|
|
@@ -35690,8 +35819,8 @@ function resolveImport(projectRoot, fromFile, specifier, fileSet, resolver) {
|
|
|
35690
35819
|
}
|
|
35691
35820
|
function resolveAssetImport(projectRoot, fromFile, specifier, resolver) {
|
|
35692
35821
|
for (const candidate of importCandidateBases(projectRoot, fromFile, specifier, resolver)) {
|
|
35693
|
-
const extension =
|
|
35694
|
-
if (ASSET_EXTENSIONS.includes(extension) && existsSync11(
|
|
35822
|
+
const extension = path101.posix.extname(candidate);
|
|
35823
|
+
if (ASSET_EXTENSIONS.includes(extension) && existsSync11(path101.join(projectRoot, candidate))) {
|
|
35695
35824
|
return candidate;
|
|
35696
35825
|
}
|
|
35697
35826
|
}
|
|
@@ -35700,17 +35829,17 @@ function resolveAssetImport(projectRoot, fromFile, specifier, resolver) {
|
|
|
35700
35829
|
function importCandidateBases(projectRoot, fromFile, specifier, resolver) {
|
|
35701
35830
|
const normalizedSpecifier = stripImportSuffix(specifier);
|
|
35702
35831
|
if (normalizedSpecifier.startsWith(".") && getLanguage(fromFile) !== "python") {
|
|
35703
|
-
const fromDir =
|
|
35704
|
-
return [normalizePath3(
|
|
35832
|
+
const fromDir = path101.posix.dirname(fromFile);
|
|
35833
|
+
return [normalizePath3(path101.posix.normalize(path101.posix.join(fromDir, normalizedSpecifier)))];
|
|
35705
35834
|
}
|
|
35706
|
-
return resolver.candidateBases(normalizedSpecifier, fromFile).map((candidate) => normalizePath3(
|
|
35835
|
+
return resolver.candidateBases(normalizedSpecifier, fromFile).map((candidate) => normalizePath3(path101.relative(projectRoot, path101.join(projectRoot, candidate))));
|
|
35707
35836
|
}
|
|
35708
35837
|
function resolveSourceCandidate(base, fileSet) {
|
|
35709
35838
|
const candidates = [
|
|
35710
35839
|
base,
|
|
35711
35840
|
...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => `${base}${extension}`),
|
|
35712
|
-
...SOURCE_RESOLUTION_EXTENSIONS.map((extension) =>
|
|
35713
|
-
|
|
35841
|
+
...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => path101.posix.join(base, `index${extension}`)),
|
|
35842
|
+
path101.posix.join(base, "__init__.py")
|
|
35714
35843
|
];
|
|
35715
35844
|
return candidates.find((candidate) => fileSet.has(candidate)) ?? null;
|
|
35716
35845
|
}
|
|
@@ -35740,7 +35869,7 @@ async function loadJavaResolver(projectRoot) {
|
|
|
35740
35869
|
return createJavaResolver(roots);
|
|
35741
35870
|
}
|
|
35742
35871
|
async function discoverJavaSourceRoots(projectRoot) {
|
|
35743
|
-
const pomPath =
|
|
35872
|
+
const pomPath = path101.join(projectRoot, "pom.xml");
|
|
35744
35873
|
if (existsSync11(pomPath)) {
|
|
35745
35874
|
try {
|
|
35746
35875
|
const roots = parseMavenSourceRoots(await readFile51(pomPath, "utf8"));
|
|
@@ -35750,7 +35879,7 @@ async function discoverJavaSourceRoots(projectRoot) {
|
|
|
35750
35879
|
} catch {}
|
|
35751
35880
|
}
|
|
35752
35881
|
for (const gradleName of ["build.gradle", "build.gradle.kts"]) {
|
|
35753
|
-
const gradlePath =
|
|
35882
|
+
const gradlePath = path101.join(projectRoot, gradleName);
|
|
35754
35883
|
if (existsSync11(gradlePath)) {
|
|
35755
35884
|
try {
|
|
35756
35885
|
const roots = parseGradleSourceRoots(await readFile51(gradlePath, "utf8"));
|
|
@@ -35772,12 +35901,12 @@ function createJavaResolver(sourceRoots) {
|
|
|
35772
35901
|
return [];
|
|
35773
35902
|
}
|
|
35774
35903
|
const relative = specifier.split(".").join("/");
|
|
35775
|
-
return sourceRoots.map((root) => normalizePath3(
|
|
35904
|
+
return sourceRoots.map((root) => normalizePath3(path101.posix.join(root, relative)));
|
|
35776
35905
|
}
|
|
35777
35906
|
};
|
|
35778
35907
|
}
|
|
35779
35908
|
function loadPythonResolver(projectRoot) {
|
|
35780
|
-
const hasSrc = existsSync11(
|
|
35909
|
+
const hasSrc = existsSync11(path101.join(projectRoot, "src"));
|
|
35781
35910
|
return createPythonResolver(hasSrc);
|
|
35782
35911
|
}
|
|
35783
35912
|
function createPythonResolver(hasSrc) {
|
|
@@ -35790,16 +35919,16 @@ function createPythonResolver(hasSrc) {
|
|
|
35790
35919
|
if (specifier.startsWith(".")) {
|
|
35791
35920
|
const dots = /^\.+/.exec(specifier)?.[0].length ?? 0;
|
|
35792
35921
|
const rest = specifier.slice(dots);
|
|
35793
|
-
let baseDir =
|
|
35922
|
+
let baseDir = path101.posix.dirname(fromFile);
|
|
35794
35923
|
for (let level = 1;level < dots; level += 1) {
|
|
35795
|
-
baseDir =
|
|
35924
|
+
baseDir = path101.posix.dirname(baseDir);
|
|
35796
35925
|
}
|
|
35797
35926
|
const suffix = rest ? rest.split(".").join("/") : "";
|
|
35798
|
-
const base = suffix ?
|
|
35927
|
+
const base = suffix ? path101.posix.join(baseDir, suffix) : baseDir;
|
|
35799
35928
|
return [normalizePath3(base)];
|
|
35800
35929
|
}
|
|
35801
35930
|
const relative = specifier.split(".").join("/");
|
|
35802
|
-
return roots.map((root) => normalizePath3(root ?
|
|
35931
|
+
return roots.map((root) => normalizePath3(root ? path101.posix.join(root, relative) : relative));
|
|
35803
35932
|
}
|
|
35804
35933
|
};
|
|
35805
35934
|
}
|
|
@@ -35808,8 +35937,8 @@ function parseMavenSourceRoots(pomXml) {
|
|
|
35808
35937
|
for (const match of pomXml.matchAll(/<module>\s*([^<]+?)\s*<\/module>/g)) {
|
|
35809
35938
|
const moduleDir = match[1]?.trim();
|
|
35810
35939
|
if (moduleDir && !moduleDir.includes("${")) {
|
|
35811
|
-
roots.add(normalizePath3(
|
|
35812
|
-
roots.add(normalizePath3(
|
|
35940
|
+
roots.add(normalizePath3(path101.posix.join(moduleDir, "src/main/java")));
|
|
35941
|
+
roots.add(normalizePath3(path101.posix.join(moduleDir, "src/test/java")));
|
|
35813
35942
|
}
|
|
35814
35943
|
}
|
|
35815
35944
|
for (const tag of ["sourceDirectory", "testSourceDirectory"]) {
|
|
@@ -35842,7 +35971,7 @@ function parseGradleSourceRoots(buildGradle) {
|
|
|
35842
35971
|
var TSCONFIG_EXTENDS_MAX_DEPTH = 10;
|
|
35843
35972
|
async function loadTsconfigResolver(projectRoot) {
|
|
35844
35973
|
const empty = createTsconfigResolver(null, []);
|
|
35845
|
-
const tsconfigPath =
|
|
35974
|
+
const tsconfigPath = path101.join(projectRoot, "tsconfig.json");
|
|
35846
35975
|
if (!existsSync11(tsconfigPath)) {
|
|
35847
35976
|
return empty;
|
|
35848
35977
|
}
|
|
@@ -35855,7 +35984,7 @@ async function loadTsconfigResolver(projectRoot) {
|
|
|
35855
35984
|
return createTsconfigResolver(resolved.baseUrl, paths);
|
|
35856
35985
|
}
|
|
35857
35986
|
function toProjectRelativeDir(projectRoot, absoluteDir) {
|
|
35858
|
-
const relative = normalizePath3(
|
|
35987
|
+
const relative = normalizePath3(path101.relative(projectRoot, absoluteDir)).replace(/^\.\//, "");
|
|
35859
35988
|
return relative === "." ? "" : relative;
|
|
35860
35989
|
}
|
|
35861
35990
|
async function readTsconfigJson(configPath) {
|
|
@@ -35870,11 +35999,11 @@ function resolveTsconfigExtendsPath(configDir, extendsSpecifier) {
|
|
|
35870
35999
|
if (!extendsSpecifier.startsWith(".") && !extendsSpecifier.startsWith("/")) {
|
|
35871
36000
|
return null;
|
|
35872
36001
|
}
|
|
35873
|
-
const resolved =
|
|
36002
|
+
const resolved = path101.resolve(configDir, extendsSpecifier);
|
|
35874
36003
|
return resolved.endsWith(".json") ? resolved : `${resolved}.json`;
|
|
35875
36004
|
}
|
|
35876
36005
|
async function resolveTsconfigOptions(configPath, visited, depth, projectRoot) {
|
|
35877
|
-
const resolvedPath =
|
|
36006
|
+
const resolvedPath = path101.resolve(configPath);
|
|
35878
36007
|
if (depth > TSCONFIG_EXTENDS_MAX_DEPTH || visited.has(resolvedPath)) {
|
|
35879
36008
|
return null;
|
|
35880
36009
|
}
|
|
@@ -35885,15 +36014,15 @@ async function resolveTsconfigOptions(configPath, visited, depth, projectRoot) {
|
|
|
35885
36014
|
}
|
|
35886
36015
|
let inherited = null;
|
|
35887
36016
|
if (typeof parsed.extends === "string") {
|
|
35888
|
-
const basePath = resolveTsconfigExtendsPath(
|
|
36017
|
+
const basePath = resolveTsconfigExtendsPath(path101.dirname(resolvedPath), parsed.extends);
|
|
35889
36018
|
if (basePath) {
|
|
35890
36019
|
inherited = await resolveTsconfigOptions(basePath, visited, depth + 1, projectRoot);
|
|
35891
36020
|
}
|
|
35892
36021
|
}
|
|
35893
|
-
const configDir =
|
|
36022
|
+
const configDir = path101.dirname(resolvedPath);
|
|
35894
36023
|
const declaringDir = toProjectRelativeDir(projectRoot, configDir);
|
|
35895
36024
|
const options = parsed.compilerOptions ?? {};
|
|
35896
|
-
const ownBaseUrl = typeof options.baseUrl === "string" ? toProjectRelativeDir(projectRoot,
|
|
36025
|
+
const ownBaseUrl = typeof options.baseUrl === "string" ? toProjectRelativeDir(projectRoot, path101.resolve(configDir, options.baseUrl)) : null;
|
|
35897
36026
|
const baseUrl = ownBaseUrl ?? inherited?.baseUrl ?? null;
|
|
35898
36027
|
const ownPaths = isRecord5(options.paths) ? Object.entries(options.paths).filter((entry) => Array.isArray(entry[1])).map(([pattern, targets]) => ({
|
|
35899
36028
|
pattern,
|
|
@@ -35922,7 +36051,7 @@ function createTsconfigResolver(baseUrl, mappings) {
|
|
|
35922
36051
|
}
|
|
35923
36052
|
}
|
|
35924
36053
|
if (baseUrl !== null) {
|
|
35925
|
-
candidates.push(normalizePath3(
|
|
36054
|
+
candidates.push(normalizePath3(path101.posix.join(baseUrl, normalizedSpecifier)));
|
|
35926
36055
|
}
|
|
35927
36056
|
return [...new Set(candidates.map((candidate) => candidate.replace(/^\.\//, "")))];
|
|
35928
36057
|
}
|
|
@@ -35942,7 +36071,7 @@ function matchPathPattern(pattern, specifier) {
|
|
|
35942
36071
|
}
|
|
35943
36072
|
function applyPathTarget(base, target, wildcard) {
|
|
35944
36073
|
const replaced = target.includes("*") ? target.replace("*", wildcard) : target;
|
|
35945
|
-
return normalizePath3(
|
|
36074
|
+
return normalizePath3(path101.posix.normalize(path101.posix.join(base, replaced)));
|
|
35946
36075
|
}
|
|
35947
36076
|
function stripJsonComments(source) {
|
|
35948
36077
|
let out = "";
|
|
@@ -35999,13 +36128,13 @@ async function writeGraph(projectRoot, graph, dataDir) {
|
|
|
35999
36128
|
const artifactsDir = gdgraphArtifactsDir(projectRoot, dataDir);
|
|
36000
36129
|
await mkdir23(storageDir, { recursive: true });
|
|
36001
36130
|
await mkdir23(artifactsDir, { recursive: true });
|
|
36002
|
-
await writeFile17(
|
|
36131
|
+
await writeFile17(path101.join(storageDir, "nodes.jsonl"), graph.nodes.map((node) => JSON.stringify(node)).join(`
|
|
36003
36132
|
`) + `
|
|
36004
36133
|
`, "utf8");
|
|
36005
|
-
await writeFile17(
|
|
36134
|
+
await writeFile17(path101.join(storageDir, "edges.jsonl"), graph.edges.map((edge) => JSON.stringify(edge)).join(`
|
|
36006
36135
|
`) + `
|
|
36007
36136
|
`, "utf8");
|
|
36008
|
-
await writeFile17(
|
|
36137
|
+
await writeFile17(path101.join(artifactsDir, "module-map.json"), JSON.stringify(buildModuleMap(graph), null, 2) + `
|
|
36009
36138
|
`, "utf8");
|
|
36010
36139
|
}
|
|
36011
36140
|
async function writeSummary(projectRoot, graph, collection, dataDir) {
|
|
@@ -36024,7 +36153,7 @@ async function writeSummary(projectRoot, graph, collection, dataDir) {
|
|
|
36024
36153
|
`);
|
|
36025
36154
|
const skippedList = collection.skippedDirectories.length > 0 ? collection.skippedDirectories.slice(0, 30).map((dir) => `- \`${dir}\``).join(`
|
|
36026
36155
|
`) : "- none";
|
|
36027
|
-
const summaryPath =
|
|
36156
|
+
const summaryPath = path101.join(artifactsDir, "summary.md");
|
|
36028
36157
|
const content = `# gdgraph Summary
|
|
36029
36158
|
|
|
36030
36159
|
## Stats
|
|
@@ -36105,7 +36234,7 @@ function groupBy(items, getKey) {
|
|
|
36105
36234
|
}
|
|
36106
36235
|
function unresolvedType(specifier) {
|
|
36107
36236
|
const stripped = stripImportSuffix(specifier);
|
|
36108
|
-
const extension =
|
|
36237
|
+
const extension = path101.posix.extname(stripped);
|
|
36109
36238
|
if (extension) {
|
|
36110
36239
|
return extension;
|
|
36111
36240
|
}
|
|
@@ -36115,7 +36244,7 @@ function unresolvedType(specifier) {
|
|
|
36115
36244
|
return "package";
|
|
36116
36245
|
}
|
|
36117
36246
|
function normalizePath3(value) {
|
|
36118
|
-
return value.split(
|
|
36247
|
+
return value.split(path101.sep).join("/");
|
|
36119
36248
|
}
|
|
36120
36249
|
|
|
36121
36250
|
// src/gdgraph/service.ts
|
|
@@ -36124,17 +36253,17 @@ init_config3();
|
|
|
36124
36253
|
|
|
36125
36254
|
// src/gdgraph/query.ts
|
|
36126
36255
|
import { readFile as readFile52 } from "fs/promises";
|
|
36127
|
-
import
|
|
36256
|
+
import path102 from "path";
|
|
36128
36257
|
init_data_dir();
|
|
36129
36258
|
init_target();
|
|
36130
36259
|
async function loadGraph(projectRoot, dataDir) {
|
|
36131
36260
|
const storageDir = gdgraphStorageDir(projectRoot, dataDir);
|
|
36132
|
-
const nodes = await readJsonl(
|
|
36133
|
-
const edges = await readJsonl(
|
|
36134
|
-
const symbols = await readJsonl(
|
|
36135
|
-
const calls = await readJsonl(
|
|
36136
|
-
const wikiPages = await readJsonl(
|
|
36137
|
-
const describes = await readJsonl(
|
|
36261
|
+
const nodes = await readJsonl(path102.join(storageDir, "nodes.jsonl"));
|
|
36262
|
+
const edges = await readJsonl(path102.join(storageDir, "edges.jsonl"));
|
|
36263
|
+
const symbols = await readJsonl(path102.join(storageDir, "symbols.jsonl"));
|
|
36264
|
+
const calls = await readJsonl(path102.join(storageDir, "calls.jsonl"));
|
|
36265
|
+
const wikiPages = await readJsonl(path102.join(storageDir, "wiki-pages.jsonl"));
|
|
36266
|
+
const describes = await readJsonl(path102.join(storageDir, "describes.jsonl"));
|
|
36138
36267
|
const graph = { nodes, edges };
|
|
36139
36268
|
if (symbols.length > 0) {
|
|
36140
36269
|
graph.symbols = symbols;
|
|
@@ -36194,7 +36323,7 @@ async function bunfigPreloadRoots(projectRoot) {
|
|
|
36194
36323
|
const roots = new Set;
|
|
36195
36324
|
let text;
|
|
36196
36325
|
try {
|
|
36197
|
-
text = await readFile52(
|
|
36326
|
+
text = await readFile52(path102.join(projectRoot, "bunfig.toml"), "utf8");
|
|
36198
36327
|
} catch {
|
|
36199
36328
|
return roots;
|
|
36200
36329
|
}
|
|
@@ -36208,8 +36337,8 @@ async function bunfigPreloadRoots(projectRoot) {
|
|
|
36208
36337
|
if (raw.length === 0) {
|
|
36209
36338
|
continue;
|
|
36210
36339
|
}
|
|
36211
|
-
const absolute =
|
|
36212
|
-
const relative =
|
|
36340
|
+
const absolute = path102.resolve(projectRoot, raw);
|
|
36341
|
+
const relative = path102.relative(projectRoot, absolute).split(path102.sep).join("/");
|
|
36213
36342
|
roots.add(relative);
|
|
36214
36343
|
}
|
|
36215
36344
|
}
|
|
@@ -36364,12 +36493,12 @@ init_section_tombstone();
|
|
|
36364
36493
|
// src/forgetting/journal.ts
|
|
36365
36494
|
init_fs();
|
|
36366
36495
|
import { appendFile as appendFile5, mkdir as mkdir25, readFile as readFile53, stat as stat15 } from "fs/promises";
|
|
36367
|
-
import
|
|
36496
|
+
import path104 from "path";
|
|
36368
36497
|
function forgettingDataDir(cwd) {
|
|
36369
|
-
return
|
|
36498
|
+
return path104.join(cwd, ".metaproject", "data", "forgetting");
|
|
36370
36499
|
}
|
|
36371
36500
|
function deletionJournalPath(cwd) {
|
|
36372
|
-
return
|
|
36501
|
+
return path104.join(forgettingDataDir(cwd), "journal.jsonl");
|
|
36373
36502
|
}
|
|
36374
36503
|
async function readDeletionJournal(cwd) {
|
|
36375
36504
|
const file = deletionJournalPath(cwd);
|
|
@@ -36784,12 +36913,12 @@ function createGdgraphService() {
|
|
|
36784
36913
|
// src/health/service.ts
|
|
36785
36914
|
init_fs();
|
|
36786
36915
|
init_json();
|
|
36787
|
-
import
|
|
36916
|
+
import path124 from "path";
|
|
36788
36917
|
|
|
36789
36918
|
// src/health/config.ts
|
|
36790
36919
|
init_fs();
|
|
36791
36920
|
init_json();
|
|
36792
|
-
import
|
|
36921
|
+
import path105 from "path";
|
|
36793
36922
|
var DEFAULT_HEALTH_CONFIG = {
|
|
36794
36923
|
schemaVersion: 2,
|
|
36795
36924
|
ignore: {
|
|
@@ -36846,7 +36975,7 @@ var DEFAULT_HEALTH_CONFIG = {
|
|
|
36846
36975
|
}
|
|
36847
36976
|
};
|
|
36848
36977
|
function configPath2(cwd) {
|
|
36849
|
-
return
|
|
36978
|
+
return path105.join(cwd, ".metaproject", "health.config.json");
|
|
36850
36979
|
}
|
|
36851
36980
|
var STRICTEST_GATE = {
|
|
36852
36981
|
failOnPriorities: ["P0", "P1", "P2", "P3"],
|
|
@@ -36897,7 +37026,7 @@ async function loadHealthConfig(cwd) {
|
|
|
36897
37026
|
// src/health/run.ts
|
|
36898
37027
|
init_fs();
|
|
36899
37028
|
import { mkdir as mkdir29, writeFile as writeFile22 } from "fs/promises";
|
|
36900
|
-
import
|
|
37029
|
+
import path123 from "path";
|
|
36901
37030
|
|
|
36902
37031
|
// src/metrics/provenance.ts
|
|
36903
37032
|
async function collectGitProvenance(cwd) {
|
|
@@ -37010,12 +37139,12 @@ function computeGate2(input) {
|
|
|
37010
37139
|
}
|
|
37011
37140
|
|
|
37012
37141
|
// src/health/scopes.ts
|
|
37013
|
-
import
|
|
37142
|
+
import path108 from "path";
|
|
37014
37143
|
|
|
37015
37144
|
// src/health/util.ts
|
|
37016
37145
|
init_fs();
|
|
37017
37146
|
import { mkdir as mkdir26, readFile as readFile54, readdir as readdir19, writeFile as writeFile19 } from "fs/promises";
|
|
37018
|
-
import
|
|
37147
|
+
import path106 from "path";
|
|
37019
37148
|
var IGNORED_DIRS = new Set([
|
|
37020
37149
|
"node_modules",
|
|
37021
37150
|
".git",
|
|
@@ -37059,14 +37188,14 @@ async function toolVersion(command, cwd) {
|
|
|
37059
37188
|
}
|
|
37060
37189
|
}
|
|
37061
37190
|
function dataRoot3(cwd) {
|
|
37062
|
-
return
|
|
37191
|
+
return path106.join(cwd, ".metaproject", "data", "health");
|
|
37063
37192
|
}
|
|
37064
37193
|
async function writeRaw(cwd, source, content, stamp) {
|
|
37065
|
-
const dir =
|
|
37194
|
+
const dir = path106.join(dataRoot3(cwd), "raw", source);
|
|
37066
37195
|
await mkdir26(dir, { recursive: true });
|
|
37067
|
-
const file =
|
|
37196
|
+
const file = path106.join(dir, `${stamp}.log`);
|
|
37068
37197
|
await writeFile19(file, content, "utf8");
|
|
37069
|
-
return
|
|
37198
|
+
return path106.relative(cwd, file);
|
|
37070
37199
|
}
|
|
37071
37200
|
async function listSourceFiles(cwd, ignorePaths = []) {
|
|
37072
37201
|
const { files } = await listSourceFilesWithReasons(cwd, ignorePaths);
|
|
@@ -37086,7 +37215,7 @@ async function walk2(root, dir, out, incompleteReasons) {
|
|
|
37086
37215
|
try {
|
|
37087
37216
|
entries = await readdir19(dir, { withFileTypes: true });
|
|
37088
37217
|
} catch (error) {
|
|
37089
|
-
incompleteReasons.push(`${
|
|
37218
|
+
incompleteReasons.push(`${path106.relative(root, dir) || "."}: ${error instanceof Error ? error.message : String(error)}`);
|
|
37090
37219
|
return;
|
|
37091
37220
|
}
|
|
37092
37221
|
for (const entry of entries) {
|
|
@@ -37094,14 +37223,14 @@ async function walk2(root, dir, out, incompleteReasons) {
|
|
|
37094
37223
|
if (entry.isDirectory() && !IGNORED_DIRS.has(entry.name)) {}
|
|
37095
37224
|
continue;
|
|
37096
37225
|
}
|
|
37097
|
-
const abs =
|
|
37226
|
+
const abs = path106.join(dir, entry.name);
|
|
37098
37227
|
if (entry.isDirectory()) {
|
|
37099
37228
|
if (IGNORED_DIRS.has(entry.name)) {
|
|
37100
37229
|
continue;
|
|
37101
37230
|
}
|
|
37102
37231
|
await walk2(root, abs, out, incompleteReasons);
|
|
37103
|
-
} else if (entry.isFile() && SOURCE_EXT.has(
|
|
37104
|
-
out.push(
|
|
37232
|
+
} else if (entry.isFile() && SOURCE_EXT.has(path106.extname(entry.name))) {
|
|
37233
|
+
out.push(path106.relative(root, abs));
|
|
37105
37234
|
}
|
|
37106
37235
|
}
|
|
37107
37236
|
}
|
|
@@ -37116,7 +37245,7 @@ function moduleOfFile(file) {
|
|
|
37116
37245
|
return null;
|
|
37117
37246
|
}
|
|
37118
37247
|
function isSourceFile(file) {
|
|
37119
|
-
return SOURCE_EXT.has(
|
|
37248
|
+
return SOURCE_EXT.has(path106.extname(file));
|
|
37120
37249
|
}
|
|
37121
37250
|
function matchesAnyPattern(file, patterns) {
|
|
37122
37251
|
const normalized = file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
@@ -37218,7 +37347,7 @@ function rankHotspots(files, churn, sourceAnalysis) {
|
|
|
37218
37347
|
// src/health/source-analysis.ts
|
|
37219
37348
|
init_fs();
|
|
37220
37349
|
import { readFile as readFile55 } from "fs/promises";
|
|
37221
|
-
import
|
|
37350
|
+
import path107 from "path";
|
|
37222
37351
|
|
|
37223
37352
|
// src/health/metrics/complexity.ts
|
|
37224
37353
|
var CONTROL_KEYWORDS = new Set([
|
|
@@ -37452,7 +37581,7 @@ async function analyzeSourceFiles(cwd, sourceFiles) {
|
|
|
37452
37581
|
return new Map(entries.filter((entry) => entry !== null));
|
|
37453
37582
|
}
|
|
37454
37583
|
async function analyzeSourceFile(cwd, file) {
|
|
37455
|
-
const abs =
|
|
37584
|
+
const abs = path107.join(cwd, file);
|
|
37456
37585
|
if (!await pathExists(abs)) {
|
|
37457
37586
|
return null;
|
|
37458
37587
|
}
|
|
@@ -37529,14 +37658,14 @@ async function computeMetrics(input) {
|
|
|
37529
37658
|
}
|
|
37530
37659
|
const components = new Map;
|
|
37531
37660
|
for (const file of sourceFiles) {
|
|
37532
|
-
const dir =
|
|
37661
|
+
const dir = path108.posix.dirname(file);
|
|
37533
37662
|
if (dir === "." || dir === moduleOfFile(file)) {
|
|
37534
37663
|
continue;
|
|
37535
37664
|
}
|
|
37536
37665
|
components.set(dir, [...components.get(dir) ?? [], file]);
|
|
37537
37666
|
}
|
|
37538
37667
|
for (const [name, files] of [...components.entries()].sort()) {
|
|
37539
|
-
const compFindings = findings.filter((f) => f.file &&
|
|
37668
|
+
const compFindings = findings.filter((f) => f.file && path108.posix.dirname(f.file) === name);
|
|
37540
37669
|
scopes.push(build("component", `component:${name}`, name, files, compFindings, averageCoverage(files, coverage)));
|
|
37541
37670
|
}
|
|
37542
37671
|
const findingFiles = findings.map((f) => f.file).filter((f) => Boolean(f));
|
|
@@ -37581,7 +37710,7 @@ function tally2(values) {
|
|
|
37581
37710
|
// src/health/baseline.ts
|
|
37582
37711
|
init_fs();
|
|
37583
37712
|
import { mkdir as mkdir27, readFile as readFile56, writeFile as writeFile20 } from "fs/promises";
|
|
37584
|
-
import
|
|
37713
|
+
import path109 from "path";
|
|
37585
37714
|
var LEGACY_BASELINE_SOURCES = Object.freeze([
|
|
37586
37715
|
"complexity",
|
|
37587
37716
|
"coverage",
|
|
@@ -37606,7 +37735,7 @@ function measuredSources(sources) {
|
|
|
37606
37735
|
return sources.filter((s) => s !== null && typeof s === "object").filter((s) => !didNotProduceResult(s)).map((s) => s.source).sort();
|
|
37607
37736
|
}
|
|
37608
37737
|
function baselinePath(cwd) {
|
|
37609
|
-
return
|
|
37738
|
+
return path109.join(cwd, ".metaproject", "health", "baselines", "scores.json");
|
|
37610
37739
|
}
|
|
37611
37740
|
async function readBaselineFile(cwd) {
|
|
37612
37741
|
const file = baselinePath(cwd);
|
|
@@ -37627,7 +37756,7 @@ async function loadBaselineSources(cwd) {
|
|
|
37627
37756
|
}
|
|
37628
37757
|
async function writeBaselineFile(cwd, data) {
|
|
37629
37758
|
const file = baselinePath(cwd);
|
|
37630
|
-
await mkdir27(
|
|
37759
|
+
await mkdir27(path109.dirname(file), { recursive: true });
|
|
37631
37760
|
await writeFile20(file, `${JSON.stringify(data, null, 2)}
|
|
37632
37761
|
`, "utf8");
|
|
37633
37762
|
}
|
|
@@ -37709,10 +37838,10 @@ async function getChurn(cwd, windowDays) {
|
|
|
37709
37838
|
|
|
37710
37839
|
// src/health/metrics/wiki-freshness.ts
|
|
37711
37840
|
import { readFile as readFile57, stat as stat16 } from "fs/promises";
|
|
37712
|
-
import
|
|
37841
|
+
import path110 from "path";
|
|
37713
37842
|
var DEFAULT_STALE_EVIDENCE_DAYS = 7;
|
|
37714
37843
|
function freshnessReportPath(cwd) {
|
|
37715
|
-
return
|
|
37844
|
+
return path110.join(cwd, ".metaproject", "data", "wiki", "freshness", "latest.json");
|
|
37716
37845
|
}
|
|
37717
37846
|
async function readWikiFreshnessMetric(cwd, options = {}) {
|
|
37718
37847
|
const file = freshnessReportPath(cwd);
|
|
@@ -37733,7 +37862,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
|
|
|
37733
37862
|
} catch {
|
|
37734
37863
|
return {
|
|
37735
37864
|
status: "unreadable-report",
|
|
37736
|
-
reason: `${
|
|
37865
|
+
reason: `${path110.relative(cwd, file)} is not valid JSON; re-run \`keryx wiki freshness\`.`
|
|
37737
37866
|
};
|
|
37738
37867
|
}
|
|
37739
37868
|
const report = parsed;
|
|
@@ -37743,7 +37872,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
|
|
|
37743
37872
|
if (pagesTotal === null || pagesFresh === null) {
|
|
37744
37873
|
return {
|
|
37745
37874
|
status: "unreadable-report",
|
|
37746
|
-
reason: `${
|
|
37875
|
+
reason: `${path110.relative(cwd, file)} is missing its totals; re-run \`keryx wiki freshness\`.`
|
|
37747
37876
|
};
|
|
37748
37877
|
}
|
|
37749
37878
|
const pagesUndecidable = numberOr3(totals.pagesUndecidable) ?? 0;
|
|
@@ -37797,12 +37926,12 @@ function renderWikiFreshnessLine(metric) {
|
|
|
37797
37926
|
}
|
|
37798
37927
|
|
|
37799
37928
|
// src/health/sources/helpers.ts
|
|
37800
|
-
import
|
|
37929
|
+
import path111 from "path";
|
|
37801
37930
|
import { existsSync as existsSync12 } from "fs";
|
|
37802
37931
|
class NoImportError extends Error {
|
|
37803
37932
|
}
|
|
37804
37933
|
function resolveBin(cwd, name) {
|
|
37805
|
-
const local =
|
|
37934
|
+
const local = path111.join(cwd, "node_modules", ".bin", name);
|
|
37806
37935
|
if (existsSync12(local)) {
|
|
37807
37936
|
return local;
|
|
37808
37937
|
}
|
|
@@ -37883,13 +38012,13 @@ async function getComplexityFindings(cwd, sourceFiles, config, sourceAnalysis) {
|
|
|
37883
38012
|
|
|
37884
38013
|
// src/health/metrics/coverage.ts
|
|
37885
38014
|
import { existsSync as existsSync13 } from "fs";
|
|
37886
|
-
import
|
|
38015
|
+
import path112 from "path";
|
|
37887
38016
|
var SUMMARY_PATHS = [
|
|
37888
38017
|
"coverage/coverage-summary.json",
|
|
37889
38018
|
"coverage/coverage-final.json"
|
|
37890
38019
|
];
|
|
37891
38020
|
async function getCoverage(cwd) {
|
|
37892
|
-
const summary = SUMMARY_PATHS.map((rel) =>
|
|
38021
|
+
const summary = SUMMARY_PATHS.map((rel) => path112.join(cwd, rel)).find((abs) => existsSync13(abs));
|
|
37893
38022
|
if (!summary) {
|
|
37894
38023
|
return { status: "missing", total: null, byFile: new Map };
|
|
37895
38024
|
}
|
|
@@ -37910,7 +38039,7 @@ async function getCoverage(cwd) {
|
|
|
37910
38039
|
total = pct;
|
|
37911
38040
|
continue;
|
|
37912
38041
|
}
|
|
37913
|
-
const relative =
|
|
38042
|
+
const relative = path112.isAbsolute(key) ? path112.relative(cwd, key) : key;
|
|
37914
38043
|
byFile.set(relative.replace(/\\/g, "/"), pct);
|
|
37915
38044
|
}
|
|
37916
38045
|
return { status: "available", total, byFile };
|
|
@@ -38043,10 +38172,10 @@ function renderWikiFreshness(metric) {
|
|
|
38043
38172
|
// src/health/skills.ts
|
|
38044
38173
|
init_fs();
|
|
38045
38174
|
import { readFile as readFile58 } from "fs/promises";
|
|
38046
|
-
import
|
|
38175
|
+
import path113 from "path";
|
|
38047
38176
|
var EMPTY = { skills: [], skillForFile: () => null };
|
|
38048
38177
|
async function loadSkillOwnership(cwd) {
|
|
38049
|
-
const manifestPath =
|
|
38178
|
+
const manifestPath = path113.join(cwd, ".metaproject", "metaproject.json");
|
|
38050
38179
|
if (!await pathExists(manifestPath)) {
|
|
38051
38180
|
return EMPTY;
|
|
38052
38181
|
}
|
|
@@ -38084,7 +38213,7 @@ function normalize(value) {
|
|
|
38084
38213
|
|
|
38085
38214
|
// src/health/sources/eslint.ts
|
|
38086
38215
|
import { existsSync as existsSync14 } from "fs";
|
|
38087
|
-
import
|
|
38216
|
+
import path114 from "path";
|
|
38088
38217
|
var CONFIG_FILES = [
|
|
38089
38218
|
".eslintrc",
|
|
38090
38219
|
".eslintrc.js",
|
|
@@ -38098,7 +38227,7 @@ var CONFIG_FILES = [
|
|
|
38098
38227
|
"eslint.config.ts"
|
|
38099
38228
|
];
|
|
38100
38229
|
function hasConfig(cwd) {
|
|
38101
|
-
return CONFIG_FILES.some((file) => existsSync14(
|
|
38230
|
+
return CONFIG_FILES.some((file) => existsSync14(path114.join(cwd, file)));
|
|
38102
38231
|
}
|
|
38103
38232
|
var eslintAdapter = {
|
|
38104
38233
|
id: "eslint",
|
|
@@ -38124,7 +38253,7 @@ var eslintAdapter = {
|
|
|
38124
38253
|
};
|
|
38125
38254
|
},
|
|
38126
38255
|
async import(ctx) {
|
|
38127
|
-
const report =
|
|
38256
|
+
const report = path114.join(ctx.cwd, "eslint-report.json");
|
|
38128
38257
|
if (!existsSync14(report)) {
|
|
38129
38258
|
throw new NoImportError("no eslint-report.json");
|
|
38130
38259
|
}
|
|
@@ -38151,7 +38280,7 @@ var eslintAdapter = {
|
|
|
38151
38280
|
}
|
|
38152
38281
|
const findings = [];
|
|
38153
38282
|
for (const file of data) {
|
|
38154
|
-
const relative =
|
|
38283
|
+
const relative = path114.isAbsolute(file.filePath) ? path114.relative(ctx.cwd, file.filePath) : file.filePath;
|
|
38155
38284
|
for (const message of file.messages ?? []) {
|
|
38156
38285
|
const isError = message.severity === 2;
|
|
38157
38286
|
findings.push(makeFinding({
|
|
@@ -38183,19 +38312,19 @@ var eslintAdapter = {
|
|
|
38183
38312
|
|
|
38184
38313
|
// src/health/sources/oxlint.ts
|
|
38185
38314
|
import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
|
|
38186
|
-
import
|
|
38315
|
+
import path115 from "path";
|
|
38187
38316
|
var CONFIG_FILES2 = [".oxlintrc.json", ".oxlintrc.jsonc"];
|
|
38188
38317
|
var OXLINT_FORMAT = "json";
|
|
38189
38318
|
var OXLINT_PARSE_ERROR = "oxlint JSON format was not recognized";
|
|
38190
38319
|
var OXLINT_NO_FILES = "oxlint found no files to lint (check its paths and ignore patterns)";
|
|
38191
38320
|
var NO_FILES_PREAMBLE = "No files found to lint";
|
|
38192
38321
|
function hasConfigFile(cwd) {
|
|
38193
|
-
if (CONFIG_FILES2.some((file) => existsSync15(
|
|
38322
|
+
if (CONFIG_FILES2.some((file) => existsSync15(path115.join(cwd, file))))
|
|
38194
38323
|
return true;
|
|
38195
|
-
return [".oxlintrc.js", ".oxlintrc.cjs", ".oxlintrc.mjs", ".oxlintrc.ts"].some((file) => existsSync15(
|
|
38324
|
+
return [".oxlintrc.js", ".oxlintrc.cjs", ".oxlintrc.mjs", ".oxlintrc.ts"].some((file) => existsSync15(path115.join(cwd, file)));
|
|
38196
38325
|
}
|
|
38197
38326
|
function packageNamesOxlint(cwd) {
|
|
38198
|
-
const file =
|
|
38327
|
+
const file = path115.join(cwd, "package.json");
|
|
38199
38328
|
if (!existsSync15(file))
|
|
38200
38329
|
return false;
|
|
38201
38330
|
try {
|
|
@@ -38253,7 +38382,7 @@ var oxlintAdapter = {
|
|
|
38253
38382
|
return [];
|
|
38254
38383
|
return data.map((diagnostic) => {
|
|
38255
38384
|
const filePath = diagnostic.filename ?? "";
|
|
38256
|
-
const relative = filePath &&
|
|
38385
|
+
const relative = filePath && path115.isAbsolute(filePath) ? path115.relative(ctx.cwd, filePath) : filePath;
|
|
38257
38386
|
const isError = diagnostic.severity === "error";
|
|
38258
38387
|
return makeFinding({
|
|
38259
38388
|
source: "oxlint",
|
|
@@ -38279,9 +38408,9 @@ var oxlintAdapter = {
|
|
|
38279
38408
|
|
|
38280
38409
|
// src/health/sources/typescript.ts
|
|
38281
38410
|
import { existsSync as existsSync16 } from "fs";
|
|
38282
|
-
import
|
|
38411
|
+
import path116 from "path";
|
|
38283
38412
|
function hasTsconfig(cwd) {
|
|
38284
|
-
return existsSync16(
|
|
38413
|
+
return existsSync16(path116.join(cwd, "tsconfig.json"));
|
|
38285
38414
|
}
|
|
38286
38415
|
var typescriptAdapter = {
|
|
38287
38416
|
id: "typescript",
|
|
@@ -38342,31 +38471,12 @@ init_fs();
|
|
|
38342
38471
|
init_contained_write();
|
|
38343
38472
|
import { existsSync as existsSync17 } from "fs";
|
|
38344
38473
|
import { readFile as readFile61, readdir as readdir20 } from "fs/promises";
|
|
38345
|
-
import
|
|
38346
|
-
|
|
38347
|
-
// src/lib/git-env.ts
|
|
38348
|
-
var GIT_DISCOVERY_OVERRIDE_VARS = [
|
|
38349
|
-
"GIT_DIR",
|
|
38350
|
-
"GIT_WORK_TREE",
|
|
38351
|
-
"GIT_INDEX_FILE",
|
|
38352
|
-
"GIT_OBJECT_DIRECTORY",
|
|
38353
|
-
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
38354
|
-
"GIT_COMMON_DIR"
|
|
38355
|
-
];
|
|
38356
|
-
function withoutGitDiscoveryOverrides(env) {
|
|
38357
|
-
const clean = {};
|
|
38358
|
-
for (const [key, value] of Object.entries(env)) {
|
|
38359
|
-
if (value !== undefined && !GIT_DISCOVERY_OVERRIDE_VARS.includes(key)) {
|
|
38360
|
-
clean[key] = value;
|
|
38361
|
-
}
|
|
38362
|
-
}
|
|
38363
|
-
return clean;
|
|
38364
|
-
}
|
|
38474
|
+
import path120 from "path";
|
|
38365
38475
|
// src/metrics/lifecycle.ts
|
|
38366
38476
|
init_fs();
|
|
38367
38477
|
init_guard();
|
|
38368
38478
|
import { readFile as readFile59 } from "fs/promises";
|
|
38369
|
-
import
|
|
38479
|
+
import path117 from "path";
|
|
38370
38480
|
|
|
38371
38481
|
// src/metrics/record.ts
|
|
38372
38482
|
var RELIABILITIES = new Set(["exact", "estimated", "unknown"]);
|
|
@@ -38381,7 +38491,7 @@ var RETRY_TYPES = new Set([
|
|
|
38381
38491
|
|
|
38382
38492
|
// src/metrics/lifecycle.ts
|
|
38383
38493
|
async function readArtifactPointer(root, expected) {
|
|
38384
|
-
const pointerFile =
|
|
38494
|
+
const pointerFile = path117.join(root, "latest.json");
|
|
38385
38495
|
if (!await pathExists(pointerFile))
|
|
38386
38496
|
return { status: "missing", pointer: null };
|
|
38387
38497
|
let pointer;
|
|
@@ -38390,7 +38500,7 @@ async function readArtifactPointer(root, expected) {
|
|
|
38390
38500
|
} catch {
|
|
38391
38501
|
return { status: "stale", pointer: null, reason: "latest pointer is invalid JSON" };
|
|
38392
38502
|
}
|
|
38393
|
-
const recordFile = pointer.record ?
|
|
38503
|
+
const recordFile = pointer.record ? path117.join(root, pointer.record) : null;
|
|
38394
38504
|
if (!recordFile || !isPathInside(root, recordFile) || !await pathExists(recordFile)) {
|
|
38395
38505
|
return { status: "stale", pointer, reason: "pointer record is missing" };
|
|
38396
38506
|
}
|
|
@@ -38406,9 +38516,9 @@ init_guard();
|
|
|
38406
38516
|
// src/testing/capability.ts
|
|
38407
38517
|
init_fs();
|
|
38408
38518
|
init_json();
|
|
38409
|
-
import
|
|
38519
|
+
import path118 from "path";
|
|
38410
38520
|
async function isTestingCapabilityEnabled(cwd, capability) {
|
|
38411
|
-
const manifestPath =
|
|
38521
|
+
const manifestPath = path118.join(cwd, ".metaproject", "metaproject.json");
|
|
38412
38522
|
if (!await pathExists(manifestPath)) {
|
|
38413
38523
|
return false;
|
|
38414
38524
|
}
|
|
@@ -38434,10 +38544,10 @@ async function isTestingCapabilityEnabled(cwd, capability) {
|
|
|
38434
38544
|
init_fs();
|
|
38435
38545
|
init_guard();
|
|
38436
38546
|
import { readFile as readFile60, mkdir as mkdir28, writeFile as writeFile21 } from "fs/promises";
|
|
38437
|
-
import
|
|
38547
|
+
import path119 from "path";
|
|
38438
38548
|
var COVERAGE_MAP_SCHEMA_VERSION = 1;
|
|
38439
38549
|
function coverageMapPath(cwd, cfg) {
|
|
38440
|
-
return
|
|
38550
|
+
return path119.isAbsolute(cfg.coverageMap.artifact) ? cfg.coverageMap.artifact : path119.join(cwd, cfg.coverageMap.artifact);
|
|
38441
38551
|
}
|
|
38442
38552
|
async function loadCoverageMap(cwd, cfg) {
|
|
38443
38553
|
const file = coverageMapPath(cwd, cfg);
|
|
@@ -38572,7 +38682,7 @@ var DEFAULT_TESTING_CONFIG = {
|
|
|
38572
38682
|
}
|
|
38573
38683
|
};
|
|
38574
38684
|
function testingDataRoot(cwd) {
|
|
38575
|
-
return
|
|
38685
|
+
return path120.join(cwd, ".metaproject", "data", "testing");
|
|
38576
38686
|
}
|
|
38577
38687
|
async function computeTestingContext(cwd) {
|
|
38578
38688
|
const { files, incompleteReasons } = await listProjectFiles(cwd);
|
|
@@ -38747,7 +38857,7 @@ async function runTesting(input) {
|
|
|
38747
38857
|
return runResult;
|
|
38748
38858
|
}
|
|
38749
38859
|
async function loadTestingContext(cwd) {
|
|
38750
|
-
const file =
|
|
38860
|
+
const file = path120.join(testingDataRoot(cwd), "context.json");
|
|
38751
38861
|
if (!await pathExists(file)) {
|
|
38752
38862
|
return null;
|
|
38753
38863
|
}
|
|
@@ -38758,18 +38868,18 @@ async function loadTestingContext(cwd) {
|
|
|
38758
38868
|
}
|
|
38759
38869
|
}
|
|
38760
38870
|
async function loadTestingReport(cwd) {
|
|
38761
|
-
const file =
|
|
38871
|
+
const file = path120.join(testingDataRoot(cwd), "artifacts", "latest.json");
|
|
38762
38872
|
if (!await pathExists(file)) {
|
|
38763
38873
|
return null;
|
|
38764
38874
|
}
|
|
38765
38875
|
try {
|
|
38766
38876
|
const latest = JSON.parse(await readFile61(file, "utf8"));
|
|
38767
38877
|
if (typeof latest.record === "string") {
|
|
38768
|
-
const pointer = await readArtifactPointer(
|
|
38878
|
+
const pointer = await readArtifactPointer(path120.join(testingDataRoot(cwd), "artifacts"), await collectGitProvenance(cwd));
|
|
38769
38879
|
if (pointer.status !== "fresh")
|
|
38770
38880
|
return null;
|
|
38771
|
-
const recordFile =
|
|
38772
|
-
if (!isPathInside(
|
|
38881
|
+
const recordFile = path120.join(testingDataRoot(cwd), "artifacts", latest.record);
|
|
38882
|
+
if (!isPathInside(path120.join(testingDataRoot(cwd), "artifacts"), recordFile))
|
|
38773
38883
|
return null;
|
|
38774
38884
|
if (!await pathExists(recordFile))
|
|
38775
38885
|
return null;
|
|
@@ -38816,28 +38926,28 @@ async function ensureContext(cwd) {
|
|
|
38816
38926
|
}
|
|
38817
38927
|
async function writeContext(cwd, context) {
|
|
38818
38928
|
const root = testingDataRoot(cwd);
|
|
38819
|
-
const rel = (p) =>
|
|
38929
|
+
const rel = (p) => path120.relative(cwd, p);
|
|
38820
38930
|
await mkdirContained(cwd, rel(root));
|
|
38821
|
-
await writeContained(cwd, rel(
|
|
38931
|
+
await writeContained(cwd, rel(path120.join(root, "context.json")), `${JSON.stringify(context, null, 2)}
|
|
38822
38932
|
`);
|
|
38823
|
-
await writeContained(cwd, rel(
|
|
38824
|
-
await writeContained(cwd, rel(
|
|
38933
|
+
await writeContained(cwd, rel(path120.join(root, "context.md")), renderContextMarkdown(context));
|
|
38934
|
+
await writeContained(cwd, rel(path120.join(root, "recommendations.md")), renderRecommendationsMarkdown(context));
|
|
38825
38935
|
}
|
|
38826
38936
|
async function writeReport(cwd, report) {
|
|
38827
38937
|
const root = testingDataRoot(cwd);
|
|
38828
|
-
const artifacts =
|
|
38829
|
-
const history =
|
|
38830
|
-
const rel = (p) =>
|
|
38938
|
+
const artifacts = path120.join(root, "artifacts");
|
|
38939
|
+
const history = path120.join(root, "history");
|
|
38940
|
+
const rel = (p) => path120.relative(cwd, p);
|
|
38831
38941
|
await mkdirContained(cwd, rel(artifacts));
|
|
38832
38942
|
await mkdirContained(cwd, rel(history));
|
|
38833
38943
|
const stamp = report.generatedAt.replace(/[:.]/g, "-");
|
|
38834
|
-
const json =
|
|
38835
|
-
const markdown =
|
|
38944
|
+
const json = path120.join(artifacts, "latest.json");
|
|
38945
|
+
const markdown = path120.join(artifacts, "latest.md");
|
|
38836
38946
|
const serialized = `${JSON.stringify(report, null, 2)}
|
|
38837
38947
|
`;
|
|
38838
38948
|
if (report.runId) {
|
|
38839
|
-
const runJson =
|
|
38840
|
-
const runMarkdown =
|
|
38949
|
+
const runJson = path120.join(artifacts, "runs", `${report.runId}.json`);
|
|
38950
|
+
const runMarkdown = path120.join(artifacts, "runs", `${report.runId}.md`);
|
|
38841
38951
|
if (await pathExists(runJson))
|
|
38842
38952
|
throw new Error(`immutable testing run already exists: ${report.runId}`);
|
|
38843
38953
|
await writeContained(cwd, rel(runJson), serialized);
|
|
@@ -38848,26 +38958,26 @@ async function writeReport(cwd, report) {
|
|
|
38848
38958
|
branch: report.provenance?.branch ?? null,
|
|
38849
38959
|
worktree: report.provenance?.worktree ?? null,
|
|
38850
38960
|
generated_at: report.generatedAt,
|
|
38851
|
-
record:
|
|
38961
|
+
record: path120.posix.join("runs", `${report.runId}.json`)
|
|
38852
38962
|
}, null, 2)}
|
|
38853
38963
|
`);
|
|
38854
38964
|
} else {
|
|
38855
38965
|
await writeContained(cwd, rel(json), serialized);
|
|
38856
38966
|
}
|
|
38857
38967
|
await writeContained(cwd, rel(markdown), renderReportMarkdown3(report));
|
|
38858
|
-
await writeContained(cwd, rel(
|
|
38968
|
+
await writeContained(cwd, rel(path120.join(history, `${stamp}.json`)), serialized);
|
|
38859
38969
|
return {
|
|
38860
|
-
markdownPath:
|
|
38861
|
-
jsonPath:
|
|
38970
|
+
markdownPath: path120.relative(cwd, markdown),
|
|
38971
|
+
jsonPath: path120.relative(cwd, json)
|
|
38862
38972
|
};
|
|
38863
38973
|
}
|
|
38864
38974
|
async function writeRawLog(cwd, raw) {
|
|
38865
|
-
const logs =
|
|
38866
|
-
const rel = (p) =>
|
|
38975
|
+
const logs = path120.join(testingDataRoot(cwd), "logs");
|
|
38976
|
+
const rel = (p) => path120.relative(cwd, p);
|
|
38867
38977
|
await mkdirContained(cwd, rel(logs));
|
|
38868
|
-
const latest =
|
|
38978
|
+
const latest = path120.join(logs, "latest.raw.log");
|
|
38869
38979
|
await writeContained(cwd, rel(latest), raw);
|
|
38870
|
-
return
|
|
38980
|
+
return path120.relative(cwd, latest);
|
|
38871
38981
|
}
|
|
38872
38982
|
async function listProjectFiles(cwd) {
|
|
38873
38983
|
const out = [];
|
|
@@ -38880,11 +38990,11 @@ async function walk3(root, dir, out, incompleteReasons) {
|
|
|
38880
38990
|
try {
|
|
38881
38991
|
entries = await readdir20(dir, { withFileTypes: true });
|
|
38882
38992
|
} catch (error) {
|
|
38883
|
-
incompleteReasons.push(`${normalizePath6(
|
|
38993
|
+
incompleteReasons.push(`${normalizePath6(path120.relative(root, dir)) || "."}: ${error instanceof Error ? error.message : String(error)}`);
|
|
38884
38994
|
return;
|
|
38885
38995
|
}
|
|
38886
38996
|
for (const entry of entries) {
|
|
38887
|
-
const abs =
|
|
38997
|
+
const abs = path120.join(dir, entry.name);
|
|
38888
38998
|
if (entry.isDirectory()) {
|
|
38889
38999
|
if (IGNORED_DIRS2.has(entry.name) || entry.name.startsWith(".tmp-")) {
|
|
38890
39000
|
continue;
|
|
@@ -38893,12 +39003,12 @@ async function walk3(root, dir, out, incompleteReasons) {
|
|
|
38893
39003
|
continue;
|
|
38894
39004
|
}
|
|
38895
39005
|
if (entry.isFile()) {
|
|
38896
|
-
out.push(normalizePath6(
|
|
39006
|
+
out.push(normalizePath6(path120.relative(root, abs)));
|
|
38897
39007
|
}
|
|
38898
39008
|
}
|
|
38899
39009
|
}
|
|
38900
39010
|
async function readPackageJson(cwd) {
|
|
38901
|
-
const file =
|
|
39011
|
+
const file = path120.join(cwd, "package.json");
|
|
38902
39012
|
if (!await pathExists(file)) {
|
|
38903
39013
|
return null;
|
|
38904
39014
|
}
|
|
@@ -38909,7 +39019,7 @@ async function readPackageJson(cwd) {
|
|
|
38909
39019
|
}
|
|
38910
39020
|
}
|
|
38911
39021
|
async function loadTestingConfig(cwd) {
|
|
38912
|
-
const file =
|
|
39022
|
+
const file = path120.join(cwd, ".metaproject", "testing.config.json");
|
|
38913
39023
|
if (!await pathExists(file)) {
|
|
38914
39024
|
return DEFAULT_TESTING_CONFIG;
|
|
38915
39025
|
}
|
|
@@ -38974,7 +39084,7 @@ function detectFrameworks(input) {
|
|
|
38974
39084
|
async function extractConventions(cwd, files) {
|
|
38975
39085
|
const conventions = new Set;
|
|
38976
39086
|
for (const file of files.slice(0, 40)) {
|
|
38977
|
-
const abs =
|
|
39087
|
+
const abs = path120.join(cwd, file);
|
|
38978
39088
|
if (!await pathExists(abs)) {
|
|
38979
39089
|
continue;
|
|
38980
39090
|
}
|
|
@@ -39104,7 +39214,7 @@ async function findTestsByImportedTargets(cwd, targets, testFiles) {
|
|
|
39104
39214
|
const targetKeys = new Set(targets.map((target) => modulePathKey(normalizePath6(target))));
|
|
39105
39215
|
const selected = new Set;
|
|
39106
39216
|
for (const testFile of testFiles) {
|
|
39107
|
-
const absoluteTest =
|
|
39217
|
+
const absoluteTest = path120.join(cwd, testFile);
|
|
39108
39218
|
if (!await pathExists(absoluteTest)) {
|
|
39109
39219
|
continue;
|
|
39110
39220
|
}
|
|
@@ -39138,10 +39248,10 @@ function resolveImportPath(cwd, testFile, importPath) {
|
|
|
39138
39248
|
if (!importPath.startsWith(".")) {
|
|
39139
39249
|
return null;
|
|
39140
39250
|
}
|
|
39141
|
-
const importerDir =
|
|
39142
|
-
const absoluteResolved =
|
|
39143
|
-
const relative =
|
|
39144
|
-
if (relative.startsWith(`..${
|
|
39251
|
+
const importerDir = path120.dirname(testFile);
|
|
39252
|
+
const absoluteResolved = path120.resolve(path120.join(cwd, importerDir), importPath);
|
|
39253
|
+
const relative = path120.relative(cwd, absoluteResolved);
|
|
39254
|
+
if (relative.startsWith(`..${path120.sep}`) || relative === "..") {
|
|
39145
39255
|
return null;
|
|
39146
39256
|
}
|
|
39147
39257
|
const relativeNormalized = normalizePath6(relative);
|
|
@@ -39193,13 +39303,13 @@ function resolveTestCommand(cwd, context, input) {
|
|
|
39193
39303
|
}
|
|
39194
39304
|
var BUN_LOCKFILES = ["bun.lock", "bun.lockb"];
|
|
39195
39305
|
function detectPackageManager(cwd) {
|
|
39196
|
-
if (resolveBunBin() && BUN_LOCKFILES.some((name) => pathExistsSync(
|
|
39306
|
+
if (resolveBunBin() && BUN_LOCKFILES.some((name) => pathExistsSync(path120.join(cwd, name)))) {
|
|
39197
39307
|
return "bun";
|
|
39198
39308
|
}
|
|
39199
|
-
if (Bun.which("pnpm") && pathExistsSync(
|
|
39309
|
+
if (Bun.which("pnpm") && pathExistsSync(path120.join(cwd, "pnpm-lock.yaml"))) {
|
|
39200
39310
|
return "pnpm";
|
|
39201
39311
|
}
|
|
39202
|
-
if (Bun.which("yarn") && pathExistsSync(
|
|
39312
|
+
if (Bun.which("yarn") && pathExistsSync(path120.join(cwd, "yarn.lock"))) {
|
|
39203
39313
|
return "yarn";
|
|
39204
39314
|
}
|
|
39205
39315
|
return "npm";
|
|
@@ -39539,7 +39649,7 @@ async function compatibleReportForHealth(ctx) {
|
|
|
39539
39649
|
|
|
39540
39650
|
// src/health/sources/dependency-audit.ts
|
|
39541
39651
|
import { existsSync as existsSync18 } from "fs";
|
|
39542
|
-
import
|
|
39652
|
+
import path121 from "path";
|
|
39543
39653
|
function auditSeverityToPriority(severity) {
|
|
39544
39654
|
if (severity === "critical" || severity === "high")
|
|
39545
39655
|
return "P0";
|
|
@@ -39658,7 +39768,7 @@ var LOCKFILE_COMMANDS = [
|
|
|
39658
39768
|
];
|
|
39659
39769
|
function auditCommand(cwd) {
|
|
39660
39770
|
for (const entry of LOCKFILE_COMMANDS) {
|
|
39661
|
-
if (!entry.lockfiles.some((name) => existsSync18(
|
|
39771
|
+
if (!entry.lockfiles.some((name) => existsSync18(path121.join(cwd, name))))
|
|
39662
39772
|
continue;
|
|
39663
39773
|
const bin = resolveBin(cwd, entry.bin);
|
|
39664
39774
|
if (bin)
|
|
@@ -39717,13 +39827,13 @@ var dependencyAuditAdapter = {
|
|
|
39717
39827
|
|
|
39718
39828
|
// src/health/sources/sonarqube.ts
|
|
39719
39829
|
import { existsSync as existsSync19 } from "fs";
|
|
39720
|
-
import
|
|
39830
|
+
import path122 from "path";
|
|
39721
39831
|
var REPORT_FILES = ["sonar-issues.json", ".metaproject/data/health/sonar-issues.json"];
|
|
39722
39832
|
function reportPath(cwd) {
|
|
39723
39833
|
const fromEnv = process.env.SONAR_ISSUES_FILE;
|
|
39724
39834
|
const candidates = fromEnv ? [fromEnv, ...REPORT_FILES] : REPORT_FILES;
|
|
39725
39835
|
for (const rel of candidates) {
|
|
39726
|
-
const abs =
|
|
39836
|
+
const abs = path122.isAbsolute(rel) ? rel : path122.join(cwd, rel);
|
|
39727
39837
|
if (existsSync19(abs)) {
|
|
39728
39838
|
return abs;
|
|
39729
39839
|
}
|
|
@@ -39807,7 +39917,7 @@ var sonarqubeAdapter = {
|
|
|
39807
39917
|
function relativizeComponent(component, cwd) {
|
|
39808
39918
|
const colon = component.indexOf(":");
|
|
39809
39919
|
const value = colon >= 0 ? component.slice(colon + 1) : component;
|
|
39810
|
-
return
|
|
39920
|
+
return path122.isAbsolute(value) ? path122.relative(cwd, value) : value;
|
|
39811
39921
|
}
|
|
39812
39922
|
|
|
39813
39923
|
// src/health/sources/index.ts
|
|
@@ -40168,19 +40278,19 @@ function filteredInfo(source, cfg) {
|
|
|
40168
40278
|
};
|
|
40169
40279
|
}
|
|
40170
40280
|
async function writeOutputs(cwd, report, config, stamp) {
|
|
40171
|
-
const artifacts =
|
|
40172
|
-
const history =
|
|
40281
|
+
const artifacts = path123.join(dataRoot3(cwd), "artifacts");
|
|
40282
|
+
const history = path123.join(dataRoot3(cwd), "history");
|
|
40173
40283
|
await mkdir29(artifacts, { recursive: true });
|
|
40174
40284
|
await mkdir29(history, { recursive: true });
|
|
40175
|
-
const markdown =
|
|
40176
|
-
const json =
|
|
40177
|
-
const historyJson =
|
|
40285
|
+
const markdown = path123.join(artifacts, "latest.md");
|
|
40286
|
+
const json = path123.join(artifacts, "latest.json");
|
|
40287
|
+
const historyJson = path123.join(history, `${stamp}.json`);
|
|
40178
40288
|
const serialized = `${JSON.stringify(report, null, 2)}
|
|
40179
40289
|
`;
|
|
40180
40290
|
await writeFile22(markdown, renderReportMarkdown2(report, config), "utf8");
|
|
40181
40291
|
if (report.runId) {
|
|
40182
|
-
const runJson =
|
|
40183
|
-
const runMarkdown =
|
|
40292
|
+
const runJson = path123.join(artifacts, "runs", `${report.runId}.json`);
|
|
40293
|
+
const runMarkdown = path123.join(artifacts, "runs", `${report.runId}.md`);
|
|
40184
40294
|
if (await pathExists(runJson))
|
|
40185
40295
|
throw new Error(`immutable health run already exists: ${report.runId}`);
|
|
40186
40296
|
await writeFileAtomic(runJson, serialized);
|
|
@@ -40191,7 +40301,7 @@ async function writeOutputs(cwd, report, config, stamp) {
|
|
|
40191
40301
|
branch: report.provenance?.branch ?? null,
|
|
40192
40302
|
worktree: report.provenance?.worktree ?? null,
|
|
40193
40303
|
generated_at: report.generatedAt,
|
|
40194
|
-
record:
|
|
40304
|
+
record: path123.posix.join("runs", `${report.runId}.json`)
|
|
40195
40305
|
}, null, 2)}
|
|
40196
40306
|
`);
|
|
40197
40307
|
} else {
|
|
@@ -40199,8 +40309,8 @@ async function writeOutputs(cwd, report, config, stamp) {
|
|
|
40199
40309
|
}
|
|
40200
40310
|
await writeFile22(historyJson, serialized, "utf8");
|
|
40201
40311
|
return {
|
|
40202
|
-
markdownPath:
|
|
40203
|
-
jsonPath:
|
|
40312
|
+
markdownPath: path123.relative(cwd, markdown),
|
|
40313
|
+
jsonPath: path123.relative(cwd, json)
|
|
40204
40314
|
};
|
|
40205
40315
|
}
|
|
40206
40316
|
async function resolveChanged(cwd, selector) {
|
|
@@ -40253,7 +40363,7 @@ function hasGateShape(value) {
|
|
|
40253
40363
|
return Array.isArray(report.metrics) && Array.isArray(report.sources) && Array.isArray(report.findings);
|
|
40254
40364
|
}
|
|
40255
40365
|
async function readLatest(cwd) {
|
|
40256
|
-
const file =
|
|
40366
|
+
const file = path124.join(dataRoot3(cwd), "artifacts", "latest.json");
|
|
40257
40367
|
if (!await pathExists(file)) {
|
|
40258
40368
|
return null;
|
|
40259
40369
|
}
|
|
@@ -40264,11 +40374,11 @@ async function readLatest(cwd) {
|
|
|
40264
40374
|
const latest = read.value;
|
|
40265
40375
|
const record = latest.record;
|
|
40266
40376
|
if (typeof record === "string") {
|
|
40267
|
-
const pointer = await readArtifactPointer(
|
|
40377
|
+
const pointer = await readArtifactPointer(path124.join(dataRoot3(cwd), "artifacts"), await collectGitProvenance(cwd));
|
|
40268
40378
|
if (pointer.status !== "fresh")
|
|
40269
40379
|
return null;
|
|
40270
|
-
const recordFile =
|
|
40271
|
-
if (!isPathInside(
|
|
40380
|
+
const recordFile = path124.join(dataRoot3(cwd), "artifacts", record);
|
|
40381
|
+
if (!isPathInside(path124.join(dataRoot3(cwd), "artifacts"), recordFile))
|
|
40272
40382
|
return null;
|
|
40273
40383
|
if (!await pathExists(recordFile))
|
|
40274
40384
|
return null;
|
|
@@ -40341,7 +40451,7 @@ function createCodeHealthService() {
|
|
|
40341
40451
|
return {
|
|
40342
40452
|
run: (input) => runHealth(input),
|
|
40343
40453
|
async status(input) {
|
|
40344
|
-
const enabled = await pathExists(
|
|
40454
|
+
const enabled = await pathExists(path124.join(input.cwd, ".metaproject", "health.config.json"));
|
|
40345
40455
|
const latest = await readLatest(input.cwd);
|
|
40346
40456
|
const project = latest?.metrics.find((m) => m.key === "project") ?? null;
|
|
40347
40457
|
const decliningScopes = latest ? latest.metrics.filter((m) => m.regression_score > 0).length : 0;
|
|
@@ -40498,10 +40608,10 @@ function renderEvidenceBlock(evidences, siblings) {
|
|
|
40498
40608
|
init_fs();
|
|
40499
40609
|
init_contained_write();
|
|
40500
40610
|
init_json();
|
|
40501
|
-
import
|
|
40611
|
+
import path125 from "path";
|
|
40502
40612
|
import { createHash as createHash21 } from "crypto";
|
|
40503
40613
|
function impactEvidenceDataRoot(root) {
|
|
40504
|
-
return
|
|
40614
|
+
return path125.join(root, ".metaproject", "data", "security", "impact-evidence");
|
|
40505
40615
|
}
|
|
40506
40616
|
function sanitizeSessionId(sessionId) {
|
|
40507
40617
|
const cleaned = sessionId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
@@ -40513,7 +40623,7 @@ function sessionStateFilename(sessionId) {
|
|
|
40513
40623
|
return `${sanitized}-${suffix}.json`;
|
|
40514
40624
|
}
|
|
40515
40625
|
function sessionStatePath(root, sessionId) {
|
|
40516
|
-
return
|
|
40626
|
+
return path125.join(impactEvidenceDataRoot(root), "sessions", sessionStateFilename(sessionId));
|
|
40517
40627
|
}
|
|
40518
40628
|
async function loadSessionState(root, sessionId) {
|
|
40519
40629
|
const file = sessionStatePath(root, sessionId);
|
|
@@ -40532,11 +40642,11 @@ async function loadSessionState(root, sessionId) {
|
|
|
40532
40642
|
}
|
|
40533
40643
|
async function saveSessionState(root, sessionId, state) {
|
|
40534
40644
|
const file = sessionStatePath(root, sessionId);
|
|
40535
|
-
await writeContained(root,
|
|
40645
|
+
await writeContained(root, path125.relative(root, file), `${JSON.stringify(state, null, 2)}
|
|
40536
40646
|
`);
|
|
40537
40647
|
}
|
|
40538
40648
|
function logPath(root) {
|
|
40539
|
-
return
|
|
40649
|
+
return path125.join(impactEvidenceDataRoot(root), "log.jsonl");
|
|
40540
40650
|
}
|
|
40541
40651
|
async function appendLogRecord(root, record) {
|
|
40542
40652
|
const full = {
|
|
@@ -40547,7 +40657,7 @@ async function appendLogRecord(root, record) {
|
|
|
40547
40657
|
...record.detail !== undefined ? { detail: record.detail } : {}
|
|
40548
40658
|
};
|
|
40549
40659
|
const file = logPath(root);
|
|
40550
|
-
await appendContained(root,
|
|
40660
|
+
await appendContained(root, path125.relative(root, file), `${JSON.stringify(full)}
|
|
40551
40661
|
`);
|
|
40552
40662
|
return full;
|
|
40553
40663
|
}
|
|
@@ -40574,7 +40684,7 @@ init_command_risk();
|
|
|
40574
40684
|
init_shell_syntax();
|
|
40575
40685
|
init_fs();
|
|
40576
40686
|
init_service2();
|
|
40577
|
-
import
|
|
40687
|
+
import path126 from "path";
|
|
40578
40688
|
import { createHash as createHash22 } from "crypto";
|
|
40579
40689
|
import { realpathSync as realpathSync2 } from "fs";
|
|
40580
40690
|
function impactEvidenceHookClass(strict) {
|
|
@@ -40590,29 +40700,29 @@ function realpathNearestExisting(p) {
|
|
|
40590
40700
|
for (;; ) {
|
|
40591
40701
|
try {
|
|
40592
40702
|
const real = realpathSync2(current);
|
|
40593
|
-
return tail.length > 0 ?
|
|
40703
|
+
return tail.length > 0 ? path126.join(real, ...tail) : real;
|
|
40594
40704
|
} catch {
|
|
40595
|
-
const parent =
|
|
40705
|
+
const parent = path126.dirname(current);
|
|
40596
40706
|
if (parent === current) {
|
|
40597
|
-
return tail.length > 0 ?
|
|
40707
|
+
return tail.length > 0 ? path126.join(current, ...tail) : current;
|
|
40598
40708
|
}
|
|
40599
|
-
tail.unshift(
|
|
40709
|
+
tail.unshift(path126.basename(current));
|
|
40600
40710
|
current = parent;
|
|
40601
40711
|
}
|
|
40602
40712
|
}
|
|
40603
40713
|
}
|
|
40604
40714
|
function normalizeRequestFiles(root, files) {
|
|
40605
|
-
const rootReal = realpathNearestExisting(
|
|
40715
|
+
const rootReal = realpathNearestExisting(path126.resolve(root));
|
|
40606
40716
|
const normalized = [];
|
|
40607
40717
|
const rejected = [];
|
|
40608
40718
|
for (const file of files) {
|
|
40609
|
-
const lexicalAbsolute =
|
|
40719
|
+
const lexicalAbsolute = path126.isAbsolute(file) ? path126.resolve(file) : path126.resolve(rootReal, toPosix(file).replace(/^\.\//, ""));
|
|
40610
40720
|
const effective = realpathNearestExisting(lexicalAbsolute);
|
|
40611
40721
|
if (!isPathInside(rootReal, effective)) {
|
|
40612
40722
|
rejected.push(file);
|
|
40613
40723
|
continue;
|
|
40614
40724
|
}
|
|
40615
|
-
normalized.push(toPosix(
|
|
40725
|
+
normalized.push(toPosix(path126.relative(rootReal, effective)));
|
|
40616
40726
|
}
|
|
40617
40727
|
return { files: [...new Set(normalized)], rejected };
|
|
40618
40728
|
}
|
|
@@ -40894,7 +41004,7 @@ function hostDeliveryStatus() {
|
|
|
40894
41004
|
// src/job/service.ts
|
|
40895
41005
|
init_fs();
|
|
40896
41006
|
import { copyFile, mkdir as mkdir31 } from "fs/promises";
|
|
40897
|
-
import
|
|
41007
|
+
import path129 from "path";
|
|
40898
41008
|
|
|
40899
41009
|
// src/job/types.ts
|
|
40900
41010
|
var JOB_INTENTS = ["implement", "analyze", "review", "custom"];
|
|
@@ -41035,15 +41145,15 @@ init_validator();
|
|
|
41035
41145
|
init_contracts();
|
|
41036
41146
|
init_fs();
|
|
41037
41147
|
import { appendFile as appendFile6, mkdir as mkdir30, readFile as readFile63, readdir as readdir21 } from "fs/promises";
|
|
41038
|
-
import
|
|
41148
|
+
import path128 from "path";
|
|
41039
41149
|
function jobsRoot(cwd) {
|
|
41040
|
-
return
|
|
41150
|
+
return path128.join(cwd, ".metaproject", "jobs");
|
|
41041
41151
|
}
|
|
41042
41152
|
function jobDir(cwd, name) {
|
|
41043
|
-
return
|
|
41153
|
+
return path128.join(jobsRoot(cwd), name);
|
|
41044
41154
|
}
|
|
41045
41155
|
function jobStatePath(cwd, name) {
|
|
41046
|
-
return
|
|
41156
|
+
return path128.join(jobDir(cwd, name), "state.json");
|
|
41047
41157
|
}
|
|
41048
41158
|
var JOB_NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
41049
41159
|
function assertJobName(name) {
|
|
@@ -41080,12 +41190,12 @@ async function writeJob(cwd, name, state) {
|
|
|
41080
41190
|
`));
|
|
41081
41191
|
}
|
|
41082
41192
|
const file = jobStatePath(cwd, name);
|
|
41083
|
-
await mkdir30(
|
|
41193
|
+
await mkdir30(path128.dirname(file), { recursive: true });
|
|
41084
41194
|
await writeFileAtomic(file, `${JSON.stringify(state, null, 2)}
|
|
41085
41195
|
`);
|
|
41086
41196
|
}
|
|
41087
41197
|
async function appendJournal2(cwd, name, at, line) {
|
|
41088
|
-
await appendFile6(
|
|
41198
|
+
await appendFile6(path128.join(jobDir(cwd, name), "journal.md"), `- ${at} - ${line}
|
|
41089
41199
|
`, "utf8");
|
|
41090
41200
|
}
|
|
41091
41201
|
function renderJournal2(name, at) {
|
|
@@ -41106,7 +41216,7 @@ function assertDocumentType(raw) {
|
|
|
41106
41216
|
return raw;
|
|
41107
41217
|
}
|
|
41108
41218
|
function documentFileName(type, sourcePath) {
|
|
41109
|
-
const extension =
|
|
41219
|
+
const extension = path128.extname(sourcePath) || ".md";
|
|
41110
41220
|
return `${type}${extension}`;
|
|
41111
41221
|
}
|
|
41112
41222
|
|
|
@@ -41114,7 +41224,7 @@ function documentFileName(type, sourcePath) {
|
|
|
41114
41224
|
function createJobService(deps) {
|
|
41115
41225
|
const now = () => deps.now().toISOString();
|
|
41116
41226
|
function lockPath(cwd, name) {
|
|
41117
|
-
return
|
|
41227
|
+
return path129.join(jobsRoot(cwd), `.job-lock-${name}`);
|
|
41118
41228
|
}
|
|
41119
41229
|
async function mutate(cwd, name, run) {
|
|
41120
41230
|
assertJobName(name);
|
|
@@ -41163,20 +41273,20 @@ function createJobService(deps) {
|
|
|
41163
41273
|
},
|
|
41164
41274
|
plan: { steps: defaultPlan(intent) },
|
|
41165
41275
|
documentation: {
|
|
41166
|
-
job_path:
|
|
41276
|
+
job_path: path129.join(".metaproject", "jobs", name),
|
|
41167
41277
|
documents_created: []
|
|
41168
41278
|
},
|
|
41169
41279
|
metrics: { steps: [] },
|
|
41170
|
-
jobs_root:
|
|
41280
|
+
jobs_root: path129.join(".metaproject", "jobs"),
|
|
41171
41281
|
updated_at: createdAt
|
|
41172
41282
|
};
|
|
41173
41283
|
const first = firstOpenStep(state.plan.steps);
|
|
41174
41284
|
if (first) {
|
|
41175
41285
|
state.plan.current_step = first.id;
|
|
41176
41286
|
}
|
|
41177
|
-
await writeFileAtomic(
|
|
41287
|
+
await writeFileAtomic(path129.join(absolute, "journal.md"), renderJournal2(name, createdAt));
|
|
41178
41288
|
await writeJob(input.cwd, name, state);
|
|
41179
|
-
return { state, dir:
|
|
41289
|
+
return { state, dir: path129.relative(input.cwd, absolute) };
|
|
41180
41290
|
},
|
|
41181
41291
|
async status({ cwd, name }) {
|
|
41182
41292
|
assertJobName(name);
|
|
@@ -41188,7 +41298,7 @@ function createJobService(deps) {
|
|
|
41188
41298
|
}
|
|
41189
41299
|
return {
|
|
41190
41300
|
state,
|
|
41191
|
-
dir:
|
|
41301
|
+
dir: path129.join(".metaproject", "jobs", name),
|
|
41192
41302
|
stepsDone: state.plan.steps.filter((step) => isTerminalStep(step.status)).length,
|
|
41193
41303
|
stepsTotal: state.plan.steps.length,
|
|
41194
41304
|
nextStep: firstOpenStep(state.plan.steps),
|
|
@@ -41245,23 +41355,23 @@ function createJobService(deps) {
|
|
|
41245
41355
|
if (!input.file) {
|
|
41246
41356
|
throw new Error("Missing --file. Usage: keryx job document <name> --type <type> --file <path>");
|
|
41247
41357
|
}
|
|
41248
|
-
const source =
|
|
41358
|
+
const source = path129.isAbsolute(input.file) ? input.file : path129.join(input.cwd, input.file);
|
|
41249
41359
|
if (!await pathExists(source)) {
|
|
41250
41360
|
throw new Error(`--file not found: ${input.file}. Write the document first, then record it.`);
|
|
41251
41361
|
}
|
|
41252
41362
|
let recorded;
|
|
41253
41363
|
await mutate(input.cwd, input.name, async (state) => {
|
|
41254
41364
|
const fileName = documentFileName(type, source);
|
|
41255
|
-
const target =
|
|
41365
|
+
const target = path129.join(jobDir(input.cwd, state.job_name), fileName);
|
|
41256
41366
|
await copyFile(source, target);
|
|
41257
41367
|
state.documentation ??= {};
|
|
41258
|
-
state.documentation.job_path ??=
|
|
41368
|
+
state.documentation.job_path ??= path129.join(".metaproject", "jobs", state.job_name);
|
|
41259
41369
|
const created = state.documentation.documents_created ?? [];
|
|
41260
41370
|
state.documentation.documents_created = created.includes(fileName) ? created : [...created, fileName];
|
|
41261
41371
|
recorded = {
|
|
41262
41372
|
state,
|
|
41263
41373
|
document: fileName,
|
|
41264
|
-
path:
|
|
41374
|
+
path: path129.join(".metaproject", "jobs", state.job_name, fileName)
|
|
41265
41375
|
};
|
|
41266
41376
|
return { state, event: "document", detail: `${type} -> ${fileName}` };
|
|
41267
41377
|
});
|
|
@@ -41296,7 +41406,7 @@ function createJobService(deps) {
|
|
|
41296
41406
|
name: state.job_name,
|
|
41297
41407
|
phase: state.phase,
|
|
41298
41408
|
intent: state.intent,
|
|
41299
|
-
dir:
|
|
41409
|
+
dir: path129.join(".metaproject", "jobs", name),
|
|
41300
41410
|
stepsDone: state.plan.steps.filter((step) => isTerminalStep(step.status)).length,
|
|
41301
41411
|
stepsTotal: state.plan.steps.length,
|
|
41302
41412
|
nextStep: firstOpenStep(state.plan.steps)?.id ?? null
|
|
@@ -41317,12 +41427,12 @@ init_fs();
|
|
|
41317
41427
|
init_preservation();
|
|
41318
41428
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
41319
41429
|
import { lstat as lstat9, readdir as readdir26 } from "fs/promises";
|
|
41320
|
-
import
|
|
41430
|
+
import path143 from "path";
|
|
41321
41431
|
|
|
41322
41432
|
// src/session/paths.ts
|
|
41323
41433
|
import { existsSync as existsSync21 } from "fs";
|
|
41324
41434
|
import { homedir as homedir2 } from "os";
|
|
41325
|
-
import
|
|
41435
|
+
import path131 from "path";
|
|
41326
41436
|
function keryxDataDir(override) {
|
|
41327
41437
|
if (override !== undefined && override.length > 0) {
|
|
41328
41438
|
return override;
|
|
@@ -41334,22 +41444,22 @@ function keryxDataDir(override) {
|
|
|
41334
41444
|
const home = homedir2();
|
|
41335
41445
|
if (process.platform === "win32") {
|
|
41336
41446
|
const appData = process.env.APPDATA;
|
|
41337
|
-
const base = appData !== undefined && appData.length > 0 ? appData :
|
|
41338
|
-
return
|
|
41447
|
+
const base = appData !== undefined && appData.length > 0 ? appData : path131.join(home, "AppData", "Roaming");
|
|
41448
|
+
return path131.join(base, "keryx");
|
|
41339
41449
|
}
|
|
41340
41450
|
const xdg = process.env.XDG_DATA_HOME;
|
|
41341
|
-
const base = xdg !== undefined && xdg.length > 0 ? xdg :
|
|
41342
|
-
return
|
|
41451
|
+
const base = xdg !== undefined && xdg.length > 0 ? xdg : path131.join(home, ".local", "share");
|
|
41452
|
+
return path131.join(base, "keryx");
|
|
41343
41453
|
}
|
|
41344
41454
|
function resolveProjectRoot2(cwd) {
|
|
41345
|
-
const abs =
|
|
41455
|
+
const abs = path131.resolve(cwd);
|
|
41346
41456
|
let dir = abs;
|
|
41347
41457
|
for (;; ) {
|
|
41348
|
-
const gitPath =
|
|
41458
|
+
const gitPath = path131.join(dir, ".git");
|
|
41349
41459
|
if (existsSync21(gitPath)) {
|
|
41350
41460
|
return dir;
|
|
41351
41461
|
}
|
|
41352
|
-
const parent =
|
|
41462
|
+
const parent = path131.dirname(dir);
|
|
41353
41463
|
if (parent === dir) {
|
|
41354
41464
|
break;
|
|
41355
41465
|
}
|
|
@@ -41358,12 +41468,12 @@ function resolveProjectRoot2(cwd) {
|
|
|
41358
41468
|
return abs;
|
|
41359
41469
|
}
|
|
41360
41470
|
function projectKeyFromPath(projectPath) {
|
|
41361
|
-
const abs =
|
|
41471
|
+
const abs = path131.resolve(projectPath);
|
|
41362
41472
|
const encoded = encodeURIComponent(abs);
|
|
41363
41473
|
if (encoded.length <= 200) {
|
|
41364
41474
|
return encoded;
|
|
41365
41475
|
}
|
|
41366
|
-
const base =
|
|
41476
|
+
const base = path131.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40);
|
|
41367
41477
|
let h = 0;
|
|
41368
41478
|
for (let i = 0;i < abs.length; i++) {
|
|
41369
41479
|
h = Math.imul(31, h) + abs.charCodeAt(i) | 0;
|
|
@@ -41373,22 +41483,22 @@ function projectKeyFromPath(projectPath) {
|
|
|
41373
41483
|
}
|
|
41374
41484
|
function projectSessionsDir(projectPath, dataDir) {
|
|
41375
41485
|
const key = projectKeyFromPath(resolveProjectRoot2(projectPath));
|
|
41376
|
-
return
|
|
41486
|
+
return path131.join(keryxDataDir(dataDir), "sessions", key);
|
|
41377
41487
|
}
|
|
41378
41488
|
function sessionDir(projectPath, sessionId, dataDir) {
|
|
41379
|
-
return
|
|
41489
|
+
return path131.join(projectSessionsDir(projectPath, dataDir), sessionId);
|
|
41380
41490
|
}
|
|
41381
41491
|
|
|
41382
41492
|
// src/sac/proposal-lifecycle.ts
|
|
41383
41493
|
init_fs();
|
|
41384
41494
|
import { createHash as createHash32, randomUUID as randomUUID7 } from "crypto";
|
|
41385
41495
|
import { appendFile as appendFile7, mkdir as mkdir35, readdir as readdir25, readFile as readFile73 } from "fs/promises";
|
|
41386
|
-
import
|
|
41496
|
+
import path142 from "path";
|
|
41387
41497
|
|
|
41388
41498
|
// src/sac/index.ts
|
|
41389
41499
|
import { access as access3, readFile as readFile64, realpath as realpath14 } from "fs/promises";
|
|
41390
41500
|
import { createHash as createHash24 } from "crypto";
|
|
41391
|
-
import
|
|
41501
|
+
import path132 from "path";
|
|
41392
41502
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
41393
41503
|
|
|
41394
41504
|
// src/sac/workspace-reference.ts
|
|
@@ -41448,21 +41558,21 @@ var normativeSchemaFiles = {
|
|
|
41448
41558
|
"review-decision": "review-decision.schema.json"
|
|
41449
41559
|
};
|
|
41450
41560
|
var normativeSchemas = new Map;
|
|
41451
|
-
var NORMATIVE_SCHEMA_DIR =
|
|
41561
|
+
var NORMATIVE_SCHEMA_DIR = path132.join("docs", "requirements", "shared-agent-context", "schemas");
|
|
41452
41562
|
async function resolveSacNormativeSchemaPath(fileName, searchFrom = [fileURLToPath3(new URL(".", import.meta.url)), process.cwd()]) {
|
|
41453
41563
|
const seen = new Set;
|
|
41454
41564
|
for (const start of searchFrom) {
|
|
41455
|
-
let dir =
|
|
41565
|
+
let dir = path132.resolve(start);
|
|
41456
41566
|
for (let i = 0;i < 10; i++) {
|
|
41457
41567
|
if (seen.has(dir))
|
|
41458
41568
|
break;
|
|
41459
41569
|
seen.add(dir);
|
|
41460
|
-
const candidate =
|
|
41570
|
+
const candidate = path132.join(dir, NORMATIVE_SCHEMA_DIR, fileName);
|
|
41461
41571
|
try {
|
|
41462
41572
|
await access3(candidate);
|
|
41463
41573
|
return candidate;
|
|
41464
41574
|
} catch {}
|
|
41465
|
-
const parent =
|
|
41575
|
+
const parent = path132.dirname(dir);
|
|
41466
41576
|
if (parent === dir)
|
|
41467
41577
|
break;
|
|
41468
41578
|
dir = parent;
|
|
@@ -42131,12 +42241,12 @@ class SacReferenceError extends Error {
|
|
|
42131
42241
|
code = "unsafe_workspace_reference";
|
|
42132
42242
|
}
|
|
42133
42243
|
async function resolveWorkspaceReference(input) {
|
|
42134
|
-
if (!workspacePathPattern.test(input.uri) ||
|
|
42244
|
+
if (!workspacePathPattern.test(input.uri) || path132.isAbsolute(input.uri) || /^[a-z][a-z0-9+.-]*:/i.test(input.uri) || input.uri.includes("\\"))
|
|
42135
42245
|
throw new SacReferenceError("unsafe workspace reference");
|
|
42136
|
-
const lexicalRoot =
|
|
42246
|
+
const lexicalRoot = path132.resolve(input.workspaceRoot);
|
|
42137
42247
|
const root = await realpath14(lexicalRoot);
|
|
42138
|
-
const candidate =
|
|
42139
|
-
if (candidate !== lexicalRoot && !candidate.startsWith(`${lexicalRoot}${
|
|
42248
|
+
const candidate = path132.resolve(lexicalRoot, input.uri.slice(2));
|
|
42249
|
+
if (candidate !== lexicalRoot && !candidate.startsWith(`${lexicalRoot}${path132.sep}`))
|
|
42140
42250
|
throw new SacReferenceError("workspace reference escapes root");
|
|
42141
42251
|
let resolved;
|
|
42142
42252
|
try {
|
|
@@ -42144,7 +42254,7 @@ async function resolveWorkspaceReference(input) {
|
|
|
42144
42254
|
} catch {
|
|
42145
42255
|
throw new SacReferenceError("workspace reference is not resolvable");
|
|
42146
42256
|
}
|
|
42147
|
-
if (resolved !== root && !resolved.startsWith(`${root}${
|
|
42257
|
+
if (resolved !== root && !resolved.startsWith(`${root}${path132.sep}`))
|
|
42148
42258
|
throw new SacReferenceError("workspace reference escapes root after realpath");
|
|
42149
42259
|
return candidate;
|
|
42150
42260
|
}
|
|
@@ -42200,16 +42310,16 @@ async function evaluateStrictSacGuard(input) {
|
|
|
42200
42310
|
init_fs();
|
|
42201
42311
|
import { mkdir as mkdir32, readdir as readdir22, readFile as readFile65 } from "fs/promises";
|
|
42202
42312
|
import { createHash as createHash25, randomUUID as randomUUID4 } from "crypto";
|
|
42203
|
-
import
|
|
42313
|
+
import path134 from "path";
|
|
42204
42314
|
|
|
42205
42315
|
// src/sac/secure-resource-read.ts
|
|
42206
42316
|
init_contained_read();
|
|
42207
42317
|
init_descriptor_read();
|
|
42208
|
-
import
|
|
42318
|
+
import path133 from "path";
|
|
42209
42319
|
function readWorkspaceFileNoFollow(workspaceRoot, absolutePath) {
|
|
42210
|
-
const relativePath =
|
|
42211
|
-
const components = relativePath.split(
|
|
42212
|
-
if (!relativePath ||
|
|
42320
|
+
const relativePath = path133.relative(workspaceRoot, absolutePath);
|
|
42321
|
+
const components = relativePath.split(path133.sep);
|
|
42322
|
+
if (!relativePath || path133.isAbsolute(relativePath) || components.some((component) => !component || component === "." || component === "..")) {
|
|
42213
42323
|
throw new Error("safe source path is not workspace-relative");
|
|
42214
42324
|
}
|
|
42215
42325
|
return readDescriptorChain(workspaceRoot, absolutePath, {
|
|
@@ -42236,8 +42346,8 @@ class WorkspaceService {
|
|
|
42236
42346
|
now;
|
|
42237
42347
|
constructor(options) {
|
|
42238
42348
|
this.options = options;
|
|
42239
|
-
this.root =
|
|
42240
|
-
this.storageRoot =
|
|
42349
|
+
this.root = path134.resolve(options.workspaceRoot);
|
|
42350
|
+
this.storageRoot = path134.resolve(options.storageRoot ?? path134.join(this.root, ".metaproject", "workspaces"));
|
|
42241
42351
|
this.now = options.now ?? (() => new Date);
|
|
42242
42352
|
}
|
|
42243
42353
|
async create(input) {
|
|
@@ -42563,13 +42673,13 @@ class WorkspaceService {
|
|
|
42563
42673
|
return parsed;
|
|
42564
42674
|
}
|
|
42565
42675
|
workspaceDir(id) {
|
|
42566
|
-
return
|
|
42676
|
+
return path134.join(this.storageRoot, id);
|
|
42567
42677
|
}
|
|
42568
42678
|
manifestPath(id) {
|
|
42569
|
-
return
|
|
42679
|
+
return path134.join(this.workspaceDir(id), "workspace.json");
|
|
42570
42680
|
}
|
|
42571
42681
|
lockPath(id) {
|
|
42572
|
-
return
|
|
42682
|
+
return path134.join(this.storageRoot, `.${id}.lock`);
|
|
42573
42683
|
}
|
|
42574
42684
|
timestamp() {
|
|
42575
42685
|
return this.now().toISOString();
|
|
@@ -42685,7 +42795,7 @@ function bindingHash(owner, intent) {
|
|
|
42685
42795
|
// src/sac/session-wrap-up.ts
|
|
42686
42796
|
import { createHash as createHash28 } from "crypto";
|
|
42687
42797
|
import { mkdir as mkdir34, writeFile as writeFile23 } from "fs/promises";
|
|
42688
|
-
import
|
|
42798
|
+
import path137 from "path";
|
|
42689
42799
|
|
|
42690
42800
|
// src/session/store.ts
|
|
42691
42801
|
init_preservation();
|
|
@@ -42698,7 +42808,7 @@ import {
|
|
|
42698
42808
|
renameSync as renameSync5,
|
|
42699
42809
|
writeFileSync as writeFileSync4
|
|
42700
42810
|
} from "fs";
|
|
42701
|
-
import
|
|
42811
|
+
import path136 from "path";
|
|
42702
42812
|
init_slate();
|
|
42703
42813
|
init_redact();
|
|
42704
42814
|
var SESSION_SCHEMA_VERSION = 1;
|
|
@@ -42791,7 +42901,7 @@ function parseRemote(value) {
|
|
|
42791
42901
|
function readSummaryFile(file) {
|
|
42792
42902
|
let pending;
|
|
42793
42903
|
try {
|
|
42794
|
-
pending = readPendingHistory(
|
|
42904
|
+
pending = readPendingHistory(path136.dirname(file));
|
|
42795
42905
|
} catch {
|
|
42796
42906
|
pending = undefined;
|
|
42797
42907
|
}
|
|
@@ -42843,11 +42953,11 @@ class TranscriptUnreadableError extends Error {
|
|
|
42843
42953
|
}
|
|
42844
42954
|
}
|
|
42845
42955
|
function readJsonl2(file) {
|
|
42846
|
-
const pending = readPendingHistory(
|
|
42956
|
+
const pending = readPendingHistory(path136.dirname(file));
|
|
42847
42957
|
if (pending === undefined && !existsSync22(file)) {
|
|
42848
42958
|
return [];
|
|
42849
42959
|
}
|
|
42850
|
-
const read = pending !== undefined ? { ok: true, text: pending.files[
|
|
42960
|
+
const read = pending !== undefined ? { ok: true, text: pending.files[path136.basename(file)] } : readTranscriptFile(file);
|
|
42851
42961
|
if (!read.ok) {
|
|
42852
42962
|
throw new TranscriptUnreadableError(file, read.reason);
|
|
42853
42963
|
}
|
|
@@ -42898,11 +43008,11 @@ function listSessions(cwd, dataDir) {
|
|
|
42898
43008
|
if (name.startsWith(".")) {
|
|
42899
43009
|
continue;
|
|
42900
43010
|
}
|
|
42901
|
-
const summary = readSummaryFile(
|
|
43011
|
+
const summary = readSummaryFile(path136.join(root, name, "summary.json"));
|
|
42902
43012
|
if (summary === undefined) {
|
|
42903
43013
|
continue;
|
|
42904
43014
|
}
|
|
42905
|
-
if (
|
|
43015
|
+
if (path136.resolve(summary.projectPath) !== path136.resolve(projectPath)) {
|
|
42906
43016
|
continue;
|
|
42907
43017
|
}
|
|
42908
43018
|
out.push(summary);
|
|
@@ -42935,15 +43045,15 @@ async function readSessionSlate(cwd, sessionId, dataDir) {
|
|
|
42935
43045
|
}
|
|
42936
43046
|
function loadContext(cwd, sessionId, dataDir) {
|
|
42937
43047
|
const dir = sessionDir(resolveProjectRoot2(cwd), sessionId, dataDir);
|
|
42938
|
-
const contextPath =
|
|
43048
|
+
const contextPath = path136.join(dir, "context.jsonl");
|
|
42939
43049
|
if (readPendingHistory(dir) !== undefined || existsSync22(contextPath)) {
|
|
42940
43050
|
return readJsonl2(contextPath);
|
|
42941
43051
|
}
|
|
42942
|
-
return readJsonl2(
|
|
43052
|
+
return readJsonl2(path136.join(dir, "transcript.jsonl"));
|
|
42943
43053
|
}
|
|
42944
43054
|
function loadArchive(cwd, sessionId, dataDir, onDegraded) {
|
|
42945
43055
|
const dir = sessionDir(resolveProjectRoot2(cwd), sessionId, dataDir);
|
|
42946
|
-
const archivePath =
|
|
43056
|
+
const archivePath = path136.join(dir, "archive.jsonl");
|
|
42947
43057
|
if (readPendingHistory(dir) !== undefined || existsSync22(archivePath)) {
|
|
42948
43058
|
try {
|
|
42949
43059
|
const archive = readJsonl2(archivePath);
|
|
@@ -43018,7 +43128,7 @@ function sessionEvidenceRef(workspaceId, sessionId) {
|
|
|
43018
43128
|
}
|
|
43019
43129
|
async function resolveSessionWrapUp(input) {
|
|
43020
43130
|
const now = input.now ?? (() => new Date);
|
|
43021
|
-
const sessionId =
|
|
43131
|
+
const sessionId = path137.posix.basename(input.sourceRef, ".md");
|
|
43022
43132
|
const summary = findSession(input.cwd, sessionId);
|
|
43023
43133
|
if (summary === undefined || input.sourceRef !== sessionEvidenceRef(input.workspaceId, summary.id)) {
|
|
43024
43134
|
throw new SessionWrapUpError("session_not_found", `no session matching "${input.sourceRef}" in this project \u2014 use \`keryx sessions list\``);
|
|
@@ -43035,7 +43145,7 @@ async function resolveSessionWrapUp(input) {
|
|
|
43035
43145
|
throw new SessionWrapUpError("session_unreadable", `session "${summary.id}" could not be read: ${cause.message}`);
|
|
43036
43146
|
}
|
|
43037
43147
|
const relPath = sessionEvidenceRef(input.workspaceId, summary.id).slice(2);
|
|
43038
|
-
const evidenceDir =
|
|
43148
|
+
const evidenceDir = path137.dirname(relPath);
|
|
43039
43149
|
const slate = await readSessionSlate(input.cwd, summary.id);
|
|
43040
43150
|
const diff = await gitDiff(input.cwd);
|
|
43041
43151
|
const diffBody = diff.kind === "measured" ? diff.text : unmeasurableDiffBody(diff.detail);
|
|
@@ -43057,23 +43167,23 @@ async function resolveSessionWrapUp(input) {
|
|
|
43057
43167
|
""
|
|
43058
43168
|
].join(`
|
|
43059
43169
|
`);
|
|
43060
|
-
const wrapUpRelPath =
|
|
43061
|
-
const diffRelPath =
|
|
43062
|
-
const noticeRelPath =
|
|
43170
|
+
const wrapUpRelPath = path137.join(evidenceDir, `${summary.id}.wrap-up.md`);
|
|
43171
|
+
const diffRelPath = path137.join(evidenceDir, `${summary.id}.diff.txt`);
|
|
43172
|
+
const noticeRelPath = path137.join(evidenceDir, `${summary.id}.redaction.md`);
|
|
43063
43173
|
const floor = await applyEvidenceRedactionFloor(input.cwd, [
|
|
43064
|
-
{ name:
|
|
43065
|
-
{ name:
|
|
43066
|
-
{ name:
|
|
43174
|
+
{ name: path137.basename(relPath), content: markdown, path: relPath, source: "generated" },
|
|
43175
|
+
{ name: path137.basename(wrapUpRelPath), content: wrapUpMarkdown, path: wrapUpRelPath, source: "generated" },
|
|
43176
|
+
{ name: path137.basename(diffRelPath), content: diffBody, path: diffRelPath, source: "tool-output" }
|
|
43067
43177
|
]);
|
|
43068
43178
|
if (!floor.ok)
|
|
43069
43179
|
throw new SessionWrapUpError("security_denied", floor.reason);
|
|
43070
43180
|
const [safeSession, safeWrapUp, safeDiff] = floor.bodies;
|
|
43071
|
-
await mkdir34(
|
|
43072
|
-
await writeFile23(
|
|
43073
|
-
await writeFile23(
|
|
43074
|
-
await writeFile23(
|
|
43181
|
+
await mkdir34(path137.join(input.cwd, evidenceDir), { recursive: true });
|
|
43182
|
+
await writeFile23(path137.join(input.cwd, relPath), safeSession.content, "utf8");
|
|
43183
|
+
await writeFile23(path137.join(input.cwd, wrapUpRelPath), safeWrapUp.content, "utf8");
|
|
43184
|
+
await writeFile23(path137.join(input.cwd, diffRelPath), safeDiff.content, "utf8");
|
|
43075
43185
|
if (floor.notice !== undefined)
|
|
43076
|
-
await writeFile23(
|
|
43186
|
+
await writeFile23(path137.join(input.cwd, noticeRelPath), floor.notice, "utf8");
|
|
43077
43187
|
const observedAt = now().toISOString();
|
|
43078
43188
|
const evidence = [
|
|
43079
43189
|
{ kind: "wrap-up", uri: `./${wrapUpRelPath}`, revision: createHash28("sha256").update(safeWrapUp.content).digest("hex"), observedAt },
|
|
@@ -43096,13 +43206,13 @@ async function resolveSessionWrapUp(input) {
|
|
|
43096
43206
|
init_fs();
|
|
43097
43207
|
import { createHash as createHash29, randomBytes as randomBytes6 } from "crypto";
|
|
43098
43208
|
import { readFile as readFile67 } from "fs/promises";
|
|
43099
|
-
import
|
|
43209
|
+
import path138 from "path";
|
|
43100
43210
|
var CONFIRM_TOKEN_TTL_MS = 2 * 60000;
|
|
43101
43211
|
function confirmTokenPath2(cwd, workspaceId, proposalId) {
|
|
43102
|
-
return
|
|
43212
|
+
return path138.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.confirm-token.json`);
|
|
43103
43213
|
}
|
|
43104
43214
|
function confirmReceiptPath(cwd, workspaceId, proposalId, idempotencyKey) {
|
|
43105
|
-
return
|
|
43215
|
+
return path138.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${sha2563(idempotencyKey)}.confirm-receipt.json`);
|
|
43106
43216
|
}
|
|
43107
43217
|
function sha2563(text) {
|
|
43108
43218
|
return createHash29("sha256").update(text).digest("hex");
|
|
@@ -43143,21 +43253,21 @@ init_store();
|
|
|
43143
43253
|
init_config2();
|
|
43144
43254
|
import { readFile as readFile69, readdir as readdir24 } from "fs/promises";
|
|
43145
43255
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
43146
|
-
import
|
|
43256
|
+
import path140 from "path";
|
|
43147
43257
|
|
|
43148
43258
|
// src/sac/proposal-evidence.ts
|
|
43149
43259
|
init_fs();
|
|
43150
43260
|
import { createHash as createHash30 } from "crypto";
|
|
43151
43261
|
import { readFile as readFile68, rm as rm7 } from "fs/promises";
|
|
43152
|
-
import
|
|
43262
|
+
import path139 from "path";
|
|
43153
43263
|
function proposalPath(cwd, workspaceId, proposalId) {
|
|
43154
|
-
return
|
|
43264
|
+
return path139.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
|
|
43155
43265
|
}
|
|
43156
43266
|
function ownerReceiptPath(cwd, owner, workspaceId, idempotencyKey) {
|
|
43157
|
-
return
|
|
43267
|
+
return path139.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-receipts`, `${idempotencyKey}.json`);
|
|
43158
43268
|
}
|
|
43159
43269
|
function proposalNotePath(cwd, workspaceId, proposalId) {
|
|
43160
|
-
return
|
|
43270
|
+
return path139.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.note.txt`);
|
|
43161
43271
|
}
|
|
43162
43272
|
async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
|
|
43163
43273
|
let proposal;
|
|
@@ -43171,7 +43281,7 @@ async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
|
|
|
43171
43281
|
return { ok: false, code: "no_evidence_to_write" };
|
|
43172
43282
|
let content;
|
|
43173
43283
|
try {
|
|
43174
|
-
content = await readFile68(
|
|
43284
|
+
content = await readFile68(path139.join(cwd, evidence.uri), "utf8");
|
|
43175
43285
|
} catch {
|
|
43176
43286
|
return { ok: false, code: "evidence_file_unreadable" };
|
|
43177
43287
|
}
|
|
@@ -43201,22 +43311,22 @@ function targetRelPath(targetRef) {
|
|
|
43201
43311
|
return targetRef.replace(/^\.\//, "");
|
|
43202
43312
|
}
|
|
43203
43313
|
function targetAbsolutePath(cwd, targetRef) {
|
|
43204
|
-
return
|
|
43314
|
+
return path139.join(cwd, ".metaproject", targetRelPath(targetRef));
|
|
43205
43315
|
}
|
|
43206
43316
|
function targetKey(targetRef) {
|
|
43207
43317
|
return digestOf2(targetRelPath(targetRef)).slice(0, 32);
|
|
43208
43318
|
}
|
|
43209
43319
|
function ownerTargetVersionPath(cwd, owner, workspaceId, targetRef) {
|
|
43210
|
-
return
|
|
43320
|
+
return path139.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-target-versions`, `${targetKey(targetRef)}.json`);
|
|
43211
43321
|
}
|
|
43212
43322
|
function ownerTargetLockPath(cwd, owner, targetRef) {
|
|
43213
|
-
return
|
|
43323
|
+
return path139.join(cwd, ".metaproject", "data", "sac", "target-locks", owner, `${targetKey(targetRef)}.lock`);
|
|
43214
43324
|
}
|
|
43215
43325
|
function ownerStagingDir(cwd, owner, workspaceId, idempotencyKey) {
|
|
43216
|
-
return
|
|
43326
|
+
return path139.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-staging`, digestOf2(idempotencyKey).slice(0, 32));
|
|
43217
43327
|
}
|
|
43218
43328
|
function ownerConflictDir(cwd, owner, workspaceId, idempotencyKey) {
|
|
43219
|
-
return
|
|
43329
|
+
return path139.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-conflicts`, digestOf2(idempotencyKey).slice(0, 32));
|
|
43220
43330
|
}
|
|
43221
43331
|
async function readJson4(file) {
|
|
43222
43332
|
try {
|
|
@@ -43287,7 +43397,7 @@ async function applyGuardedTargetWrite(input) {
|
|
|
43287
43397
|
staged: input.staged,
|
|
43288
43398
|
stagedAt: receipt.completedAt
|
|
43289
43399
|
};
|
|
43290
|
-
await writeFileAtomic(
|
|
43400
|
+
await writeFileAtomic(path139.join(ownerStagingDir(cwd, owner, intent.workspaceId, intent.idempotencyKey), "plan.json"), `${JSON.stringify(staged, null, 2)}
|
|
43291
43401
|
`);
|
|
43292
43402
|
const applied = await input.apply(input.staged);
|
|
43293
43403
|
if (!applied.ok) {
|
|
@@ -43313,15 +43423,15 @@ async function recoverStagedOwnerWrite(input) {
|
|
|
43313
43423
|
});
|
|
43314
43424
|
}
|
|
43315
43425
|
async function readStagedOwnerWrite(cwd, owner, workspaceId, idempotencyKey) {
|
|
43316
|
-
return readJson4(
|
|
43426
|
+
return readJson4(path139.join(ownerStagingDir(cwd, owner, workspaceId, idempotencyKey), "plan.json"));
|
|
43317
43427
|
}
|
|
43318
43428
|
async function recordConflict(input) {
|
|
43319
43429
|
const base = { targetRef: input.targetRef, expectedVersion: input.expectedVersion, currentVersion: input.currentVersion };
|
|
43320
43430
|
if (input.proposedContent === undefined)
|
|
43321
43431
|
return base;
|
|
43322
43432
|
const dir = ownerConflictDir(input.cwd, input.owner, input.intent.workspaceId, input.intent.idempotencyKey);
|
|
43323
|
-
await writeFileAtomic(
|
|
43324
|
-
const diffRef = `./workspaces/${input.intent.workspaceId}/${input.owner}-write-conflicts/${
|
|
43433
|
+
await writeFileAtomic(path139.join(dir, "proposed"), input.proposedContent);
|
|
43434
|
+
const diffRef = `./workspaces/${input.intent.workspaceId}/${input.owner}-write-conflicts/${path139.basename(dir)}/proposed`;
|
|
43325
43435
|
return { ...base, diffRef };
|
|
43326
43436
|
}
|
|
43327
43437
|
|
|
@@ -43371,7 +43481,7 @@ async function resolveWorkspaceModule(cwd, workspaceId) {
|
|
|
43371
43481
|
}
|
|
43372
43482
|
}
|
|
43373
43483
|
async function collectWikiDecisionEntries(cwd) {
|
|
43374
|
-
const dir =
|
|
43484
|
+
const dir = path140.join(cwd, ".metaproject", "wiki", "decisions");
|
|
43375
43485
|
let files;
|
|
43376
43486
|
try {
|
|
43377
43487
|
files = (await readdir24(dir)).filter((name) => name.endsWith(".md"));
|
|
@@ -43380,12 +43490,12 @@ async function collectWikiDecisionEntries(cwd) {
|
|
|
43380
43490
|
}
|
|
43381
43491
|
const entries = [];
|
|
43382
43492
|
for (const file of files) {
|
|
43383
|
-
const absolutePath =
|
|
43493
|
+
const absolutePath = path140.join(dir, file);
|
|
43384
43494
|
try {
|
|
43385
43495
|
const content = await readFile69(absolutePath, "utf8");
|
|
43386
43496
|
entries.push({
|
|
43387
43497
|
absolutePath,
|
|
43388
|
-
relativePath:
|
|
43498
|
+
relativePath: path140.posix.join("decisions", file),
|
|
43389
43499
|
type: extractHeaderField(content, "Type") ?? "decision",
|
|
43390
43500
|
title: extractTitle(content),
|
|
43391
43501
|
version: extractHeaderField(content, "Version") ?? null,
|
|
@@ -43607,7 +43717,7 @@ function createRealMemoryOwnerWriter(cwd, opts) {
|
|
|
43607
43717
|
init_service4();
|
|
43608
43718
|
init_guard();
|
|
43609
43719
|
import { readFile as readFile71 } from "fs/promises";
|
|
43610
|
-
import
|
|
43720
|
+
import path141 from "path";
|
|
43611
43721
|
function renderWrapUpDecisionPage(input) {
|
|
43612
43722
|
const note = input.note?.trim();
|
|
43613
43723
|
return `# ${input.title}
|
|
@@ -43648,7 +43758,7 @@ export is the source of truth for what actually happened.
|
|
|
43648
43758
|
`;
|
|
43649
43759
|
}
|
|
43650
43760
|
function wikiPageRelativePath(proposalId) {
|
|
43651
|
-
return
|
|
43761
|
+
return path141.posix.join("decisions", `sac-${proposalId}.md`);
|
|
43652
43762
|
}
|
|
43653
43763
|
function createRealWikiOwnerWriter(cwd, opts) {
|
|
43654
43764
|
const now = opts?.now ?? (() => new Date);
|
|
@@ -43656,7 +43766,7 @@ function createRealWikiOwnerWriter(cwd, opts) {
|
|
|
43656
43766
|
const relativePath = staged.relativePath;
|
|
43657
43767
|
const content = staged.content;
|
|
43658
43768
|
const history = await openWikiWriteContext(cwd, "sac proposal accept");
|
|
43659
|
-
await writeWikiPage(history,
|
|
43769
|
+
await writeWikiPage(history, path141.join(cwd, ".metaproject", "wiki", relativePath), content);
|
|
43660
43770
|
return { ok: true };
|
|
43661
43771
|
};
|
|
43662
43772
|
return {
|
|
@@ -43805,7 +43915,7 @@ class ProposalLifecycleService {
|
|
|
43805
43915
|
now;
|
|
43806
43916
|
constructor(options) {
|
|
43807
43917
|
this.options = options;
|
|
43808
|
-
this.root =
|
|
43918
|
+
this.root = path142.resolve(options.workspaceRoot);
|
|
43809
43919
|
this.now = options.now ?? (() => new Date);
|
|
43810
43920
|
}
|
|
43811
43921
|
async create(input) {
|
|
@@ -43825,7 +43935,7 @@ class ProposalLifecycleService {
|
|
|
43825
43935
|
if (manifest.status === "archived")
|
|
43826
43936
|
throw new ProposalLifecycleError("guard_denied", "workspace is archived");
|
|
43827
43937
|
const file = this.proposalPath(workspaceId, proposal.id);
|
|
43828
|
-
await mkdir35(
|
|
43938
|
+
await mkdir35(path142.dirname(file), { recursive: true, mode: 448 });
|
|
43829
43939
|
return withFileLock(`${file}.lock`, async () => {
|
|
43830
43940
|
const consume = this.options.wrapUpAuthority.consume(input.wrapUp, { actor, workspaceId });
|
|
43831
43941
|
if (consume !== "ok")
|
|
@@ -43853,7 +43963,7 @@ class ProposalLifecycleService {
|
|
|
43853
43963
|
return this.options.workspaces.withAuthorizedActor({ actorContext: actor, workspaceId: input.workspaceId, action: "review", execute: async (manifest) => {
|
|
43854
43964
|
const proposal = await this.loadProposal(input.workspaceId, input.proposalId);
|
|
43855
43965
|
const ledger = this.ledgerPath(input.workspaceId);
|
|
43856
|
-
await mkdir35(
|
|
43966
|
+
await mkdir35(path142.dirname(ledger), { recursive: true, mode: 448 });
|
|
43857
43967
|
return withFileLock(`${ledger}.lock`, async () => {
|
|
43858
43968
|
const records = (await this.records(ledger)).filter((record) => record.proposalId === proposal.id);
|
|
43859
43969
|
const events = records.filter((record) => record.recordType === "proposal-transition");
|
|
@@ -43895,7 +44005,7 @@ class ProposalLifecycleService {
|
|
|
43895
44005
|
} });
|
|
43896
44006
|
}
|
|
43897
44007
|
async listProposedProposals(workspaceId) {
|
|
43898
|
-
const proposalsDir =
|
|
44008
|
+
const proposalsDir = path142.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals");
|
|
43899
44009
|
let entries;
|
|
43900
44010
|
try {
|
|
43901
44011
|
entries = (await readdir25(proposalsDir)).filter((name) => name.endsWith(".json"));
|
|
@@ -43907,7 +44017,7 @@ class ProposalLifecycleService {
|
|
|
43907
44017
|
const proposals = [];
|
|
43908
44018
|
for (const entry of entries) {
|
|
43909
44019
|
try {
|
|
43910
|
-
const parsed = JSON.parse(await readFile73(
|
|
44020
|
+
const parsed = JSON.parse(await readFile73(path142.join(proposalsDir, entry), "utf8"));
|
|
43911
44021
|
if (parsed.recordType === "proposal-created")
|
|
43912
44022
|
proposals.push(parsed);
|
|
43913
44023
|
} catch {}
|
|
@@ -44173,31 +44283,31 @@ class ProposalLifecycleService {
|
|
|
44173
44283
|
}
|
|
44174
44284
|
}
|
|
44175
44285
|
proposalPath(workspaceId, proposalId) {
|
|
44176
|
-
return
|
|
44286
|
+
return path142.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
|
|
44177
44287
|
}
|
|
44178
44288
|
decisionRef(proposalId, key) {
|
|
44179
44289
|
return `./proposals/${proposalId}.${hash2(key)}.decision.json`;
|
|
44180
44290
|
}
|
|
44181
44291
|
decisionPath(workspaceId, proposalId, key) {
|
|
44182
|
-
return
|
|
44292
|
+
return path142.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash2(key)}.decision.json`);
|
|
44183
44293
|
}
|
|
44184
44294
|
approvalRef(proposalId, key) {
|
|
44185
44295
|
return `./proposals/${proposalId}.${hash2(key)}.approval.json`;
|
|
44186
44296
|
}
|
|
44187
44297
|
approvalPath(workspaceId, proposalId, key) {
|
|
44188
|
-
return
|
|
44298
|
+
return path142.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash2(key)}.approval.json`);
|
|
44189
44299
|
}
|
|
44190
44300
|
writeResultPath(workspaceId, proposalId, key) {
|
|
44191
|
-
return
|
|
44301
|
+
return path142.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash2(key)}.write-result.json`);
|
|
44192
44302
|
}
|
|
44193
44303
|
intentRef(proposalId, key) {
|
|
44194
44304
|
return `./proposals/${proposalId}.${hash2(key)}.write-intent.json`;
|
|
44195
44305
|
}
|
|
44196
44306
|
intentPath(workspaceId, proposalId, key) {
|
|
44197
|
-
return
|
|
44307
|
+
return path142.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash2(key)}.write-intent.json`);
|
|
44198
44308
|
}
|
|
44199
44309
|
attemptPath(workspaceId, proposalId, key) {
|
|
44200
|
-
return
|
|
44310
|
+
return path142.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash2(key)}.owner-write-attempt.json`);
|
|
44201
44311
|
}
|
|
44202
44312
|
async loadWriteResult(workspaceId, proposalId, key) {
|
|
44203
44313
|
try {
|
|
@@ -44224,7 +44334,7 @@ class ProposalLifecycleService {
|
|
|
44224
44334
|
}
|
|
44225
44335
|
}
|
|
44226
44336
|
ledgerPath(workspaceId) {
|
|
44227
|
-
return
|
|
44337
|
+
return path142.join(this.root, ".metaproject", "workspaces", workspaceId, "activity.jsonl");
|
|
44228
44338
|
}
|
|
44229
44339
|
timestamp() {
|
|
44230
44340
|
return this.now().toISOString();
|
|
@@ -44343,11 +44453,11 @@ async function replayPreservation(input) {
|
|
|
44343
44453
|
if (typeof slate.workspaceId !== "string" || !/^[a-z][a-z0-9-]{2,63}$/.test(slate.workspaceId))
|
|
44344
44454
|
throw new Error("invalid workspace identity");
|
|
44345
44455
|
const workspaceId = slate.workspaceId;
|
|
44346
|
-
const outbox =
|
|
44347
|
-
const receipt = await readReplayJson(
|
|
44456
|
+
const outbox = path143.join(input.dir, "preservation", "outbox");
|
|
44457
|
+
const receipt = await readReplayJson(path143.join(outbox, `${input.snapshot}.json`));
|
|
44348
44458
|
if (receipt.version !== 1 || receipt.snapshot !== input.snapshot || receipt.state !== "pending-review")
|
|
44349
44459
|
throw new Error("invalid outbox receipt");
|
|
44350
|
-
return withFileLock(
|
|
44460
|
+
return withFileLock(path143.join(outbox, `${input.snapshot}.delivery.lock`), async () => {
|
|
44351
44461
|
input.signal?.throwIfAborted();
|
|
44352
44462
|
const { service, wrapUpAuthority, authorizationServer } = createHarnessProposalLifecycleService(input.cwd, {
|
|
44353
44463
|
workspaceId,
|
|
@@ -44374,12 +44484,12 @@ async function replayPreservation(input) {
|
|
|
44374
44484
|
} catch (error) {
|
|
44375
44485
|
if (!(error instanceof ProposalLifecycleError) || error.code !== "conflict")
|
|
44376
44486
|
throw error;
|
|
44377
|
-
const existing = await readReplayJson(
|
|
44487
|
+
const existing = await readReplayJson(path143.join(input.cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${id}.json`));
|
|
44378
44488
|
const refs = (evidence) => evidence.map((e) => [e.uri, e.revision]);
|
|
44379
44489
|
if (existing.workspaceId !== workspaceId || existing.author !== actor.subject || existing.kind !== "follow-up" || existing.proposalRevision !== input.snapshot || existing.wrapUp?.sourceRef !== sourceRef || existing.wrapUp?.sourceRevision !== wrapUp.sourceRevision || JSON.stringify(refs(existing.evidence)) !== JSON.stringify(refs(wrapUp.evidence)))
|
|
44380
44490
|
throw new Error("delivery conflict mismatch", { cause: error });
|
|
44381
44491
|
}
|
|
44382
|
-
const delivered =
|
|
44492
|
+
const delivered = path143.join(outbox, `${input.snapshot}.delivered`);
|
|
44383
44493
|
try {
|
|
44384
44494
|
const marker = await readReplayJson(delivered);
|
|
44385
44495
|
if (marker.version !== 1 || marker.workspaceId !== workspaceId || marker.proposalId !== id || marker.snapshot !== input.snapshot) {
|
|
@@ -44392,7 +44502,7 @@ async function replayPreservation(input) {
|
|
|
44392
44502
|
}
|
|
44393
44503
|
input.afterCreate?.();
|
|
44394
44504
|
input.signal?.throwIfAborted();
|
|
44395
|
-
writePreservationFile(
|
|
44505
|
+
writePreservationFile(path143.join(outbox, `${input.snapshot}.delivered`), JSON.stringify({ version: 1, workspaceId, proposalId: id, snapshot: input.snapshot }));
|
|
44396
44506
|
return "proposed";
|
|
44397
44507
|
}, input.signal ? { signal: input.signal } : {});
|
|
44398
44508
|
}
|
|
@@ -44415,14 +44525,14 @@ async function scanPreservationOutbox(input) {
|
|
|
44415
44525
|
const result = { proposed: 0, deferred: 0, unbound: 0 };
|
|
44416
44526
|
let entries;
|
|
44417
44527
|
try {
|
|
44418
|
-
entries = await readdir26(
|
|
44528
|
+
entries = await readdir26(path143.join(input.dir, "preservation", "outbox"));
|
|
44419
44529
|
} catch (error) {
|
|
44420
44530
|
if (error.code === "ENOENT")
|
|
44421
44531
|
return result;
|
|
44422
44532
|
throw error;
|
|
44423
44533
|
}
|
|
44424
44534
|
let attempted = 0;
|
|
44425
|
-
const cursorFile =
|
|
44535
|
+
const cursorFile = path143.join(input.dir, "preservation", "outbox", "SCAN_CURSOR");
|
|
44426
44536
|
for (const entry of resumeScan(entries.filter((name) => /^[a-f0-9]{64}\.json$/.test(name)), cursorFile)) {
|
|
44427
44537
|
if (input.signal?.aborted || Date.now() >= (input.deadline ?? Infinity) || attempted >= (input.maxItems ?? 8))
|
|
44428
44538
|
break;
|
|
@@ -44447,11 +44557,11 @@ async function replayProjectPreservationOutboxes(input) {
|
|
|
44447
44557
|
return boundedReplay(input, scanProjectPreservationOutboxes);
|
|
44448
44558
|
}
|
|
44449
44559
|
async function retryProjectPreservation(cwd) {
|
|
44450
|
-
return replayProjectPreservationOutboxes({ cwd, dir:
|
|
44560
|
+
return replayProjectPreservationOutboxes({ cwd, dir: path143.join(projectSessionsDir(cwd), ".explicit-retry") });
|
|
44451
44561
|
}
|
|
44452
44562
|
async function scanProjectPreservationOutboxes(input) {
|
|
44453
44563
|
const result = { proposed: 0, deferred: 0, unbound: 0 };
|
|
44454
|
-
const root =
|
|
44564
|
+
const root = path143.dirname(input.dir);
|
|
44455
44565
|
let entries;
|
|
44456
44566
|
try {
|
|
44457
44567
|
entries = await readdir26(root, { withFileTypes: true });
|
|
@@ -44462,7 +44572,7 @@ async function scanProjectPreservationOutboxes(input) {
|
|
|
44462
44572
|
}
|
|
44463
44573
|
const deadline = input.deadline ?? Date.now() + 2000;
|
|
44464
44574
|
let scanned = 0;
|
|
44465
|
-
const cursorFile =
|
|
44575
|
+
const cursorFile = path143.join(root, ".preservation-replay-cursor");
|
|
44466
44576
|
const candidates = entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).map((entry) => entry.name);
|
|
44467
44577
|
for (const name of resumeScan(candidates, cursorFile)) {
|
|
44468
44578
|
if (input.signal?.aborted || Date.now() >= deadline || scanned >= 32)
|
|
@@ -44471,7 +44581,7 @@ async function scanProjectPreservationOutboxes(input) {
|
|
|
44471
44581
|
recordScanCursor(cursorFile, name);
|
|
44472
44582
|
scanned++;
|
|
44473
44583
|
try {
|
|
44474
|
-
const replay = await replayPreservationOutbox({ ...input, deadline, maxItems: 1, dir:
|
|
44584
|
+
const replay = await replayPreservationOutbox({ ...input, deadline, maxItems: 1, dir: path143.join(root, name) });
|
|
44475
44585
|
result.proposed += replay.proposed;
|
|
44476
44586
|
result.deferred += replay.deferred;
|
|
44477
44587
|
result.unbound += replay.unbound;
|
|
@@ -44510,7 +44620,7 @@ async function boundedReplay(input, scan) {
|
|
|
44510
44620
|
import { createHash as createHash35, randomUUID as randomUUID9 } from "crypto";
|
|
44511
44621
|
init_assembly();
|
|
44512
44622
|
import { appendFile as appendFile8, mkdir as mkdir36, open as open4, readFile as readFile74, rename as rename7, rm as rm8, stat as stat18, writeFile as writeFile24 } from "fs/promises";
|
|
44513
|
-
import
|
|
44623
|
+
import path144 from "path";
|
|
44514
44624
|
init_fs();
|
|
44515
44625
|
|
|
44516
44626
|
// src/sac/policy-experiment.ts
|
|
@@ -45253,7 +45363,7 @@ function hasReportIntegrity(report) {
|
|
|
45253
45363
|
return reportHashPattern.test(reportDigest) && sha2566(body) === reportDigest;
|
|
45254
45364
|
}
|
|
45255
45365
|
async function resolvePolicySelection(workspaceRoot, canonicalFallback) {
|
|
45256
|
-
const configPath =
|
|
45366
|
+
const configPath = path144.join(workspaceRoot, ...policyExperimentConfigPath);
|
|
45257
45367
|
let configJson;
|
|
45258
45368
|
try {
|
|
45259
45369
|
const raw = await readFile74(configPath, "utf8").catch((error) => {
|
|
@@ -45451,9 +45561,9 @@ class FwkReadService {
|
|
|
45451
45561
|
const recordedAt = nowIso2(now);
|
|
45452
45562
|
const id = `receipt-${randomUUID9().replace(/-/g, "").slice(0, 16)}`;
|
|
45453
45563
|
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"}` } : {} };
|
|
45454
|
-
const ledger =
|
|
45455
|
-
const checkpointPath =
|
|
45456
|
-
await mkdir36(
|
|
45564
|
+
const ledger = path144.join(this.options.canonical.workspaceRoot, ".metaproject", "context-operations", "access-receipts.jsonl");
|
|
45565
|
+
const checkpointPath = path144.join(path144.dirname(ledger), "access-receipts.checkpoint.json");
|
|
45566
|
+
await mkdir36(path144.dirname(ledger), { recursive: true, mode: 448 });
|
|
45457
45567
|
return withFileLock(`${ledger}.lock`, async () => {
|
|
45458
45568
|
const state = await resolveLedgerState(ledger, checkpointPath, this.options.verifyReceiptLedger ?? verifyAccessReceiptLedger);
|
|
45459
45569
|
const receipt = sealAccessReceipt(base, state.headHash);
|
|
@@ -45556,7 +45666,7 @@ function normalizeFwkResult(result) {
|
|
|
45556
45666
|
// src/sac/collaboration-service.ts
|
|
45557
45667
|
import { appendFile as appendFile9, mkdir as mkdir37, readFile as readFile75 } from "fs/promises";
|
|
45558
45668
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
45559
|
-
import
|
|
45669
|
+
import path145 from "path";
|
|
45560
45670
|
class CollaborationServiceError extends Error {
|
|
45561
45671
|
code;
|
|
45562
45672
|
constructor(code, message) {
|
|
@@ -45571,7 +45681,7 @@ class CollaborationService {
|
|
|
45571
45681
|
this.input = input;
|
|
45572
45682
|
}
|
|
45573
45683
|
file(id) {
|
|
45574
|
-
return
|
|
45684
|
+
return path145.join(this.input.workspaceRoot, ".metaproject", "workspaces", id, "activity.jsonl");
|
|
45575
45685
|
}
|
|
45576
45686
|
async overview(input) {
|
|
45577
45687
|
const manifest = await this.input.workspaces.show(input);
|
|
@@ -45608,7 +45718,7 @@ class CollaborationService {
|
|
|
45608
45718
|
occurredAt: (this.input.now ?? (() => new Date))().toISOString(),
|
|
45609
45719
|
...suppliedHandoff ? { handoff: { ...suppliedHandoff, from: actor.subject } } : {}
|
|
45610
45720
|
});
|
|
45611
|
-
await mkdir37(
|
|
45721
|
+
await mkdir37(path145.dirname(this.file(manifest.id)), { recursive: true, mode: 448 });
|
|
45612
45722
|
await appendFile9(this.file(manifest.id), `${JSON.stringify(activity)}
|
|
45613
45723
|
`, { mode: 384 });
|
|
45614
45724
|
return normalizeCollaborationResult(activity);
|
|
@@ -45658,14 +45768,14 @@ function normalizeCollaborationResult(value) {
|
|
|
45658
45768
|
// src/session/external-slate.ts
|
|
45659
45769
|
init_fs();
|
|
45660
45770
|
import { mkdir as mkdir39, readdir as readdir27, readFile as readFile76 } from "fs/promises";
|
|
45661
|
-
import
|
|
45771
|
+
import path147 from "path";
|
|
45662
45772
|
|
|
45663
45773
|
// src/sac/machine-wrap-up.ts
|
|
45664
45774
|
init_fs();
|
|
45665
45775
|
init_slate();
|
|
45666
45776
|
import { createHash as createHash36, randomUUID as randomUUID12 } from "crypto";
|
|
45667
45777
|
import { mkdir as mkdir38 } from "fs/promises";
|
|
45668
|
-
import
|
|
45778
|
+
import path146 from "path";
|
|
45669
45779
|
|
|
45670
45780
|
// src/sac/workspace-resolve.ts
|
|
45671
45781
|
init_redact();
|
|
@@ -45808,11 +45918,11 @@ async function resolveMachineWrapUp(input) {
|
|
|
45808
45918
|
`;
|
|
45809
45919
|
const seedsJson = `${JSON.stringify(seedsForKind.map((seed) => ({ text: seed.text, source: describeSource(seed.source) })), null, 2)}
|
|
45810
45920
|
`;
|
|
45811
|
-
const evidenceRelBase =
|
|
45921
|
+
const evidenceRelBase = path146.posix.join(".metaproject", "workspaces", input.workspaceId, "machine-evidence");
|
|
45812
45922
|
const floor = await applyEvidenceRedactionFloor(input.cwd, [
|
|
45813
|
-
{ name: `${input.kind}.diff.txt`, content: diffBody, path:
|
|
45814
|
-
{ name: `${input.kind}.flow.json`, content: flowSnapshotJson, path:
|
|
45815
|
-
{ name: `${input.kind}.seeds.json`, content: seedsJson, path:
|
|
45923
|
+
{ name: `${input.kind}.diff.txt`, content: diffBody, path: path146.posix.join(evidenceRelBase, `${input.kind}.diff.txt`), source: "tool-output" },
|
|
45924
|
+
{ name: `${input.kind}.flow.json`, content: flowSnapshotJson, path: path146.posix.join(evidenceRelBase, `${input.kind}.flow.json`), source: "generated" },
|
|
45925
|
+
{ name: `${input.kind}.seeds.json`, content: seedsJson, path: path146.posix.join(evidenceRelBase, `${input.kind}.seeds.json`), source: "generated" }
|
|
45816
45926
|
]);
|
|
45817
45927
|
if (!floor.ok)
|
|
45818
45928
|
return { ok: false, code: "security_denied", detail: floor.reason };
|
|
@@ -45866,14 +45976,14 @@ ${safeSeeds.content}`;
|
|
|
45866
45976
|
}
|
|
45867
45977
|
summary = result.text.trim().length > 0 ? result.text.trim() : mechanicalSummary(summaryDiff, course);
|
|
45868
45978
|
}
|
|
45869
|
-
const evidenceDir =
|
|
45979
|
+
const evidenceDir = path146.join(input.cwd, ".metaproject", "workspaces", input.workspaceId, "machine-evidence");
|
|
45870
45980
|
await mkdir38(evidenceDir, { recursive: true });
|
|
45871
45981
|
const diffFile = `${input.kind}.${shortHash}.diff.txt`;
|
|
45872
45982
|
const flowFile = `${input.kind}.${shortHash}.flow.json`;
|
|
45873
45983
|
const seedsFile = `${input.kind}.${shortHash}.seeds.json`;
|
|
45874
|
-
await writeFileAtomic(
|
|
45875
|
-
await writeFileAtomic(
|
|
45876
|
-
await writeFileAtomic(
|
|
45984
|
+
await writeFileAtomic(path146.join(evidenceDir, diffFile), safeDiff.content);
|
|
45985
|
+
await writeFileAtomic(path146.join(evidenceDir, flowFile), safeFlow.content);
|
|
45986
|
+
await writeFileAtomic(path146.join(evidenceDir, seedsFile), safeSeeds.content);
|
|
45877
45987
|
const observedAt = now().toISOString();
|
|
45878
45988
|
const relBase = `./.metaproject/workspaces/${input.workspaceId}/machine-evidence`;
|
|
45879
45989
|
const evidence = [
|
|
@@ -45883,7 +45993,7 @@ ${safeSeeds.content}`;
|
|
|
45883
45993
|
];
|
|
45884
45994
|
if (floor.notice !== undefined) {
|
|
45885
45995
|
const noticeFile = `${input.kind}.${shortHash}.redaction.md`;
|
|
45886
|
-
await writeFileAtomic(
|
|
45996
|
+
await writeFileAtomic(path146.join(evidenceDir, noticeFile), floor.notice);
|
|
45887
45997
|
evidence.push({ kind: REDACTION_NOTICE_KIND, uri: `${relBase}/${noticeFile}`, revision: sha2567(floor.notice), observedAt });
|
|
45888
45998
|
}
|
|
45889
45999
|
return {
|
|
@@ -45902,18 +46012,18 @@ async function writeFlooredArchiveArtifact(params) {
|
|
|
45902
46012
|
{
|
|
45903
46013
|
name: params.filename,
|
|
45904
46014
|
content: params.content,
|
|
45905
|
-
path:
|
|
46015
|
+
path: path146.posix.join("slate-archive", params.filename),
|
|
45906
46016
|
source: "generated"
|
|
45907
46017
|
}
|
|
45908
46018
|
]);
|
|
45909
46019
|
if (!floor.ok)
|
|
45910
46020
|
return { ok: false, code: "security_denied", detail: floor.reason };
|
|
45911
46021
|
const body = floor.bodies[0];
|
|
45912
|
-
const archiveDir =
|
|
46022
|
+
const archiveDir = path146.join(params.dir, "slate-archive");
|
|
45913
46023
|
await mkdir38(archiveDir, { recursive: true });
|
|
45914
|
-
await writeFileAtomic(
|
|
46024
|
+
await writeFileAtomic(path146.join(archiveDir, params.filename), body.content);
|
|
45915
46025
|
if (floor.notice !== undefined) {
|
|
45916
|
-
await writeFileAtomic(
|
|
46026
|
+
await writeFileAtomic(path146.join(archiveDir, `${params.filename}${ARCHIVE_REDACTION_NOTICE_SUFFIX}`), floor.notice);
|
|
45917
46027
|
}
|
|
45918
46028
|
return { ok: true, altered: body.altered };
|
|
45919
46029
|
}
|
|
@@ -45949,9 +46059,9 @@ async function writeWrapUpOutcomeArtifact(cwd, dir, trigger, now, groups) {
|
|
|
45949
46059
|
return;
|
|
45950
46060
|
const refusalIso = now().toISOString();
|
|
45951
46061
|
const refusalFilename = `${refusalIso.replace(/[:.]/g, "-")}-wrap-up-outcome.json`;
|
|
45952
|
-
const archiveDir =
|
|
46062
|
+
const archiveDir = path146.join(dir, "slate-archive");
|
|
45953
46063
|
await mkdir38(archiveDir, { recursive: true });
|
|
45954
|
-
await writeFileAtomic(
|
|
46064
|
+
await writeFileAtomic(path146.join(archiveDir, refusalFilename), `${JSON.stringify({
|
|
45955
46065
|
recordType: "wrap-up-outcome",
|
|
45956
46066
|
trigger,
|
|
45957
46067
|
generatedAt: refusalIso,
|
|
@@ -46088,7 +46198,7 @@ async function runWrapUp(input) {
|
|
|
46088
46198
|
|
|
46089
46199
|
// src/session/external-slate.ts
|
|
46090
46200
|
function externalSlatesDir(cwd) {
|
|
46091
|
-
return
|
|
46201
|
+
return path147.join(cwd, ".keryx", "external-slates");
|
|
46092
46202
|
}
|
|
46093
46203
|
var EXTERNAL_SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
46094
46204
|
function assertValidExternalSessionId(externalSessionId) {
|
|
@@ -46098,14 +46208,14 @@ function assertValidExternalSessionId(externalSessionId) {
|
|
|
46098
46208
|
}
|
|
46099
46209
|
function externalSlatePath(cwd, externalSessionId) {
|
|
46100
46210
|
assertValidExternalSessionId(externalSessionId);
|
|
46101
|
-
return
|
|
46211
|
+
return path147.join(externalSlatesDir(cwd), `${externalSessionId}.json`);
|
|
46102
46212
|
}
|
|
46103
46213
|
function externalSlateLockPath(cwd, externalSessionId) {
|
|
46104
46214
|
return `${externalSlatePath(cwd, externalSessionId)}.lock`;
|
|
46105
46215
|
}
|
|
46106
46216
|
function externalSlateEvidenceDir(cwd, externalSessionId) {
|
|
46107
46217
|
assertValidExternalSessionId(externalSessionId);
|
|
46108
|
-
return
|
|
46218
|
+
return path147.join(externalSlatesDir(cwd), externalSessionId);
|
|
46109
46219
|
}
|
|
46110
46220
|
async function readExternalSlate(cwd, externalSessionId) {
|
|
46111
46221
|
try {
|
|
@@ -46189,12 +46299,12 @@ init_service2();
|
|
|
46189
46299
|
|
|
46190
46300
|
// src/standard/service.ts
|
|
46191
46301
|
init_fs();
|
|
46192
|
-
import
|
|
46302
|
+
import path150 from "path";
|
|
46193
46303
|
import { readFile as readFile79 } from "fs/promises";
|
|
46194
46304
|
|
|
46195
46305
|
// src/standard/validate.ts
|
|
46196
46306
|
init_fs();
|
|
46197
|
-
import
|
|
46307
|
+
import path149 from "path";
|
|
46198
46308
|
import { readFile as readFile78 } from "fs/promises";
|
|
46199
46309
|
|
|
46200
46310
|
// src/standard/schemas.ts
|
|
@@ -46324,7 +46434,7 @@ var SCHEMA_REGISTRY2 = {
|
|
|
46324
46434
|
// src/standard/profiles.ts
|
|
46325
46435
|
init_fs();
|
|
46326
46436
|
init_entrypoint_targets();
|
|
46327
|
-
import
|
|
46437
|
+
import path148 from "path";
|
|
46328
46438
|
import { readFile as readFile77 } from "fs/promises";
|
|
46329
46439
|
var AGENT_MODULES = ["gdgraph", "gdctx", "gdskills", "gdwiki", "memory"];
|
|
46330
46440
|
var CI_MODULES = ["health", "testing"];
|
|
@@ -46349,7 +46459,7 @@ function enabledModuleKeys(manifest) {
|
|
|
46349
46459
|
}
|
|
46350
46460
|
async function rootEntrypointLinksIndex(cwd, manifest) {
|
|
46351
46461
|
for (const { path: name } of namedEntrypoints(manifest)) {
|
|
46352
|
-
const filePath =
|
|
46462
|
+
const filePath = path148.join(cwd, name);
|
|
46353
46463
|
if (!await pathExists(filePath)) {
|
|
46354
46464
|
continue;
|
|
46355
46465
|
}
|
|
@@ -46361,16 +46471,16 @@ async function rootEntrypointLinksIndex(cwd, manifest) {
|
|
|
46361
46471
|
return false;
|
|
46362
46472
|
}
|
|
46363
46473
|
async function minimalSatisfied(cwd) {
|
|
46364
|
-
const metaprojectRoot =
|
|
46474
|
+
const metaprojectRoot = path148.join(cwd, ".metaproject");
|
|
46365
46475
|
const requiredFiles = ["index.md", "README.md", "metaproject.json"];
|
|
46366
46476
|
const requiredDirs = ["modules", "rules", "skills", "data"];
|
|
46367
46477
|
for (const file of requiredFiles) {
|
|
46368
|
-
if (!await pathExists(
|
|
46478
|
+
if (!await pathExists(path148.join(metaprojectRoot, file))) {
|
|
46369
46479
|
return false;
|
|
46370
46480
|
}
|
|
46371
46481
|
}
|
|
46372
46482
|
for (const dir of requiredDirs) {
|
|
46373
|
-
if (!await pathExists(
|
|
46483
|
+
if (!await pathExists(path148.join(metaprojectRoot, dir))) {
|
|
46374
46484
|
return false;
|
|
46375
46485
|
}
|
|
46376
46486
|
}
|
|
@@ -46383,7 +46493,7 @@ async function ciSatisfied(cwd, manifest) {
|
|
|
46383
46493
|
return false;
|
|
46384
46494
|
}
|
|
46385
46495
|
for (const key of ciModules) {
|
|
46386
|
-
if (await pathExists(
|
|
46496
|
+
if (await pathExists(path148.join(cwd, ".metaproject", "data", key, "artifacts"))) {
|
|
46387
46497
|
return true;
|
|
46388
46498
|
}
|
|
46389
46499
|
}
|
|
@@ -46396,7 +46506,7 @@ async function evaluateProfiles(cwd, manifest) {
|
|
|
46396
46506
|
satisfied.push("minimal");
|
|
46397
46507
|
}
|
|
46398
46508
|
const hasAgentModule = AGENT_MODULES.some((key) => new Set(enabledModuleKeys(manifest)).has(key));
|
|
46399
|
-
const agent = minimal && hasAgentModule && await rootEntrypointLinksIndex(cwd, manifest) && await pathExists(
|
|
46509
|
+
const agent = minimal && hasAgentModule && await rootEntrypointLinksIndex(cwd, manifest) && await pathExists(path148.join(cwd, ".metaproject", "rules"));
|
|
46400
46510
|
if (agent) {
|
|
46401
46511
|
satisfied.push("agent");
|
|
46402
46512
|
}
|
|
@@ -46565,20 +46675,20 @@ var MANIFEST_TOP_LEVEL_SCHEMA = {
|
|
|
46565
46675
|
async function validateWorkspace2(cwd) {
|
|
46566
46676
|
const errors = [];
|
|
46567
46677
|
const warnings = [];
|
|
46568
|
-
const metaprojectRoot =
|
|
46678
|
+
const metaprojectRoot = path149.join(cwd, ".metaproject");
|
|
46569
46679
|
const requiredFiles = ["index.md", "README.md", "metaproject.json"];
|
|
46570
46680
|
for (const file of requiredFiles) {
|
|
46571
|
-
if (!await pathExists(
|
|
46681
|
+
if (!await pathExists(path149.join(metaprojectRoot, file))) {
|
|
46572
46682
|
errors.push(issue("missing-required-file", `Required file .metaproject/${file} is missing`, `Run \`keryx init\` to scaffold .metaproject/${file}.`));
|
|
46573
46683
|
}
|
|
46574
46684
|
}
|
|
46575
46685
|
const requiredDirs = ["modules", "rules", "skills", "data"];
|
|
46576
46686
|
for (const dir of requiredDirs) {
|
|
46577
|
-
if (!await pathExists(
|
|
46687
|
+
if (!await pathExists(path149.join(metaprojectRoot, dir))) {
|
|
46578
46688
|
errors.push(issue("missing-required-dir", `Required directory .metaproject/${dir}/ is missing`, `Run \`keryx init\` to create .metaproject/${dir}/.`));
|
|
46579
46689
|
}
|
|
46580
46690
|
}
|
|
46581
|
-
const manifestPath =
|
|
46691
|
+
const manifestPath = path149.join(metaprojectRoot, "metaproject.json");
|
|
46582
46692
|
if (!await pathExists(manifestPath)) {
|
|
46583
46693
|
return { ok: errors.length === 0, errors, warnings };
|
|
46584
46694
|
}
|
|
@@ -46610,7 +46720,7 @@ async function validateWorkspace2(cwd) {
|
|
|
46610
46720
|
if (typeof value !== "string") {
|
|
46611
46721
|
continue;
|
|
46612
46722
|
}
|
|
46613
|
-
if (!await pathExists(
|
|
46723
|
+
if (!await pathExists(path149.join(cwd, value))) {
|
|
46614
46724
|
errors.push(issue("missing-declared-path", `Declared path paths.${key} -> ${value} does not exist`, `Create ${value} or remove paths.${key} from metaproject.json.`));
|
|
46615
46725
|
}
|
|
46616
46726
|
}
|
|
@@ -46620,7 +46730,7 @@ async function validateWorkspace2(cwd) {
|
|
|
46620
46730
|
continue;
|
|
46621
46731
|
}
|
|
46622
46732
|
if (typeof entry.manifest === "string") {
|
|
46623
|
-
if (!await pathExists(
|
|
46733
|
+
if (!await pathExists(path149.join(cwd, entry.manifest))) {
|
|
46624
46734
|
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.`));
|
|
46625
46735
|
}
|
|
46626
46736
|
}
|
|
@@ -46629,14 +46739,14 @@ async function validateWorkspace2(cwd) {
|
|
|
46629
46739
|
if (typeof value !== "string") {
|
|
46630
46740
|
continue;
|
|
46631
46741
|
}
|
|
46632
|
-
if (!await pathExists(
|
|
46742
|
+
if (!await pathExists(path149.join(cwd, value))) {
|
|
46633
46743
|
const sink = field === "data" ? warnings : errors;
|
|
46634
46744
|
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.`));
|
|
46635
46745
|
}
|
|
46636
46746
|
}
|
|
46637
46747
|
}
|
|
46638
46748
|
for (const { path: name, scope } of namedEntrypoints(manifest)) {
|
|
46639
|
-
const filePath =
|
|
46749
|
+
const filePath = path149.join(cwd, name);
|
|
46640
46750
|
if (!await pathExists(filePath)) {
|
|
46641
46751
|
continue;
|
|
46642
46752
|
}
|
|
@@ -47642,7 +47752,7 @@ async function runDoctor(cwd) {
|
|
|
47642
47752
|
return validateWorkspace2(cwd);
|
|
47643
47753
|
}
|
|
47644
47754
|
async function readManifest2(cwd) {
|
|
47645
|
-
const manifestPath =
|
|
47755
|
+
const manifestPath = path150.join(cwd, ".metaproject", "metaproject.json");
|
|
47646
47756
|
if (!await pathExists(manifestPath)) {
|
|
47647
47757
|
throw new Error("Metaproject is not initialized (missing .metaproject/metaproject.json). Run `keryx init` first.");
|
|
47648
47758
|
}
|