@mrciphersmith/keryx 0.3.81 → 0.3.83
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/cli.js +2236 -2109
- package/dist/core.js +538 -430
- package/package.json +1 -1
- package/src/gdskills/bundled/skills/orchestration/job-orchestrator/SKILL.md +6 -6
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +13 -24
- package/src/gdskills/bundled/skills/review/review-orchestrator/templates/review-report.md +124 -41
package/dist/core.js
CHANGED
|
@@ -10853,7 +10853,7 @@ var init_skill_length_ceilings = __esm(() => {
|
|
|
10853
10853
|
"review/review-jev-scenarios": 187,
|
|
10854
10854
|
"review/review-layout": 238,
|
|
10855
10855
|
"review/review-logic": 377,
|
|
10856
|
-
"review/review-orchestrator":
|
|
10856
|
+
"review/review-orchestrator": 1712,
|
|
10857
10857
|
"review/review-performance": 374,
|
|
10858
10858
|
"review/review-pr-feedback": 895,
|
|
10859
10859
|
"review/review-regression": 216,
|
|
@@ -22803,7 +22803,7 @@ var MARKER_VERSION = 1, BEGIN, END, REFERENCE_HEADING;
|
|
|
22803
22803
|
var init_managed_block = __esm(() => {
|
|
22804
22804
|
BEGIN = /^<!--\s*keryx:reference:begin\s+v=(\d+)(?:\s+hash=([0-9a-f]{64}))?\s*-->$/;
|
|
22805
22805
|
END = /^<!--\s*keryx:reference:end\s*-->$/;
|
|
22806
|
-
REFERENCE_HEADING = /^##\s+Reference
|
|
22806
|
+
REFERENCE_HEADING = /^##\s+Reference(?:\s*\([^)]*\))?\s*$/i;
|
|
22807
22807
|
});
|
|
22808
22808
|
|
|
22809
22809
|
// src/wiki/page-invariants.ts
|
|
@@ -23010,6 +23010,49 @@ ${entry}
|
|
|
23010
23010
|
return all.join(`
|
|
23011
23011
|
`);
|
|
23012
23012
|
}
|
|
23013
|
+
function repairVersionAndOrder(markdown) {
|
|
23014
|
+
let next = markdown;
|
|
23015
|
+
const all = next.split(`
|
|
23016
|
+
`);
|
|
23017
|
+
const range = changelogRange(all);
|
|
23018
|
+
if (range !== null) {
|
|
23019
|
+
const mask = fencedLines2(all);
|
|
23020
|
+
const starts = [];
|
|
23021
|
+
for (let index = range.heading + 1;index < range.end; index += 1) {
|
|
23022
|
+
if (!mask[index] && ENTRY_START.test(all[index]))
|
|
23023
|
+
starts.push(index);
|
|
23024
|
+
}
|
|
23025
|
+
const chunks = starts.map((start, position) => {
|
|
23026
|
+
const end = position + 1 < starts.length ? starts[position + 1] : range.end;
|
|
23027
|
+
const body = all.slice(start, end);
|
|
23028
|
+
while (body.length > 1 && body[body.length - 1].trim() === "")
|
|
23029
|
+
body.pop();
|
|
23030
|
+
return { body, version: ENTRY_VERSION.exec(body[0])?.[1] ?? null };
|
|
23031
|
+
});
|
|
23032
|
+
const ordered = chunks.every((chunk) => chunk.version !== null) ? [...chunks].sort((left, right) => compareVersions(right.version, left.version)) : chunks;
|
|
23033
|
+
if (ordered.some((chunk, index) => chunk !== chunks[index])) {
|
|
23034
|
+
const spaced = starts.length > 1 && all[starts[1] - 1].trim() === "";
|
|
23035
|
+
const rebuilt = [];
|
|
23036
|
+
ordered.forEach((chunk, index) => {
|
|
23037
|
+
if (index > 0 && spaced)
|
|
23038
|
+
rebuilt.push("");
|
|
23039
|
+
rebuilt.push(...chunk.body);
|
|
23040
|
+
});
|
|
23041
|
+
let tail = range.end;
|
|
23042
|
+
while (tail > starts[0] && all[tail - 1].trim() === "")
|
|
23043
|
+
tail -= 1;
|
|
23044
|
+
all.splice(starts[0], tail - starts[0], ...rebuilt);
|
|
23045
|
+
next = all.join(`
|
|
23046
|
+
`);
|
|
23047
|
+
}
|
|
23048
|
+
}
|
|
23049
|
+
const version = pageVersion(next);
|
|
23050
|
+
const newest = newestChangelogVersion(parseChangelog(next));
|
|
23051
|
+
if (version !== null && newest !== null && compareVersions(version, newest) < 0) {
|
|
23052
|
+
next = setPageVersion(next, newest);
|
|
23053
|
+
}
|
|
23054
|
+
return next;
|
|
23055
|
+
}
|
|
23013
23056
|
function sectionsOf(markdown) {
|
|
23014
23057
|
const all = lines2(markdown);
|
|
23015
23058
|
const mask = fencedLines2(all);
|
|
@@ -23095,6 +23138,8 @@ function withAddedLines(fresh, existingBody) {
|
|
|
23095
23138
|
return false;
|
|
23096
23139
|
if (/^[-*]\s+\[Module [^\]]+\]\([^)]+\.md\)$/.test(text))
|
|
23097
23140
|
return false;
|
|
23141
|
+
if (/^[-*]\s+`[^`]+`\s+\(no wiki page\)$/.test(text))
|
|
23142
|
+
return false;
|
|
23098
23143
|
if (/^graph-derived\b/i.test(text))
|
|
23099
23144
|
return false;
|
|
23100
23145
|
return !freshText.includes(text);
|
|
@@ -23155,10 +23200,11 @@ ${replacement.lines.join(`
|
|
|
23155
23200
|
`);
|
|
23156
23201
|
}
|
|
23157
23202
|
}
|
|
23203
|
+
const repaired = repairVersionAndOrder(next);
|
|
23158
23204
|
if (next === source)
|
|
23159
|
-
return existing;
|
|
23160
|
-
const version = nextPageVersion(
|
|
23161
|
-
return inEolOf(existing, prependChangelogEntry(setPageVersion(
|
|
23205
|
+
return repaired === source ? existing : inEolOf(existing, repaired);
|
|
23206
|
+
const version = nextPageVersion(repaired);
|
|
23207
|
+
return inEolOf(existing, prependChangelogEntry(setPageVersion(repaired, version), `- ${version} - ${entryNote}`));
|
|
23162
23208
|
}
|
|
23163
23209
|
var CHANGELOG_HEADING, SECTION_HEADING, H2, ENTRY_START, ENTRY_VERSION, LEGACY_META_KEYS;
|
|
23164
23210
|
var init_page_invariants = __esm(() => {
|
|
@@ -23182,6 +23228,55 @@ var init_page_invariants = __esm(() => {
|
|
|
23182
23228
|
]);
|
|
23183
23229
|
});
|
|
23184
23230
|
|
|
23231
|
+
// src/wiki/readme-links.ts
|
|
23232
|
+
import path76 from "path";
|
|
23233
|
+
function rewriteReadmeLinks(text, readmeDir, pageLink) {
|
|
23234
|
+
return text.replace(MARKDOWN_LINK, (whole, bang, label, target) => {
|
|
23235
|
+
if (target === "" || HAS_SCHEME.test(target)) {
|
|
23236
|
+
return whole;
|
|
23237
|
+
}
|
|
23238
|
+
const filePart = target.split(/[#?]/)[0] ?? "";
|
|
23239
|
+
if (filePart === "") {
|
|
23240
|
+
return label;
|
|
23241
|
+
}
|
|
23242
|
+
const resolved = path76.posix.normalize(filePart.startsWith("/") ? filePart.replace(/^\/+/, "") : path76.posix.join(readmeDir, filePart));
|
|
23243
|
+
const codePath = resolved.replace(/\/+$/, "");
|
|
23244
|
+
if (codePath === "" || codePath === "." || codePath === ".." || codePath.startsWith("../")) {
|
|
23245
|
+
return label;
|
|
23246
|
+
}
|
|
23247
|
+
const named = label.length > 0 ? `${label} (\`${codePath}\`)` : `\`${codePath}\``;
|
|
23248
|
+
if (bang === "!") {
|
|
23249
|
+
return named;
|
|
23250
|
+
}
|
|
23251
|
+
const moduleName = moduleOfTarget(filePart, codePath);
|
|
23252
|
+
const page = moduleName === null ? null : pageLink(moduleName);
|
|
23253
|
+
return page === null ? named : `[${label.length > 0 ? label : moduleName}](${page})`;
|
|
23254
|
+
});
|
|
23255
|
+
}
|
|
23256
|
+
function moduleOfTarget(filePart, codePath) {
|
|
23257
|
+
const base = path76.posix.basename(codePath);
|
|
23258
|
+
if (filePart.endsWith("/") || !/\.[A-Za-z0-9]+$/.test(base)) {
|
|
23259
|
+
return codePath;
|
|
23260
|
+
}
|
|
23261
|
+
if (DOC_ENTRY.test(base)) {
|
|
23262
|
+
const dir = path76.posix.dirname(codePath);
|
|
23263
|
+
return dir === "." ? null : dir;
|
|
23264
|
+
}
|
|
23265
|
+
return null;
|
|
23266
|
+
}
|
|
23267
|
+
function truncateMarkdown(text, max) {
|
|
23268
|
+
if (text.length <= max) {
|
|
23269
|
+
return text;
|
|
23270
|
+
}
|
|
23271
|
+
return text.slice(0, max).replace(/\s*!?\[[^\]]*$|\s*!?\[[^\]]*\]\([^)]*$/, "").trimEnd();
|
|
23272
|
+
}
|
|
23273
|
+
var MARKDOWN_LINK, HAS_SCHEME, DOC_ENTRY;
|
|
23274
|
+
var init_readme_links = __esm(() => {
|
|
23275
|
+
MARKDOWN_LINK = /(!?)\[([^[\]]*)\]\(\s*<?([^)\s>]*)>?(?:\s+(?:"[^"]*"|'[^']*'))?\s*\)/g;
|
|
23276
|
+
HAS_SCHEME = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
|
23277
|
+
DOC_ENTRY = /^(?:readme|index)\.(?:md|mdx)$/i;
|
|
23278
|
+
});
|
|
23279
|
+
|
|
23185
23280
|
// src/wiki/think-tags.ts
|
|
23186
23281
|
function maskCodeRegions(text) {
|
|
23187
23282
|
const maskMatch = (m) => "\x00".repeat(m.length);
|
|
@@ -23570,15 +23665,15 @@ __export(exports_service4, {
|
|
|
23570
23665
|
import { spawn as spawn3 } from "child_process";
|
|
23571
23666
|
import { createHash as createHash15 } from "crypto";
|
|
23572
23667
|
import { mkdir as mkdir20, readFile as readFile39, readdir as readdir13, writeFile as writeFile14 } from "fs/promises";
|
|
23573
|
-
import
|
|
23668
|
+
import path77 from "path";
|
|
23574
23669
|
function wikiRootPath3(cwd) {
|
|
23575
|
-
return
|
|
23670
|
+
return path77.join(cwd, ".metaproject", "wiki");
|
|
23576
23671
|
}
|
|
23577
23672
|
function dataRootPath(cwd) {
|
|
23578
|
-
return
|
|
23673
|
+
return path77.join(cwd, ".metaproject", "data", "gdwiki");
|
|
23579
23674
|
}
|
|
23580
23675
|
function linkCheckReportPath(cwd) {
|
|
23581
|
-
return
|
|
23676
|
+
return path77.join(dataRootPath(cwd), "link-check", "latest.md");
|
|
23582
23677
|
}
|
|
23583
23678
|
async function wikiStatus(cwd) {
|
|
23584
23679
|
const root = wikiRootPath3(cwd);
|
|
@@ -23586,7 +23681,7 @@ async function wikiStatus(cwd) {
|
|
|
23586
23681
|
const pages = enabled ? await collectPages(cwd) : [];
|
|
23587
23682
|
return {
|
|
23588
23683
|
enabled,
|
|
23589
|
-
wikiRoot:
|
|
23684
|
+
wikiRoot: path77.relative(cwd, root),
|
|
23590
23685
|
totalPages: pages.length,
|
|
23591
23686
|
countsByType: WIKI_PAGE_TYPES.map(({ type }) => ({
|
|
23592
23687
|
type,
|
|
@@ -23617,9 +23712,9 @@ async function wikiCreatePage(input) {
|
|
|
23617
23712
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(input.slug)) {
|
|
23618
23713
|
throw new Error(`Invalid slug: ${input.slug}. Use lowercase letters, digits, and hyphens.`);
|
|
23619
23714
|
}
|
|
23620
|
-
const dir =
|
|
23621
|
-
const filePath =
|
|
23622
|
-
const relativePath =
|
|
23715
|
+
const dir = path77.join(wikiRootPath3(input.cwd), typeConfig.folder);
|
|
23716
|
+
const filePath = path77.join(dir, `${input.slug}.md`);
|
|
23717
|
+
const relativePath = path77.relative(input.cwd, filePath);
|
|
23623
23718
|
if (await pathExists(filePath) && !input.force) {
|
|
23624
23719
|
throw new Error(`Page already exists: ${relativePath}. Use --force to overwrite.`);
|
|
23625
23720
|
}
|
|
@@ -23631,7 +23726,7 @@ async function wikiCreatePage(input) {
|
|
|
23631
23726
|
}
|
|
23632
23727
|
async function wikiGenerateIndex(cwd, history) {
|
|
23633
23728
|
const root = wikiRootPath3(cwd);
|
|
23634
|
-
const indexPath =
|
|
23729
|
+
const indexPath = path77.join(root, "index.md");
|
|
23635
23730
|
const pages = await collectPages(cwd);
|
|
23636
23731
|
const generatedAt = new Date().toISOString();
|
|
23637
23732
|
const managedBlock = `${WIKI_INDEX_BEGIN}
|
|
@@ -23648,7 +23743,7 @@ ${managedBlock}
|
|
|
23648
23743
|
`;
|
|
23649
23744
|
await writeWikiPage(history ?? await openWikiWriteContext(cwd, "wiki index"), indexPath, next);
|
|
23650
23745
|
return {
|
|
23651
|
-
path:
|
|
23746
|
+
path: path77.relative(cwd, indexPath),
|
|
23652
23747
|
pageCount: pages.length,
|
|
23653
23748
|
generatedAt
|
|
23654
23749
|
};
|
|
@@ -23656,13 +23751,13 @@ ${managedBlock}
|
|
|
23656
23751
|
async function wikiCheckLinks(cwd) {
|
|
23657
23752
|
const root = wikiRootPath3(cwd);
|
|
23658
23753
|
const allFiles = await pathExists(root) ? await walkMarkdown(root) : [];
|
|
23659
|
-
const files = allFiles.filter((absolutePath) => !
|
|
23754
|
+
const files = allFiles.filter((absolutePath) => !path77.relative(root, absolutePath).startsWith(`templates${path77.sep}`));
|
|
23660
23755
|
const broken = [];
|
|
23661
23756
|
let checkedLinks = 0;
|
|
23662
23757
|
let skippedExternal = 0;
|
|
23663
23758
|
for (const absolutePath of files) {
|
|
23664
23759
|
const content = await readFile39(absolutePath, "utf8");
|
|
23665
|
-
const pageRelative =
|
|
23760
|
+
const pageRelative = path77.relative(cwd, absolutePath);
|
|
23666
23761
|
for (const target of extractLinkTargets(content)) {
|
|
23667
23762
|
if (EXTERNAL_LINK.test(target)) {
|
|
23668
23763
|
skippedExternal += 1;
|
|
@@ -23673,7 +23768,7 @@ async function wikiCheckLinks(cwd) {
|
|
|
23673
23768
|
continue;
|
|
23674
23769
|
}
|
|
23675
23770
|
checkedLinks += 1;
|
|
23676
|
-
const resolved =
|
|
23771
|
+
const resolved = path77.resolve(path77.dirname(absolutePath), filePart);
|
|
23677
23772
|
if (!await pathExists(resolved)) {
|
|
23678
23773
|
broken.push({
|
|
23679
23774
|
page: pageRelative,
|
|
@@ -23685,7 +23780,7 @@ async function wikiCheckLinks(cwd) {
|
|
|
23685
23780
|
}
|
|
23686
23781
|
const generatedAt = new Date().toISOString();
|
|
23687
23782
|
const reportPath = linkCheckReportPath(cwd);
|
|
23688
|
-
await mkdir20(
|
|
23783
|
+
await mkdir20(path77.dirname(reportPath), { recursive: true });
|
|
23689
23784
|
await writeFile14(reportPath, renderLinkCheckReport({
|
|
23690
23785
|
generatedAt,
|
|
23691
23786
|
checkedPages: files.length,
|
|
@@ -23694,7 +23789,7 @@ async function wikiCheckLinks(cwd) {
|
|
|
23694
23789
|
broken
|
|
23695
23790
|
}), "utf8");
|
|
23696
23791
|
return {
|
|
23697
|
-
reportPath:
|
|
23792
|
+
reportPath: path77.relative(cwd, reportPath),
|
|
23698
23793
|
checkedPages: files.length,
|
|
23699
23794
|
checkedLinks,
|
|
23700
23795
|
skippedExternal,
|
|
@@ -23745,7 +23840,7 @@ async function wikiValidate(cwd) {
|
|
|
23745
23840
|
}
|
|
23746
23841
|
if (await isIndexStale(cwd, pages)) {
|
|
23747
23842
|
issues.push({
|
|
23748
|
-
page:
|
|
23843
|
+
page: path77.join(path77.relative(cwd, wikiRootPath3(cwd)), "index.md"),
|
|
23749
23844
|
kind: "index",
|
|
23750
23845
|
message: "index out of date, run `keryx wiki index`"
|
|
23751
23846
|
});
|
|
@@ -23791,7 +23886,7 @@ function collectCommandLabel(input) {
|
|
|
23791
23886
|
return ["wiki collect", ...flags].join(" ");
|
|
23792
23887
|
}
|
|
23793
23888
|
async function wikiPruneOrphans(cwd, history) {
|
|
23794
|
-
const componentsDir =
|
|
23889
|
+
const componentsDir = path77.join(wikiRootPath3(cwd), "components");
|
|
23795
23890
|
if (!await pathExists(componentsDir)) {
|
|
23796
23891
|
return { pruned: [], orphanedAccepted: [] };
|
|
23797
23892
|
}
|
|
@@ -23811,15 +23906,15 @@ async function wikiPruneOrphans(cwd, history) {
|
|
|
23811
23906
|
if (validSlugs.has(slug)) {
|
|
23812
23907
|
continue;
|
|
23813
23908
|
}
|
|
23814
|
-
const filePath =
|
|
23909
|
+
const filePath = path77.join(componentsDir, entry);
|
|
23815
23910
|
const current = await readFile39(filePath, "utf8");
|
|
23816
23911
|
const isUnmodifiedDraft = /\nStatus:\s*draft\s*\n/.test(current) && current.includes("Generated by `keryx wiki collect`");
|
|
23817
23912
|
if (isUnmodifiedDraft) {
|
|
23818
23913
|
run ??= history ?? await openWikiWriteContext(cwd, "wiki prune");
|
|
23819
23914
|
await deleteWikiPage(run, filePath);
|
|
23820
|
-
pruned.push(
|
|
23915
|
+
pruned.push(path77.relative(cwd, filePath));
|
|
23821
23916
|
} else {
|
|
23822
|
-
orphanedAccepted.push(
|
|
23917
|
+
orphanedAccepted.push(path77.relative(cwd, filePath));
|
|
23823
23918
|
}
|
|
23824
23919
|
}
|
|
23825
23920
|
return { pruned, orphanedAccepted };
|
|
@@ -23829,7 +23924,7 @@ async function validModuleNames(cwd) {
|
|
|
23829
23924
|
return counts === undefined ? undefined : new Set(counts.keys());
|
|
23830
23925
|
}
|
|
23831
23926
|
async function moduleFileCounts(cwd) {
|
|
23832
|
-
const nodesPath =
|
|
23927
|
+
const nodesPath = path77.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
|
|
23833
23928
|
if (!await pathExists(nodesPath)) {
|
|
23834
23929
|
return;
|
|
23835
23930
|
}
|
|
@@ -23900,9 +23995,9 @@ async function wikiEvidence(input) {
|
|
|
23900
23995
|
});
|
|
23901
23996
|
}
|
|
23902
23997
|
function resolveEvidenceScope(cwd, override) {
|
|
23903
|
-
const absolute =
|
|
23998
|
+
const absolute = path77.resolve(cwd);
|
|
23904
23999
|
return {
|
|
23905
|
-
projectId: override?.projectId ?? (
|
|
24000
|
+
projectId: override?.projectId ?? (path77.basename(absolute) || "project"),
|
|
23906
24001
|
checkoutId: override?.checkoutId ?? `checkout:${createHash15("sha256").update(absolute).digest("hex").slice(0, 16)}`,
|
|
23907
24002
|
...override?.workspaceId ? { workspaceId: override.workspaceId } : {},
|
|
23908
24003
|
...override?.taskId ? { taskId: override.taskId } : {}
|
|
@@ -23917,7 +24012,7 @@ function isMachineAuthoredPage(pageType, relativePath, content) {
|
|
|
23917
24012
|
if (source === null) {
|
|
23918
24013
|
return false;
|
|
23919
24014
|
}
|
|
23920
|
-
const normalised = relativePath.split(
|
|
24015
|
+
const normalised = relativePath.split(path77.sep).join("/").replace(/^wiki\//, "");
|
|
23921
24016
|
return WIKI_PAGE_PRODUCERS.some((producer) => producer.source === source && producer.pageType === pageType && producer.path.test(normalised) && /^-[ \t]+Link:.*\bsha256\b/m.test(content));
|
|
23922
24017
|
}
|
|
23923
24018
|
function createGdWikiService() {
|
|
@@ -23933,8 +24028,8 @@ function createGdWikiService() {
|
|
|
23933
24028
|
};
|
|
23934
24029
|
}
|
|
23935
24030
|
async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules) {
|
|
23936
|
-
const nodesPath =
|
|
23937
|
-
const edgesPath =
|
|
24031
|
+
const nodesPath = path77.join(cwd, ".metaproject", "data", "gdgraph", "storage", "nodes.jsonl");
|
|
24032
|
+
const edgesPath = path77.join(cwd, ".metaproject", "data", "gdgraph", "storage", "edges.jsonl");
|
|
23938
24033
|
if (!await pathExists(nodesPath) || !await pathExists(edgesPath)) {
|
|
23939
24034
|
return [];
|
|
23940
24035
|
}
|
|
@@ -24021,6 +24116,12 @@ async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules)
|
|
|
24021
24116
|
};
|
|
24022
24117
|
const moduleCandidates = [];
|
|
24023
24118
|
const pageModules = new Set(topModules.map((entry) => entry.name));
|
|
24119
|
+
const componentsDir = path77.join(wikiRootPath3(cwd), "components");
|
|
24120
|
+
const existingSlugs = new Set((await pathExists(componentsDir) ? await readdir13(componentsDir) : []).filter((entry) => entry.endsWith(".md")).map((entry) => entry.slice(0, -3)));
|
|
24121
|
+
const pageLink = (name) => {
|
|
24122
|
+
const slug = slugifyPath(name);
|
|
24123
|
+
return pageModules.has(name) || existingSlugs.has(slug) ? `${slug}.md` : null;
|
|
24124
|
+
};
|
|
24024
24125
|
for (const item of topModules) {
|
|
24025
24126
|
const moduleName = item.name;
|
|
24026
24127
|
const moduleFileList = moduleFiles.get(moduleName) ?? [];
|
|
@@ -24032,7 +24133,7 @@ async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules)
|
|
|
24032
24133
|
const entryFiles = moduleFileList.filter((file) => /(^|\/)index\.[jt]sx?$/.test(file)).slice(0, 4);
|
|
24033
24134
|
const deps = topCounts(moduleDeps.get(moduleName), 6);
|
|
24034
24135
|
const dependents = topCounts(moduleDependents.get(moduleName), 6);
|
|
24035
|
-
const readme = await readModuleReadme(cwd, moduleName);
|
|
24136
|
+
const readme = await readModuleReadme(cwd, moduleName, pageLink);
|
|
24036
24137
|
const exportsFrom = entryFiles.length > 0 ? entryFiles : keyFiles.slice(0, 2).map((entry) => entry.file);
|
|
24037
24138
|
const exportApi = await extractModuleApi(cwd, exportsFrom);
|
|
24038
24139
|
const reference = [];
|
|
@@ -24064,15 +24165,20 @@ async function collectGraphWikiCandidates(cwd, generatedAt, limit, onlyModules)
|
|
|
24064
24165
|
if (exportApi.length > 0) {
|
|
24065
24166
|
summaryParts.push("Exposes " + exportApi.length + " public symbol(s).");
|
|
24066
24167
|
}
|
|
24067
|
-
const
|
|
24168
|
+
const linkedNames = [];
|
|
24169
|
+
const unlinkedNames = [];
|
|
24068
24170
|
const seenRelated = new Set([moduleName]);
|
|
24069
24171
|
for (const [name] of [...deps, ...dependents]) {
|
|
24070
|
-
if (
|
|
24071
|
-
|
|
24072
|
-
relatedNames.push(name);
|
|
24172
|
+
if (seenRelated.has(name)) {
|
|
24173
|
+
continue;
|
|
24073
24174
|
}
|
|
24175
|
+
seenRelated.add(name);
|
|
24176
|
+
(pageLink(name) === null ? unlinkedNames : linkedNames).push(name);
|
|
24074
24177
|
}
|
|
24075
|
-
const related =
|
|
24178
|
+
const related = [
|
|
24179
|
+
...linkedNames.slice(0, 8).map((name) => ({ name, page: pageLink(name) })),
|
|
24180
|
+
...unlinkedNames.slice(0, 8).map((name) => ({ name, page: null }))
|
|
24181
|
+
];
|
|
24076
24182
|
moduleCandidates.push({
|
|
24077
24183
|
type: "component",
|
|
24078
24184
|
slug: slugifyPath(moduleName),
|
|
@@ -24117,8 +24223,8 @@ function topCounts(bucket, limit) {
|
|
|
24117
24223
|
}
|
|
24118
24224
|
return [...bucket.entries()].sort((a, b) => b[1] - a[1]).slice(0, limit);
|
|
24119
24225
|
}
|
|
24120
|
-
async function readModuleReadme(cwd, moduleName) {
|
|
24121
|
-
const readmePath =
|
|
24226
|
+
async function readModuleReadme(cwd, moduleName, pageLink) {
|
|
24227
|
+
const readmePath = path77.join(cwd, ...moduleName.split("/"), "README.md");
|
|
24122
24228
|
if (!await pathExists(readmePath)) {
|
|
24123
24229
|
return null;
|
|
24124
24230
|
}
|
|
@@ -24128,7 +24234,7 @@ async function readModuleReadme(cwd, moduleName) {
|
|
|
24128
24234
|
if (!paragraph) {
|
|
24129
24235
|
return null;
|
|
24130
24236
|
}
|
|
24131
|
-
const normalized = paragraph.replace(/\s+/g, " ")
|
|
24237
|
+
const normalized = truncateMarkdown(rewriteReadmeLinks(paragraph.replace(/\s+/g, " "), moduleName, pageLink), 400);
|
|
24132
24238
|
return "- " + normalized + " (from module README)";
|
|
24133
24239
|
} catch {
|
|
24134
24240
|
return null;
|
|
@@ -24139,7 +24245,7 @@ async function extractModuleExports(cwd, files) {
|
|
|
24139
24245
|
const declRe = /export\s+(?:async\s+)?(?:default\s+)?(?:const|let|var|function|class|type|interface|enum)\s+([A-Za-z_$][\w$]*)/g;
|
|
24140
24246
|
const braceRe = /export\s*\{([^}]+)\}/g;
|
|
24141
24247
|
for (const file of files.slice(0, 4)) {
|
|
24142
|
-
const filePath =
|
|
24248
|
+
const filePath = path77.join(cwd, ...file.split("/"));
|
|
24143
24249
|
if (!await pathExists(filePath)) {
|
|
24144
24250
|
continue;
|
|
24145
24251
|
}
|
|
@@ -24170,7 +24276,7 @@ async function extractModuleExports(cwd, files) {
|
|
|
24170
24276
|
}
|
|
24171
24277
|
async function extractModuleApi(cwd, files) {
|
|
24172
24278
|
const names = await extractModuleExports(cwd, files);
|
|
24173
|
-
const symbolsPath =
|
|
24279
|
+
const symbolsPath = path77.join(cwd, ".metaproject", "data", "gdgraph", "storage", "symbols.jsonl");
|
|
24174
24280
|
if (names.length === 0 || !await pathExists(symbolsPath)) {
|
|
24175
24281
|
return names.map((name) => "`" + name + "`");
|
|
24176
24282
|
}
|
|
@@ -24196,7 +24302,7 @@ async function extractModuleApi(cwd, files) {
|
|
|
24196
24302
|
});
|
|
24197
24303
|
}
|
|
24198
24304
|
async function collectHealthWikiCandidates(cwd, generatedAt) {
|
|
24199
|
-
const healthPath =
|
|
24305
|
+
const healthPath = path77.join(cwd, ".metaproject", "data", "health", "artifacts", "latest.json");
|
|
24200
24306
|
if (!await pathExists(healthPath)) {
|
|
24201
24307
|
return [];
|
|
24202
24308
|
}
|
|
@@ -24238,7 +24344,7 @@ async function collectHealthWikiCandidates(cwd, generatedAt) {
|
|
|
24238
24344
|
}];
|
|
24239
24345
|
}
|
|
24240
24346
|
async function collectTestingWikiCandidates(cwd, generatedAt) {
|
|
24241
|
-
const contextPath =
|
|
24347
|
+
const contextPath = path77.join(cwd, ".metaproject", "data", "testing", "context.md");
|
|
24242
24348
|
if (!await pathExists(contextPath)) {
|
|
24243
24349
|
return [];
|
|
24244
24350
|
}
|
|
@@ -24269,8 +24375,8 @@ async function writeCollectedPage(cwd, candidate, force, history) {
|
|
|
24269
24375
|
if (!folder) {
|
|
24270
24376
|
throw new Error(`Unsupported collected wiki type: ${candidate.type}`);
|
|
24271
24377
|
}
|
|
24272
|
-
const filePath =
|
|
24273
|
-
const relativePath =
|
|
24378
|
+
const filePath = path77.join(wikiRootPath3(cwd), folder, `${candidate.slug}.md`);
|
|
24379
|
+
const relativePath = path77.relative(cwd, filePath);
|
|
24274
24380
|
const exists = await pathExists(filePath);
|
|
24275
24381
|
if (exists && !force) {
|
|
24276
24382
|
return { path: relativePath, type: candidate.type, source: candidate.source, action: "skipped" };
|
|
@@ -24321,7 +24427,7 @@ async function writeCollectedPage(cwd, candidate, force, history) {
|
|
|
24321
24427
|
async function wikiPagesForFile(cwd, targetRepoPath) {
|
|
24322
24428
|
const pages = await collectPages(cwd);
|
|
24323
24429
|
const refs = await Promise.all(pages.map(async (page) => ({
|
|
24324
|
-
repoPath:
|
|
24430
|
+
repoPath: path77.relative(cwd, page.absolutePath).split(path77.sep).join("/"),
|
|
24325
24431
|
content: await readFile39(page.absolutePath, "utf8")
|
|
24326
24432
|
})));
|
|
24327
24433
|
return backlinksFor(buildBacklinkIndex(refs), targetRepoPath);
|
|
@@ -24360,7 +24466,7 @@ function renderIndexBody(pages, generatedAt) {
|
|
|
24360
24466
|
`).trimEnd();
|
|
24361
24467
|
}
|
|
24362
24468
|
async function isIndexStale(cwd, pages) {
|
|
24363
|
-
const indexPath =
|
|
24469
|
+
const indexPath = path77.join(wikiRootPath3(cwd), "index.md");
|
|
24364
24470
|
if (!await pathExists(indexPath)) {
|
|
24365
24471
|
return true;
|
|
24366
24472
|
}
|
|
@@ -24378,7 +24484,7 @@ async function walkMarkdown(root) {
|
|
|
24378
24484
|
const results = [];
|
|
24379
24485
|
const entries = await readdir13(root, { withFileTypes: true });
|
|
24380
24486
|
for (const entry of entries) {
|
|
24381
|
-
const absolutePath =
|
|
24487
|
+
const absolutePath = path77.join(root, entry.name);
|
|
24382
24488
|
if (entry.isDirectory()) {
|
|
24383
24489
|
results.push(...await walkMarkdown(absolutePath));
|
|
24384
24490
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
@@ -24435,7 +24541,7 @@ ${JSON.stringify(state, null, 2)}
|
|
|
24435
24541
|
`;
|
|
24436
24542
|
}
|
|
24437
24543
|
async function readIndexGeneratedAt(cwd) {
|
|
24438
|
-
const indexPath =
|
|
24544
|
+
const indexPath = path77.join(wikiRootPath3(cwd), "index.md");
|
|
24439
24545
|
if (!await pathExists(indexPath)) {
|
|
24440
24546
|
return null;
|
|
24441
24547
|
}
|
|
@@ -24518,10 +24624,11 @@ ${reference.join(`
|
|
|
24518
24624
|
## Related Wiki
|
|
24519
24625
|
|
|
24520
24626
|
Graph-derived - regenerated by \`keryx wiki collect --force\`. Only pages that
|
|
24521
|
-
exist are linked
|
|
24627
|
+
exist are linked, other modules are named as code paths; when enriching, add
|
|
24628
|
+
new links only to pages you have verified.
|
|
24522
24629
|
|
|
24523
24630
|
- [Wiki Index](../index.md)
|
|
24524
|
-
${related.map((entry) => "- [Module " + entry.name + "](" + entry.
|
|
24631
|
+
${related.map((entry) => entry.page === null ? "- `" + entry.name + "` (no wiki page)" : "- [Module " + entry.name + "](" + entry.page + ")").join(`
|
|
24525
24632
|
`)}
|
|
24526
24633
|
|
|
24527
24634
|
## Changelog
|
|
@@ -24672,7 +24779,7 @@ async function validateStructure(cwd, pages, issues) {
|
|
|
24672
24779
|
if (pattern.includes("*")) {
|
|
24673
24780
|
continue;
|
|
24674
24781
|
}
|
|
24675
|
-
if (!await pathExists(
|
|
24782
|
+
if (!await pathExists(path77.join(cwd, pattern))) {
|
|
24676
24783
|
issues.push({
|
|
24677
24784
|
page: page.relativePath,
|
|
24678
24785
|
kind: "describes",
|
|
@@ -24742,7 +24849,7 @@ async function validatePageInvariants(cwd, pages, issues) {
|
|
|
24742
24849
|
}
|
|
24743
24850
|
}
|
|
24744
24851
|
function toPosixPath(value) {
|
|
24745
|
-
return value.split(
|
|
24852
|
+
return value.split(path77.sep).join("/");
|
|
24746
24853
|
}
|
|
24747
24854
|
function compareSemver(a, b) {
|
|
24748
24855
|
const pa = a.split(".").map(Number);
|
|
@@ -24764,6 +24871,7 @@ var init_service4 = __esm(() => {
|
|
|
24764
24871
|
init_evidence();
|
|
24765
24872
|
init_history();
|
|
24766
24873
|
init_page_invariants();
|
|
24874
|
+
init_readme_links();
|
|
24767
24875
|
init_section_index();
|
|
24768
24876
|
init_section_tombstone();
|
|
24769
24877
|
init_staleness2();
|
|
@@ -24785,9 +24893,9 @@ var init_service4 = __esm(() => {
|
|
|
24785
24893
|
// src/gdgraph/wiki-layer.ts
|
|
24786
24894
|
import { createHash as createHash16 } from "crypto";
|
|
24787
24895
|
import { mkdir as mkdir21, stat as stat12, writeFile as writeFile15 } from "fs/promises";
|
|
24788
|
-
import
|
|
24896
|
+
import path78 from "path";
|
|
24789
24897
|
function storageDir(projectRoot) {
|
|
24790
|
-
return
|
|
24898
|
+
return path78.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
|
|
24791
24899
|
}
|
|
24792
24900
|
function wikiPageId(relativePath) {
|
|
24793
24901
|
return `wiki:${relativePath}`;
|
|
@@ -24853,11 +24961,11 @@ async function enrichBuildWithWikiLayer(input) {
|
|
|
24853
24961
|
const mtimes = new Map;
|
|
24854
24962
|
for (const record of input.fileRecords) {
|
|
24855
24963
|
try {
|
|
24856
|
-
const info = await stat12(
|
|
24964
|
+
const info = await stat12(path78.join(input.projectRoot, record.path));
|
|
24857
24965
|
mtimes.set(record.path, info.mtimeMs);
|
|
24858
24966
|
} catch {}
|
|
24859
24967
|
}
|
|
24860
|
-
await writeFile15(
|
|
24968
|
+
await writeFile15(path78.join(dir, BUILD_MANIFEST_FILE), `${JSON.stringify({ version: 1, files: computeFingerprints(input.fileRecords, mtimes) }, null, 2)}
|
|
24861
24969
|
`, "utf8");
|
|
24862
24970
|
const validModules = input.validModules !== undefined ? input.validModules : await (input.loadValidModules ?? defaultLoadValidModules)(input.projectRoot);
|
|
24863
24971
|
const wikiPages = await collectPages(input.projectRoot);
|
|
@@ -24882,8 +24990,8 @@ async function enrichBuildWithWikiLayer(input) {
|
|
|
24882
24990
|
version: page.version
|
|
24883
24991
|
}))
|
|
24884
24992
|
});
|
|
24885
|
-
await writeJsonl(
|
|
24886
|
-
await writeJsonl(
|
|
24993
|
+
await writeJsonl(path78.join(dir, WIKI_PAGES_FILE), layer.pages);
|
|
24994
|
+
await writeJsonl(path78.join(dir, DESCRIBES_FILE), layer.describes);
|
|
24887
24995
|
return layer;
|
|
24888
24996
|
}
|
|
24889
24997
|
async function defaultLoadValidModules(projectRoot) {
|
|
@@ -24901,7 +25009,7 @@ var init_wiki_layer = __esm(() => {
|
|
|
24901
25009
|
// src/gdskills/contracts.ts
|
|
24902
25010
|
import { readFile as readFile51 } from "fs/promises";
|
|
24903
25011
|
import { existsSync as existsSync15 } from "fs";
|
|
24904
|
-
import
|
|
25012
|
+
import path106 from "path";
|
|
24905
25013
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
24906
25014
|
async function loadSchema(name) {
|
|
24907
25015
|
const contract = CONTRACTS.find((entry) => entry.name === name);
|
|
@@ -24912,10 +25020,10 @@ async function loadSchema(name) {
|
|
|
24912
25020
|
return JSON.parse(raw);
|
|
24913
25021
|
}
|
|
24914
25022
|
function contractPath(contract) {
|
|
24915
|
-
const here =
|
|
25023
|
+
const here = path106.dirname(fileURLToPath2(import.meta.url));
|
|
24916
25024
|
if (contract.sourcePath) {
|
|
24917
|
-
for (const root of [
|
|
24918
|
-
const candidate =
|
|
25025
|
+
for (const root of [path106.join(here, "..", ".."), path106.join(here, ".."), here]) {
|
|
25026
|
+
const candidate = path106.resolve(root, contract.sourcePath);
|
|
24919
25027
|
if (existsSync15(candidate)) {
|
|
24920
25028
|
return candidate;
|
|
24921
25029
|
}
|
|
@@ -24925,7 +25033,7 @@ function contractPath(contract) {
|
|
|
24925
25033
|
if (existsSync15(directPath)) {
|
|
24926
25034
|
return directPath;
|
|
24927
25035
|
}
|
|
24928
|
-
const packagedSourcePath =
|
|
25036
|
+
const packagedSourcePath = path106.join(here, "..", "src", "gdskills", "contracts", contract.fileName);
|
|
24929
25037
|
if (existsSync15(packagedSourcePath)) {
|
|
24930
25038
|
return packagedSourcePath;
|
|
24931
25039
|
}
|
|
@@ -29959,7 +30067,7 @@ __export(exports_service5, {
|
|
|
29959
30067
|
// src/gdgraph/build.ts
|
|
29960
30068
|
import { mkdir as mkdir22, readdir as readdir14, readFile as readFile40, writeFile as writeFile16 } from "fs/promises";
|
|
29961
30069
|
import { existsSync as existsSync7 } from "fs";
|
|
29962
|
-
import
|
|
30070
|
+
import path79 from "path";
|
|
29963
30071
|
|
|
29964
30072
|
// src/gdgraph/types.ts
|
|
29965
30073
|
var UNKNOWN_IMPORT_KIND = "unknown-static";
|
|
@@ -30024,7 +30132,7 @@ async function buildGraph(projectRoot) {
|
|
|
30024
30132
|
const assetNodes = new Map;
|
|
30025
30133
|
const fileRecords = [];
|
|
30026
30134
|
for (const file of files) {
|
|
30027
|
-
const absolutePath =
|
|
30135
|
+
const absolutePath = path79.join(projectRoot, file);
|
|
30028
30136
|
const content = await readFile40(absolutePath, "utf8");
|
|
30029
30137
|
fileRecords.push({ path: file, content });
|
|
30030
30138
|
const language = getLanguage(file);
|
|
@@ -30077,24 +30185,24 @@ async function collectSourceFiles(projectRoot) {
|
|
|
30077
30185
|
const result = [];
|
|
30078
30186
|
const skippedDirectories = [];
|
|
30079
30187
|
async function walk(relativeDir) {
|
|
30080
|
-
const absoluteDir =
|
|
30188
|
+
const absoluteDir = path79.join(projectRoot, relativeDir);
|
|
30081
30189
|
const entries = await readdir14(absoluteDir, { withFileTypes: true });
|
|
30082
30190
|
for (const entry of entries) {
|
|
30083
30191
|
if (entry.isDirectory()) {
|
|
30084
30192
|
if (IGNORE_DIRS.has(entry.name)) {
|
|
30085
|
-
skippedDirectories.push(normalizePath2(
|
|
30193
|
+
skippedDirectories.push(normalizePath2(path79.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
|
|
30086
30194
|
continue;
|
|
30087
30195
|
}
|
|
30088
|
-
await walk(normalizePath2(
|
|
30196
|
+
await walk(normalizePath2(path79.posix.join(relativeDir, entry.name)));
|
|
30089
30197
|
continue;
|
|
30090
30198
|
}
|
|
30091
30199
|
if (!entry.isFile()) {
|
|
30092
30200
|
continue;
|
|
30093
30201
|
}
|
|
30094
|
-
if (!SOURCE_EXTENSIONS.includes(
|
|
30202
|
+
if (!SOURCE_EXTENSIONS.includes(path79.extname(entry.name))) {
|
|
30095
30203
|
continue;
|
|
30096
30204
|
}
|
|
30097
|
-
result.push(normalizePath2(
|
|
30205
|
+
result.push(normalizePath2(path79.posix.join(relativeDir, entry.name)).replace(/^\.\//, ""));
|
|
30098
30206
|
}
|
|
30099
30207
|
}
|
|
30100
30208
|
await walk(".");
|
|
@@ -30176,8 +30284,8 @@ function resolveImport(projectRoot, fromFile, specifier, fileSet, resolver) {
|
|
|
30176
30284
|
}
|
|
30177
30285
|
function resolveAssetImport(projectRoot, fromFile, specifier, resolver) {
|
|
30178
30286
|
for (const candidate of importCandidateBases(projectRoot, fromFile, specifier, resolver)) {
|
|
30179
|
-
const extension =
|
|
30180
|
-
if (ASSET_EXTENSIONS.includes(extension) && existsSync7(
|
|
30287
|
+
const extension = path79.posix.extname(candidate);
|
|
30288
|
+
if (ASSET_EXTENSIONS.includes(extension) && existsSync7(path79.join(projectRoot, candidate))) {
|
|
30181
30289
|
return candidate;
|
|
30182
30290
|
}
|
|
30183
30291
|
}
|
|
@@ -30186,17 +30294,17 @@ function resolveAssetImport(projectRoot, fromFile, specifier, resolver) {
|
|
|
30186
30294
|
function importCandidateBases(projectRoot, fromFile, specifier, resolver) {
|
|
30187
30295
|
const normalizedSpecifier = stripImportSuffix(specifier);
|
|
30188
30296
|
if (normalizedSpecifier.startsWith(".") && getLanguage(fromFile) !== "python") {
|
|
30189
|
-
const fromDir =
|
|
30190
|
-
return [normalizePath2(
|
|
30297
|
+
const fromDir = path79.posix.dirname(fromFile);
|
|
30298
|
+
return [normalizePath2(path79.posix.normalize(path79.posix.join(fromDir, normalizedSpecifier)))];
|
|
30191
30299
|
}
|
|
30192
|
-
return resolver.candidateBases(normalizedSpecifier, fromFile).map((candidate) => normalizePath2(
|
|
30300
|
+
return resolver.candidateBases(normalizedSpecifier, fromFile).map((candidate) => normalizePath2(path79.relative(projectRoot, path79.join(projectRoot, candidate))));
|
|
30193
30301
|
}
|
|
30194
30302
|
function resolveSourceCandidate(base, fileSet) {
|
|
30195
30303
|
const candidates = [
|
|
30196
30304
|
base,
|
|
30197
30305
|
...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => `${base}${extension}`),
|
|
30198
|
-
...SOURCE_RESOLUTION_EXTENSIONS.map((extension) =>
|
|
30199
|
-
|
|
30306
|
+
...SOURCE_RESOLUTION_EXTENSIONS.map((extension) => path79.posix.join(base, `index${extension}`)),
|
|
30307
|
+
path79.posix.join(base, "__init__.py")
|
|
30200
30308
|
];
|
|
30201
30309
|
return candidates.find((candidate) => fileSet.has(candidate)) ?? null;
|
|
30202
30310
|
}
|
|
@@ -30226,7 +30334,7 @@ async function loadJavaResolver(projectRoot) {
|
|
|
30226
30334
|
return createJavaResolver(roots);
|
|
30227
30335
|
}
|
|
30228
30336
|
async function discoverJavaSourceRoots(projectRoot) {
|
|
30229
|
-
const pomPath =
|
|
30337
|
+
const pomPath = path79.join(projectRoot, "pom.xml");
|
|
30230
30338
|
if (existsSync7(pomPath)) {
|
|
30231
30339
|
try {
|
|
30232
30340
|
const roots = parseMavenSourceRoots(await readFile40(pomPath, "utf8"));
|
|
@@ -30236,7 +30344,7 @@ async function discoverJavaSourceRoots(projectRoot) {
|
|
|
30236
30344
|
} catch {}
|
|
30237
30345
|
}
|
|
30238
30346
|
for (const gradleName of ["build.gradle", "build.gradle.kts"]) {
|
|
30239
|
-
const gradlePath =
|
|
30347
|
+
const gradlePath = path79.join(projectRoot, gradleName);
|
|
30240
30348
|
if (existsSync7(gradlePath)) {
|
|
30241
30349
|
try {
|
|
30242
30350
|
const roots = parseGradleSourceRoots(await readFile40(gradlePath, "utf8"));
|
|
@@ -30258,12 +30366,12 @@ function createJavaResolver(sourceRoots) {
|
|
|
30258
30366
|
return [];
|
|
30259
30367
|
}
|
|
30260
30368
|
const relative = specifier.split(".").join("/");
|
|
30261
|
-
return sourceRoots.map((root) => normalizePath2(
|
|
30369
|
+
return sourceRoots.map((root) => normalizePath2(path79.posix.join(root, relative)));
|
|
30262
30370
|
}
|
|
30263
30371
|
};
|
|
30264
30372
|
}
|
|
30265
30373
|
function loadPythonResolver(projectRoot) {
|
|
30266
|
-
const hasSrc = existsSync7(
|
|
30374
|
+
const hasSrc = existsSync7(path79.join(projectRoot, "src"));
|
|
30267
30375
|
return createPythonResolver(hasSrc);
|
|
30268
30376
|
}
|
|
30269
30377
|
function createPythonResolver(hasSrc) {
|
|
@@ -30276,16 +30384,16 @@ function createPythonResolver(hasSrc) {
|
|
|
30276
30384
|
if (specifier.startsWith(".")) {
|
|
30277
30385
|
const dots = /^\.+/.exec(specifier)?.[0].length ?? 0;
|
|
30278
30386
|
const rest = specifier.slice(dots);
|
|
30279
|
-
let baseDir =
|
|
30387
|
+
let baseDir = path79.posix.dirname(fromFile);
|
|
30280
30388
|
for (let level = 1;level < dots; level += 1) {
|
|
30281
|
-
baseDir =
|
|
30389
|
+
baseDir = path79.posix.dirname(baseDir);
|
|
30282
30390
|
}
|
|
30283
30391
|
const suffix = rest ? rest.split(".").join("/") : "";
|
|
30284
|
-
const base = suffix ?
|
|
30392
|
+
const base = suffix ? path79.posix.join(baseDir, suffix) : baseDir;
|
|
30285
30393
|
return [normalizePath2(base)];
|
|
30286
30394
|
}
|
|
30287
30395
|
const relative = specifier.split(".").join("/");
|
|
30288
|
-
return roots.map((root) => normalizePath2(root ?
|
|
30396
|
+
return roots.map((root) => normalizePath2(root ? path79.posix.join(root, relative) : relative));
|
|
30289
30397
|
}
|
|
30290
30398
|
};
|
|
30291
30399
|
}
|
|
@@ -30294,8 +30402,8 @@ function parseMavenSourceRoots(pomXml) {
|
|
|
30294
30402
|
for (const match of pomXml.matchAll(/<module>\s*([^<]+?)\s*<\/module>/g)) {
|
|
30295
30403
|
const moduleDir = match[1]?.trim();
|
|
30296
30404
|
if (moduleDir && !moduleDir.includes("${")) {
|
|
30297
|
-
roots.add(normalizePath2(
|
|
30298
|
-
roots.add(normalizePath2(
|
|
30405
|
+
roots.add(normalizePath2(path79.posix.join(moduleDir, "src/main/java")));
|
|
30406
|
+
roots.add(normalizePath2(path79.posix.join(moduleDir, "src/test/java")));
|
|
30299
30407
|
}
|
|
30300
30408
|
}
|
|
30301
30409
|
for (const tag of ["sourceDirectory", "testSourceDirectory"]) {
|
|
@@ -30328,7 +30436,7 @@ function parseGradleSourceRoots(buildGradle) {
|
|
|
30328
30436
|
var TSCONFIG_EXTENDS_MAX_DEPTH = 10;
|
|
30329
30437
|
async function loadTsconfigResolver(projectRoot) {
|
|
30330
30438
|
const empty = createTsconfigResolver(null, []);
|
|
30331
|
-
const tsconfigPath =
|
|
30439
|
+
const tsconfigPath = path79.join(projectRoot, "tsconfig.json");
|
|
30332
30440
|
if (!existsSync7(tsconfigPath)) {
|
|
30333
30441
|
return empty;
|
|
30334
30442
|
}
|
|
@@ -30341,7 +30449,7 @@ async function loadTsconfigResolver(projectRoot) {
|
|
|
30341
30449
|
return createTsconfigResolver(resolved.baseUrl, paths);
|
|
30342
30450
|
}
|
|
30343
30451
|
function toProjectRelativeDir(projectRoot, absoluteDir) {
|
|
30344
|
-
const relative = normalizePath2(
|
|
30452
|
+
const relative = normalizePath2(path79.relative(projectRoot, absoluteDir)).replace(/^\.\//, "");
|
|
30345
30453
|
return relative === "." ? "" : relative;
|
|
30346
30454
|
}
|
|
30347
30455
|
async function readTsconfigJson(configPath) {
|
|
@@ -30356,11 +30464,11 @@ function resolveTsconfigExtendsPath(configDir, extendsSpecifier) {
|
|
|
30356
30464
|
if (!extendsSpecifier.startsWith(".") && !extendsSpecifier.startsWith("/")) {
|
|
30357
30465
|
return null;
|
|
30358
30466
|
}
|
|
30359
|
-
const resolved =
|
|
30467
|
+
const resolved = path79.resolve(configDir, extendsSpecifier);
|
|
30360
30468
|
return resolved.endsWith(".json") ? resolved : `${resolved}.json`;
|
|
30361
30469
|
}
|
|
30362
30470
|
async function resolveTsconfigOptions(configPath, visited, depth, projectRoot) {
|
|
30363
|
-
const resolvedPath =
|
|
30471
|
+
const resolvedPath = path79.resolve(configPath);
|
|
30364
30472
|
if (depth > TSCONFIG_EXTENDS_MAX_DEPTH || visited.has(resolvedPath)) {
|
|
30365
30473
|
return null;
|
|
30366
30474
|
}
|
|
@@ -30371,15 +30479,15 @@ async function resolveTsconfigOptions(configPath, visited, depth, projectRoot) {
|
|
|
30371
30479
|
}
|
|
30372
30480
|
let inherited = null;
|
|
30373
30481
|
if (typeof parsed.extends === "string") {
|
|
30374
|
-
const basePath = resolveTsconfigExtendsPath(
|
|
30482
|
+
const basePath = resolveTsconfigExtendsPath(path79.dirname(resolvedPath), parsed.extends);
|
|
30375
30483
|
if (basePath) {
|
|
30376
30484
|
inherited = await resolveTsconfigOptions(basePath, visited, depth + 1, projectRoot);
|
|
30377
30485
|
}
|
|
30378
30486
|
}
|
|
30379
|
-
const configDir =
|
|
30487
|
+
const configDir = path79.dirname(resolvedPath);
|
|
30380
30488
|
const declaringDir = toProjectRelativeDir(projectRoot, configDir);
|
|
30381
30489
|
const options = parsed.compilerOptions ?? {};
|
|
30382
|
-
const ownBaseUrl = typeof options.baseUrl === "string" ? toProjectRelativeDir(projectRoot,
|
|
30490
|
+
const ownBaseUrl = typeof options.baseUrl === "string" ? toProjectRelativeDir(projectRoot, path79.resolve(configDir, options.baseUrl)) : null;
|
|
30383
30491
|
const baseUrl = ownBaseUrl ?? inherited?.baseUrl ?? null;
|
|
30384
30492
|
const ownPaths = isRecord4(options.paths) ? Object.entries(options.paths).filter((entry) => Array.isArray(entry[1])).map(([pattern, targets]) => ({
|
|
30385
30493
|
pattern,
|
|
@@ -30408,7 +30516,7 @@ function createTsconfigResolver(baseUrl, mappings) {
|
|
|
30408
30516
|
}
|
|
30409
30517
|
}
|
|
30410
30518
|
if (baseUrl !== null) {
|
|
30411
|
-
candidates.push(normalizePath2(
|
|
30519
|
+
candidates.push(normalizePath2(path79.posix.join(baseUrl, normalizedSpecifier)));
|
|
30412
30520
|
}
|
|
30413
30521
|
return [...new Set(candidates.map((candidate) => candidate.replace(/^\.\//, "")))];
|
|
30414
30522
|
}
|
|
@@ -30428,7 +30536,7 @@ function matchPathPattern(pattern, specifier) {
|
|
|
30428
30536
|
}
|
|
30429
30537
|
function applyPathTarget(base, target, wildcard) {
|
|
30430
30538
|
const replaced = target.includes("*") ? target.replace("*", wildcard) : target;
|
|
30431
|
-
return normalizePath2(
|
|
30539
|
+
return normalizePath2(path79.posix.normalize(path79.posix.join(base, replaced)));
|
|
30432
30540
|
}
|
|
30433
30541
|
function stripJsonComments(source) {
|
|
30434
30542
|
let out = "";
|
|
@@ -30481,21 +30589,21 @@ function isRecord4(value) {
|
|
|
30481
30589
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30482
30590
|
}
|
|
30483
30591
|
async function writeGraph(projectRoot, graph) {
|
|
30484
|
-
const storageDir =
|
|
30485
|
-
const artifactsDir =
|
|
30592
|
+
const storageDir = path79.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
|
|
30593
|
+
const artifactsDir = path79.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
|
|
30486
30594
|
await mkdir22(storageDir, { recursive: true });
|
|
30487
30595
|
await mkdir22(artifactsDir, { recursive: true });
|
|
30488
|
-
await writeFile16(
|
|
30596
|
+
await writeFile16(path79.join(storageDir, "nodes.jsonl"), graph.nodes.map((node) => JSON.stringify(node)).join(`
|
|
30489
30597
|
`) + `
|
|
30490
30598
|
`, "utf8");
|
|
30491
|
-
await writeFile16(
|
|
30599
|
+
await writeFile16(path79.join(storageDir, "edges.jsonl"), graph.edges.map((edge) => JSON.stringify(edge)).join(`
|
|
30492
30600
|
`) + `
|
|
30493
30601
|
`, "utf8");
|
|
30494
|
-
await writeFile16(
|
|
30602
|
+
await writeFile16(path79.join(artifactsDir, "module-map.json"), JSON.stringify(buildModuleMap(graph), null, 2) + `
|
|
30495
30603
|
`, "utf8");
|
|
30496
30604
|
}
|
|
30497
30605
|
async function writeSummary(projectRoot, graph, collection) {
|
|
30498
|
-
const artifactsDir =
|
|
30606
|
+
const artifactsDir = path79.join(projectRoot, ".metaproject", "data", "gdgraph", "artifacts");
|
|
30499
30607
|
await mkdir22(artifactsDir, { recursive: true });
|
|
30500
30608
|
const unresolved = graph.edges.filter((edge) => edge.kind === "unresolved");
|
|
30501
30609
|
const imports = graph.edges.filter((edge) => edge.kind === "imports");
|
|
@@ -30510,7 +30618,7 @@ async function writeSummary(projectRoot, graph, collection) {
|
|
|
30510
30618
|
`);
|
|
30511
30619
|
const skippedList = collection.skippedDirectories.length > 0 ? collection.skippedDirectories.slice(0, 30).map((dir) => `- \`${dir}\``).join(`
|
|
30512
30620
|
`) : "- none";
|
|
30513
|
-
const summaryPath =
|
|
30621
|
+
const summaryPath = path79.join(artifactsDir, "summary.md");
|
|
30514
30622
|
const content = `# gdgraph Summary
|
|
30515
30623
|
|
|
30516
30624
|
## Stats
|
|
@@ -30591,7 +30699,7 @@ function groupBy(items, getKey) {
|
|
|
30591
30699
|
}
|
|
30592
30700
|
function unresolvedType(specifier) {
|
|
30593
30701
|
const stripped = stripImportSuffix(specifier);
|
|
30594
|
-
const extension =
|
|
30702
|
+
const extension = path79.posix.extname(stripped);
|
|
30595
30703
|
if (extension) {
|
|
30596
30704
|
return extension;
|
|
30597
30705
|
}
|
|
@@ -30601,13 +30709,13 @@ function unresolvedType(specifier) {
|
|
|
30601
30709
|
return "package";
|
|
30602
30710
|
}
|
|
30603
30711
|
function normalizePath2(value) {
|
|
30604
|
-
return value.split(
|
|
30712
|
+
return value.split(path79.sep).join("/");
|
|
30605
30713
|
}
|
|
30606
30714
|
|
|
30607
30715
|
// src/gdgraph/target.ts
|
|
30608
|
-
import
|
|
30716
|
+
import path80 from "path";
|
|
30609
30717
|
function normalizeTarget(target) {
|
|
30610
|
-
return target.replace(/^\.\//, "").split(
|
|
30718
|
+
return target.replace(/^\.\//, "").split(path80.sep).join("/");
|
|
30611
30719
|
}
|
|
30612
30720
|
function resolveGraphTarget(graph, target) {
|
|
30613
30721
|
const normalized = normalizeTarget(target);
|
|
@@ -30700,15 +30808,15 @@ init_config3();
|
|
|
30700
30808
|
|
|
30701
30809
|
// src/gdgraph/query.ts
|
|
30702
30810
|
import { readFile as readFile41 } from "fs/promises";
|
|
30703
|
-
import
|
|
30811
|
+
import path81 from "path";
|
|
30704
30812
|
async function loadGraph(projectRoot) {
|
|
30705
|
-
const storageDir =
|
|
30706
|
-
const nodes = await readJsonl(
|
|
30707
|
-
const edges = await readJsonl(
|
|
30708
|
-
const symbols = await readJsonl(
|
|
30709
|
-
const calls = await readJsonl(
|
|
30710
|
-
const wikiPages = await readJsonl(
|
|
30711
|
-
const describes = await readJsonl(
|
|
30813
|
+
const storageDir = path81.join(projectRoot, ".metaproject", "data", "gdgraph", "storage");
|
|
30814
|
+
const nodes = await readJsonl(path81.join(storageDir, "nodes.jsonl"));
|
|
30815
|
+
const edges = await readJsonl(path81.join(storageDir, "edges.jsonl"));
|
|
30816
|
+
const symbols = await readJsonl(path81.join(storageDir, "symbols.jsonl"));
|
|
30817
|
+
const calls = await readJsonl(path81.join(storageDir, "calls.jsonl"));
|
|
30818
|
+
const wikiPages = await readJsonl(path81.join(storageDir, "wiki-pages.jsonl"));
|
|
30819
|
+
const describes = await readJsonl(path81.join(storageDir, "describes.jsonl"));
|
|
30712
30820
|
const graph = { nodes, edges };
|
|
30713
30821
|
if (symbols.length > 0) {
|
|
30714
30822
|
graph.symbols = symbols;
|
|
@@ -30768,7 +30876,7 @@ async function bunfigPreloadRoots(projectRoot) {
|
|
|
30768
30876
|
const roots = new Set;
|
|
30769
30877
|
let text;
|
|
30770
30878
|
try {
|
|
30771
|
-
text = await readFile41(
|
|
30879
|
+
text = await readFile41(path81.join(projectRoot, "bunfig.toml"), "utf8");
|
|
30772
30880
|
} catch {
|
|
30773
30881
|
return roots;
|
|
30774
30882
|
}
|
|
@@ -30782,8 +30890,8 @@ async function bunfigPreloadRoots(projectRoot) {
|
|
|
30782
30890
|
if (raw.length === 0) {
|
|
30783
30891
|
continue;
|
|
30784
30892
|
}
|
|
30785
|
-
const absolute =
|
|
30786
|
-
const relative =
|
|
30893
|
+
const absolute = path81.resolve(projectRoot, raw);
|
|
30894
|
+
const relative = path81.relative(projectRoot, absolute).split(path81.sep).join("/");
|
|
30787
30895
|
roots.add(relative);
|
|
30788
30896
|
}
|
|
30789
30897
|
}
|
|
@@ -30856,7 +30964,7 @@ function canonicalCycle(cycle) {
|
|
|
30856
30964
|
|
|
30857
30965
|
// src/gdgraph/repomap.ts
|
|
30858
30966
|
import { mkdir as mkdir23, writeFile as writeFile17 } from "fs/promises";
|
|
30859
|
-
import
|
|
30967
|
+
import path82 from "path";
|
|
30860
30968
|
|
|
30861
30969
|
// src/gdgraph/pagerank.ts
|
|
30862
30970
|
function personalizedPageRank(nodes, edges, options) {
|
|
@@ -30967,7 +31075,7 @@ function overflowContent(required, missing, budget) {
|
|
|
30967
31075
|
`);
|
|
30968
31076
|
}
|
|
30969
31077
|
function repomapArtifactPath(cwd) {
|
|
30970
|
-
return
|
|
31078
|
+
return path82.join(cwd, ".metaproject", "data", "gdgraph", "artifacts", "repomap.md");
|
|
30971
31079
|
}
|
|
30972
31080
|
function buildRankEdges(graph, config) {
|
|
30973
31081
|
const edges = [];
|
|
@@ -31112,7 +31220,7 @@ function computeRepomap(graph, config, options = {}) {
|
|
|
31112
31220
|
async function writeRepomap(cwd, graph, config, options = {}) {
|
|
31113
31221
|
const result = computeRepomap(graph, config, options);
|
|
31114
31222
|
const artifactPath = repomapArtifactPath(cwd);
|
|
31115
|
-
await mkdir23(
|
|
31223
|
+
await mkdir23(path82.dirname(artifactPath), { recursive: true });
|
|
31116
31224
|
await writeFile17(artifactPath, result.content, "utf8");
|
|
31117
31225
|
return { ...result, path: artifactPath };
|
|
31118
31226
|
}
|
|
@@ -31195,12 +31303,12 @@ init_section_tombstone();
|
|
|
31195
31303
|
// src/forgetting/journal.ts
|
|
31196
31304
|
init_fs();
|
|
31197
31305
|
import { appendFile as appendFile5, mkdir as mkdir24, readFile as readFile42, stat as stat13 } from "fs/promises";
|
|
31198
|
-
import
|
|
31306
|
+
import path83 from "path";
|
|
31199
31307
|
function forgettingDataDir(cwd) {
|
|
31200
|
-
return
|
|
31308
|
+
return path83.join(cwd, ".metaproject", "data", "forgetting");
|
|
31201
31309
|
}
|
|
31202
31310
|
function deletionJournalPath(cwd) {
|
|
31203
|
-
return
|
|
31311
|
+
return path83.join(forgettingDataDir(cwd), "journal.jsonl");
|
|
31204
31312
|
}
|
|
31205
31313
|
async function readDeletionJournal(cwd) {
|
|
31206
31314
|
const file = deletionJournalPath(cwd);
|
|
@@ -31619,12 +31727,12 @@ __export(exports_service7, {
|
|
|
31619
31727
|
gateExitCode: () => gateExitCode,
|
|
31620
31728
|
readWikiFreshnessMetric: () => readWikiFreshnessMetric
|
|
31621
31729
|
});
|
|
31622
|
-
import
|
|
31730
|
+
import path103 from "path";
|
|
31623
31731
|
|
|
31624
31732
|
// src/health/config.ts
|
|
31625
31733
|
init_fs();
|
|
31626
31734
|
init_json();
|
|
31627
|
-
import
|
|
31735
|
+
import path84 from "path";
|
|
31628
31736
|
var DEFAULT_HEALTH_CONFIG = {
|
|
31629
31737
|
schemaVersion: 2,
|
|
31630
31738
|
ignore: {
|
|
@@ -31680,7 +31788,7 @@ var DEFAULT_HEALTH_CONFIG = {
|
|
|
31680
31788
|
}
|
|
31681
31789
|
};
|
|
31682
31790
|
function configPath2(cwd) {
|
|
31683
|
-
return
|
|
31791
|
+
return path84.join(cwd, ".metaproject", "health.config.json");
|
|
31684
31792
|
}
|
|
31685
31793
|
var STRICTEST_GATE = {
|
|
31686
31794
|
failOnPriorities: ["P0", "P1", "P2", "P3"],
|
|
@@ -31731,7 +31839,7 @@ async function loadHealthConfig(cwd) {
|
|
|
31731
31839
|
// src/health/run.ts
|
|
31732
31840
|
init_fs();
|
|
31733
31841
|
import { mkdir as mkdir28, writeFile as writeFile21 } from "fs/promises";
|
|
31734
|
-
import
|
|
31842
|
+
import path102 from "path";
|
|
31735
31843
|
|
|
31736
31844
|
// src/metrics/provenance.ts
|
|
31737
31845
|
async function collectGitProvenance(cwd) {
|
|
@@ -31831,12 +31939,12 @@ function computeGate2(input) {
|
|
|
31831
31939
|
}
|
|
31832
31940
|
|
|
31833
31941
|
// src/health/scopes.ts
|
|
31834
|
-
import
|
|
31942
|
+
import path87 from "path";
|
|
31835
31943
|
|
|
31836
31944
|
// src/health/util.ts
|
|
31837
31945
|
init_fs();
|
|
31838
31946
|
import { mkdir as mkdir25, readFile as readFile43, readdir as readdir15, writeFile as writeFile18 } from "fs/promises";
|
|
31839
|
-
import
|
|
31947
|
+
import path85 from "path";
|
|
31840
31948
|
var IGNORED_DIRS = new Set([
|
|
31841
31949
|
"node_modules",
|
|
31842
31950
|
".git",
|
|
@@ -31880,14 +31988,14 @@ async function toolVersion(command, cwd) {
|
|
|
31880
31988
|
}
|
|
31881
31989
|
}
|
|
31882
31990
|
function dataRoot3(cwd) {
|
|
31883
|
-
return
|
|
31991
|
+
return path85.join(cwd, ".metaproject", "data", "health");
|
|
31884
31992
|
}
|
|
31885
31993
|
async function writeRaw(cwd, source, content, stamp) {
|
|
31886
|
-
const dir =
|
|
31994
|
+
const dir = path85.join(dataRoot3(cwd), "raw", source);
|
|
31887
31995
|
await mkdir25(dir, { recursive: true });
|
|
31888
|
-
const file =
|
|
31996
|
+
const file = path85.join(dir, `${stamp}.log`);
|
|
31889
31997
|
await writeFile18(file, content, "utf8");
|
|
31890
|
-
return
|
|
31998
|
+
return path85.relative(cwd, file);
|
|
31891
31999
|
}
|
|
31892
32000
|
async function listSourceFiles(cwd, ignorePaths = []) {
|
|
31893
32001
|
const { files } = await listSourceFilesWithReasons(cwd, ignorePaths);
|
|
@@ -31907,7 +32015,7 @@ async function walk2(root, dir, out, incompleteReasons) {
|
|
|
31907
32015
|
try {
|
|
31908
32016
|
entries = await readdir15(dir, { withFileTypes: true });
|
|
31909
32017
|
} catch (error) {
|
|
31910
|
-
incompleteReasons.push(`${
|
|
32018
|
+
incompleteReasons.push(`${path85.relative(root, dir) || "."}: ${error instanceof Error ? error.message : String(error)}`);
|
|
31911
32019
|
return;
|
|
31912
32020
|
}
|
|
31913
32021
|
for (const entry of entries) {
|
|
@@ -31915,14 +32023,14 @@ async function walk2(root, dir, out, incompleteReasons) {
|
|
|
31915
32023
|
if (entry.isDirectory() && !IGNORED_DIRS.has(entry.name)) {}
|
|
31916
32024
|
continue;
|
|
31917
32025
|
}
|
|
31918
|
-
const abs =
|
|
32026
|
+
const abs = path85.join(dir, entry.name);
|
|
31919
32027
|
if (entry.isDirectory()) {
|
|
31920
32028
|
if (IGNORED_DIRS.has(entry.name)) {
|
|
31921
32029
|
continue;
|
|
31922
32030
|
}
|
|
31923
32031
|
await walk2(root, abs, out, incompleteReasons);
|
|
31924
|
-
} else if (entry.isFile() && SOURCE_EXT.has(
|
|
31925
|
-
out.push(
|
|
32032
|
+
} else if (entry.isFile() && SOURCE_EXT.has(path85.extname(entry.name))) {
|
|
32033
|
+
out.push(path85.relative(root, abs));
|
|
31926
32034
|
}
|
|
31927
32035
|
}
|
|
31928
32036
|
}
|
|
@@ -31937,7 +32045,7 @@ function moduleOfFile(file) {
|
|
|
31937
32045
|
return null;
|
|
31938
32046
|
}
|
|
31939
32047
|
function isSourceFile(file) {
|
|
31940
|
-
return SOURCE_EXT.has(
|
|
32048
|
+
return SOURCE_EXT.has(path85.extname(file));
|
|
31941
32049
|
}
|
|
31942
32050
|
function matchesAnyPattern(file, patterns) {
|
|
31943
32051
|
const normalized = file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
@@ -32037,7 +32145,7 @@ function rankHotspots(files, churn, sourceAnalysis) {
|
|
|
32037
32145
|
// src/health/source-analysis.ts
|
|
32038
32146
|
init_fs();
|
|
32039
32147
|
import { readFile as readFile44 } from "fs/promises";
|
|
32040
|
-
import
|
|
32148
|
+
import path86 from "path";
|
|
32041
32149
|
|
|
32042
32150
|
// src/health/metrics/complexity.ts
|
|
32043
32151
|
var CONTROL_KEYWORDS = new Set([
|
|
@@ -32271,7 +32379,7 @@ async function analyzeSourceFiles(cwd, sourceFiles) {
|
|
|
32271
32379
|
return new Map(entries.filter((entry) => entry !== null));
|
|
32272
32380
|
}
|
|
32273
32381
|
async function analyzeSourceFile(cwd, file) {
|
|
32274
|
-
const abs =
|
|
32382
|
+
const abs = path86.join(cwd, file);
|
|
32275
32383
|
if (!await pathExists(abs)) {
|
|
32276
32384
|
return null;
|
|
32277
32385
|
}
|
|
@@ -32344,14 +32452,14 @@ async function computeMetrics(input) {
|
|
|
32344
32452
|
}
|
|
32345
32453
|
const components = new Map;
|
|
32346
32454
|
for (const file of sourceFiles) {
|
|
32347
|
-
const dir =
|
|
32455
|
+
const dir = path87.posix.dirname(file);
|
|
32348
32456
|
if (dir === "." || dir === moduleOfFile(file)) {
|
|
32349
32457
|
continue;
|
|
32350
32458
|
}
|
|
32351
32459
|
components.set(dir, [...components.get(dir) ?? [], file]);
|
|
32352
32460
|
}
|
|
32353
32461
|
for (const [name, files] of [...components.entries()].sort()) {
|
|
32354
|
-
const compFindings = findings.filter((f) => f.file &&
|
|
32462
|
+
const compFindings = findings.filter((f) => f.file && path87.posix.dirname(f.file) === name);
|
|
32355
32463
|
scopes.push(build("component", `component:${name}`, name, files, compFindings, averageCoverage(files, coverage)));
|
|
32356
32464
|
}
|
|
32357
32465
|
const findingFiles = findings.map((f) => f.file).filter((f) => Boolean(f));
|
|
@@ -32396,9 +32504,9 @@ function tally2(values) {
|
|
|
32396
32504
|
// src/health/baseline.ts
|
|
32397
32505
|
init_fs();
|
|
32398
32506
|
import { mkdir as mkdir26, readFile as readFile45, writeFile as writeFile19 } from "fs/promises";
|
|
32399
|
-
import
|
|
32507
|
+
import path88 from "path";
|
|
32400
32508
|
function baselinePath(cwd) {
|
|
32401
|
-
return
|
|
32509
|
+
return path88.join(cwd, ".metaproject", "health", "baselines", "scores.json");
|
|
32402
32510
|
}
|
|
32403
32511
|
async function loadBaseline(cwd) {
|
|
32404
32512
|
const file = baselinePath(cwd);
|
|
@@ -32430,7 +32538,7 @@ async function writeBaseline(cwd, metrics, generatedAt, selector) {
|
|
|
32430
32538
|
scopes[key] = value;
|
|
32431
32539
|
}
|
|
32432
32540
|
const file = baselinePath(cwd);
|
|
32433
|
-
await mkdir26(
|
|
32541
|
+
await mkdir26(path88.dirname(file), { recursive: true });
|
|
32434
32542
|
await writeFile19(file, `${JSON.stringify({ generatedAt, scopes }, null, 2)}
|
|
32435
32543
|
`, "utf8");
|
|
32436
32544
|
return updated;
|
|
@@ -32484,10 +32592,10 @@ async function getChurn(cwd, windowDays) {
|
|
|
32484
32592
|
|
|
32485
32593
|
// src/health/metrics/wiki-freshness.ts
|
|
32486
32594
|
import { readFile as readFile46, stat as stat14 } from "fs/promises";
|
|
32487
|
-
import
|
|
32595
|
+
import path89 from "path";
|
|
32488
32596
|
var DEFAULT_STALE_EVIDENCE_DAYS = 7;
|
|
32489
32597
|
function freshnessReportPath(cwd) {
|
|
32490
|
-
return
|
|
32598
|
+
return path89.join(cwd, ".metaproject", "data", "wiki", "freshness", "latest.json");
|
|
32491
32599
|
}
|
|
32492
32600
|
async function readWikiFreshnessMetric(cwd, options = {}) {
|
|
32493
32601
|
const file = freshnessReportPath(cwd);
|
|
@@ -32508,7 +32616,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
|
|
|
32508
32616
|
} catch {
|
|
32509
32617
|
return {
|
|
32510
32618
|
status: "unreadable-report",
|
|
32511
|
-
reason: `${
|
|
32619
|
+
reason: `${path89.relative(cwd, file)} is not valid JSON; re-run \`keryx wiki freshness\`.`
|
|
32512
32620
|
};
|
|
32513
32621
|
}
|
|
32514
32622
|
const report = parsed;
|
|
@@ -32518,7 +32626,7 @@ async function readWikiFreshnessMetric(cwd, options = {}) {
|
|
|
32518
32626
|
if (pagesTotal === null || pagesFresh === null) {
|
|
32519
32627
|
return {
|
|
32520
32628
|
status: "unreadable-report",
|
|
32521
|
-
reason: `${
|
|
32629
|
+
reason: `${path89.relative(cwd, file)} is missing its totals; re-run \`keryx wiki freshness\`.`
|
|
32522
32630
|
};
|
|
32523
32631
|
}
|
|
32524
32632
|
const pagesUndecidable = numberOr3(totals.pagesUndecidable) ?? 0;
|
|
@@ -32572,12 +32680,12 @@ function renderWikiFreshnessLine(metric) {
|
|
|
32572
32680
|
}
|
|
32573
32681
|
|
|
32574
32682
|
// src/health/sources/helpers.ts
|
|
32575
|
-
import
|
|
32683
|
+
import path90 from "path";
|
|
32576
32684
|
import { existsSync as existsSync8 } from "fs";
|
|
32577
32685
|
class NoImportError extends Error {
|
|
32578
32686
|
}
|
|
32579
32687
|
function resolveBin(cwd, name) {
|
|
32580
|
-
const local =
|
|
32688
|
+
const local = path90.join(cwd, "node_modules", ".bin", name);
|
|
32581
32689
|
if (existsSync8(local)) {
|
|
32582
32690
|
return local;
|
|
32583
32691
|
}
|
|
@@ -32658,13 +32766,13 @@ async function getComplexityFindings(cwd, sourceFiles, config, sourceAnalysis) {
|
|
|
32658
32766
|
|
|
32659
32767
|
// src/health/metrics/coverage.ts
|
|
32660
32768
|
import { existsSync as existsSync9 } from "fs";
|
|
32661
|
-
import
|
|
32769
|
+
import path91 from "path";
|
|
32662
32770
|
var SUMMARY_PATHS = [
|
|
32663
32771
|
"coverage/coverage-summary.json",
|
|
32664
32772
|
"coverage/coverage-final.json"
|
|
32665
32773
|
];
|
|
32666
32774
|
async function getCoverage(cwd) {
|
|
32667
|
-
const summary = SUMMARY_PATHS.map((rel) =>
|
|
32775
|
+
const summary = SUMMARY_PATHS.map((rel) => path91.join(cwd, rel)).find((abs) => existsSync9(abs));
|
|
32668
32776
|
if (!summary) {
|
|
32669
32777
|
return { status: "missing", total: null, byFile: new Map };
|
|
32670
32778
|
}
|
|
@@ -32685,7 +32793,7 @@ async function getCoverage(cwd) {
|
|
|
32685
32793
|
total = pct;
|
|
32686
32794
|
continue;
|
|
32687
32795
|
}
|
|
32688
|
-
const relative =
|
|
32796
|
+
const relative = path91.isAbsolute(key) ? path91.relative(cwd, key) : key;
|
|
32689
32797
|
byFile.set(relative.replace(/\\/g, "/"), pct);
|
|
32690
32798
|
}
|
|
32691
32799
|
return { status: "available", total, byFile };
|
|
@@ -32818,10 +32926,10 @@ function renderWikiFreshness(metric) {
|
|
|
32818
32926
|
// src/health/skills.ts
|
|
32819
32927
|
init_fs();
|
|
32820
32928
|
import { readFile as readFile47 } from "fs/promises";
|
|
32821
|
-
import
|
|
32929
|
+
import path92 from "path";
|
|
32822
32930
|
var EMPTY = { skills: [], skillForFile: () => null };
|
|
32823
32931
|
async function loadSkillOwnership(cwd) {
|
|
32824
|
-
const manifestPath =
|
|
32932
|
+
const manifestPath = path92.join(cwd, ".metaproject", "metaproject.json");
|
|
32825
32933
|
if (!await pathExists(manifestPath)) {
|
|
32826
32934
|
return EMPTY;
|
|
32827
32935
|
}
|
|
@@ -32859,7 +32967,7 @@ function normalize(value) {
|
|
|
32859
32967
|
|
|
32860
32968
|
// src/health/sources/eslint.ts
|
|
32861
32969
|
import { existsSync as existsSync10 } from "fs";
|
|
32862
|
-
import
|
|
32970
|
+
import path93 from "path";
|
|
32863
32971
|
var CONFIG_FILES = [
|
|
32864
32972
|
".eslintrc",
|
|
32865
32973
|
".eslintrc.js",
|
|
@@ -32873,7 +32981,7 @@ var CONFIG_FILES = [
|
|
|
32873
32981
|
"eslint.config.ts"
|
|
32874
32982
|
];
|
|
32875
32983
|
function hasConfig(cwd) {
|
|
32876
|
-
return CONFIG_FILES.some((file) => existsSync10(
|
|
32984
|
+
return CONFIG_FILES.some((file) => existsSync10(path93.join(cwd, file)));
|
|
32877
32985
|
}
|
|
32878
32986
|
var eslintAdapter = {
|
|
32879
32987
|
id: "eslint",
|
|
@@ -32898,7 +33006,7 @@ var eslintAdapter = {
|
|
|
32898
33006
|
};
|
|
32899
33007
|
},
|
|
32900
33008
|
async import(ctx) {
|
|
32901
|
-
const report =
|
|
33009
|
+
const report = path93.join(ctx.cwd, "eslint-report.json");
|
|
32902
33010
|
if (!existsSync10(report)) {
|
|
32903
33011
|
throw new NoImportError("no eslint-report.json");
|
|
32904
33012
|
}
|
|
@@ -32925,7 +33033,7 @@ var eslintAdapter = {
|
|
|
32925
33033
|
}
|
|
32926
33034
|
const findings = [];
|
|
32927
33035
|
for (const file of data) {
|
|
32928
|
-
const relative =
|
|
33036
|
+
const relative = path93.isAbsolute(file.filePath) ? path93.relative(ctx.cwd, file.filePath) : file.filePath;
|
|
32929
33037
|
for (const message of file.messages ?? []) {
|
|
32930
33038
|
const isError = message.severity === 2;
|
|
32931
33039
|
findings.push(makeFinding({
|
|
@@ -32957,9 +33065,9 @@ var eslintAdapter = {
|
|
|
32957
33065
|
|
|
32958
33066
|
// src/health/sources/typescript.ts
|
|
32959
33067
|
import { existsSync as existsSync11 } from "fs";
|
|
32960
|
-
import
|
|
33068
|
+
import path94 from "path";
|
|
32961
33069
|
function hasTsconfig(cwd) {
|
|
32962
|
-
return existsSync11(
|
|
33070
|
+
return existsSync11(path94.join(cwd, "tsconfig.json"));
|
|
32963
33071
|
}
|
|
32964
33072
|
var typescriptAdapter = {
|
|
32965
33073
|
id: "typescript",
|
|
@@ -33035,7 +33143,7 @@ __export(exports_service6, {
|
|
|
33035
33143
|
});
|
|
33036
33144
|
import { existsSync as existsSync12 } from "fs";
|
|
33037
33145
|
import { readFile as readFile50, readdir as readdir16 } from "fs/promises";
|
|
33038
|
-
import
|
|
33146
|
+
import path99 from "path";
|
|
33039
33147
|
|
|
33040
33148
|
// src/lib/git-env.ts
|
|
33041
33149
|
var GIT_DISCOVERY_OVERRIDE_VARS = [
|
|
@@ -33060,7 +33168,7 @@ function withoutGitDiscoveryOverrides(env) {
|
|
|
33060
33168
|
init_fs();
|
|
33061
33169
|
init_guard();
|
|
33062
33170
|
import { readFile as readFile48 } from "fs/promises";
|
|
33063
|
-
import
|
|
33171
|
+
import path95 from "path";
|
|
33064
33172
|
|
|
33065
33173
|
// src/metrics/record.ts
|
|
33066
33174
|
var RELIABILITIES = new Set(["exact", "estimated", "unknown"]);
|
|
@@ -33075,7 +33183,7 @@ var RETRY_TYPES = new Set([
|
|
|
33075
33183
|
|
|
33076
33184
|
// src/metrics/lifecycle.ts
|
|
33077
33185
|
async function readArtifactPointer(root, expected) {
|
|
33078
|
-
const pointerFile =
|
|
33186
|
+
const pointerFile = path95.join(root, "latest.json");
|
|
33079
33187
|
if (!await pathExists(pointerFile))
|
|
33080
33188
|
return { status: "missing", pointer: null };
|
|
33081
33189
|
let pointer;
|
|
@@ -33084,7 +33192,7 @@ async function readArtifactPointer(root, expected) {
|
|
|
33084
33192
|
} catch {
|
|
33085
33193
|
return { status: "stale", pointer: null, reason: "latest pointer is invalid JSON" };
|
|
33086
33194
|
}
|
|
33087
|
-
const recordFile = pointer.record ?
|
|
33195
|
+
const recordFile = pointer.record ? path95.join(root, pointer.record) : null;
|
|
33088
33196
|
if (!recordFile || !isPathInside(root, recordFile) || !await pathExists(recordFile)) {
|
|
33089
33197
|
return { status: "stale", pointer, reason: "pointer record is missing" };
|
|
33090
33198
|
}
|
|
@@ -33100,9 +33208,9 @@ init_guard();
|
|
|
33100
33208
|
// src/testing/capability.ts
|
|
33101
33209
|
init_fs();
|
|
33102
33210
|
init_json();
|
|
33103
|
-
import
|
|
33211
|
+
import path96 from "path";
|
|
33104
33212
|
async function isTestingCapabilityEnabled(cwd, capability) {
|
|
33105
|
-
const manifestPath =
|
|
33213
|
+
const manifestPath = path96.join(cwd, ".metaproject", "metaproject.json");
|
|
33106
33214
|
if (!await pathExists(manifestPath)) {
|
|
33107
33215
|
return false;
|
|
33108
33216
|
}
|
|
@@ -33128,10 +33236,10 @@ async function isTestingCapabilityEnabled(cwd, capability) {
|
|
|
33128
33236
|
init_fs();
|
|
33129
33237
|
init_guard();
|
|
33130
33238
|
import { readFile as readFile49, mkdir as mkdir27, writeFile as writeFile20 } from "fs/promises";
|
|
33131
|
-
import
|
|
33239
|
+
import path97 from "path";
|
|
33132
33240
|
var COVERAGE_MAP_SCHEMA_VERSION = 1;
|
|
33133
33241
|
function coverageMapPath(cwd, cfg) {
|
|
33134
|
-
return
|
|
33242
|
+
return path97.isAbsolute(cfg.coverageMap.artifact) ? cfg.coverageMap.artifact : path97.join(cwd, cfg.coverageMap.artifact);
|
|
33135
33243
|
}
|
|
33136
33244
|
async function loadCoverageMap(cwd, cfg) {
|
|
33137
33245
|
const file = coverageMapPath(cwd, cfg);
|
|
@@ -33205,20 +33313,20 @@ function normalizePath4(file) {
|
|
|
33205
33313
|
}
|
|
33206
33314
|
|
|
33207
33315
|
// src/testing/selection.ts
|
|
33208
|
-
import
|
|
33316
|
+
import path98 from "path";
|
|
33209
33317
|
var TEST_FILE_RE = /(^|\/)(__tests__\/.*|.*\.(test|spec)\.[cm]?[tj]sx?$|e2e\/.*\.[cm]?[tj]sx?$|tests\/.*\.[cm]?[tj]sx?$)/;
|
|
33210
33318
|
function normalizePath5(file) {
|
|
33211
33319
|
return file.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
33212
33320
|
}
|
|
33213
33321
|
function relatedByNamingAndDirectory(target, testFiles) {
|
|
33214
33322
|
const normalized = normalizePath5(target);
|
|
33215
|
-
const ext =
|
|
33323
|
+
const ext = path98.extname(normalized);
|
|
33216
33324
|
const withoutExt = ext ? normalized.slice(0, -ext.length) : normalized;
|
|
33217
|
-
const base =
|
|
33218
|
-
const dir =
|
|
33325
|
+
const base = path98.basename(withoutExt);
|
|
33326
|
+
const dir = path98.dirname(normalized);
|
|
33219
33327
|
return testFiles.filter((file) => {
|
|
33220
|
-
const fileDir =
|
|
33221
|
-
const fileBase =
|
|
33328
|
+
const fileDir = path98.dirname(file);
|
|
33329
|
+
const fileBase = path98.basename(file);
|
|
33222
33330
|
return file.startsWith(`${withoutExt}.`) || file.includes(`${withoutExt}.`) || fileDir === dir && fileBase.startsWith(`${base}.`) || fileDir.startsWith(dir) && fileBase.includes(base);
|
|
33223
33331
|
}).sort();
|
|
33224
33332
|
}
|
|
@@ -33348,7 +33456,7 @@ var DEFAULT_TESTING_CONFIG = {
|
|
|
33348
33456
|
}
|
|
33349
33457
|
};
|
|
33350
33458
|
function testingDataRoot(cwd) {
|
|
33351
|
-
return
|
|
33459
|
+
return path99.join(cwd, ".metaproject", "data", "testing");
|
|
33352
33460
|
}
|
|
33353
33461
|
async function computeTestingContext(cwd) {
|
|
33354
33462
|
const { files, incompleteReasons } = await listProjectFiles(cwd);
|
|
@@ -33523,7 +33631,7 @@ async function runTesting(input) {
|
|
|
33523
33631
|
return runResult;
|
|
33524
33632
|
}
|
|
33525
33633
|
async function loadTestingContext(cwd) {
|
|
33526
|
-
const file =
|
|
33634
|
+
const file = path99.join(testingDataRoot(cwd), "context.json");
|
|
33527
33635
|
if (!await pathExists(file)) {
|
|
33528
33636
|
return null;
|
|
33529
33637
|
}
|
|
@@ -33534,18 +33642,18 @@ async function loadTestingContext(cwd) {
|
|
|
33534
33642
|
}
|
|
33535
33643
|
}
|
|
33536
33644
|
async function loadTestingReport(cwd) {
|
|
33537
|
-
const file =
|
|
33645
|
+
const file = path99.join(testingDataRoot(cwd), "artifacts", "latest.json");
|
|
33538
33646
|
if (!await pathExists(file)) {
|
|
33539
33647
|
return null;
|
|
33540
33648
|
}
|
|
33541
33649
|
try {
|
|
33542
33650
|
const latest = JSON.parse(await readFile50(file, "utf8"));
|
|
33543
33651
|
if (typeof latest.record === "string") {
|
|
33544
|
-
const pointer = await readArtifactPointer(
|
|
33652
|
+
const pointer = await readArtifactPointer(path99.join(testingDataRoot(cwd), "artifacts"), await collectGitProvenance(cwd));
|
|
33545
33653
|
if (pointer.status !== "fresh")
|
|
33546
33654
|
return null;
|
|
33547
|
-
const recordFile =
|
|
33548
|
-
if (!isPathInside(
|
|
33655
|
+
const recordFile = path99.join(testingDataRoot(cwd), "artifacts", latest.record);
|
|
33656
|
+
if (!isPathInside(path99.join(testingDataRoot(cwd), "artifacts"), recordFile))
|
|
33549
33657
|
return null;
|
|
33550
33658
|
if (!await pathExists(recordFile))
|
|
33551
33659
|
return null;
|
|
@@ -33592,28 +33700,28 @@ async function ensureContext(cwd) {
|
|
|
33592
33700
|
}
|
|
33593
33701
|
async function writeContext(cwd, context) {
|
|
33594
33702
|
const root = testingDataRoot(cwd);
|
|
33595
|
-
const rel = (p) =>
|
|
33703
|
+
const rel = (p) => path99.relative(cwd, p);
|
|
33596
33704
|
await mkdirContained(cwd, rel(root));
|
|
33597
|
-
await writeContained(cwd, rel(
|
|
33705
|
+
await writeContained(cwd, rel(path99.join(root, "context.json")), `${JSON.stringify(context, null, 2)}
|
|
33598
33706
|
`);
|
|
33599
|
-
await writeContained(cwd, rel(
|
|
33600
|
-
await writeContained(cwd, rel(
|
|
33707
|
+
await writeContained(cwd, rel(path99.join(root, "context.md")), renderContextMarkdown(context));
|
|
33708
|
+
await writeContained(cwd, rel(path99.join(root, "recommendations.md")), renderRecommendationsMarkdown(context));
|
|
33601
33709
|
}
|
|
33602
33710
|
async function writeReport(cwd, report) {
|
|
33603
33711
|
const root = testingDataRoot(cwd);
|
|
33604
|
-
const artifacts =
|
|
33605
|
-
const history =
|
|
33606
|
-
const rel = (p) =>
|
|
33712
|
+
const artifacts = path99.join(root, "artifacts");
|
|
33713
|
+
const history = path99.join(root, "history");
|
|
33714
|
+
const rel = (p) => path99.relative(cwd, p);
|
|
33607
33715
|
await mkdirContained(cwd, rel(artifacts));
|
|
33608
33716
|
await mkdirContained(cwd, rel(history));
|
|
33609
33717
|
const stamp = report.generatedAt.replace(/[:.]/g, "-");
|
|
33610
|
-
const json =
|
|
33611
|
-
const markdown =
|
|
33718
|
+
const json = path99.join(artifacts, "latest.json");
|
|
33719
|
+
const markdown = path99.join(artifacts, "latest.md");
|
|
33612
33720
|
const serialized = `${JSON.stringify(report, null, 2)}
|
|
33613
33721
|
`;
|
|
33614
33722
|
if (report.runId) {
|
|
33615
|
-
const runJson =
|
|
33616
|
-
const runMarkdown =
|
|
33723
|
+
const runJson = path99.join(artifacts, "runs", `${report.runId}.json`);
|
|
33724
|
+
const runMarkdown = path99.join(artifacts, "runs", `${report.runId}.md`);
|
|
33617
33725
|
if (await pathExists(runJson))
|
|
33618
33726
|
throw new Error(`immutable testing run already exists: ${report.runId}`);
|
|
33619
33727
|
await writeContained(cwd, rel(runJson), serialized);
|
|
@@ -33624,26 +33732,26 @@ async function writeReport(cwd, report) {
|
|
|
33624
33732
|
branch: report.provenance?.branch ?? null,
|
|
33625
33733
|
worktree: report.provenance?.worktree ?? null,
|
|
33626
33734
|
generated_at: report.generatedAt,
|
|
33627
|
-
record:
|
|
33735
|
+
record: path99.posix.join("runs", `${report.runId}.json`)
|
|
33628
33736
|
}, null, 2)}
|
|
33629
33737
|
`);
|
|
33630
33738
|
} else {
|
|
33631
33739
|
await writeContained(cwd, rel(json), serialized);
|
|
33632
33740
|
}
|
|
33633
33741
|
await writeContained(cwd, rel(markdown), renderReportMarkdown3(report));
|
|
33634
|
-
await writeContained(cwd, rel(
|
|
33742
|
+
await writeContained(cwd, rel(path99.join(history, `${stamp}.json`)), serialized);
|
|
33635
33743
|
return {
|
|
33636
|
-
markdownPath:
|
|
33637
|
-
jsonPath:
|
|
33744
|
+
markdownPath: path99.relative(cwd, markdown),
|
|
33745
|
+
jsonPath: path99.relative(cwd, json)
|
|
33638
33746
|
};
|
|
33639
33747
|
}
|
|
33640
33748
|
async function writeRawLog(cwd, raw) {
|
|
33641
|
-
const logs =
|
|
33642
|
-
const rel = (p) =>
|
|
33749
|
+
const logs = path99.join(testingDataRoot(cwd), "logs");
|
|
33750
|
+
const rel = (p) => path99.relative(cwd, p);
|
|
33643
33751
|
await mkdirContained(cwd, rel(logs));
|
|
33644
|
-
const latest =
|
|
33752
|
+
const latest = path99.join(logs, "latest.raw.log");
|
|
33645
33753
|
await writeContained(cwd, rel(latest), raw);
|
|
33646
|
-
return
|
|
33754
|
+
return path99.relative(cwd, latest);
|
|
33647
33755
|
}
|
|
33648
33756
|
async function listProjectFiles(cwd) {
|
|
33649
33757
|
const out = [];
|
|
@@ -33656,11 +33764,11 @@ async function walk3(root, dir, out, incompleteReasons) {
|
|
|
33656
33764
|
try {
|
|
33657
33765
|
entries = await readdir16(dir, { withFileTypes: true });
|
|
33658
33766
|
} catch (error) {
|
|
33659
|
-
incompleteReasons.push(`${normalizePath6(
|
|
33767
|
+
incompleteReasons.push(`${normalizePath6(path99.relative(root, dir)) || "."}: ${error instanceof Error ? error.message : String(error)}`);
|
|
33660
33768
|
return;
|
|
33661
33769
|
}
|
|
33662
33770
|
for (const entry of entries) {
|
|
33663
|
-
const abs =
|
|
33771
|
+
const abs = path99.join(dir, entry.name);
|
|
33664
33772
|
if (entry.isDirectory()) {
|
|
33665
33773
|
if (IGNORED_DIRS2.has(entry.name) || entry.name.startsWith(".tmp-")) {
|
|
33666
33774
|
continue;
|
|
@@ -33669,12 +33777,12 @@ async function walk3(root, dir, out, incompleteReasons) {
|
|
|
33669
33777
|
continue;
|
|
33670
33778
|
}
|
|
33671
33779
|
if (entry.isFile()) {
|
|
33672
|
-
out.push(normalizePath6(
|
|
33780
|
+
out.push(normalizePath6(path99.relative(root, abs)));
|
|
33673
33781
|
}
|
|
33674
33782
|
}
|
|
33675
33783
|
}
|
|
33676
33784
|
async function readPackageJson(cwd) {
|
|
33677
|
-
const file =
|
|
33785
|
+
const file = path99.join(cwd, "package.json");
|
|
33678
33786
|
if (!await pathExists(file)) {
|
|
33679
33787
|
return null;
|
|
33680
33788
|
}
|
|
@@ -33685,7 +33793,7 @@ async function readPackageJson(cwd) {
|
|
|
33685
33793
|
}
|
|
33686
33794
|
}
|
|
33687
33795
|
async function loadTestingConfig(cwd) {
|
|
33688
|
-
const file =
|
|
33796
|
+
const file = path99.join(cwd, ".metaproject", "testing.config.json");
|
|
33689
33797
|
if (!await pathExists(file)) {
|
|
33690
33798
|
return DEFAULT_TESTING_CONFIG;
|
|
33691
33799
|
}
|
|
@@ -33750,7 +33858,7 @@ function detectFrameworks(input) {
|
|
|
33750
33858
|
async function extractConventions(cwd, files) {
|
|
33751
33859
|
const conventions = new Set;
|
|
33752
33860
|
for (const file of files.slice(0, 40)) {
|
|
33753
|
-
const abs =
|
|
33861
|
+
const abs = path99.join(cwd, file);
|
|
33754
33862
|
if (!await pathExists(abs)) {
|
|
33755
33863
|
continue;
|
|
33756
33864
|
}
|
|
@@ -33880,7 +33988,7 @@ async function findTestsByImportedTargets(cwd, targets, testFiles) {
|
|
|
33880
33988
|
const targetKeys = new Set(targets.map((target) => modulePathKey(normalizePath6(target))));
|
|
33881
33989
|
const selected = new Set;
|
|
33882
33990
|
for (const testFile of testFiles) {
|
|
33883
|
-
const absoluteTest =
|
|
33991
|
+
const absoluteTest = path99.join(cwd, testFile);
|
|
33884
33992
|
if (!await pathExists(absoluteTest)) {
|
|
33885
33993
|
continue;
|
|
33886
33994
|
}
|
|
@@ -33914,10 +34022,10 @@ function resolveImportPath(cwd, testFile, importPath) {
|
|
|
33914
34022
|
if (!importPath.startsWith(".")) {
|
|
33915
34023
|
return null;
|
|
33916
34024
|
}
|
|
33917
|
-
const importerDir =
|
|
33918
|
-
const absoluteResolved =
|
|
33919
|
-
const relative =
|
|
33920
|
-
if (relative.startsWith(`..${
|
|
34025
|
+
const importerDir = path99.dirname(testFile);
|
|
34026
|
+
const absoluteResolved = path99.resolve(path99.join(cwd, importerDir), importPath);
|
|
34027
|
+
const relative = path99.relative(cwd, absoluteResolved);
|
|
34028
|
+
if (relative.startsWith(`..${path99.sep}`) || relative === "..") {
|
|
33921
34029
|
return null;
|
|
33922
34030
|
}
|
|
33923
34031
|
const relativeNormalized = normalizePath6(relative);
|
|
@@ -33969,13 +34077,13 @@ function resolveTestCommand(cwd, context, input) {
|
|
|
33969
34077
|
}
|
|
33970
34078
|
var BUN_LOCKFILES = ["bun.lock", "bun.lockb"];
|
|
33971
34079
|
function detectPackageManager(cwd) {
|
|
33972
|
-
if (resolveBunBin() && BUN_LOCKFILES.some((name) => pathExistsSync(
|
|
34080
|
+
if (resolveBunBin() && BUN_LOCKFILES.some((name) => pathExistsSync(path99.join(cwd, name)))) {
|
|
33973
34081
|
return "bun";
|
|
33974
34082
|
}
|
|
33975
|
-
if (Bun.which("pnpm") && pathExistsSync(
|
|
34083
|
+
if (Bun.which("pnpm") && pathExistsSync(path99.join(cwd, "pnpm-lock.yaml"))) {
|
|
33976
34084
|
return "pnpm";
|
|
33977
34085
|
}
|
|
33978
|
-
if (Bun.which("yarn") && pathExistsSync(
|
|
34086
|
+
if (Bun.which("yarn") && pathExistsSync(path99.join(cwd, "yarn.lock"))) {
|
|
33979
34087
|
return "yarn";
|
|
33980
34088
|
}
|
|
33981
34089
|
return "npm";
|
|
@@ -34315,7 +34423,7 @@ async function compatibleReportForHealth(ctx) {
|
|
|
34315
34423
|
|
|
34316
34424
|
// src/health/sources/dependency-audit.ts
|
|
34317
34425
|
import { existsSync as existsSync13 } from "fs";
|
|
34318
|
-
import
|
|
34426
|
+
import path100 from "path";
|
|
34319
34427
|
function auditSeverityToPriority(severity) {
|
|
34320
34428
|
if (severity === "critical" || severity === "high")
|
|
34321
34429
|
return "P0";
|
|
@@ -34434,7 +34542,7 @@ var LOCKFILE_COMMANDS = [
|
|
|
34434
34542
|
];
|
|
34435
34543
|
function auditCommand(cwd) {
|
|
34436
34544
|
for (const entry of LOCKFILE_COMMANDS) {
|
|
34437
|
-
if (!entry.lockfiles.some((name) => existsSync13(
|
|
34545
|
+
if (!entry.lockfiles.some((name) => existsSync13(path100.join(cwd, name))))
|
|
34438
34546
|
continue;
|
|
34439
34547
|
const bin = resolveBin(cwd, entry.bin);
|
|
34440
34548
|
if (bin)
|
|
@@ -34493,13 +34601,13 @@ var dependencyAuditAdapter = {
|
|
|
34493
34601
|
|
|
34494
34602
|
// src/health/sources/sonarqube.ts
|
|
34495
34603
|
import { existsSync as existsSync14 } from "fs";
|
|
34496
|
-
import
|
|
34604
|
+
import path101 from "path";
|
|
34497
34605
|
var REPORT_FILES = ["sonar-issues.json", ".metaproject/data/health/sonar-issues.json"];
|
|
34498
34606
|
function reportPath(cwd) {
|
|
34499
34607
|
const fromEnv = process.env.SONAR_ISSUES_FILE;
|
|
34500
34608
|
const candidates = fromEnv ? [fromEnv, ...REPORT_FILES] : REPORT_FILES;
|
|
34501
34609
|
for (const rel of candidates) {
|
|
34502
|
-
const abs =
|
|
34610
|
+
const abs = path101.isAbsolute(rel) ? rel : path101.join(cwd, rel);
|
|
34503
34611
|
if (existsSync14(abs)) {
|
|
34504
34612
|
return abs;
|
|
34505
34613
|
}
|
|
@@ -34583,7 +34691,7 @@ var sonarqubeAdapter = {
|
|
|
34583
34691
|
function relativizeComponent(component, cwd) {
|
|
34584
34692
|
const colon = component.indexOf(":");
|
|
34585
34693
|
const value = colon >= 0 ? component.slice(colon + 1) : component;
|
|
34586
|
-
return
|
|
34694
|
+
return path101.isAbsolute(value) ? path101.relative(cwd, value) : value;
|
|
34587
34695
|
}
|
|
34588
34696
|
|
|
34589
34697
|
// src/health/sources/index.ts
|
|
@@ -34920,19 +35028,19 @@ function filteredInfo(source, cfg) {
|
|
|
34920
35028
|
};
|
|
34921
35029
|
}
|
|
34922
35030
|
async function writeOutputs(cwd, report, config, stamp) {
|
|
34923
|
-
const artifacts =
|
|
34924
|
-
const history =
|
|
35031
|
+
const artifacts = path102.join(dataRoot3(cwd), "artifacts");
|
|
35032
|
+
const history = path102.join(dataRoot3(cwd), "history");
|
|
34925
35033
|
await mkdir28(artifacts, { recursive: true });
|
|
34926
35034
|
await mkdir28(history, { recursive: true });
|
|
34927
|
-
const markdown =
|
|
34928
|
-
const json =
|
|
34929
|
-
const historyJson =
|
|
35035
|
+
const markdown = path102.join(artifacts, "latest.md");
|
|
35036
|
+
const json = path102.join(artifacts, "latest.json");
|
|
35037
|
+
const historyJson = path102.join(history, `${stamp}.json`);
|
|
34930
35038
|
const serialized = `${JSON.stringify(report, null, 2)}
|
|
34931
35039
|
`;
|
|
34932
35040
|
await writeFile21(markdown, renderReportMarkdown2(report, config), "utf8");
|
|
34933
35041
|
if (report.runId) {
|
|
34934
|
-
const runJson =
|
|
34935
|
-
const runMarkdown =
|
|
35042
|
+
const runJson = path102.join(artifacts, "runs", `${report.runId}.json`);
|
|
35043
|
+
const runMarkdown = path102.join(artifacts, "runs", `${report.runId}.md`);
|
|
34936
35044
|
if (await pathExists(runJson))
|
|
34937
35045
|
throw new Error(`immutable health run already exists: ${report.runId}`);
|
|
34938
35046
|
await writeFileAtomic(runJson, serialized);
|
|
@@ -34943,7 +35051,7 @@ async function writeOutputs(cwd, report, config, stamp) {
|
|
|
34943
35051
|
branch: report.provenance?.branch ?? null,
|
|
34944
35052
|
worktree: report.provenance?.worktree ?? null,
|
|
34945
35053
|
generated_at: report.generatedAt,
|
|
34946
|
-
record:
|
|
35054
|
+
record: path102.posix.join("runs", `${report.runId}.json`)
|
|
34947
35055
|
}, null, 2)}
|
|
34948
35056
|
`);
|
|
34949
35057
|
} else {
|
|
@@ -34951,8 +35059,8 @@ async function writeOutputs(cwd, report, config, stamp) {
|
|
|
34951
35059
|
}
|
|
34952
35060
|
await writeFile21(historyJson, serialized, "utf8");
|
|
34953
35061
|
return {
|
|
34954
|
-
markdownPath:
|
|
34955
|
-
jsonPath:
|
|
35062
|
+
markdownPath: path102.relative(cwd, markdown),
|
|
35063
|
+
jsonPath: path102.relative(cwd, json)
|
|
34956
35064
|
};
|
|
34957
35065
|
}
|
|
34958
35066
|
async function resolveChanged(cwd, selector) {
|
|
@@ -35005,7 +35113,7 @@ function hasGateShape(value) {
|
|
|
35005
35113
|
return Array.isArray(report.metrics) && Array.isArray(report.sources) && Array.isArray(report.findings);
|
|
35006
35114
|
}
|
|
35007
35115
|
async function readLatest(cwd) {
|
|
35008
|
-
const file =
|
|
35116
|
+
const file = path103.join(dataRoot3(cwd), "artifacts", "latest.json");
|
|
35009
35117
|
if (!await pathExists(file)) {
|
|
35010
35118
|
return null;
|
|
35011
35119
|
}
|
|
@@ -35016,11 +35124,11 @@ async function readLatest(cwd) {
|
|
|
35016
35124
|
const latest = read.value;
|
|
35017
35125
|
const record = latest.record;
|
|
35018
35126
|
if (typeof record === "string") {
|
|
35019
|
-
const pointer = await readArtifactPointer(
|
|
35127
|
+
const pointer = await readArtifactPointer(path103.join(dataRoot3(cwd), "artifacts"), await collectGitProvenance(cwd));
|
|
35020
35128
|
if (pointer.status !== "fresh")
|
|
35021
35129
|
return null;
|
|
35022
|
-
const recordFile =
|
|
35023
|
-
if (!isPathInside(
|
|
35130
|
+
const recordFile = path103.join(dataRoot3(cwd), "artifacts", record);
|
|
35131
|
+
if (!isPathInside(path103.join(dataRoot3(cwd), "artifacts"), recordFile))
|
|
35024
35132
|
return null;
|
|
35025
35133
|
if (!await pathExists(recordFile))
|
|
35026
35134
|
return null;
|
|
@@ -35093,7 +35201,7 @@ function createCodeHealthService() {
|
|
|
35093
35201
|
return {
|
|
35094
35202
|
run: (input) => runHealth(input),
|
|
35095
35203
|
async status(input) {
|
|
35096
|
-
const enabled = await pathExists(
|
|
35204
|
+
const enabled = await pathExists(path103.join(input.cwd, ".metaproject", "health.config.json"));
|
|
35097
35205
|
const latest = await readLatest(input.cwd);
|
|
35098
35206
|
const project = latest?.metrics.find((m) => m.key === "project") ?? null;
|
|
35099
35207
|
const decliningScopes = latest ? latest.metrics.filter((m) => m.regression_score > 0).length : 0;
|
|
@@ -35251,10 +35359,10 @@ function renderEvidenceBlock(evidences, siblings) {
|
|
|
35251
35359
|
init_fs();
|
|
35252
35360
|
init_contained_write();
|
|
35253
35361
|
init_json();
|
|
35254
|
-
import
|
|
35362
|
+
import path104 from "path";
|
|
35255
35363
|
import { createHash as createHash17 } from "crypto";
|
|
35256
35364
|
function impactEvidenceDataRoot(root) {
|
|
35257
|
-
return
|
|
35365
|
+
return path104.join(root, ".metaproject", "data", "security", "impact-evidence");
|
|
35258
35366
|
}
|
|
35259
35367
|
function sanitizeSessionId(sessionId) {
|
|
35260
35368
|
const cleaned = sessionId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
@@ -35266,7 +35374,7 @@ function sessionStateFilename(sessionId) {
|
|
|
35266
35374
|
return `${sanitized}-${suffix}.json`;
|
|
35267
35375
|
}
|
|
35268
35376
|
function sessionStatePath(root, sessionId) {
|
|
35269
|
-
return
|
|
35377
|
+
return path104.join(impactEvidenceDataRoot(root), "sessions", sessionStateFilename(sessionId));
|
|
35270
35378
|
}
|
|
35271
35379
|
async function loadSessionState(root, sessionId) {
|
|
35272
35380
|
const file = sessionStatePath(root, sessionId);
|
|
@@ -35285,11 +35393,11 @@ async function loadSessionState(root, sessionId) {
|
|
|
35285
35393
|
}
|
|
35286
35394
|
async function saveSessionState(root, sessionId, state) {
|
|
35287
35395
|
const file = sessionStatePath(root, sessionId);
|
|
35288
|
-
await writeContained(root,
|
|
35396
|
+
await writeContained(root, path104.relative(root, file), `${JSON.stringify(state, null, 2)}
|
|
35289
35397
|
`);
|
|
35290
35398
|
}
|
|
35291
35399
|
function logPath(root) {
|
|
35292
|
-
return
|
|
35400
|
+
return path104.join(impactEvidenceDataRoot(root), "log.jsonl");
|
|
35293
35401
|
}
|
|
35294
35402
|
async function appendLogRecord(root, record) {
|
|
35295
35403
|
const full = {
|
|
@@ -35300,7 +35408,7 @@ async function appendLogRecord(root, record) {
|
|
|
35300
35408
|
...record.detail !== undefined ? { detail: record.detail } : {}
|
|
35301
35409
|
};
|
|
35302
35410
|
const file = logPath(root);
|
|
35303
|
-
await appendContained(root,
|
|
35411
|
+
await appendContained(root, path104.relative(root, file), `${JSON.stringify(full)}
|
|
35304
35412
|
`);
|
|
35305
35413
|
return full;
|
|
35306
35414
|
}
|
|
@@ -35327,7 +35435,7 @@ init_command_risk();
|
|
|
35327
35435
|
init_shell_syntax();
|
|
35328
35436
|
init_fs();
|
|
35329
35437
|
init_service2();
|
|
35330
|
-
import
|
|
35438
|
+
import path105 from "path";
|
|
35331
35439
|
import { createHash as createHash18 } from "crypto";
|
|
35332
35440
|
import { realpathSync as realpathSync2 } from "fs";
|
|
35333
35441
|
function impactEvidenceHookClass(strict) {
|
|
@@ -35343,29 +35451,29 @@ function realpathNearestExisting(p) {
|
|
|
35343
35451
|
for (;; ) {
|
|
35344
35452
|
try {
|
|
35345
35453
|
const real = realpathSync2(current);
|
|
35346
|
-
return tail.length > 0 ?
|
|
35454
|
+
return tail.length > 0 ? path105.join(real, ...tail) : real;
|
|
35347
35455
|
} catch {
|
|
35348
|
-
const parent =
|
|
35456
|
+
const parent = path105.dirname(current);
|
|
35349
35457
|
if (parent === current) {
|
|
35350
|
-
return tail.length > 0 ?
|
|
35458
|
+
return tail.length > 0 ? path105.join(current, ...tail) : current;
|
|
35351
35459
|
}
|
|
35352
|
-
tail.unshift(
|
|
35460
|
+
tail.unshift(path105.basename(current));
|
|
35353
35461
|
current = parent;
|
|
35354
35462
|
}
|
|
35355
35463
|
}
|
|
35356
35464
|
}
|
|
35357
35465
|
function normalizeRequestFiles(root, files) {
|
|
35358
|
-
const rootReal = realpathNearestExisting(
|
|
35466
|
+
const rootReal = realpathNearestExisting(path105.resolve(root));
|
|
35359
35467
|
const normalized = [];
|
|
35360
35468
|
const rejected = [];
|
|
35361
35469
|
for (const file of files) {
|
|
35362
|
-
const lexicalAbsolute =
|
|
35470
|
+
const lexicalAbsolute = path105.isAbsolute(file) ? path105.resolve(file) : path105.resolve(rootReal, toPosix(file).replace(/^\.\//, ""));
|
|
35363
35471
|
const effective = realpathNearestExisting(lexicalAbsolute);
|
|
35364
35472
|
if (!isPathInside(rootReal, effective)) {
|
|
35365
35473
|
rejected.push(file);
|
|
35366
35474
|
continue;
|
|
35367
35475
|
}
|
|
35368
|
-
normalized.push(toPosix(
|
|
35476
|
+
normalized.push(toPosix(path105.relative(rootReal, effective)));
|
|
35369
35477
|
}
|
|
35370
35478
|
return { files: [...new Set(normalized)], rejected };
|
|
35371
35479
|
}
|
|
@@ -35651,7 +35759,7 @@ __export(exports_service8, {
|
|
|
35651
35759
|
createJobService: () => createJobService
|
|
35652
35760
|
});
|
|
35653
35761
|
import { copyFile, mkdir as mkdir30 } from "fs/promises";
|
|
35654
|
-
import
|
|
35762
|
+
import path108 from "path";
|
|
35655
35763
|
|
|
35656
35764
|
// src/job/types.ts
|
|
35657
35765
|
var JOB_INTENTS = ["implement", "analyze", "review", "custom"];
|
|
@@ -35792,15 +35900,15 @@ init_validator();
|
|
|
35792
35900
|
init_contracts();
|
|
35793
35901
|
init_fs();
|
|
35794
35902
|
import { appendFile as appendFile6, mkdir as mkdir29, readFile as readFile52, readdir as readdir17 } from "fs/promises";
|
|
35795
|
-
import
|
|
35903
|
+
import path107 from "path";
|
|
35796
35904
|
function jobsRoot(cwd) {
|
|
35797
|
-
return
|
|
35905
|
+
return path107.join(cwd, ".metaproject", "jobs");
|
|
35798
35906
|
}
|
|
35799
35907
|
function jobDir(cwd, name) {
|
|
35800
|
-
return
|
|
35908
|
+
return path107.join(jobsRoot(cwd), name);
|
|
35801
35909
|
}
|
|
35802
35910
|
function jobStatePath(cwd, name) {
|
|
35803
|
-
return
|
|
35911
|
+
return path107.join(jobDir(cwd, name), "state.json");
|
|
35804
35912
|
}
|
|
35805
35913
|
var JOB_NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
35806
35914
|
function assertJobName(name) {
|
|
@@ -35837,12 +35945,12 @@ async function writeJob(cwd, name, state) {
|
|
|
35837
35945
|
`));
|
|
35838
35946
|
}
|
|
35839
35947
|
const file = jobStatePath(cwd, name);
|
|
35840
|
-
await mkdir29(
|
|
35948
|
+
await mkdir29(path107.dirname(file), { recursive: true });
|
|
35841
35949
|
await writeFileAtomic(file, `${JSON.stringify(state, null, 2)}
|
|
35842
35950
|
`);
|
|
35843
35951
|
}
|
|
35844
35952
|
async function appendJournal2(cwd, name, at, line) {
|
|
35845
|
-
await appendFile6(
|
|
35953
|
+
await appendFile6(path107.join(jobDir(cwd, name), "journal.md"), `- ${at} - ${line}
|
|
35846
35954
|
`, "utf8");
|
|
35847
35955
|
}
|
|
35848
35956
|
function renderJournal2(name, at) {
|
|
@@ -35863,7 +35971,7 @@ function assertDocumentType(raw) {
|
|
|
35863
35971
|
return raw;
|
|
35864
35972
|
}
|
|
35865
35973
|
function documentFileName(type, sourcePath) {
|
|
35866
|
-
const extension =
|
|
35974
|
+
const extension = path107.extname(sourcePath) || ".md";
|
|
35867
35975
|
return `${type}${extension}`;
|
|
35868
35976
|
}
|
|
35869
35977
|
|
|
@@ -35871,7 +35979,7 @@ function documentFileName(type, sourcePath) {
|
|
|
35871
35979
|
function createJobService(deps) {
|
|
35872
35980
|
const now = () => deps.now().toISOString();
|
|
35873
35981
|
function lockPath(cwd, name) {
|
|
35874
|
-
return
|
|
35982
|
+
return path108.join(jobsRoot(cwd), `.job-lock-${name}`);
|
|
35875
35983
|
}
|
|
35876
35984
|
async function mutate(cwd, name, run) {
|
|
35877
35985
|
assertJobName(name);
|
|
@@ -35920,20 +36028,20 @@ function createJobService(deps) {
|
|
|
35920
36028
|
},
|
|
35921
36029
|
plan: { steps: defaultPlan(intent) },
|
|
35922
36030
|
documentation: {
|
|
35923
|
-
job_path:
|
|
36031
|
+
job_path: path108.join(".metaproject", "jobs", name),
|
|
35924
36032
|
documents_created: []
|
|
35925
36033
|
},
|
|
35926
36034
|
metrics: { steps: [] },
|
|
35927
|
-
jobs_root:
|
|
36035
|
+
jobs_root: path108.join(".metaproject", "jobs"),
|
|
35928
36036
|
updated_at: createdAt
|
|
35929
36037
|
};
|
|
35930
36038
|
const first = firstOpenStep(state.plan.steps);
|
|
35931
36039
|
if (first) {
|
|
35932
36040
|
state.plan.current_step = first.id;
|
|
35933
36041
|
}
|
|
35934
|
-
await writeFileAtomic(
|
|
36042
|
+
await writeFileAtomic(path108.join(absolute, "journal.md"), renderJournal2(name, createdAt));
|
|
35935
36043
|
await writeJob(input.cwd, name, state);
|
|
35936
|
-
return { state, dir:
|
|
36044
|
+
return { state, dir: path108.relative(input.cwd, absolute) };
|
|
35937
36045
|
},
|
|
35938
36046
|
async status({ cwd, name }) {
|
|
35939
36047
|
assertJobName(name);
|
|
@@ -35945,7 +36053,7 @@ function createJobService(deps) {
|
|
|
35945
36053
|
}
|
|
35946
36054
|
return {
|
|
35947
36055
|
state,
|
|
35948
|
-
dir:
|
|
36056
|
+
dir: path108.join(".metaproject", "jobs", name),
|
|
35949
36057
|
stepsDone: state.plan.steps.filter((step) => isTerminalStep(step.status)).length,
|
|
35950
36058
|
stepsTotal: state.plan.steps.length,
|
|
35951
36059
|
nextStep: firstOpenStep(state.plan.steps),
|
|
@@ -36002,23 +36110,23 @@ function createJobService(deps) {
|
|
|
36002
36110
|
if (!input.file) {
|
|
36003
36111
|
throw new Error("Missing --file. Usage: keryx job document <name> --type <type> --file <path>");
|
|
36004
36112
|
}
|
|
36005
|
-
const source =
|
|
36113
|
+
const source = path108.isAbsolute(input.file) ? input.file : path108.join(input.cwd, input.file);
|
|
36006
36114
|
if (!await pathExists(source)) {
|
|
36007
36115
|
throw new Error(`--file not found: ${input.file}. Write the document first, then record it.`);
|
|
36008
36116
|
}
|
|
36009
36117
|
let recorded;
|
|
36010
36118
|
await mutate(input.cwd, input.name, async (state) => {
|
|
36011
36119
|
const fileName = documentFileName(type, source);
|
|
36012
|
-
const target =
|
|
36120
|
+
const target = path108.join(jobDir(input.cwd, state.job_name), fileName);
|
|
36013
36121
|
await copyFile(source, target);
|
|
36014
36122
|
state.documentation ??= {};
|
|
36015
|
-
state.documentation.job_path ??=
|
|
36123
|
+
state.documentation.job_path ??= path108.join(".metaproject", "jobs", state.job_name);
|
|
36016
36124
|
const created = state.documentation.documents_created ?? [];
|
|
36017
36125
|
state.documentation.documents_created = created.includes(fileName) ? created : [...created, fileName];
|
|
36018
36126
|
recorded = {
|
|
36019
36127
|
state,
|
|
36020
36128
|
document: fileName,
|
|
36021
|
-
path:
|
|
36129
|
+
path: path108.join(".metaproject", "jobs", state.job_name, fileName)
|
|
36022
36130
|
};
|
|
36023
36131
|
return { state, event: "document", detail: `${type} -> ${fileName}` };
|
|
36024
36132
|
});
|
|
@@ -36053,7 +36161,7 @@ function createJobService(deps) {
|
|
|
36053
36161
|
name: state.job_name,
|
|
36054
36162
|
phase: state.phase,
|
|
36055
36163
|
intent: state.intent,
|
|
36056
|
-
dir:
|
|
36164
|
+
dir: path108.join(".metaproject", "jobs", name),
|
|
36057
36165
|
stepsDone: state.plan.steps.filter((step) => isTerminalStep(step.status)).length,
|
|
36058
36166
|
stepsTotal: state.plan.steps.length,
|
|
36059
36167
|
nextStep: firstOpenStep(state.plan.steps)?.id ?? null
|
|
@@ -36158,12 +36266,12 @@ function normalizeWorkspaceReference(raw) {
|
|
|
36158
36266
|
// src/sac/fwk-service.ts
|
|
36159
36267
|
init_assembly();
|
|
36160
36268
|
import { appendFile as appendFile7, mkdir as mkdir32, open as open4, readFile as readFile55, rename as rename7, rm as rm6, stat as stat15, writeFile as writeFile22 } from "fs/promises";
|
|
36161
|
-
import
|
|
36269
|
+
import path112 from "path";
|
|
36162
36270
|
|
|
36163
36271
|
// src/sac/index.ts
|
|
36164
36272
|
import { access as access3, readFile as readFile53, realpath as realpath12 } from "fs/promises";
|
|
36165
36273
|
import { createHash as createHash19 } from "crypto";
|
|
36166
|
-
import
|
|
36274
|
+
import path109 from "path";
|
|
36167
36275
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
36168
36276
|
var idPattern = /^[a-z][a-z0-9-]{2,63}$/;
|
|
36169
36277
|
var subjectPattern = /^(?:user|team|service|agent):[a-z0-9][a-z0-9._-]{0,127}$/;
|
|
@@ -36181,21 +36289,21 @@ var normativeSchemaFiles = {
|
|
|
36181
36289
|
"review-decision": "review-decision.schema.json"
|
|
36182
36290
|
};
|
|
36183
36291
|
var normativeSchemas = new Map;
|
|
36184
|
-
var NORMATIVE_SCHEMA_DIR =
|
|
36292
|
+
var NORMATIVE_SCHEMA_DIR = path109.join("docs", "requirements", "shared-agent-context", "schemas");
|
|
36185
36293
|
async function resolveSacNormativeSchemaPath(fileName, searchFrom = [fileURLToPath3(new URL(".", import.meta.url)), process.cwd()]) {
|
|
36186
36294
|
const seen = new Set;
|
|
36187
36295
|
for (const start of searchFrom) {
|
|
36188
|
-
let dir =
|
|
36296
|
+
let dir = path109.resolve(start);
|
|
36189
36297
|
for (let i = 0;i < 10; i++) {
|
|
36190
36298
|
if (seen.has(dir))
|
|
36191
36299
|
break;
|
|
36192
36300
|
seen.add(dir);
|
|
36193
|
-
const candidate =
|
|
36301
|
+
const candidate = path109.join(dir, NORMATIVE_SCHEMA_DIR, fileName);
|
|
36194
36302
|
try {
|
|
36195
36303
|
await access3(candidate);
|
|
36196
36304
|
return candidate;
|
|
36197
36305
|
} catch {}
|
|
36198
|
-
const parent =
|
|
36306
|
+
const parent = path109.dirname(dir);
|
|
36199
36307
|
if (parent === dir)
|
|
36200
36308
|
break;
|
|
36201
36309
|
dir = parent;
|
|
@@ -36864,12 +36972,12 @@ class SacReferenceError extends Error {
|
|
|
36864
36972
|
code = "unsafe_workspace_reference";
|
|
36865
36973
|
}
|
|
36866
36974
|
async function resolveWorkspaceReference(input) {
|
|
36867
|
-
if (!workspacePathPattern.test(input.uri) ||
|
|
36975
|
+
if (!workspacePathPattern.test(input.uri) || path109.isAbsolute(input.uri) || /^[a-z][a-z0-9+.-]*:/i.test(input.uri) || input.uri.includes("\\"))
|
|
36868
36976
|
throw new SacReferenceError("unsafe workspace reference");
|
|
36869
|
-
const lexicalRoot =
|
|
36977
|
+
const lexicalRoot = path109.resolve(input.workspaceRoot);
|
|
36870
36978
|
const root = await realpath12(lexicalRoot);
|
|
36871
|
-
const candidate =
|
|
36872
|
-
if (candidate !== lexicalRoot && !candidate.startsWith(`${lexicalRoot}${
|
|
36979
|
+
const candidate = path109.resolve(lexicalRoot, input.uri.slice(2));
|
|
36980
|
+
if (candidate !== lexicalRoot && !candidate.startsWith(`${lexicalRoot}${path109.sep}`))
|
|
36873
36981
|
throw new SacReferenceError("workspace reference escapes root");
|
|
36874
36982
|
let resolved;
|
|
36875
36983
|
try {
|
|
@@ -36877,7 +36985,7 @@ async function resolveWorkspaceReference(input) {
|
|
|
36877
36985
|
} catch {
|
|
36878
36986
|
throw new SacReferenceError("workspace reference is not resolvable");
|
|
36879
36987
|
}
|
|
36880
|
-
if (resolved !== root && !resolved.startsWith(`${root}${
|
|
36988
|
+
if (resolved !== root && !resolved.startsWith(`${root}${path109.sep}`))
|
|
36881
36989
|
throw new SacReferenceError("workspace reference escapes root after realpath");
|
|
36882
36990
|
return candidate;
|
|
36883
36991
|
}
|
|
@@ -36933,16 +37041,16 @@ async function evaluateStrictSacGuard(input) {
|
|
|
36933
37041
|
init_fs();
|
|
36934
37042
|
import { mkdir as mkdir31, readdir as readdir18, readFile as readFile54 } from "fs/promises";
|
|
36935
37043
|
import { createHash as createHash20, randomUUID as randomUUID3 } from "crypto";
|
|
36936
|
-
import
|
|
37044
|
+
import path111 from "path";
|
|
36937
37045
|
|
|
36938
37046
|
// src/sac/secure-resource-read.ts
|
|
36939
37047
|
init_contained_read();
|
|
36940
37048
|
init_descriptor_read();
|
|
36941
|
-
import
|
|
37049
|
+
import path110 from "path";
|
|
36942
37050
|
function readWorkspaceFileNoFollow(workspaceRoot, absolutePath) {
|
|
36943
|
-
const relativePath =
|
|
36944
|
-
const components = relativePath.split(
|
|
36945
|
-
if (!relativePath ||
|
|
37051
|
+
const relativePath = path110.relative(workspaceRoot, absolutePath);
|
|
37052
|
+
const components = relativePath.split(path110.sep);
|
|
37053
|
+
if (!relativePath || path110.isAbsolute(relativePath) || components.some((component) => !component || component === "." || component === "..")) {
|
|
36946
37054
|
throw new Error("safe source path is not workspace-relative");
|
|
36947
37055
|
}
|
|
36948
37056
|
return readDescriptorChain(workspaceRoot, absolutePath, {
|
|
@@ -36969,8 +37077,8 @@ class WorkspaceService {
|
|
|
36969
37077
|
now;
|
|
36970
37078
|
constructor(options) {
|
|
36971
37079
|
this.options = options;
|
|
36972
|
-
this.root =
|
|
36973
|
-
this.storageRoot =
|
|
37080
|
+
this.root = path111.resolve(options.workspaceRoot);
|
|
37081
|
+
this.storageRoot = path111.resolve(options.storageRoot ?? path111.join(this.root, ".metaproject", "workspaces"));
|
|
36974
37082
|
this.now = options.now ?? (() => new Date);
|
|
36975
37083
|
}
|
|
36976
37084
|
async create(input) {
|
|
@@ -37295,13 +37403,13 @@ class WorkspaceService {
|
|
|
37295
37403
|
return parsed;
|
|
37296
37404
|
}
|
|
37297
37405
|
workspaceDir(id) {
|
|
37298
|
-
return
|
|
37406
|
+
return path111.join(this.storageRoot, id);
|
|
37299
37407
|
}
|
|
37300
37408
|
manifestPath(id) {
|
|
37301
|
-
return
|
|
37409
|
+
return path111.join(this.workspaceDir(id), "workspace.json");
|
|
37302
37410
|
}
|
|
37303
37411
|
lockPath(id) {
|
|
37304
|
-
return
|
|
37412
|
+
return path111.join(this.storageRoot, `.${id}.lock`);
|
|
37305
37413
|
}
|
|
37306
37414
|
timestamp() {
|
|
37307
37415
|
return this.now().toISOString();
|
|
@@ -38090,7 +38198,7 @@ function hasReportIntegrity(report) {
|
|
|
38090
38198
|
return reportHashPattern.test(reportDigest) && sha2565(body) === reportDigest;
|
|
38091
38199
|
}
|
|
38092
38200
|
async function resolvePolicySelection(workspaceRoot, canonicalFallback) {
|
|
38093
|
-
const configPath =
|
|
38201
|
+
const configPath = path112.join(workspaceRoot, ...policyExperimentConfigPath);
|
|
38094
38202
|
let configJson;
|
|
38095
38203
|
try {
|
|
38096
38204
|
const raw = await readFile55(configPath, "utf8").catch((error) => {
|
|
@@ -38288,9 +38396,9 @@ class FwkReadService {
|
|
|
38288
38396
|
const recordedAt = nowIso(now);
|
|
38289
38397
|
const id = `receipt-${randomUUID4().replace(/-/g, "").slice(0, 16)}`;
|
|
38290
38398
|
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"}` } : {} };
|
|
38291
|
-
const ledger =
|
|
38292
|
-
const checkpointPath =
|
|
38293
|
-
await mkdir32(
|
|
38399
|
+
const ledger = path112.join(this.options.canonical.workspaceRoot, ".metaproject", "context-operations", "access-receipts.jsonl");
|
|
38400
|
+
const checkpointPath = path112.join(path112.dirname(ledger), "access-receipts.checkpoint.json");
|
|
38401
|
+
await mkdir32(path112.dirname(ledger), { recursive: true, mode: 448 });
|
|
38294
38402
|
return withFileLock(`${ledger}.lock`, async () => {
|
|
38295
38403
|
const state = await resolveLedgerState(ledger, checkpointPath, this.options.verifyReceiptLedger ?? verifyAccessReceiptLedger);
|
|
38296
38404
|
const receipt = sealAccessReceipt(base, state.headHash);
|
|
@@ -38394,7 +38502,7 @@ function normalizeFwkResult(result) {
|
|
|
38394
38502
|
init_fs();
|
|
38395
38503
|
import { createHash as createHash30, randomUUID as randomUUID7 } from "crypto";
|
|
38396
38504
|
import { appendFile as appendFile8, mkdir as mkdir35, readdir as readdir21, readFile as readFile64 } from "fs/promises";
|
|
38397
|
-
import
|
|
38505
|
+
import path122 from "path";
|
|
38398
38506
|
|
|
38399
38507
|
// src/sac/trusted-wrap-up.ts
|
|
38400
38508
|
import { createHash as createHash24, randomUUID as randomUUID5 } from "crypto";
|
|
@@ -38466,7 +38574,7 @@ function bindingHash(owner, intent) {
|
|
|
38466
38574
|
// src/sac/session-wrap-up.ts
|
|
38467
38575
|
import { createHash as createHash26 } from "crypto";
|
|
38468
38576
|
import { mkdir as mkdir34, writeFile as writeFile23 } from "fs/promises";
|
|
38469
|
-
import
|
|
38577
|
+
import path116 from "path";
|
|
38470
38578
|
|
|
38471
38579
|
// src/session/store.ts
|
|
38472
38580
|
init_config_dir();
|
|
@@ -38478,12 +38586,12 @@ import {
|
|
|
38478
38586
|
renameSync as renameSync2,
|
|
38479
38587
|
writeFileSync as writeFileSync2
|
|
38480
38588
|
} from "fs";
|
|
38481
|
-
import
|
|
38589
|
+
import path115 from "path";
|
|
38482
38590
|
|
|
38483
38591
|
// src/session/paths.ts
|
|
38484
38592
|
import { existsSync as existsSync16 } from "fs";
|
|
38485
38593
|
import { homedir } from "os";
|
|
38486
|
-
import
|
|
38594
|
+
import path113 from "path";
|
|
38487
38595
|
function keryxDataDir(override) {
|
|
38488
38596
|
if (override !== undefined && override.length > 0) {
|
|
38489
38597
|
return override;
|
|
@@ -38495,22 +38603,22 @@ function keryxDataDir(override) {
|
|
|
38495
38603
|
const home = homedir();
|
|
38496
38604
|
if (process.platform === "win32") {
|
|
38497
38605
|
const appData = process.env.APPDATA;
|
|
38498
|
-
const base = appData !== undefined && appData.length > 0 ? appData :
|
|
38499
|
-
return
|
|
38606
|
+
const base = appData !== undefined && appData.length > 0 ? appData : path113.join(home, "AppData", "Roaming");
|
|
38607
|
+
return path113.join(base, "keryx");
|
|
38500
38608
|
}
|
|
38501
38609
|
const xdg = process.env.XDG_DATA_HOME;
|
|
38502
|
-
const base = xdg !== undefined && xdg.length > 0 ? xdg :
|
|
38503
|
-
return
|
|
38610
|
+
const base = xdg !== undefined && xdg.length > 0 ? xdg : path113.join(home, ".local", "share");
|
|
38611
|
+
return path113.join(base, "keryx");
|
|
38504
38612
|
}
|
|
38505
38613
|
function resolveProjectRoot2(cwd) {
|
|
38506
|
-
const abs =
|
|
38614
|
+
const abs = path113.resolve(cwd);
|
|
38507
38615
|
let dir = abs;
|
|
38508
38616
|
for (;; ) {
|
|
38509
|
-
const gitPath =
|
|
38617
|
+
const gitPath = path113.join(dir, ".git");
|
|
38510
38618
|
if (existsSync16(gitPath)) {
|
|
38511
38619
|
return dir;
|
|
38512
38620
|
}
|
|
38513
|
-
const parent =
|
|
38621
|
+
const parent = path113.dirname(dir);
|
|
38514
38622
|
if (parent === dir) {
|
|
38515
38623
|
break;
|
|
38516
38624
|
}
|
|
@@ -38519,12 +38627,12 @@ function resolveProjectRoot2(cwd) {
|
|
|
38519
38627
|
return abs;
|
|
38520
38628
|
}
|
|
38521
38629
|
function projectKeyFromPath(projectPath) {
|
|
38522
|
-
const abs =
|
|
38630
|
+
const abs = path113.resolve(projectPath);
|
|
38523
38631
|
const encoded = encodeURIComponent(abs);
|
|
38524
38632
|
if (encoded.length <= 200) {
|
|
38525
38633
|
return encoded;
|
|
38526
38634
|
}
|
|
38527
|
-
const base =
|
|
38635
|
+
const base = path113.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40);
|
|
38528
38636
|
let h = 0;
|
|
38529
38637
|
for (let i = 0;i < abs.length; i++) {
|
|
38530
38638
|
h = Math.imul(31, h) + abs.charCodeAt(i) | 0;
|
|
@@ -38534,17 +38642,17 @@ function projectKeyFromPath(projectPath) {
|
|
|
38534
38642
|
}
|
|
38535
38643
|
function projectSessionsDir(projectPath, dataDir) {
|
|
38536
38644
|
const key = projectKeyFromPath(resolveProjectRoot2(projectPath));
|
|
38537
|
-
return
|
|
38645
|
+
return path113.join(keryxDataDir(dataDir), "sessions", key);
|
|
38538
38646
|
}
|
|
38539
38647
|
function sessionDir(projectPath, sessionId, dataDir) {
|
|
38540
|
-
return
|
|
38648
|
+
return path113.join(projectSessionsDir(projectPath, dataDir), sessionId);
|
|
38541
38649
|
}
|
|
38542
38650
|
|
|
38543
38651
|
// src/session/slate.ts
|
|
38544
38652
|
init_fs();
|
|
38545
38653
|
init_assembly();
|
|
38546
38654
|
import { mkdir as mkdir33, readFile as readFile56, readdir as readdir19, rm as rm7, stat as stat16 } from "fs/promises";
|
|
38547
|
-
import
|
|
38655
|
+
import path114 from "path";
|
|
38548
38656
|
init_redact();
|
|
38549
38657
|
var SLATE_SEED_KINDS = [
|
|
38550
38658
|
"decision",
|
|
@@ -38559,7 +38667,7 @@ function isSlateSeedKind(value) {
|
|
|
38559
38667
|
}
|
|
38560
38668
|
var SEED_TEXT_MAX_LENGTH = 4000;
|
|
38561
38669
|
function slatePath(dir) {
|
|
38562
|
-
return
|
|
38670
|
+
return path114.join(dir, "slate.json");
|
|
38563
38671
|
}
|
|
38564
38672
|
function slateLockPath(dir) {
|
|
38565
38673
|
return `${slatePath(dir)}.lock`;
|
|
@@ -38789,11 +38897,11 @@ function listSessions(cwd, dataDir) {
|
|
|
38789
38897
|
if (name.startsWith(".")) {
|
|
38790
38898
|
continue;
|
|
38791
38899
|
}
|
|
38792
|
-
const summary = readSummaryFile(
|
|
38900
|
+
const summary = readSummaryFile(path115.join(root, name, "summary.json"));
|
|
38793
38901
|
if (summary === undefined) {
|
|
38794
38902
|
continue;
|
|
38795
38903
|
}
|
|
38796
|
-
if (
|
|
38904
|
+
if (path115.resolve(summary.projectPath) !== path115.resolve(projectPath)) {
|
|
38797
38905
|
continue;
|
|
38798
38906
|
}
|
|
38799
38907
|
out.push(summary);
|
|
@@ -38826,15 +38934,15 @@ async function readSessionSlate(cwd, sessionId, dataDir) {
|
|
|
38826
38934
|
}
|
|
38827
38935
|
function loadContext(cwd, sessionId, dataDir) {
|
|
38828
38936
|
const dir = sessionDir(resolveProjectRoot2(cwd), sessionId, dataDir);
|
|
38829
|
-
const contextPath =
|
|
38937
|
+
const contextPath = path115.join(dir, "context.jsonl");
|
|
38830
38938
|
if (existsSync17(contextPath)) {
|
|
38831
38939
|
return readJsonl2(contextPath);
|
|
38832
38940
|
}
|
|
38833
|
-
return readJsonl2(
|
|
38941
|
+
return readJsonl2(path115.join(dir, "transcript.jsonl"));
|
|
38834
38942
|
}
|
|
38835
38943
|
function loadArchive(cwd, sessionId, dataDir, onDegraded) {
|
|
38836
38944
|
const dir = sessionDir(resolveProjectRoot2(cwd), sessionId, dataDir);
|
|
38837
|
-
const archivePath =
|
|
38945
|
+
const archivePath = path115.join(dir, "archive.jsonl");
|
|
38838
38946
|
if (existsSync17(archivePath)) {
|
|
38839
38947
|
try {
|
|
38840
38948
|
const archive = readJsonl2(archivePath);
|
|
@@ -39018,7 +39126,7 @@ function sessionEvidenceRef(workspaceId, sessionId) {
|
|
|
39018
39126
|
}
|
|
39019
39127
|
async function resolveSessionWrapUp(input) {
|
|
39020
39128
|
const now = input.now ?? (() => new Date);
|
|
39021
|
-
const sessionId =
|
|
39129
|
+
const sessionId = path116.posix.basename(input.sourceRef, ".md");
|
|
39022
39130
|
const summary = findSession(input.cwd, sessionId);
|
|
39023
39131
|
if (summary === undefined || input.sourceRef !== sessionEvidenceRef(input.workspaceId, summary.id)) {
|
|
39024
39132
|
throw new SessionWrapUpError("session_not_found", `no session matching "${input.sourceRef}" in this project \u2014 use \`keryx sessions list\``);
|
|
@@ -39035,7 +39143,7 @@ async function resolveSessionWrapUp(input) {
|
|
|
39035
39143
|
throw new SessionWrapUpError("session_unreadable", `session "${summary.id}" could not be read: ${cause.message}`);
|
|
39036
39144
|
}
|
|
39037
39145
|
const relPath = sessionEvidenceRef(input.workspaceId, summary.id).slice(2);
|
|
39038
|
-
const evidenceDir =
|
|
39146
|
+
const evidenceDir = path116.dirname(relPath);
|
|
39039
39147
|
const slate = await readSessionSlate(input.cwd, summary.id);
|
|
39040
39148
|
const diff = await gitDiff(input.cwd);
|
|
39041
39149
|
const diffBody = diff.kind === "measured" ? diff.text : unmeasurableDiffBody(diff.detail);
|
|
@@ -39057,23 +39165,23 @@ async function resolveSessionWrapUp(input) {
|
|
|
39057
39165
|
""
|
|
39058
39166
|
].join(`
|
|
39059
39167
|
`);
|
|
39060
|
-
const wrapUpRelPath =
|
|
39061
|
-
const diffRelPath =
|
|
39062
|
-
const noticeRelPath =
|
|
39168
|
+
const wrapUpRelPath = path116.join(evidenceDir, `${summary.id}.wrap-up.md`);
|
|
39169
|
+
const diffRelPath = path116.join(evidenceDir, `${summary.id}.diff.txt`);
|
|
39170
|
+
const noticeRelPath = path116.join(evidenceDir, `${summary.id}.redaction.md`);
|
|
39063
39171
|
const floor = await applyEvidenceRedactionFloor(input.cwd, [
|
|
39064
|
-
{ name:
|
|
39065
|
-
{ name:
|
|
39066
|
-
{ name:
|
|
39172
|
+
{ name: path116.basename(relPath), content: markdown, path: relPath, source: "generated" },
|
|
39173
|
+
{ name: path116.basename(wrapUpRelPath), content: wrapUpMarkdown, path: wrapUpRelPath, source: "generated" },
|
|
39174
|
+
{ name: path116.basename(diffRelPath), content: diffBody, path: diffRelPath, source: "tool-output" }
|
|
39067
39175
|
]);
|
|
39068
39176
|
if (!floor.ok)
|
|
39069
39177
|
throw new SessionWrapUpError("security_denied", floor.reason);
|
|
39070
39178
|
const [safeSession, safeWrapUp, safeDiff] = floor.bodies;
|
|
39071
|
-
await mkdir34(
|
|
39072
|
-
await writeFile23(
|
|
39073
|
-
await writeFile23(
|
|
39074
|
-
await writeFile23(
|
|
39179
|
+
await mkdir34(path116.join(input.cwd, evidenceDir), { recursive: true });
|
|
39180
|
+
await writeFile23(path116.join(input.cwd, relPath), safeSession.content, "utf8");
|
|
39181
|
+
await writeFile23(path116.join(input.cwd, wrapUpRelPath), safeWrapUp.content, "utf8");
|
|
39182
|
+
await writeFile23(path116.join(input.cwd, diffRelPath), safeDiff.content, "utf8");
|
|
39075
39183
|
if (floor.notice !== undefined)
|
|
39076
|
-
await writeFile23(
|
|
39184
|
+
await writeFile23(path116.join(input.cwd, noticeRelPath), floor.notice, "utf8");
|
|
39077
39185
|
const observedAt = now().toISOString();
|
|
39078
39186
|
const evidence = [
|
|
39079
39187
|
{ kind: "wrap-up", uri: `./${wrapUpRelPath}`, revision: createHash26("sha256").update(safeWrapUp.content).digest("hex"), observedAt },
|
|
@@ -39096,13 +39204,13 @@ async function resolveSessionWrapUp(input) {
|
|
|
39096
39204
|
init_fs();
|
|
39097
39205
|
import { createHash as createHash27, randomBytes as randomBytes6 } from "crypto";
|
|
39098
39206
|
import { readFile as readFile57 } from "fs/promises";
|
|
39099
|
-
import
|
|
39207
|
+
import path117 from "path";
|
|
39100
39208
|
var CONFIRM_TOKEN_TTL_MS = 2 * 60000;
|
|
39101
39209
|
function confirmTokenPath2(cwd, workspaceId, proposalId) {
|
|
39102
|
-
return
|
|
39210
|
+
return path117.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.confirm-token.json`);
|
|
39103
39211
|
}
|
|
39104
39212
|
function confirmReceiptPath(cwd, workspaceId, proposalId, idempotencyKey) {
|
|
39105
|
-
return
|
|
39213
|
+
return path117.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${sha2566(idempotencyKey)}.confirm-receipt.json`);
|
|
39106
39214
|
}
|
|
39107
39215
|
function sha2566(text) {
|
|
39108
39216
|
return createHash27("sha256").update(text).digest("hex");
|
|
@@ -39143,21 +39251,21 @@ init_store();
|
|
|
39143
39251
|
init_config();
|
|
39144
39252
|
import { readFile as readFile59, readdir as readdir20 } from "fs/promises";
|
|
39145
39253
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
39146
|
-
import
|
|
39254
|
+
import path119 from "path";
|
|
39147
39255
|
|
|
39148
39256
|
// src/sac/proposal-evidence.ts
|
|
39149
39257
|
init_fs();
|
|
39150
39258
|
import { createHash as createHash28 } from "crypto";
|
|
39151
39259
|
import { readFile as readFile58, rm as rm8 } from "fs/promises";
|
|
39152
|
-
import
|
|
39260
|
+
import path118 from "path";
|
|
39153
39261
|
function proposalPath(cwd, workspaceId, proposalId) {
|
|
39154
|
-
return
|
|
39262
|
+
return path118.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
|
|
39155
39263
|
}
|
|
39156
39264
|
function ownerReceiptPath(cwd, owner, workspaceId, idempotencyKey) {
|
|
39157
|
-
return
|
|
39265
|
+
return path118.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-receipts`, `${idempotencyKey}.json`);
|
|
39158
39266
|
}
|
|
39159
39267
|
function proposalNotePath(cwd, workspaceId, proposalId) {
|
|
39160
|
-
return
|
|
39268
|
+
return path118.join(cwd, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.note.txt`);
|
|
39161
39269
|
}
|
|
39162
39270
|
async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
|
|
39163
39271
|
let proposal;
|
|
@@ -39171,7 +39279,7 @@ async function readVerifiedProposalEvidence(cwd, workspaceId, proposalId) {
|
|
|
39171
39279
|
return { ok: false, code: "no_evidence_to_write" };
|
|
39172
39280
|
let content;
|
|
39173
39281
|
try {
|
|
39174
|
-
content = await readFile58(
|
|
39282
|
+
content = await readFile58(path118.join(cwd, evidence.uri), "utf8");
|
|
39175
39283
|
} catch {
|
|
39176
39284
|
return { ok: false, code: "evidence_file_unreadable" };
|
|
39177
39285
|
}
|
|
@@ -39201,22 +39309,22 @@ function targetRelPath(targetRef) {
|
|
|
39201
39309
|
return targetRef.replace(/^\.\//, "");
|
|
39202
39310
|
}
|
|
39203
39311
|
function targetAbsolutePath(cwd, targetRef) {
|
|
39204
|
-
return
|
|
39312
|
+
return path118.join(cwd, ".metaproject", targetRelPath(targetRef));
|
|
39205
39313
|
}
|
|
39206
39314
|
function targetKey(targetRef) {
|
|
39207
39315
|
return digestOf2(targetRelPath(targetRef)).slice(0, 32);
|
|
39208
39316
|
}
|
|
39209
39317
|
function ownerTargetVersionPath(cwd, owner, workspaceId, targetRef) {
|
|
39210
|
-
return
|
|
39318
|
+
return path118.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-target-versions`, `${targetKey(targetRef)}.json`);
|
|
39211
39319
|
}
|
|
39212
39320
|
function ownerTargetLockPath(cwd, owner, targetRef) {
|
|
39213
|
-
return
|
|
39321
|
+
return path118.join(cwd, ".metaproject", "data", "sac", "target-locks", owner, `${targetKey(targetRef)}.lock`);
|
|
39214
39322
|
}
|
|
39215
39323
|
function ownerStagingDir(cwd, owner, workspaceId, idempotencyKey) {
|
|
39216
|
-
return
|
|
39324
|
+
return path118.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-staging`, digestOf2(idempotencyKey).slice(0, 32));
|
|
39217
39325
|
}
|
|
39218
39326
|
function ownerConflictDir(cwd, owner, workspaceId, idempotencyKey) {
|
|
39219
|
-
return
|
|
39327
|
+
return path118.join(cwd, ".metaproject", "workspaces", workspaceId, `${owner}-write-conflicts`, digestOf2(idempotencyKey).slice(0, 32));
|
|
39220
39328
|
}
|
|
39221
39329
|
async function readJson2(file) {
|
|
39222
39330
|
try {
|
|
@@ -39287,7 +39395,7 @@ async function applyGuardedTargetWrite(input) {
|
|
|
39287
39395
|
staged: input.staged,
|
|
39288
39396
|
stagedAt: receipt.completedAt
|
|
39289
39397
|
};
|
|
39290
|
-
await writeFileAtomic(
|
|
39398
|
+
await writeFileAtomic(path118.join(ownerStagingDir(cwd, owner, intent.workspaceId, intent.idempotencyKey), "plan.json"), `${JSON.stringify(staged, null, 2)}
|
|
39291
39399
|
`);
|
|
39292
39400
|
const applied = await input.apply(input.staged);
|
|
39293
39401
|
if (!applied.ok) {
|
|
@@ -39313,15 +39421,15 @@ async function recoverStagedOwnerWrite(input) {
|
|
|
39313
39421
|
});
|
|
39314
39422
|
}
|
|
39315
39423
|
async function readStagedOwnerWrite(cwd, owner, workspaceId, idempotencyKey) {
|
|
39316
|
-
return readJson2(
|
|
39424
|
+
return readJson2(path118.join(ownerStagingDir(cwd, owner, workspaceId, idempotencyKey), "plan.json"));
|
|
39317
39425
|
}
|
|
39318
39426
|
async function recordConflict(input) {
|
|
39319
39427
|
const base = { targetRef: input.targetRef, expectedVersion: input.expectedVersion, currentVersion: input.currentVersion };
|
|
39320
39428
|
if (input.proposedContent === undefined)
|
|
39321
39429
|
return base;
|
|
39322
39430
|
const dir = ownerConflictDir(input.cwd, input.owner, input.intent.workspaceId, input.intent.idempotencyKey);
|
|
39323
|
-
await writeFileAtomic(
|
|
39324
|
-
const diffRef = `./workspaces/${input.intent.workspaceId}/${input.owner}-write-conflicts/${
|
|
39431
|
+
await writeFileAtomic(path118.join(dir, "proposed"), input.proposedContent);
|
|
39432
|
+
const diffRef = `./workspaces/${input.intent.workspaceId}/${input.owner}-write-conflicts/${path118.basename(dir)}/proposed`;
|
|
39325
39433
|
return { ...base, diffRef };
|
|
39326
39434
|
}
|
|
39327
39435
|
|
|
@@ -39371,7 +39479,7 @@ async function resolveWorkspaceModule(cwd, workspaceId) {
|
|
|
39371
39479
|
}
|
|
39372
39480
|
}
|
|
39373
39481
|
async function collectWikiDecisionEntries(cwd) {
|
|
39374
|
-
const dir =
|
|
39482
|
+
const dir = path119.join(cwd, ".metaproject", "wiki", "decisions");
|
|
39375
39483
|
let files;
|
|
39376
39484
|
try {
|
|
39377
39485
|
files = (await readdir20(dir)).filter((name) => name.endsWith(".md"));
|
|
@@ -39380,12 +39488,12 @@ async function collectWikiDecisionEntries(cwd) {
|
|
|
39380
39488
|
}
|
|
39381
39489
|
const entries = [];
|
|
39382
39490
|
for (const file of files) {
|
|
39383
|
-
const absolutePath =
|
|
39491
|
+
const absolutePath = path119.join(dir, file);
|
|
39384
39492
|
try {
|
|
39385
39493
|
const content = await readFile59(absolutePath, "utf8");
|
|
39386
39494
|
entries.push({
|
|
39387
39495
|
absolutePath,
|
|
39388
|
-
relativePath:
|
|
39496
|
+
relativePath: path119.posix.join("decisions", file),
|
|
39389
39497
|
type: extractHeaderField(content, "Type") ?? "decision",
|
|
39390
39498
|
title: extractTitle(content),
|
|
39391
39499
|
version: extractHeaderField(content, "Version") ?? null,
|
|
@@ -39607,7 +39715,7 @@ function createRealMemoryOwnerWriter(cwd, opts) {
|
|
|
39607
39715
|
init_service4();
|
|
39608
39716
|
init_guard();
|
|
39609
39717
|
import { readFile as readFile61 } from "fs/promises";
|
|
39610
|
-
import
|
|
39718
|
+
import path120 from "path";
|
|
39611
39719
|
function renderWrapUpDecisionPage(input) {
|
|
39612
39720
|
const note = input.note?.trim();
|
|
39613
39721
|
return `# ${input.title}
|
|
@@ -39648,7 +39756,7 @@ export is the source of truth for what actually happened.
|
|
|
39648
39756
|
`;
|
|
39649
39757
|
}
|
|
39650
39758
|
function wikiPageRelativePath(proposalId) {
|
|
39651
|
-
return
|
|
39759
|
+
return path120.posix.join("decisions", `sac-${proposalId}.md`);
|
|
39652
39760
|
}
|
|
39653
39761
|
function createRealWikiOwnerWriter(cwd, opts) {
|
|
39654
39762
|
const now = opts?.now ?? (() => new Date);
|
|
@@ -39656,7 +39764,7 @@ function createRealWikiOwnerWriter(cwd, opts) {
|
|
|
39656
39764
|
const relativePath = staged.relativePath;
|
|
39657
39765
|
const content = staged.content;
|
|
39658
39766
|
const history = await openWikiWriteContext(cwd, "sac proposal accept");
|
|
39659
|
-
await writeWikiPage(history,
|
|
39767
|
+
await writeWikiPage(history, path120.join(cwd, ".metaproject", "wiki", relativePath), content);
|
|
39660
39768
|
return { ok: true };
|
|
39661
39769
|
};
|
|
39662
39770
|
return {
|
|
@@ -39726,7 +39834,7 @@ init_guard();
|
|
|
39726
39834
|
import { createHash as createHash29 } from "crypto";
|
|
39727
39835
|
import { homedir as homedir2 } from "os";
|
|
39728
39836
|
import { readFile as readFile62, stat as stat17 } from "fs/promises";
|
|
39729
|
-
import
|
|
39837
|
+
import path121 from "path";
|
|
39730
39838
|
var VERSION = "0.1.0";
|
|
39731
39839
|
var PROJECT_SKILLS_DIR = ".metaproject/project-skills";
|
|
39732
39840
|
var PROJECT_SKILLS_MANIFEST_PATH = ".metaproject/metaproject.json";
|
|
@@ -39756,7 +39864,7 @@ async function assertProjectWritesContained(projectRoot, paths) {
|
|
|
39756
39864
|
}
|
|
39757
39865
|
}
|
|
39758
39866
|
async function createProjectSkill(projectRoot, options) {
|
|
39759
|
-
const metaprojectRoot =
|
|
39867
|
+
const metaprojectRoot = path121.join(projectRoot, ".metaproject");
|
|
39760
39868
|
if (!await pathExists(metaprojectRoot)) {
|
|
39761
39869
|
throw new Error("Metaproject is not initialized. Run: keryx init");
|
|
39762
39870
|
}
|
|
@@ -39767,7 +39875,7 @@ async function createProjectSkill(projectRoot, options) {
|
|
|
39767
39875
|
const skillName = projectSkillSlug(options.name ?? inferSkillName(options.target));
|
|
39768
39876
|
const format = options.format ?? "auto";
|
|
39769
39877
|
const relativeSkillPath = projectSkillPackagePath(moduleName, skillName);
|
|
39770
|
-
const packageRoot =
|
|
39878
|
+
const packageRoot = path121.join(projectRoot, relativeSkillPath);
|
|
39771
39879
|
await assertProjectWritesContained(projectRoot, projectSkillWritePaths(moduleName, skillName, format));
|
|
39772
39880
|
const origin = options.origin ? options.originContent !== undefined ? {
|
|
39773
39881
|
ref: options.origin.trim(),
|
|
@@ -39778,7 +39886,7 @@ async function createProjectSkill(projectRoot, options) {
|
|
|
39778
39886
|
const warnings = collectWarnings(evidence, format);
|
|
39779
39887
|
const files = filesForPackage(packageRoot, format);
|
|
39780
39888
|
if (!options.dryRun) {
|
|
39781
|
-
await withFileLock(
|
|
39889
|
+
await withFileLock(path121.join(projectRoot, PROJECT_SKILLS_LOCK_PATH), async () => {
|
|
39782
39890
|
await writeProjectSkillPackage({
|
|
39783
39891
|
projectRoot,
|
|
39784
39892
|
packageRoot,
|
|
@@ -39807,7 +39915,7 @@ async function createProjectSkill(projectRoot, options) {
|
|
|
39807
39915
|
name: skillName,
|
|
39808
39916
|
target: options.target,
|
|
39809
39917
|
skillPath: relativeSkillPath,
|
|
39810
|
-
files: files.map((filePath) => toPosix(
|
|
39918
|
+
files: files.map((filePath) => toPosix(path121.relative(projectRoot, filePath))),
|
|
39811
39919
|
warnings,
|
|
39812
39920
|
dryRun: options.dryRun === true
|
|
39813
39921
|
};
|
|
@@ -39816,9 +39924,9 @@ var MAX_SKILL_TARGET_LENGTH = 80;
|
|
|
39816
39924
|
function resolveOriginPath(ref, projectRoot) {
|
|
39817
39925
|
const trimmed = ref.trim();
|
|
39818
39926
|
if (trimmed === "~" || trimmed.startsWith("~/")) {
|
|
39819
|
-
return
|
|
39927
|
+
return path121.join(homedir2(), trimmed.slice(1));
|
|
39820
39928
|
}
|
|
39821
|
-
return
|
|
39929
|
+
return path121.resolve(projectRoot, trimmed);
|
|
39822
39930
|
}
|
|
39823
39931
|
function hashOriginContent(content) {
|
|
39824
39932
|
return `sha256:${createHash29("sha256").update(content).digest("hex")}`;
|
|
@@ -39856,16 +39964,16 @@ async function writeProjectSkillPackage({
|
|
|
39856
39964
|
}) {
|
|
39857
39965
|
const packageFormat = format === "single" ? "single" : "package";
|
|
39858
39966
|
const skillContent = renderProjectSkill({ moduleName, skillName, target, note, origin, evidence, packageFormat });
|
|
39859
|
-
const relativeSkillMdPath = toPosix(
|
|
39967
|
+
const relativeSkillMdPath = toPosix(path121.join(path121.relative(projectRoot, packageRoot), "SKILL.md"));
|
|
39860
39968
|
const guard = await guardOutput({ cwd: projectRoot, content: skillContent, target: "skill", source: "generated", path: relativeSkillMdPath });
|
|
39861
39969
|
const output = prepareOutputForPersistence(guard, skillContent);
|
|
39862
39970
|
if (!output.allowed) {
|
|
39863
39971
|
throw new Error(`Project skill blocked by the security gate: ${output.reason}`);
|
|
39864
39972
|
}
|
|
39865
|
-
const packageRel = toPosix(
|
|
39973
|
+
const packageRel = toPosix(path121.relative(projectRoot, packageRoot));
|
|
39866
39974
|
const write = (file, content) => writeContained(projectRoot, `${packageRel}/${file}`, content);
|
|
39867
39975
|
await write("SKILL.md", output.content);
|
|
39868
|
-
if (!await pathExists(
|
|
39976
|
+
if (!await pathExists(path121.join(packageRoot, "skill-changelog.md"))) {
|
|
39869
39977
|
await write("skill-changelog.md", renderSkillChangelog({ moduleName, skillName, target }));
|
|
39870
39978
|
}
|
|
39871
39979
|
if (packageFormat === "package") {
|
|
@@ -39875,10 +39983,10 @@ async function writeProjectSkillPackage({
|
|
|
39875
39983
|
}
|
|
39876
39984
|
}
|
|
39877
39985
|
async function collectEvidence(projectRoot, target) {
|
|
39878
|
-
const absoluteTarget =
|
|
39986
|
+
const absoluteTarget = path121.resolve(projectRoot, target);
|
|
39879
39987
|
const targetExists = await pathExists(absoluteTarget);
|
|
39880
39988
|
const targetKind = await classifyTarget(absoluteTarget, targetExists);
|
|
39881
|
-
const maybeRelativeTarget = targetExists ? toPosix(
|
|
39989
|
+
const maybeRelativeTarget = targetExists ? toPosix(path121.relative(projectRoot, absoluteTarget)) : undefined;
|
|
39882
39990
|
const graphArtifacts = await existingRelativePaths(projectRoot, [
|
|
39883
39991
|
".metaproject/data/gdgraph/artifacts/summary.md",
|
|
39884
39992
|
".metaproject/data/gdgraph/artifacts/module-map.json"
|
|
@@ -39908,7 +40016,7 @@ async function classifyTarget(absoluteTarget, targetExists) {
|
|
|
39908
40016
|
async function existingRelativePaths(projectRoot, candidates) {
|
|
39909
40017
|
const existing = [];
|
|
39910
40018
|
for (const candidate of candidates) {
|
|
39911
|
-
if (await pathExists(
|
|
40019
|
+
if (await pathExists(path121.join(projectRoot, candidate))) {
|
|
39912
40020
|
existing.push(candidate);
|
|
39913
40021
|
}
|
|
39914
40022
|
}
|
|
@@ -39935,17 +40043,17 @@ function collectWarnings(evidence, format) {
|
|
|
39935
40043
|
}
|
|
39936
40044
|
function filesForPackage(packageRoot, format) {
|
|
39937
40045
|
const base = [
|
|
39938
|
-
|
|
39939
|
-
|
|
40046
|
+
path121.join(packageRoot, "SKILL.md"),
|
|
40047
|
+
path121.join(packageRoot, "skill-changelog.md")
|
|
39940
40048
|
];
|
|
39941
40049
|
if (format === "single") {
|
|
39942
40050
|
return base;
|
|
39943
40051
|
}
|
|
39944
40052
|
return [
|
|
39945
40053
|
...base,
|
|
39946
|
-
|
|
39947
|
-
|
|
39948
|
-
|
|
40054
|
+
path121.join(packageRoot, "verification.md"),
|
|
40055
|
+
path121.join(packageRoot, "references", "context.md"),
|
|
40056
|
+
path121.join(packageRoot, "templates", "README.md")
|
|
39949
40057
|
];
|
|
39950
40058
|
}
|
|
39951
40059
|
function renderProjectSkill({
|
|
@@ -40173,7 +40281,7 @@ keryx skills verify ${moduleName}/${skillName}
|
|
|
40173
40281
|
`;
|
|
40174
40282
|
}
|
|
40175
40283
|
async function updateManifest(projectRoot, entry) {
|
|
40176
|
-
const manifestPath =
|
|
40284
|
+
const manifestPath = path121.join(projectRoot, PROJECT_SKILLS_MANIFEST_PATH);
|
|
40177
40285
|
const manifest = await readJsonFileOr(manifestPath, {});
|
|
40178
40286
|
manifest.modules ??= {};
|
|
40179
40287
|
manifest.modules.gdskills ??= {};
|
|
@@ -40187,8 +40295,8 @@ async function updateManifest(projectRoot, entry) {
|
|
|
40187
40295
|
`);
|
|
40188
40296
|
}
|
|
40189
40297
|
async function updateSkillsCatalog(projectRoot) {
|
|
40190
|
-
const manifestPath =
|
|
40191
|
-
const catalogPath =
|
|
40298
|
+
const manifestPath = path121.join(projectRoot, PROJECT_SKILLS_MANIFEST_PATH);
|
|
40299
|
+
const catalogPath = path121.join(projectRoot, PROJECT_SKILLS_CATALOG_PATH);
|
|
40192
40300
|
const manifest = await readJsonFileOr(manifestPath, {});
|
|
40193
40301
|
const registry = manifest.modules?.gdskills?.projectSkillRegistry ?? [];
|
|
40194
40302
|
const rows = registry.length > 0 ? registry.map(projectSkillCatalogRow).join(`
|
|
@@ -40228,7 +40336,7 @@ function inferModule(target) {
|
|
|
40228
40336
|
}
|
|
40229
40337
|
function inferSkillName(target) {
|
|
40230
40338
|
const normalized = target.trim().replace(/[#:]+/g, "/");
|
|
40231
|
-
const base =
|
|
40339
|
+
const base = path121.basename(normalized).replace(/\.[^.]+$/, "");
|
|
40232
40340
|
return base || "entity";
|
|
40233
40341
|
}
|
|
40234
40342
|
function projectSkillSlug(value) {
|
|
@@ -40333,7 +40441,7 @@ class ProposalLifecycleService {
|
|
|
40333
40441
|
now;
|
|
40334
40442
|
constructor(options) {
|
|
40335
40443
|
this.options = options;
|
|
40336
|
-
this.root =
|
|
40444
|
+
this.root = path122.resolve(options.workspaceRoot);
|
|
40337
40445
|
this.now = options.now ?? (() => new Date);
|
|
40338
40446
|
}
|
|
40339
40447
|
async create(input) {
|
|
@@ -40352,7 +40460,7 @@ class ProposalLifecycleService {
|
|
|
40352
40460
|
if (manifest.status === "archived")
|
|
40353
40461
|
throw new ProposalLifecycleError("guard_denied", "workspace is archived");
|
|
40354
40462
|
const file = this.proposalPath(workspaceId, proposal.id);
|
|
40355
|
-
await mkdir35(
|
|
40463
|
+
await mkdir35(path122.dirname(file), { recursive: true, mode: 448 });
|
|
40356
40464
|
return withFileLock(`${file}.lock`, async () => {
|
|
40357
40465
|
const consume = this.options.wrapUpAuthority.consume(input.wrapUp, { actor, workspaceId });
|
|
40358
40466
|
if (consume !== "ok")
|
|
@@ -40380,7 +40488,7 @@ class ProposalLifecycleService {
|
|
|
40380
40488
|
return this.options.workspaces.withAuthorizedActor({ actorContext: actor, workspaceId: input.workspaceId, action: "review", execute: async (manifest) => {
|
|
40381
40489
|
const proposal = await this.loadProposal(input.workspaceId, input.proposalId);
|
|
40382
40490
|
const ledger = this.ledgerPath(input.workspaceId);
|
|
40383
|
-
await mkdir35(
|
|
40491
|
+
await mkdir35(path122.dirname(ledger), { recursive: true, mode: 448 });
|
|
40384
40492
|
return withFileLock(`${ledger}.lock`, async () => {
|
|
40385
40493
|
const records = (await this.records(ledger)).filter((record) => record.proposalId === proposal.id);
|
|
40386
40494
|
const events = records.filter((record) => record.recordType === "proposal-transition");
|
|
@@ -40422,7 +40530,7 @@ class ProposalLifecycleService {
|
|
|
40422
40530
|
} });
|
|
40423
40531
|
}
|
|
40424
40532
|
async listProposedProposals(workspaceId) {
|
|
40425
|
-
const proposalsDir =
|
|
40533
|
+
const proposalsDir = path122.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals");
|
|
40426
40534
|
let entries;
|
|
40427
40535
|
try {
|
|
40428
40536
|
entries = (await readdir21(proposalsDir)).filter((name) => name.endsWith(".json"));
|
|
@@ -40434,7 +40542,7 @@ class ProposalLifecycleService {
|
|
|
40434
40542
|
const proposals = [];
|
|
40435
40543
|
for (const entry of entries) {
|
|
40436
40544
|
try {
|
|
40437
|
-
const parsed = JSON.parse(await readFile64(
|
|
40545
|
+
const parsed = JSON.parse(await readFile64(path122.join(proposalsDir, entry), "utf8"));
|
|
40438
40546
|
if (parsed.recordType === "proposal-created")
|
|
40439
40547
|
proposals.push(parsed);
|
|
40440
40548
|
} catch {}
|
|
@@ -40700,31 +40808,31 @@ class ProposalLifecycleService {
|
|
|
40700
40808
|
}
|
|
40701
40809
|
}
|
|
40702
40810
|
proposalPath(workspaceId, proposalId) {
|
|
40703
|
-
return
|
|
40811
|
+
return path122.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.json`);
|
|
40704
40812
|
}
|
|
40705
40813
|
decisionRef(proposalId, key) {
|
|
40706
40814
|
return `./proposals/${proposalId}.${hash(key)}.decision.json`;
|
|
40707
40815
|
}
|
|
40708
40816
|
decisionPath(workspaceId, proposalId, key) {
|
|
40709
|
-
return
|
|
40817
|
+
return path122.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.decision.json`);
|
|
40710
40818
|
}
|
|
40711
40819
|
approvalRef(proposalId, key) {
|
|
40712
40820
|
return `./proposals/${proposalId}.${hash(key)}.approval.json`;
|
|
40713
40821
|
}
|
|
40714
40822
|
approvalPath(workspaceId, proposalId, key) {
|
|
40715
|
-
return
|
|
40823
|
+
return path122.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.approval.json`);
|
|
40716
40824
|
}
|
|
40717
40825
|
writeResultPath(workspaceId, proposalId, key) {
|
|
40718
|
-
return
|
|
40826
|
+
return path122.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-result.json`);
|
|
40719
40827
|
}
|
|
40720
40828
|
intentRef(proposalId, key) {
|
|
40721
40829
|
return `./proposals/${proposalId}.${hash(key)}.write-intent.json`;
|
|
40722
40830
|
}
|
|
40723
40831
|
intentPath(workspaceId, proposalId, key) {
|
|
40724
|
-
return
|
|
40832
|
+
return path122.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.write-intent.json`);
|
|
40725
40833
|
}
|
|
40726
40834
|
attemptPath(workspaceId, proposalId, key) {
|
|
40727
|
-
return
|
|
40835
|
+
return path122.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals", `${proposalId}.${hash(key)}.owner-write-attempt.json`);
|
|
40728
40836
|
}
|
|
40729
40837
|
async loadWriteResult(workspaceId, proposalId, key) {
|
|
40730
40838
|
try {
|
|
@@ -40751,7 +40859,7 @@ class ProposalLifecycleService {
|
|
|
40751
40859
|
}
|
|
40752
40860
|
}
|
|
40753
40861
|
ledgerPath(workspaceId) {
|
|
40754
|
-
return
|
|
40862
|
+
return path122.join(this.root, ".metaproject", "workspaces", workspaceId, "activity.jsonl");
|
|
40755
40863
|
}
|
|
40756
40864
|
timestamp() {
|
|
40757
40865
|
return this.now().toISOString();
|
|
@@ -40834,7 +40942,7 @@ function normalizeProposalLifecycleResult(value) {
|
|
|
40834
40942
|
// src/sac/collaboration-service.ts
|
|
40835
40943
|
import { appendFile as appendFile9, mkdir as mkdir36, readFile as readFile65 } from "fs/promises";
|
|
40836
40944
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
40837
|
-
import
|
|
40945
|
+
import path123 from "path";
|
|
40838
40946
|
class CollaborationServiceError extends Error {
|
|
40839
40947
|
code;
|
|
40840
40948
|
constructor(code, message) {
|
|
@@ -40849,7 +40957,7 @@ class CollaborationService {
|
|
|
40849
40957
|
this.input = input;
|
|
40850
40958
|
}
|
|
40851
40959
|
file(id) {
|
|
40852
|
-
return
|
|
40960
|
+
return path123.join(this.input.workspaceRoot, ".metaproject", "workspaces", id, "activity.jsonl");
|
|
40853
40961
|
}
|
|
40854
40962
|
async overview(input) {
|
|
40855
40963
|
const manifest = await this.input.workspaces.show(input);
|
|
@@ -40886,7 +40994,7 @@ class CollaborationService {
|
|
|
40886
40994
|
occurredAt: (this.input.now ?? (() => new Date))().toISOString(),
|
|
40887
40995
|
...suppliedHandoff ? { handoff: { ...suppliedHandoff, from: actor.subject } } : {}
|
|
40888
40996
|
});
|
|
40889
|
-
await mkdir36(
|
|
40997
|
+
await mkdir36(path123.dirname(this.file(manifest.id)), { recursive: true, mode: 448 });
|
|
40890
40998
|
await appendFile9(this.file(manifest.id), `${JSON.stringify(activity)}
|
|
40891
40999
|
`, { mode: 384 });
|
|
40892
41000
|
return normalizeCollaborationResult(activity);
|
|
@@ -40936,13 +41044,13 @@ function normalizeCollaborationResult(value) {
|
|
|
40936
41044
|
// src/session/external-slate.ts
|
|
40937
41045
|
init_fs();
|
|
40938
41046
|
import { mkdir as mkdir38, readdir as readdir22, readFile as readFile66 } from "fs/promises";
|
|
40939
|
-
import
|
|
41047
|
+
import path125 from "path";
|
|
40940
41048
|
|
|
40941
41049
|
// src/sac/machine-wrap-up.ts
|
|
40942
41050
|
init_fs();
|
|
40943
41051
|
import { createHash as createHash31, randomUUID as randomUUID10 } from "crypto";
|
|
40944
41052
|
import { mkdir as mkdir37 } from "fs/promises";
|
|
40945
|
-
import
|
|
41053
|
+
import path124 from "path";
|
|
40946
41054
|
|
|
40947
41055
|
// src/sac/workspace-resolve.ts
|
|
40948
41056
|
init_redact();
|
|
@@ -41083,11 +41191,11 @@ async function resolveMachineWrapUp(input) {
|
|
|
41083
41191
|
`;
|
|
41084
41192
|
const seedsJson = `${JSON.stringify(seedsForKind.map((seed) => ({ text: seed.text, source: describeSource(seed.source) })), null, 2)}
|
|
41085
41193
|
`;
|
|
41086
|
-
const evidenceRelBase =
|
|
41194
|
+
const evidenceRelBase = path124.posix.join(".metaproject", "workspaces", input.workspaceId, "machine-evidence");
|
|
41087
41195
|
const floor = await applyEvidenceRedactionFloor(input.cwd, [
|
|
41088
|
-
{ name: `${input.kind}.diff.txt`, content: diffBody, path:
|
|
41089
|
-
{ name: `${input.kind}.flow.json`, content: flowSnapshotJson, path:
|
|
41090
|
-
{ name: `${input.kind}.seeds.json`, content: seedsJson, path:
|
|
41196
|
+
{ name: `${input.kind}.diff.txt`, content: diffBody, path: path124.posix.join(evidenceRelBase, `${input.kind}.diff.txt`), source: "tool-output" },
|
|
41197
|
+
{ name: `${input.kind}.flow.json`, content: flowSnapshotJson, path: path124.posix.join(evidenceRelBase, `${input.kind}.flow.json`), source: "generated" },
|
|
41198
|
+
{ name: `${input.kind}.seeds.json`, content: seedsJson, path: path124.posix.join(evidenceRelBase, `${input.kind}.seeds.json`), source: "generated" }
|
|
41091
41199
|
]);
|
|
41092
41200
|
if (!floor.ok)
|
|
41093
41201
|
return { ok: false, code: "security_denied", detail: floor.reason };
|
|
@@ -41141,14 +41249,14 @@ ${safeSeeds.content}`;
|
|
|
41141
41249
|
}
|
|
41142
41250
|
summary = result.text.trim().length > 0 ? result.text.trim() : mechanicalSummary(summaryDiff, course);
|
|
41143
41251
|
}
|
|
41144
|
-
const evidenceDir =
|
|
41252
|
+
const evidenceDir = path124.join(input.cwd, ".metaproject", "workspaces", input.workspaceId, "machine-evidence");
|
|
41145
41253
|
await mkdir37(evidenceDir, { recursive: true });
|
|
41146
41254
|
const diffFile = `${input.kind}.${shortHash}.diff.txt`;
|
|
41147
41255
|
const flowFile = `${input.kind}.${shortHash}.flow.json`;
|
|
41148
41256
|
const seedsFile = `${input.kind}.${shortHash}.seeds.json`;
|
|
41149
|
-
await writeFileAtomic(
|
|
41150
|
-
await writeFileAtomic(
|
|
41151
|
-
await writeFileAtomic(
|
|
41257
|
+
await writeFileAtomic(path124.join(evidenceDir, diffFile), safeDiff.content);
|
|
41258
|
+
await writeFileAtomic(path124.join(evidenceDir, flowFile), safeFlow.content);
|
|
41259
|
+
await writeFileAtomic(path124.join(evidenceDir, seedsFile), safeSeeds.content);
|
|
41152
41260
|
const observedAt = now().toISOString();
|
|
41153
41261
|
const relBase = `./.metaproject/workspaces/${input.workspaceId}/machine-evidence`;
|
|
41154
41262
|
const evidence = [
|
|
@@ -41158,7 +41266,7 @@ ${safeSeeds.content}`;
|
|
|
41158
41266
|
];
|
|
41159
41267
|
if (floor.notice !== undefined) {
|
|
41160
41268
|
const noticeFile = `${input.kind}.${shortHash}.redaction.md`;
|
|
41161
|
-
await writeFileAtomic(
|
|
41269
|
+
await writeFileAtomic(path124.join(evidenceDir, noticeFile), floor.notice);
|
|
41162
41270
|
evidence.push({ kind: REDACTION_NOTICE_KIND, uri: `${relBase}/${noticeFile}`, revision: sha2567(floor.notice), observedAt });
|
|
41163
41271
|
}
|
|
41164
41272
|
return {
|
|
@@ -41177,18 +41285,18 @@ async function writeFlooredArchiveArtifact(params) {
|
|
|
41177
41285
|
{
|
|
41178
41286
|
name: params.filename,
|
|
41179
41287
|
content: params.content,
|
|
41180
|
-
path:
|
|
41288
|
+
path: path124.posix.join("slate-archive", params.filename),
|
|
41181
41289
|
source: "generated"
|
|
41182
41290
|
}
|
|
41183
41291
|
]);
|
|
41184
41292
|
if (!floor.ok)
|
|
41185
41293
|
return { ok: false, code: "security_denied", detail: floor.reason };
|
|
41186
41294
|
const body = floor.bodies[0];
|
|
41187
|
-
const archiveDir =
|
|
41295
|
+
const archiveDir = path124.join(params.dir, "slate-archive");
|
|
41188
41296
|
await mkdir37(archiveDir, { recursive: true });
|
|
41189
|
-
await writeFileAtomic(
|
|
41297
|
+
await writeFileAtomic(path124.join(archiveDir, params.filename), body.content);
|
|
41190
41298
|
if (floor.notice !== undefined) {
|
|
41191
|
-
await writeFileAtomic(
|
|
41299
|
+
await writeFileAtomic(path124.join(archiveDir, `${params.filename}${ARCHIVE_REDACTION_NOTICE_SUFFIX}`), floor.notice);
|
|
41192
41300
|
}
|
|
41193
41301
|
return { ok: true, altered: body.altered };
|
|
41194
41302
|
}
|
|
@@ -41224,9 +41332,9 @@ async function writeWrapUpOutcomeArtifact(cwd, dir, trigger, now, groups) {
|
|
|
41224
41332
|
return;
|
|
41225
41333
|
const refusalIso = now().toISOString();
|
|
41226
41334
|
const refusalFilename = `${refusalIso.replace(/[:.]/g, "-")}-wrap-up-outcome.json`;
|
|
41227
|
-
const archiveDir =
|
|
41335
|
+
const archiveDir = path124.join(dir, "slate-archive");
|
|
41228
41336
|
await mkdir37(archiveDir, { recursive: true });
|
|
41229
|
-
await writeFileAtomic(
|
|
41337
|
+
await writeFileAtomic(path124.join(archiveDir, refusalFilename), `${JSON.stringify({
|
|
41230
41338
|
recordType: "wrap-up-outcome",
|
|
41231
41339
|
trigger,
|
|
41232
41340
|
generatedAt: refusalIso,
|
|
@@ -41362,7 +41470,7 @@ async function runWrapUp(input) {
|
|
|
41362
41470
|
|
|
41363
41471
|
// src/session/external-slate.ts
|
|
41364
41472
|
function externalSlatesDir(cwd) {
|
|
41365
|
-
return
|
|
41473
|
+
return path125.join(cwd, ".keryx", "external-slates");
|
|
41366
41474
|
}
|
|
41367
41475
|
var EXTERNAL_SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
41368
41476
|
function assertValidExternalSessionId(externalSessionId) {
|
|
@@ -41372,14 +41480,14 @@ function assertValidExternalSessionId(externalSessionId) {
|
|
|
41372
41480
|
}
|
|
41373
41481
|
function externalSlatePath(cwd, externalSessionId) {
|
|
41374
41482
|
assertValidExternalSessionId(externalSessionId);
|
|
41375
|
-
return
|
|
41483
|
+
return path125.join(externalSlatesDir(cwd), `${externalSessionId}.json`);
|
|
41376
41484
|
}
|
|
41377
41485
|
function externalSlateLockPath(cwd, externalSessionId) {
|
|
41378
41486
|
return `${externalSlatePath(cwd, externalSessionId)}.lock`;
|
|
41379
41487
|
}
|
|
41380
41488
|
function externalSlateEvidenceDir(cwd, externalSessionId) {
|
|
41381
41489
|
assertValidExternalSessionId(externalSessionId);
|
|
41382
|
-
return
|
|
41490
|
+
return path125.join(externalSlatesDir(cwd), externalSessionId);
|
|
41383
41491
|
}
|
|
41384
41492
|
async function readExternalSlate(cwd, externalSessionId) {
|
|
41385
41493
|
try {
|
|
@@ -41485,12 +41593,12 @@ __export(exports_service10, {
|
|
|
41485
41593
|
runDoctor: () => runDoctor,
|
|
41486
41594
|
runValidate: () => runValidate
|
|
41487
41595
|
});
|
|
41488
|
-
import
|
|
41596
|
+
import path128 from "path";
|
|
41489
41597
|
import { readFile as readFile69 } from "fs/promises";
|
|
41490
41598
|
|
|
41491
41599
|
// src/standard/validate.ts
|
|
41492
41600
|
init_fs();
|
|
41493
|
-
import
|
|
41601
|
+
import path127 from "path";
|
|
41494
41602
|
import { readFile as readFile68 } from "fs/promises";
|
|
41495
41603
|
|
|
41496
41604
|
// src/standard/schemas.ts
|
|
@@ -41620,7 +41728,7 @@ var SCHEMA_REGISTRY2 = {
|
|
|
41620
41728
|
// src/standard/profiles.ts
|
|
41621
41729
|
init_fs();
|
|
41622
41730
|
init_entrypoint_targets();
|
|
41623
|
-
import
|
|
41731
|
+
import path126 from "path";
|
|
41624
41732
|
import { readFile as readFile67 } from "fs/promises";
|
|
41625
41733
|
var AGENT_MODULES = ["gdgraph", "gdctx", "gdskills", "gdwiki", "memory"];
|
|
41626
41734
|
var CI_MODULES = ["health", "testing"];
|
|
@@ -41645,7 +41753,7 @@ function enabledModuleKeys(manifest) {
|
|
|
41645
41753
|
}
|
|
41646
41754
|
async function rootEntrypointLinksIndex(cwd, manifest) {
|
|
41647
41755
|
for (const { path: name } of namedEntrypoints(manifest)) {
|
|
41648
|
-
const filePath =
|
|
41756
|
+
const filePath = path126.join(cwd, name);
|
|
41649
41757
|
if (!await pathExists(filePath)) {
|
|
41650
41758
|
continue;
|
|
41651
41759
|
}
|
|
@@ -41657,16 +41765,16 @@ async function rootEntrypointLinksIndex(cwd, manifest) {
|
|
|
41657
41765
|
return false;
|
|
41658
41766
|
}
|
|
41659
41767
|
async function minimalSatisfied(cwd) {
|
|
41660
|
-
const metaprojectRoot =
|
|
41768
|
+
const metaprojectRoot = path126.join(cwd, ".metaproject");
|
|
41661
41769
|
const requiredFiles = ["index.md", "README.md", "metaproject.json"];
|
|
41662
41770
|
const requiredDirs = ["modules", "rules", "skills", "data"];
|
|
41663
41771
|
for (const file of requiredFiles) {
|
|
41664
|
-
if (!await pathExists(
|
|
41772
|
+
if (!await pathExists(path126.join(metaprojectRoot, file))) {
|
|
41665
41773
|
return false;
|
|
41666
41774
|
}
|
|
41667
41775
|
}
|
|
41668
41776
|
for (const dir of requiredDirs) {
|
|
41669
|
-
if (!await pathExists(
|
|
41777
|
+
if (!await pathExists(path126.join(metaprojectRoot, dir))) {
|
|
41670
41778
|
return false;
|
|
41671
41779
|
}
|
|
41672
41780
|
}
|
|
@@ -41679,7 +41787,7 @@ async function ciSatisfied(cwd, manifest) {
|
|
|
41679
41787
|
return false;
|
|
41680
41788
|
}
|
|
41681
41789
|
for (const key of ciModules) {
|
|
41682
|
-
if (await pathExists(
|
|
41790
|
+
if (await pathExists(path126.join(cwd, ".metaproject", "data", key, "artifacts"))) {
|
|
41683
41791
|
return true;
|
|
41684
41792
|
}
|
|
41685
41793
|
}
|
|
@@ -41692,7 +41800,7 @@ async function evaluateProfiles(cwd, manifest) {
|
|
|
41692
41800
|
satisfied.push("minimal");
|
|
41693
41801
|
}
|
|
41694
41802
|
const hasAgentModule = AGENT_MODULES.some((key) => new Set(enabledModuleKeys(manifest)).has(key));
|
|
41695
|
-
const agent = minimal && hasAgentModule && await rootEntrypointLinksIndex(cwd, manifest) && await pathExists(
|
|
41803
|
+
const agent = minimal && hasAgentModule && await rootEntrypointLinksIndex(cwd, manifest) && await pathExists(path126.join(cwd, ".metaproject", "rules"));
|
|
41696
41804
|
if (agent) {
|
|
41697
41805
|
satisfied.push("agent");
|
|
41698
41806
|
}
|
|
@@ -41861,20 +41969,20 @@ var MANIFEST_TOP_LEVEL_SCHEMA = {
|
|
|
41861
41969
|
async function validateWorkspace2(cwd) {
|
|
41862
41970
|
const errors = [];
|
|
41863
41971
|
const warnings = [];
|
|
41864
|
-
const metaprojectRoot =
|
|
41972
|
+
const metaprojectRoot = path127.join(cwd, ".metaproject");
|
|
41865
41973
|
const requiredFiles = ["index.md", "README.md", "metaproject.json"];
|
|
41866
41974
|
for (const file of requiredFiles) {
|
|
41867
|
-
if (!await pathExists(
|
|
41975
|
+
if (!await pathExists(path127.join(metaprojectRoot, file))) {
|
|
41868
41976
|
errors.push(issue("missing-required-file", `Required file .metaproject/${file} is missing`, `Run \`keryx init\` to scaffold .metaproject/${file}.`));
|
|
41869
41977
|
}
|
|
41870
41978
|
}
|
|
41871
41979
|
const requiredDirs = ["modules", "rules", "skills", "data"];
|
|
41872
41980
|
for (const dir of requiredDirs) {
|
|
41873
|
-
if (!await pathExists(
|
|
41981
|
+
if (!await pathExists(path127.join(metaprojectRoot, dir))) {
|
|
41874
41982
|
errors.push(issue("missing-required-dir", `Required directory .metaproject/${dir}/ is missing`, `Run \`keryx init\` to create .metaproject/${dir}/.`));
|
|
41875
41983
|
}
|
|
41876
41984
|
}
|
|
41877
|
-
const manifestPath =
|
|
41985
|
+
const manifestPath = path127.join(metaprojectRoot, "metaproject.json");
|
|
41878
41986
|
if (!await pathExists(manifestPath)) {
|
|
41879
41987
|
return { ok: errors.length === 0, errors, warnings };
|
|
41880
41988
|
}
|
|
@@ -41906,7 +42014,7 @@ async function validateWorkspace2(cwd) {
|
|
|
41906
42014
|
if (typeof value !== "string") {
|
|
41907
42015
|
continue;
|
|
41908
42016
|
}
|
|
41909
|
-
if (!await pathExists(
|
|
42017
|
+
if (!await pathExists(path127.join(cwd, value))) {
|
|
41910
42018
|
errors.push(issue("missing-declared-path", `Declared path paths.${key} -> ${value} does not exist`, `Create ${value} or remove paths.${key} from metaproject.json.`));
|
|
41911
42019
|
}
|
|
41912
42020
|
}
|
|
@@ -41916,7 +42024,7 @@ async function validateWorkspace2(cwd) {
|
|
|
41916
42024
|
continue;
|
|
41917
42025
|
}
|
|
41918
42026
|
if (typeof entry.manifest === "string") {
|
|
41919
|
-
if (!await pathExists(
|
|
42027
|
+
if (!await pathExists(path127.join(cwd, entry.manifest))) {
|
|
41920
42028
|
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.`));
|
|
41921
42029
|
}
|
|
41922
42030
|
}
|
|
@@ -41925,14 +42033,14 @@ async function validateWorkspace2(cwd) {
|
|
|
41925
42033
|
if (typeof value !== "string") {
|
|
41926
42034
|
continue;
|
|
41927
42035
|
}
|
|
41928
|
-
if (!await pathExists(
|
|
42036
|
+
if (!await pathExists(path127.join(cwd, value))) {
|
|
41929
42037
|
const sink = field === "data" ? warnings : errors;
|
|
41930
42038
|
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.`));
|
|
41931
42039
|
}
|
|
41932
42040
|
}
|
|
41933
42041
|
}
|
|
41934
42042
|
for (const { path: name, scope } of namedEntrypoints(manifest)) {
|
|
41935
|
-
const filePath =
|
|
42043
|
+
const filePath = path127.join(cwd, name);
|
|
41936
42044
|
if (!await pathExists(filePath)) {
|
|
41937
42045
|
continue;
|
|
41938
42046
|
}
|
|
@@ -42932,7 +43040,7 @@ async function runDoctor(cwd) {
|
|
|
42932
43040
|
return validateWorkspace2(cwd);
|
|
42933
43041
|
}
|
|
42934
43042
|
async function readManifest(cwd) {
|
|
42935
|
-
const manifestPath =
|
|
43043
|
+
const manifestPath = path128.join(cwd, ".metaproject", "metaproject.json");
|
|
42936
43044
|
if (!await pathExists(manifestPath)) {
|
|
42937
43045
|
throw new Error("Metaproject is not initialized (missing .metaproject/metaproject.json). Run `keryx init` first.");
|
|
42938
43046
|
}
|