@mrciphersmith/keryx 0.3.89 → 0.3.91

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.89",
21108
+ version: "0.3.91",
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 mkdir56, open as open10, readFile as readFile109 } from "fs/promises";
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 mkdir56(parent, { recursive: true });
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 writeFile36 } from "fs/promises";
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 writeFile36(schemaPath, schemaText, "utf8");
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 writeFile36(resultSchemaPathForCodec, JSON.stringify(toStrictOutputSchema(bundledResultSchema)), "utf8");
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 mkdir57 } from "fs/promises";
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 mkdir57(worktreesDir, { recursive: true });
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 mkdir58, readFile as readFile121, readdir as readdir39, realpath as realpath20, rm as rm18, stat as stat29 } from "fs/promises";
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 mkdir58(packageDir, { recursive: true });
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)}
@@ -118152,7 +118220,13 @@ async function readReport(input) {
118152
118220
  return input.reportText;
118153
118221
  }
118154
118222
  if (input.reportPath) {
118155
- return readFile121(path252.resolve(input.cwd, input.reportPath), "utf8");
118223
+ try {
118224
+ return await readFile121(path252.resolve(input.cwd, input.reportPath), "utf8");
118225
+ } catch (error) {
118226
+ const code = error.code;
118227
+ if (input.mode === "ingest" || code !== "ENOENT" && code !== "EISDIR")
118228
+ throw error;
118229
+ }
118156
118230
  }
118157
118231
  if (input.mode === "ingest") {
118158
118232
  throw new Error("ingest requires --report or reportText");
@@ -125399,7 +125473,7 @@ var init_aggregate = __esm(() => {
125399
125473
  });
125400
125474
 
125401
125475
  // src/governance/report.ts
125402
- import { mkdir as mkdir59 } from "fs/promises";
125476
+ import { mkdir as mkdir60 } from "fs/promises";
125403
125477
  import path261 from "path";
125404
125478
  function governanceDataRoot(cwd) {
125405
125479
  return path261.join(cwd, ".metaproject", "data", "governance");
@@ -125585,7 +125659,7 @@ function renderTriggerSpendLine(spend) {
125585
125659
  }
125586
125660
  async function writeGovernanceArtifacts(cwd, report) {
125587
125661
  const { markdown, json } = artifactPaths(cwd);
125588
- await mkdir59(path261.dirname(markdown), { recursive: true });
125662
+ await mkdir60(path261.dirname(markdown), { recursive: true });
125589
125663
  await writeFileAtomic(markdown, renderGovernanceMarkdown(report));
125590
125664
  await writeFileAtomic(json, `${JSON.stringify(report, null, 2)}
125591
125665
  `);
@@ -128773,7 +128847,7 @@ var init_granted_json_ids = __esm(() => {
128773
128847
  // src/commands/trigger-agent-task.ts
128774
128848
  import { execFile as execFile11 } from "child_process";
128775
128849
  import { randomUUID as randomUUID35 } from "crypto";
128776
- import { mkdtemp as mkdtemp5, mkdir as mkdir60, readdir as readdir42, rm as rm19, writeFile as writeFile37 } from "fs/promises";
128850
+ import { mkdtemp as mkdtemp5, mkdir as mkdir61, readdir as readdir42, rm as rm19, writeFile as writeFile38 } from "fs/promises";
128777
128851
  import { homedir as homedir12, tmpdir as tmpdir11 } from "os";
128778
128852
  import path268 from "path";
128779
128853
  function scrubGrantedOutput(text, env, secrets = [], json = false) {
@@ -128944,9 +129018,9 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
128944
129018
  const workdir = path268.join(scratch, "work");
128945
129019
  const scratchHome = path268.join(scratch, "home");
128946
129020
  const grantedCwd = path268.join(scratch, "granted-cwd");
128947
- await mkdir60(workdir, { recursive: true });
128948
- await mkdir60(scratchHome, { recursive: true });
128949
- await mkdir60(grantedCwd, { recursive: true, mode: 448 });
129021
+ await mkdir61(workdir, { recursive: true });
129022
+ await mkdir61(scratchHome, { recursive: true });
129023
+ await mkdir61(grantedCwd, { recursive: true, mode: 448 });
128950
129024
  const cleanup = async () => {
128951
129025
  await rm19(scratch, { recursive: true, force: true }).catch(() => {});
128952
129026
  };
@@ -129114,9 +129188,9 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
129114
129188
  try {
129115
129189
  await ensureTriggerDataIgnored(projectRoot);
129116
129190
  const dir = path268.join(triggerReportsDir(projectRoot), entry.name);
129117
- await mkdir60(dir, { recursive: true });
129191
+ await mkdir61(dir, { recursive: true });
129118
129192
  const file = path268.join(dir, `${runId}.md`);
129119
- await writeFile37(file, renderReport3({ entry, action, runId, at: now().toISOString(), outcome, why, cost, grantedCalls, denials, sandboxNote, summary, networkDecisions }), "utf8");
129193
+ await writeFile38(file, renderReport3({ entry, action, runId, at: now().toISOString(), outcome, why, cost, grantedCalls, denials, sandboxNote, summary, networkDecisions }), "utf8");
129120
129194
  await pruneReports(dir, action.report.keep);
129121
129195
  reportPath = path268.relative(projectRoot, file);
129122
129196
  } catch (error) {
@@ -129663,18 +129737,18 @@ var init_types10 = __esm(() => {
129663
129737
 
129664
129738
  // src/intake/store.ts
129665
129739
  import { createHash as createHash70 } from "crypto";
129666
- import { appendFile as appendFile14, mkdir as mkdir61, readFile as readFile128, writeFile as writeFile38 } from "fs/promises";
129740
+ import { appendFile as appendFile14, mkdir as mkdir62, readFile as readFile128, writeFile as writeFile39 } from "fs/promises";
129667
129741
  import path272 from "path";
129668
129742
  async function ensureIntakeDataIgnored(root) {
129669
129743
  const dir = intakeDataDir(root);
129670
- await mkdir61(dir, { recursive: true });
129744
+ await mkdir62(dir, { recursive: true });
129671
129745
  const file = path272.join(dir, ".gitignore");
129672
129746
  try {
129673
129747
  await readFile128(file, "utf8");
129674
129748
  } catch (error) {
129675
129749
  if (!isNotFound(error))
129676
129750
  throw error;
129677
- await writeFile38(file, `# Work intake: the card registry, the ledger and the poll state. Never committed.
129751
+ await writeFile39(file, `# Work intake: the card registry, the ledger and the poll state. Never committed.
129678
129752
  *
129679
129753
  !.gitignore
129680
129754
  `, "utf8");
@@ -130815,7 +130889,7 @@ var init_events = __esm(() => {
130815
130889
 
130816
130890
  // src/intake/poll.ts
130817
130891
  import { randomUUID as randomUUID36 } from "crypto";
130818
- import { mkdir as mkdir62, mkdtemp as mkdtemp6, rm as rm21, writeFile as writeFile39 } from "fs/promises";
130892
+ import { mkdir as mkdir63, mkdtemp as mkdtemp6, rm as rm21, writeFile as writeFile40 } from "fs/promises";
130819
130893
  import path275 from "path";
130820
130894
  function intakePollDue(config, state, now) {
130821
130895
  if (!config.enabled || state.paused || config.repos.length === 0)
@@ -130924,7 +130998,7 @@ async function pollLocked(root, config, deps, runId, now) {
130924
130998
  try {
130925
130999
  if (scratch !== undefined) {
130926
131000
  const cwd = path275.join(scratch, "granted-cwd");
130927
- await mkdir62(cwd, { recursive: true, mode: 448 });
131001
+ await mkdir63(cwd, { recursive: true, mode: 448 });
130928
131002
  const gh = await verifyGh(root, env);
130929
131003
  if (!gh.ok)
130930
131004
  failures.push({ source: "gh", detail: `refusing to run: ${gh.reason}` });
@@ -131113,9 +131187,9 @@ async function writeReport2(root, r) {
131113
131187
  try {
131114
131188
  await ensureIntakeDataIgnored(root);
131115
131189
  const dir = intakeReportsDir(root);
131116
- await mkdir62(dir, { recursive: true });
131190
+ await mkdir63(dir, { recursive: true });
131117
131191
  const file = path275.join(dir, `${r.runId}.md`);
131118
- await writeFile39(file, scrubGrantedOutput(lines.join(`
131192
+ await writeFile40(file, scrubGrantedOutput(lines.join(`
131119
131193
  `), r.env), "utf8");
131120
131194
  await pruneReports(dir, REPORTS_KEEP);
131121
131195
  return path275.relative(root, file);
@@ -132412,7 +132486,7 @@ var init_decisions_surface = __esm(() => {
132412
132486
  });
132413
132487
 
132414
132488
  // src/scheduler/research-sync-job.ts
132415
- import { mkdir as mkdir63, readFile as readFile131, readdir as readdir44, rm as rm22, writeFile as writeFile40 } from "fs/promises";
132489
+ import { mkdir as mkdir64, readFile as readFile131, readdir as readdir44, rm as rm22, writeFile as writeFile41 } from "fs/promises";
132416
132490
  import path276 from "path";
132417
132491
  function researchSyncDataDir(projectRoot) {
132418
132492
  return path276.join(projectRoot, ".metaproject", "data", "research-sync");
@@ -132451,14 +132525,14 @@ async function writeFired2(projectRoot, state) {
132451
132525
  }
132452
132526
  async function ensureIgnored(projectRoot) {
132453
132527
  const dir = researchSyncDataDir(projectRoot);
132454
- await mkdir63(dir, { recursive: true });
132528
+ await mkdir64(dir, { recursive: true });
132455
132529
  const file = path276.join(dir, ".gitignore");
132456
132530
  try {
132457
132531
  await readFile131(file, "utf8");
132458
132532
  } catch (error) {
132459
132533
  if (!isNotFound(error))
132460
132534
  throw error;
132461
- await writeFile40(file, `# Daily research sync: the entry and the day it last ran. Never staged.
132535
+ await writeFile41(file, `# Daily research sync: the entry and the day it last ran. Never staged.
132462
132536
  *
132463
132537
  !.gitignore
132464
132538
  `, "utf8");
@@ -132490,7 +132564,7 @@ async function claimFiles(projectRoot) {
132490
132564
  }
132491
132565
  async function claimDay(projectRoot, day, at) {
132492
132566
  try {
132493
- await writeFile40(researchSyncClaimPath(projectRoot, day), `${JSON.stringify({ pid: process.pid, claimedAt: at.toISOString() })}
132567
+ await writeFile41(researchSyncClaimPath(projectRoot, day), `${JSON.stringify({ pid: process.pid, claimedAt: at.toISOString() })}
132494
132568
  `, { flag: "wx" });
132495
132569
  } catch (error) {
132496
132570
  if (error.code === "EEXIST")
@@ -132688,7 +132762,7 @@ var STATUS_TITLE = "# \u0422\u0435\u043A\u0443\u0449\u0435\u0435 \u0441\u043E\u0
132688
132762
 
132689
132763
  // src/commands/research-sync.ts
132690
132764
  import { execFile as execFile12 } from "child_process";
132691
- import { mkdir as mkdir64, mkdtemp as mkdtemp7, readFile as readFile132, rename as rename12, rm as rm23, writeFile as writeFile41 } from "fs/promises";
132765
+ import { mkdir as mkdir65, mkdtemp as mkdtemp7, readFile as readFile132, rename as rename12, rm as rm23, writeFile as writeFile42 } from "fs/promises";
132692
132766
  import { tmpdir as tmpdir12 } from "os";
132693
132767
  import path277 from "path";
132694
132768
  import { promisify as promisify9 } from "util";
@@ -132723,7 +132797,7 @@ async function runCounts(root) {
132723
132797
  const gitDir = (await tool("git", ["rev-parse", "--absolute-git-dir"], { cwd: root }, "git rev-parse")).trim();
132724
132798
  const archive = path277.join(work, "flows.tar");
132725
132799
  const tree = path277.join(work, "tree");
132726
- await mkdir64(tree);
132800
+ await mkdir65(tree);
132727
132801
  await tool("git", ["archive", "--format=tar", `--output=${archive}`, "HEAD", ".metaproject/flows"], { cwd: root }, "git archive");
132728
132802
  await tool("tar", ["-xf", archive, "-C", tree], { cwd: work }, "tar extract");
132729
132803
  const python = process.platform === "win32" ? "python" : "python3";
@@ -132755,7 +132829,7 @@ function withoutTime(counts) {
132755
132829
  async function writeAtomic(file, content) {
132756
132830
  const temp = `${file}.tmp-${process.pid}`;
132757
132831
  try {
132758
- await writeFile41(temp, content, "utf8");
132832
+ await writeFile42(temp, content, "utf8");
132759
132833
  await rename12(temp, file);
132760
132834
  } catch (error) {
132761
132835
  await rm23(temp, { force: true });
@@ -132808,7 +132882,7 @@ async function recordFailure(root, runAt, reason) {
132808
132882
  await writeIfChanged(file, text);
132809
132883
  }
132810
132884
  async function runResearchSync(input) {
132811
- const deps = { now: () => new Date, runCounts, headHash, writeStaged: (file, content) => writeFile41(file, content, "utf8"), renameStaged: rename12, ...input };
132885
+ const deps = { now: () => new Date, runCounts, headHash, writeStaged: (file, content) => writeFile42(file, content, "utf8"), renameStaged: rename12, ...input };
132812
132886
  const { root } = deps;
132813
132887
  const runAt = deps.now();
132814
132888
  let computed;
@@ -132855,7 +132929,7 @@ async function runResearchSync(input) {
132855
132929
  if (item.previous === null)
132856
132930
  await rm23(item.file, { force: true });
132857
132931
  else
132858
- await writeFile41(item.file, item.previous, "utf8");
132932
+ await writeFile42(item.file, item.previous, "utf8");
132859
132933
  } catch {}
132860
132934
  }
132861
132935
  changed.length = 0;
@@ -146613,7 +146687,7 @@ var init_jev_edit_guard_inspector = __esm(() => {
146613
146687
  // src/review/jev-edit-guard-log.ts
146614
146688
  import { appendFile as appendFile16, readFile as readFile154 } from "fs/promises";
146615
146689
  import path296 from "path";
146616
- import { mkdir as mkdir65 } from "fs/promises";
146690
+ import { mkdir as mkdir66 } from "fs/promises";
146617
146691
  function isEditGuardLogStatus(value) {
146618
146692
  return typeof value === "string" && EDIT_GUARD_LOG_STATUSES.includes(value);
146619
146693
  }
@@ -146667,7 +146741,7 @@ async function readEditGuardLogRecords(cwd) {
146667
146741
  }
146668
146742
  async function appendEditGuardLog(cwd, record) {
146669
146743
  const file = path296.join(cwd, EDIT_GUARD_LOG_PATH);
146670
- await mkdir65(path296.dirname(file), { recursive: true });
146744
+ await mkdir66(path296.dirname(file), { recursive: true });
146671
146745
  await appendFile16(file, `${JSON.stringify(record)}
146672
146746
  `, { mode: 384 });
146673
146747
  }
@@ -155309,7 +155383,7 @@ var init_execution_plan_panel = __esm(() => {
155309
155383
  });
155310
155384
 
155311
155385
  // src/assets/pull.ts
155312
- import { mkdir as mkdir66, writeFile as writeFile42 } from "fs/promises";
155386
+ import { mkdir as mkdir67, writeFile as writeFile43 } from "fs/promises";
155313
155387
  import path301 from "path";
155314
155388
  async function pullAsset(id, lock, options = {}) {
155315
155389
  const entry = lock.assets[id];
@@ -155328,8 +155402,8 @@ async function pullAsset(id, lock, options = {}) {
155328
155402
  }
155329
155403
  const destDir = options.destDir ?? assetCacheDir();
155330
155404
  const destPath = path301.join(destDir, id);
155331
- await mkdir66(destDir, { recursive: true });
155332
- await writeFile42(destPath, bytes);
155405
+ await mkdir67(destDir, { recursive: true });
155406
+ await writeFile43(destPath, bytes);
155333
155407
  return { path: destPath, sha256: actual, verified: true };
155334
155408
  }
155335
155409
  var defaultFetcher = async (url) => {
@@ -156269,7 +156343,7 @@ var init_diff = __esm(() => {
156269
156343
  });
156270
156344
 
156271
156345
  // src/sync/hooks.ts
156272
- import { chmod as chmod11, mkdir as mkdir67, readFile as readFile157, writeFile as writeFile43 } from "fs/promises";
156346
+ import { chmod as chmod11, mkdir as mkdir68, readFile as readFile157, writeFile as writeFile44 } from "fs/promises";
156273
156347
  import path303 from "path";
156274
156348
  function escapeRegExp8(value) {
156275
156349
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -156292,7 +156366,7 @@ async function writeManagedHook(projectRoot, hookName) {
156292
156366
  if (!hooksRoot) {
156293
156367
  return false;
156294
156368
  }
156295
- await mkdir67(hooksRoot, { recursive: true });
156369
+ await mkdir68(hooksRoot, { recursive: true });
156296
156370
  const hookPath = path303.join(hooksRoot, hookName);
156297
156371
  const start = `# keryx:${BLOCK_ID}:begin`;
156298
156372
  const end = `# keryx:${BLOCK_ID}:end`;
@@ -156306,7 +156380,7 @@ ${end}`;
156306
156380
 
156307
156381
  ${block}
156308
156382
  `;
156309
- await writeFile43(hookPath, next, "utf8");
156383
+ await writeFile44(hookPath, next, "utf8");
156310
156384
  await chmod11(hookPath, 493);
156311
156385
  return true;
156312
156386
  }
@@ -156326,7 +156400,7 @@ async function stripManagedHook(projectRoot, hookName) {
156326
156400
  if (!pattern.test(existing)) {
156327
156401
  return false;
156328
156402
  }
156329
- await writeFile43(hookPath, `${existing.replace(pattern, `
156403
+ await writeFile44(hookPath, `${existing.replace(pattern, `
156330
156404
  `).trimEnd()}
156331
156405
  `, "utf8");
156332
156406
  return true;
@@ -157612,7 +157686,7 @@ var init_digest_summary = __esm(() => {
157612
157686
 
157613
157687
  // src/scheduler/digest-run.ts
157614
157688
  import { randomUUID as randomUUID41 } from "crypto";
157615
- import { mkdir as mkdir68, mkdtemp as mkdtemp10, rm as rm26, writeFile as writeFile44 } from "fs/promises";
157689
+ import { mkdir as mkdir69, mkdtemp as mkdtemp10, rm as rm26, writeFile as writeFile45 } from "fs/promises";
157616
157690
  import path305 from "path";
157617
157691
  function scrubDigestReportLocator(locator, env) {
157618
157692
  const scrubbed = scrubGrantedOutput(locator, env);
@@ -157684,7 +157758,7 @@ async function runLocked2(projectRoot, entry, action, deps, runId, now) {
157684
157758
  }
157685
157759
  const scratch = await mkdtemp10(path305.join(parent.dir, `${entry.name.replace(/[^A-Za-z0-9._-]/g, "-")}-`));
157686
157760
  const grantedCwd = path305.join(scratch, "granted-cwd");
157687
- await mkdir68(grantedCwd, { recursive: true, mode: 448 });
157761
+ await mkdir69(grantedCwd, { recursive: true, mode: 448 });
157688
157762
  const limits = startLimits({ maxSeconds: dispatch.maxSeconds, memoryLimitMb: digest.memoryLimitMb }, { ...deps.armTimeout !== undefined ? { armTimeout: deps.armTimeout } : {}, ...deps.limits ?? {} });
157689
157763
  let crashed;
157690
157764
  let collected = { items: [], failures: [], failedSources: new Set, truncatedSources: new Set, raw: [], calls: [], stopped: false };
@@ -157771,9 +157845,9 @@ async function runLocked2(projectRoot, entry, action, deps, runId, now) {
157771
157845
  try {
157772
157846
  await ensureTriggerDataIgnored(projectRoot);
157773
157847
  const dir = path305.join(triggerReportsDir(projectRoot), entry.name);
157774
- await mkdir68(dir, { recursive: true });
157848
+ await mkdir69(dir, { recursive: true });
157775
157849
  const file = path305.join(dir, `${runId}.md`);
157776
- await writeFile44(file, renderDigestReport({
157850
+ await writeFile45(file, renderDigestReport({
157777
157851
  entry,
157778
157852
  runId,
157779
157853
  at: startedAt.toISOString(),
@@ -174232,7 +174306,7 @@ var init_sweep = __esm(() => {
174232
174306
  });
174233
174307
 
174234
174308
  // src/retention/auto-sweep.ts
174235
- import { mkdir as mkdir69, readFile as readFile167, rm as rm27, stat as stat35, writeFile as writeFile45 } from "fs/promises";
174309
+ import { mkdir as mkdir70, readFile as readFile167, rm as rm27, stat as stat35, writeFile as writeFile46 } from "fs/promises";
174236
174310
  import { randomUUID as randomUUID43 } from "crypto";
174237
174311
  import path322 from "path";
174238
174312
  function autoSweepStampPath(cwd) {
@@ -174285,7 +174359,7 @@ async function acquireClaim(claimPath, staleMs) {
174285
174359
  const nonce = `${process.pid}:${randomUUID43()}`;
174286
174360
  for (let attempt = 0;attempt < 2; attempt += 1) {
174287
174361
  try {
174288
- await writeFile45(claimPath, nonce, { flag: "wx", mode: 384 });
174362
+ await writeFile46(claimPath, nonce, { flag: "wx", mode: 384 });
174289
174363
  return {
174290
174364
  release: async () => {
174291
174365
  try {
@@ -174328,7 +174402,7 @@ async function maybeAutoSweepGdctx(cwd, options = {}) {
174328
174402
  }
174329
174403
  const stamp = autoSweepStampPath(cwd);
174330
174404
  try {
174331
- await mkdir69(path322.dirname(stamp), { recursive: true });
174405
+ await mkdir70(path322.dirname(stamp), { recursive: true });
174332
174406
  } catch {
174333
174407
  return { ran: false, reason: "stamp-unwritable" };
174334
174408
  }
@@ -174341,7 +174415,7 @@ async function maybeAutoSweepGdctx(cwd, options = {}) {
174341
174415
  return { ran: false, reason: "throttled" };
174342
174416
  }
174343
174417
  try {
174344
- await writeFile45(stamp, `${JSON.stringify({ startedAtMs: now, completedAtMs: null }, null, 2)}
174418
+ await writeFile46(stamp, `${JSON.stringify({ startedAtMs: now, completedAtMs: null }, null, 2)}
174345
174419
  `, "utf8");
174346
174420
  } catch {
174347
174421
  return { ran: false, reason: "stamp-unwritable" };
@@ -174351,7 +174425,7 @@ async function maybeAutoSweepGdctx(cwd, options = {}) {
174351
174425
  now
174352
174426
  });
174353
174427
  const completedAtMs = options.now ?? Date.now();
174354
- await writeFile45(stamp, `${JSON.stringify({ startedAtMs: now, completedAtMs, lastRunAtMs: completedAtMs }, null, 2)}
174428
+ await writeFile46(stamp, `${JSON.stringify({ startedAtMs: now, completedAtMs, lastRunAtMs: completedAtMs }, null, 2)}
174355
174429
  `, "utf8").catch(() => {
174356
174430
  return;
174357
174431
  });
@@ -174371,7 +174445,7 @@ var init_auto_sweep = __esm(() => {
174371
174445
 
174372
174446
  // src/ctx/artifact-id.ts
174373
174447
  import { randomBytes as randomBytes14 } from "crypto";
174374
- import { mkdir as mkdir70, readFile as readFile168, rm as rm28, writeFile as writeFile46 } from "fs/promises";
174448
+ import { mkdir as mkdir71, readFile as readFile168, rm as rm28, writeFile as writeFile47 } from "fs/promises";
174375
174449
  import path323 from "path";
174376
174450
  function pinnedClock() {
174377
174451
  const pin = process.env.KERYX_CTX_CLOCK_PIN_MS;
@@ -174397,7 +174471,7 @@ function isAlreadyExists(error) {
174397
174471
  }
174398
174472
  async function claim(file) {
174399
174473
  try {
174400
- await writeFile46(file, "", { encoding: "utf8", flag: "wx" });
174474
+ await writeFile47(file, "", { encoding: "utf8", flag: "wx" });
174401
174475
  return true;
174402
174476
  } catch (error) {
174403
174477
  if (isAlreadyExists(error)) {
@@ -174410,8 +174484,8 @@ async function reserveArtifact(options) {
174410
174484
  const now = options.now ?? pinnedClock() ?? (() => new Date);
174411
174485
  const token = options.token ?? defaultToken;
174412
174486
  const maxAttempts = options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
174413
- await mkdir70(options.rawDir, { recursive: true });
174414
- await mkdir70(options.artifactsDir, { recursive: true });
174487
+ await mkdir71(options.rawDir, { recursive: true });
174488
+ await mkdir71(options.artifactsDir, { recursive: true });
174415
174489
  for (let attempt = 0;attempt < maxAttempts; attempt += 1) {
174416
174490
  const id = artifactIdCandidate(options.kind, now(), token());
174417
174491
  const rawPath = path323.join(options.rawDir, `${id}.log`);
@@ -174584,7 +174658,7 @@ var init_structured = __esm(() => {
174584
174658
  });
174585
174659
 
174586
174660
  // src/commands/ctx.ts
174587
- import { readFile as readFile169, writeFile as writeFile47 } from "fs/promises";
174661
+ import { readFile as readFile169, writeFile as writeFile48 } from "fs/promises";
174588
174662
  import path324 from "path";
174589
174663
  function structuredBudgetBytes(config) {
174590
174664
  return (config.compactHeadLines + config.compactTailLines) * 40;
@@ -175023,8 +175097,8 @@ async function writeArtifact({
175023
175097
  ${JSON.stringify(artifact, null, 2)}
175024
175098
  \`\`\`
175025
175099
  `;
175026
- await writeFile47(rawPath, raw, "utf8");
175027
- await writeFile47(summaryPath, summaryWithMeta, "utf8");
175100
+ await writeFile48(rawPath, raw, "utf8");
175101
+ await writeFile48(summaryPath, summaryWithMeta, "utf8");
175028
175102
  await writeFileAtomic(latestRawPath, raw);
175029
175103
  await writeFileAtomic(latestSummaryPath, summaryWithMeta);
175030
175104
  await maybeAutoSweepGdctx(projectRoot).catch(() => {
@@ -175920,7 +175994,7 @@ function readLiteral(source, start, quote) {
175920
175994
  }
175921
175995
 
175922
175996
  // src/wiki/freshness/queue.ts
175923
- import { readFile as readFile170, rename as rename13, stat as stat36, unlink as unlink3, writeFile as writeFile48 } from "fs/promises";
175997
+ import { readFile as readFile170, rename as rename13, stat as stat36, unlink as unlink3, writeFile as writeFile49 } from "fs/promises";
175924
175998
  import path325 from "path";
175925
175999
  function queuePath(cwd) {
175926
176000
  return path325.join(cwd, ".metaproject", "data", "wiki", QUEUE_FILE);
@@ -176504,7 +176578,7 @@ var init_report6 = __esm(() => {
176504
176578
  });
176505
176579
 
176506
176580
  // src/wiki/freshness/run.ts
176507
- import { mkdir as mkdir71, readFile as readFile172, writeFile as writeFile49 } from "fs/promises";
176581
+ import { mkdir as mkdir72, readFile as readFile172, writeFile as writeFile50 } from "fs/promises";
176508
176582
  import path326 from "path";
176509
176583
  function freshnessDir(cwd) {
176510
176584
  return path326.join(cwd, ".metaproject", "data", "wiki", "freshness");
@@ -176550,10 +176624,10 @@ async function runFreshness(input) {
176550
176624
  }
176551
176625
  async function persist(cwd, report) {
176552
176626
  const dir = freshnessDir(cwd);
176553
- await mkdir71(dir, { recursive: true });
176554
- await writeFile49(path326.join(dir, "latest.json"), `${JSON.stringify(report, null, 2)}
176627
+ await mkdir72(dir, { recursive: true });
176628
+ await writeFile50(path326.join(dir, "latest.json"), `${JSON.stringify(report, null, 2)}
176555
176629
  `, "utf8");
176556
- await writeFile49(path326.join(dir, "latest.md"), renderMarkdown2(report), "utf8");
176630
+ await writeFile50(path326.join(dir, "latest.md"), renderMarkdown2(report), "utf8");
176557
176631
  }
176558
176632
  async function collectChanges(cwd, git, fromRev) {
176559
176633
  const status = await git(cwd, ["diff", "--name-status", "-M", fromRev, "HEAD"]);
@@ -180546,7 +180620,7 @@ var init_manifest4 = __esm(() => {
180546
180620
  });
180547
180621
 
180548
180622
  // src/gdskills/sync.ts
180549
- import { copyFile as copyFile3, mkdir as mkdir72, readdir as readdir55, writeFile as writeFile50 } from "fs/promises";
180623
+ import { copyFile as copyFile3, mkdir as mkdir73, readdir as readdir55, writeFile as writeFile51 } from "fs/promises";
180550
180624
  import path340 from "path";
180551
180625
  function isGlobalSyncRuntime(runtime) {
180552
180626
  return Object.hasOwn(GLOBAL_SKILL_SYNC_TARGETS, runtime);
@@ -180617,12 +180691,12 @@ async function syncRuntimeSkillsToRoot(projectRoot, options) {
180617
180691
  const manifestPath = path340.join(targetRoot, "keryx-sync-manifest.json");
180618
180692
  const syncedSkills = skillDirs.map((skillDir) => path340.basename(skillDir)).sort();
180619
180693
  if (!options.dryRun) {
180620
- await mkdir72(targetRoot, { recursive: true });
180694
+ await mkdir73(targetRoot, { recursive: true });
180621
180695
  for (const skillDir of skillDirs) {
180622
180696
  const targetSkillDir = path340.join(targetRoot, path340.basename(skillDir));
180623
180697
  await copyDirectory(skillDir, targetSkillDir);
180624
180698
  }
180625
- await writeFile50(manifestPath, `${JSON.stringify({
180699
+ await writeFile51(manifestPath, `${JSON.stringify({
180626
180700
  schemaVersion: 1,
180627
180701
  runtime: options.runtime,
180628
180702
  sourceRoot: toPosix(path340.relative(projectRoot, sourceRoot)),
@@ -180687,7 +180761,7 @@ async function plannedSyncFiles(projectRoot, skillDirs, sourceRoot, targetRoot)
180687
180761
  async function copyDirectory(sourceDir, targetDir) {
180688
180762
  for (const filePath of await listFiles3(sourceDir)) {
180689
180763
  const targetPath = path340.join(targetDir, path340.relative(sourceDir, filePath));
180690
- await mkdir72(path340.dirname(targetPath), { recursive: true });
180764
+ await mkdir73(path340.dirname(targetPath), { recursive: true });
180691
180765
  await copyFile3(filePath, targetPath);
180692
180766
  }
180693
180767
  }
@@ -182830,7 +182904,7 @@ var init_remove_skill = __esm(() => {
182830
182904
  });
182831
182905
 
182832
182906
  // src/gdskills/verify.ts
182833
- import { mkdir as mkdir73, readFile as readFile181, writeFile as writeFile51 } from "fs/promises";
182907
+ import { mkdir as mkdir74, readFile as readFile181, writeFile as writeFile52 } from "fs/promises";
182834
182908
  import path345 from "path";
182835
182909
  async function verifyProjectSkill(projectRoot, options) {
182836
182910
  const metaprojectRoot = path345.join(projectRoot, ".metaproject");
@@ -182876,11 +182950,11 @@ async function verifyProjectSkill(projectRoot, options) {
182876
182950
  dryRun: options.dryRun === true
182877
182951
  };
182878
182952
  if (!options.dryRun) {
182879
- await mkdir73(path345.dirname(reportPath), { recursive: true });
182880
- await writeFile51(reportPath, `${JSON.stringify(report, null, 2)}
182953
+ await mkdir74(path345.dirname(reportPath), { recursive: true });
182954
+ await writeFile52(reportPath, `${JSON.stringify(report, null, 2)}
182881
182955
  `, "utf8");
182882
- await writeFile51(path345.join(resolved.packageRoot, "verification.md"), renderVerificationMarkdown(report), "utf8");
182883
- await writeFile51(skillMdPath, updateLastVerified(skillMd, verifiedAt), "utf8");
182956
+ await writeFile52(path345.join(resolved.packageRoot, "verification.md"), renderVerificationMarkdown(report), "utf8");
182957
+ await writeFile52(skillMdPath, updateLastVerified(skillMd, verifiedAt), "utf8");
182884
182958
  }
182885
182959
  return report;
182886
182960
  }
@@ -185586,7 +185660,7 @@ var init_plans = __esm(() => {
185586
185660
  });
185587
185661
 
185588
185662
  // src/job/store.ts
185589
- import { appendFile as appendFile17, mkdir as mkdir74, readFile as readFile184, readdir as readdir61 } from "fs/promises";
185663
+ import { appendFile as appendFile17, mkdir as mkdir75, readFile as readFile184, readdir as readdir61 } from "fs/promises";
185590
185664
  import path348 from "path";
185591
185665
  function jobsRoot(cwd) {
185592
185666
  return path348.join(cwd, ".metaproject", "jobs");
@@ -185631,7 +185705,7 @@ async function writeJob(cwd, name, state) {
185631
185705
  `));
185632
185706
  }
185633
185707
  const file = jobStatePath(cwd, name);
185634
- await mkdir74(path348.dirname(file), { recursive: true });
185708
+ await mkdir75(path348.dirname(file), { recursive: true });
185635
185709
  await writeFileAtomic(file, `${JSON.stringify(state, null, 2)}
185636
185710
  `);
185637
185711
  }
@@ -185670,7 +185744,7 @@ var init_store10 = __esm(() => {
185670
185744
  });
185671
185745
 
185672
185746
  // src/job/service.ts
185673
- import { copyFile as copyFile4, mkdir as mkdir75 } from "fs/promises";
185747
+ import { copyFile as copyFile4, mkdir as mkdir76 } from "fs/promises";
185674
185748
  import path349 from "path";
185675
185749
  function createJobService(deps) {
185676
185750
  const now = () => deps.now().toISOString();
@@ -185713,7 +185787,7 @@ function createJobService(deps) {
185713
185787
  if (await pathExists(absolute)) {
185714
185788
  throw new Error(`Job package already exists: .metaproject/jobs/${name}. ` + `Run: keryx job status ${name}`);
185715
185789
  }
185716
- await mkdir75(absolute, { recursive: true });
185790
+ await mkdir76(absolute, { recursive: true });
185717
185791
  const createdAt = now();
185718
185792
  const state = {
185719
185793
  phase: "PLAN",
@@ -187383,7 +187457,7 @@ var init_retry_plan = __esm(() => {
187383
187457
 
187384
187458
  // src/commands/review-slice.ts
187385
187459
  import { existsSync as existsSync58, readFileSync as readFileSync28, statSync as statSync20 } from "fs";
187386
- import { mkdir as mkdir76, readFile as readFile188, readdir as readdir63, rm as rm29 } from "fs/promises";
187460
+ import { mkdir as mkdir77, readFile as readFile188, readdir as readdir63, rm as rm29 } from "fs/promises";
187387
187461
  import path351 from "path";
187388
187462
  function wantsHelp2(args) {
187389
187463
  return args.includes("--help") || args.includes("-h");
@@ -187441,7 +187515,7 @@ Attempts are remembered in ${RETRY_STATE_NAME} beside the manifest (--state to m
187441
187515
  `);
187442
187516
  }
187443
187517
  async function writeSliceFiles(dir, slices) {
187444
- await mkdir76(dir, { recursive: true });
187518
+ await mkdir77(dir, { recursive: true });
187445
187519
  for (const slice of slices) {
187446
187520
  await writeFileAtomic(path351.join(dir, slice.path), slice.text);
187447
187521
  }
@@ -187460,7 +187534,7 @@ async function runSlice(args, deps) {
187460
187534
  const outDir = path351.resolve(optionValue(args, "--out") ?? DEFAULT_SLICE_DIR);
187461
187535
  const diff = diffFile !== undefined ? await deps.readDiffSource(diffFile) : await deps.gitDiff(ref, contextLines);
187462
187536
  const { manifest, slices } = buildSlices(sliceSourceFromDiff(diff, { contextLines }), { maxBytes });
187463
- await mkdir76(outDir, { recursive: true });
187537
+ await mkdir77(outDir, { recursive: true });
187464
187538
  for (const entry of await readdir63(outDir)) {
187465
187539
  if (/^slice-\d+\.diff$/.test(entry)) {
187466
187540
  await rm29(path351.join(outDir, entry), { force: true });
@@ -188935,7 +189009,7 @@ var init_floor = __esm(() => {
188935
189009
  });
188936
189010
 
188937
189011
  // src/commands/review.ts
188938
- import { mkdir as mkdir77, readdir as readdir64, readFile as readFile192 } from "fs/promises";
189012
+ import { mkdir as mkdir78, readdir as readdir64, readFile as readFile192 } from "fs/promises";
188939
189013
  import path356, { join as join11 } from "path";
188940
189014
  function reviewerList(args) {
188941
189015
  return (optionValue(args, "--reviewers") ?? "").split(",").map((item) => item.trim()).filter(Boolean);
@@ -190245,7 +190319,7 @@ async function runLearn(args) {
190245
190319
  const sourcePath = learningSourcePath(cwd, config.repo, number);
190246
190320
  const recordPath = learningRecordPath(cwd, config.repo, number);
190247
190321
  const relativeSourcePath = toPosix(path356.relative(cwd, sourcePath));
190248
- await mkdir77(path356.dirname(sourcePath), { recursive: true });
190322
+ await mkdir78(path356.dirname(sourcePath), { recursive: true });
190249
190323
  await writeFileAtomic(sourcePath, renderLearningSource(selection));
190250
190324
  await writeFileAtomic(recordPath, renderLearningRecord({
190251
190325
  repo: config.repo,
@@ -191876,7 +191950,7 @@ function classifyBaselineStatuses(baseline, pr) {
191876
191950
  }
191877
191951
 
191878
191952
  // src/commands/standard.ts
191879
- import { mkdir as mkdir78, writeFile as writeFile52 } from "fs/promises";
191953
+ import { mkdir as mkdir79, writeFile as writeFile53 } from "fs/promises";
191880
191954
  import path359 from "path";
191881
191955
  async function standardCommand(args = [], projectRoot = process.cwd()) {
191882
191956
  const subcommand = args[0];
@@ -191987,8 +192061,8 @@ async function handleEmit(projectRoot, args) {
191987
192061
  if (args.includes("--stdout")) {
191988
192062
  process.stdout.write(result.content);
191989
192063
  } else {
191990
- await mkdir78(path359.dirname(result.path), { recursive: true });
191991
- await writeFile52(result.path, result.content, "utf8");
192064
+ await mkdir79(path359.dirname(result.path), { recursive: true });
192065
+ await writeFile53(result.path, result.content, "utf8");
191992
192066
  heading("keryx standard emit llms");
191993
192067
  if (problems.length === 0) {
191994
192068
  console.log(` ${style.green(symbols.ok)} wrote ${path359.relative(projectRoot, result.path)} (valid llms.txt)`);
@@ -194732,7 +194806,7 @@ var init_security_impact_evidence = __esm(() => {
194732
194806
  });
194733
194807
 
194734
194808
  // src/commands/security.ts
194735
- import { mkdir as mkdir79, readdir as readdir66, readFile as readFile195, writeFile as writeFile53 } from "fs/promises";
194809
+ import { mkdir as mkdir80, readdir as readdir66, readFile as readFile195, writeFile as writeFile54 } from "fs/promises";
194736
194810
  import path363 from "path";
194737
194811
  import { fileURLToPath as fileURLToPath10 } from "url";
194738
194812
  async function securityCommand(args = [], cwd = process.cwd()) {
@@ -195015,8 +195089,8 @@ async function handleScanMcp(cwd, args) {
195015
195089
  const { manifest } = extractManifestAndBaseline(read.value, {});
195016
195090
  const baseline = { schemaVersion: 1, tools: buildMcpBaseline(manifest) };
195017
195091
  const outPath = mcpBaselinePath(cwd);
195018
- await mkdir79(path363.dirname(outPath), { recursive: true });
195019
- await writeFile53(outPath, `${JSON.stringify(baseline, null, 2)}
195092
+ await mkdir80(path363.dirname(outPath), { recursive: true });
195093
+ await writeFile54(outPath, `${JSON.stringify(baseline, null, 2)}
195020
195094
  `, "utf8");
195021
195095
  if (asJson) {
195022
195096
  console.log(JSON.stringify({ pinned: Object.keys(baseline.tools).length, path: outPath }, null, 2));
@@ -195138,7 +195212,7 @@ async function handleRedact(cwd, args) {
195138
195212
  source
195139
195213
  });
195140
195214
  if (out) {
195141
- await writeFile53(out, redacted, "utf8");
195215
+ await writeFile54(out, redacted, "utf8");
195142
195216
  heading("keryx security redact");
195143
195217
  console.log(` ${style.green(symbols.ok)} redacted ${findings.length} span(s) \u2192 ${out}`);
195144
195218
  } else {
@@ -196399,7 +196473,7 @@ var init_metaproject_tools2 = __esm(() => {
196399
196473
  });
196400
196474
 
196401
196475
  // src/mcp/tools.ts
196402
- import { readFile as readFile196, realpath as realpath24, writeFile as writeFile54 } from "fs/promises";
196476
+ import { readFile as readFile196, realpath as realpath24, writeFile as writeFile55 } from "fs/promises";
196403
196477
  import path365 from "path";
196404
196478
  import { randomUUID as randomUUID44 } from "crypto";
196405
196479
  function sacWorkspaceService(cwd) {
@@ -196545,7 +196619,7 @@ function buildToolRegistry() {
196545
196619
  const wrapUp = await wrapUpAuthority.issue({ actor, source: "session", sourceRef: sessionEvidenceRef(workspaceId, session.id) });
196546
196620
  const proposal = await service.create({ request: undefined, requestCorrelationId, workspaceId, id: `proposal-${randomUUID44().replace(/-/g, "").slice(0, 16)}`, proposalRevision, kind, wrapUp });
196547
196621
  if (note)
196548
- await writeFile54(proposalNotePath(cwd, workspaceId, proposal.id), note, "utf8");
196622
+ await writeFile55(proposalNotePath(cwd, workspaceId, proposal.id), note, "utf8");
196549
196623
  return normalizeProposalLifecycleResult(proposal);
196550
196624
  }
196551
196625
  },
@@ -213287,7 +213361,7 @@ var PROBE_TIMEOUT_MS = 1e4;
213287
213361
 
213288
213362
  // src/commands/agents-external.ts
213289
213363
  import { randomUUID as randomUUID56 } from "crypto";
213290
- import { mkdir as mkdir80 } from "fs/promises";
213364
+ import { mkdir as mkdir81 } from "fs/promises";
213291
213365
  import { tmpdir as tmpdir16 } from "os";
213292
213366
  import path386 from "path";
213293
213367
  import { createInterface as createInterface4 } from "readline";
@@ -213560,7 +213634,7 @@ async function runCommand4(args, deps, log) {
213560
213634
  const worktreesDir = path386.join(tmpdir16(), "keryx-external-worktrees");
213561
213635
  const worktree = seams.worktree ?? createGitWorktreePort({ repoRoot: cwd, worktreesDir });
213562
213636
  if (seams.worktree === undefined)
213563
- await mkdir80(worktreesDir, { recursive: true });
213637
+ await mkdir81(worktreesDir, { recursive: true });
213564
213638
  const detect = seams.detect === null ? undefined : seams.detect ?? createVersionProbe();
213565
213639
  const runInput = {
213566
213640
  runtime: {
@@ -215535,7 +215609,7 @@ function factPreservation(rawFacts, compactFacts) {
215535
215609
  }
215536
215610
 
215537
215611
  // src/metrics/oracle-runner.ts
215538
- import { mkdir as mkdir81, writeFile as writeFile55 } from "fs/promises";
215612
+ import { mkdir as mkdir82, writeFile as writeFile56 } from "fs/promises";
215539
215613
  import path388 from "path";
215540
215614
  function oracleTaskId(target) {
215541
215615
  return `metastore:gdgraph-affected:${target}`;
@@ -215858,8 +215932,8 @@ async function persistEvidenceBundle(outDir, bundle, ladder = "metastore") {
215858
215932
  const safeTarget = bundle.target.replace(/[^A-Za-z0-9._/-]/g, "_");
215859
215933
  const safeCase = bundle.caseId.replace(/[^A-Za-z0-9._-]/g, "_");
215860
215934
  const dir = path388.join(outDir, "bench", ladder, safeTarget, safeCase, bundle.variant, String(bundle.seed));
215861
- await mkdir81(dir, { recursive: true });
215862
- const write = (name, value) => writeFile55(path388.join(dir, name), `${JSON.stringify(value, null, 2)}
215935
+ await mkdir82(dir, { recursive: true });
215936
+ const write = (name, value) => writeFile56(path388.join(dir, name), `${JSON.stringify(value, null, 2)}
215863
215937
  `, "utf8");
215864
215938
  await Promise.all([
215865
215939
  write("inputs.json", bundle.inputs),
@@ -216583,7 +216657,7 @@ function formatFwkExplain(result) {
216583
216657
 
216584
216658
  // src/commands/workspace.ts
216585
216659
  import { randomUUID as randomUUID57 } from "crypto";
216586
- import { writeFile as writeFile56 } from "fs/promises";
216660
+ import { writeFile as writeFile57 } from "fs/promises";
216587
216661
  function service8() {
216588
216662
  return new WorkspaceService({
216589
216663
  workspaceRoot: process.cwd(),
@@ -216724,7 +216798,7 @@ async function workspaceCommand(args) {
216724
216798
  const wrapUp = await wrapUpAuthority.issue({ actor, source: "session", sourceRef: sessionEvidenceRef(workspaceId, session.id) });
216725
216799
  const proposal = await service.create({ request: undefined, requestCorrelationId, workspaceId, id: proposalId, proposalRevision, kind, wrapUp });
216726
216800
  if (persistedNote)
216727
- await writeFile56(notePath, persistedNote, "utf8");
216801
+ await writeFile57(notePath, persistedNote, "utf8");
216728
216802
  console.log(JSON.stringify(normalizeProposalLifecycleResult(proposal), null, 2));
216729
216803
  return;
216730
216804
  }
@@ -221044,7 +221118,7 @@ var init_learned_pattern_schema = __esm(() => {
221044
221118
 
221045
221119
  // src/bundle/export.ts
221046
221120
  import { execFileSync as execFileSync3 } from "child_process";
221047
- import { mkdir as mkdir82, readdir as readdir71, readFile as readFile205, writeFile as writeFile57, lstat as lstat24 } from "fs/promises";
221121
+ import { mkdir as mkdir83, readdir as readdir71, readFile as readFile205, writeFile as writeFile58, lstat as lstat24 } from "fs/promises";
221048
221122
  import { existsSync as existsSync62 } from "fs";
221049
221123
  import path395 from "path";
221050
221124
  function globToRegExp5(glob) {
@@ -221279,12 +221353,12 @@ async function outDirIsEmpty(out) {
221279
221353
  }
221280
221354
  }
221281
221355
  async function writeDirectoryBundle(out, manifestBytes, files) {
221282
- await mkdir82(out, { recursive: true });
221283
- await writeFile57(path395.join(out, "bundle.json"), manifestBytes);
221356
+ await mkdir83(out, { recursive: true });
221357
+ await writeFile58(path395.join(out, "bundle.json"), manifestBytes);
221284
221358
  for (const [rel, bytes] of files) {
221285
221359
  const abs = path395.join(out, ...rel.split("/"));
221286
- await mkdir82(path395.dirname(abs), { recursive: true });
221287
- await writeFile57(abs, bytes);
221360
+ await mkdir83(path395.dirname(abs), { recursive: true });
221361
+ await writeFile58(abs, bytes);
221288
221362
  }
221289
221363
  }
221290
221364
  async function exportBundle(opts) {
@@ -221417,8 +221491,8 @@ async function exportBundle(opts) {
221417
221491
  const archive = buildBundleArchive(files, manifestBytes);
221418
221492
  if (!archive.ok)
221419
221493
  return { ok: false, refusals: [archive.refusal] };
221420
- await mkdir82(path395.dirname(opts.out), { recursive: true });
221421
- await writeFile57(opts.out, archive.value);
221494
+ await mkdir83(path395.dirname(opts.out), { recursive: true });
221495
+ await writeFile58(opts.out, archive.value);
221422
221496
  } else {
221423
221497
  if (existsSync62(opts.out) && !await outDirIsEmpty(opts.out)) {
221424
221498
  return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.notABundle, message: `${opts.out} already exists and is not empty` }] };
@@ -221601,7 +221675,7 @@ var init_applied_state = __esm(() => {
221601
221675
  });
221602
221676
 
221603
221677
  // src/lib/private-dir.ts
221604
- import { lstat as lstat25, mkdir as mkdir83, open as open11, readFile as readFile207 } from "fs/promises";
221678
+ import { lstat as lstat25, mkdir as mkdir84, open as open11, readFile as readFile207 } from "fs/promises";
221605
221679
  import path397 from "path";
221606
221680
  async function checkPrivateDirGitignore(dir, root) {
221607
221681
  if (root !== undefined) {
@@ -221691,7 +221765,7 @@ async function ensurePrivateDirGitignore(dir, root) {
221691
221765
  return check;
221692
221766
  }
221693
221767
  const gitignorePath = path397.join(dir, ".gitignore");
221694
- await mkdir83(dir, { recursive: true });
221768
+ await mkdir84(dir, { recursive: true });
221695
221769
  try {
221696
221770
  const handle = await open11(gitignorePath, "wx");
221697
221771
  try {
@@ -222106,7 +222180,7 @@ var init_plan2 = __esm(() => {
222106
222180
  });
222107
222181
 
222108
222182
  // src/bundle/audit.ts
222109
- import { mkdtemp as mkdtemp11, mkdir as mkdir84, rm as rm30, writeFile as writeFile58 } from "fs/promises";
222183
+ import { mkdtemp as mkdtemp11, mkdir as mkdir85, rm as rm30, writeFile as writeFile59 } from "fs/promises";
222110
222184
  import { tmpdir as tmpdir17 } from "os";
222111
222185
  import path398 from "path";
222112
222186
  function entriesToStage(plan) {
@@ -222123,8 +222197,8 @@ async function auditBundlePlan(plan, opts = {}) {
222123
222197
  try {
222124
222198
  for (const entry of toStage) {
222125
222199
  const abs = path398.join(stagingDir, ...entry.path.split("/"));
222126
- await mkdir84(path398.dirname(abs), { recursive: true });
222127
- await writeFile58(abs, entry.bytes);
222200
+ await mkdir85(path398.dirname(abs), { recursive: true });
222201
+ await writeFile59(abs, entry.bytes);
222128
222202
  }
222129
222203
  } catch (err) {
222130
222204
  return {
@@ -222157,7 +222231,7 @@ var init_audit = __esm(() => {
222157
222231
  });
222158
222232
 
222159
222233
  // src/bundle/apply.ts
222160
- import { mkdir as mkdir85, rmdir as rmdir2, stat as stat42 } from "fs/promises";
222234
+ import { mkdir as mkdir86, rmdir as rmdir2, stat as stat42 } from "fs/promises";
222161
222235
  import path399 from "path";
222162
222236
  function writableEntries(plan) {
222163
222237
  return plan.entries.filter((e) => e.bucket === "new" || e.bucket === "update" || e.bucket === "conflict" && e.forced);
@@ -222326,7 +222400,7 @@ async function mkdirRecordingCreated(dir) {
222326
222400
  }
222327
222401
  }
222328
222402
  if (missing.length > 0) {
222329
- await mkdir85(dir, { recursive: true });
222403
+ await mkdir86(dir, { recursive: true });
222330
222404
  }
222331
222405
  return missing;
222332
222406
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.3.89",
3
+ "version": "0.3.91",
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