@mrciphersmith/keryx 0.3.89 → 0.3.90
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
CHANGED
|
@@ -21105,7 +21105,7 @@ var package_default;
|
|
|
21105
21105
|
var init_package = __esm(() => {
|
|
21106
21106
|
package_default = {
|
|
21107
21107
|
name: "@mrciphersmith/keryx",
|
|
21108
|
-
version: "0.3.
|
|
21108
|
+
version: "0.3.90",
|
|
21109
21109
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
21110
21110
|
private: false,
|
|
21111
21111
|
publishConfig: {
|
|
@@ -98346,7 +98346,7 @@ var init_registry3 = __esm(() => {
|
|
|
98346
98346
|
// src/harness/tool/builtin/spawn-subagent-tool.ts
|
|
98347
98347
|
import { createHash as createHash64, randomUUID as randomUUID26 } from "crypto";
|
|
98348
98348
|
import { execFile as execFile7 } from "child_process";
|
|
98349
|
-
import { lstat as lstat15, mkdtemp as mkdtemp2, readFile as readFile108, realpath as realpath19, rm as rm15, stat as stat27 } from "fs/promises";
|
|
98349
|
+
import { lstat as lstat15, mkdir as mkdir56, mkdtemp as mkdtemp2, readFile as readFile108, realpath as realpath19, rm as rm15, stat as stat27, writeFile as writeFile36 } from "fs/promises";
|
|
98350
98350
|
import { tmpdir as tmpdir6 } from "os";
|
|
98351
98351
|
import path222 from "path";
|
|
98352
98352
|
import { promisify as promisify5 } from "util";
|
|
@@ -98413,6 +98413,57 @@ ${blocks.join(`
|
|
|
98413
98413
|
|
|
98414
98414
|
`)}` };
|
|
98415
98415
|
}
|
|
98416
|
+
async function resolveSaveResultPath(root, target) {
|
|
98417
|
+
if (target === undefined)
|
|
98418
|
+
return { ok: true, abs: undefined };
|
|
98419
|
+
if (typeof target !== "string" || target.trim() === "") {
|
|
98420
|
+
return { ok: false, reason: "spawn_subagent save_result_to must be a non-empty project-relative path" };
|
|
98421
|
+
}
|
|
98422
|
+
const abs = confineToRoot(root, target);
|
|
98423
|
+
if (abs === null)
|
|
98424
|
+
return { ok: false, reason: `spawn_subagent save_result_to path escapes the project root: ${target}` };
|
|
98425
|
+
if (CONTEXT_FILE_DENYLIST.test(path222.relative(root, abs).split(path222.sep).join("/"))) {
|
|
98426
|
+
return { ok: false, reason: `spawn_subagent save_result_to refuses a credential or VCS-internal path: ${target}` };
|
|
98427
|
+
}
|
|
98428
|
+
try {
|
|
98429
|
+
const realRoot = await realpath19(root);
|
|
98430
|
+
let probe = abs;
|
|
98431
|
+
for (;; ) {
|
|
98432
|
+
try {
|
|
98433
|
+
const real = await realpath19(probe);
|
|
98434
|
+
const rel = path222.relative(realRoot, real);
|
|
98435
|
+
if (rel.startsWith("..") || path222.isAbsolute(rel)) {
|
|
98436
|
+
return { ok: false, reason: `spawn_subagent save_result_to resolves outside the project root: ${target}` };
|
|
98437
|
+
}
|
|
98438
|
+
if (probe === abs && !(await stat27(abs)).isFile()) {
|
|
98439
|
+
return { ok: false, reason: `spawn_subagent save_result_to is not a regular file: ${target}` };
|
|
98440
|
+
}
|
|
98441
|
+
break;
|
|
98442
|
+
} catch (err) {
|
|
98443
|
+
if (err.code !== "ENOENT")
|
|
98444
|
+
throw err;
|
|
98445
|
+
const parent = path222.dirname(probe);
|
|
98446
|
+
if (parent === probe)
|
|
98447
|
+
throw err;
|
|
98448
|
+
probe = parent;
|
|
98449
|
+
}
|
|
98450
|
+
}
|
|
98451
|
+
} catch {
|
|
98452
|
+
return { ok: false, reason: `spawn_subagent save_result_to cannot be used: ${target}` };
|
|
98453
|
+
}
|
|
98454
|
+
return { ok: true, abs };
|
|
98455
|
+
}
|
|
98456
|
+
async function saveChildResult(abs, text) {
|
|
98457
|
+
try {
|
|
98458
|
+
await mkdir56(path222.dirname(abs), { recursive: true });
|
|
98459
|
+
await writeFile36(abs, text.endsWith(`
|
|
98460
|
+
`) ? text : `${text}
|
|
98461
|
+
`, "utf8");
|
|
98462
|
+
return;
|
|
98463
|
+
} catch (err) {
|
|
98464
|
+
return err.message;
|
|
98465
|
+
}
|
|
98466
|
+
}
|
|
98416
98467
|
function resolveSubagentMaxToolCalls(env = process.env) {
|
|
98417
98468
|
const n = parseIntEnvVar(env, ENV_SUBAGENT_MAX_TOOL_CALLS);
|
|
98418
98469
|
return n === undefined || n <= 0 ? undefined : n;
|
|
@@ -98618,7 +98669,7 @@ function createSpawnSubagentTool(deps) {
|
|
|
98618
98669
|
return {
|
|
98619
98670
|
definition: {
|
|
98620
98671
|
name: "spawn_subagent",
|
|
98621
|
-
description: "Spawn a bounded subagent to work on a focused subtask in parallel-safe isolation " + "(MAE multi-agent). Use for independent investigations, reviews, or research while " + "you continue the main plan. Input: { task: string, mode?: 'read_only'|'general', " + "label?: string, max_tool_calls?: integer, max_rounds?: integer, context_files?: string[] }. " + "max_tool_calls is ADVISORY: it never stops the child, it only sets when the child is warned " + "(from 80% of it) to return its result; a hard tool-call cap exists only when the operator " + `configures ${ENV_SUBAGENT_MAX_TOOL_CALLS}. max_rounds limits model rounds (default 40, capped ` + "at 200). A child that hits its round budget or the operator's call cap gets one final round to " + "submit a partial result, and the output's first line is then 'status: BudgetExhausted (...)'. " + "External runtimes cannot accept these limits. " + "Default mode is read_only (no shell). " + "Returns the child's summary. Prefer one clear task per spawn; do not spawn for " + "trivial questions (answer yourself). Optionally accepts a 'model_tier' " + "(light|standard|deep) to size the child's model against your own, and a 'runtime' " + "block to delegate the child to an external vendor coding CLI instead of running it " + "in-process. Optional 'cwd' runs the child's tools against a different directory than " + "yours (e.g. a review worktree checked out at a PR head) \u2014 accepted only when it is your " + "own project root, a descendant of it, or one of its git worktrees; a relative path " + "resolves against your own cwd. Not supported for external (runtime.kind='external') children.",
|
|
98672
|
+
description: "Spawn a bounded subagent to work on a focused subtask in parallel-safe isolation " + "(MAE multi-agent). Use for independent investigations, reviews, or research while " + "you continue the main plan. Input: { task: string, mode?: 'read_only'|'general', " + "label?: string, max_tool_calls?: integer, max_rounds?: integer, context_files?: string[], save_result_to?: string }. " + "max_tool_calls is ADVISORY: it never stops the child, it only sets when the child is warned " + "(from 80% of it) to return its result; a hard tool-call cap exists only when the operator " + `configures ${ENV_SUBAGENT_MAX_TOOL_CALLS}. max_rounds limits model rounds (default 40, capped ` + "at 200). A child that hits its round budget or the operator's call cap gets one final round to " + "submit a partial result, and the output's first line is then 'status: BudgetExhausted (...)'. " + "External runtimes cannot accept these limits. " + "Default mode is read_only (no shell). " + "Returns the child's summary. Prefer one clear task per spawn; do not spawn for " + "trivial questions (answer yourself). Optionally accepts a 'model_tier' " + "(light|standard|deep) to size the child's model against your own, and a 'runtime' " + "block to delegate the child to an external vendor coding CLI instead of running it " + "in-process. Optional 'cwd' runs the child's tools against a different directory than " + "yours (e.g. a review worktree checked out at a PR head) \u2014 accepted only when it is your " + "own project root, a descendant of it, or one of its git worktrees; a relative path " + "resolves against your own cwd. Not supported for external (runtime.kind='external') children.",
|
|
98622
98673
|
inputSchema: {
|
|
98623
98674
|
type: "object",
|
|
98624
98675
|
properties: {
|
|
@@ -98640,6 +98691,10 @@ function createSpawnSubagentTool(deps) {
|
|
|
98640
98691
|
items: { type: "string" },
|
|
98641
98692
|
description: "Project-relative files (e.g. review slices) the host copies into the child's task, so " + "you do not paste them yourself. Resolved against your own project root (not 'cwd'); native " + "children only; credential files (.env*, keys) are refused. Up to 40 files and 400000 bytes in total."
|
|
98642
98693
|
},
|
|
98694
|
+
save_result_to: {
|
|
98695
|
+
type: "string",
|
|
98696
|
+
description: "Project-relative file the host writes the child's complete final text to when it ends, " + "so the result survives your own context (e.g. .metaproject/data/review/raw/<reviewer>.txt). " + "Native children only; credential and VCS paths are refused."
|
|
98697
|
+
},
|
|
98643
98698
|
max_rounds: {
|
|
98644
98699
|
type: "integer",
|
|
98645
98700
|
minimum: 1,
|
|
@@ -98718,6 +98773,17 @@ function createSpawnSubagentTool(deps) {
|
|
|
98718
98773
|
if (!attached.ok) {
|
|
98719
98774
|
return { status: "Error", output: attached.reason, isError: true };
|
|
98720
98775
|
}
|
|
98776
|
+
if (input.save_result_to !== undefined && isExternalRuntimeRequest) {
|
|
98777
|
+
return {
|
|
98778
|
+
status: "Error",
|
|
98779
|
+
output: "spawn_subagent save_result_to is not supported for external (runtime.kind='external') children.",
|
|
98780
|
+
isError: true
|
|
98781
|
+
};
|
|
98782
|
+
}
|
|
98783
|
+
const saveTarget = await resolveSaveResultPath(deps.cwd, input.save_result_to);
|
|
98784
|
+
if (!saveTarget.ok) {
|
|
98785
|
+
return { status: "Error", output: saveTarget.reason, isError: true };
|
|
98786
|
+
}
|
|
98721
98787
|
const task = taskText;
|
|
98722
98788
|
const labelRaw = typeof input.label === "string" ? input.label.trim() : "";
|
|
98723
98789
|
childSeq += 1;
|
|
@@ -99191,9 +99257,11 @@ ${boundSummary(foldedPartial)}` : ""),
|
|
|
99191
99257
|
` + `MAE reservation: rounds\u2264${maxRounds} ` + (configuredMaxToolCalls === undefined ? "" : `calls\u2264${configuredMaxToolCalls} `) + (advisoryToolCalls === undefined ? "" : `calls~${advisoryToolCalls}(advisory) `) + `runtime\u2264${spawned.reservation.maxRuntimeMs}ms children=${ledger.childCount}
|
|
99192
99258
|
` + (tierRecord === undefined ? "" : `${tierRecord}
|
|
99193
99259
|
`);
|
|
99260
|
+
const saveNote = saveTarget.abs === undefined ? "" : `
|
|
99261
|
+
[full result ${await saveChildResult(saveTarget.abs, raw) === undefined ? "saved to" : "could NOT be saved to"} ${String(input.save_result_to)}]`;
|
|
99194
99262
|
if (status === "Completed") {
|
|
99195
99263
|
return { status, isError, output: `${header}--- summary ---
|
|
99196
|
-
${boundSummary(folded.text)}` };
|
|
99264
|
+
${boundSummary(folded.text)}${saveNote}` };
|
|
99197
99265
|
}
|
|
99198
99266
|
const statusLine = formatStoppedStatusLine(status, turnResult);
|
|
99199
99267
|
const submitted = turnResult?.submittedResult;
|
|
@@ -99208,7 +99276,7 @@ ${raw}`).text;
|
|
|
99208
99276
|
status,
|
|
99209
99277
|
isError,
|
|
99210
99278
|
output: `${statusLine}
|
|
99211
|
-
${header}${boundedResult}`,
|
|
99279
|
+
${header}${boundedResult}${saveNote}`,
|
|
99212
99280
|
partial: boundedResult
|
|
99213
99281
|
};
|
|
99214
99282
|
} catch (cause) {
|
|
@@ -100926,7 +100994,7 @@ var init_dispatch2 = __esm(() => {
|
|
|
100926
100994
|
|
|
100927
100995
|
// src/harness/external/acp-fs.ts
|
|
100928
100996
|
import { constants as constants2, realpathSync as realpathSync15, statSync as statSync12 } from "fs";
|
|
100929
|
-
import { mkdir as
|
|
100997
|
+
import { mkdir as mkdir57, open as open10, readFile as readFile109 } from "fs/promises";
|
|
100930
100998
|
import path225 from "path";
|
|
100931
100999
|
function refusedMethodError(method, reason) {
|
|
100932
101000
|
return new AcpError(JSON_RPC_ERROR_CODES.methodNotFound, `${method} refused: ${reason}`, { reason });
|
|
@@ -100985,7 +101053,7 @@ async function writeTextFileInWorktree(worktree, target, content, requested, hoo
|
|
|
100985
101053
|
}
|
|
100986
101054
|
await hooks.beforeWrite?.();
|
|
100987
101055
|
const parent = path225.dirname(target);
|
|
100988
|
-
await
|
|
101056
|
+
await mkdir57(parent, { recursive: true });
|
|
100989
101057
|
const rootReal = realpathSync15(worktree);
|
|
100990
101058
|
const parentReal = realpathSync15(parent);
|
|
100991
101059
|
const rel = path225.relative(rootReal, parentReal);
|
|
@@ -103087,7 +103155,7 @@ var init_codec2 = __esm(() => {
|
|
|
103087
103155
|
});
|
|
103088
103156
|
|
|
103089
103157
|
// src/harness/external/runtime.ts
|
|
103090
|
-
import { mkdtemp as mkdtemp4, rm as rm17, writeFile as
|
|
103158
|
+
import { mkdtemp as mkdtemp4, rm as rm17, writeFile as writeFile37 } from "fs/promises";
|
|
103091
103159
|
import { tmpdir as tmpdir8 } from "os";
|
|
103092
103160
|
import path227 from "path";
|
|
103093
103161
|
function refuse2(status, output) {
|
|
@@ -103100,7 +103168,7 @@ async function prepareResultSchema() {
|
|
|
103100
103168
|
const schemaText = JSON.stringify(schema, null, 2);
|
|
103101
103169
|
schemaDir = await mkdtemp4(path227.join(tmpdir8(), "keryx-external-result-schema-"));
|
|
103102
103170
|
const schemaPath = path227.join(schemaDir, "subagent-result.schema.json");
|
|
103103
|
-
await
|
|
103171
|
+
await writeFile37(schemaPath, schemaText, "utf8");
|
|
103104
103172
|
return { ok: true, schema, schemaText, schemaPath, schemaDir };
|
|
103105
103173
|
} catch (error) {
|
|
103106
103174
|
if (schemaDir !== undefined) {
|
|
@@ -103209,7 +103277,7 @@ async function runExternalChild(input, deps) {
|
|
|
103209
103277
|
if (codexStrict) {
|
|
103210
103278
|
resultSchemaPathForCodec = path227.join(schemaDir, STRICT_SCHEMA_FILE);
|
|
103211
103279
|
try {
|
|
103212
|
-
await
|
|
103280
|
+
await writeFile37(resultSchemaPathForCodec, JSON.stringify(toStrictOutputSchema(bundledResultSchema)), "utf8");
|
|
103213
103281
|
} catch (error) {
|
|
103214
103282
|
await rm17(schemaDir, { recursive: true, force: true }).catch(() => {
|
|
103215
103283
|
return;
|
|
@@ -103475,7 +103543,7 @@ var init_runtime2 = __esm(() => {
|
|
|
103475
103543
|
// src/harness/run-external-factory.ts
|
|
103476
103544
|
import { randomUUID as randomUUID27 } from "crypto";
|
|
103477
103545
|
import { execFile as execFile10 } from "child_process";
|
|
103478
|
-
import { mkdir as
|
|
103546
|
+
import { mkdir as mkdir58 } from "fs/promises";
|
|
103479
103547
|
import { tmpdir as tmpdir9 } from "os";
|
|
103480
103548
|
import path228 from "path";
|
|
103481
103549
|
import { promisify as promisify8 } from "util";
|
|
@@ -103505,7 +103573,7 @@ async function defaultWorkingDiff(cwd) {
|
|
|
103505
103573
|
function ensuringParentDir(port, worktreesDir) {
|
|
103506
103574
|
return {
|
|
103507
103575
|
async create(worktreeId) {
|
|
103508
|
-
await
|
|
103576
|
+
await mkdir58(worktreesDir, { recursive: true });
|
|
103509
103577
|
return port.create(worktreeId);
|
|
103510
103578
|
},
|
|
103511
103579
|
remove: (worktreeId) => port.remove(worktreeId),
|
|
@@ -117740,7 +117808,7 @@ var init_repair = __esm(() => {
|
|
|
117740
117808
|
});
|
|
117741
117809
|
|
|
117742
117810
|
// src/review/managed.ts
|
|
117743
|
-
import { mkdir as
|
|
117811
|
+
import { mkdir as mkdir59, readFile as readFile121, readdir as readdir39, realpath as realpath20, rm as rm18, stat as stat29 } from "fs/promises";
|
|
117744
117812
|
import path252 from "path";
|
|
117745
117813
|
function reviewsRoot(cwd) {
|
|
117746
117814
|
return path252.join(cwd, ".metaproject", "reviews");
|
|
@@ -117876,7 +117944,7 @@ async function createManagedReviewPackage(input) {
|
|
|
117876
117944
|
if (contractErrors.length > 0) {
|
|
117877
117945
|
throw new Error(`Refusing to record findings that do not satisfy review-finding.schema.json: ${contractErrors.map((error) => `${error.path} ${error.message}`).join("; ")}`);
|
|
117878
117946
|
}
|
|
117879
|
-
await
|
|
117947
|
+
await mkdir59(packageDir, { recursive: true });
|
|
117880
117948
|
await writeFileAtomic(path252.join(packageDir, "research.json"), `${JSON.stringify(input.research ?? PENDING_RESEARCH, null, 2)}
|
|
117881
117949
|
`);
|
|
117882
117950
|
await writeFileAtomic(path252.join(packageDir, "manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
@@ -125399,7 +125467,7 @@ var init_aggregate = __esm(() => {
|
|
|
125399
125467
|
});
|
|
125400
125468
|
|
|
125401
125469
|
// src/governance/report.ts
|
|
125402
|
-
import { mkdir as
|
|
125470
|
+
import { mkdir as mkdir60 } from "fs/promises";
|
|
125403
125471
|
import path261 from "path";
|
|
125404
125472
|
function governanceDataRoot(cwd) {
|
|
125405
125473
|
return path261.join(cwd, ".metaproject", "data", "governance");
|
|
@@ -125585,7 +125653,7 @@ function renderTriggerSpendLine(spend) {
|
|
|
125585
125653
|
}
|
|
125586
125654
|
async function writeGovernanceArtifacts(cwd, report) {
|
|
125587
125655
|
const { markdown, json } = artifactPaths(cwd);
|
|
125588
|
-
await
|
|
125656
|
+
await mkdir60(path261.dirname(markdown), { recursive: true });
|
|
125589
125657
|
await writeFileAtomic(markdown, renderGovernanceMarkdown(report));
|
|
125590
125658
|
await writeFileAtomic(json, `${JSON.stringify(report, null, 2)}
|
|
125591
125659
|
`);
|
|
@@ -128773,7 +128841,7 @@ var init_granted_json_ids = __esm(() => {
|
|
|
128773
128841
|
// src/commands/trigger-agent-task.ts
|
|
128774
128842
|
import { execFile as execFile11 } from "child_process";
|
|
128775
128843
|
import { randomUUID as randomUUID35 } from "crypto";
|
|
128776
|
-
import { mkdtemp as mkdtemp5, mkdir as
|
|
128844
|
+
import { mkdtemp as mkdtemp5, mkdir as mkdir61, readdir as readdir42, rm as rm19, writeFile as writeFile38 } from "fs/promises";
|
|
128777
128845
|
import { homedir as homedir12, tmpdir as tmpdir11 } from "os";
|
|
128778
128846
|
import path268 from "path";
|
|
128779
128847
|
function scrubGrantedOutput(text, env, secrets = [], json = false) {
|
|
@@ -128944,9 +129012,9 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
128944
129012
|
const workdir = path268.join(scratch, "work");
|
|
128945
129013
|
const scratchHome = path268.join(scratch, "home");
|
|
128946
129014
|
const grantedCwd = path268.join(scratch, "granted-cwd");
|
|
128947
|
-
await
|
|
128948
|
-
await
|
|
128949
|
-
await
|
|
129015
|
+
await mkdir61(workdir, { recursive: true });
|
|
129016
|
+
await mkdir61(scratchHome, { recursive: true });
|
|
129017
|
+
await mkdir61(grantedCwd, { recursive: true, mode: 448 });
|
|
128950
129018
|
const cleanup = async () => {
|
|
128951
129019
|
await rm19(scratch, { recursive: true, force: true }).catch(() => {});
|
|
128952
129020
|
};
|
|
@@ -129114,9 +129182,9 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
|
|
|
129114
129182
|
try {
|
|
129115
129183
|
await ensureTriggerDataIgnored(projectRoot);
|
|
129116
129184
|
const dir = path268.join(triggerReportsDir(projectRoot), entry.name);
|
|
129117
|
-
await
|
|
129185
|
+
await mkdir61(dir, { recursive: true });
|
|
129118
129186
|
const file = path268.join(dir, `${runId}.md`);
|
|
129119
|
-
await
|
|
129187
|
+
await writeFile38(file, renderReport3({ entry, action, runId, at: now().toISOString(), outcome, why, cost, grantedCalls, denials, sandboxNote, summary, networkDecisions }), "utf8");
|
|
129120
129188
|
await pruneReports(dir, action.report.keep);
|
|
129121
129189
|
reportPath = path268.relative(projectRoot, file);
|
|
129122
129190
|
} catch (error) {
|
|
@@ -129663,18 +129731,18 @@ var init_types10 = __esm(() => {
|
|
|
129663
129731
|
|
|
129664
129732
|
// src/intake/store.ts
|
|
129665
129733
|
import { createHash as createHash70 } from "crypto";
|
|
129666
|
-
import { appendFile as appendFile14, mkdir as
|
|
129734
|
+
import { appendFile as appendFile14, mkdir as mkdir62, readFile as readFile128, writeFile as writeFile39 } from "fs/promises";
|
|
129667
129735
|
import path272 from "path";
|
|
129668
129736
|
async function ensureIntakeDataIgnored(root) {
|
|
129669
129737
|
const dir = intakeDataDir(root);
|
|
129670
|
-
await
|
|
129738
|
+
await mkdir62(dir, { recursive: true });
|
|
129671
129739
|
const file = path272.join(dir, ".gitignore");
|
|
129672
129740
|
try {
|
|
129673
129741
|
await readFile128(file, "utf8");
|
|
129674
129742
|
} catch (error) {
|
|
129675
129743
|
if (!isNotFound(error))
|
|
129676
129744
|
throw error;
|
|
129677
|
-
await
|
|
129745
|
+
await writeFile39(file, `# Work intake: the card registry, the ledger and the poll state. Never committed.
|
|
129678
129746
|
*
|
|
129679
129747
|
!.gitignore
|
|
129680
129748
|
`, "utf8");
|
|
@@ -130815,7 +130883,7 @@ var init_events = __esm(() => {
|
|
|
130815
130883
|
|
|
130816
130884
|
// src/intake/poll.ts
|
|
130817
130885
|
import { randomUUID as randomUUID36 } from "crypto";
|
|
130818
|
-
import { mkdir as
|
|
130886
|
+
import { mkdir as mkdir63, mkdtemp as mkdtemp6, rm as rm21, writeFile as writeFile40 } from "fs/promises";
|
|
130819
130887
|
import path275 from "path";
|
|
130820
130888
|
function intakePollDue(config, state, now) {
|
|
130821
130889
|
if (!config.enabled || state.paused || config.repos.length === 0)
|
|
@@ -130924,7 +130992,7 @@ async function pollLocked(root, config, deps, runId, now) {
|
|
|
130924
130992
|
try {
|
|
130925
130993
|
if (scratch !== undefined) {
|
|
130926
130994
|
const cwd = path275.join(scratch, "granted-cwd");
|
|
130927
|
-
await
|
|
130995
|
+
await mkdir63(cwd, { recursive: true, mode: 448 });
|
|
130928
130996
|
const gh = await verifyGh(root, env);
|
|
130929
130997
|
if (!gh.ok)
|
|
130930
130998
|
failures.push({ source: "gh", detail: `refusing to run: ${gh.reason}` });
|
|
@@ -131113,9 +131181,9 @@ async function writeReport2(root, r) {
|
|
|
131113
131181
|
try {
|
|
131114
131182
|
await ensureIntakeDataIgnored(root);
|
|
131115
131183
|
const dir = intakeReportsDir(root);
|
|
131116
|
-
await
|
|
131184
|
+
await mkdir63(dir, { recursive: true });
|
|
131117
131185
|
const file = path275.join(dir, `${r.runId}.md`);
|
|
131118
|
-
await
|
|
131186
|
+
await writeFile40(file, scrubGrantedOutput(lines.join(`
|
|
131119
131187
|
`), r.env), "utf8");
|
|
131120
131188
|
await pruneReports(dir, REPORTS_KEEP);
|
|
131121
131189
|
return path275.relative(root, file);
|
|
@@ -132412,7 +132480,7 @@ var init_decisions_surface = __esm(() => {
|
|
|
132412
132480
|
});
|
|
132413
132481
|
|
|
132414
132482
|
// src/scheduler/research-sync-job.ts
|
|
132415
|
-
import { mkdir as
|
|
132483
|
+
import { mkdir as mkdir64, readFile as readFile131, readdir as readdir44, rm as rm22, writeFile as writeFile41 } from "fs/promises";
|
|
132416
132484
|
import path276 from "path";
|
|
132417
132485
|
function researchSyncDataDir(projectRoot) {
|
|
132418
132486
|
return path276.join(projectRoot, ".metaproject", "data", "research-sync");
|
|
@@ -132451,14 +132519,14 @@ async function writeFired2(projectRoot, state) {
|
|
|
132451
132519
|
}
|
|
132452
132520
|
async function ensureIgnored(projectRoot) {
|
|
132453
132521
|
const dir = researchSyncDataDir(projectRoot);
|
|
132454
|
-
await
|
|
132522
|
+
await mkdir64(dir, { recursive: true });
|
|
132455
132523
|
const file = path276.join(dir, ".gitignore");
|
|
132456
132524
|
try {
|
|
132457
132525
|
await readFile131(file, "utf8");
|
|
132458
132526
|
} catch (error) {
|
|
132459
132527
|
if (!isNotFound(error))
|
|
132460
132528
|
throw error;
|
|
132461
|
-
await
|
|
132529
|
+
await writeFile41(file, `# Daily research sync: the entry and the day it last ran. Never staged.
|
|
132462
132530
|
*
|
|
132463
132531
|
!.gitignore
|
|
132464
132532
|
`, "utf8");
|
|
@@ -132490,7 +132558,7 @@ async function claimFiles(projectRoot) {
|
|
|
132490
132558
|
}
|
|
132491
132559
|
async function claimDay(projectRoot, day, at) {
|
|
132492
132560
|
try {
|
|
132493
|
-
await
|
|
132561
|
+
await writeFile41(researchSyncClaimPath(projectRoot, day), `${JSON.stringify({ pid: process.pid, claimedAt: at.toISOString() })}
|
|
132494
132562
|
`, { flag: "wx" });
|
|
132495
132563
|
} catch (error) {
|
|
132496
132564
|
if (error.code === "EEXIST")
|
|
@@ -132688,7 +132756,7 @@ var STATUS_TITLE = "# \u0422\u0435\u043A\u0443\u0449\u0435\u0435 \u0441\u043E\u0
|
|
|
132688
132756
|
|
|
132689
132757
|
// src/commands/research-sync.ts
|
|
132690
132758
|
import { execFile as execFile12 } from "child_process";
|
|
132691
|
-
import { mkdir as
|
|
132759
|
+
import { mkdir as mkdir65, mkdtemp as mkdtemp7, readFile as readFile132, rename as rename12, rm as rm23, writeFile as writeFile42 } from "fs/promises";
|
|
132692
132760
|
import { tmpdir as tmpdir12 } from "os";
|
|
132693
132761
|
import path277 from "path";
|
|
132694
132762
|
import { promisify as promisify9 } from "util";
|
|
@@ -132723,7 +132791,7 @@ async function runCounts(root) {
|
|
|
132723
132791
|
const gitDir = (await tool("git", ["rev-parse", "--absolute-git-dir"], { cwd: root }, "git rev-parse")).trim();
|
|
132724
132792
|
const archive = path277.join(work, "flows.tar");
|
|
132725
132793
|
const tree = path277.join(work, "tree");
|
|
132726
|
-
await
|
|
132794
|
+
await mkdir65(tree);
|
|
132727
132795
|
await tool("git", ["archive", "--format=tar", `--output=${archive}`, "HEAD", ".metaproject/flows"], { cwd: root }, "git archive");
|
|
132728
132796
|
await tool("tar", ["-xf", archive, "-C", tree], { cwd: work }, "tar extract");
|
|
132729
132797
|
const python = process.platform === "win32" ? "python" : "python3";
|
|
@@ -132755,7 +132823,7 @@ function withoutTime(counts) {
|
|
|
132755
132823
|
async function writeAtomic(file, content) {
|
|
132756
132824
|
const temp = `${file}.tmp-${process.pid}`;
|
|
132757
132825
|
try {
|
|
132758
|
-
await
|
|
132826
|
+
await writeFile42(temp, content, "utf8");
|
|
132759
132827
|
await rename12(temp, file);
|
|
132760
132828
|
} catch (error) {
|
|
132761
132829
|
await rm23(temp, { force: true });
|
|
@@ -132808,7 +132876,7 @@ async function recordFailure(root, runAt, reason) {
|
|
|
132808
132876
|
await writeIfChanged(file, text);
|
|
132809
132877
|
}
|
|
132810
132878
|
async function runResearchSync(input) {
|
|
132811
|
-
const deps = { now: () => new Date, runCounts, headHash, writeStaged: (file, content) =>
|
|
132879
|
+
const deps = { now: () => new Date, runCounts, headHash, writeStaged: (file, content) => writeFile42(file, content, "utf8"), renameStaged: rename12, ...input };
|
|
132812
132880
|
const { root } = deps;
|
|
132813
132881
|
const runAt = deps.now();
|
|
132814
132882
|
let computed;
|
|
@@ -132855,7 +132923,7 @@ async function runResearchSync(input) {
|
|
|
132855
132923
|
if (item.previous === null)
|
|
132856
132924
|
await rm23(item.file, { force: true });
|
|
132857
132925
|
else
|
|
132858
|
-
await
|
|
132926
|
+
await writeFile42(item.file, item.previous, "utf8");
|
|
132859
132927
|
} catch {}
|
|
132860
132928
|
}
|
|
132861
132929
|
changed.length = 0;
|
|
@@ -146613,7 +146681,7 @@ var init_jev_edit_guard_inspector = __esm(() => {
|
|
|
146613
146681
|
// src/review/jev-edit-guard-log.ts
|
|
146614
146682
|
import { appendFile as appendFile16, readFile as readFile154 } from "fs/promises";
|
|
146615
146683
|
import path296 from "path";
|
|
146616
|
-
import { mkdir as
|
|
146684
|
+
import { mkdir as mkdir66 } from "fs/promises";
|
|
146617
146685
|
function isEditGuardLogStatus(value) {
|
|
146618
146686
|
return typeof value === "string" && EDIT_GUARD_LOG_STATUSES.includes(value);
|
|
146619
146687
|
}
|
|
@@ -146667,7 +146735,7 @@ async function readEditGuardLogRecords(cwd) {
|
|
|
146667
146735
|
}
|
|
146668
146736
|
async function appendEditGuardLog(cwd, record) {
|
|
146669
146737
|
const file = path296.join(cwd, EDIT_GUARD_LOG_PATH);
|
|
146670
|
-
await
|
|
146738
|
+
await mkdir66(path296.dirname(file), { recursive: true });
|
|
146671
146739
|
await appendFile16(file, `${JSON.stringify(record)}
|
|
146672
146740
|
`, { mode: 384 });
|
|
146673
146741
|
}
|
|
@@ -155309,7 +155377,7 @@ var init_execution_plan_panel = __esm(() => {
|
|
|
155309
155377
|
});
|
|
155310
155378
|
|
|
155311
155379
|
// src/assets/pull.ts
|
|
155312
|
-
import { mkdir as
|
|
155380
|
+
import { mkdir as mkdir67, writeFile as writeFile43 } from "fs/promises";
|
|
155313
155381
|
import path301 from "path";
|
|
155314
155382
|
async function pullAsset(id, lock, options = {}) {
|
|
155315
155383
|
const entry = lock.assets[id];
|
|
@@ -155328,8 +155396,8 @@ async function pullAsset(id, lock, options = {}) {
|
|
|
155328
155396
|
}
|
|
155329
155397
|
const destDir = options.destDir ?? assetCacheDir();
|
|
155330
155398
|
const destPath = path301.join(destDir, id);
|
|
155331
|
-
await
|
|
155332
|
-
await
|
|
155399
|
+
await mkdir67(destDir, { recursive: true });
|
|
155400
|
+
await writeFile43(destPath, bytes);
|
|
155333
155401
|
return { path: destPath, sha256: actual, verified: true };
|
|
155334
155402
|
}
|
|
155335
155403
|
var defaultFetcher = async (url) => {
|
|
@@ -156269,7 +156337,7 @@ var init_diff = __esm(() => {
|
|
|
156269
156337
|
});
|
|
156270
156338
|
|
|
156271
156339
|
// src/sync/hooks.ts
|
|
156272
|
-
import { chmod as chmod11, mkdir as
|
|
156340
|
+
import { chmod as chmod11, mkdir as mkdir68, readFile as readFile157, writeFile as writeFile44 } from "fs/promises";
|
|
156273
156341
|
import path303 from "path";
|
|
156274
156342
|
function escapeRegExp8(value) {
|
|
156275
156343
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -156292,7 +156360,7 @@ async function writeManagedHook(projectRoot, hookName) {
|
|
|
156292
156360
|
if (!hooksRoot) {
|
|
156293
156361
|
return false;
|
|
156294
156362
|
}
|
|
156295
|
-
await
|
|
156363
|
+
await mkdir68(hooksRoot, { recursive: true });
|
|
156296
156364
|
const hookPath = path303.join(hooksRoot, hookName);
|
|
156297
156365
|
const start = `# keryx:${BLOCK_ID}:begin`;
|
|
156298
156366
|
const end = `# keryx:${BLOCK_ID}:end`;
|
|
@@ -156306,7 +156374,7 @@ ${end}`;
|
|
|
156306
156374
|
|
|
156307
156375
|
${block}
|
|
156308
156376
|
`;
|
|
156309
|
-
await
|
|
156377
|
+
await writeFile44(hookPath, next, "utf8");
|
|
156310
156378
|
await chmod11(hookPath, 493);
|
|
156311
156379
|
return true;
|
|
156312
156380
|
}
|
|
@@ -156326,7 +156394,7 @@ async function stripManagedHook(projectRoot, hookName) {
|
|
|
156326
156394
|
if (!pattern.test(existing)) {
|
|
156327
156395
|
return false;
|
|
156328
156396
|
}
|
|
156329
|
-
await
|
|
156397
|
+
await writeFile44(hookPath, `${existing.replace(pattern, `
|
|
156330
156398
|
`).trimEnd()}
|
|
156331
156399
|
`, "utf8");
|
|
156332
156400
|
return true;
|
|
@@ -157612,7 +157680,7 @@ var init_digest_summary = __esm(() => {
|
|
|
157612
157680
|
|
|
157613
157681
|
// src/scheduler/digest-run.ts
|
|
157614
157682
|
import { randomUUID as randomUUID41 } from "crypto";
|
|
157615
|
-
import { mkdir as
|
|
157683
|
+
import { mkdir as mkdir69, mkdtemp as mkdtemp10, rm as rm26, writeFile as writeFile45 } from "fs/promises";
|
|
157616
157684
|
import path305 from "path";
|
|
157617
157685
|
function scrubDigestReportLocator(locator, env) {
|
|
157618
157686
|
const scrubbed = scrubGrantedOutput(locator, env);
|
|
@@ -157684,7 +157752,7 @@ async function runLocked2(projectRoot, entry, action, deps, runId, now) {
|
|
|
157684
157752
|
}
|
|
157685
157753
|
const scratch = await mkdtemp10(path305.join(parent.dir, `${entry.name.replace(/[^A-Za-z0-9._-]/g, "-")}-`));
|
|
157686
157754
|
const grantedCwd = path305.join(scratch, "granted-cwd");
|
|
157687
|
-
await
|
|
157755
|
+
await mkdir69(grantedCwd, { recursive: true, mode: 448 });
|
|
157688
157756
|
const limits = startLimits({ maxSeconds: dispatch.maxSeconds, memoryLimitMb: digest.memoryLimitMb }, { ...deps.armTimeout !== undefined ? { armTimeout: deps.armTimeout } : {}, ...deps.limits ?? {} });
|
|
157689
157757
|
let crashed;
|
|
157690
157758
|
let collected = { items: [], failures: [], failedSources: new Set, truncatedSources: new Set, raw: [], calls: [], stopped: false };
|
|
@@ -157771,9 +157839,9 @@ async function runLocked2(projectRoot, entry, action, deps, runId, now) {
|
|
|
157771
157839
|
try {
|
|
157772
157840
|
await ensureTriggerDataIgnored(projectRoot);
|
|
157773
157841
|
const dir = path305.join(triggerReportsDir(projectRoot), entry.name);
|
|
157774
|
-
await
|
|
157842
|
+
await mkdir69(dir, { recursive: true });
|
|
157775
157843
|
const file = path305.join(dir, `${runId}.md`);
|
|
157776
|
-
await
|
|
157844
|
+
await writeFile45(file, renderDigestReport({
|
|
157777
157845
|
entry,
|
|
157778
157846
|
runId,
|
|
157779
157847
|
at: startedAt.toISOString(),
|
|
@@ -174232,7 +174300,7 @@ var init_sweep = __esm(() => {
|
|
|
174232
174300
|
});
|
|
174233
174301
|
|
|
174234
174302
|
// src/retention/auto-sweep.ts
|
|
174235
|
-
import { mkdir as
|
|
174303
|
+
import { mkdir as mkdir70, readFile as readFile167, rm as rm27, stat as stat35, writeFile as writeFile46 } from "fs/promises";
|
|
174236
174304
|
import { randomUUID as randomUUID43 } from "crypto";
|
|
174237
174305
|
import path322 from "path";
|
|
174238
174306
|
function autoSweepStampPath(cwd) {
|
|
@@ -174285,7 +174353,7 @@ async function acquireClaim(claimPath, staleMs) {
|
|
|
174285
174353
|
const nonce = `${process.pid}:${randomUUID43()}`;
|
|
174286
174354
|
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
174287
174355
|
try {
|
|
174288
|
-
await
|
|
174356
|
+
await writeFile46(claimPath, nonce, { flag: "wx", mode: 384 });
|
|
174289
174357
|
return {
|
|
174290
174358
|
release: async () => {
|
|
174291
174359
|
try {
|
|
@@ -174328,7 +174396,7 @@ async function maybeAutoSweepGdctx(cwd, options = {}) {
|
|
|
174328
174396
|
}
|
|
174329
174397
|
const stamp = autoSweepStampPath(cwd);
|
|
174330
174398
|
try {
|
|
174331
|
-
await
|
|
174399
|
+
await mkdir70(path322.dirname(stamp), { recursive: true });
|
|
174332
174400
|
} catch {
|
|
174333
174401
|
return { ran: false, reason: "stamp-unwritable" };
|
|
174334
174402
|
}
|
|
@@ -174341,7 +174409,7 @@ async function maybeAutoSweepGdctx(cwd, options = {}) {
|
|
|
174341
174409
|
return { ran: false, reason: "throttled" };
|
|
174342
174410
|
}
|
|
174343
174411
|
try {
|
|
174344
|
-
await
|
|
174412
|
+
await writeFile46(stamp, `${JSON.stringify({ startedAtMs: now, completedAtMs: null }, null, 2)}
|
|
174345
174413
|
`, "utf8");
|
|
174346
174414
|
} catch {
|
|
174347
174415
|
return { ran: false, reason: "stamp-unwritable" };
|
|
@@ -174351,7 +174419,7 @@ async function maybeAutoSweepGdctx(cwd, options = {}) {
|
|
|
174351
174419
|
now
|
|
174352
174420
|
});
|
|
174353
174421
|
const completedAtMs = options.now ?? Date.now();
|
|
174354
|
-
await
|
|
174422
|
+
await writeFile46(stamp, `${JSON.stringify({ startedAtMs: now, completedAtMs, lastRunAtMs: completedAtMs }, null, 2)}
|
|
174355
174423
|
`, "utf8").catch(() => {
|
|
174356
174424
|
return;
|
|
174357
174425
|
});
|
|
@@ -174371,7 +174439,7 @@ var init_auto_sweep = __esm(() => {
|
|
|
174371
174439
|
|
|
174372
174440
|
// src/ctx/artifact-id.ts
|
|
174373
174441
|
import { randomBytes as randomBytes14 } from "crypto";
|
|
174374
|
-
import { mkdir as
|
|
174442
|
+
import { mkdir as mkdir71, readFile as readFile168, rm as rm28, writeFile as writeFile47 } from "fs/promises";
|
|
174375
174443
|
import path323 from "path";
|
|
174376
174444
|
function pinnedClock() {
|
|
174377
174445
|
const pin = process.env.KERYX_CTX_CLOCK_PIN_MS;
|
|
@@ -174397,7 +174465,7 @@ function isAlreadyExists(error) {
|
|
|
174397
174465
|
}
|
|
174398
174466
|
async function claim(file) {
|
|
174399
174467
|
try {
|
|
174400
|
-
await
|
|
174468
|
+
await writeFile47(file, "", { encoding: "utf8", flag: "wx" });
|
|
174401
174469
|
return true;
|
|
174402
174470
|
} catch (error) {
|
|
174403
174471
|
if (isAlreadyExists(error)) {
|
|
@@ -174410,8 +174478,8 @@ async function reserveArtifact(options) {
|
|
|
174410
174478
|
const now = options.now ?? pinnedClock() ?? (() => new Date);
|
|
174411
174479
|
const token = options.token ?? defaultToken;
|
|
174412
174480
|
const maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
174413
|
-
await
|
|
174414
|
-
await
|
|
174481
|
+
await mkdir71(options.rawDir, { recursive: true });
|
|
174482
|
+
await mkdir71(options.artifactsDir, { recursive: true });
|
|
174415
174483
|
for (let attempt = 0;attempt < maxAttempts; attempt += 1) {
|
|
174416
174484
|
const id = artifactIdCandidate(options.kind, now(), token());
|
|
174417
174485
|
const rawPath = path323.join(options.rawDir, `${id}.log`);
|
|
@@ -174584,7 +174652,7 @@ var init_structured = __esm(() => {
|
|
|
174584
174652
|
});
|
|
174585
174653
|
|
|
174586
174654
|
// src/commands/ctx.ts
|
|
174587
|
-
import { readFile as readFile169, writeFile as
|
|
174655
|
+
import { readFile as readFile169, writeFile as writeFile48 } from "fs/promises";
|
|
174588
174656
|
import path324 from "path";
|
|
174589
174657
|
function structuredBudgetBytes(config) {
|
|
174590
174658
|
return (config.compactHeadLines + config.compactTailLines) * 40;
|
|
@@ -175023,8 +175091,8 @@ async function writeArtifact({
|
|
|
175023
175091
|
${JSON.stringify(artifact, null, 2)}
|
|
175024
175092
|
\`\`\`
|
|
175025
175093
|
`;
|
|
175026
|
-
await
|
|
175027
|
-
await
|
|
175094
|
+
await writeFile48(rawPath, raw, "utf8");
|
|
175095
|
+
await writeFile48(summaryPath, summaryWithMeta, "utf8");
|
|
175028
175096
|
await writeFileAtomic(latestRawPath, raw);
|
|
175029
175097
|
await writeFileAtomic(latestSummaryPath, summaryWithMeta);
|
|
175030
175098
|
await maybeAutoSweepGdctx(projectRoot).catch(() => {
|
|
@@ -175920,7 +175988,7 @@ function readLiteral(source, start, quote) {
|
|
|
175920
175988
|
}
|
|
175921
175989
|
|
|
175922
175990
|
// src/wiki/freshness/queue.ts
|
|
175923
|
-
import { readFile as readFile170, rename as rename13, stat as stat36, unlink as unlink3, writeFile as
|
|
175991
|
+
import { readFile as readFile170, rename as rename13, stat as stat36, unlink as unlink3, writeFile as writeFile49 } from "fs/promises";
|
|
175924
175992
|
import path325 from "path";
|
|
175925
175993
|
function queuePath(cwd) {
|
|
175926
175994
|
return path325.join(cwd, ".metaproject", "data", "wiki", QUEUE_FILE);
|
|
@@ -176504,7 +176572,7 @@ var init_report6 = __esm(() => {
|
|
|
176504
176572
|
});
|
|
176505
176573
|
|
|
176506
176574
|
// src/wiki/freshness/run.ts
|
|
176507
|
-
import { mkdir as
|
|
176575
|
+
import { mkdir as mkdir72, readFile as readFile172, writeFile as writeFile50 } from "fs/promises";
|
|
176508
176576
|
import path326 from "path";
|
|
176509
176577
|
function freshnessDir(cwd) {
|
|
176510
176578
|
return path326.join(cwd, ".metaproject", "data", "wiki", "freshness");
|
|
@@ -176550,10 +176618,10 @@ async function runFreshness(input) {
|
|
|
176550
176618
|
}
|
|
176551
176619
|
async function persist(cwd, report) {
|
|
176552
176620
|
const dir = freshnessDir(cwd);
|
|
176553
|
-
await
|
|
176554
|
-
await
|
|
176621
|
+
await mkdir72(dir, { recursive: true });
|
|
176622
|
+
await writeFile50(path326.join(dir, "latest.json"), `${JSON.stringify(report, null, 2)}
|
|
176555
176623
|
`, "utf8");
|
|
176556
|
-
await
|
|
176624
|
+
await writeFile50(path326.join(dir, "latest.md"), renderMarkdown2(report), "utf8");
|
|
176557
176625
|
}
|
|
176558
176626
|
async function collectChanges(cwd, git, fromRev) {
|
|
176559
176627
|
const status = await git(cwd, ["diff", "--name-status", "-M", fromRev, "HEAD"]);
|
|
@@ -180546,7 +180614,7 @@ var init_manifest4 = __esm(() => {
|
|
|
180546
180614
|
});
|
|
180547
180615
|
|
|
180548
180616
|
// src/gdskills/sync.ts
|
|
180549
|
-
import { copyFile as copyFile3, mkdir as
|
|
180617
|
+
import { copyFile as copyFile3, mkdir as mkdir73, readdir as readdir55, writeFile as writeFile51 } from "fs/promises";
|
|
180550
180618
|
import path340 from "path";
|
|
180551
180619
|
function isGlobalSyncRuntime(runtime) {
|
|
180552
180620
|
return Object.hasOwn(GLOBAL_SKILL_SYNC_TARGETS, runtime);
|
|
@@ -180617,12 +180685,12 @@ async function syncRuntimeSkillsToRoot(projectRoot, options) {
|
|
|
180617
180685
|
const manifestPath = path340.join(targetRoot, "keryx-sync-manifest.json");
|
|
180618
180686
|
const syncedSkills = skillDirs.map((skillDir) => path340.basename(skillDir)).sort();
|
|
180619
180687
|
if (!options.dryRun) {
|
|
180620
|
-
await
|
|
180688
|
+
await mkdir73(targetRoot, { recursive: true });
|
|
180621
180689
|
for (const skillDir of skillDirs) {
|
|
180622
180690
|
const targetSkillDir = path340.join(targetRoot, path340.basename(skillDir));
|
|
180623
180691
|
await copyDirectory(skillDir, targetSkillDir);
|
|
180624
180692
|
}
|
|
180625
|
-
await
|
|
180693
|
+
await writeFile51(manifestPath, `${JSON.stringify({
|
|
180626
180694
|
schemaVersion: 1,
|
|
180627
180695
|
runtime: options.runtime,
|
|
180628
180696
|
sourceRoot: toPosix(path340.relative(projectRoot, sourceRoot)),
|
|
@@ -180687,7 +180755,7 @@ async function plannedSyncFiles(projectRoot, skillDirs, sourceRoot, targetRoot)
|
|
|
180687
180755
|
async function copyDirectory(sourceDir, targetDir) {
|
|
180688
180756
|
for (const filePath of await listFiles3(sourceDir)) {
|
|
180689
180757
|
const targetPath = path340.join(targetDir, path340.relative(sourceDir, filePath));
|
|
180690
|
-
await
|
|
180758
|
+
await mkdir73(path340.dirname(targetPath), { recursive: true });
|
|
180691
180759
|
await copyFile3(filePath, targetPath);
|
|
180692
180760
|
}
|
|
180693
180761
|
}
|
|
@@ -182830,7 +182898,7 @@ var init_remove_skill = __esm(() => {
|
|
|
182830
182898
|
});
|
|
182831
182899
|
|
|
182832
182900
|
// src/gdskills/verify.ts
|
|
182833
|
-
import { mkdir as
|
|
182901
|
+
import { mkdir as mkdir74, readFile as readFile181, writeFile as writeFile52 } from "fs/promises";
|
|
182834
182902
|
import path345 from "path";
|
|
182835
182903
|
async function verifyProjectSkill(projectRoot, options) {
|
|
182836
182904
|
const metaprojectRoot = path345.join(projectRoot, ".metaproject");
|
|
@@ -182876,11 +182944,11 @@ async function verifyProjectSkill(projectRoot, options) {
|
|
|
182876
182944
|
dryRun: options.dryRun === true
|
|
182877
182945
|
};
|
|
182878
182946
|
if (!options.dryRun) {
|
|
182879
|
-
await
|
|
182880
|
-
await
|
|
182947
|
+
await mkdir74(path345.dirname(reportPath), { recursive: true });
|
|
182948
|
+
await writeFile52(reportPath, `${JSON.stringify(report, null, 2)}
|
|
182881
182949
|
`, "utf8");
|
|
182882
|
-
await
|
|
182883
|
-
await
|
|
182950
|
+
await writeFile52(path345.join(resolved.packageRoot, "verification.md"), renderVerificationMarkdown(report), "utf8");
|
|
182951
|
+
await writeFile52(skillMdPath, updateLastVerified(skillMd, verifiedAt), "utf8");
|
|
182884
182952
|
}
|
|
182885
182953
|
return report;
|
|
182886
182954
|
}
|
|
@@ -185586,7 +185654,7 @@ var init_plans = __esm(() => {
|
|
|
185586
185654
|
});
|
|
185587
185655
|
|
|
185588
185656
|
// src/job/store.ts
|
|
185589
|
-
import { appendFile as appendFile17, mkdir as
|
|
185657
|
+
import { appendFile as appendFile17, mkdir as mkdir75, readFile as readFile184, readdir as readdir61 } from "fs/promises";
|
|
185590
185658
|
import path348 from "path";
|
|
185591
185659
|
function jobsRoot(cwd) {
|
|
185592
185660
|
return path348.join(cwd, ".metaproject", "jobs");
|
|
@@ -185631,7 +185699,7 @@ async function writeJob(cwd, name, state) {
|
|
|
185631
185699
|
`));
|
|
185632
185700
|
}
|
|
185633
185701
|
const file = jobStatePath(cwd, name);
|
|
185634
|
-
await
|
|
185702
|
+
await mkdir75(path348.dirname(file), { recursive: true });
|
|
185635
185703
|
await writeFileAtomic(file, `${JSON.stringify(state, null, 2)}
|
|
185636
185704
|
`);
|
|
185637
185705
|
}
|
|
@@ -185670,7 +185738,7 @@ var init_store10 = __esm(() => {
|
|
|
185670
185738
|
});
|
|
185671
185739
|
|
|
185672
185740
|
// src/job/service.ts
|
|
185673
|
-
import { copyFile as copyFile4, mkdir as
|
|
185741
|
+
import { copyFile as copyFile4, mkdir as mkdir76 } from "fs/promises";
|
|
185674
185742
|
import path349 from "path";
|
|
185675
185743
|
function createJobService(deps) {
|
|
185676
185744
|
const now = () => deps.now().toISOString();
|
|
@@ -185713,7 +185781,7 @@ function createJobService(deps) {
|
|
|
185713
185781
|
if (await pathExists(absolute)) {
|
|
185714
185782
|
throw new Error(`Job package already exists: .metaproject/jobs/${name}. ` + `Run: keryx job status ${name}`);
|
|
185715
185783
|
}
|
|
185716
|
-
await
|
|
185784
|
+
await mkdir76(absolute, { recursive: true });
|
|
185717
185785
|
const createdAt = now();
|
|
185718
185786
|
const state = {
|
|
185719
185787
|
phase: "PLAN",
|
|
@@ -187383,7 +187451,7 @@ var init_retry_plan = __esm(() => {
|
|
|
187383
187451
|
|
|
187384
187452
|
// src/commands/review-slice.ts
|
|
187385
187453
|
import { existsSync as existsSync58, readFileSync as readFileSync28, statSync as statSync20 } from "fs";
|
|
187386
|
-
import { mkdir as
|
|
187454
|
+
import { mkdir as mkdir77, readFile as readFile188, readdir as readdir63, rm as rm29 } from "fs/promises";
|
|
187387
187455
|
import path351 from "path";
|
|
187388
187456
|
function wantsHelp2(args) {
|
|
187389
187457
|
return args.includes("--help") || args.includes("-h");
|
|
@@ -187441,7 +187509,7 @@ Attempts are remembered in ${RETRY_STATE_NAME} beside the manifest (--state to m
|
|
|
187441
187509
|
`);
|
|
187442
187510
|
}
|
|
187443
187511
|
async function writeSliceFiles(dir, slices) {
|
|
187444
|
-
await
|
|
187512
|
+
await mkdir77(dir, { recursive: true });
|
|
187445
187513
|
for (const slice of slices) {
|
|
187446
187514
|
await writeFileAtomic(path351.join(dir, slice.path), slice.text);
|
|
187447
187515
|
}
|
|
@@ -187460,7 +187528,7 @@ async function runSlice(args, deps) {
|
|
|
187460
187528
|
const outDir = path351.resolve(optionValue(args, "--out") ?? DEFAULT_SLICE_DIR);
|
|
187461
187529
|
const diff = diffFile !== undefined ? await deps.readDiffSource(diffFile) : await deps.gitDiff(ref, contextLines);
|
|
187462
187530
|
const { manifest, slices } = buildSlices(sliceSourceFromDiff(diff, { contextLines }), { maxBytes });
|
|
187463
|
-
await
|
|
187531
|
+
await mkdir77(outDir, { recursive: true });
|
|
187464
187532
|
for (const entry of await readdir63(outDir)) {
|
|
187465
187533
|
if (/^slice-\d+\.diff$/.test(entry)) {
|
|
187466
187534
|
await rm29(path351.join(outDir, entry), { force: true });
|
|
@@ -188935,7 +189003,7 @@ var init_floor = __esm(() => {
|
|
|
188935
189003
|
});
|
|
188936
189004
|
|
|
188937
189005
|
// src/commands/review.ts
|
|
188938
|
-
import { mkdir as
|
|
189006
|
+
import { mkdir as mkdir78, readdir as readdir64, readFile as readFile192 } from "fs/promises";
|
|
188939
189007
|
import path356, { join as join11 } from "path";
|
|
188940
189008
|
function reviewerList(args) {
|
|
188941
189009
|
return (optionValue(args, "--reviewers") ?? "").split(",").map((item) => item.trim()).filter(Boolean);
|
|
@@ -190245,7 +190313,7 @@ async function runLearn(args) {
|
|
|
190245
190313
|
const sourcePath = learningSourcePath(cwd, config.repo, number);
|
|
190246
190314
|
const recordPath = learningRecordPath(cwd, config.repo, number);
|
|
190247
190315
|
const relativeSourcePath = toPosix(path356.relative(cwd, sourcePath));
|
|
190248
|
-
await
|
|
190316
|
+
await mkdir78(path356.dirname(sourcePath), { recursive: true });
|
|
190249
190317
|
await writeFileAtomic(sourcePath, renderLearningSource(selection));
|
|
190250
190318
|
await writeFileAtomic(recordPath, renderLearningRecord({
|
|
190251
190319
|
repo: config.repo,
|
|
@@ -191876,7 +191944,7 @@ function classifyBaselineStatuses(baseline, pr) {
|
|
|
191876
191944
|
}
|
|
191877
191945
|
|
|
191878
191946
|
// src/commands/standard.ts
|
|
191879
|
-
import { mkdir as
|
|
191947
|
+
import { mkdir as mkdir79, writeFile as writeFile53 } from "fs/promises";
|
|
191880
191948
|
import path359 from "path";
|
|
191881
191949
|
async function standardCommand(args = [], projectRoot = process.cwd()) {
|
|
191882
191950
|
const subcommand = args[0];
|
|
@@ -191987,8 +192055,8 @@ async function handleEmit(projectRoot, args) {
|
|
|
191987
192055
|
if (args.includes("--stdout")) {
|
|
191988
192056
|
process.stdout.write(result.content);
|
|
191989
192057
|
} else {
|
|
191990
|
-
await
|
|
191991
|
-
await
|
|
192058
|
+
await mkdir79(path359.dirname(result.path), { recursive: true });
|
|
192059
|
+
await writeFile53(result.path, result.content, "utf8");
|
|
191992
192060
|
heading("keryx standard emit llms");
|
|
191993
192061
|
if (problems.length === 0) {
|
|
191994
192062
|
console.log(` ${style.green(symbols.ok)} wrote ${path359.relative(projectRoot, result.path)} (valid llms.txt)`);
|
|
@@ -194732,7 +194800,7 @@ var init_security_impact_evidence = __esm(() => {
|
|
|
194732
194800
|
});
|
|
194733
194801
|
|
|
194734
194802
|
// src/commands/security.ts
|
|
194735
|
-
import { mkdir as
|
|
194803
|
+
import { mkdir as mkdir80, readdir as readdir66, readFile as readFile195, writeFile as writeFile54 } from "fs/promises";
|
|
194736
194804
|
import path363 from "path";
|
|
194737
194805
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
194738
194806
|
async function securityCommand(args = [], cwd = process.cwd()) {
|
|
@@ -195015,8 +195083,8 @@ async function handleScanMcp(cwd, args) {
|
|
|
195015
195083
|
const { manifest } = extractManifestAndBaseline(read.value, {});
|
|
195016
195084
|
const baseline = { schemaVersion: 1, tools: buildMcpBaseline(manifest) };
|
|
195017
195085
|
const outPath = mcpBaselinePath(cwd);
|
|
195018
|
-
await
|
|
195019
|
-
await
|
|
195086
|
+
await mkdir80(path363.dirname(outPath), { recursive: true });
|
|
195087
|
+
await writeFile54(outPath, `${JSON.stringify(baseline, null, 2)}
|
|
195020
195088
|
`, "utf8");
|
|
195021
195089
|
if (asJson) {
|
|
195022
195090
|
console.log(JSON.stringify({ pinned: Object.keys(baseline.tools).length, path: outPath }, null, 2));
|
|
@@ -195138,7 +195206,7 @@ async function handleRedact(cwd, args) {
|
|
|
195138
195206
|
source
|
|
195139
195207
|
});
|
|
195140
195208
|
if (out) {
|
|
195141
|
-
await
|
|
195209
|
+
await writeFile54(out, redacted, "utf8");
|
|
195142
195210
|
heading("keryx security redact");
|
|
195143
195211
|
console.log(` ${style.green(symbols.ok)} redacted ${findings.length} span(s) \u2192 ${out}`);
|
|
195144
195212
|
} else {
|
|
@@ -196399,7 +196467,7 @@ var init_metaproject_tools2 = __esm(() => {
|
|
|
196399
196467
|
});
|
|
196400
196468
|
|
|
196401
196469
|
// src/mcp/tools.ts
|
|
196402
|
-
import { readFile as readFile196, realpath as realpath24, writeFile as
|
|
196470
|
+
import { readFile as readFile196, realpath as realpath24, writeFile as writeFile55 } from "fs/promises";
|
|
196403
196471
|
import path365 from "path";
|
|
196404
196472
|
import { randomUUID as randomUUID44 } from "crypto";
|
|
196405
196473
|
function sacWorkspaceService(cwd) {
|
|
@@ -196545,7 +196613,7 @@ function buildToolRegistry() {
|
|
|
196545
196613
|
const wrapUp = await wrapUpAuthority.issue({ actor, source: "session", sourceRef: sessionEvidenceRef(workspaceId, session.id) });
|
|
196546
196614
|
const proposal = await service.create({ request: undefined, requestCorrelationId, workspaceId, id: `proposal-${randomUUID44().replace(/-/g, "").slice(0, 16)}`, proposalRevision, kind, wrapUp });
|
|
196547
196615
|
if (note)
|
|
196548
|
-
await
|
|
196616
|
+
await writeFile55(proposalNotePath(cwd, workspaceId, proposal.id), note, "utf8");
|
|
196549
196617
|
return normalizeProposalLifecycleResult(proposal);
|
|
196550
196618
|
}
|
|
196551
196619
|
},
|
|
@@ -213287,7 +213355,7 @@ var PROBE_TIMEOUT_MS = 1e4;
|
|
|
213287
213355
|
|
|
213288
213356
|
// src/commands/agents-external.ts
|
|
213289
213357
|
import { randomUUID as randomUUID56 } from "crypto";
|
|
213290
|
-
import { mkdir as
|
|
213358
|
+
import { mkdir as mkdir81 } from "fs/promises";
|
|
213291
213359
|
import { tmpdir as tmpdir16 } from "os";
|
|
213292
213360
|
import path386 from "path";
|
|
213293
213361
|
import { createInterface as createInterface4 } from "readline";
|
|
@@ -213560,7 +213628,7 @@ async function runCommand4(args, deps, log) {
|
|
|
213560
213628
|
const worktreesDir = path386.join(tmpdir16(), "keryx-external-worktrees");
|
|
213561
213629
|
const worktree = seams.worktree ?? createGitWorktreePort({ repoRoot: cwd, worktreesDir });
|
|
213562
213630
|
if (seams.worktree === undefined)
|
|
213563
|
-
await
|
|
213631
|
+
await mkdir81(worktreesDir, { recursive: true });
|
|
213564
213632
|
const detect = seams.detect === null ? undefined : seams.detect ?? createVersionProbe();
|
|
213565
213633
|
const runInput = {
|
|
213566
213634
|
runtime: {
|
|
@@ -215535,7 +215603,7 @@ function factPreservation(rawFacts, compactFacts) {
|
|
|
215535
215603
|
}
|
|
215536
215604
|
|
|
215537
215605
|
// src/metrics/oracle-runner.ts
|
|
215538
|
-
import { mkdir as
|
|
215606
|
+
import { mkdir as mkdir82, writeFile as writeFile56 } from "fs/promises";
|
|
215539
215607
|
import path388 from "path";
|
|
215540
215608
|
function oracleTaskId(target) {
|
|
215541
215609
|
return `metastore:gdgraph-affected:${target}`;
|
|
@@ -215858,8 +215926,8 @@ async function persistEvidenceBundle(outDir, bundle, ladder = "metastore") {
|
|
|
215858
215926
|
const safeTarget = bundle.target.replace(/[^A-Za-z0-9._/-]/g, "_");
|
|
215859
215927
|
const safeCase = bundle.caseId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
215860
215928
|
const dir = path388.join(outDir, "bench", ladder, safeTarget, safeCase, bundle.variant, String(bundle.seed));
|
|
215861
|
-
await
|
|
215862
|
-
const write = (name, value) =>
|
|
215929
|
+
await mkdir82(dir, { recursive: true });
|
|
215930
|
+
const write = (name, value) => writeFile56(path388.join(dir, name), `${JSON.stringify(value, null, 2)}
|
|
215863
215931
|
`, "utf8");
|
|
215864
215932
|
await Promise.all([
|
|
215865
215933
|
write("inputs.json", bundle.inputs),
|
|
@@ -216583,7 +216651,7 @@ function formatFwkExplain(result) {
|
|
|
216583
216651
|
|
|
216584
216652
|
// src/commands/workspace.ts
|
|
216585
216653
|
import { randomUUID as randomUUID57 } from "crypto";
|
|
216586
|
-
import { writeFile as
|
|
216654
|
+
import { writeFile as writeFile57 } from "fs/promises";
|
|
216587
216655
|
function service8() {
|
|
216588
216656
|
return new WorkspaceService({
|
|
216589
216657
|
workspaceRoot: process.cwd(),
|
|
@@ -216724,7 +216792,7 @@ async function workspaceCommand(args) {
|
|
|
216724
216792
|
const wrapUp = await wrapUpAuthority.issue({ actor, source: "session", sourceRef: sessionEvidenceRef(workspaceId, session.id) });
|
|
216725
216793
|
const proposal = await service.create({ request: undefined, requestCorrelationId, workspaceId, id: proposalId, proposalRevision, kind, wrapUp });
|
|
216726
216794
|
if (persistedNote)
|
|
216727
|
-
await
|
|
216795
|
+
await writeFile57(notePath, persistedNote, "utf8");
|
|
216728
216796
|
console.log(JSON.stringify(normalizeProposalLifecycleResult(proposal), null, 2));
|
|
216729
216797
|
return;
|
|
216730
216798
|
}
|
|
@@ -221044,7 +221112,7 @@ var init_learned_pattern_schema = __esm(() => {
|
|
|
221044
221112
|
|
|
221045
221113
|
// src/bundle/export.ts
|
|
221046
221114
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
221047
|
-
import { mkdir as
|
|
221115
|
+
import { mkdir as mkdir83, readdir as readdir71, readFile as readFile205, writeFile as writeFile58, lstat as lstat24 } from "fs/promises";
|
|
221048
221116
|
import { existsSync as existsSync62 } from "fs";
|
|
221049
221117
|
import path395 from "path";
|
|
221050
221118
|
function globToRegExp5(glob) {
|
|
@@ -221279,12 +221347,12 @@ async function outDirIsEmpty(out) {
|
|
|
221279
221347
|
}
|
|
221280
221348
|
}
|
|
221281
221349
|
async function writeDirectoryBundle(out, manifestBytes, files) {
|
|
221282
|
-
await
|
|
221283
|
-
await
|
|
221350
|
+
await mkdir83(out, { recursive: true });
|
|
221351
|
+
await writeFile58(path395.join(out, "bundle.json"), manifestBytes);
|
|
221284
221352
|
for (const [rel, bytes] of files) {
|
|
221285
221353
|
const abs = path395.join(out, ...rel.split("/"));
|
|
221286
|
-
await
|
|
221287
|
-
await
|
|
221354
|
+
await mkdir83(path395.dirname(abs), { recursive: true });
|
|
221355
|
+
await writeFile58(abs, bytes);
|
|
221288
221356
|
}
|
|
221289
221357
|
}
|
|
221290
221358
|
async function exportBundle(opts) {
|
|
@@ -221417,8 +221485,8 @@ async function exportBundle(opts) {
|
|
|
221417
221485
|
const archive = buildBundleArchive(files, manifestBytes);
|
|
221418
221486
|
if (!archive.ok)
|
|
221419
221487
|
return { ok: false, refusals: [archive.refusal] };
|
|
221420
|
-
await
|
|
221421
|
-
await
|
|
221488
|
+
await mkdir83(path395.dirname(opts.out), { recursive: true });
|
|
221489
|
+
await writeFile58(opts.out, archive.value);
|
|
221422
221490
|
} else {
|
|
221423
221491
|
if (existsSync62(opts.out) && !await outDirIsEmpty(opts.out)) {
|
|
221424
221492
|
return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.notABundle, message: `${opts.out} already exists and is not empty` }] };
|
|
@@ -221601,7 +221669,7 @@ var init_applied_state = __esm(() => {
|
|
|
221601
221669
|
});
|
|
221602
221670
|
|
|
221603
221671
|
// src/lib/private-dir.ts
|
|
221604
|
-
import { lstat as lstat25, mkdir as
|
|
221672
|
+
import { lstat as lstat25, mkdir as mkdir84, open as open11, readFile as readFile207 } from "fs/promises";
|
|
221605
221673
|
import path397 from "path";
|
|
221606
221674
|
async function checkPrivateDirGitignore(dir, root) {
|
|
221607
221675
|
if (root !== undefined) {
|
|
@@ -221691,7 +221759,7 @@ async function ensurePrivateDirGitignore(dir, root) {
|
|
|
221691
221759
|
return check;
|
|
221692
221760
|
}
|
|
221693
221761
|
const gitignorePath = path397.join(dir, ".gitignore");
|
|
221694
|
-
await
|
|
221762
|
+
await mkdir84(dir, { recursive: true });
|
|
221695
221763
|
try {
|
|
221696
221764
|
const handle = await open11(gitignorePath, "wx");
|
|
221697
221765
|
try {
|
|
@@ -222106,7 +222174,7 @@ var init_plan2 = __esm(() => {
|
|
|
222106
222174
|
});
|
|
222107
222175
|
|
|
222108
222176
|
// src/bundle/audit.ts
|
|
222109
|
-
import { mkdtemp as mkdtemp11, mkdir as
|
|
222177
|
+
import { mkdtemp as mkdtemp11, mkdir as mkdir85, rm as rm30, writeFile as writeFile59 } from "fs/promises";
|
|
222110
222178
|
import { tmpdir as tmpdir17 } from "os";
|
|
222111
222179
|
import path398 from "path";
|
|
222112
222180
|
function entriesToStage(plan) {
|
|
@@ -222123,8 +222191,8 @@ async function auditBundlePlan(plan, opts = {}) {
|
|
|
222123
222191
|
try {
|
|
222124
222192
|
for (const entry of toStage) {
|
|
222125
222193
|
const abs = path398.join(stagingDir, ...entry.path.split("/"));
|
|
222126
|
-
await
|
|
222127
|
-
await
|
|
222194
|
+
await mkdir85(path398.dirname(abs), { recursive: true });
|
|
222195
|
+
await writeFile59(abs, entry.bytes);
|
|
222128
222196
|
}
|
|
222129
222197
|
} catch (err) {
|
|
222130
222198
|
return {
|
|
@@ -222157,7 +222225,7 @@ var init_audit = __esm(() => {
|
|
|
222157
222225
|
});
|
|
222158
222226
|
|
|
222159
222227
|
// src/bundle/apply.ts
|
|
222160
|
-
import { mkdir as
|
|
222228
|
+
import { mkdir as mkdir86, rmdir as rmdir2, stat as stat42 } from "fs/promises";
|
|
222161
222229
|
import path399 from "path";
|
|
222162
222230
|
function writableEntries(plan) {
|
|
222163
222231
|
return plan.entries.filter((e) => e.bucket === "new" || e.bucket === "update" || e.bucket === "conflict" && e.forced);
|
|
@@ -222326,7 +222394,7 @@ async function mkdirRecordingCreated(dir) {
|
|
|
222326
222394
|
}
|
|
222327
222395
|
}
|
|
222328
222396
|
if (missing.length > 0) {
|
|
222329
|
-
await
|
|
222397
|
+
await mkdir86(dir, { recursive: true });
|
|
222330
222398
|
}
|
|
222331
222399
|
return missing;
|
|
222332
222400
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrciphersmith/keryx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.90",
|
|
4
4
|
"description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -85,7 +85,7 @@ A reviewer on this host cannot open a path: its file tool reads inside its worki
|
|
|
85
85
|
1. **Slice first.** `keryx review slice --ref <base> --out <dir>` after `keryx review scope`. It writes `slice-NN.diff` files of at most 150000 bytes each and a `manifest.json`; ledgers (csv, lockfiles, snapshots, generated files) are listed under `omissions` with a reason — list them in the report as not reviewed, never as clean.
|
|
86
86
|
2. **Slices travel by `context_files`.** Write the slices under the project (the default `--out`, `.metaproject/data/review/slices`, already is) and pass each reviewer its slice paths in `spawn_subagent`'s `context_files`: the host copies the text into that reviewer's task, so you never paste or retype a slice. Put the `slices` ids in its reviewer-input. A dispatch that names a git range but no slice and no `context_files` leaves the reviewer with nothing to read — that is `BLOCKED`, not a review.
|
|
87
87
|
3. **Check before dispatch.** `keryx review dispatch-check --payload <file> --manifest <dir>/manifest.json` for the wave; exit 1 means a payload names no slice, is over the ceiling, or breaks `reviewer-input.schema.json`. Fix it; do not dispatch around it.
|
|
88
|
-
4. **One batch.** Dispatch the whole wave — up to 10 reviewers — in one message, not one at a time. Give each reviewer `max_rounds` of at least 40 (the default); a reviewer that spends its rounds reading the skill and the schema returns nothing. **Incomplete means retry once, then Not run.** On `INCOMPLETE` or `BLOCKED`, `keryx review retry-plan --manifest <dir>/manifest.json --result <result.json>` decides: it cuts the assigned slices in half and names the one retry, and after that prints the `- **Not run:** …` line to paste into the report. An unfinished reviewer is never counted as a clean pass.
|
|
88
|
+
4. **One batch.** Dispatch the whole wave — up to 10 reviewers — in one message, not one at a time. Give each reviewer `max_rounds` of at least 40 (the default); a reviewer that spends its rounds reading the skill and the schema returns nothing. **Incomplete means retry once, then Not run.** On `INCOMPLETE` or `BLOCKED`, `keryx review retry-plan --manifest <dir>/manifest.json --result <result.json>` decides: it cuts the assigned slices in half and names the one retry, and after that prints the `- **Not run:** …` line to paste into the report. An unfinished reviewer is never counted as a clean pass. **Persist every result.** Pass each reviewer `save_result_to: .metaproject/data/review/raw/<reviewer>.txt`: the host writes its full final text there, so `review complete` has raw evidence even after the transcript is cut. Build `research.json` from those files — the ledger fields from the detail file plus one more key, `dispatch: {version:1, selected:[names], unresolvedRules:[], runs:[{reviewer, executionId:<its sub:… id>, status:"complete", scopeComplete:true, rawEvidence:<saved path>, ruleEvidence:[<rule paths>], executionRequired:false, executionReason:<why>}]}` — and ingest once with `--research`, into the package `review start` created. A refused `review complete` names what is missing: fix that with a command and run it again; it is never `blocked`. `--head` wants a SHA (`git rev-parse HEAD`), not `HEAD`.
|
|
89
89
|
5. **Never print a scope or a slice.** The tool output of one call is cut at about 20 KB and `keryx review scope` of a large PR prints hundreds of KB. Run it as `keryx review scope --ref <base> --json > .metaproject/data/review/scope.json` and read the counts from the file (`keryx ctx read`, or `jq`); take `<base>` from `git symbolic-ref refs/remotes/origin/HEAD`, not a guessed `origin/main`. Create `.metaproject/data/review/` first (`mkdir -p`) — a missing directory is a command to run, not a blocker. **Machine artifacts by direct write.** Save slices, payloads and results by redirection or `keryx ctx run --raw -- <command>`; the summarized form of `keryx ctx run` drops the bytes a later step parses.
|
|
90
90
|
|
|
91
91
|
## Control
|