@mrciphersmith/keryx 0.3.113 → 0.3.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/cli.js +414 -143
- package/dist/core.js +3 -1
- package/package.json +1 -1
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +8 -8
- package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +13 -0
- package/src/gdskills/bundled/skills/review/review-orchestrator/templates/review-report.md +22 -0
package/dist/cli.js
CHANGED
|
@@ -23150,7 +23150,7 @@ var package_default;
|
|
|
23150
23150
|
var init_package = __esm(() => {
|
|
23151
23151
|
package_default = {
|
|
23152
23152
|
name: "@mrciphersmith/keryx",
|
|
23153
|
-
version: "0.3.
|
|
23153
|
+
version: "0.3.115",
|
|
23154
23154
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
23155
23155
|
private: false,
|
|
23156
23156
|
publishConfig: {
|
|
@@ -52419,6 +52419,7 @@ var init_codex_catalog_version = __esm(() => {
|
|
|
52419
52419
|
});
|
|
52420
52420
|
|
|
52421
52421
|
// src/commands/subscription-models.ts
|
|
52422
|
+
import { resolve as resolve2 } from "path";
|
|
52422
52423
|
function positiveInt(value) {
|
|
52423
52424
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : undefined;
|
|
52424
52425
|
}
|
|
@@ -52426,7 +52427,22 @@ async function fetchOpenAiCodexModels(fetchFn, opts = {}) {
|
|
|
52426
52427
|
const { contextWindows: _windows, ...result } = await fetchOpenAiCodexCatalog(fetchFn, opts);
|
|
52427
52428
|
return result;
|
|
52428
52429
|
}
|
|
52429
|
-
|
|
52430
|
+
function fetchOpenAiCodexCatalog(fetchFn, opts = {}) {
|
|
52431
|
+
let requests = catalogInFlight.get(fetchFn);
|
|
52432
|
+
if (requests === undefined) {
|
|
52433
|
+
requests = new Map;
|
|
52434
|
+
catalogInFlight.set(fetchFn, requests);
|
|
52435
|
+
}
|
|
52436
|
+
const key = JSON.stringify([resolve2(keryxConfigDir(opts.configDir)), opts.timeoutMs ?? 8000, opts.refreshCatalogVersion ?? false]);
|
|
52437
|
+
const existing = requests.get(key);
|
|
52438
|
+
if (existing !== undefined)
|
|
52439
|
+
return existing;
|
|
52440
|
+
const scope = requests;
|
|
52441
|
+
const request = requestOpenAiCodexCatalog(fetchFn, opts).finally(() => scope.delete(key));
|
|
52442
|
+
scope.set(key, request);
|
|
52443
|
+
return request;
|
|
52444
|
+
}
|
|
52445
|
+
async function requestOpenAiCodexCatalog(fetchFn, opts = {}) {
|
|
52430
52446
|
const controller = new AbortController;
|
|
52431
52447
|
const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? 8000);
|
|
52432
52448
|
let authenticated = false;
|
|
@@ -52476,8 +52492,9 @@ async function fetchOpenAiCodexCatalog(fetchFn, opts = {}) {
|
|
|
52476
52492
|
clearTimeout(timer);
|
|
52477
52493
|
}
|
|
52478
52494
|
}
|
|
52479
|
-
var OPENAI_CODEX_PICKER;
|
|
52495
|
+
var OPENAI_CODEX_PICKER, catalogInFlight;
|
|
52480
52496
|
var init_subscription_models = __esm(() => {
|
|
52497
|
+
init_config_dir();
|
|
52481
52498
|
init_openai_subscription();
|
|
52482
52499
|
init_codex_catalog_version();
|
|
52483
52500
|
OPENAI_CODEX_PICKER = {
|
|
@@ -52486,6 +52503,7 @@ var init_subscription_models = __esm(() => {
|
|
|
52486
52503
|
baseUrl: "https://chatgpt.com/backend-api/codex",
|
|
52487
52504
|
models: ["gpt-5.3-codex"]
|
|
52488
52505
|
};
|
|
52506
|
+
catalogInFlight = new WeakMap;
|
|
52489
52507
|
});
|
|
52490
52508
|
|
|
52491
52509
|
// src/commands/live-codex-models.ts
|
|
@@ -60559,7 +60577,7 @@ var init_output_spill = __esm(() => {
|
|
|
60559
60577
|
|
|
60560
60578
|
// src/harness/tool/builtin/interactive-tools.ts
|
|
60561
60579
|
import { readdir as readdir24 } from "fs/promises";
|
|
60562
|
-
import { basename, dirname, isAbsolute, join as join3, relative, resolve as
|
|
60580
|
+
import { basename, dirname, isAbsolute, join as join3, relative, resolve as resolve3, sep } from "path";
|
|
60563
60581
|
import { lstatSync as lstatSync5, realpathSync as realpathSync4 } from "fs";
|
|
60564
60582
|
async function readFromLine(file, startLine, cap) {
|
|
60565
60583
|
const reader = file.stream().getReader();
|
|
@@ -60617,7 +60635,7 @@ async function readFromLine(file, startLine, cap) {
|
|
|
60617
60635
|
}
|
|
60618
60636
|
function confineToRoot(root, candidate) {
|
|
60619
60637
|
const rootReal = realpathOr(root);
|
|
60620
|
-
const target =
|
|
60638
|
+
const target = resolve3(rootReal, candidate ?? ".");
|
|
60621
60639
|
const effective = realpathThroughAncestors(target);
|
|
60622
60640
|
if (effective === undefined) {
|
|
60623
60641
|
return null;
|
|
@@ -60635,7 +60653,7 @@ function realpathOr(candidate) {
|
|
|
60635
60653
|
try {
|
|
60636
60654
|
return realpathSync4(candidate);
|
|
60637
60655
|
} catch {
|
|
60638
|
-
return
|
|
60656
|
+
return resolve3(candidate);
|
|
60639
60657
|
}
|
|
60640
60658
|
}
|
|
60641
60659
|
function realpathThroughAncestors(absolute) {
|
|
@@ -60652,7 +60670,7 @@ function realpathThroughAncestors(absolute) {
|
|
|
60652
60670
|
} catch {}
|
|
60653
60671
|
const parent = dirname(current);
|
|
60654
60672
|
if (parent === current) {
|
|
60655
|
-
return
|
|
60673
|
+
return resolve3(absolute);
|
|
60656
60674
|
}
|
|
60657
60675
|
missing.push(basename(current));
|
|
60658
60676
|
current = parent;
|
|
@@ -68818,10 +68836,12 @@ function researchErrors(value, findings) {
|
|
|
68818
68836
|
ids.add(id);
|
|
68819
68837
|
if (!nonempty(o.source) || !nonempty(o.question))
|
|
68820
68838
|
errors.push(`${id}: source and question are required`);
|
|
68821
|
-
if (!["finding", "refuted", "out-of-scope"].includes(String(o.status)))
|
|
68839
|
+
if (!["finding", "refuted", "out-of-scope", "narrowed"].includes(String(o.status)))
|
|
68822
68840
|
errors.push(`${id}: unresolved research (${String(o.status)})`);
|
|
68823
68841
|
if (!nonempty(o.evidence) || !nonempty(o.reason))
|
|
68824
68842
|
errors.push(`${id}: closure needs evidence and reason`);
|
|
68843
|
+
if (o.status === "narrowed" && !nonempty(o.remains))
|
|
68844
|
+
errors.push(`${id}: narrowed needs a "what remains" text`);
|
|
68825
68845
|
if (o.status === "finding") {
|
|
68826
68846
|
const matches = findings.filter((f) => f && typeof f === "object" && (f.id === o.finding || f.global_id === o.finding));
|
|
68827
68847
|
if (!nonempty(o.finding) || matches.length !== 1)
|
|
@@ -75018,7 +75038,7 @@ var init_github = __esm(() => {
|
|
|
75018
75038
|
|
|
75019
75039
|
// src/harness/tool/metaproject-adapter.ts
|
|
75020
75040
|
import { lstat as lstat10, readdir as readdir32, readFile as readFile92, realpath as realpath17, stat as stat25 } from "fs/promises";
|
|
75021
|
-
import { isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve as
|
|
75041
|
+
import { isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve as resolve4 } from "path";
|
|
75022
75042
|
function isMissingExecutable(cause) {
|
|
75023
75043
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
75024
75044
|
return /Executable not found|\bENOENT\b|not found in \$?PATH/i.test(message);
|
|
@@ -75060,7 +75080,7 @@ function portableMemoryPath(candidate) {
|
|
|
75060
75080
|
}
|
|
75061
75081
|
function confineToWiki(cwd, candidate) {
|
|
75062
75082
|
const wikiRoot = join4(cwd, ".metaproject", "wiki");
|
|
75063
|
-
const target =
|
|
75083
|
+
const target = resolve4(wikiRoot, candidate);
|
|
75064
75084
|
const rel = relative2(wikiRoot, target);
|
|
75065
75085
|
if (rel === "") {
|
|
75066
75086
|
return null;
|
|
@@ -75117,7 +75137,7 @@ async function detectMemoryStoreUnreadable(cwd) {
|
|
|
75117
75137
|
}
|
|
75118
75138
|
function confineToSkills(cwd, candidate) {
|
|
75119
75139
|
const skillsRoot = join4(cwd, ".metaproject", "skills", "gdskills");
|
|
75120
|
-
const target =
|
|
75140
|
+
const target = resolve4(cwd, candidate);
|
|
75121
75141
|
const rel = relative2(skillsRoot, target);
|
|
75122
75142
|
if (rel === "") {
|
|
75123
75143
|
return null;
|
|
@@ -78919,6 +78939,127 @@ function arbiterSession() {
|
|
|
78919
78939
|
}
|
|
78920
78940
|
var session;
|
|
78921
78941
|
|
|
78942
|
+
// src/review/rebuttal-citation.ts
|
|
78943
|
+
function citedPaths(text) {
|
|
78944
|
+
const found = new Set;
|
|
78945
|
+
for (const match of text.replace(URL2, " ").matchAll(CITED)) {
|
|
78946
|
+
const cited = match[1];
|
|
78947
|
+
if (cited.includes("/") || ROOT_DOCUMENT.test(cited))
|
|
78948
|
+
found.add(cited);
|
|
78949
|
+
}
|
|
78950
|
+
return [...found];
|
|
78951
|
+
}
|
|
78952
|
+
async function flagMissingCitations(findings, exists) {
|
|
78953
|
+
let added = 0;
|
|
78954
|
+
for (const finding of findings) {
|
|
78955
|
+
const disposition = finding.disposition;
|
|
78956
|
+
if (disposition === undefined || typeof disposition.evidence !== "string")
|
|
78957
|
+
continue;
|
|
78958
|
+
const missing = [];
|
|
78959
|
+
for (const cited of citedPaths(disposition.evidence)) {
|
|
78960
|
+
if (disposition.evidence.includes(marker(cited)))
|
|
78961
|
+
continue;
|
|
78962
|
+
if (!await exists(cited))
|
|
78963
|
+
missing.push(cited);
|
|
78964
|
+
}
|
|
78965
|
+
if (missing.length === 0)
|
|
78966
|
+
continue;
|
|
78967
|
+
disposition.evidence = `${disposition.evidence}
|
|
78968
|
+
${missing.map(marker).join(`
|
|
78969
|
+
`)}`;
|
|
78970
|
+
added += missing.length;
|
|
78971
|
+
}
|
|
78972
|
+
return added;
|
|
78973
|
+
}
|
|
78974
|
+
var URL2, CITED, ROOT_DOCUMENT, marker = (cited) => `citation not found: ${cited}`;
|
|
78975
|
+
var init_rebuttal_citation = __esm(() => {
|
|
78976
|
+
URL2 = /\bhttps?:\/\/\S+/gi;
|
|
78977
|
+
CITED = /(?<![\w./-])((?:\.\.?\/)*(?:[\w.-]+\/)*[\w.-]+\.(?:mdc|mdx|md|txt|json|ya?ml|toml))(?![\w-])/g;
|
|
78978
|
+
ROOT_DOCUMENT = /^[A-Z][A-Z0-9_-]*\.(?:md|mdx|txt)$/;
|
|
78979
|
+
});
|
|
78980
|
+
|
|
78981
|
+
// src/review/complete-head-gate.ts
|
|
78982
|
+
async function completeHeadGate(input) {
|
|
78983
|
+
const { target } = input.manifest;
|
|
78984
|
+
if (target.kind !== "pr")
|
|
78985
|
+
return { warnings: [] };
|
|
78986
|
+
let pr;
|
|
78987
|
+
try {
|
|
78988
|
+
pr = await input.lookup(target.ref);
|
|
78989
|
+
} catch (error) {
|
|
78990
|
+
return { warnings: [`could not read the PR state for ${target.ref} (${error instanceof Error ? error.message : String(error)}); the head and merge check was skipped`] };
|
|
78991
|
+
}
|
|
78992
|
+
if (pr === null || !pr.exists)
|
|
78993
|
+
return { warnings: [`could not read the PR state for ${target.ref}; the head and merge check was skipped`] };
|
|
78994
|
+
const recorded = target.head ?? null;
|
|
78995
|
+
const reviewed = recorded !== null && USABLE_SHA.test(recorded) ? recorded : null;
|
|
78996
|
+
const unusable = recorded !== null && reviewed === null ? [`the reviewed head recorded for ${target.ref} ("${recorded}") is not a commit SHA; the moved-head check was skipped`] : [];
|
|
78997
|
+
const merged = typeof pr.state === "string" && pr.state.toUpperCase() === "MERGED";
|
|
78998
|
+
const prHead = typeof pr.headSha === "string" && pr.headSha !== "" ? pr.headSha : null;
|
|
78999
|
+
const moved = reviewed !== null && prHead !== null && !sameCommit(reviewed, prHead);
|
|
79000
|
+
if (!merged && !moved)
|
|
79001
|
+
return { warnings: unusable };
|
|
79002
|
+
const what = [merged ? "the PR is merged" : undefined, moved ? `the PR head moved (reviewed ${reviewed.slice(0, 7)}, now ${prHead.slice(0, 7)})` : undefined].filter(Boolean).join(" and ");
|
|
79003
|
+
const first = input.report.split(/\r?\n/).find((line) => line.trim() !== "" && !/^\s*<!--.*-->\s*$/.test(line)) ?? "";
|
|
79004
|
+
const names = reviewed === null ? /\b[0-9a-f]{7,40}\b/i.test(first) : first.toLowerCase().includes(reviewed.slice(0, 7).toLowerCase());
|
|
79005
|
+
if (names && SAYS_SO.test(first))
|
|
79006
|
+
return { warnings: unusable };
|
|
79007
|
+
throw new Error(`Cannot complete managed review; ${what}. The report's first line must name the reviewed SHA${reviewed === null ? "" : ` (${reviewed.slice(0, 7)})`} and say the PR moved, for example: "Reviewed ${(reviewed ?? "<sha>").slice(0, 7)} \u2014 the PR has since ${merged ? "merged" : "moved on"}."`);
|
|
79008
|
+
}
|
|
79009
|
+
var MOVE_WORD = "(?:merged|moved|advanced|superseded|closed|force-pushed)", PR_WORD = "(?:pr|pull request|head)", SAYS_SO, USABLE_SHA, sameCommit = (a, b) => {
|
|
79010
|
+
const [x, y] = [a.toLowerCase(), b.toLowerCase()];
|
|
79011
|
+
return x.startsWith(y) || y.startsWith(x);
|
|
79012
|
+
};
|
|
79013
|
+
var init_complete_head_gate = __esm(() => {
|
|
79014
|
+
SAYS_SO = new RegExp(`\\b${PR_WORD}\\b.{0,40}\\b${MOVE_WORD}\\b|\\b${MOVE_WORD}\\b.{0,40}\\b${PR_WORD}\\b`, "i");
|
|
79015
|
+
USABLE_SHA = /^[0-9a-f]{7,40}$/i;
|
|
79016
|
+
});
|
|
79017
|
+
|
|
79018
|
+
// src/review/evidence-level.ts
|
|
79019
|
+
function itemsOf(text) {
|
|
79020
|
+
return text.split(/[,;]/).map((item) => item.trim()).filter((item) => item.length > 0 && !PLACEHOLDER.test(item));
|
|
79021
|
+
}
|
|
79022
|
+
function withoutFences(report) {
|
|
79023
|
+
let fence = null;
|
|
79024
|
+
const kept = [];
|
|
79025
|
+
for (const line of report.split(/\r?\n/)) {
|
|
79026
|
+
const marker = /^\s*(```+|~~~+)/.exec(line)?.[1];
|
|
79027
|
+
if (marker !== undefined) {
|
|
79028
|
+
if (fence === null)
|
|
79029
|
+
fence = marker[0];
|
|
79030
|
+
else if (marker[0] === fence)
|
|
79031
|
+
fence = null;
|
|
79032
|
+
continue;
|
|
79033
|
+
}
|
|
79034
|
+
if (fence === null)
|
|
79035
|
+
kept.push(line);
|
|
79036
|
+
}
|
|
79037
|
+
return kept;
|
|
79038
|
+
}
|
|
79039
|
+
function parseEvidenceLevel(report) {
|
|
79040
|
+
const line = withoutFences(report).map((l) => LINE.exec(l)).find((m) => m !== null);
|
|
79041
|
+
if (!line)
|
|
79042
|
+
return { ok: false, reason: "the report has no `Evidence level:` line" };
|
|
79043
|
+
const value = line[1].replace(/(?:\*\*|__)\s*$/, "").trim();
|
|
79044
|
+
const staticOnly = /^static[ -]only\b/i.exec(value);
|
|
79045
|
+
if (staticOnly) {
|
|
79046
|
+
const items = itemsOf(value.slice(staticOnly[0].length).replace(SEPARATORS, "").replace(/^(?:did not run|not run|did not)\s*:?\s*/i, ""));
|
|
79047
|
+
return items.length > 0 ? { ok: true, level: "static-only", items } : { ok: false, reason: "`static only` must list what did not run" };
|
|
79048
|
+
}
|
|
79049
|
+
const ran = /^ran\b/i.exec(value);
|
|
79050
|
+
if (ran) {
|
|
79051
|
+
const items = itemsOf(value.slice(ran[0].length).replace(SEPARATORS, ""));
|
|
79052
|
+
return items.length > 0 ? { ok: true, level: "ran", items } : { ok: false, reason: "`ran` must list what ran" };
|
|
79053
|
+
}
|
|
79054
|
+
return { ok: false, reason: "the evidence level must start with `static only` or `ran`" };
|
|
79055
|
+
}
|
|
79056
|
+
var REPORT_FIELD_EVIDENCE_LEVEL = "evidence-level", LINE, SEPARATORS, PLACEHOLDER;
|
|
79057
|
+
var init_evidence_level = __esm(() => {
|
|
79058
|
+
LINE = /^\s*(?:[-*+]\s+)?(?:\*\*|__)?evidence level\s*:?\s*(?:\*\*|__)?\s*:?\s*(.*)$/i;
|
|
79059
|
+
SEPARATORS = /^[\s:\u2014\u2013-]+/;
|
|
79060
|
+
PLACEHOLDER = /^(?:none|nothing|n\/a|na|nil|-|\u2014|\u2013)\.?$/i;
|
|
79061
|
+
});
|
|
79062
|
+
|
|
78922
79063
|
// src/review/verification.ts
|
|
78923
79064
|
function verificationClaims(source) {
|
|
78924
79065
|
if (source === undefined) {
|
|
@@ -79868,7 +80009,7 @@ var init_repair = __esm(() => {
|
|
|
79868
80009
|
});
|
|
79869
80010
|
|
|
79870
80011
|
// src/review/managed.ts
|
|
79871
|
-
import { mkdir as mkdir52, readFile as readFile98, readdir as readdir33, realpath as realpath18, rm as rm13, stat as stat27 } from "fs/promises";
|
|
80012
|
+
import { lstat as lstat12, mkdir as mkdir52, readFile as readFile98, readdir as readdir33, realpath as realpath18, rm as rm13, stat as stat27 } from "fs/promises";
|
|
79872
80013
|
import path188 from "path";
|
|
79873
80014
|
function reviewsRoot(cwd) {
|
|
79874
80015
|
return path188.join(cwd, ".metaproject", "reviews");
|
|
@@ -79937,6 +80078,7 @@ async function createManagedReviewPackage(input) {
|
|
|
79937
80078
|
const repairs = repairMechanicalOmissions(reported);
|
|
79938
80079
|
const head = await resolveTargetHead(input);
|
|
79939
80080
|
await anchorFindings(reported, input, head);
|
|
80081
|
+
refuseUnresolvedLocators(reported, input, head);
|
|
79940
80082
|
assignGlobalIds(reported, reviewId);
|
|
79941
80083
|
const merged = mergeVerifications(reported, input.verifications ?? [], {
|
|
79942
80084
|
mode: input.verificationMode ?? DEFAULT_VERIFICATION_MODE
|
|
@@ -79955,6 +80097,7 @@ async function createManagedReviewPackage(input) {
|
|
|
79955
80097
|
...roundDismissed
|
|
79956
80098
|
];
|
|
79957
80099
|
assignGlobalIds(findings, reviewId);
|
|
80100
|
+
await flagMissingCitations(findings, (cited) => citationExists(input.cwd, head, cited));
|
|
79958
80101
|
const carried = input.scope === undefined ? await readPreFilterScopeBlock(packageDir) : undefined;
|
|
79959
80102
|
const concurrency = concurrencyPlan(input, coverage);
|
|
79960
80103
|
const caps = {
|
|
@@ -80150,6 +80293,18 @@ async function completeManagedReview(cwd, ref, options = {}) {
|
|
|
80150
80293
|
if (missing.length > 0) {
|
|
80151
80294
|
throw new Error(`Cannot complete managed review; missing artifacts: ${missing.join(", ")}`);
|
|
80152
80295
|
}
|
|
80296
|
+
const warnings = [];
|
|
80297
|
+
const reportText = await readFile98(path188.join(packageDir, "report.md"), "utf8");
|
|
80298
|
+
if (options.prLookup !== undefined)
|
|
80299
|
+
warnings.push(...(await completeHeadGate({ manifest, report: reportText, lookup: options.prLookup })).warnings);
|
|
80300
|
+
const evidence = parseEvidenceLevel(reportText);
|
|
80301
|
+
if (!evidence.ok) {
|
|
80302
|
+
const problem = `the report's evidence level is missing or invalid: ${evidence.reason}`;
|
|
80303
|
+
if (manifest.report_fields?.includes(REPORT_FIELD_EVIDENCE_LEVEL)) {
|
|
80304
|
+
throw new Error(`Cannot complete managed review; ${problem}. Add a line \`Evidence level: static only \u2014 did not run: <what>\` or \`Evidence level: ran \u2014 <what>\` to report.md`);
|
|
80305
|
+
}
|
|
80306
|
+
warnings.push(`${problem} (this package predates the field, so it is a warning)`);
|
|
80307
|
+
}
|
|
80153
80308
|
const researchFindings = JSON.parse(await readFile98(path188.join(packageDir, "findings.json"), "utf8"));
|
|
80154
80309
|
const researchPath = path188.join(packageDir, "research.json");
|
|
80155
80310
|
const researchBefore = options.waiveCoverage === undefined ? undefined : await readFile98(researchPath, "utf8").catch(() => {
|
|
@@ -80193,7 +80348,7 @@ async function completeManagedReview(cwd, ref, options = {}) {
|
|
|
80193
80348
|
packagePath: path188.relative(cwd, packageDir),
|
|
80194
80349
|
...options.now === undefined ? {} : { now: options.now }
|
|
80195
80350
|
});
|
|
80196
|
-
return { manifest: updated, reviewNotes, dispositions: tallyDispositions(recorded), ...coverageWaiver === undefined ? {} : { coverageWaiver } };
|
|
80351
|
+
return { manifest: updated, reviewNotes, dispositions: tallyDispositions(recorded), warnings, ...coverageWaiver === undefined ? {} : { coverageWaiver } };
|
|
80197
80352
|
}
|
|
80198
80353
|
async function validateManagedReviewManifest(cwd, manifest) {
|
|
80199
80354
|
const errors = [];
|
|
@@ -80283,6 +80438,7 @@ function buildManifest(args) {
|
|
|
80283
80438
|
coverage: args.coverage,
|
|
80284
80439
|
filter_stats: args.filterStats,
|
|
80285
80440
|
...args.repairs.length === 0 ? {} : { repairs: args.repairs },
|
|
80441
|
+
report_fields: [REPORT_FIELD_EVIDENCE_LEVEL],
|
|
80286
80442
|
...args.input.cost === undefined ? {} : { cost: args.input.cost },
|
|
80287
80443
|
...crossFamily === undefined ? {} : { cross_family_review: crossFamily },
|
|
80288
80444
|
...args.input.automatic === true ? { automatic: true } : {},
|
|
@@ -80358,7 +80514,7 @@ function triage(findings, args) {
|
|
|
80358
80514
|
}
|
|
80359
80515
|
async function anchorFindings(findings, input, head) {
|
|
80360
80516
|
const read = input.readTreeFile ?? (head === null ? readFromWorkingTree(input) : async (relative) => {
|
|
80361
|
-
const contained =
|
|
80517
|
+
const contained = lexicalRelativePath(relative);
|
|
80362
80518
|
return contained === null ? null : readFileAtCommit(input.cwd, head, contained);
|
|
80363
80519
|
});
|
|
80364
80520
|
for (const finding of findings) {
|
|
@@ -80384,17 +80540,42 @@ async function anchorFindings(findings, input, head) {
|
|
|
80384
80540
|
};
|
|
80385
80541
|
}
|
|
80386
80542
|
}
|
|
80387
|
-
|
|
80388
|
-
|
|
80389
|
-
|
|
80390
|
-
|
|
80391
|
-
|
|
80543
|
+
function refuseUnresolvedLocators(findings, input, head) {
|
|
80544
|
+
if (head === null || input.readTreeFile !== undefined) {
|
|
80545
|
+
return;
|
|
80546
|
+
}
|
|
80547
|
+
const unresolved = findings.filter((finding) => finding.source !== "external" && finding.disposition === undefined && finding.locator?.state === "unlocatable");
|
|
80548
|
+
if (unresolved.length === 0) {
|
|
80549
|
+
return;
|
|
80550
|
+
}
|
|
80551
|
+
const lines = unresolved.map((finding) => {
|
|
80552
|
+
const locator = finding.locator?.state === "unlocatable" ? finding.locator : undefined;
|
|
80553
|
+
const line = locator?.reported_line ?? null;
|
|
80554
|
+
return ` - ${finding.id ?? finding.summary} (${finding.file}${line === null ? "" : `:${line}`}): ${locator?.reason ?? ""}`;
|
|
80555
|
+
});
|
|
80556
|
+
throw new Error(`Cannot ingest review; ${unresolved.length} finding(s) cite a quote that does not resolve at the reviewed SHA ${head.slice(0, 12)}:
|
|
80557
|
+
${lines.join(`
|
|
80558
|
+
`)}
|
|
80559
|
+
Causes: the quote is not in the file at that commit, appears in it more than once, or the file or the commit is not in this checkout (check \`git cat-file -e ${head.slice(0, 12)}\`). Re-quote one distinct line from \`git show ${head.slice(0, 7)}:<path>\` or dismiss the finding with evidence.`);
|
|
80560
|
+
}
|
|
80561
|
+
async function citationExists(cwd, head, cited) {
|
|
80562
|
+
const relative = lexicalRelativePath(cited);
|
|
80563
|
+
if (relative === null) {
|
|
80564
|
+
return false;
|
|
80565
|
+
}
|
|
80566
|
+
if (head !== null && await readFileAtCommit(cwd, head, relative) !== null) {
|
|
80567
|
+
return true;
|
|
80568
|
+
}
|
|
80569
|
+
return lstat12(path188.resolve(cwd, relative)).then(() => true, () => false);
|
|
80570
|
+
}
|
|
80571
|
+
function lexicalRelativePath(relative) {
|
|
80572
|
+
const normalised = path188.posix.normalize(relative.replace(/\\/g, "/"));
|
|
80573
|
+
if (normalised === "." || normalised === ".." || normalised.startsWith("../") || path188.posix.isAbsolute(normalised)) {
|
|
80392
80574
|
return null;
|
|
80393
80575
|
}
|
|
80394
|
-
return
|
|
80576
|
+
return normalised;
|
|
80395
80577
|
}
|
|
80396
|
-
async function readFileAtCommit(cwd, commit,
|
|
80397
|
-
const relative = path188.relative(await realpath18(cwd).catch(() => path188.resolve(cwd)), absolute);
|
|
80578
|
+
async function readFileAtCommit(cwd, commit, relative) {
|
|
80398
80579
|
try {
|
|
80399
80580
|
const proc = Bun.spawn(["git", "show", `${commit}:${relative}`], {
|
|
80400
80581
|
cwd,
|
|
@@ -81091,6 +81272,9 @@ async function loadDocpackSchema(cwd) {
|
|
|
81091
81272
|
var REQUIRED_ARTIFACTS, BLAST_RADIUS_ARTIFACT = "blast-radius.json", EMBEDDED_FINDINGS_FENCE, SEVERITY_PREFIX, NOT_RECORDED = (field) => `not recorded: derived from a markdown review report, which carried no ${field} field`, LABEL_LINE, HEADING_MARKER, FINDING_IDENTIFIER, TITLE_SEPARATOR, REFERENCE_PUNCTUATION, PRE_FILTER_SCOPE_BLOCK, BLAST_RADIUS_RECORD_SOURCE, MAX_SAME_DAY_ROUNDS = 99;
|
|
81092
81273
|
var init_managed = __esm(() => {
|
|
81093
81274
|
init_coverage_complete();
|
|
81275
|
+
init_rebuttal_citation();
|
|
81276
|
+
init_complete_head_gate();
|
|
81277
|
+
init_evidence_level();
|
|
81094
81278
|
init_research();
|
|
81095
81279
|
init_validator();
|
|
81096
81280
|
init_contracts();
|
|
@@ -88980,7 +89164,7 @@ function sha256Hex5(bytes) {
|
|
|
88980
89164
|
var init_checksum = () => {};
|
|
88981
89165
|
|
|
88982
89166
|
// src/bundle/external.ts
|
|
88983
|
-
import { mkdir as mkdir54, lstat as
|
|
89167
|
+
import { mkdir as mkdir54, lstat as lstat13, readFile as readFile108, readdir as readdir40, rename as rename11, stat as stat29, unlink, writeFile as writeFile33 } from "fs/promises";
|
|
88984
89168
|
import { createHmac as createHmac4, randomBytes as randomBytes10, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
88985
89169
|
import path215 from "path";
|
|
88986
89170
|
function emptyRegistry() {
|
|
@@ -89024,7 +89208,7 @@ async function loadIntegrityKey(env, homeDir) {
|
|
|
89024
89208
|
const keyPath = integrityKeyPathFor(env, homeDir);
|
|
89025
89209
|
let st;
|
|
89026
89210
|
try {
|
|
89027
|
-
st = await
|
|
89211
|
+
st = await lstat13(keyPath);
|
|
89028
89212
|
} catch (err) {
|
|
89029
89213
|
if (err?.code === "ENOENT")
|
|
89030
89214
|
return { ok: false, reason: "missing" };
|
|
@@ -89464,7 +89648,7 @@ var init_external = __esm(() => {
|
|
|
89464
89648
|
|
|
89465
89649
|
// src/gdskills/governance/scout.ts
|
|
89466
89650
|
import { existsSync as existsSync32, readFileSync as readFileSync19, statSync as statSync8 } from "fs";
|
|
89467
|
-
import { lstat as
|
|
89651
|
+
import { lstat as lstat14, mkdtemp as mkdtemp2, readdir as readdir41, readFile as readFile109 } from "fs/promises";
|
|
89468
89652
|
import { tmpdir as tmpdir3 } from "os";
|
|
89469
89653
|
import path216 from "path";
|
|
89470
89654
|
function stemLite(token) {
|
|
@@ -89690,7 +89874,7 @@ async function scoutImports(query, opts = {}) {
|
|
|
89690
89874
|
async function collectSkillDirectorySnapshot(dir, limits = DEFAULT_SNAPSHOT_VETTING_LIMITS) {
|
|
89691
89875
|
let rootStat;
|
|
89692
89876
|
try {
|
|
89693
|
-
rootStat = await
|
|
89877
|
+
rootStat = await lstat14(dir);
|
|
89694
89878
|
} catch (error) {
|
|
89695
89879
|
return { ok: false, reason: "unreadable-dir", message: `cannot read ${dir}: ${error instanceof Error ? error.message : String(error)}` };
|
|
89696
89880
|
}
|
|
@@ -89722,7 +89906,7 @@ async function collectSkillDirectorySnapshot(dir, limits = DEFAULT_SNAPSHOT_VETT
|
|
|
89722
89906
|
const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
|
|
89723
89907
|
let entryStat;
|
|
89724
89908
|
try {
|
|
89725
|
-
entryStat = await
|
|
89909
|
+
entryStat = await lstat14(abs);
|
|
89726
89910
|
} catch (error) {
|
|
89727
89911
|
return { ok: false, reason: "unreadable-file", message: `cannot stat ${rel}: ${error instanceof Error ? error.message : String(error)}` };
|
|
89728
89912
|
}
|
|
@@ -94092,7 +94276,7 @@ var init_slate_lifecycle = __esm(() => {
|
|
|
94092
94276
|
|
|
94093
94277
|
// src/harness/tool/builtin/slate-memory-tools.ts
|
|
94094
94278
|
import { createReadStream } from "fs";
|
|
94095
|
-
import { lstat as
|
|
94279
|
+
import { lstat as lstat15, realpath as realpath19 } from "fs/promises";
|
|
94096
94280
|
import path223 from "path";
|
|
94097
94281
|
import { createInterface } from "readline";
|
|
94098
94282
|
function failure3(message) {
|
|
@@ -94110,7 +94294,7 @@ async function confinedFile(sessionDir, candidate, within) {
|
|
|
94110
94294
|
try {
|
|
94111
94295
|
const root = await realpath19(within === undefined ? sessionDir : path223.join(sessionDir, within));
|
|
94112
94296
|
const sessionReal = await realpath19(sessionDir);
|
|
94113
|
-
const info = await
|
|
94297
|
+
const info = await lstat15(path223.resolve(candidate));
|
|
94114
94298
|
if (info.isSymbolicLink() || !info.isFile())
|
|
94115
94299
|
return null;
|
|
94116
94300
|
const real = await realpath19(path223.resolve(candidate));
|
|
@@ -95022,6 +95206,9 @@ ${block}
|
|
|
95022
95206
|
function asksForAutomaticReview(deps, options, userLine) {
|
|
95023
95207
|
return options.automaticReview ?? ((options.origin ?? "operator") === "operator" && deps.subagentBudget === undefined && isAutomaticReviewRequest(userLine));
|
|
95024
95208
|
}
|
|
95209
|
+
function agentContextWindow(deps) {
|
|
95210
|
+
return deps.getContextWindow !== undefined ? deps.getContextWindow() : deps.contextWindow;
|
|
95211
|
+
}
|
|
95025
95212
|
async function runAgentTurn(io, deps, history, userLine, options = {}) {
|
|
95026
95213
|
const controlNonce = deps.controlNonce ?? generateControlNonce();
|
|
95027
95214
|
recordBunfigBaseline();
|
|
@@ -95254,7 +95441,7 @@ async function pruneHistory(io, deps, history, sessionDir, minSavingTokens, shou
|
|
|
95254
95441
|
return { pruned: 0, collapsed: 0, reasoningStripped: 0, savedTokens: 0 };
|
|
95255
95442
|
}
|
|
95256
95443
|
const lengthBefore = history.length;
|
|
95257
|
-
const thresholds = pruneThresholdsForWindow(deps
|
|
95444
|
+
const thresholds = pruneThresholdsForWindow(agentContextWindow(deps));
|
|
95258
95445
|
const result = await pruneToolOutputs(history, {
|
|
95259
95446
|
sessionDir,
|
|
95260
95447
|
protectTokens: thresholds.protectTokens,
|
|
@@ -95292,7 +95479,7 @@ async function pruneOrRewriteHistory(input) {
|
|
|
95292
95479
|
round: input.round,
|
|
95293
95480
|
maxRounds: input.maxRounds
|
|
95294
95481
|
});
|
|
95295
|
-
const forced = needsCompaction(estimateRequestTokens(history, input.systemInstruction, input.toolDefs), deps
|
|
95482
|
+
const forced = needsCompaction(estimateRequestTokens(history, input.systemInstruction, input.toolDefs), agentContextWindow(deps));
|
|
95296
95483
|
const logDecision = (d) => {
|
|
95297
95484
|
const key = `${d.kind}:${d.reason}`;
|
|
95298
95485
|
if (d.apply) {
|
|
@@ -95337,7 +95524,7 @@ ${describeRewriteDecision(d)}
|
|
|
95337
95524
|
sessionDir: wmDir,
|
|
95338
95525
|
slate,
|
|
95339
95526
|
frame: { nonce: input.controlNonce, scrub, ts: input.now() },
|
|
95340
|
-
...deps
|
|
95527
|
+
...agentContextWindow(deps) !== undefined ? { contextWindow: agentContextWindow(deps) } : {},
|
|
95341
95528
|
providerId: deps.providerId,
|
|
95342
95529
|
remainingRounds,
|
|
95343
95530
|
atPlanBoundary: boundary,
|
|
@@ -95411,13 +95598,13 @@ async function pruneThenCompact(io, deps, history, systemInstruction, toolDefs,
|
|
|
95411
95598
|
usageAnchors.delete(history);
|
|
95412
95599
|
}
|
|
95413
95600
|
const estimate = estimateRequestTokens(history, systemInstruction, toolDefs);
|
|
95414
|
-
if (!needsCompaction(estimate, deps
|
|
95601
|
+
if (!needsCompaction(estimate, agentContextWindow(deps))) {
|
|
95415
95602
|
return;
|
|
95416
95603
|
}
|
|
95417
95604
|
await firePreCompactBestEffort(deps, estimate);
|
|
95418
95605
|
const compacted = compactWithFallback(history, {
|
|
95419
95606
|
keepLastUserTurns: 3,
|
|
95420
|
-
fits: (ctx) => !needsCompaction(estimateRequestTokens(ctx, systemInstruction, toolDefs), deps
|
|
95607
|
+
fits: (ctx) => !needsCompaction(estimateRequestTokens(ctx, systemInstruction, toolDefs), agentContextWindow(deps))
|
|
95421
95608
|
});
|
|
95422
95609
|
if (!compacted.noop) {
|
|
95423
95610
|
history.splice(0, history.length, ...compacted.context);
|
|
@@ -95803,11 +95990,11 @@ ${planSnapshot}`;
|
|
|
95803
95990
|
`);
|
|
95804
95991
|
}
|
|
95805
95992
|
const preRequestEstimate = pruneResult.pruned + pruneResult.reasoningStripped > 0 ? estimateRequestTokens(history, roundSystemInstruction, toolDefs) : estimateWithUsageAnchor(history, roundSystemInstruction, toolDefs, liveAnchor);
|
|
95806
|
-
if (needsCompaction(preRequestEstimate, deps
|
|
95993
|
+
if (needsCompaction(preRequestEstimate, agentContextWindow(deps))) {
|
|
95807
95994
|
await firePreCompactBestEffort(deps, preRequestEstimate);
|
|
95808
95995
|
const compacted = compactWithFallback(history, {
|
|
95809
95996
|
keepLastUserTurns: 3,
|
|
95810
|
-
fits: (ctx) => !needsCompaction(estimateRequestTokens(ctx, roundSystemInstruction, toolDefs), deps
|
|
95997
|
+
fits: (ctx) => !needsCompaction(estimateRequestTokens(ctx, roundSystemInstruction, toolDefs), agentContextWindow(deps))
|
|
95811
95998
|
});
|
|
95812
95999
|
if (!compacted.noop) {
|
|
95813
96000
|
history.splice(0, history.length, ...compacted.context);
|
|
@@ -96121,7 +96308,7 @@ ${planSnapshot}`;
|
|
|
96121
96308
|
usageAnchors.delete(history);
|
|
96122
96309
|
forgetHiddenHashes();
|
|
96123
96310
|
}
|
|
96124
|
-
const overflowTarget = overflowTargetTokens(parseOverflowLimits(pendingOverflowError.message), deps
|
|
96311
|
+
const overflowTarget = overflowTargetTokens(parseOverflowLimits(pendingOverflowError.message), agentContextWindow(deps), overflowEstimate);
|
|
96125
96312
|
const compacted = compactWithFallback(history, {
|
|
96126
96313
|
keepLastUserTurns: 3,
|
|
96127
96314
|
fits: (ctx) => overflowTarget !== undefined && estimateRequestTokens(ctx, roundSystemInstruction, toolDefs) <= overflowTarget
|
|
@@ -99580,7 +99767,7 @@ async function resolveGitHooksRoot(projectRoot) {
|
|
|
99580
99767
|
var init_git_hooks = () => {};
|
|
99581
99768
|
|
|
99582
99769
|
// src/lib/managed-git-hook.ts
|
|
99583
|
-
import { chmod as chmod9, lstat as
|
|
99770
|
+
import { chmod as chmod9, lstat as lstat16, mkdir as mkdir57, readFile as readFile112, realpath as realpath20, writeFile as writeFile35 } from "fs/promises";
|
|
99584
99771
|
import path230 from "path";
|
|
99585
99772
|
function escapeRegExp6(value) {
|
|
99586
99773
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -99611,13 +99798,13 @@ async function resolveContainedHookPath(projectRoot, hookName) {
|
|
|
99611
99798
|
const commonDirReal = await realpath20(path230.dirname(hooksRoot)).catch(() => path230.dirname(hooksRoot));
|
|
99612
99799
|
const projectRootReal = await realpath20(projectRoot).catch(() => projectRoot);
|
|
99613
99800
|
const acceptedContainers = [commonDirReal, projectRootReal];
|
|
99614
|
-
const hooksRootStat = await
|
|
99801
|
+
const hooksRootStat = await lstat16(hooksRoot).catch(() => null);
|
|
99615
99802
|
const hooksRootReal = await realpath20(hooksRoot).catch(() => hooksRoot);
|
|
99616
99803
|
if (hooksRootStat?.isSymbolicLink()) {
|
|
99617
99804
|
await assertResolvesInside(hooksRoot, acceptedContainers, "the git hooks directory");
|
|
99618
99805
|
}
|
|
99619
99806
|
const hookPath = path230.join(hooksRoot, hookName);
|
|
99620
|
-
const hookStat = await
|
|
99807
|
+
const hookStat = await lstat16(hookPath).catch(() => null);
|
|
99621
99808
|
if (hookStat?.isSymbolicLink()) {
|
|
99622
99809
|
await assertResolvesInside(hookPath, [hooksRootReal, projectRootReal], "the git hook file");
|
|
99623
99810
|
}
|
|
@@ -105195,7 +105382,7 @@ var init_metaproject_operations = __esm(() => {
|
|
|
105195
105382
|
|
|
105196
105383
|
// src/harness/tool/builtin/metaproject-tools.ts
|
|
105197
105384
|
import { existsSync as existsSync43 } from "fs";
|
|
105198
|
-
import { resolve as
|
|
105385
|
+
import { resolve as resolve5 } from "path";
|
|
105199
105386
|
function normalizeSearchResult(result) {
|
|
105200
105387
|
if (result.isError && RG_UNAVAILABLE_SIGNATURE.test(result.output)) {
|
|
105201
105388
|
return { output: SEARCH_CODE_RG_UNAVAILABLE_MESSAGE, isError: true };
|
|
@@ -105203,7 +105390,7 @@ function normalizeSearchResult(result) {
|
|
|
105203
105390
|
return result;
|
|
105204
105391
|
}
|
|
105205
105392
|
function keryxSelfCommand(main = Bun.main, execPath = process.execPath, exists = existsSync43, entries = KERYX_ENTRIES) {
|
|
105206
|
-
if (entries.includes(
|
|
105393
|
+
if (entries.includes(resolve5(main)) && exists(main)) {
|
|
105207
105394
|
return [execPath, ...SAFE_BUN_SPAWN_ARGS, main];
|
|
105208
105395
|
}
|
|
105209
105396
|
if (isCompiledBinaryEntry(main)) {
|
|
@@ -105359,8 +105546,8 @@ var init_metaproject_tools = __esm(() => {
|
|
|
105359
105546
|
RG_UNAVAILABLE_SIGNATURE = /ripgrep \(rg\) is not installed|Executable not found[^\n]*\brg\b|\brg\b[^\n]*\bENOENT\b|\bENOENT\b[^\n]*\brg\b/i;
|
|
105360
105547
|
SEARCH_CODE_RG_UNAVAILABLE_MESSAGE = "ripgrep (rg) is not installed or not on PATH, and search_code needs it. Install it " + "(`brew install ripgrep` / `apt install ripgrep`), or use read_file and list_dir to " + "inspect files directly instead of retrying search_code.";
|
|
105361
105548
|
KERYX_ENTRIES = [
|
|
105362
|
-
|
|
105363
|
-
|
|
105549
|
+
resolve5(import.meta.dir, "..", "..", "..", "cli.ts"),
|
|
105550
|
+
resolve5(import.meta.dir, "cli.js")
|
|
105364
105551
|
];
|
|
105365
105552
|
});
|
|
105366
105553
|
|
|
@@ -107924,7 +108111,7 @@ var init_registry3 = __esm(() => {
|
|
|
107924
108111
|
// src/harness/tool/builtin/spawn-subagent-tool.ts
|
|
107925
108112
|
import { createHash as createHash74, randomUUID as randomUUID28 } from "crypto";
|
|
107926
108113
|
import { execFile as execFile7 } from "child_process";
|
|
107927
|
-
import { lstat as
|
|
108114
|
+
import { lstat as lstat17, mkdir as mkdir60, mkdtemp as mkdtemp3, readFile as readFile114, realpath as realpath21, rm as rm16, stat as stat31, writeFile as writeFile38 } from "fs/promises";
|
|
107928
108115
|
import { tmpdir as tmpdir7 } from "os";
|
|
107929
108116
|
import path243 from "path";
|
|
107930
108117
|
import { promisify as promisify5 } from "util";
|
|
@@ -108232,7 +108419,7 @@ async function verifyWorktreeCandidate(candidate, commonDir, worktreesDir) {
|
|
|
108232
108419
|
try {
|
|
108233
108420
|
const realCandidate = await realpath21(candidate);
|
|
108234
108421
|
const dotGit = path243.join(realCandidate, ".git");
|
|
108235
|
-
const dotGitStat = await
|
|
108422
|
+
const dotGitStat = await lstat17(dotGit);
|
|
108236
108423
|
if (dotGitStat.isDirectory()) {
|
|
108237
108424
|
return await realpath21(dotGit) === commonDir ? realCandidate : undefined;
|
|
108238
108425
|
}
|
|
@@ -126701,6 +126888,12 @@ function layersLockPath(packageDir) {
|
|
|
126701
126888
|
function packageMemoryDir(packageDir) {
|
|
126702
126889
|
return path275.join(packageDir, LAYERS_DIR, MEMORY_DIR);
|
|
126703
126890
|
}
|
|
126891
|
+
function failedRecently(existing, now) {
|
|
126892
|
+
if (existing.graph.status !== "failed")
|
|
126893
|
+
return false;
|
|
126894
|
+
const age = now.getTime() - Date.parse(existing.graph.failedAt ?? existing.refreshedAt);
|
|
126895
|
+
return age >= 0 && age < FAILED_RETRY_WINDOW_MS;
|
|
126896
|
+
}
|
|
126704
126897
|
function layersRefreshInFlight(packageDir) {
|
|
126705
126898
|
return isLockHeld(layersLockPath(packageDir), LOCK_STALE_MS2);
|
|
126706
126899
|
}
|
|
@@ -126842,20 +127035,35 @@ async function sweepStaleWorktrees(deps, projectRoot) {
|
|
|
126842
127035
|
await rm19(worktree, { recursive: true, force: true }).catch(() => {});
|
|
126843
127036
|
}
|
|
126844
127037
|
}
|
|
126845
|
-
async function
|
|
126846
|
-
const
|
|
126847
|
-
const cleanup = async () => {
|
|
126848
|
-
await cleanupExtra().catch(() => {});
|
|
126849
|
-
await deps.git(input.projectRoot, ["worktree", "remove", "--force", "--end-of-options", worktree]);
|
|
126850
|
-
await rm19(worktree, { recursive: true, force: true }).catch(() => {});
|
|
126851
|
-
};
|
|
127038
|
+
async function withSignalCleanup(packageDir, body) {
|
|
127039
|
+
const cleanups = new Set;
|
|
126852
127040
|
const onSignal = (signal) => {
|
|
126853
127041
|
for (const name of SIGNALS)
|
|
126854
127042
|
process.off(name, onSignal);
|
|
126855
|
-
|
|
127043
|
+
const settled = Promise.all([...cleanups].map((cleanup) => cleanup().catch(() => {})));
|
|
127044
|
+
const bound = new Promise((resolve) => setTimeout(resolve, SIGNAL_CLEANUP_MAX_MS).unref());
|
|
127045
|
+
Promise.race([settled, bound]).then(() => rm19(layersLockPath(packageDir), { recursive: true, force: true })).catch(() => {}).finally(() => process.kill(process.pid, signal));
|
|
126856
127046
|
};
|
|
126857
127047
|
for (const name of SIGNALS)
|
|
126858
127048
|
process.on(name, onSignal);
|
|
127049
|
+
try {
|
|
127050
|
+
return await body((cleanup) => {
|
|
127051
|
+
cleanups.add(cleanup);
|
|
127052
|
+
return () => void cleanups.delete(cleanup);
|
|
127053
|
+
});
|
|
127054
|
+
} finally {
|
|
127055
|
+
for (const name of SIGNALS)
|
|
127056
|
+
process.off(name, onSignal);
|
|
127057
|
+
}
|
|
127058
|
+
}
|
|
127059
|
+
async function withDetachedWorktree(deps, input, rev, cleanupExtra, register, use) {
|
|
127060
|
+
const worktree = await mkdtemp6(path275.join(tmpdir12(), WORKTREE_PREFIX));
|
|
127061
|
+
const cleanup = async () => {
|
|
127062
|
+
await cleanupExtra().catch(() => {});
|
|
127063
|
+
await deps.git(input.projectRoot, ["worktree", "remove", "--force", "--end-of-options", worktree]);
|
|
127064
|
+
await rm19(worktree, { recursive: true, force: true }).catch(() => {});
|
|
127065
|
+
};
|
|
127066
|
+
const unregister = register(cleanup);
|
|
126859
127067
|
try {
|
|
126860
127068
|
const add = ["-c", "core.hooksPath=/dev/null", "-c", "core.fsmonitor=false", "worktree", "add", "--detach", "--force", "--end-of-options", worktree, rev];
|
|
126861
127069
|
let added = await deps.git(input.projectRoot, add);
|
|
@@ -126867,19 +127075,22 @@ async function withDetachedWorktree(deps, input, rev, cleanupExtra, use) {
|
|
|
126867
127075
|
throw new Error(`could not check out ${rev} to build its graph`);
|
|
126868
127076
|
return await use(worktree, await deps.git(worktree, ["rev-parse", "HEAD"]));
|
|
126869
127077
|
} finally {
|
|
126870
|
-
|
|
126871
|
-
|
|
126872
|
-
|
|
127078
|
+
try {
|
|
127079
|
+
await cleanup();
|
|
127080
|
+
} finally {
|
|
127081
|
+
unregister();
|
|
127082
|
+
}
|
|
126873
127083
|
}
|
|
126874
127084
|
}
|
|
126875
|
-
async function buildPackageGraph(deps, input, prHead) {
|
|
127085
|
+
async function buildPackageGraph(deps, input, prHead, register) {
|
|
126876
127086
|
const failed = (error) => ({
|
|
126877
127087
|
status: "failed",
|
|
126878
127088
|
commit: null,
|
|
126879
127089
|
builtAt: null,
|
|
126880
127090
|
nodes: 0,
|
|
126881
127091
|
edges: 0,
|
|
126882
|
-
error
|
|
127092
|
+
error,
|
|
127093
|
+
failedAt: deps.now().toISOString()
|
|
126883
127094
|
});
|
|
126884
127095
|
if (prHead === null)
|
|
126885
127096
|
return failed("no commit to build the graph at");
|
|
@@ -126887,7 +127098,7 @@ async function buildPackageGraph(deps, input, prHead) {
|
|
|
126887
127098
|
const staging = `${dataDir}.${randomUUID35()}`;
|
|
126888
127099
|
const dropStaging = () => rm19(staging, { recursive: true, force: true }).catch(() => {});
|
|
126889
127100
|
try {
|
|
126890
|
-
return await withDetachedWorktree(deps, input, prHead, dropStaging, async (worktree, builtFrom) => {
|
|
127101
|
+
return await withDetachedWorktree(deps, input, prHead, dropStaging, register, async (worktree, builtFrom) => {
|
|
126891
127102
|
if (builtFrom !== prHead) {
|
|
126892
127103
|
return failed(`graph would be built at ${builtFrom ?? "an unknown commit"}, not the PR head ${prHead}`);
|
|
126893
127104
|
}
|
|
@@ -127005,7 +127216,7 @@ async function refreshLayers(input) {
|
|
|
127005
127216
|
base = fromTarget ?? `${prHead}~1`;
|
|
127006
127217
|
}
|
|
127007
127218
|
await writeSelfIgnoringDir(path275.join(input.packageDir, LAYERS_DIR));
|
|
127008
|
-
return withFileLock(layersLockPath(input.packageDir), async () => {
|
|
127219
|
+
return withFileLock(layersLockPath(input.packageDir), () => withSignalCleanup(input.packageDir, async (register) => {
|
|
127009
127220
|
await recoverGraphDirectory(input.packageDir);
|
|
127010
127221
|
await sweepStaleWorktrees(deps, input.projectRoot);
|
|
127011
127222
|
const existing = await readLayers(input.packageDir);
|
|
@@ -127013,8 +127224,10 @@ async function refreshLayers(input) {
|
|
|
127013
127224
|
let graph;
|
|
127014
127225
|
if (input.force !== true && sameHead && await layersCurrent(input.packageDir, existing, prHead)) {
|
|
127015
127226
|
graph = existing.graph;
|
|
127227
|
+
} else if (input.force !== true && sameHead && failedRecently(existing, deps.now())) {
|
|
127228
|
+
graph = existing.graph;
|
|
127016
127229
|
} else {
|
|
127017
|
-
graph = await buildPackageGraph(deps, input, prHead);
|
|
127230
|
+
graph = await buildPackageGraph(deps, input, prHead, register);
|
|
127018
127231
|
if (graph.status === "failed" && sameHead && await layersCurrent(input.packageDir, existing, prHead)) {
|
|
127019
127232
|
graph = existing.graph;
|
|
127020
127233
|
}
|
|
@@ -127032,10 +127245,10 @@ async function refreshLayers(input) {
|
|
|
127032
127245
|
wiki,
|
|
127033
127246
|
memory
|
|
127034
127247
|
};
|
|
127035
|
-
await
|
|
127248
|
+
await deps.writeLayers(layersFilePath(input.packageDir), `${JSON.stringify(layers, null, 2)}
|
|
127036
127249
|
`);
|
|
127037
127250
|
return layers;
|
|
127038
|
-
}, { timeoutMs: LOCK_WAIT_MS, staleMs: LOCK_STALE_MS2 });
|
|
127251
|
+
}), { timeoutMs: LOCK_WAIT_MS, staleMs: LOCK_STALE_MS2 });
|
|
127039
127252
|
}
|
|
127040
127253
|
async function loadPackageGraph(packageDir, prHead) {
|
|
127041
127254
|
if (await layersRefreshInFlight(packageDir)) {
|
|
@@ -127045,7 +127258,8 @@ async function loadPackageGraph(packageDir, prHead) {
|
|
|
127045
127258
|
if (layers === null)
|
|
127046
127259
|
throw new PackageGraphError(`no ${LAYERS_FILE} in ${packageDir}; run \`keryx review layers refresh --package ${shellWord(packageDir)}\``);
|
|
127047
127260
|
if (layers.graph.status !== "ok") {
|
|
127048
|
-
|
|
127261
|
+
const retry = layers.graph.status === "failed" ? `; a failed build is not retried for ${FAILED_RETRY_WINDOW_MS / 60000} minutes at the same head, run \`keryx review layers refresh --package ${shellWord(packageDir)} --force\` to retry now` : "";
|
|
127262
|
+
throw new PackageGraphError(`the package graph is ${layers.graph.status}${layers.graph.error ? `: ${layers.graph.error}` : ""}${retry}`);
|
|
127049
127263
|
}
|
|
127050
127264
|
if (!await graphIntact(packageDir, layers)) {
|
|
127051
127265
|
throw new PackageGraphError(`the package graph directory is missing or does not match ${LAYERS_FILE}; run \`keryx review layers refresh --package ${shellWord(packageDir)}\``);
|
|
@@ -127057,7 +127271,7 @@ async function loadPackageGraph(packageDir, prHead) {
|
|
|
127057
127271
|
const dataDir = packageGraphDir(packageDir);
|
|
127058
127272
|
return { graph: await loadGraph(packageDir, dataDir), dataDir, layers };
|
|
127059
127273
|
}
|
|
127060
|
-
var execFileAsync9, LAYERS_FILE = "layers.json", LAYERS_VERSION = 1, LAYERS_DIR = "layers", GRAPH_DIR = "graph", GRAPH_BUILD_FILE = "build.json", MEMORY_DIR = "memory", LOCK_NAME = "refresh.lock", MANIFEST_FILE2 = "manifest.json", LOCK_STALE_MS2 = 60000, LOCK_WAIT_MS, WORKTREE_PREFIX = "keryx-layers-", WORKTREE_SWEEP_AGE_MS, SIGNALS, WIKI_PATH_PREFIX = ".metaproject/wiki", MEMORY_PATH_PREFIX = ".metaproject/memory", defaultLayerDeps, COMMIT_ID, PackageGraphError;
|
|
127274
|
+
var execFileAsync9, LAYERS_FILE = "layers.json", LAYERS_VERSION = 1, LAYERS_DIR = "layers", GRAPH_DIR = "graph", GRAPH_BUILD_FILE = "build.json", MEMORY_DIR = "memory", LOCK_NAME = "refresh.lock", MANIFEST_FILE2 = "manifest.json", LOCK_STALE_MS2 = 60000, LOCK_WAIT_MS, WORKTREE_PREFIX = "keryx-layers-", WORKTREE_SWEEP_AGE_MS, FAILED_RETRY_WINDOW_MS, SIGNALS, SIGNAL_CLEANUP_MAX_MS = 5000, WIKI_PATH_PREFIX = ".metaproject/wiki", MEMORY_PATH_PREFIX = ".metaproject/memory", defaultLayerDeps, COMMIT_ID, PackageGraphError;
|
|
127061
127275
|
var init_layers = __esm(() => {
|
|
127062
127276
|
init_build();
|
|
127063
127277
|
init_fs();
|
|
@@ -127071,6 +127285,7 @@ var init_layers = __esm(() => {
|
|
|
127071
127285
|
execFileAsync9 = promisify9(execFile11);
|
|
127072
127286
|
LOCK_WAIT_MS = 16 * 60000;
|
|
127073
127287
|
WORKTREE_SWEEP_AGE_MS = 30 * 60000;
|
|
127288
|
+
FAILED_RETRY_WINDOW_MS = 5 * 60000;
|
|
127074
127289
|
SIGNALS = ["SIGINT", "SIGTERM"];
|
|
127075
127290
|
defaultLayerDeps = {
|
|
127076
127291
|
async git(cwd, args) {
|
|
@@ -127090,6 +127305,7 @@ var init_layers = __esm(() => {
|
|
|
127090
127305
|
async indexMemory(cwd, indexDir) {
|
|
127091
127306
|
return createMemoryService().index({ cwd, embeddings: false, indexDir });
|
|
127092
127307
|
},
|
|
127308
|
+
writeLayers: writeFileAtomic,
|
|
127093
127309
|
now: () => new Date
|
|
127094
127310
|
};
|
|
127095
127311
|
COMMIT_ID = /^[0-9a-f]{7,64}$/i;
|
|
@@ -127119,7 +127335,7 @@ function layersSummaryLine(layers) {
|
|
|
127119
127335
|
function layersDetailLines(layers) {
|
|
127120
127336
|
const lines = [];
|
|
127121
127337
|
const graph = layers.graph;
|
|
127122
|
-
lines.push(graph.status === "ok" ? `graph: ok @${shortSha(graph.commit)} = ${graphHeadState(layers)} (PR head ${shortSha(layers.prHead)}), ${graph.nodes} nodes, ${graph.edges} edges, built ${graph.builtAt ?? "?"}` : `graph: ${graph.status}${graph.error ? ` \u2014 ${graph.error}` : ""}`);
|
|
127338
|
+
lines.push(graph.status === "ok" ? `graph: ok @${shortSha(graph.commit)} = ${graphHeadState(layers)} (PR head ${shortSha(layers.prHead)}), ${graph.nodes} nodes, ${graph.edges} edges, built ${graph.builtAt ?? "?"}` : `graph: ${graph.status}${graph.error ? ` \u2014 ${graph.error}` : ""}${graph.status === "failed" ? " (not retried automatically for a few minutes at the same head; refresh --force retries now)" : ""}`);
|
|
127123
127339
|
const wiki = layers.wiki;
|
|
127124
127340
|
lines.push(`wiki: ${wiki.status} @${shortSha(wiki.commit)}, divergence ${divergenceText(wiki.divergence)}, ${wiki.pagesRefreshed} page(s) ${wiki.written ? "refreshed" : "would refresh (dry run)"}, ` + `${wiki.pagesStaleProse === null ? "stale prose unknown" : `${wiki.pagesStaleProse} page(s) with stale prose`}${wiki.error ? ` \u2014 ${wiki.error}` : ""}`);
|
|
127125
127341
|
const memory = layers.memory;
|
|
@@ -127458,7 +127674,7 @@ var init_review_panel = __esm(() => {
|
|
|
127458
127674
|
// src/tui/review-layers-actions.ts
|
|
127459
127675
|
import { execFile as execFile12 } from "child_process";
|
|
127460
127676
|
function layersRefreshArgv(entry, packageDir) {
|
|
127461
|
-
return [...SAFE_BUN_SPAWN_ARGS, entry, "review", "layers", "refresh", "--package", packageDir, "--json"];
|
|
127677
|
+
return [...SAFE_BUN_SPAWN_ARGS, entry, "review", "layers", "refresh", "--package", packageDir, "--force", "--json"];
|
|
127462
127678
|
}
|
|
127463
127679
|
function killLiveChildren() {
|
|
127464
127680
|
for (const child of liveChildren)
|
|
@@ -127474,8 +127690,14 @@ function makeLayersRefreshRunner(entry, timeoutMs = REFRESH_TIMEOUT_MS) {
|
|
|
127474
127690
|
exitHookInstalled = true;
|
|
127475
127691
|
process.once("exit", killLiveChildren);
|
|
127476
127692
|
}
|
|
127693
|
+
const startedAt = Date.now();
|
|
127477
127694
|
const child = execFile12(process.execPath, layersRefreshArgv(entry, packageDir), { cwd: projectRoot, timeout: timeoutMs, maxBuffer: 16 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
127478
127695
|
liveChildren.delete(child);
|
|
127696
|
+
if (error?.killed === true || /maxBuffer/i.test(error?.message ?? "")) {
|
|
127697
|
+
const timedOut = error?.killed === true && Date.now() - startedAt >= timeoutMs - 100;
|
|
127698
|
+
reject(new Error(timedOut ? `the layers refresh did not finish within ${Math.round(timeoutMs / 1000)}s and was stopped` : "the layers refresh printed more output than the limit allows and was stopped"));
|
|
127699
|
+
return;
|
|
127700
|
+
}
|
|
127479
127701
|
try {
|
|
127480
127702
|
resolve(JSON.parse(stdout));
|
|
127481
127703
|
} catch {
|
|
@@ -137684,7 +137906,7 @@ function protectJsonIds(text) {
|
|
|
137684
137906
|
const head = text.trim();
|
|
137685
137907
|
if (head.length === 0 || head[0] !== "[" && head[0] !== "{")
|
|
137686
137908
|
return;
|
|
137687
|
-
if (text.includes(
|
|
137909
|
+
if (text.includes(PLACEHOLDER2))
|
|
137688
137910
|
return;
|
|
137689
137911
|
try {
|
|
137690
137912
|
JSON.parse(head);
|
|
@@ -137694,7 +137916,7 @@ function protectJsonIds(text) {
|
|
|
137694
137916
|
const hidden = [];
|
|
137695
137917
|
const hide = (value) => {
|
|
137696
137918
|
hidden.push(value);
|
|
137697
|
-
return `${
|
|
137919
|
+
return `${PLACEHOLDER2}${letters(hidden.length - 1)}x`;
|
|
137698
137920
|
};
|
|
137699
137921
|
let out = "";
|
|
137700
137922
|
let i = 0;
|
|
@@ -137724,13 +137946,13 @@ function protectJsonIds(text) {
|
|
|
137724
137946
|
}
|
|
137725
137947
|
return {
|
|
137726
137948
|
text: out,
|
|
137727
|
-
restore: (scrubbed) => scrubbed.replace(new RegExp(`${
|
|
137949
|
+
restore: (scrubbed) => scrubbed.replace(new RegExp(`${PLACEHOLDER2}([a-j]+)x`, "g"), (whole, index) => {
|
|
137728
137950
|
const at = Number(index.replace(/[a-j]/g, (c) => String(c.charCodeAt(0) - 97)));
|
|
137729
137951
|
return hidden[at] ?? whole;
|
|
137730
137952
|
})
|
|
137731
137953
|
};
|
|
137732
137954
|
}
|
|
137733
|
-
var
|
|
137955
|
+
var PLACEHOLDER2 = "kxjsonid", GITHUB_URL_PREFIX, GITHUB_URL_REST, SENSITIVE_KEY, NUMBER2;
|
|
137734
137956
|
var init_granted_json_ids = __esm(() => {
|
|
137735
137957
|
GITHUB_URL_PREFIX = /^https:\/\/(?:api\.)?github\.com\/(?:repos\/)?[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\//;
|
|
137736
137958
|
GITHUB_URL_REST = /^(?:actions\/runs|pull|issues)\/\d+(?:\/[A-Za-z0-9_-]+)*(?:#[A-Za-z_-]+-?\d+)?$/;
|
|
@@ -146462,6 +146684,7 @@ function mountStartupIndicator(otui, r, initialLabel, opts = {}) {
|
|
|
146462
146684
|
return;
|
|
146463
146685
|
}
|
|
146464
146686
|
text.content = otui.t`${dimChunk(otui, `${SPINNER_FRAMES[frame % SPINNER_FRAMES.length]} ${label}`)}`;
|
|
146687
|
+
r.requestRender();
|
|
146465
146688
|
};
|
|
146466
146689
|
paint();
|
|
146467
146690
|
const schedule = opts.setInterval ?? ((fn, ms) => setInterval(fn, ms));
|
|
@@ -146483,6 +146706,7 @@ function mountStartupIndicator(otui, r, initialLabel, opts = {}) {
|
|
|
146483
146706
|
removed = true;
|
|
146484
146707
|
unschedule(timer);
|
|
146485
146708
|
r.root.remove(box);
|
|
146709
|
+
r.requestRender();
|
|
146486
146710
|
}
|
|
146487
146711
|
};
|
|
146488
146712
|
}
|
|
@@ -158195,6 +158419,15 @@ async function fetchCodexLimits(fetchFn, model, configDir, timeoutMs) {
|
|
|
158195
158419
|
return {};
|
|
158196
158420
|
}
|
|
158197
158421
|
}
|
|
158422
|
+
function startSessionLimits(input, load = loadSessionLimits) {
|
|
158423
|
+
let contextWindow;
|
|
158424
|
+
const ready = new Promise((resolve) => setTimeout(resolve, 0)).then(async () => {
|
|
158425
|
+
try {
|
|
158426
|
+
contextWindow = (await load(input)).contextWindow;
|
|
158427
|
+
} catch {}
|
|
158428
|
+
});
|
|
158429
|
+
return { getContextWindow: () => contextWindow, ready };
|
|
158430
|
+
}
|
|
158198
158431
|
async function loadSessionLimits(input) {
|
|
158199
158432
|
const fetchFn = input.fetch ?? globalThis.fetch;
|
|
158200
158433
|
const env = envWithSavedApiKeys(input.env ?? process.env);
|
|
@@ -180210,15 +180443,12 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
|
|
|
180210
180443
|
steerable: true
|
|
180211
180444
|
})
|
|
180212
180445
|
});
|
|
180213
|
-
|
|
180214
|
-
|
|
180215
|
-
|
|
180216
|
-
|
|
180217
|
-
|
|
180218
|
-
|
|
180219
|
-
});
|
|
180220
|
-
contextWindow = limits.contextWindow;
|
|
180221
|
-
} catch {}
|
|
180446
|
+
const limits = startSessionLimits({
|
|
180447
|
+
provider: sel.provider,
|
|
180448
|
+
model: sel.model,
|
|
180449
|
+
...sel.baseUrl !== undefined ? { baseUrl: sel.baseUrl } : {},
|
|
180450
|
+
...runtime.cacheDir !== undefined ? { configDir: runtime.cacheDir } : {}
|
|
180451
|
+
});
|
|
180222
180452
|
const deps = {
|
|
180223
180453
|
provider: agentProvider,
|
|
180224
180454
|
providerId: sel.provider,
|
|
@@ -180250,7 +180480,7 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
|
|
|
180250
180480
|
sweepBackgroundJobs: () => jobRegistry.sweepAll(),
|
|
180251
180481
|
jobRegistry,
|
|
180252
180482
|
...resetSubagentBudget !== undefined ? { resetSubagentBudget } : {},
|
|
180253
|
-
|
|
180483
|
+
getContextWindow: limits.getContextWindow,
|
|
180254
180484
|
...Object.keys(resolvedModelParams).length > 0 ? { modelParams: resolvedModelParams } : {},
|
|
180255
180485
|
...(() => {
|
|
180256
180486
|
const h = getShellHooks();
|
|
@@ -181120,7 +181350,7 @@ var init_retired_rules = __esm(() => {
|
|
|
181120
181350
|
});
|
|
181121
181351
|
|
|
181122
181352
|
// src/gdskills/guarded-fs-ops.ts
|
|
181123
|
-
import { cp as cp2, lstat as
|
|
181353
|
+
import { cp as cp2, lstat as lstat18, readFile as readFile171, readdir as readdir59, realpath as realpath25, unlink as unlink3 } from "fs/promises";
|
|
181124
181354
|
import { existsSync as existsSync63 } from "fs";
|
|
181125
181355
|
import { createHash as createHash84 } from "crypto";
|
|
181126
181356
|
import path340 from "path";
|
|
@@ -181211,7 +181441,7 @@ async function removeStaleRuntimeBuilds(skillsRoot, fsOps = { unlink: unlink3 })
|
|
|
181211
181441
|
continue;
|
|
181212
181442
|
const installedPath = path340.join(installedDir, entryName);
|
|
181213
181443
|
try {
|
|
181214
|
-
const stats = await
|
|
181444
|
+
const stats = await lstat18(installedPath);
|
|
181215
181445
|
if (!stats.isFile()) {
|
|
181216
181446
|
outcomes.push({ path: installedPath, action: "kept-not-regular-file" });
|
|
181217
181447
|
continue;
|
|
@@ -181230,7 +181460,7 @@ async function removeStaleRuntimeBuilds(skillsRoot, fsOps = { unlink: unlink3 })
|
|
|
181230
181460
|
}
|
|
181231
181461
|
async function resolveSweepableDir(dir) {
|
|
181232
181462
|
try {
|
|
181233
|
-
const stats = await
|
|
181463
|
+
const stats = await lstat18(dir);
|
|
181234
181464
|
if (stats.isSymbolicLink() || !stats.isDirectory()) {
|
|
181235
181465
|
return {
|
|
181236
181466
|
kind: "blocked",
|
|
@@ -181305,7 +181535,7 @@ async function removeUnmodifiedRetiredRules(rulesTarget, fsOps = { unlink: unlin
|
|
|
181305
181535
|
const installedPath = path340.join(rulesTarget, retired.fileName);
|
|
181306
181536
|
let stage = "lstat";
|
|
181307
181537
|
try {
|
|
181308
|
-
const stats = await
|
|
181538
|
+
const stats = await lstat18(installedPath);
|
|
181309
181539
|
if (!stats.isFile()) {
|
|
181310
181540
|
outcomes.push({ fileName: retired.fileName, action: "kept-not-regular-file" });
|
|
181311
181541
|
continue;
|
|
@@ -181376,7 +181606,7 @@ var init_guarded_fs_ops = __esm(() => {
|
|
|
181376
181606
|
});
|
|
181377
181607
|
|
|
181378
181608
|
// src/gdskills/install.ts
|
|
181379
|
-
import { lstat as
|
|
181609
|
+
import { lstat as lstat19, readFile as readFile172, readlink as readlink2 } from "fs/promises";
|
|
181380
181610
|
import { existsSync as existsSync64 } from "fs";
|
|
181381
181611
|
import path341 from "path";
|
|
181382
181612
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
@@ -181489,7 +181719,7 @@ async function installBundledSharedSkills(skillsRoot, metaprojectRoot) {
|
|
|
181489
181719
|
async function checkInstallDestination(destination, displayPath) {
|
|
181490
181720
|
let stats;
|
|
181491
181721
|
try {
|
|
181492
|
-
stats = await
|
|
181722
|
+
stats = await lstat19(destination);
|
|
181493
181723
|
} catch (error) {
|
|
181494
181724
|
if (isErrnoException(error) && error.code === "ENOENT") {
|
|
181495
181725
|
return { usable: true };
|
|
@@ -181572,7 +181802,7 @@ async function installContracts(contractsRoot, metaprojectRoot) {
|
|
|
181572
181802
|
async function checkInstallFile(destination, displayPath) {
|
|
181573
181803
|
let stats;
|
|
181574
181804
|
try {
|
|
181575
|
-
stats = await
|
|
181805
|
+
stats = await lstat19(destination);
|
|
181576
181806
|
} catch (error) {
|
|
181577
181807
|
if (isMissingPathError(error)) {
|
|
181578
181808
|
return { usable: true };
|
|
@@ -189768,7 +189998,7 @@ var init_plan = __esm(() => {
|
|
|
189768
189998
|
});
|
|
189769
189999
|
|
|
189770
190000
|
// src/gdskills/manifest/state.ts
|
|
189771
|
-
import { lstat as
|
|
190001
|
+
import { lstat as lstat20, readFile as readFile182 } from "fs/promises";
|
|
189772
190002
|
import path363 from "path";
|
|
189773
190003
|
function isValidInstallState(value) {
|
|
189774
190004
|
return validateAgainstSchemaObject(INSTALL_STATE_SCHEMA, value).valid;
|
|
@@ -189811,7 +190041,7 @@ async function hasSymlinkSegment(repoRoot, posixRel) {
|
|
|
189811
190041
|
current = path363.join(current, segment);
|
|
189812
190042
|
let stat;
|
|
189813
190043
|
try {
|
|
189814
|
-
stat = await
|
|
190044
|
+
stat = await lstat20(current);
|
|
189815
190045
|
} catch {
|
|
189816
190046
|
return false;
|
|
189817
190047
|
}
|
|
@@ -190390,7 +190620,7 @@ var init_sync2 = __esm(() => {
|
|
|
190390
190620
|
});
|
|
190391
190621
|
|
|
190392
190622
|
// src/gdskills/import-skills.ts
|
|
190393
|
-
import { lstat as
|
|
190623
|
+
import { lstat as lstat21, readdir as readdir64, readFile as readFile185, stat as stat41 } from "fs/promises";
|
|
190394
190624
|
import { homedir as homedir15 } from "os";
|
|
190395
190625
|
import path368 from "path";
|
|
190396
190626
|
function emptyOnlyError(label) {
|
|
@@ -191401,7 +191631,7 @@ async function decideReferencedRules(options, sources, refusedPackages) {
|
|
|
191401
191631
|
async function listTemplateFiles(sourcePath) {
|
|
191402
191632
|
const root = path368.join(path368.dirname(sourcePath), TEMPLATES_DIR);
|
|
191403
191633
|
try {
|
|
191404
|
-
if (!(await
|
|
191634
|
+
if (!(await lstat21(root)).isDirectory())
|
|
191405
191635
|
return [];
|
|
191406
191636
|
} catch {
|
|
191407
191637
|
return [];
|
|
@@ -191823,7 +192053,7 @@ var init_import_skills = __esm(() => {
|
|
|
191823
192053
|
});
|
|
191824
192054
|
|
|
191825
192055
|
// src/gdskills/remove-skill.ts
|
|
191826
|
-
import { lstat as
|
|
192056
|
+
import { lstat as lstat22, readdir as readdir65, readFile as readFile186, realpath as realpath26 } from "fs/promises";
|
|
191827
192057
|
import path369 from "path";
|
|
191828
192058
|
async function removeProjectSkill(projectRoot, options) {
|
|
191829
192059
|
if (!await pathExists(path369.join(projectRoot, ".metaproject"))) {
|
|
@@ -192018,7 +192248,7 @@ function normalizeSkillKey(input) {
|
|
|
192018
192248
|
}
|
|
192019
192249
|
async function lstatOrMissing(target) {
|
|
192020
192250
|
try {
|
|
192021
|
-
return await
|
|
192251
|
+
return await lstat22(target);
|
|
192022
192252
|
} catch (error) {
|
|
192023
192253
|
if (isMissingPathError(error))
|
|
192024
192254
|
return;
|
|
@@ -192083,7 +192313,7 @@ async function locateRewritable(root, relativePath) {
|
|
|
192083
192313
|
if (absolute === root || !isPathInside(root, absolute)) {
|
|
192084
192314
|
throw new Error(`${LABEL}: ${relativePath} resolves to ${absolute}, outside the project. Refusing to rewrite a file the project does not own. ${UNCHANGED}`);
|
|
192085
192315
|
}
|
|
192086
|
-
if (!(await
|
|
192316
|
+
if (!(await lstat22(absolute)).isFile()) {
|
|
192087
192317
|
throw new Error(`${LABEL}: ${relativePath} is not a regular file. ${UNCHANGED}`);
|
|
192088
192318
|
}
|
|
192089
192319
|
const resolvedPath = toPosix(path369.relative(root, absolute));
|
|
@@ -197025,7 +197255,7 @@ function buildLedger(input) {
|
|
|
197025
197255
|
continue;
|
|
197026
197256
|
}
|
|
197027
197257
|
obligations.push({ ...base, status: "unresolved" });
|
|
197028
|
-
gaps.push({ detail: `${id}: raw finding is not in the canonical findings and has no closure`, next: `add a disposition {"id":"${id}","status":"finding|refuted|out-of-scope","evidence":\u2026,"reason":\u2026} to --dispositions` });
|
|
197258
|
+
gaps.push({ detail: `${id}: raw finding is not in the canonical findings and has no closure`, next: `add a disposition {"id":"${id}","status":"finding|refuted|out-of-scope|narrowed","evidence":\u2026,"reason":\u2026,"remains":\u2026 (narrowed only)} to --dispositions` });
|
|
197029
197259
|
}
|
|
197030
197260
|
}
|
|
197031
197261
|
for (const given of input.dispositions) {
|
|
@@ -197053,7 +197283,9 @@ function closeWith(given, canonical) {
|
|
|
197053
197283
|
return;
|
|
197054
197284
|
if (given.status === "finding" && !(text4(given.finding) && canonical.filter((f) => f.id === given.finding || f.global_id === given.finding).length === 1))
|
|
197055
197285
|
return;
|
|
197056
|
-
|
|
197286
|
+
if (given.status === "narrowed" && !text4(given.remains))
|
|
197287
|
+
return;
|
|
197288
|
+
return { status: given.status, evidence: given.evidence, reason: given.reason, ...given.status === "finding" ? { finding: given.finding } : {}, ...given.status === "narrowed" ? { remains: given.remains } : {} };
|
|
197057
197289
|
}
|
|
197058
197290
|
async function ledgerBlockers(ledger, canonical, options) {
|
|
197059
197291
|
const dispatch = dispatchErrors(ledger.dispatch);
|
|
@@ -197069,7 +197301,7 @@ var init_ledger2 = __esm(() => {
|
|
|
197069
197301
|
init_slice();
|
|
197070
197302
|
init_waves();
|
|
197071
197303
|
FINISHED = new Set(["DONE", "DONE_WITH_CONCERNS"]);
|
|
197072
|
-
CLOSED = new Set(["finding", "refuted", "out-of-scope"]);
|
|
197304
|
+
CLOSED = new Set(["finding", "refuted", "out-of-scope", "narrowed"]);
|
|
197073
197305
|
OBJECT_START = /\{\s*["}]/y;
|
|
197074
197306
|
RESULT_KEYS = new Set(["status", "reviewer", "findings"]);
|
|
197075
197307
|
KEY_COLON = /\s*:/y;
|
|
@@ -197101,8 +197333,8 @@ needs_context and every slice its path gate requires covered by its dispatched p
|
|
|
197101
197333
|
complete run (source-only, executionRequired false); anything else \u2014 NEEDS_CONTEXT, BLOCKED,
|
|
197102
197334
|
INCOMPLETE, missing slices, no result \u2014 stays incomplete or not-run, never declared complete.
|
|
197103
197335
|
Each raw finding becomes an obligation, closed only by a matching canonical finding or a
|
|
197104
|
-
valid --dispositions entry ({id, status finding|refuted|out-of-scope, evidence, reason,
|
|
197105
|
-
finding?}; default: the obligations already in research.json). scopeReviewed and rawReconciled
|
|
197336
|
+
valid --dispositions entry ({id, status finding|refuted|out-of-scope|narrowed, evidence, reason,
|
|
197337
|
+
finding?, remains? \u2014 required for narrowed: what of the finding still stands}; default: the obligations already in research.json). scopeReviewed and rawReconciled
|
|
197106
197338
|
are true only when established.
|
|
197107
197339
|
|
|
197108
197340
|
Slices are dispatched in waves bounded by the manifest's wave budget; a reviewer that covered
|
|
@@ -197348,24 +197580,36 @@ import path380 from "path";
|
|
|
197348
197580
|
function sizeOf(block) {
|
|
197349
197581
|
return Buffer.byteLength(JSON.stringify(block), "utf8");
|
|
197350
197582
|
}
|
|
197583
|
+
function reasonOf(error) {
|
|
197584
|
+
const first = (error instanceof Error ? error.message : String(error)).split(`
|
|
197585
|
+
`)[0] ?? "unknown error";
|
|
197586
|
+
return first.length > MAX_REASON_CHARS ? `${first.slice(0, MAX_REASON_CHARS)}\u2026` : first;
|
|
197587
|
+
}
|
|
197351
197588
|
function unique2(values) {
|
|
197352
197589
|
return [...new Set(values)].sort();
|
|
197353
197590
|
}
|
|
197354
197591
|
function affectedFor(graph, files, depth) {
|
|
197355
197592
|
const own = new Set(files);
|
|
197356
197593
|
const found = new Set;
|
|
197594
|
+
const failures = [];
|
|
197357
197595
|
for (const file of files) {
|
|
197358
197596
|
let result;
|
|
197359
197597
|
try {
|
|
197360
197598
|
result = computeAffected(graph, file, { depth });
|
|
197361
|
-
} catch {
|
|
197599
|
+
} catch (error) {
|
|
197600
|
+
failures.push(`${file}: ${reasonOf(error)}`);
|
|
197362
197601
|
continue;
|
|
197363
197602
|
}
|
|
197364
197603
|
for (const dependent of result.dependents)
|
|
197365
197604
|
if (!own.has(dependent))
|
|
197366
197605
|
found.add(dependent);
|
|
197367
197606
|
}
|
|
197368
|
-
|
|
197607
|
+
const named = failures.slice(0, MAX_NAMED_FAILURES).join("; ");
|
|
197608
|
+
const more = failures.length > MAX_NAMED_FAILURES ? ` (and ${failures.length - MAX_NAMED_FAILURES} more)` : "";
|
|
197609
|
+
return {
|
|
197610
|
+
files: [...found].sort(),
|
|
197611
|
+
unavailable: failures.length === 0 ? null : `not computed for ${failures.length} of ${files.length} file(s) \u2014 ${named}${more}`
|
|
197612
|
+
};
|
|
197369
197613
|
}
|
|
197370
197614
|
function symbolsFor(graph, files) {
|
|
197371
197615
|
const symbols = graph.symbols ?? [];
|
|
@@ -197415,29 +197659,34 @@ function relatedTestsFor(graph, files, affected) {
|
|
|
197415
197659
|
found.add(dependent);
|
|
197416
197660
|
return [...found].sort();
|
|
197417
197661
|
}
|
|
197418
|
-
async function wikiFor(projectRoot, graph, files) {
|
|
197662
|
+
async function wikiFor(projectRoot, graph, files, readPage = (absolutePath) => readFile196(absolutePath, "utf8")) {
|
|
197419
197663
|
let pages;
|
|
197420
197664
|
try {
|
|
197421
197665
|
pages = await collectPages(projectRoot);
|
|
197422
|
-
} catch {
|
|
197423
|
-
return [];
|
|
197666
|
+
} catch (error) {
|
|
197667
|
+
return { items: [], unavailable: `the wiki could not be read \u2014 ${reasonOf(error)}` };
|
|
197424
197668
|
}
|
|
197425
197669
|
const knownPaths = new Set(graph.nodes.map((node) => node.path));
|
|
197426
197670
|
const keyFilesIndex = computeModuleKeyFiles(graph);
|
|
197427
197671
|
const wanted = new Set(files);
|
|
197428
197672
|
const out = [];
|
|
197673
|
+
const unreadable = [];
|
|
197429
197674
|
for (const page of pages) {
|
|
197430
197675
|
let content;
|
|
197431
197676
|
try {
|
|
197432
|
-
content = await
|
|
197677
|
+
content = await readPage(page.absolutePath);
|
|
197433
197678
|
} catch {
|
|
197679
|
+
unreadable.push(page.relativePath);
|
|
197434
197680
|
continue;
|
|
197435
197681
|
}
|
|
197436
197682
|
const set = resolveDescribeSet({ page, content, knownPaths, keyFilesIndex });
|
|
197437
197683
|
if (set.paths.some((candidate) => wanted.has(candidate)))
|
|
197438
197684
|
out.push({ page: page.relativePath, title: page.title });
|
|
197439
197685
|
}
|
|
197440
|
-
return
|
|
197686
|
+
return {
|
|
197687
|
+
items: out.sort((a, b) => a.page.localeCompare(b.page)),
|
|
197688
|
+
unavailable: unreadable.length === 0 ? null : `${unreadable.length} of ${pages.length} wiki page(s) could not be read \u2014 ${unreadable.slice(0, MAX_NAMED_FAILURES).join(", ")}`
|
|
197689
|
+
};
|
|
197441
197690
|
}
|
|
197442
197691
|
function modulesOf(file) {
|
|
197443
197692
|
const parts = file.split("/").filter(Boolean);
|
|
@@ -197451,8 +197700,8 @@ async function memoryFor(projectRoot, files) {
|
|
|
197451
197700
|
let entries;
|
|
197452
197701
|
try {
|
|
197453
197702
|
entries = await collectEntries(projectRoot);
|
|
197454
|
-
} catch {
|
|
197455
|
-
return [];
|
|
197703
|
+
} catch (error) {
|
|
197704
|
+
return { items: [], unavailable: `the memory could not be read \u2014 ${reasonOf(error)}` };
|
|
197456
197705
|
}
|
|
197457
197706
|
const modules = new Set(files.flatMap(modulesOf));
|
|
197458
197707
|
const wanted = new Set(files);
|
|
@@ -197466,7 +197715,7 @@ async function memoryFor(projectRoot, files) {
|
|
|
197466
197715
|
if (byModule || byFile)
|
|
197467
197716
|
out.push({ path: entry.relativePath, title: entry.title, status: entry.status, module: module ?? "" });
|
|
197468
197717
|
}
|
|
197469
|
-
return out.sort((a, b) => a.path.localeCompare(b.path));
|
|
197718
|
+
return { items: out.sort((a, b) => a.path.localeCompare(b.path)), unavailable: null };
|
|
197470
197719
|
}
|
|
197471
197720
|
function fetchCommand(section, files, packageDir, projectRoot) {
|
|
197472
197721
|
const first = files[0] ?? "<file>";
|
|
@@ -197496,18 +197745,28 @@ async function buildLayersBlock(input) {
|
|
|
197496
197745
|
const { graph, layers } = await loadPackageGraph(input.packageDir);
|
|
197497
197746
|
const base = async (depth) => {
|
|
197498
197747
|
const affected = affectedFor(graph, files, depth);
|
|
197748
|
+
const wiki = await wikiFor(input.projectRoot, graph, files, input.readPage);
|
|
197749
|
+
const memory = await memoryFor(input.projectRoot, files);
|
|
197750
|
+
const unavailable = [];
|
|
197751
|
+
if (affected.unavailable !== null)
|
|
197752
|
+
unavailable.push({ section: "affected", reason: affected.unavailable });
|
|
197753
|
+
if (wiki.unavailable !== null)
|
|
197754
|
+
unavailable.push({ section: "wiki", reason: wiki.unavailable });
|
|
197755
|
+
if (memory.unavailable !== null)
|
|
197756
|
+
unavailable.push({ section: "memory", reason: memory.unavailable });
|
|
197499
197757
|
return {
|
|
197500
197758
|
version: LAYERS_BLOCK_VERSION,
|
|
197501
197759
|
files,
|
|
197502
197760
|
prHead: layers.prHead,
|
|
197503
197761
|
graphCommit: layers.graphCommit,
|
|
197504
197762
|
maxBytes,
|
|
197505
|
-
affected: { depth, files: affected },
|
|
197763
|
+
affected: { depth, files: affected.files },
|
|
197506
197764
|
symbols: symbolsFor(graph, files),
|
|
197507
|
-
relatedTests: relatedTestsFor(graph, files, affected),
|
|
197508
|
-
wiki:
|
|
197509
|
-
memory:
|
|
197510
|
-
truncated: []
|
|
197765
|
+
relatedTests: relatedTestsFor(graph, files, affected.files),
|
|
197766
|
+
wiki: wiki.items,
|
|
197767
|
+
memory: memory.items,
|
|
197768
|
+
truncated: [],
|
|
197769
|
+
unavailable
|
|
197511
197770
|
};
|
|
197512
197771
|
};
|
|
197513
197772
|
let block = await base(1);
|
|
@@ -197577,11 +197836,13 @@ function layersBlockLines(block) {
|
|
|
197577
197836
|
` wiki pages: ${block.wiki.length}`,
|
|
197578
197837
|
` memory entries: ${block.memory.length}`
|
|
197579
197838
|
];
|
|
197839
|
+
for (const gap of block.unavailable)
|
|
197840
|
+
lines.push(` ${gap.section}: unavailable (${gap.reason})`);
|
|
197580
197841
|
for (const cut of block.truncated)
|
|
197581
197842
|
lines.push(` truncated ${cut.section}: ${cut.shown}/${cut.total} \u2014 ${cut.command}`);
|
|
197582
197843
|
return lines;
|
|
197583
197844
|
}
|
|
197584
|
-
var LAYERS_BLOCK_VERSION = 1, DEFAULT_LAYERS_BLOCK_MAX_BYTES = 8192, MAX_SYMBOLS_PER_FILE = 6, MAX_NEIGHBOURS_PER_SYMBOL = 4, MAX_BLOCK_FILES = 100, LAYERS_BLOCK_SECTIONS, CONTROL_CHARACTER;
|
|
197845
|
+
var LAYERS_BLOCK_VERSION = 1, DEFAULT_LAYERS_BLOCK_MAX_BYTES = 8192, MAX_SYMBOLS_PER_FILE = 6, MAX_NEIGHBOURS_PER_SYMBOL = 4, MAX_REASON_CHARS = 160, MAX_BLOCK_FILES = 100, LAYERS_BLOCK_SECTIONS, MAX_NAMED_FAILURES = 3, CONTROL_CHARACTER;
|
|
197585
197846
|
var init_layers_payload = __esm(() => {
|
|
197586
197847
|
init_affected();
|
|
197587
197848
|
init_shell_quote();
|
|
@@ -197602,7 +197863,7 @@ function printLayersHelp() {
|
|
|
197602
197863
|
|
|
197603
197864
|
keryx review layers refresh --package <dir> [--head <sha>] [--base <ref>] [--write-wiki] [--force] [--json]
|
|
197604
197865
|
keryx review layers status --package <dir> [--json]
|
|
197605
|
-
keryx review layers block --package <dir> --files <a,b,...> [--max-bytes <n>] [--json]
|
|
197866
|
+
keryx review layers block --package <dir> --files <a,b,...> [--max-bytes <n>] [--force] [--json]
|
|
197606
197867
|
|
|
197607
197868
|
\`block\` prints the bounded \`layers\` block a reviewer payload carries for those files: files
|
|
197608
197869
|
the graph says are affected (depth 1, then 2 while under the cap), symbol neighbours, related
|
|
@@ -197618,7 +197879,8 @@ The graph is built at the PR head into <dir>/layers/graph; the tracked graph art
|
|
|
197618
197879
|
the working tree are not touched. The wiki and the memory are read from the project's
|
|
197619
197880
|
working copy, and layers.json marks how far that is from the PR head. The wiki refresh is a
|
|
197620
197881
|
dry run unless --write-wiki is given. A graph that is already built at this head and intact is
|
|
197621
|
-
kept (the wiki and the memory are still refreshed); --force rebuilds it
|
|
197882
|
+
kept (the wiki and the memory are still refreshed); --force rebuilds it. A graph that failed at
|
|
197883
|
+
this head is not rebuilt for 5 minutes after the failure; --force or a new head rebuilds it.`);
|
|
197622
197884
|
}
|
|
197623
197885
|
function wantsHelp2(args) {
|
|
197624
197886
|
return args.includes("--help") || args.includes("-h");
|
|
@@ -197649,7 +197911,8 @@ async function ensurePackageLayers(packageDir, options = {}) {
|
|
|
197649
197911
|
projectRoot,
|
|
197650
197912
|
packageDir,
|
|
197651
197913
|
...head === undefined ? {} : { prHead: head },
|
|
197652
|
-
...options.base === undefined ? {} : { base: options.base }
|
|
197914
|
+
...options.base === undefined ? {} : { base: options.base },
|
|
197915
|
+
...options.force === true ? { force: true } : {}
|
|
197653
197916
|
});
|
|
197654
197917
|
}
|
|
197655
197918
|
function print(layers, json) {
|
|
@@ -197708,7 +197971,7 @@ async function runLayers(args, deps) {
|
|
|
197708
197971
|
if (maxBytes !== undefined && (!Number.isInteger(maxBytes) || maxBytes < 256))
|
|
197709
197972
|
throw new Error("--max-bytes must be an integer of at least 256; a block with every list empty needs more than that, and the refusal names how much.");
|
|
197710
197973
|
const projectRoot = resolveProjectRoot2(process.cwd());
|
|
197711
|
-
await ensurePackageLayers(packageDir, { projectRoot });
|
|
197974
|
+
await ensurePackageLayers(packageDir, { projectRoot, force: rest.includes("--force") });
|
|
197712
197975
|
const block = await buildLayersBlock({ projectRoot, packageDir, files, ...maxBytes === undefined ? {} : { maxBytes } });
|
|
197713
197976
|
console.log(rest.includes("--json") ? JSON.stringify(block, null, 2) : layersBlockLines(block).join(`
|
|
197714
197977
|
`));
|
|
@@ -197727,7 +197990,7 @@ var init_review_layers = __esm(() => {
|
|
|
197727
197990
|
init_layers_payload();
|
|
197728
197991
|
LAYERS_REFRESH_FLAGS = ["--package", "--head", "--base", "--write-wiki", "--force", "--json", "--help", "-h"];
|
|
197729
197992
|
LAYERS_STATUS_FLAGS = ["--package", "--json", "--help", "-h"];
|
|
197730
|
-
LAYERS_BLOCK_FLAGS = ["--package", "--files", "--max-bytes", "--json", "--help", "-h"];
|
|
197993
|
+
LAYERS_BLOCK_FLAGS = ["--package", "--files", "--max-bytes", "--force", "--json", "--help", "-h"];
|
|
197731
197994
|
});
|
|
197732
197995
|
|
|
197733
197996
|
// src/commands/review-chunks.ts
|
|
@@ -199687,6 +199950,11 @@ function rejectUnknownFlags(args, allowed, usage) {
|
|
|
199687
199950
|
throw new Error(`Unknown option${unknown.length > 1 ? "s" : ""} for \`keryx review ${usage}\`: ${[...new Set(unknown)].join(", ")}. Accepted: ${allowed.join(", ")}. Refused rather than ignored \u2014 a flag that is silently dropped writes nothing and reports success.`);
|
|
199688
199951
|
}
|
|
199689
199952
|
}
|
|
199953
|
+
async function trackerPrLookup(ref) {
|
|
199954
|
+
if (!await githubAdapter.detect())
|
|
199955
|
+
return null;
|
|
199956
|
+
return githubAdapter.prStatus(ref);
|
|
199957
|
+
}
|
|
199690
199958
|
async function reviewCommand(args, seams) {
|
|
199691
199959
|
const command = args[0];
|
|
199692
199960
|
if (!command || command === "--help" || command === "-h") {
|
|
@@ -201667,8 +201935,11 @@ async function runComplete3(args, seams) {
|
|
|
201667
201935
|
manifest,
|
|
201668
201936
|
reviewNotes,
|
|
201669
201937
|
dispositions: tally,
|
|
201670
|
-
coverageWaiver
|
|
201671
|
-
|
|
201938
|
+
coverageWaiver,
|
|
201939
|
+
warnings
|
|
201940
|
+
} = await completeManagedReview(process.cwd(), ref, { dispositions, prLookup: seams?.prLookup ?? trackerPrLookup, ...waiver?.value === undefined ? {} : { waiveCoverage: waiver.value } });
|
|
201941
|
+
for (const warning of warnings)
|
|
201942
|
+
console.error(`warning: ${warning}`);
|
|
201672
201943
|
if (coverageWaiver !== undefined) {
|
|
201673
201944
|
const shown = coverageWaiver.files.slice(0, FIRST_FILES).join(", ");
|
|
201674
201945
|
console.log(`coverage waived by the operator (${coverageWaiver.time}): "${coverageWaiver.operatorQuote}"; ${coverageWaiver.files.length} file(s) not reviewed: ${shown}${coverageWaiver.files.length > FIRST_FILES ? ", \u2026" : ""}`);
|
|
@@ -201927,7 +202198,7 @@ Usage:
|
|
|
201927
202198
|
[--package <review-dir>] [--json | --brief] [--out <file>]
|
|
201928
202199
|
keryx review layers refresh --package <review-dir> [--head <sha>] [--base <ref>] [--write-wiki] [--force] [--json]
|
|
201929
202200
|
keryx review layers status --package <review-dir> [--json]
|
|
201930
|
-
keryx review layers block --package <review-dir> --files a,b [--max-bytes <n>] [--json]
|
|
202201
|
+
keryx review layers block --package <review-dir> --files a,b [--max-bytes <n>] [--force] [--json]
|
|
201931
202202
|
Graph, wiki and memory for one review; no model is called. An intact graph at
|
|
201932
202203
|
the same head is reused (--force rebuilds); a second refresh waits up to 16 min.
|
|
201933
202204
|
keryx review chunks plan|estimate|next|record|merge --package <review-dir>
|
|
@@ -208130,7 +208401,7 @@ var init_tools3 = __esm(() => {
|
|
|
208130
208401
|
|
|
208131
208402
|
// src/mcp/resources.ts
|
|
208132
208403
|
import path396 from "path";
|
|
208133
|
-
import { lstat as
|
|
208404
|
+
import { lstat as lstat23, readdir as readdir76, realpath as realpath28, stat as stat44 } from "fs/promises";
|
|
208134
208405
|
function mimeForPath(filePath) {
|
|
208135
208406
|
if (filePath.endsWith(".json") || filePath.endsWith(".jsonl")) {
|
|
208136
208407
|
return "application/json";
|
|
@@ -208153,7 +208424,7 @@ async function walkFiles(root, ownerRoot = root, ancestors = new Set) {
|
|
|
208153
208424
|
if (!await pathExists(root)) {
|
|
208154
208425
|
return [];
|
|
208155
208426
|
}
|
|
208156
|
-
const ownerInfo = await
|
|
208427
|
+
const ownerInfo = await lstat23(ownerRoot).catch(() => null);
|
|
208157
208428
|
if (!ownerInfo || !ownerInfo.isDirectory() || ownerInfo.isSymbolicLink())
|
|
208158
208429
|
return [];
|
|
208159
208430
|
const ownerReal = await realpath28(ownerRoot).catch(() => null);
|
|
@@ -224400,7 +224671,7 @@ function describeAvailability(entry, availability) {
|
|
|
224400
224671
|
const range = verdict.state === "in-range" ? "within the recorded range" : verdict.state === "below-min" ? `below the recorded minimum ${verdict.min} \u2014 parsing may drift` : verdict.state === "above-max" ? `above the recorded maximum ${verdict.max} \u2014 parsing may drift` : "version banner not recognised";
|
|
224401
224672
|
return `installed, ${version} (${range}); login not verified \u2014 keryx cannot know`;
|
|
224402
224673
|
}
|
|
224403
|
-
function
|
|
224674
|
+
function marker2(availability) {
|
|
224404
224675
|
if (availability.state === "available")
|
|
224405
224676
|
return style.cyan("\u25CF");
|
|
224406
224677
|
if (availability.state === "binary-missing")
|
|
@@ -224440,7 +224711,7 @@ function renderExternalAgents(rows, capability) {
|
|
|
224440
224711
|
lines.push(capability.available ? "capability: enabled" : `capability: unavailable \u2014 ${capability.reason ?? "no reason given"}`);
|
|
224441
224712
|
lines.push("");
|
|
224442
224713
|
for (const row of rows) {
|
|
224443
|
-
lines.push(` ${
|
|
224714
|
+
lines.push(` ${marker2(row.availability)} ${row.entry.id} ${row.entry.label}`);
|
|
224444
224715
|
lines.push(` ${describeAvailability(row.entry, row.availability)}`);
|
|
224445
224716
|
lines.push(` transport: ${transportOf(row.entry)} sandbox: ${row.entry.sandboxModes.join(", ")} streaming: ${row.entry.streamingInput} ` + `resumable: ${row.entry.resumable} reports cost: ${row.entry.reportsCost}`);
|
|
224446
224717
|
}
|
|
@@ -230794,7 +231065,7 @@ var init_types13 = __esm(() => {
|
|
|
230794
231065
|
});
|
|
230795
231066
|
|
|
230796
231067
|
// src/bundle/paths.ts
|
|
230797
|
-
import { lstat as
|
|
231068
|
+
import { lstat as lstat24, readFile as readFile214 } from "fs/promises";
|
|
230798
231069
|
import path423 from "path";
|
|
230799
231070
|
function scopeRoot(scope, ctx) {
|
|
230800
231071
|
if (scope === "user") {
|
|
@@ -230988,7 +231259,7 @@ async function resolveContainedPathForWrite(root, relPath) {
|
|
|
230988
231259
|
async function refuseSymlinkChain(root, relPath) {
|
|
230989
231260
|
const rootResolved = path423.resolve(root);
|
|
230990
231261
|
try {
|
|
230991
|
-
const rootStat = await
|
|
231262
|
+
const rootStat = await lstat24(rootResolved);
|
|
230992
231263
|
if (rootStat.isSymbolicLink()) {
|
|
230993
231264
|
return {
|
|
230994
231265
|
ok: false,
|
|
@@ -231001,7 +231272,7 @@ async function refuseSymlinkChain(root, relPath) {
|
|
|
231001
231272
|
for (const segment of segments) {
|
|
231002
231273
|
current = path423.join(current, segment);
|
|
231003
231274
|
try {
|
|
231004
|
-
const stat = await
|
|
231275
|
+
const stat = await lstat24(current);
|
|
231005
231276
|
if (stat.isSymbolicLink()) {
|
|
231006
231277
|
return {
|
|
231007
231278
|
ok: false,
|
|
@@ -231051,7 +231322,7 @@ var init_paths5 = __esm(() => {
|
|
|
231051
231322
|
});
|
|
231052
231323
|
|
|
231053
231324
|
// src/bundle/archive.ts
|
|
231054
|
-
import { readdir as readdir79, readFile as readFile215, lstat as
|
|
231325
|
+
import { readdir as readdir79, readFile as readFile215, lstat as lstat25 } from "fs/promises";
|
|
231055
231326
|
import path424 from "path";
|
|
231056
231327
|
import { gzipSync, gunzipSync } from "zlib";
|
|
231057
231328
|
function resolveLimits(limits) {
|
|
@@ -231259,7 +231530,7 @@ async function openBundle(bundlePath, limits) {
|
|
|
231259
231530
|
const resolved = resolveLimits(limits);
|
|
231260
231531
|
let stat;
|
|
231261
231532
|
try {
|
|
231262
|
-
stat = await
|
|
231533
|
+
stat = await lstat25(bundlePath);
|
|
231263
231534
|
} catch {
|
|
231264
231535
|
return { ok: false, refusal: { reason: BUNDLE_REFUSAL.notABundle, message: `no such path: ${bundlePath}` } };
|
|
231265
231536
|
}
|
|
@@ -231273,7 +231544,7 @@ async function openBundle(bundlePath, limits) {
|
|
|
231273
231544
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
231274
231545
|
const abs = path424.join(dir, entry.name);
|
|
231275
231546
|
const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
|
|
231276
|
-
const entryStat = await
|
|
231547
|
+
const entryStat = await lstat25(abs);
|
|
231277
231548
|
if (entryStat.isSymbolicLink()) {
|
|
231278
231549
|
return { reason: BUNDLE_REFUSAL.symlinkRefused, path: rel, message: `${rel} is a symlink; bundles may not contain symlinks` };
|
|
231279
231550
|
}
|
|
@@ -232148,7 +232419,7 @@ var init_learned_pattern_schema = __esm(() => {
|
|
|
232148
232419
|
|
|
232149
232420
|
// src/bundle/export.ts
|
|
232150
232421
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
232151
|
-
import { mkdir as mkdir89, readdir as readdir80, readFile as readFile216, writeFile as writeFile63, lstat as
|
|
232422
|
+
import { mkdir as mkdir89, readdir as readdir80, readFile as readFile216, writeFile as writeFile63, lstat as lstat26 } from "fs/promises";
|
|
232152
232423
|
import { existsSync as existsSync78 } from "fs";
|
|
232153
232424
|
import path425 from "path";
|
|
232154
232425
|
function globToRegExp6(glob) {
|
|
@@ -232235,7 +232506,7 @@ async function walkFiles2(dir, relPrefix, out, skipped) {
|
|
|
232235
232506
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
232236
232507
|
const abs = path425.join(dir, entry.name);
|
|
232237
232508
|
const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
|
|
232238
|
-
const st = await
|
|
232509
|
+
const st = await lstat26(abs);
|
|
232239
232510
|
if (st.isSymbolicLink()) {
|
|
232240
232511
|
skipped.push({ path: rel, reason: "symlink" });
|
|
232241
232512
|
continue;
|
|
@@ -232283,7 +232554,7 @@ async function collectAgents(root, skipped) {
|
|
|
232283
232554
|
const candidates = [];
|
|
232284
232555
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
232285
232556
|
const abs = path425.join(base, entry.name);
|
|
232286
|
-
const st = await
|
|
232557
|
+
const st = await lstat26(abs);
|
|
232287
232558
|
if (st.isSymbolicLink()) {
|
|
232288
232559
|
skipped.push({ path: `agents/${entry.name}`, reason: "symlink" });
|
|
232289
232560
|
continue;
|
|
@@ -232308,7 +232579,7 @@ async function collectMemory(root, skipped) {
|
|
|
232308
232579
|
}
|
|
232309
232580
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
232310
232581
|
const abs = path425.join(base, entry.name);
|
|
232311
|
-
const st = await
|
|
232582
|
+
const st = await lstat26(abs);
|
|
232312
232583
|
if (st.isSymbolicLink()) {
|
|
232313
232584
|
skipped.push({ path: `memory/${folder}/${entry.name}`, reason: "symlink" });
|
|
232314
232585
|
continue;
|
|
@@ -232324,7 +232595,7 @@ async function collectHookConfig(root) {
|
|
|
232324
232595
|
const abs = path425.join(root, "hooks.json");
|
|
232325
232596
|
if (!existsSync78(abs))
|
|
232326
232597
|
return [];
|
|
232327
|
-
const st = await
|
|
232598
|
+
const st = await lstat26(abs);
|
|
232328
232599
|
if (st.isSymbolicLink() || !st.isFile())
|
|
232329
232600
|
return [];
|
|
232330
232601
|
return [{ bundlePath: "hooks.json", kind: "hook-config", absolutePath: abs }];
|
|
@@ -232705,7 +232976,7 @@ var init_applied_state = __esm(() => {
|
|
|
232705
232976
|
});
|
|
232706
232977
|
|
|
232707
232978
|
// src/lib/private-dir.ts
|
|
232708
|
-
import { lstat as
|
|
232979
|
+
import { lstat as lstat27, mkdir as mkdir90, open as open12, readFile as readFile218 } from "fs/promises";
|
|
232709
232980
|
import path427 from "path";
|
|
232710
232981
|
async function checkPrivateDirGitignore(dir, root) {
|
|
232711
232982
|
if (root !== undefined) {
|
|
@@ -232724,7 +232995,7 @@ async function checkPrivateDirGitignore(dir, root) {
|
|
|
232724
232995
|
}
|
|
232725
232996
|
let dirStats;
|
|
232726
232997
|
try {
|
|
232727
|
-
dirStats = await
|
|
232998
|
+
dirStats = await lstat27(dir);
|
|
232728
232999
|
} catch (error) {
|
|
232729
233000
|
if (isNotFound(error)) {
|
|
232730
233001
|
return { ok: true, action: "create" };
|
|
@@ -232745,7 +233016,7 @@ async function checkPrivateDirGitignore(dir, root) {
|
|
|
232745
233016
|
const gitignorePath = path427.join(dir, ".gitignore");
|
|
232746
233017
|
let stats;
|
|
232747
233018
|
try {
|
|
232748
|
-
stats = await
|
|
233019
|
+
stats = await lstat27(gitignorePath);
|
|
232749
233020
|
} catch (error) {
|
|
232750
233021
|
if (isNotFound(error)) {
|
|
232751
233022
|
return { ok: true, action: "create" };
|