@mrciphersmith/keryx 0.3.64 → 0.3.66

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.
Files changed (2) hide show
  1. package/dist/cli.js +851 -315
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -20107,7 +20107,7 @@ var package_default;
20107
20107
  var init_package = __esm(() => {
20108
20108
  package_default = {
20109
20109
  name: "@mrciphersmith/keryx",
20110
- version: "0.3.64",
20110
+ version: "0.3.66",
20111
20111
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
20112
20112
  private: false,
20113
20113
  publishConfig: {
@@ -88435,6 +88435,58 @@ var MAX_TEXT_LENGTH = 300;
88435
88435
  function emptyTally() {
88436
88436
  return { answered: 0, matched: 0 };
88437
88437
  }
88438
+ function median(values) {
88439
+ if (values.length === 0)
88440
+ return null;
88441
+ const sorted = [...values].sort((a, b) => a - b);
88442
+ const mid = Math.floor(sorted.length / 2);
88443
+ const low = sorted[mid - 1] ?? 0;
88444
+ const high = sorted[mid] ?? 0;
88445
+ return sorted.length % 2 === 1 ? high : Math.round((low + high) / 2);
88446
+ }
88447
+ function buildBackfilled(history, firstAnswer, reasons) {
88448
+ const out = {
88449
+ total: history.length,
88450
+ answered: 0,
88451
+ withRecommendation: 0,
88452
+ withoutRecommendation: 0,
88453
+ matchTally: emptyTally(),
88454
+ matchShare: null,
88455
+ deviations: []
88456
+ };
88457
+ for (const open of history) {
88458
+ if (open.recommendation === null)
88459
+ out.withoutRecommendation += 1;
88460
+ else
88461
+ out.withRecommendation += 1;
88462
+ const first = firstAnswer(open.id);
88463
+ if (first === undefined)
88464
+ continue;
88465
+ out.answered += 1;
88466
+ if (open.recommendation === null)
88467
+ continue;
88468
+ out.matchTally.answered += 1;
88469
+ if (first.choice === open.recommendation.optionId) {
88470
+ out.matchTally.matched += 1;
88471
+ continue;
88472
+ }
88473
+ const reason = reasons.get(open.id)?.reason;
88474
+ out.deviations.push({
88475
+ id: open.id,
88476
+ flow: open.flow,
88477
+ stage: open.stage,
88478
+ mode: open.mode,
88479
+ question: open.question,
88480
+ recommended: open.recommendation.optionId,
88481
+ chose: first.choice,
88482
+ changed: false,
88483
+ ...open.source !== undefined ? { source: open.source } : {},
88484
+ ...reason !== undefined ? { reason } : {}
88485
+ });
88486
+ }
88487
+ out.matchShare = out.matchTally.answered === 0 ? null : out.matchTally.matched / out.matchTally.answered;
88488
+ return out;
88489
+ }
88438
88490
  function buildReport2(records, skipped = 0) {
88439
88491
  const opens = [];
88440
88492
  const answers = new Map;
@@ -88454,8 +88506,11 @@ function buildReport2(records, skipped = 0) {
88454
88506
  reasons.set(record.id, record);
88455
88507
  }
88456
88508
  }
88509
+ const live = opens.filter((open) => open.backfilled !== true);
88510
+ const history = opens.filter((open) => open.backfilled === true);
88511
+ const firstAnswer = (id) => [...answers.get(id) ?? []].sort((a, b) => a.seq - b.seq)[0];
88457
88512
  const report = {
88458
- total: opens.length,
88513
+ total: live.length,
88459
88514
  answered: 0,
88460
88515
  unanswered: 0,
88461
88516
  withoutRecommendation: 0,
@@ -88463,9 +88518,11 @@ function buildReport2(records, skipped = 0) {
88463
88518
  byMode: { ordinary: emptyTally(), blind: emptyTally() },
88464
88519
  byStage: [],
88465
88520
  deviations: [],
88466
- irreversible: opens.filter((open) => open.irreversible).length,
88467
- blindRefused: opens.filter((open) => open.blindRefused === true).length,
88468
- inferredFlow: opens.filter((open) => open.flow !== null && open.flowSource === "inferred").length,
88521
+ irreversible: live.filter((open) => open.irreversible).length,
88522
+ blindRefused: live.filter((open) => open.blindRefused === true).length,
88523
+ inferredFlow: live.filter((open) => open.flow !== null && open.flowSource === "inferred").length,
88524
+ timing: { answered: 0, medianMs: null },
88525
+ backfilled: buildBackfilled(history, firstAnswer, reasons),
88469
88526
  skipped
88470
88527
  };
88471
88528
  const stages = new Map;
@@ -88474,7 +88531,8 @@ function buildReport2(records, skipped = 0) {
88474
88531
  stages.set(name, found);
88475
88532
  return found;
88476
88533
  };
88477
- for (const open of opens) {
88534
+ const times = [];
88535
+ for (const open of live) {
88478
88536
  if (open.blindRefused === true)
88479
88537
  stageOf(open.stage).blindRefused += 1;
88480
88538
  const list = (answers.get(open.id) ?? []).sort((a, b) => a.seq - b.seq);
@@ -88484,6 +88542,7 @@ function buildReport2(records, skipped = 0) {
88484
88542
  continue;
88485
88543
  }
88486
88544
  report.answered += 1;
88545
+ times.push(first.timeToAnswerMs);
88487
88546
  if (list.length > 1)
88488
88547
  report.changed += 1;
88489
88548
  if (open.recommendation === null) {
@@ -88513,6 +88572,7 @@ function buildReport2(records, skipped = 0) {
88513
88572
  });
88514
88573
  }
88515
88574
  }
88575
+ report.timing = { answered: times.length, medianMs: median(times) };
88516
88576
  report.byStage = [...stages.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([stage, tallies]) => ({ stage, ...tallies }));
88517
88577
  return report;
88518
88578
  }
@@ -88521,14 +88581,45 @@ function share(tally) {
88521
88581
  return "n/a";
88522
88582
  return `${Math.round(tally.matched / tally.answered * 100)}% (${tally.matched}/${tally.answered})`;
88523
88583
  }
88584
+ function backfilledShare(report) {
88585
+ if (report.matchTally.answered === 0)
88586
+ return "n/a";
88587
+ return `${Math.round(report.matchTally.matched / report.matchTally.answered * 100)}% (${report.matchTally.matched}/${report.matchTally.answered})`;
88588
+ }
88589
+ function renderBackfilled(report) {
88590
+ const lines = [
88591
+ "\u0414\u043E (\u0438\u0441\u0442\u043E\u0440\u0438\u0447\u0435\u0441\u043A\u043E\u0435, \u0434\u043E\u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u043E \u0437\u0430\u0434\u043D\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C):",
88592
+ ` \u0432\u0441\u0435\u0433\u043E: ${report.total}, \u0441 \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u0435\u0439: ${report.withRecommendation}, \u0441\u043E\u0432\u043F\u0430\u0434\u0435\u043D\u0438\u0435: ${backfilledShare(report)}`,
88593
+ ` \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u0438\u0439: ${report.deviations.length}`
88594
+ ];
88595
+ for (const dev of report.deviations) {
88596
+ const where = [dev.source === undefined ? undefined : oneLine2(dev.source), dev.flow === null ? "project" : `flow ${oneLine2(dev.flow)}`, oneLine2(dev.stage)].filter((part) => part !== undefined);
88597
+ lines.push(` ${oneLine2(dev.id)} [${where.join(", ")}]`);
88598
+ lines.push(` ${oneLine2(dev.question)}`);
88599
+ lines.push(` \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u043E\u0432\u0430\u043D\u043E ${oneLine2(dev.recommended)}, \u0432\u044B\u0431\u0440\u0430\u043D\u043E ${oneLine2(dev.chose)}`);
88600
+ lines.push(` \u043F\u0440\u0438\u0447\u0438\u043D\u0430: ${dev.reason === undefined ? "(\u043D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D\u0430)" : oneLine2(dev.reason)}`);
88601
+ }
88602
+ return lines;
88603
+ }
88604
+ function seconds(ms) {
88605
+ return `${(ms / 1000).toFixed(1)}s`;
88606
+ }
88524
88607
  function renderReport(report) {
88525
88608
  const skippedLine = report.skipped > 0 ? `Skipped ${report.skipped} unreadable journal record${report.skipped === 1 ? "" : "s"}.` : undefined;
88526
- if (report.total === 0)
88609
+ if (report.total === 0 && report.backfilled.total === 0)
88527
88610
  return skippedLine === undefined ? "No decisions recorded yet." : `No decisions recorded yet.
88528
88611
  ${skippedLine}`;
88612
+ if (report.total === 0) {
88613
+ const lines = ["No live decisions recorded yet.", "", ...renderBackfilled(report.backfilled)];
88614
+ if (skippedLine !== undefined)
88615
+ lines.push("", skippedLine);
88616
+ return lines.join(`
88617
+ `);
88618
+ }
88529
88619
  const lines = [
88530
88620
  `Decisions: ${report.total} recorded, ${report.answered} answered, ${report.unanswered} not answered yet`,
88531
88621
  `Changed after the reveal: ${report.changed}. Without a recommendation: ${report.withoutRecommendation}.`,
88622
+ ...report.timing.medianMs === null ? [] : [`Median time to answer: ${seconds(report.timing.medianMs)} (${report.timing.answered} answered).`],
88532
88623
  "",
88533
88624
  "Match with the recommendation, by mode (first answer):",
88534
88625
  ` ordinary ${share(report.byMode.ordinary)}`,
@@ -88555,15 +88646,27 @@ ${skippedLine}`;
88555
88646
  if (report.inferredFlow > 0) {
88556
88647
  lines.push("", `Flow attribution inferred (the one flow in progress, not named by KERYX_FLOW or the branch): ${report.inferredFlow} decision${report.inferredFlow === 1 ? "" : "s"}.`);
88557
88648
  }
88649
+ if (report.backfilled.total > 0)
88650
+ lines.push("", ...renderBackfilled(report.backfilled));
88558
88651
  if (skippedLine !== undefined)
88559
88652
  lines.push("", skippedLine);
88560
88653
  return lines.join(`
88561
88654
  `);
88562
88655
  }
88656
+ function percent(tally) {
88657
+ if (tally.answered === 0)
88658
+ return "\u043D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445";
88659
+ return `${Math.round(tally.matched / tally.answered * 100)}% (${tally.matched}/${tally.answered})`;
88660
+ }
88661
+ function renderReportLine(report) {
88662
+ const all = report.total + report.backfilled.total;
88663
+ return `\u0416\u0443\u0440\u043D\u0430\u043B \u0440\u0435\u0448\u0435\u043D\u0438\u0439: \u0432\u0441\u0435\u0433\u043E ${all} (\u0434\u043E: ${report.backfilled.total}, \u043F\u043E\u0441\u043B\u0435: ${report.total}). ` + `\u0421\u043E\u0432\u043F\u0430\u0434\u0435\u043D\u0438\u0435 \u0441 \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u0435\u0439: \u0432\u0438\u0434\u0438\u043C\u0430\u044F ${percent(report.byMode.ordinary)}, \u0441\u043A\u0440\u044B\u0442\u0430\u044F ${percent(report.byMode.blind)}; ` + `\u0434\u043E: ${percent(report.backfilled.matchTally)}.`;
88664
+ }
88563
88665
  var init_report4 = () => {};
88564
88666
 
88565
88667
  // src/decisions/store.ts
88566
- import { appendFile as appendFile11, mkdir as mkdir52, readFile as readFile102 } from "fs/promises";
88668
+ import { randomUUID as randomUUID23 } from "crypto";
88669
+ import { appendFile as appendFile11, mkdir as mkdir52, open as open9, readFile as readFile102, rename as rename10, rm as rm13, stat as stat24 } from "fs/promises";
88567
88670
  import path211 from "path";
88568
88671
  async function journalRoot(cwd) {
88569
88672
  const cached = rootCache.get(cwd);
@@ -88594,6 +88697,102 @@ async function appendRecord(cwd, record) {
88594
88697
  await appendFile11(journalFile(root), `${JSON.stringify(record)}
88595
88698
  `, { encoding: "utf8", mode: 384 });
88596
88699
  }
88700
+ async function endsWithoutNewline2(file) {
88701
+ try {
88702
+ const text = await readFile102(file, "utf8");
88703
+ return text.length > 0 && !text.endsWith(`
88704
+ `);
88705
+ } catch {
88706
+ return false;
88707
+ }
88708
+ }
88709
+ async function appendRecords(cwd, records) {
88710
+ if (records.length === 0)
88711
+ return;
88712
+ const root = await journalRoot(cwd);
88713
+ await mkdir52(decisionsDir(root), { recursive: true });
88714
+ const file = journalFile(root);
88715
+ const lead = await endsWithoutNewline2(file) ? `
88716
+ ` : "";
88717
+ await appendFile11(file, lead + records.map((record) => `${JSON.stringify(record)}
88718
+ `).join(""), { encoding: "utf8", mode: 384 });
88719
+ }
88720
+ function journalLockFile(root) {
88721
+ return `${journalFile(root)}.lock`;
88722
+ }
88723
+ function pidAlive(pid) {
88724
+ try {
88725
+ process.kill(pid, 0);
88726
+ return true;
88727
+ } catch (error) {
88728
+ return error.code === "EPERM";
88729
+ }
88730
+ }
88731
+ async function lockIsStale(file, staleMs) {
88732
+ let mtimeMs;
88733
+ try {
88734
+ mtimeMs = (await stat24(file)).mtimeMs;
88735
+ } catch {
88736
+ return false;
88737
+ }
88738
+ if (Date.now() - mtimeMs > staleMs)
88739
+ return true;
88740
+ try {
88741
+ const pid = JSON.parse(await readFile102(file, "utf8")).pid;
88742
+ return typeof pid === "number" && !pidAlive(pid);
88743
+ } catch {
88744
+ return false;
88745
+ }
88746
+ }
88747
+ async function ownsLock2(file, token) {
88748
+ try {
88749
+ return JSON.parse(await readFile102(file, "utf8")).token === token;
88750
+ } catch {
88751
+ return false;
88752
+ }
88753
+ }
88754
+ async function withJournalLock(cwd, fn, options = {}) {
88755
+ const staleMs = options.staleMs ?? JOURNAL_LOCK_STALE_MS;
88756
+ const timeoutMs = options.timeoutMs ?? JOURNAL_LOCK_TIMEOUT_MS;
88757
+ const pollMs = options.pollMs ?? 25;
88758
+ const root = await journalRoot(cwd);
88759
+ await mkdir52(decisionsDir(root), { recursive: true });
88760
+ const file = journalLockFile(root);
88761
+ const token = randomUUID23();
88762
+ const deadline = Date.now() + timeoutMs;
88763
+ for (;; ) {
88764
+ try {
88765
+ const handle = await open9(file, "wx", 384);
88766
+ try {
88767
+ await handle.writeFile(JSON.stringify({ pid: process.pid, at: new Date().toISOString(), token }));
88768
+ } finally {
88769
+ await handle.close();
88770
+ }
88771
+ break;
88772
+ } catch (error) {
88773
+ if (error.code !== "EEXIST")
88774
+ throw error;
88775
+ }
88776
+ if (await lockIsStale(file, staleMs)) {
88777
+ const aside = `${file}.stale-${process.pid}-${Date.now()}`;
88778
+ try {
88779
+ await rename10(file, aside);
88780
+ await rm13(aside, { force: true });
88781
+ } catch {}
88782
+ continue;
88783
+ }
88784
+ if (Date.now() >= deadline) {
88785
+ throw new Error(`the decisions journal is locked by another run (${file}); try again, or delete that file if no import is running`);
88786
+ }
88787
+ await new Promise((resolve) => setTimeout(resolve, pollMs));
88788
+ }
88789
+ try {
88790
+ return await fn();
88791
+ } finally {
88792
+ if (await ownsLock2(file, token))
88793
+ await rm13(file, { force: true });
88794
+ }
88795
+ }
88597
88796
  function isOption(value) {
88598
88797
  if (value === null || typeof value !== "object")
88599
88798
  return false;
@@ -88669,7 +88868,7 @@ async function readJournal(cwd) {
88669
88868
  async function readRecords(cwd) {
88670
88869
  return (await readJournal(cwd)).records;
88671
88870
  }
88672
- var rootCache, isString2 = (value) => typeof value === "string";
88871
+ var rootCache, JOURNAL_LOCK_STALE_MS = 60000, JOURNAL_LOCK_TIMEOUT_MS = 15000, isString2 = (value) => typeof value === "string";
88673
88872
  var init_store6 = __esm(() => {
88674
88873
  init_git_worktrees();
88675
88874
  rootCache = new Map;
@@ -88935,6 +89134,8 @@ async function answerDecision(input) {
88935
89134
  const open = records.find((r) => r.kind === "open" && r.id === input.id);
88936
89135
  if (open === undefined)
88937
89136
  throw new Error(`no open decision with id ${input.id}`);
89137
+ if (open.backfilled === true)
89138
+ throw new Error(`decision ${open.id} is a backfilled historical record; its answer is not changed`);
88938
89139
  const other = input.other === true;
88939
89140
  const choice = other ? oneLine2(input.choice) : input.choice.trim();
88940
89141
  if (choice.length === 0)
@@ -88979,8 +89180,11 @@ async function answerDecision(input) {
88979
89180
  }
88980
89181
  async function recordReason(cwd, id, text, now = () => new Date, options = {}) {
88981
89182
  const records = await readRecords(cwd);
88982
- if (!records.some((r) => r.kind === "open" && r.id === id))
89183
+ const open = records.find((r) => r.kind === "open" && r.id === id);
89184
+ if (open === undefined)
88983
89185
  throw new Error(`no open decision with id ${id}`);
89186
+ if (open.backfilled === true)
89187
+ throw new Error(`decision ${id} is a backfilled historical record; its reason is not changed`);
88984
89188
  if (options.replace !== true && records.some((r) => r.kind === "reason" && r.id === id))
88985
89189
  return false;
88986
89190
  const reason = text === undefined ? "" : oneLine2(text);
@@ -89116,6 +89320,244 @@ var init_ask2 = __esm(() => {
89116
89320
  init_journal2();
89117
89321
  });
89118
89322
 
89323
+ // src/decisions/import.ts
89324
+ function parseEntry3(raw) {
89325
+ if (!isObject(raw))
89326
+ return "a decision must be a JSON object";
89327
+ const id = raw["id"];
89328
+ if (!isString3(id) || id.trim().length === 0)
89329
+ return "needs a non-empty string id";
89330
+ const at = raw["at"];
89331
+ if (!isString3(at) || !Number.isFinite(Date.parse(at)))
89332
+ return `${id}: "at" must be an ISO date`;
89333
+ const flow = raw["flow"] === undefined ? null : raw["flow"];
89334
+ if (flow !== null && !isString3(flow))
89335
+ return `${id}: "flow" must be a string or null`;
89336
+ const stageRaw = raw["stage"];
89337
+ if (stageRaw !== undefined && !isString3(stageRaw))
89338
+ return `${id}: "stage" must be a string`;
89339
+ const question = raw["question"];
89340
+ if (!isString3(question) || oneLine2(question).length === 0)
89341
+ return `${id}: needs a question`;
89342
+ const optionsRaw = raw["options"];
89343
+ if (!Array.isArray(optionsRaw) || optionsRaw.length < 2)
89344
+ return `${id}: needs at least two options`;
89345
+ const options = [];
89346
+ const ids = new Set;
89347
+ for (const item of optionsRaw) {
89348
+ if (!isObject(item) || !isString3(item["id"]) || item["id"].trim().length === 0)
89349
+ return `${id}: every option needs an id`;
89350
+ const optionId = item["id"];
89351
+ if (ids.has(optionId))
89352
+ return `${id}: duplicate option id: ${optionId}`;
89353
+ ids.add(optionId);
89354
+ const label = isString3(item["label"]) && item["label"].length > 0 ? item["label"] : optionId;
89355
+ options.push({ id: optionId, label, ...isString3(item["description"]) && item["description"].length > 0 ? { description: item["description"] } : {} });
89356
+ }
89357
+ let recommendation = null;
89358
+ const recRaw = raw["recommendation"];
89359
+ if (recRaw !== undefined && recRaw !== null) {
89360
+ if (!isObject(recRaw) || !isString3(recRaw["optionId"]))
89361
+ return `${id}: "recommendation" needs an optionId`;
89362
+ if (!ids.has(recRaw["optionId"]))
89363
+ return `${id}: the recommended option "${recRaw["optionId"]}" is not one of the options`;
89364
+ recommendation = { optionId: recRaw["optionId"], reason: isString3(recRaw["reason"]) ? oneLine2(recRaw["reason"]) : "" };
89365
+ }
89366
+ let answer = null;
89367
+ const answerRaw = raw["answer"];
89368
+ if (answerRaw !== undefined && answerRaw !== null) {
89369
+ if (!isObject(answerRaw) || !isString3(answerRaw["choice"]) || answerRaw["choice"].trim().length === 0)
89370
+ return `${id}: "answer" needs a choice`;
89371
+ const other = answerRaw["other"] === true;
89372
+ if (!other && !ids.has(answerRaw["choice"].trim())) {
89373
+ return `${id}: the answer "${answerRaw["choice"]}" is not one of the options (use "other": true for the human's own words)`;
89374
+ }
89375
+ answer = { choice: other ? oneLine2(answerRaw["choice"]) : answerRaw["choice"].trim(), other };
89376
+ }
89377
+ const sourceRaw = raw["source"];
89378
+ if (sourceRaw !== undefined && !isString3(sourceRaw))
89379
+ return `${id}: "source" must be a string`;
89380
+ const reasonRaw = raw["reason"];
89381
+ if (reasonRaw !== undefined && reasonRaw !== null && !isString3(reasonRaw))
89382
+ return `${id}: "reason" must be a string`;
89383
+ const reason = isString3(reasonRaw) ? oneLine2(reasonRaw) : "";
89384
+ const source = isString3(sourceRaw) ? oneLine2(sourceRaw) : "";
89385
+ return {
89386
+ id,
89387
+ at,
89388
+ flow,
89389
+ stage: isString3(stageRaw) && stageRaw.trim().length > 0 ? oneLine2(stageRaw) : DEFAULT_STAGE,
89390
+ question: oneLine2(question),
89391
+ options,
89392
+ recommendation,
89393
+ ...source.length > 0 ? { source } : {},
89394
+ answer,
89395
+ ...reason.length > 0 ? { reason } : {}
89396
+ };
89397
+ }
89398
+ function parseBackfill(text) {
89399
+ const entries = [];
89400
+ const errors = [];
89401
+ text.split(`
89402
+ `).forEach((line, index) => {
89403
+ if (line.trim().length === 0)
89404
+ return;
89405
+ let parsed;
89406
+ try {
89407
+ parsed = JSON.parse(line);
89408
+ } catch {
89409
+ errors.push({ line: index + 1, message: "not valid JSON" });
89410
+ return;
89411
+ }
89412
+ const entry = parseEntry3(parsed);
89413
+ if (typeof entry === "string")
89414
+ errors.push({ line: index + 1, message: entry });
89415
+ else
89416
+ entries.push(entry);
89417
+ });
89418
+ return { entries, errors };
89419
+ }
89420
+ function answerRecordOf(entry, at) {
89421
+ if (entry.answer === null)
89422
+ return;
89423
+ return {
89424
+ kind: "answer",
89425
+ id: entry.id,
89426
+ at,
89427
+ seq: 1,
89428
+ choice: entry.answer.choice,
89429
+ timeToAnswerMs: 0,
89430
+ changed: false,
89431
+ ...entry.answer.other ? { other: true } : {}
89432
+ };
89433
+ }
89434
+ function reasonRecordOf(entry, at) {
89435
+ return entry.reason === undefined ? undefined : { kind: "reason", id: entry.id, at, reason: entry.reason };
89436
+ }
89437
+ function backfillRecords(entry) {
89438
+ const open = {
89439
+ kind: "open",
89440
+ id: entry.id,
89441
+ at: entry.at,
89442
+ flow: entry.flow,
89443
+ stage: entry.stage,
89444
+ question: entry.question,
89445
+ options: entry.options,
89446
+ recommendation: entry.recommendation,
89447
+ mode: "ordinary",
89448
+ order: entry.options.map((option) => option.id),
89449
+ showMark: entry.recommendation !== null,
89450
+ irreversible: false,
89451
+ backfilled: true,
89452
+ ...entry.source !== undefined ? { source: entry.source } : {}
89453
+ };
89454
+ const records = [open];
89455
+ const answer = answerRecordOf(entry, entry.at);
89456
+ if (answer !== undefined)
89457
+ records.push(answer);
89458
+ const reason = reasonRecordOf(entry, entry.at);
89459
+ if (reason !== undefined)
89460
+ records.push(reason);
89461
+ return records;
89462
+ }
89463
+ async function importBackfill(cwd, text, options = {}) {
89464
+ if (options.dryRun === true)
89465
+ return importUnlocked(cwd, text, options);
89466
+ return withJournalLock(cwd, () => importUnlocked(cwd, text, options));
89467
+ }
89468
+ async function importUnlocked(cwd, text, options) {
89469
+ const { entries, errors } = parseBackfill(text);
89470
+ const records = await readRecords(cwd);
89471
+ const known = new Map;
89472
+ const answered = new Set;
89473
+ const reasoned = new Set;
89474
+ for (const record of records) {
89475
+ if (record.kind === "open")
89476
+ known.set(record.id, record);
89477
+ else if (record.kind === "answer")
89478
+ answered.add(record.id);
89479
+ else
89480
+ reasoned.add(record.id);
89481
+ }
89482
+ const result = {
89483
+ dryRun: options.dryRun === true,
89484
+ imported: 0,
89485
+ skipped: 0,
89486
+ withRecommendation: 0,
89487
+ answered: 0,
89488
+ deviations: 0,
89489
+ skippedIds: [],
89490
+ repaired: 0,
89491
+ repairedIds: [],
89492
+ malformed: errors
89493
+ };
89494
+ const toWrite = [];
89495
+ for (const entry of entries) {
89496
+ const existing = known.get(entry.id);
89497
+ if (existing !== undefined) {
89498
+ const answer = entry.answer;
89499
+ const repairable = existing.backfilled === true && answer !== null && !answered.has(entry.id) && (answer.other || existing.options.some((option) => option.id === answer.choice));
89500
+ if (!repairable || answer === null) {
89501
+ result.skipped += 1;
89502
+ result.skippedIds.push(entry.id);
89503
+ continue;
89504
+ }
89505
+ const missing = [answerRecordOf(entry, existing.at), reasoned.has(entry.id) ? undefined : reasonRecordOf(entry, existing.at)].filter((record) => record !== undefined);
89506
+ toWrite.push(...missing);
89507
+ answered.add(entry.id);
89508
+ result.repaired += 1;
89509
+ result.repairedIds.push(entry.id);
89510
+ result.answered += 1;
89511
+ if (existing.recommendation !== null && answer.choice !== existing.recommendation.optionId)
89512
+ result.deviations += 1;
89513
+ continue;
89514
+ }
89515
+ known.set(entry.id, backfillRecords(entry)[0]);
89516
+ answered.add(entry.id);
89517
+ result.imported += 1;
89518
+ if (entry.recommendation !== null)
89519
+ result.withRecommendation += 1;
89520
+ if (entry.answer !== null) {
89521
+ result.answered += 1;
89522
+ if (entry.recommendation !== null && entry.answer.choice !== entry.recommendation.optionId)
89523
+ result.deviations += 1;
89524
+ }
89525
+ toWrite.push(...backfillRecords(entry));
89526
+ }
89527
+ if (!result.dryRun)
89528
+ await appendRecords(cwd, toWrite);
89529
+ return result;
89530
+ }
89531
+ function renderImportResult(result) {
89532
+ const repaired = result.repaired > 0 ? `, repaired: ${result.repaired}` : "";
89533
+ const malformed = result.malformed.length > 0 ? `, malformed: ${result.malformed.length}` : "";
89534
+ const lines = [
89535
+ `${result.dryRun ? "Dry run, nothing written. " : ""}Imported: ${result.imported}, skipped: ${result.skipped}, with recommendation: ${result.withRecommendation}, answered: ${result.answered}, deviations: ${result.deviations}${repaired}${malformed}`
89536
+ ];
89537
+ if (result.skippedIds.length > 0) {
89538
+ const shown = result.skippedIds.slice(0, 20).map((id) => oneLine2(id, 80));
89539
+ lines.push(`Skipped (already in the journal): ${shown.join(", ")}${result.skippedIds.length > shown.length ? `, ... and ${result.skippedIds.length - shown.length} more` : ""}`);
89540
+ }
89541
+ if (result.repairedIds.length > 0) {
89542
+ const shown = result.repairedIds.slice(0, 20).map((id) => oneLine2(id, 80));
89543
+ lines.push(`Repaired (the answer was missing from the journal and was added): ${shown.join(", ")}${result.repairedIds.length > shown.length ? `, ... and ${result.repairedIds.length - shown.length} more` : ""}`);
89544
+ }
89545
+ if (result.malformed.length > 0) {
89546
+ lines.push("Malformed (skipped):");
89547
+ for (const error of result.malformed.slice(0, 20))
89548
+ lines.push(` line ${error.line}: ${oneLine2(error.message, 200)}`);
89549
+ if (result.malformed.length > 20)
89550
+ lines.push(` ... and ${result.malformed.length - 20} more`);
89551
+ }
89552
+ return lines.join(`
89553
+ `);
89554
+ }
89555
+ var isString3 = (value) => typeof value === "string", isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
89556
+ var init_import = __esm(() => {
89557
+ init_journal2();
89558
+ init_store6();
89559
+ });
89560
+
89119
89561
  // src/decisions/context.ts
89120
89562
  async function currentBranch(cwd) {
89121
89563
  try {
@@ -89203,7 +89645,7 @@ async function latestAnsweredDecision(cwd, flow) {
89203
89645
  const answered = new Set(records.filter((r) => r.kind === "answer").map((r) => r.id));
89204
89646
  for (let i = records.length - 1;i >= 0; i -= 1) {
89205
89647
  const record = records[i];
89206
- if (record !== undefined && record.kind === "open" && answered.has(record.id) && (flow === undefined || record.flow === flow))
89648
+ if (record !== undefined && record.kind === "open" && record.backfilled !== true && answered.has(record.id) && (flow === undefined || record.flow === flow))
89207
89649
  return record.id;
89208
89650
  }
89209
89651
  return;
@@ -89261,6 +89703,8 @@ function resolveOptionId(open, typed) {
89261
89703
  }
89262
89704
  async function changeAnswer(input) {
89263
89705
  const open = await resolveOpen(input.cwd, input.id, input.lastId, input.flow, input.session, "keryx decisions answer <id> --choice <option>");
89706
+ if (open.backfilled === true)
89707
+ throw new Error(`decision ${open.id} is a backfilled historical record; its answer is not changed`);
89264
89708
  const choice = resolveOptionId(open, input.choice);
89265
89709
  const answers = (await readRecords(input.cwd)).filter((r) => r.kind === "answer" && r.id === open.id);
89266
89710
  const first = [...answers].sort((x, y) => x.seq - y.seq)[0];
@@ -89280,9 +89724,15 @@ async function loadReport(cwd) {
89280
89724
  async function reportText(cwd) {
89281
89725
  return renderReport(await loadReport(cwd));
89282
89726
  }
89727
+ async function reportLine(cwd) {
89728
+ return renderReportLine(await loadReport(cwd));
89729
+ }
89283
89730
  async function decisionCount(cwd) {
89284
89731
  return (await loadReport(cwd)).total;
89285
89732
  }
89733
+ async function backfilledCount(cwd) {
89734
+ return (await loadReport(cwd)).backfilled.total;
89735
+ }
89286
89736
  var init_service13 = __esm(() => {
89287
89737
  init_report4();
89288
89738
  init_store6();
@@ -89290,13 +89740,14 @@ var init_service13 = __esm(() => {
89290
89740
  init_blind();
89291
89741
  init_journal2();
89292
89742
  init_report4();
89743
+ init_import();
89293
89744
  init_store6();
89294
89745
  init_context2();
89295
89746
  init_followup();
89296
89747
  });
89297
89748
 
89298
89749
  // src/tui/ask-user-bridge.ts
89299
- import { randomUUID as randomUUID23 } from "crypto";
89750
+ import { randomUUID as randomUUID24 } from "crypto";
89300
89751
  function setAskUserHost(fn) {
89301
89752
  host = fn;
89302
89753
  }
@@ -89331,7 +89782,7 @@ function journaledAskUser(cwd) {
89331
89782
  var host, notice, lastDecisionId, sessionId;
89332
89783
  var init_ask_user_bridge = __esm(() => {
89333
89784
  init_service13();
89334
- sessionId = `s-${randomUUID23()}`;
89785
+ sessionId = `s-${randomUUID24()}`;
89335
89786
  });
89336
89787
 
89337
89788
  // src/harness/tool/metaproject-operations.ts
@@ -90872,7 +91323,7 @@ var init_project_tools = __esm(() => {
90872
91323
  });
90873
91324
 
90874
91325
  // src/commands/interactive-agent-tools.ts
90875
- import { randomUUID as randomUUID24 } from "crypto";
91326
+ import { randomUUID as randomUUID25 } from "crypto";
90876
91327
  function denyInteractiveTools(tools, denied) {
90877
91328
  if (denied.length === 0)
90878
91329
  return [...tools];
@@ -90890,7 +91341,7 @@ function buildInteractiveAgentTools(input) {
90890
91341
  const getSessionDir = input.getSessionDir ?? (() => {
90891
91342
  return;
90892
91343
  });
90893
- const idSeq = input.idSeq ?? (() => randomUUID24());
91344
+ const idSeq = input.idSeq ?? (() => randomUUID25());
90894
91345
  const clock = input.clock ?? (() => new Date().toISOString());
90895
91346
  const jobRegistry = input.jobRegistry;
90896
91347
  const project = buildProjectTools(input.cwd, input.metaprojectPort);
@@ -93393,9 +93844,9 @@ var init_registry3 = __esm(() => {
93393
93844
  });
93394
93845
 
93395
93846
  // src/harness/tool/builtin/spawn-subagent-tool.ts
93396
- import { createHash as createHash60, randomUUID as randomUUID25 } from "crypto";
93847
+ import { createHash as createHash60, randomUUID as randomUUID26 } from "crypto";
93397
93848
  import { execFile as execFile7 } from "child_process";
93398
- import { lstat as lstat14, mkdtemp as mkdtemp2, readFile as readFile104, realpath as realpath17, rm as rm13 } from "fs/promises";
93849
+ import { lstat as lstat14, mkdtemp as mkdtemp2, readFile as readFile104, realpath as realpath17, rm as rm14 } from "fs/promises";
93399
93850
  import { tmpdir as tmpdir6 } from "os";
93400
93851
  import path216 from "path";
93401
93852
  import { promisify as promisify5 } from "util";
@@ -93585,7 +94036,7 @@ async function verifyWorktreeCandidate(candidate, commonDir, worktreesDir) {
93585
94036
  }
93586
94037
  }
93587
94038
  function createSpawnSubagentTool(deps) {
93588
- const idSeq = deps.idSeq ?? (() => randomUUID25());
94039
+ const idSeq = deps.idSeq ?? (() => randomUUID26());
93589
94040
  const clock = deps.clock ?? (() => new Date().toISOString());
93590
94041
  const parentRunId = deps.parentRunId ?? idSeq();
93591
94042
  const parentSessionId = deps.parentSessionId ?? idSeq();
@@ -93946,7 +94397,7 @@ function createSpawnSubagentTool(deps) {
93946
94397
  provider = deps.makeProvider(runModel.provider, runModel.model, parent.baseUrl);
93947
94398
  } catch (cause) {
93948
94399
  if (ephemeralDir !== undefined) {
93949
- await rm13(ephemeralDir, { recursive: true, force: true }).catch(() => {});
94400
+ await rm14(ephemeralDir, { recursive: true, force: true }).catch(() => {});
93950
94401
  }
93951
94402
  await fireSubagentStop("Error").catch(() => {});
93952
94403
  ledger.release(spawned.reservation.reservationId, {
@@ -94072,7 +94523,7 @@ function createSpawnSubagentTool(deps) {
94072
94523
  }
94073
94524
  }
94074
94525
  } finally {
94075
- await rm13(dirToClean, { recursive: true, force: true }).catch(() => {});
94526
+ await rm14(dirToClean, { recursive: true, force: true }).catch(() => {});
94076
94527
  }
94077
94528
  });
94078
94529
  } catch (lockCause) {
@@ -94082,7 +94533,7 @@ function createSpawnSubagentTool(deps) {
94082
94533
  id: workerId,
94083
94534
  entry: { kind: "system", text: `slate cleanup lock failed (ignored): ${lockMsg}` }
94084
94535
  });
94085
- await rm13(dirToClean, { recursive: true, force: true }).catch(() => {});
94536
+ await rm14(dirToClean, { recursive: true, force: true }).catch(() => {});
94086
94537
  }
94087
94538
  };
94088
94539
  try {
@@ -95887,7 +96338,7 @@ var init_dispatch2 = __esm(() => {
95887
96338
 
95888
96339
  // src/harness/external/acp-fs.ts
95889
96340
  import { constants as constants2, realpathSync as realpathSync15, statSync as statSync12 } from "fs";
95890
- import { mkdir as mkdir53, open as open9, readFile as readFile105 } from "fs/promises";
96341
+ import { mkdir as mkdir53, open as open10, readFile as readFile105 } from "fs/promises";
95891
96342
  import path219 from "path";
95892
96343
  function refusedMethodError(method, reason) {
95893
96344
  return new AcpError(JSON_RPC_ERROR_CODES.methodNotFound, `${method} refused: ${reason}`, { reason });
@@ -95956,7 +96407,7 @@ async function writeTextFileInWorktree(worktree, target, content, requested, hoo
95956
96407
  const finalTarget = path219.join(parentReal, path219.basename(target));
95957
96408
  let handle;
95958
96409
  try {
95959
- handle = await open9(finalTarget, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_TRUNC | constants2.O_NOFOLLOW, 420);
96410
+ handle = await open10(finalTarget, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_TRUNC | constants2.O_NOFOLLOW, 420);
95960
96411
  } catch (error) {
95961
96412
  const code = error.code;
95962
96413
  if (code === "ELOOP" || code === "EMLINK") {
@@ -96121,7 +96572,7 @@ function describeOutcome(outcome) {
96121
96572
  return outcome.reason;
96122
96573
  return "an unexpected result";
96123
96574
  }
96124
- function isObject(value) {
96575
+ function isObject2(value) {
96125
96576
  return typeof value === "object" && value !== null && !Array.isArray(value);
96126
96577
  }
96127
96578
  function short(value, max = 500) {
@@ -96131,7 +96582,7 @@ function short(value, max = 500) {
96131
96582
  function readOptions(raw) {
96132
96583
  if (!Array.isArray(raw))
96133
96584
  return [];
96134
- return raw.filter((option) => isObject(option) && typeof option["optionId"] === "string" && typeof option["kind"] === "string");
96585
+ return raw.filter((option) => isObject2(option) && typeof option["optionId"] === "string" && typeof option["kind"] === "string");
96135
96586
  }
96136
96587
  async function superviseAcpRun(input, deps) {
96137
96588
  const clientCapabilities = acpClientCapabilities(input.write);
@@ -96203,7 +96654,7 @@ async function superviseAcpRun(input, deps) {
96203
96654
  let promptRequestId;
96204
96655
  let boundSessionId;
96205
96656
  const guardSession = (method, params) => {
96206
- const claimed = isObject(params) ? params["sessionId"] : undefined;
96657
+ const claimed = isObject2(params) ? params["sessionId"] : undefined;
96207
96658
  let reason;
96208
96659
  if (phase !== "prompting") {
96209
96660
  reason = phase === "handshake" ? "no prompt is in progress yet; keryx answers only during this run's turn" : "this run's turn has ended; keryx no longer answers for it";
@@ -96234,9 +96685,9 @@ async function superviseAcpRun(input, deps) {
96234
96685
  });
96235
96686
  dispatcher.onRequest(ACP_CLIENT_METHODS.sessionRequestPermission, async (params, context) => {
96236
96687
  guardSession(ACP_CLIENT_METHODS.sessionRequestPermission, params);
96237
- const p = isObject(params) ? params : {};
96688
+ const p = isObject2(params) ? params : {};
96238
96689
  const rawToolCall = p["toolCall"];
96239
- const toolCall = isObject(rawToolCall) && typeof rawToolCall["toolCallId"] === "string" ? rawToolCall : { toolCallId: "unidentified" };
96690
+ const toolCall = isObject2(rawToolCall) && typeof rawToolCall["toolCallId"] === "string" ? rawToolCall : { toolCallId: "unidentified" };
96240
96691
  const { answer, decision } = await answerAcpPermission({ requestId: context.id, toolCall, options: readOptions(p["options"]) }, permissionContext);
96241
96692
  recordDecision(decision);
96242
96693
  return { outcome: answer.outcome };
@@ -96244,7 +96695,7 @@ async function superviseAcpRun(input, deps) {
96244
96695
  dispatcher.onRequest(ACP_CLIENT_METHODS.fsReadTextFile, async (params) => {
96245
96696
  const method = ACP_CLIENT_METHODS.fsReadTextFile;
96246
96697
  guardSession(method, params);
96247
- const p = isObject(params) ? params : {};
96698
+ const p = isObject2(params) ? params : {};
96248
96699
  try {
96249
96700
  const { content } = await readTextFileInWorktree(input.cwd, p);
96250
96701
  recordFs({ method, path: String(p["path"]), outcome: "served", bytes: Buffer.byteLength(content, "utf8") });
@@ -96257,7 +96708,7 @@ async function superviseAcpRun(input, deps) {
96257
96708
  dispatcher.onRequest(ACP_CLIENT_METHODS.fsWriteTextFile, async (params, context) => {
96258
96709
  const method = ACP_CLIENT_METHODS.fsWriteTextFile;
96259
96710
  guardSession(method, params);
96260
- const p = isObject(params) ? params : {};
96711
+ const p = isObject2(params) ? params : {};
96261
96712
  const requested = typeof p["path"] === "string" ? p["path"] : String(p["path"]);
96262
96713
  if (!input.write) {
96263
96714
  const reason = "keryx did not advertise fs.writeTextFile (a read-only run)";
@@ -96294,7 +96745,7 @@ async function superviseAcpRun(input, deps) {
96294
96745
  });
96295
96746
  for (const [method, reason] of ACP_REFUSED_CLIENT_METHODS) {
96296
96747
  dispatcher.onRequest(method, (params) => {
96297
- const p = isObject(params) ? params : {};
96748
+ const p = isObject2(params) ? params : {};
96298
96749
  recordFs({
96299
96750
  method,
96300
96751
  ...typeof p["command"] === "string" ? { path: p["command"] } : {},
@@ -96308,7 +96759,7 @@ async function superviseAcpRun(input, deps) {
96308
96759
  return;
96309
96760
  });
96310
96761
  dispatcher.onNotification(ACP_CLIENT_METHODS.sessionUpdate, (params) => {
96311
- if (!isObject(params) || !isObject(params["update"]))
96762
+ if (!isObject2(params) || !isObject2(params["update"]))
96312
96763
  return;
96313
96764
  if (boundSessionId === undefined || params["sessionId"] !== boundSessionId) {
96314
96765
  stderr.push(`[keryx] ignored a session/update for session ${JSON.stringify(params["sessionId"] ?? null)}`);
@@ -96368,7 +96819,7 @@ async function superviseAcpRun(input, deps) {
96368
96819
  usage = { used: update.used, size: update.size };
96369
96820
  }
96370
96821
  const reported = update.cost;
96371
- if (isObject(reported) && typeof reported["amount"] === "number" && typeof reported["currency"] === "string") {
96822
+ if (isObject2(reported) && typeof reported["amount"] === "number" && typeof reported["currency"] === "string") {
96372
96823
  cost = { amount: reported["amount"], currency: reported["currency"] };
96373
96824
  }
96374
96825
  emit(cost !== undefined && cost.currency === "USD" ? { kind: "usage", costUnits: cost.amount } : { kind: "usage" });
@@ -96385,7 +96836,7 @@ async function superviseAcpRun(input, deps) {
96385
96836
  if (phase === "prompting" && promptRequestId !== undefined && line.includes(promptRequestId)) {
96386
96837
  try {
96387
96838
  const value = JSON.parse(line);
96388
- if (isObject(value) && !("method" in value) && value["id"] === promptRequestId)
96839
+ if (isObject2(value) && !("method" in value) && value["id"] === promptRequestId)
96389
96840
  phase = "ended";
96390
96841
  } catch {}
96391
96842
  }
@@ -96465,16 +96916,16 @@ async function superviseAcpRun(input, deps) {
96465
96916
  failure = `the agent did not answer initialize within ${input.timeoutMs}ms`;
96466
96917
  return await finish();
96467
96918
  }
96468
- if (init.kind !== "result" || !isObject(init.result)) {
96919
+ if (init.kind !== "result" || !isObject2(init.result)) {
96469
96920
  failure = `the agent did not answer initialize: ${describeOutcome(init)}`;
96470
96921
  return await finish();
96471
96922
  }
96472
96923
  const initResult = init.result;
96473
96924
  const version = initResult["protocolVersion"];
96474
96925
  protocolVersion = typeof version === "number" ? version : undefined;
96475
- if (isObject(initResult["agentInfo"]))
96926
+ if (isObject2(initResult["agentInfo"]))
96476
96927
  agentInfo = initResult["agentInfo"];
96477
- if (isObject(initResult["agentCapabilities"]))
96928
+ if (isObject2(initResult["agentCapabilities"]))
96478
96929
  agentCapabilities = initResult["agentCapabilities"];
96479
96930
  if (typeof version !== "number" || !ACP_SUPPORTED_PROTOCOL_VERSIONS.includes(version)) {
96480
96931
  failure = `unsupported ACP protocol version: the agent answered initialize with protocolVersion ${JSON.stringify(version)}; ` + `keryx speaks ${ACP_SUPPORTED_PROTOCOL_VERSIONS.join(", ")}`;
@@ -96486,7 +96937,7 @@ async function superviseAcpRun(input, deps) {
96486
96937
  failure = `the agent did not answer session/new within ${input.timeoutMs}ms`;
96487
96938
  return await finish();
96488
96939
  }
96489
- if (created.kind !== "result" || !isObject(created.result) || typeof created.result["sessionId"] !== "string") {
96940
+ if (created.kind !== "result" || !isObject2(created.result) || typeof created.result["sessionId"] !== "string") {
96490
96941
  failure = `the agent refused session/new: ${created.kind === "result" ? "no sessionId in the answer" : describeOutcome(created)}`;
96491
96942
  return await finish();
96492
96943
  }
@@ -96526,12 +96977,12 @@ ${resource.text}` });
96526
96977
  const grace = afterMs(graceMs);
96527
96978
  const late = await Promise.race([turn, grace.promise]);
96528
96979
  grace.cancel();
96529
- if (late !== TIMEOUT && late.kind === "result" && isObject(late.result) && typeof late.result["stopReason"] === "string") {
96980
+ if (late !== TIMEOUT && late.kind === "result" && isObject2(late.result) && typeof late.result["stopReason"] === "string") {
96530
96981
  stopReason = late.result["stopReason"];
96531
96982
  }
96532
96983
  return await finish();
96533
96984
  }
96534
- if (answered.kind !== "result" || !isObject(answered.result)) {
96985
+ if (answered.kind !== "result" || !isObject2(answered.result)) {
96535
96986
  failure = `session/prompt did not complete: ${describeOutcome(answered)}`;
96536
96987
  return await finish();
96537
96988
  }
@@ -96610,7 +97061,7 @@ var init_acp_client = __esm(() => {
96610
97061
  // src/harness/external/acp-run.ts
96611
97062
  import { execFile as execFile9 } from "child_process";
96612
97063
  import { existsSync as existsSync38, readFileSync as readFileSync20, writeFileSync as writeFileSync4 } from "fs";
96613
- import { mkdtemp as mkdtemp3, rm as rm14 } from "fs/promises";
97064
+ import { mkdtemp as mkdtemp3, rm as rm15 } from "fs/promises";
96614
97065
  import { tmpdir as tmpdir7 } from "os";
96615
97066
  import path220 from "path";
96616
97067
  import { promisify as promisify7 } from "util";
@@ -96687,7 +97138,7 @@ async function captureWorktreePatch(worktreePath) {
96687
97138
  } catch {
96688
97139
  return;
96689
97140
  } finally {
96690
- await rm14(dir, { recursive: true, force: true }).catch(() => {
97141
+ await rm15(dir, { recursive: true, force: true }).catch(() => {
96691
97142
  return;
96692
97143
  });
96693
97144
  }
@@ -98048,7 +98499,7 @@ var init_codec2 = __esm(() => {
98048
98499
  });
98049
98500
 
98050
98501
  // src/harness/external/runtime.ts
98051
- import { mkdtemp as mkdtemp4, rm as rm15, writeFile as writeFile34 } from "fs/promises";
98502
+ import { mkdtemp as mkdtemp4, rm as rm16, writeFile as writeFile34 } from "fs/promises";
98052
98503
  import { tmpdir as tmpdir8 } from "os";
98053
98504
  import path221 from "path";
98054
98505
  function refuse2(status, output) {
@@ -98065,7 +98516,7 @@ async function prepareResultSchema() {
98065
98516
  return { ok: true, schema, schemaText, schemaPath, schemaDir };
98066
98517
  } catch (error) {
98067
98518
  if (schemaDir !== undefined) {
98068
- await rm15(schemaDir, { recursive: true, force: true }).catch(() => {
98519
+ await rm16(schemaDir, { recursive: true, force: true }).catch(() => {
98069
98520
  return;
98070
98521
  });
98071
98522
  }
@@ -98172,7 +98623,7 @@ async function runExternalChild(input, deps) {
98172
98623
  try {
98173
98624
  await writeFile34(resultSchemaPathForCodec, JSON.stringify(toStrictOutputSchema(bundledResultSchema)), "utf8");
98174
98625
  } catch (error) {
98175
- await rm15(schemaDir, { recursive: true, force: true }).catch(() => {
98626
+ await rm16(schemaDir, { recursive: true, force: true }).catch(() => {
98176
98627
  return;
98177
98628
  });
98178
98629
  const message = error instanceof Error ? error.message : String(error);
@@ -98267,7 +98718,7 @@ async function runExternalChild(input, deps) {
98267
98718
  });
98268
98719
  }
98269
98720
  } finally {
98270
- await rm15(schemaDir, { recursive: true, force: true }).catch(() => {
98721
+ await rm16(schemaDir, { recursive: true, force: true }).catch(() => {
98271
98722
  return;
98272
98723
  });
98273
98724
  }
@@ -98434,7 +98885,7 @@ var init_runtime2 = __esm(() => {
98434
98885
  });
98435
98886
 
98436
98887
  // src/harness/run-external-factory.ts
98437
- import { randomUUID as randomUUID26 } from "crypto";
98888
+ import { randomUUID as randomUUID27 } from "crypto";
98438
98889
  import { execFile as execFile10 } from "child_process";
98439
98890
  import { mkdir as mkdir54 } from "fs/promises";
98440
98891
  import { tmpdir as tmpdir9 } from "os";
@@ -98495,7 +98946,7 @@ async function createRunExternal(options) {
98495
98946
  return;
98496
98947
  }
98497
98948
  const config = gate.config;
98498
- const idSeq = options.idSeq ?? (() => randomUUID26());
98949
+ const idSeq = options.idSeq ?? (() => randomUUID27());
98499
98950
  const worktreesDir = options.worktreesDir ?? path222.join(tmpdir9(), "keryx-external-worktrees");
98500
98951
  const spawn = options.spawn ?? createBunSpawnPort();
98501
98952
  const worktree = options.worktree ?? ensuringParentDir(createGitWorktreePort({ repoRoot: options.cwd, worktreesDir }), worktreesDir);
@@ -99434,7 +99885,7 @@ var init_client2 = __esm(() => {
99434
99885
 
99435
99886
  // src/lib/file-lock.ts
99436
99887
  import { closeSync as closeSync3, mkdirSync as mkdirSync7, openSync as openSync3, readFileSync as readFileSync21, rmSync as rmSync3, statSync as statSync13, writeFileSync as writeFileSync6 } from "fs";
99437
- import { randomUUID as randomUUID27 } from "crypto";
99888
+ import { randomUUID as randomUUID28 } from "crypto";
99438
99889
  import path225 from "path";
99439
99890
  function sleepSync(ms) {
99440
99891
  const bunSleep = globalThis.Bun?.sleepSync;
@@ -99451,7 +99902,7 @@ function withFileLock2(lockPath, fn, options = {}) {
99451
99902
  } catch {
99452
99903
  return null;
99453
99904
  }
99454
- const nonce = randomUUID27();
99905
+ const nonce = randomUUID28();
99455
99906
  const started = Date.now();
99456
99907
  const deadline = started + LOCK_TIMEOUT_MS;
99457
99908
  let handle = null;
@@ -101709,7 +102160,7 @@ import {
101709
102160
  writeFileSync as writeFileSync7
101710
102161
  } from "fs";
101711
102162
  import path232 from "path";
101712
- import { randomUUID as randomUUID28 } from "crypto";
102163
+ import { randomUUID as randomUUID29 } from "crypto";
101713
102164
  function projectRegistryPath(dir) {
101714
102165
  return path232.join(keryxConfigDir(dir), "projects.json");
101715
102166
  }
@@ -101824,7 +102275,7 @@ function quarantineDamagedRegistry(dir, onWarn) {
101824
102275
  }
101825
102276
  function saveProjectRegistry(registry, dir, onWarn) {
101826
102277
  const file = projectRegistryPath(dir);
101827
- const temp = `${file}.${randomUUID28()}.tmp`;
102278
+ const temp = `${file}.${randomUUID29()}.tmp`;
101828
102279
  try {
101829
102280
  ensureKeryxConfigDir(dir);
101830
102281
  const sorted = {
@@ -101880,7 +102331,7 @@ function registerProject(projectPath, options = {}) {
101880
102331
  return { ok: true, entry: existing, created: false };
101881
102332
  }
101882
102333
  const entry = {
101883
- projectId: randomUUID28(),
102334
+ projectId: randomUUID29(),
101884
102335
  path: absolute,
101885
102336
  displayName: options.displayName ?? path232.basename(absolute),
101886
102337
  state: "active",
@@ -109019,7 +109470,7 @@ function formatHygieneTags(hygiene) {
109019
109470
  }
109020
109471
 
109021
109472
  // src/sac/lifecycle-flag.ts
109022
- import { randomUUID as randomUUID29 } from "crypto";
109473
+ import { randomUUID as randomUUID30 } from "crypto";
109023
109474
  function normalize3(raw) {
109024
109475
  return raw.replace(/^\.\//, "");
109025
109476
  }
@@ -109038,7 +109489,7 @@ async function computeLifecycleFlags(cwd, now = () => new Date) {
109038
109489
  authorizationServer: localWorkspaceAuthorizationServer(),
109039
109490
  strictGuard: { mode: "strict", availability: "available", decision: "pass", policyRevision: "local-offline-v1" }
109040
109491
  });
109041
- const workspaces = await workspaceService.list({ request: undefined, requestCorrelationId: randomUUID29(), includeArchived: true });
109492
+ const workspaces = await workspaceService.list({ request: undefined, requestCorrelationId: randomUUID30(), includeArchived: true });
109042
109493
  for (const workspace of workspaces) {
109043
109494
  const component = workspace.resources.find((r) => r.kind === "component")?.uri;
109044
109495
  if (component !== undefined && !isStillPresent(component, valid)) {
@@ -109067,8 +109518,8 @@ var init_lifecycle_flag = __esm(() => {
109067
109518
  });
109068
109519
 
109069
109520
  // src/sac/catch-up.ts
109070
- import { randomUUID as randomUUID30 } from "crypto";
109071
- import { readdir as readdir36, stat as stat24 } from "fs/promises";
109521
+ import { randomUUID as randomUUID31 } from "crypto";
109522
+ import { readdir as readdir36, stat as stat25 } from "fs/promises";
109072
109523
  import path243 from "path";
109073
109524
  async function buildCatchUp(input) {
109074
109525
  const [proposals, sessionCategories, lifecycleFlagsAll, unreviewedPathsAll] = await Promise.all([
@@ -109083,7 +109534,7 @@ async function buildCatchUp(input) {
109083
109534
  }
109084
109535
  async function collectProposals(cwd, workspaceId) {
109085
109536
  const authorizationServer = localWorkspaceAuthorizationServer();
109086
- const actor = await authorizationServer.actorContextFor(undefined, randomUUID30());
109537
+ const actor = await authorizationServer.actorContextFor(undefined, randomUUID31());
109087
109538
  if (!actor)
109088
109539
  throw new Error("trusted ActorContext is required for catch-up");
109089
109540
  const proposalService = createLocalProposalLifecycleService(cwd);
@@ -109286,7 +109737,7 @@ async function collectReceiptTargets(cwd, owner) {
109286
109737
  async function attributeToSession(absolutePath, sessionsNewestFirst) {
109287
109738
  let mtimeMs;
109288
109739
  try {
109289
- mtimeMs = (await stat24(absolutePath)).mtimeMs;
109740
+ mtimeMs = (await stat25(absolutePath)).mtimeMs;
109290
109741
  } catch {
109291
109742
  return;
109292
109743
  }
@@ -109572,7 +110023,7 @@ var init_session = __esm(() => {
109572
110023
  });
109573
110024
 
109574
110025
  // src/tui/inspector-sources.ts
109575
- import { randomUUID as randomUUID31 } from "crypto";
110026
+ import { randomUUID as randomUUID32 } from "crypto";
109576
110027
  function workspaceFromManifest(manifest) {
109577
110028
  return {
109578
110029
  id: manifest.id,
@@ -109651,7 +110102,7 @@ async function loadInspectorWorkspaces(cwd) {
109651
110102
  authorizationServer: localWorkspaceAuthorizationServer(),
109652
110103
  strictGuard: localSacGuard()
109653
110104
  });
109654
- const listed = await service.list({ request: undefined, requestCorrelationId: randomUUID31() });
110105
+ const listed = await service.list({ request: undefined, requestCorrelationId: randomUUID32() });
109655
110106
  return listed.map(workspaceFromManifest);
109656
110107
  } catch {
109657
110108
  return [];
@@ -109664,7 +110115,7 @@ async function loadInspectorWorkspace(cwd, workspaceId) {
109664
110115
  authorizationServer: localWorkspaceAuthorizationServer(),
109665
110116
  strictGuard: localSacGuard()
109666
110117
  });
109667
- const manifest = await service.show({ request: undefined, requestCorrelationId: randomUUID31(), workspaceId });
110118
+ const manifest = await service.show({ request: undefined, requestCorrelationId: randomUUID32(), workspaceId });
109668
110119
  return workspaceFromManifest(manifest);
109669
110120
  } catch {
109670
110121
  return;
@@ -111983,7 +112434,7 @@ var init_repair = __esm(() => {
111983
112434
  });
111984
112435
 
111985
112436
  // src/review/managed.ts
111986
- import { mkdir as mkdir55, readFile as readFile117, readdir as readdir38, realpath as realpath18, rm as rm16, stat as stat25 } from "fs/promises";
112437
+ import { mkdir as mkdir55, readFile as readFile117, readdir as readdir38, realpath as realpath18, rm as rm17, stat as stat26 } from "fs/promises";
111987
112438
  import path246 from "path";
111988
112439
  function reviewsRoot(cwd) {
111989
112440
  return path246.join(cwd, ".metaproject", "reviews");
@@ -112210,7 +112661,7 @@ async function persistScreenRadius(packageDir, resolved) {
112210
112661
  `);
112211
112662
  }
112212
112663
  if (resolved.source === "handoff" && resolved.file !== undefined) {
112213
- await rm16(resolved.file, { force: true });
112664
+ await rm17(resolved.file, { force: true });
112214
112665
  }
112215
112666
  }
112216
112667
  function concurrencyPlan(input, coverage) {
@@ -112489,7 +112940,7 @@ function readFromWorkingTree(input) {
112489
112940
  return null;
112490
112941
  }
112491
112942
  try {
112492
- const info = await stat25(real);
112943
+ const info = await stat26(real);
112493
112944
  if (!info.isFile() || info.size > MAX_LOCATE_FILE_BYTES) {
112494
112945
  return null;
112495
112946
  }
@@ -114473,7 +114924,7 @@ var init_endpoint = __esm(() => {
114473
114924
  });
114474
114925
 
114475
114926
  // src/lib/serve-credential.ts
114476
- import { createHash as createHash63, randomBytes as randomBytes11, randomUUID as randomUUID32 } from "crypto";
114927
+ import { createHash as createHash63, randomBytes as randomBytes11, randomUUID as randomUUID33 } from "crypto";
114477
114928
  import {
114478
114929
  chmodSync as chmodSync5,
114479
114930
  closeSync as closeSync5,
@@ -114557,7 +115008,7 @@ function readServeCredential(dir) {
114557
115008
  }
114558
115009
  function writeStore(store, dir) {
114559
115010
  const file = serveCredentialPath(dir);
114560
- const temp = `${file}.${randomUUID32()}.tmp`;
115011
+ const temp = `${file}.${randomUUID33()}.tmp`;
114561
115012
  try {
114562
115013
  ensureKeryxConfigDir(dir);
114563
115014
  const handle = openSync5(temp, "wx", 384);
@@ -114597,7 +115048,7 @@ function mintRecord(now) {
114597
115048
  const salt = randomBytes11(32).toString("hex");
114598
115049
  return {
114599
115050
  token,
114600
- record: { id: randomUUID32(), algorithm: "sha256", salt, hash: hashToken(salt, token), createdAt: now }
115051
+ record: { id: randomUUID33(), algorithm: "sha256", salt, hash: hashToken(salt, token), createdAt: now }
114601
115052
  };
114602
115053
  }
114603
115054
  function issueServeToken(dir, now = () => new Date().toISOString(), onWaiting) {
@@ -116193,7 +116644,7 @@ function fileExists(file) {
116193
116644
  const read = readConfigFile(file);
116194
116645
  return read.ok || read.reason !== "absent";
116195
116646
  }
116196
- function isObject2(value) {
116647
+ function isObject3(value) {
116197
116648
  return typeof value === "object" && value !== null && !Array.isArray(value);
116198
116649
  }
116199
116650
  function plural2(count, one, many) {
@@ -116220,7 +116671,7 @@ class ChannelsClient {
116220
116671
  status() {
116221
116672
  return this.call("channels-status", (body) => {
116222
116673
  const telegram = body.telegram;
116223
- return typeof body.machine === "string" && isObject2(telegram) && typeof telegram.state === "string" && typeof telegram.sessions === "number";
116674
+ return typeof body.machine === "string" && isObject3(telegram) && typeof telegram.state === "string" && typeof telegram.sessions === "number";
116224
116675
  });
116225
116676
  }
116226
116677
  async startPairing(token) {
@@ -116389,12 +116840,12 @@ class ChannelsClient {
116389
116840
  parsed = undefined;
116390
116841
  }
116391
116842
  if (!response.ok) {
116392
- const error = isObject2(parsed) && isObject2(parsed.error) ? parsed.error : undefined;
116843
+ const error = isObject3(parsed) && isObject3(parsed.error) ? parsed.error : undefined;
116393
116844
  const code = typeof error?.code === "string" ? error.code : `http-${response.status}`;
116394
116845
  const message = typeof error?.message === "string" ? error.message : `keryx serve refused the request (HTTP ${response.status})`;
116395
116846
  return { ok: false, code, reason: message };
116396
116847
  }
116397
- if (!isObject2(parsed) || !guard(parsed)) {
116848
+ if (!isObject3(parsed) || !guard(parsed)) {
116398
116849
  return { ok: false, code: "unexpected-response", reason: "keryx serve sent an answer this shell does not understand; update keryx on both sides" };
116399
116850
  }
116400
116851
  return { ok: true, value: parsed };
@@ -116414,7 +116865,7 @@ class ChannelsClient {
116414
116865
  }
116415
116866
  function refusedConnection(error) {
116416
116867
  const seen = new Set;
116417
- for (let current = error;isObject2(current) || current instanceof Error; ) {
116868
+ for (let current = error;isObject3(current) || current instanceof Error; ) {
116418
116869
  if (seen.has(current))
116419
116870
  break;
116420
116871
  seen.add(current);
@@ -120921,7 +121372,7 @@ var init_serve_turn_store = __esm(() => {
120921
121372
  });
120922
121373
 
120923
121374
  // src/lib/serve-approvals-store.ts
120924
- import { randomUUID as randomUUID33 } from "crypto";
121375
+ import { randomUUID as randomUUID34 } from "crypto";
120925
121376
  import { existsSync as existsSync45, readdirSync as readdirSync10 } from "fs";
120926
121377
  import path261 from "path";
120927
121378
  function isApprovalId(value) {
@@ -121197,7 +121648,7 @@ function toPublicApproval(view) {
121197
121648
  };
121198
121649
  }
121199
121650
  function newApprovalId() {
121200
- return randomUUID33();
121651
+ return randomUUID34();
121201
121652
  }
121202
121653
  var APPROVAL_SCHEMA_VERSION = "1.0.0", SUMMARY_MAX = 500, SCOPE_MAX = 300, CONSEQUENCE_MAX = 300, ID_PATTERN2;
121203
121654
  var init_serve_approvals_store = __esm(() => {
@@ -121718,10 +122169,12 @@ async function openDecisions(otui, chrome, options) {
121718
122169
  const text = await reportText(cwd).catch(() => UNREADABLE);
121719
122170
  return presentDecisions((hostOtui, hostChrome, input) => openModal(hostOtui, hostChrome, input), otui, chrome, { ...rest, text });
121720
122171
  }
121721
- function projectDecisionsPanel(count, width) {
121722
- if (count <= 0)
122172
+ function projectDecisionsPanel(count, width, backfilled = 0) {
122173
+ if (count <= 0 && backfilled <= 0)
121723
122174
  return { visible: false, text: "" };
121724
- const label = `${count} decision${count === 1 ? "" : "s"}`;
122175
+ const live = count > 0 ? `${count} decision${count === 1 ? "" : "s"}` : "";
122176
+ const before = backfilled > 0 ? `${count > 0 ? " + " : ""}${backfilled} before` : "";
122177
+ const label = `${live}${before}`;
121725
122178
  const candidates = [`${label} \xB7 /decisions`, label];
121726
122179
  const text = candidates.find((candidate) => candidate.length <= width) ?? label.slice(0, Math.max(1, width));
121727
122180
  return { visible: true, text };
@@ -121744,6 +122197,7 @@ function mountDecisionsSidebar(options) {
121744
122197
  const { chrome } = options;
121745
122198
  const r = chrome.renderer;
121746
122199
  const count = options.count ?? (() => decisionCount(options.cwd));
122200
+ const backfilledTotal = options.backfilled ?? (() => backfilledCount(options.cwd));
121747
122201
  const box = new core.BoxRenderable(r, { id: "sb-decisions", flexDirection: "column", flexShrink: 0 });
121748
122202
  options.parent.add(box);
121749
122203
  let modal;
@@ -121789,7 +122243,13 @@ function mountDecisionsSidebar(options) {
121789
122243
  } catch {
121790
122244
  n = 0;
121791
122245
  }
121792
- projected = projectDecisionsPanel(n, options.width);
122246
+ let before;
122247
+ try {
122248
+ before = await backfilledTotal();
122249
+ } catch {
122250
+ before = 0;
122251
+ }
122252
+ projected = projectDecisionsPanel(n, options.width, before);
121793
122253
  paint();
121794
122254
  };
121795
122255
  const unsubscribeTheme = onThemeChange(guardedThemeRepaint("decisions-row", () => paint(true), () => disposed || isRenderableGone(box)));
@@ -121837,8 +122297,8 @@ var init_decisions_surface = __esm(() => {
121837
122297
 
121838
122298
  // src/harness/external/write-run.ts
121839
122299
  import { execFile as execFile11 } from "child_process";
121840
- import { createHash as createHash66, randomUUID as randomUUID34 } from "crypto";
121841
- import { mkdtemp as mkdtemp5, readlink, realpath as realpath19, rm as rm17 } from "fs/promises";
122300
+ import { createHash as createHash66, randomUUID as randomUUID35 } from "crypto";
122301
+ import { mkdtemp as mkdtemp5, readlink, realpath as realpath19, rm as rm18 } from "fs/promises";
121842
122302
  import { tmpdir as tmpdir11 } from "os";
121843
122303
  import path262 from "path";
121844
122304
  import { promisify as promisify9 } from "util";
@@ -121957,7 +122417,7 @@ async function captureWriteDiff(input) {
121957
122417
  refusedPaths
121958
122418
  };
121959
122419
  } finally {
121960
- await rm17(indexDir, { recursive: true, force: true }).catch(() => {
122420
+ await rm18(indexDir, { recursive: true, force: true }).catch(() => {
121961
122421
  return;
121962
122422
  });
121963
122423
  }
@@ -122031,7 +122491,7 @@ async function runExternalWriteChild(input, deps) {
122031
122491
  });
122032
122492
  }
122033
122493
  if (ownedDir !== undefined)
122034
- await rm17(ownedDir, { recursive: true, force: true }).catch(() => {
122494
+ await rm18(ownedDir, { recursive: true, force: true }).catch(() => {
122035
122495
  return;
122036
122496
  });
122037
122497
  }
@@ -122056,7 +122516,7 @@ async function runExternalWriteChild(input, deps) {
122056
122516
  }
122057
122517
  }
122058
122518
  function persistWriteRun(args) {
122059
- const runId = randomUUID34();
122519
+ const runId = randomUUID35();
122060
122520
  const title = `External write ${args.agentId}: ${args.runStatus}`;
122061
122521
  const handle = createSession({
122062
122522
  cwd: args.projectRoot,
@@ -122172,7 +122632,7 @@ var init_write_run = __esm(() => {
122172
122632
  import { execFile as execFile12 } from "child_process";
122173
122633
  import { createHash as createHash67 } from "crypto";
122174
122634
  import { existsSync as existsSync46, rmSync as rmSync5 } from "fs";
122175
- import { mkdtemp as mkdtemp6, rm as rm18 } from "fs/promises";
122635
+ import { mkdtemp as mkdtemp6, rm as rm19 } from "fs/promises";
122176
122636
  import { tmpdir as tmpdir12 } from "os";
122177
122637
  import path263 from "path";
122178
122638
  function errorMessage3(error) {
@@ -122292,11 +122752,11 @@ async function landWriteRun(input, deps = {}) {
122292
122752
  return;
122293
122753
  });
122294
122754
  if (ownedDir !== undefined)
122295
- await rm18(ownedDir, { recursive: true, force: true }).catch(() => {
122755
+ await rm19(ownedDir, { recursive: true, force: true }).catch(() => {
122296
122756
  return;
122297
122757
  });
122298
122758
  else
122299
- await rm18(path263.join(worktreesDir, worktreeId), { recursive: true, force: true }).catch(() => {
122759
+ await rm19(path263.join(worktreesDir, worktreeId), { recursive: true, force: true }).catch(() => {
122300
122760
  return;
122301
122761
  });
122302
122762
  await git(["worktree", "prune"], repo).catch(() => {
@@ -126285,7 +126745,7 @@ function recordTaskCost(store, record) {
126285
126745
  const next = existing.length >= MAX_SAMPLES_PER_KEY ? [...existing.slice(existing.length - MAX_SAMPLES_PER_KEY + 1), record] : [...existing, record];
126286
126746
  return { ...store, [key]: next };
126287
126747
  }
126288
- function median(values) {
126748
+ function median2(values) {
126289
126749
  if (values.length === 0)
126290
126750
  return 0;
126291
126751
  const sorted = [...values].sort((a, b) => a - b);
@@ -126294,9 +126754,9 @@ function median(values) {
126294
126754
  }
126295
126755
  function statsForKey(records, providerId, modelId, category) {
126296
126756
  const n = records.length;
126297
- const medianTokens = median(records.map((r) => r.totalTokens));
126757
+ const medianTokens = median2(records.map((r) => r.totalTokens));
126298
126758
  const knownCosts = records.map((r) => r.costUsd).filter((c) => c !== undefined);
126299
- const medianCostUsd = knownCosts.length > 0 ? median(knownCosts) : undefined;
126759
+ const medianCostUsd = knownCosts.length > 0 ? median2(knownCosts) : undefined;
126300
126760
  const successRate = records.filter((r) => r.success).length / n;
126301
126761
  return { providerId, modelId, category, n, medianTokens, ...medianCostUsd !== undefined ? { medianCostUsd } : {}, successRate };
126302
126762
  }
@@ -128677,7 +129137,7 @@ var init_conform_report = __esm(() => {
128677
129137
  });
128678
129138
 
128679
129139
  // src/tui/conform-source.ts
128680
- import { readFile as readFile127, readdir as readdir41, stat as stat26 } from "fs/promises";
129140
+ import { readFile as readFile127, readdir as readdir41, stat as stat27 } from "fs/promises";
128681
129141
  import path270 from "path";
128682
129142
  async function readRecentConformDocs(cwd) {
128683
129143
  try {
@@ -128720,7 +129180,7 @@ async function mostRecentReviewPackage(cwd) {
128720
129180
  continue;
128721
129181
  const dir = path270.join(reviewsDir, reviewEntry.name);
128722
129182
  try {
128723
- const info = await stat26(path270.join(dir, "report.md"));
129183
+ const info = await stat27(path270.join(dir, "report.md"));
128724
129184
  if (best === undefined || info.mtimeMs > best.mtimeMs)
128725
129185
  best = { dir, mtimeMs: info.mtimeMs };
128726
129186
  } catch {}
@@ -129687,7 +130147,7 @@ var init_jev_rules = __esm(() => {
129687
130147
  });
129688
130148
 
129689
130149
  // src/commands/review-jev-rules.ts
129690
- import { readFile as readFile130, readdir as readdir42, stat as stat27 } from "fs/promises";
130150
+ import { readFile as readFile130, readdir as readdir42, stat as stat28 } from "fs/promises";
129691
130151
  import { basename as basename3, dirname as dirname2, isAbsolute as isAbsolute3, join as join5, relative as relative3 } from "path";
129692
130152
  function rejectUnknownJevRulesFlags(args) {
129693
130153
  const unknown = args.filter((arg) => arg.startsWith("--") && !JEV_RULES_FLAGS.includes(arg.split("=")[0]));
@@ -129800,7 +130260,7 @@ async function discoverRuleSources(cwd, explicitPaths) {
129800
130260
  const explicitDirSources = [];
129801
130261
  for (const raw of explicitPaths) {
129802
130262
  const resolved = isAbsolute3(raw) ? raw : join5(cwd, raw);
129803
- const stats = await stat27(resolved).catch(() => {
130263
+ const stats = await stat28(resolved).catch(() => {
129804
130264
  return;
129805
130265
  });
129806
130266
  if (stats === undefined) {
@@ -131677,7 +132137,7 @@ var init_jev_triage = __esm(() => {
131677
132137
  });
131678
132138
 
131679
132139
  // src/commands/review-jev-triage.ts
131680
- import { readFile as readFile136, stat as stat28 } from "fs/promises";
132140
+ import { readFile as readFile136, stat as stat29 } from "fs/promises";
131681
132141
  import path276 from "path";
131682
132142
  function rejectUnknownJevTriageFlags(args) {
131683
132143
  const unknown = args.filter((arg) => arg.startsWith("--") && !JEV_TRIAGE_FLAGS.includes(arg.split("=")[0]));
@@ -131712,7 +132172,7 @@ function isMaxTokensExceededError2(error) {
131712
132172
  async function loadReportRaw(reportPath) {
131713
132173
  let filePath = reportPath;
131714
132174
  try {
131715
- const stats = await stat28(reportPath);
132175
+ const stats = await stat29(reportPath);
131716
132176
  if (stats.isDirectory())
131717
132177
  filePath = path276.join(reportPath, "findings.json");
131718
132178
  } catch {}
@@ -131857,7 +132317,7 @@ var init_review_jev_triage = __esm(() => {
131857
132317
  });
131858
132318
 
131859
132319
  // src/tui/jev-triage-command.ts
131860
- import { readdir as readdir43, readFile as readFile137, stat as stat29 } from "fs/promises";
132320
+ import { readdir as readdir43, readFile as readFile137, stat as stat30 } from "fs/promises";
131861
132321
  import path277 from "path";
131862
132322
  function isJevTriageCommand(name) {
131863
132323
  return name === JEV_TRIAGE_COMMAND;
@@ -131886,7 +132346,7 @@ async function resolveLatestReviewPackage(cwd) {
131886
132346
  const packageDir = path277.join(reviewsDir, reviewName);
131887
132347
  const findingsPath = path277.join(packageDir, "findings.json");
131888
132348
  try {
131889
- const stats = await stat29(findingsPath);
132349
+ const stats = await stat30(findingsPath);
131890
132350
  candidates.push({ dir: packageDir, mtimeMs: stats.mtimeMs });
131891
132351
  } catch {
131892
132352
  continue;
@@ -139215,7 +139675,7 @@ function maxOverFiles(files, values) {
139215
139675
  }
139216
139676
 
139217
139677
  // src/wiki/deep-enrich.ts
139218
- import { randomUUID as randomUUID35, createHash as createHash68 } from "crypto";
139678
+ import { randomUUID as randomUUID36, createHash as createHash68 } from "crypto";
139219
139679
  function errorMessage4(cause) {
139220
139680
  return cause instanceof Error ? cause.message : String(cause);
139221
139681
  }
@@ -139251,7 +139711,7 @@ function buildDeepUserPrompt(page, original, extra) {
139251
139711
  `);
139252
139712
  }
139253
139713
  async function enrichPageDeep(input) {
139254
- const idSeq = input.idSeq ?? (() => randomUUID35());
139714
+ const idSeq = input.idSeq ?? (() => randomUUID36());
139255
139715
  const clock = input.clock ?? (() => new Date().toISOString());
139256
139716
  const toolCalls = [];
139257
139717
  if (input.signal?.aborted) {
@@ -144740,7 +145200,7 @@ var init_reflect = __esm(() => {
144740
145200
  });
144741
145201
 
144742
145202
  // src/commands/memory.ts
144743
- import { randomUUID as randomUUID36 } from "crypto";
145203
+ import { randomUUID as randomUUID37 } from "crypto";
144744
145204
  import { readdir as readdir46 } from "fs/promises";
144745
145205
  import { join as join9 } from "path";
144746
145206
  function getService2() {
@@ -144928,7 +145388,7 @@ async function runSearch(args) {
144928
145388
  }
144929
145389
  if (args.includes("--json")) {
144930
145390
  const projection = renderMemorySearchReport({
144931
- runId: randomUUID36(),
145391
+ runId: randomUUID37(),
144932
145392
  generatedAt: new Date,
144933
145393
  search: result,
144934
145394
  filters
@@ -145932,8 +146392,8 @@ var init_proxy = __esm(() => {
145932
146392
 
145933
146393
  // src/commands/trigger-agent-task.ts
145934
146394
  import { execFile as execFile13 } from "child_process";
145935
- import { randomUUID as randomUUID37 } from "crypto";
145936
- import { mkdtemp as mkdtemp7, mkdir as mkdir61, readdir as readdir47, rm as rm19, writeFile as writeFile38 } from "fs/promises";
146395
+ import { randomUUID as randomUUID38 } from "crypto";
146396
+ import { mkdtemp as mkdtemp7, mkdir as mkdir61, readdir as readdir47, rm as rm20, writeFile as writeFile38 } from "fs/promises";
145937
146397
  import { homedir as homedir12, tmpdir as tmpdir13 } from "os";
145938
146398
  import path290 from "path";
145939
146399
  function scrubGrantedOutput(text, env, secrets = []) {
@@ -146055,12 +146515,12 @@ function lastAssistantText(history) {
146055
146515
  async function pruneReports(dir, keep) {
146056
146516
  const names = (await readdir47(dir).catch(() => [])).filter((n) => n.endsWith(".md")).sort();
146057
146517
  for (const old of names.slice(0, Math.max(0, names.length - keep))) {
146058
- await rm19(path290.join(dir, old), { force: true }).catch(() => {});
146518
+ await rm20(path290.join(dir, old), { force: true }).catch(() => {});
146059
146519
  }
146060
146520
  }
146061
146521
  async function runAgentTaskDispatch(projectRoot, entry, action, deps = {}) {
146062
146522
  const now = deps.now ?? (() => new Date);
146063
- const runId = deps.runId?.() ?? `sch-${now().toISOString().replace(/[-:.]/g, "").slice(0, 15)}-${randomUUID37().slice(0, 8)}`;
146523
+ const runId = deps.runId?.() ?? `sch-${now().toISOString().replace(/[-:.]/g, "").slice(0, 15)}-${randomUUID38().slice(0, 8)}`;
146064
146524
  await ensureLocksDir(projectRoot);
146065
146525
  try {
146066
146526
  return await withFileLock(dispatchLockPath(projectRoot, `schedule-${entry.name}`), () => runLocked(projectRoot, entry, action, deps, runId, now), {
@@ -146100,7 +146560,7 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
146100
146560
  await mkdir61(scratchHome, { recursive: true });
146101
146561
  await mkdir61(grantedCwd, { recursive: true, mode: 448 });
146102
146562
  const cleanup = async () => {
146103
- await rm19(scratch, { recursive: true, force: true }).catch(() => {});
146563
+ await rm20(scratch, { recursive: true, force: true }).catch(() => {});
146104
146564
  };
146105
146565
  let closeProxy = async () => {};
146106
146566
  const networkDecisions = [];
@@ -146223,7 +146683,7 @@ async function runLocked(projectRoot, entry, action, deps, runId, now) {
146223
146683
  modelId: dispatch.model,
146224
146684
  toolNames: tools.map((t) => t.definition.name)
146225
146685
  }),
146226
- idSeq: () => randomUUID37(),
146686
+ idSeq: () => randomUUID38(),
146227
146687
  unattended: true,
146228
146688
  hardDeny: unattendedRefusal,
146229
146689
  ...shellHooks !== undefined ? { hooks: shellHooks } : {}
@@ -146738,7 +147198,7 @@ var init_digest_limits = __esm(() => {
146738
147198
  });
146739
147199
 
146740
147200
  // src/scheduler/digest-summary.ts
146741
- import { randomUUID as randomUUID38 } from "crypto";
147201
+ import { randomUUID as randomUUID39 } from "crypto";
146742
147202
  var SYSTEM, MAX_OUTPUT_TOKENS = 400, defaultSummarize = async (input) => {
146743
147203
  const { action, entry } = input;
146744
147204
  const dispatch = action.dispatch;
@@ -146768,7 +147228,7 @@ var SYSTEM, MAX_OUTPUT_TOKENS = 400, defaultSummarize = async (input) => {
146768
147228
  local.abort();
146769
147229
  });
146770
147230
  const provider = guardUsage(built, () => meter.markUsageMissing());
146771
- const requestId = `digest-${randomUUID38().slice(0, 8)}`;
147231
+ const requestId = `digest-${randomUUID39().slice(0, 8)}`;
146772
147232
  const request = {
146773
147233
  providerId: dispatch.provider,
146774
147234
  modelId: dispatch.model,
@@ -146817,8 +147277,8 @@ var init_digest_summary = __esm(() => {
146817
147277
  });
146818
147278
 
146819
147279
  // src/scheduler/digest-run.ts
146820
- import { randomUUID as randomUUID39 } from "crypto";
146821
- import { mkdir as mkdir62, mkdtemp as mkdtemp8, rm as rm20, writeFile as writeFile39 } from "fs/promises";
147280
+ import { randomUUID as randomUUID40 } from "crypto";
147281
+ import { mkdir as mkdir62, mkdtemp as mkdtemp8, rm as rm21, writeFile as writeFile39 } from "fs/promises";
146822
147282
  import path292 from "path";
146823
147283
  function capForDelivery(text, reportPath) {
146824
147284
  if (text.length <= DELIVERY_TEXT_MAX)
@@ -146838,7 +147298,7 @@ async function announceRefusal(projectRoot, name, topic, runId, reason, result,
146838
147298
  }
146839
147299
  async function runDigestDispatch(projectRoot, entry, action, deps = {}) {
146840
147300
  const now = deps.now ?? (() => new Date);
146841
- const runId = deps.runId?.() ?? `dig-${now().toISOString().replace(/[-:.]/g, "").slice(0, 15)}-${randomUUID39().slice(0, 8)}`;
147301
+ const runId = deps.runId?.() ?? `dig-${now().toISOString().replace(/[-:.]/g, "").slice(0, 15)}-${randomUUID40().slice(0, 8)}`;
146842
147302
  await ensureLocksDir(projectRoot);
146843
147303
  try {
146844
147304
  return await withFileLock(dispatchLockPath(projectRoot, `schedule-${entry.name}`), () => runLocked2(projectRoot, entry, action, deps, runId, now), {
@@ -146950,7 +147410,7 @@ async function runLocked2(projectRoot, entry, action, deps, runId, now) {
146950
147410
  crashed = error instanceof Error ? error.message : String(error);
146951
147411
  } finally {
146952
147412
  limits.dispose();
146953
- await rm20(scratch, { recursive: true, force: true }).catch(() => {});
147413
+ await rm21(scratch, { recursive: true, force: true }).catch(() => {});
146954
147414
  }
146955
147415
  const tools = DIGEST_TOOL_IDS.filter((id) => action.grants.tools.includes(id));
146956
147416
  const attempted = tools.length * action.grants.repos.length;
@@ -155829,7 +156289,7 @@ var init_debug_watcher = __esm(() => {
155829
156289
  });
155830
156290
 
155831
156291
  // src/commands/shell.ts
155832
- import { randomUUID as randomUUID40 } from "crypto";
156292
+ import { randomUUID as randomUUID41 } from "crypto";
155833
156293
  import { join as joinPath2 } from "path";
155834
156294
  import * as readline2 from "readline";
155835
156295
  function reportMcpProblems(runtime) {
@@ -158188,14 +158648,14 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
158188
158648
  `);
158189
158649
  }
158190
158650
  const surface = chooseShellSurface(flags, runtime.isTty ?? process.stdout.isTTY === true);
158191
- const shellHookSessionId = randomUUID40();
158651
+ const shellHookSessionId = randomUUID41();
158192
158652
  let shellHooks;
158193
158653
  const getShellHooks = () => {
158194
158654
  if (shellHooks === undefined) {
158195
158655
  shellHooks = buildShellHookRuntime({
158196
158656
  projectRoot: resolveProjectRoot2(process.cwd()),
158197
158657
  sessionId: shellHookSessionId,
158198
- runId: randomUUID40(),
158658
+ runId: randomUUID41(),
158199
158659
  interactive: true,
158200
158660
  profileId: "monitored-trusted-local",
158201
158661
  ...runtime.cacheDir === undefined ? {} : { configDir: runtime.cacheDir }
@@ -158300,7 +158760,7 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
158300
158760
  sessionOverride: reasoningSessionOverride,
158301
158761
  globalEffort: loadShellConfig(runtime.cacheDir).reasoningEffort
158302
158762
  }),
158303
- idSeq: () => randomUUID40(),
158763
+ idSeq: () => randomUUID41(),
158304
158764
  askUser: invokeAskUserHost,
158305
158765
  sweepBackgroundJobs: () => jobRegistry.sweepAll(),
158306
158766
  jobRegistry,
@@ -158371,7 +158831,7 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
158371
158831
  return {
158372
158832
  makeProvider: chatFactory,
158373
158833
  clock: () => new Date().toISOString(),
158374
- idSeq: () => randomUUID40(),
158834
+ idSeq: () => randomUUID41(),
158375
158835
  initial: Object.keys(resolvedModelParams).length > 0 ? { ...sel, modelParams: resolvedModelParams } : sel,
158376
158836
  session: {
158377
158837
  cwd,
@@ -158499,7 +158959,7 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
158499
158959
  const deps = {
158500
158960
  makeProvider: baseFactory,
158501
158961
  clock: () => new Date().toISOString(),
158502
- idSeq: () => randomUUID40(),
158962
+ idSeq: () => randomUUID41(),
158503
158963
  initial: {
158504
158964
  provider,
158505
158965
  model,
@@ -158580,7 +159040,7 @@ Example: keryx shell --provider ollama --model llama3.1:latest`);
158580
159040
  sessionOverride: reasoningSessionOverride,
158581
159041
  globalEffort: loadShellConfig(runtime.cacheDir).reasoningEffort
158582
159042
  }),
158583
- idSeq: () => randomUUID40(),
159043
+ idSeq: () => randomUUID41(),
158584
159044
  askUser: invokeAskUserHost,
158585
159045
  mcpRuntime: () => mcpRuntime,
158586
159046
  sweepBackgroundJobs: () => jobRegistry.sweepAll(),
@@ -163090,8 +163550,8 @@ var init_sweep = __esm(() => {
163090
163550
  });
163091
163551
 
163092
163552
  // src/retention/auto-sweep.ts
163093
- import { mkdir as mkdir63, readFile as readFile158, rm as rm21, stat as stat30, writeFile as writeFile40 } from "fs/promises";
163094
- import { randomUUID as randomUUID41 } from "crypto";
163553
+ import { mkdir as mkdir63, readFile as readFile158, rm as rm22, stat as stat31, writeFile as writeFile40 } from "fs/promises";
163554
+ import { randomUUID as randomUUID42 } from "crypto";
163095
163555
  import path309 from "path";
163096
163556
  function autoSweepStampPath(cwd) {
163097
163557
  return path309.join(cwd, ".metaproject", "data", "retention", "last-auto-sweep.json");
@@ -163123,7 +163583,7 @@ async function readAutoSweepStamp(cwd) {
163123
163583
  }
163124
163584
  async function claimIsLive(cwd, staleMs) {
163125
163585
  const claimPath = autoSweepClaimPath(cwd);
163126
- const held = await stat30(claimPath).catch(() => null);
163586
+ const held = await stat31(claimPath).catch(() => null);
163127
163587
  if (held === null || Date.now() - held.mtimeMs > staleMs) {
163128
163588
  return false;
163129
163589
  }
@@ -163140,7 +163600,7 @@ async function claimIsLive(cwd, staleMs) {
163140
163600
  }
163141
163601
  }
163142
163602
  async function acquireClaim(claimPath, staleMs) {
163143
- const nonce = `${process.pid}:${randomUUID41()}`;
163603
+ const nonce = `${process.pid}:${randomUUID42()}`;
163144
163604
  for (let attempt = 0;attempt < 2; attempt += 1) {
163145
163605
  try {
163146
163606
  await writeFile40(claimPath, nonce, { flag: "wx", mode: 384 });
@@ -163148,7 +163608,7 @@ async function acquireClaim(claimPath, staleMs) {
163148
163608
  release: async () => {
163149
163609
  try {
163150
163610
  if (await readFile158(claimPath, "utf8") === nonce) {
163151
- await rm21(claimPath, { force: true });
163611
+ await rm22(claimPath, { force: true });
163152
163612
  }
163153
163613
  } catch {}
163154
163614
  }
@@ -163158,9 +163618,9 @@ async function acquireClaim(claimPath, staleMs) {
163158
163618
  if (code !== "EEXIST") {
163159
163619
  return null;
163160
163620
  }
163161
- const held = await stat30(claimPath).catch(() => null);
163621
+ const held = await stat31(claimPath).catch(() => null);
163162
163622
  if (held !== null && Date.now() - held.mtimeMs > staleMs) {
163163
- await rm21(claimPath, { force: true }).catch(() => {
163623
+ await rm22(claimPath, { force: true }).catch(() => {
163164
163624
  return;
163165
163625
  });
163166
163626
  continue;
@@ -163229,7 +163689,7 @@ var init_auto_sweep = __esm(() => {
163229
163689
 
163230
163690
  // src/ctx/artifact-id.ts
163231
163691
  import { randomBytes as randomBytes13 } from "crypto";
163232
- import { mkdir as mkdir64, readFile as readFile159, rm as rm22, writeFile as writeFile41 } from "fs/promises";
163692
+ import { mkdir as mkdir64, readFile as readFile159, rm as rm23, writeFile as writeFile41 } from "fs/promises";
163233
163693
  import path310 from "path";
163234
163694
  function pinnedClock() {
163235
163695
  const pin = process.env.KERYX_CTX_CLOCK_PIN_MS;
@@ -163278,7 +163738,7 @@ async function reserveArtifact(options) {
163278
163738
  continue;
163279
163739
  }
163280
163740
  if (!await claim(summaryPath)) {
163281
- await rm22(rawPath, { force: true });
163741
+ await rm23(rawPath, { force: true });
163282
163742
  continue;
163283
163743
  }
163284
163744
  return { id, rawPath, summaryPath };
@@ -164754,7 +165214,7 @@ function readLiteral(source, start, quote) {
164754
165214
  }
164755
165215
 
164756
165216
  // src/wiki/freshness/queue.ts
164757
- import { readFile as readFile161, rename as rename10, stat as stat31, unlink as unlink3, writeFile as writeFile43 } from "fs/promises";
165217
+ import { readFile as readFile161, rename as rename11, stat as stat32, unlink as unlink3, writeFile as writeFile43 } from "fs/promises";
164758
165218
  import path312 from "path";
164759
165219
  function queuePath(cwd) {
164760
165220
  return path312.join(cwd, ".metaproject", "data", "wiki", QUEUE_FILE);
@@ -164776,7 +165236,7 @@ async function drainQueue(cwd) {
164776
165236
  if (line.trim().length === 0) {
164777
165237
  continue;
164778
165238
  }
164779
- const entry = parseEntry3(line);
165239
+ const entry = parseEntry4(line);
164780
165240
  if (entry === null) {
164781
165241
  corruptLines += 1;
164782
165242
  continue;
@@ -164798,7 +165258,7 @@ async function clearQueue(cwd) {
164798
165258
  }
164799
165259
  }
164800
165260
  }
164801
- function parseEntry3(line) {
165261
+ function parseEntry4(line) {
164802
165262
  try {
164803
165263
  const value = JSON.parse(line);
164804
165264
  if (value.schemaVersion !== 1 || typeof value.rev !== "string" || !/^[0-9a-f]{40}$/.test(value.rev) || typeof value.recordedAt !== "string" || !Array.isArray(value.paths)) {
@@ -169551,7 +170011,7 @@ var init_sync2 = __esm(() => {
169551
170011
  });
169552
170012
 
169553
170013
  // src/gdskills/rule-references.ts
169554
- import { stat as stat32 } from "fs/promises";
170014
+ import { stat as stat33 } from "fs/promises";
169555
170015
  import path328 from "path";
169556
170016
  function ruleReferences(content) {
169557
170017
  const refs = new Set;
@@ -169568,7 +170028,7 @@ function withKeryxDirSpelling(ref) {
169568
170028
  }
169569
170029
  async function isRegularFile(absolute) {
169570
170030
  try {
169571
- return (await stat32(absolute)).isFile();
170031
+ return (await stat33(absolute)).isFile();
169572
170032
  } catch {
169573
170033
  return false;
169574
170034
  }
@@ -169789,7 +170249,7 @@ var init_project_reviewers = __esm(() => {
169789
170249
  });
169790
170250
 
169791
170251
  // src/gdskills/import-skills.ts
169792
- import { readdir as readdir54, readFile as readFile170, stat as stat33 } from "fs/promises";
170252
+ import { readdir as readdir54, readFile as readFile170, stat as stat34 } from "fs/promises";
169793
170253
  import { homedir as homedir14 } from "os";
169794
170254
  import path330 from "path";
169795
170255
  function emptyOnlyError(label) {
@@ -169830,7 +170290,7 @@ async function importProjectSkills(options) {
169830
170290
  addFlagWarnings(imported, sources, existingFlags);
169831
170291
  const rules = [];
169832
170292
  for (const decision of ruleDecisions) {
169833
- rules.push("row" in decision ? decision.row : options.dryRun ? unwrittenRow(decision.placement, [decision.dryRunReason, ...gateNotes(decision.gate, true)].filter(isString3).join(" \u2014 ") || undefined, decision.gate.security) : await writePlacedRule(options, decision.placement, decision.gate));
170293
+ rules.push("row" in decision ? decision.row : options.dryRun ? unwrittenRow(decision.placement, [decision.dryRunReason, ...gateNotes(decision.gate, true)].filter(isString4).join(" \u2014 ") || undefined, decision.gate.security) : await writePlacedRule(options, decision.placement, decision.gate));
169834
170294
  }
169835
170295
  return {
169836
170296
  from: options.from,
@@ -170150,7 +170610,7 @@ async function resolveImportSources(options) {
170150
170610
  if (!await pathExists(resolved)) {
170151
170611
  throw new Error(`keryx skills import: --from ${options.from} does not exist (resolved to ${resolved})`);
170152
170612
  }
170153
- const stats = await stat33(resolved);
170613
+ const stats = await stat34(resolved);
170154
170614
  if (stats.isFile()) {
170155
170615
  return [await sourceFromFile(options, resolved)];
170156
170616
  }
@@ -170351,7 +170811,7 @@ function gateRowParts(gate, dryRun) {
170351
170811
  return security;
170352
170812
  }
170353
170813
  function gateNotes(gate, dryRun) {
170354
- return [gateRowParts(gate, dryRun).reason].filter(isString3);
170814
+ return [gateRowParts(gate, dryRun).reason].filter(isString4);
170355
170815
  }
170356
170816
  function plannedSkillText(content, header) {
170357
170817
  const version = parseSkillFrontmatter(content).metadataVersion ?? "0.1.0";
@@ -170967,7 +171427,7 @@ Examples:
170967
171427
  var BUNDLED_NAMES, PATHS_NONE_WARNING = 'paths: none \u2014 dispatched on every round. Declare `metadata.paths: "<glob>, <glob>"` in its frontmatter to gate it on the diff.', DEFAULT_FETCHER = async (url) => {
170968
171428
  const response = await fetch(url);
170969
171429
  return { ok: response.ok, status: response.status, text: await response.text() };
170970
- }, DEPRECATED_REASON = "deprecated", KNOWN_CATEGORIES, isString3 = (value) => value !== undefined, REFUSED_NOTE = "A refused file was not written.", ALLOW_FLAGGED_HINT = "A prompt-injection refusal can be overridden after you read the file: run the command again with --allow-flagged.", IMPORT_HEADER_LABELS, IMPORT_HEADER_LINE, BYTE_ORDER_MARK = 65279, ALLOW_FLAGGED_FLAG = "--allow-flagged", SECURITY_GATE_HELP = `Security gate: a SKILL.md or rule is written as the gate returns it, so a secret is
171430
+ }, DEPRECATED_REASON = "deprecated", KNOWN_CATEGORIES, isString4 = (value) => value !== undefined, REFUSED_NOTE = "A refused file was not written.", ALLOW_FLAGGED_HINT = "A prompt-injection refusal can be overridden after you read the file: run the command again with --allow-flagged.", IMPORT_HEADER_LABELS, IMPORT_HEADER_LINE, BYTE_ORDER_MARK = 65279, ALLOW_FLAGGED_FLAG = "--allow-flagged", SECURITY_GATE_HELP = `Security gate: a SKILL.md or rule is written as the gate returns it, so a secret is
170971
171431
  masked and the row says it was redacted, and any other finding is reported on the
170972
171432
  row. Text with a prompt-injection finding is refused in every security mode: the
170973
171433
  row is \`refused\` (\`would-refuse\` on a dry run) with the gate's own summary,
@@ -181155,12 +181615,29 @@ var init_command_registry = __esm(() => {
181155
181615
  {
181156
181616
  module: "decisions",
181157
181617
  command: "decisions report",
181158
- summary: "Match share between the human's choice and the agent's recommendation, by mode (ordinary, blind) and by stage, " + "with every deviation and its reason. Deterministic, no model.",
181618
+ summary: "Match share between the human's choice and the agent's recommendation, by mode (ordinary, blind) and by stage, " + "with every deviation and its reason. Backfilled (imported, historical) decisions are reported in a block of their own and never counted in the live shares or the time to answer. Deterministic, no model.",
181159
181619
  intent: ["decisions report", "\u043E\u0442\u0447\u0451\u0442 \u043F\u043E \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u044F\u043C", "how often does the human follow the recommendation", "blind mode results"],
181160
- args: [{ name: "json", type: "bool", required: false, desc: "print the report as JSON" }],
181620
+ args: [
181621
+ { name: "json", type: "bool", required: false, desc: "print the report as JSON (with a `backfilled` section)" },
181622
+ { name: "line", type: "bool", required: false, desc: "print ONE line in Russian for the daily topic message: the total and the match share of the visible, hidden and historical decisions" }
181623
+ ],
181161
181624
  json: true,
181162
181625
  read: true
181163
181626
  },
181627
+ {
181628
+ module: "decisions",
181629
+ command: "decisions import",
181630
+ summary: 'Import historical decisions from a JSON-lines file as backfilled records: the "before" arm of a comparison with the live journal. ' + "Each is marked backfilled, is never blind, keeps the time it was asked, and is reported apart from the live ones. " + "A line that is not a decision is skipped, named with its line number and counted as malformed, and the rest is imported; an id already in the journal is skipped, so a second import changes nothing (except that a backfilled decision missing its answer gets just that answer).",
181631
+ intent: ["decisions import", "import historical decisions", "backfill the recommendation journal", "\u0438\u043C\u043F\u043E\u0440\u0442 \u0438\u0441\u0442\u043E\u0440\u0438\u0447\u0435\u0441\u043A\u0438\u0445 \u0440\u0435\u0448\u0435\u043D\u0438\u0439", "\u0434\u043E\u0437\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u0436\u0443\u0440\u043D\u0430\u043B \u0440\u0435\u0448\u0435\u043D\u0438\u0439"],
181632
+ args: [
181633
+ { name: "<file>", type: "string", required: true, desc: "a JSON-lines file, one decision per line: id, at, flow, stage, question, options, recommendation, source, answer, reason" },
181634
+ { name: "dry-run", type: "bool", required: false, desc: "check and count without writing" },
181635
+ { name: "json", type: "bool", required: false, desc: 'print the counts as JSON (a failure is {"error": "..."})' }
181636
+ ],
181637
+ json: true,
181638
+ read: false,
181639
+ sideEffects: ["appends open, answer and reason records to .metaproject/data/decisions/journal.jsonl (nothing with --dry-run)"]
181640
+ },
181164
181641
  {
181165
181642
  module: "product",
181166
181643
  command: "product index",
@@ -182014,7 +182491,7 @@ function isPassGate(gate) {
182014
182491
 
182015
182492
  // src/commands/security-audit-harness.ts
182016
182493
  import path347 from "path";
182017
- import { stat as stat34 } from "fs/promises";
182494
+ import { stat as stat35 } from "fs/promises";
182018
182495
  function isSeverity(value) {
182019
182496
  return value !== undefined && SEVERITIES3.includes(value);
182020
182497
  }
@@ -182059,7 +182536,7 @@ async function handleAuditHarness(cwd, args = []) {
182059
182536
  }
182060
182537
  async function handleRun(cwd, args) {
182061
182538
  const root = resolveRoot(cwd, args);
182062
- const rootStat = await stat34(root).catch(() => {
182539
+ const rootStat = await stat35(root).catch(() => {
182063
182540
  return;
182064
182541
  });
182065
182542
  if (!rootStat || !rootStat.isDirectory()) {
@@ -182146,7 +182623,7 @@ async function handleApply(cwd, args) {
182146
182623
  process.exitCode = 1;
182147
182624
  return;
182148
182625
  }
182149
- const rootStat = await stat34(root).catch(() => {
182626
+ const rootStat = await stat35(root).catch(() => {
182150
182627
  return;
182151
182628
  });
182152
182629
  if (!rootStat || !rootStat.isDirectory()) {
@@ -184193,7 +184670,7 @@ var init_metaproject_tools2 = __esm(() => {
184193
184670
  // src/mcp/tools.ts
184194
184671
  import { readFile as readFile185, realpath as realpath22, writeFile as writeFile49 } from "fs/promises";
184195
184672
  import path351 from "path";
184196
- import { randomUUID as randomUUID42 } from "crypto";
184673
+ import { randomUUID as randomUUID43 } from "crypto";
184197
184674
  function sacWorkspaceService(cwd) {
184198
184675
  return new WorkspaceService({
184199
184676
  workspaceRoot: cwd,
@@ -184279,7 +184756,7 @@ function buildToolRegistry() {
184279
184756
  { name: "sac.collaboration", module: "sac", description: "Read the collaboration references and activity for one Shared Agent Context workspace \u2014 who is participating and what has moved recently, redacted to what this actor may see. Local stdio only: over HTTP it returns `sac_transport_denied` without reading anything, because HTTP has no verified principal and must not inherit the local OS actor. Returns references and activity, not the items themselves \u2014 use sac.overview to enumerate items and sac.read to fetch one. Discover the workspaceId with sac.workspaceList.", inputSchema: OBJECT_SCHEMA({ workspaceId: { type: "string" } }, ["workspaceId"]), mutating: false, async invoke(cwd, params, context) {
184280
184757
  if (context?.transport === "http")
184281
184758
  return { code: "sac_transport_denied" };
184282
- return normalizeCollaborationResult(await createLocalCollaborationService(cwd).overview({ workspaceId: stringParam2(params, "workspaceId") ?? "", request: undefined, requestCorrelationId: randomUUID42() }));
184759
+ return normalizeCollaborationResult(await createLocalCollaborationService(cwd).overview({ workspaceId: stringParam2(params, "workspaceId") ?? "", request: undefined, requestCorrelationId: randomUUID43() }));
184283
184760
  } },
184284
184761
  {
184285
184762
  name: "sac.overview",
@@ -184293,7 +184770,7 @@ function buildToolRegistry() {
184293
184770
  const workspaceId = stringParam2(params, "workspaceId") ?? "";
184294
184771
  const maxItems = typeof params.maxItems === "number" ? params.maxItems : 32;
184295
184772
  const maxTokens = typeof params.maxTokens === "number" ? params.maxTokens : 4096;
184296
- return normalizeFwkResult(await createLocalFwkReadService(cwd).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID42(), budget: { maxItems, maxTokens } }));
184773
+ return normalizeFwkResult(await createLocalFwkReadService(cwd).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID43(), budget: { maxItems, maxTokens } }));
184297
184774
  }
184298
184775
  },
184299
184776
  {
@@ -184309,7 +184786,7 @@ function buildToolRegistry() {
184309
184786
  const itemId = stringParam2(params, "itemId") ?? "";
184310
184787
  const maxItems = typeof params.maxItems === "number" ? params.maxItems : 1;
184311
184788
  const maxTokens = typeof params.maxTokens === "number" ? params.maxTokens : 4096;
184312
- return normalizeFwkResult(await createLocalFwkReadService(cwd).read({ workspaceId, itemId, request: undefined, requestCorrelationId: randomUUID42(), budget: { maxItems, maxTokens } }));
184789
+ return normalizeFwkResult(await createLocalFwkReadService(cwd).read({ workspaceId, itemId, request: undefined, requestCorrelationId: randomUUID43(), budget: { maxItems, maxTokens } }));
184313
184790
  }
184314
184791
  },
184315
184792
  {
@@ -184330,12 +184807,12 @@ function buildToolRegistry() {
184330
184807
  if (!session)
184331
184808
  throw new Error(`no session matching "${sessionRef}" in this project`);
184332
184809
  const { service, wrapUpAuthority, authorizationServer } = createHarnessProposalLifecycleService(cwd, { workspaceId, ...note ? { note } : {} });
184333
- const requestCorrelationId = randomUUID42();
184810
+ const requestCorrelationId = randomUUID43();
184334
184811
  const actor = await authorizationServer.actorContextFor(undefined, requestCorrelationId);
184335
184812
  if (!actor)
184336
184813
  throw new Error("trusted ActorContext is required");
184337
184814
  const wrapUp = await wrapUpAuthority.issue({ actor, source: "session", sourceRef: sessionEvidenceRef(workspaceId, session.id) });
184338
- const proposal = await service.create({ request: undefined, requestCorrelationId, workspaceId, id: `proposal-${randomUUID42().replace(/-/g, "").slice(0, 16)}`, proposalRevision, kind, wrapUp });
184815
+ const proposal = await service.create({ request: undefined, requestCorrelationId, workspaceId, id: `proposal-${randomUUID43().replace(/-/g, "").slice(0, 16)}`, proposalRevision, kind, wrapUp });
184339
184816
  if (note)
184340
184817
  await writeFile49(proposalNotePath(cwd, workspaceId, proposal.id), note, "utf8");
184341
184818
  return normalizeProposalLifecycleResult(proposal);
@@ -184354,9 +184831,9 @@ function buildToolRegistry() {
184354
184831
  const proposalId = stringParam2(params, "proposalId") ?? "";
184355
184832
  const decision = stringParam2(params, "decision");
184356
184833
  const reason = stringParam2(params, "reason");
184357
- const idempotencyKey = stringParam2(params, "idempotencyKey") ?? randomUUID42();
184834
+ const idempotencyKey = stringParam2(params, "idempotencyKey") ?? randomUUID43();
184358
184835
  const confirmToken = stringParam2(params, "confirmToken");
184359
- const result = await createHarnessProposalLifecycleService(cwd, { workspaceId }).service.review({ request: undefined, requestCorrelationId: randomUUID42(), workspaceId, proposalId, decision, idempotencyKey, interactive: true, ...reason ? { reason } : {}, ...confirmToken ? { confirmToken } : {} });
184836
+ const result = await createHarnessProposalLifecycleService(cwd, { workspaceId }).service.review({ request: undefined, requestCorrelationId: randomUUID43(), workspaceId, proposalId, decision, idempotencyKey, interactive: true, ...reason ? { reason } : {}, ...confirmToken ? { confirmToken } : {} });
184360
184837
  return normalizeProposalLifecycleResult(result);
184361
184838
  }
184362
184839
  },
@@ -184404,7 +184881,7 @@ function buildToolRegistry() {
184404
184881
  throw new Error("sac.workspaceCreate requires a non-empty 'title'");
184405
184882
  const rawComponent = stringParam2(params, "component");
184406
184883
  const component = rawComponent === undefined ? undefined : requireWorkspaceReference(rawComponent);
184407
- const workspace = await sacWorkspaceService(cwd).create({ request: undefined, requestCorrelationId: randomUUID42(), id: newWorkspaceId(), title, ...component ? { component: { kind: "component", uri: component } } : {} });
184884
+ const workspace = await sacWorkspaceService(cwd).create({ request: undefined, requestCorrelationId: randomUUID43(), id: newWorkspaceId(), title, ...component ? { component: { kind: "component", uri: component } } : {} });
184408
184885
  return workspace;
184409
184886
  }
184410
184887
  },
@@ -184465,7 +184942,7 @@ function buildToolRegistry() {
184465
184942
  const text = redactSensitiveText(rawText);
184466
184943
  const ts = new Date().toISOString();
184467
184944
  const seed = {
184468
- id: `seed-${randomUUID42()}`,
184945
+ id: `seed-${randomUUID43()}`,
184469
184946
  text,
184470
184947
  ts,
184471
184948
  ...kind ? { kind } : {},
@@ -184911,7 +185388,7 @@ var init_tools3 = __esm(() => {
184911
185388
 
184912
185389
  // src/mcp/resources.ts
184913
185390
  import path352 from "path";
184914
- import { lstat as lstat19, readdir as readdir63, realpath as realpath23, stat as stat35 } from "fs/promises";
185391
+ import { lstat as lstat19, readdir as readdir63, realpath as realpath23, stat as stat36 } from "fs/promises";
184915
185392
  function mimeForPath(filePath) {
184916
185393
  if (filePath.endsWith(".json") || filePath.endsWith(".jsonl")) {
184917
185394
  return "application/json";
@@ -184954,7 +185431,7 @@ async function walkFiles(root, ownerRoot = root, ancestors = new Set) {
184954
185431
  }
184955
185432
  for (const entry of entries) {
184956
185433
  const full = path352.join(root, entry.name);
184957
- const info = await stat35(full).catch(() => null);
185434
+ const info = await stat36(full).catch(() => null);
184958
185435
  if (!info || !isPathInside(ownerReal, await realpath23(full).catch(() => "")))
184959
185436
  continue;
184960
185437
  if (info.isDirectory()) {
@@ -185075,7 +185552,7 @@ async function readResource(cwd, roots, uri, harnessIdentity = null) {
185075
185552
  throw new Error(`Resource not found: ${uri}`);
185076
185553
  }
185077
185554
  }
185078
- const info = await stat35(resolved.absolute).catch(() => null);
185555
+ const info = await stat36(resolved.absolute).catch(() => null);
185079
185556
  if (!info || !info.isFile()) {
185080
185557
  throw new Error(`Resource not found: ${uri}`);
185081
185558
  }
@@ -186593,7 +187070,7 @@ var init_service18 = __esm(() => {
186593
187070
 
186594
187071
  // src/commands/stack.ts
186595
187072
  import path356 from "path";
186596
- import { stat as stat36 } from "fs/promises";
187073
+ import { stat as stat37 } from "fs/promises";
186597
187074
  async function stackCommand(args, cwd = process.cwd()) {
186598
187075
  const sub = args[0];
186599
187076
  if (sub === undefined || sub === "--help" || sub === "-h") {
@@ -186625,7 +187102,7 @@ async function handleDetect(args, cwd) {
186625
187102
  const write = !args.includes("--no-write");
186626
187103
  let rootStat;
186627
187104
  try {
186628
- rootStat = await stat36(root);
187105
+ rootStat = await stat37(root);
186629
187106
  } catch {
186630
187107
  console.error(`--cwd directory does not exist: ${root}`);
186631
187108
  process.exitCode = 1;
@@ -188125,7 +188602,7 @@ function checkApproval(input) {
188125
188602
  // src/commands/harness.ts
188126
188603
  import { readFileSync as readFileSync28, writeFileSync as writeFileSync10 } from "fs";
188127
188604
  import path357 from "path";
188128
- import { randomUUID as randomUUID43 } from "crypto";
188605
+ import { randomUUID as randomUUID44 } from "crypto";
188129
188606
  import { realpathSync as realpathSync18 } from "fs";
188130
188607
  import { homedir as homedir15, tmpdir as tmpdir14 } from "os";
188131
188608
  function canonicalPath2(p) {
@@ -188152,7 +188629,7 @@ function resolveRuntime(deps) {
188152
188629
  const env = deps?.env ?? process.env;
188153
188630
  const clock = deps?.clock ?? (() => new Date().toISOString());
188154
188631
  let idCounter = 0;
188155
- const idSeq = deps?.idSeq ?? (() => `${randomUUID43()}-${idCounter++}`);
188632
+ const idSeq = deps?.idSeq ?? (() => `${randomUUID44()}-${idCounter++}`);
188156
188633
  return { env, clock, idSeq };
188157
188634
  }
188158
188635
  function shellAllowProfile() {
@@ -188256,7 +188733,7 @@ async function harnessCommand(args, deps) {
188256
188733
  const env = deps?.env ?? process.env;
188257
188734
  const clock = deps?.clock ?? (() => new Date().toISOString());
188258
188735
  let idCounter = 0;
188259
- const idSeq = deps?.idSeq ?? (() => `${randomUUID43()}-${idCounter++}`);
188736
+ const idSeq = deps?.idSeq ?? (() => `${randomUUID44()}-${idCounter++}`);
188260
188737
  const fetchImpl = deps?.fetch ?? globalThis.fetch;
188261
188738
  if (provider === "anthropic") {
188262
188739
  const apiKey = env.ANTHROPIC_API_KEY;
@@ -188397,7 +188874,7 @@ function harnessReplay(args, deps) {
188397
188874
  }
188398
188875
  const clock = deps?.clock ?? (() => new Date().toISOString());
188399
188876
  let idCounter = 0;
188400
- const idSeq = deps?.idSeq ?? (() => `${randomUUID43()}-${idCounter++}`);
188877
+ const idSeq = deps?.idSeq ?? (() => `${randomUUID44()}-${idCounter++}`);
188401
188878
  const fixture = (() => {
188402
188879
  if (parsed.fixture === undefined || parsed.fixture.length === 0) {
188403
188880
  return { ok: true, value: buildReplayFixture(run, { idSeq }), built: true };
@@ -189112,7 +189589,7 @@ var init_permission = __esm(() => {
189112
189589
  });
189113
189590
 
189114
189591
  // src/acp/agent-io.ts
189115
- import { randomUUID as randomUUID44 } from "crypto";
189592
+ import { randomUUID as randomUUID45 } from "crypto";
189116
189593
  function toolKindFor(name) {
189117
189594
  return TOOL_KIND_BY_NAME[name] ?? "other";
189118
189595
  }
@@ -189127,7 +189604,7 @@ function createAcpAgentIo(sessionId, send, askPermission) {
189127
189604
  const pendingByName = new Map;
189128
189605
  const emit = (update) => send(sessionId, update);
189129
189606
  const openToolCall = (name, input, claimed) => {
189130
- const toolCallId = randomUUID44();
189607
+ const toolCallId = randomUUID45();
189131
189608
  const queue = pendingByName.get(name) ?? [];
189132
189609
  queue.push({ toolCallId, input, claimed });
189133
189610
  pendingByName.set(name, queue);
@@ -189214,7 +189691,7 @@ function createAcpAgentIo(sessionId, send, askPermission) {
189214
189691
  const toolCallId = pending?.toolCallId;
189215
189692
  emit({
189216
189693
  sessionUpdate: "tool_call_update",
189217
- toolCallId: toolCallId ?? randomUUID44(),
189694
+ toolCallId: toolCallId ?? randomUUID45(),
189218
189695
  status: result.isError ? "failed" : "completed",
189219
189696
  content: [{ type: "content", content: textBlock(result.output) }],
189220
189697
  rawOutput: result.output
@@ -189813,7 +190290,7 @@ var init_session_mcp = __esm(() => {
189813
190290
  });
189814
190291
 
189815
190292
  // src/acp/server.ts
189816
- import { randomUUID as randomUUID45 } from "crypto";
190293
+ import { randomUUID as randomUUID46 } from "crypto";
189817
190294
  function finishReasonToStopReason(finishReason) {
189818
190295
  switch (finishReason) {
189819
190296
  case "budget":
@@ -189833,7 +190310,7 @@ function refuse5(error) {
189833
190310
  async function runAcpServer(options) {
189834
190311
  let initialized = false;
189835
190312
  let clientCapabilities;
189836
- const idSeq = options.idSeq ?? (() => randomUUID45());
190313
+ const idSeq = options.idSeq ?? (() => randomUUID46());
189837
190314
  const registry = new AcpSessionRegistry({
189838
190315
  providerId: options.providerId,
189839
190316
  modelId: options.modelId,
@@ -190476,7 +190953,7 @@ Switch with /model <model>; it applies from the next turn.`;
190476
190953
  }
190477
190954
  continue;
190478
190955
  }
190479
- const toolCallId = message.toolCallId ?? randomUUID45();
190956
+ const toolCallId = message.toolCallId ?? randomUUID46();
190480
190957
  sendUpdate(sessionId, {
190481
190958
  sessionUpdate: "tool_call_update",
190482
190959
  toolCallId,
@@ -190715,7 +191192,7 @@ var MODEL_PLACEHOLDER = "{{model}}";
190715
191192
  var init_fixture_provider = () => {};
190716
191193
 
190717
191194
  // src/commands/acp.ts
190718
- import { randomUUID as randomUUID46 } from "crypto";
191195
+ import { randomUUID as randomUUID47 } from "crypto";
190719
191196
  function parseAcpArgs(args) {
190720
191197
  const parsed = {};
190721
191198
  for (let i = 0;i < args.length; i += 1) {
@@ -190969,7 +191446,7 @@ async function acpCommand(args) {
190969
191446
  } : { providerUnavailable: resolution.message, providerId: "", modelId: "" },
190970
191447
  agentInfo: { name: "keryx", version: package_default.version },
190971
191448
  ...parsed.dataDir !== undefined ? { dataDir: parsed.dataDir } : {},
190972
- idSeq: () => randomUUID46()
191449
+ idSeq: () => randomUUID47()
190973
191450
  });
190974
191451
  } finally {
190975
191452
  process.off("SIGTERM", onSignal);
@@ -191036,7 +191513,7 @@ var init_acp = __esm(() => {
191036
191513
  });
191037
191514
 
191038
191515
  // src/bus/prune.ts
191039
- import { randomUUID as randomUUID47 } from "crypto";
191516
+ import { randomUUID as randomUUID48 } from "crypto";
191040
191517
  async function expiryAlreadyLogged(root, leaseId) {
191041
191518
  const { events } = await readEvents(root, await cursorAtStart(root));
191042
191519
  return events.some((event) => event.kind === "lease-expired" && event.refs?.leaseId === leaseId);
@@ -191070,7 +191547,7 @@ async function pruneBus(root, options = {}) {
191070
191547
  const file = leasePath(root, lease.leaseId);
191071
191548
  try {
191072
191549
  await appendEvent(root, {
191073
- from: { instanceId: randomUUID47(), name: "system", origin: "system" },
191550
+ from: { instanceId: randomUUID48(), name: "system", origin: "system" },
191074
191551
  to: ["*"],
191075
191552
  toLabel: "@all",
191076
191553
  kind: "lease-expired",
@@ -191123,7 +191600,7 @@ var init_prune3 = __esm(() => {
191123
191600
  });
191124
191601
 
191125
191602
  // src/commands/bus.ts
191126
- import { randomUUID as randomUUID48 } from "crypto";
191603
+ import { randomUUID as randomUUID49 } from "crypto";
191127
191604
  async function busCommand(args) {
191128
191605
  const code = await runBusCommand(args);
191129
191606
  if (code !== 0)
@@ -191276,7 +191753,7 @@ ${PAUSE_USAGE3}`);
191276
191753
  if (toLabel === undefined || reason === undefined || reason.length === 0) {
191277
191754
  throw new BusRefusal("invalid-event", PAUSE_USAGE3);
191278
191755
  }
191279
- const holder = { instanceId: randomUUID48(), name: "cli", origin: "cli" };
191756
+ const holder = { instanceId: randomUUID49(), name: "cli", origin: "cli" };
191280
191757
  const lease = await createPauseLease(busRoot, {
191281
191758
  holder,
191282
191759
  toLabel,
@@ -191298,7 +191775,7 @@ async function resume(args, busRoot, ctx) {
191298
191775
  if (leaseId === undefined) {
191299
191776
  throw new BusRefusal("invalid-event", "usage: keryx bus resume <leaseId> [--json]");
191300
191777
  }
191301
- await resumePauseLease(busRoot, { leaseId, by: { instanceId: randomUUID48(), name: "cli", origin: "cli" }, now: ctx.now });
191778
+ await resumePauseLease(busRoot, { leaseId, by: { instanceId: randomUUID49(), name: "cli", origin: "cli" }, now: ctx.now });
191302
191779
  if (args.includes("--json")) {
191303
191780
  ctx.out(JSON.stringify({ schemaVersion: 1, leaseId }, null, 2));
191304
191781
  } else {
@@ -191602,7 +192079,7 @@ var init_modules = __esm(() => {
191602
192079
  });
191603
192080
 
191604
192081
  // src/lib/serve-approvals-broker.ts
191605
- import { randomUUID as randomUUID49 } from "crypto";
192082
+ import { randomUUID as randomUUID50 } from "crypto";
191606
192083
  function describeAsk(ask) {
191607
192084
  const floors = ask.floors.length > 0 ? ` Needs a fresh answer every time (${ask.floors.join(", ")}).` : "";
191608
192085
  return {
@@ -191658,7 +192135,7 @@ function createApprovalBroker(options) {
191658
192135
  sessionId: ask.sessionId,
191659
192136
  ...text,
191660
192137
  expiresAt: new Date(createdAt.getTime() + options.expirySeconds * 1000),
191661
- correlationId: randomUUID49(),
192138
+ correlationId: randomUUID50(),
191662
192139
  callFingerprint: ask.callFingerprint,
191663
192140
  floors: ask.floors
191664
192141
  }, options.dir, createdAt);
@@ -191800,7 +192277,7 @@ var init_serve_throttle = __esm(() => {
191800
192277
  });
191801
192278
 
191802
192279
  // src/lib/serve-turn.ts
191803
- import { randomUUID as randomUUID50 } from "crypto";
192280
+ import { randomUUID as randomUUID51 } from "crypto";
191804
192281
  import path359 from "path";
191805
192282
  function validateTurnRequest(body) {
191806
192283
  const problem = (message) => ({
@@ -191975,7 +192452,7 @@ async function redactOut(security, text) {
191975
192452
  async function runRemoteTurn(input) {
191976
192453
  const scanRoot = input.scanRoot;
191977
192454
  const security = createSecurityService(scanRoot);
191978
- const newId = input.newId ?? (() => randomUUID50());
192455
+ const newId = input.newId ?? (() => randomUUID51());
191979
192456
  const clock = input.clock ?? (() => new Date().toISOString());
191980
192457
  const turnId = input.turnId ?? newId();
191981
192458
  const sessionId = input.request.sessionId ?? newId();
@@ -192158,7 +192635,7 @@ function outcomeOf(status, gate, unresolvedBlockerIds) {
192158
192635
  }
192159
192636
  function createSubmitTurn(deps) {
192160
192637
  return async (request, project) => {
192161
- const turnId = (deps.newId ?? (() => randomUUID50()))();
192638
+ const turnId = (deps.newId ?? (() => randomUUID51()))();
192162
192639
  const scanned = await scanPrompt(deps.dir, request.prompt);
192163
192640
  if (scanned.rejected) {
192164
192641
  return { kind: "rejected" };
@@ -192173,7 +192650,7 @@ function createSubmitTurn(deps) {
192173
192650
  }
192174
192651
  let effected = false;
192175
192652
  const detached = deps.approvals !== undefined && (deps.toolRegistry?.list().length ?? 0) > 0;
192176
- const sessionId = request.sessionId ?? (deps.newId ?? (() => randomUUID50()))();
192653
+ const sessionId = request.sessionId ?? (deps.newId ?? (() => randomUUID51()))();
192177
192654
  let onStarted = () => {
192178
192655
  return;
192179
192656
  };
@@ -194059,7 +194536,7 @@ var init_durable_log = __esm(() => {
194059
194536
  import { createHash as createHash80 } from "crypto";
194060
194537
  import { unlinkSync as unlinkSync9 } from "fs";
194061
194538
  import path361 from "path";
194062
- function parseEntry4(value) {
194539
+ function parseEntry5(value) {
194063
194540
  if (typeof value !== "object" || value === null) {
194064
194541
  return;
194065
194542
  }
@@ -194095,7 +194572,7 @@ class InboundQueues {
194095
194572
  log(bindingKey) {
194096
194573
  let log = this.logs.get(bindingKey);
194097
194574
  if (log === undefined) {
194098
- log = new DurableLog({ file: this.fileFor(bindingKey), parse: parseEntry4, maxEntries: MAX_INBOUND_PER_TOPIC });
194575
+ log = new DurableLog({ file: this.fileFor(bindingKey), parse: parseEntry5, maxEntries: MAX_INBOUND_PER_TOPIC });
194099
194576
  log.load();
194100
194577
  this.logs.set(bindingKey, log);
194101
194578
  }
@@ -194736,9 +195213,9 @@ var init_rendering = __esm(() => {
194736
195213
  });
194737
195214
 
194738
195215
  // src/remote/outbound-queue.ts
194739
- import { randomUUID as randomUUID51 } from "crypto";
195216
+ import { randomUUID as randomUUID52 } from "crypto";
194740
195217
  import path363 from "path";
194741
- function parseEntry5(value) {
195218
+ function parseEntry6(value) {
194742
195219
  if (typeof value !== "object" || value === null) {
194743
195220
  return;
194744
195221
  }
@@ -194781,7 +195258,7 @@ class OutboundQueue {
194781
195258
  this.log = new DurableLog({
194782
195259
  file: path363.join(directory, OUTBOUND_FILE),
194783
195260
  maxEntries: options.maxEntries ?? OUTBOUND_MAX_ENTRIES,
194784
- parse: parseEntry5
195261
+ parse: parseEntry6
194785
195262
  });
194786
195263
  }
194787
195264
  load() {
@@ -194798,7 +195275,7 @@ class OutboundQueue {
194798
195275
  const entries = [];
194799
195276
  parts.forEach((text, index) => {
194800
195277
  const entry = {
194801
- id: randomUUID51(),
195278
+ id: randomUUID52(),
194802
195279
  chatId: message.chatId,
194803
195280
  ...message.threadId === undefined ? {} : { threadId: message.threadId },
194804
195281
  text,
@@ -197932,7 +198409,7 @@ var init_serve_digest = __esm(() => {
197932
198409
  });
197933
198410
 
197934
198411
  // src/commands/serve.ts
197935
- import { randomUUID as randomUUID52 } from "crypto";
198412
+ import { randomUUID as randomUUID53 } from "crypto";
197936
198413
  function parseArgs5(args, valueFlags, booleanFlags) {
197937
198414
  const values = new Map;
197938
198415
  const flags = new Set;
@@ -198258,7 +198735,7 @@ function runConfig(args) {
198258
198735
  return;
198259
198736
  }
198260
198737
  const credential = readServeCredential();
198261
- const credentialId = credential.status === "ok" ? credential.record.id : randomUUID52();
198738
+ const credentialId = credential.status === "ok" ? credential.record.id : randomUUID53();
198262
198739
  const config = defaultServeConfig(credentialId, {
198263
198740
  address: parsed.parsed.values.get("--bind") ?? DEFAULT_SERVE_BIND_ADDRESS,
198264
198741
  port: port ?? DEFAULT_SERVE_PORT,
@@ -199932,7 +200409,7 @@ ${settled.stderr}` };
199932
200409
  var PROBE_TIMEOUT_MS = 1e4;
199933
200410
 
199934
200411
  // src/commands/agents-external.ts
199935
- import { randomUUID as randomUUID53 } from "crypto";
200412
+ import { randomUUID as randomUUID54 } from "crypto";
199936
200413
  import { mkdir as mkdir73 } from "fs/promises";
199937
200414
  import { tmpdir as tmpdir15 } from "os";
199938
200415
  import path369 from "path";
@@ -200219,7 +200696,7 @@ async function runCommand4(args, deps, log) {
200219
200696
  taskTitle: task.length > 80 ? `${task.slice(0, 77)}...` : task,
200220
200697
  taskDescription: task,
200221
200698
  acceptanceCriteria: [],
200222
- worktreeId: `acp-${randomUUID53()}`,
200699
+ worktreeId: `acp-${randomUUID54()}`,
200223
200700
  maxPromptBytes: gate.config.maxPromptBytes,
200224
200701
  timeoutMs,
200225
200702
  parentEnv: env,
@@ -201865,7 +202342,7 @@ var init_metrics2 = __esm(() => {
201865
202342
  });
201866
202343
 
201867
202344
  // src/metrics/ablation-runner.ts
201868
- function median2(values) {
202345
+ function median3(values) {
201869
202346
  if (values.length === 0)
201870
202347
  return null;
201871
202348
  const sorted = [...values].sort((a, b) => a - b);
@@ -201891,7 +202368,7 @@ function toolCallDistribution(samples) {
201891
202368
  }));
201892
202369
  return {
201893
202370
  samples: runSamples,
201894
- median: median2(values),
202371
+ median: median3(values),
201895
202372
  spread: spread(values),
201896
202373
  reliability: ABLATION_RELIABILITY
201897
202374
  };
@@ -201901,7 +202378,7 @@ function tokenCost(samples, source) {
201901
202378
  if (known.length === 0)
201902
202379
  return;
201903
202380
  const note = `median of ${known.length}/${samples.length} seed samples with a reported token count`;
201904
- return { tokens: { raw: measured(median2(known), source, note) } };
202381
+ return { tokens: { raw: measured(median3(known), source, note) } };
201905
202382
  }
201906
202383
  function successRate(samples) {
201907
202384
  const successes = samples.filter((s) => s.success).length;
@@ -203228,7 +203705,7 @@ function formatFwkExplain(result) {
203228
203705
  }
203229
203706
 
203230
203707
  // src/commands/workspace.ts
203231
- import { randomUUID as randomUUID54 } from "crypto";
203708
+ import { randomUUID as randomUUID55 } from "crypto";
203232
203709
  import { writeFile as writeFile51 } from "fs/promises";
203233
203710
  function service8() {
203234
203711
  return new WorkspaceService({
@@ -203249,7 +203726,7 @@ async function workspaceCommand(args) {
203249
203726
  const component = rawComponent === undefined ? undefined : requireWorkspaceReference(rawComponent);
203250
203727
  if (!title)
203251
203728
  throw new Error("Usage: keryx workspace create --title <title> [--component <workspace-relative-ref>]");
203252
- const workspace = await service8().create({ request: undefined, requestCorrelationId: randomUUID54(), id: newWorkspaceId(), title, ...component ? { component: { kind: "component", uri: component } } : {} });
203729
+ const workspace = await service8().create({ request: undefined, requestCorrelationId: randomUUID55(), id: newWorkspaceId(), title, ...component ? { component: { kind: "component", uri: component } } : {} });
203253
203730
  console.log(JSON.stringify(workspace, null, 2));
203254
203731
  return;
203255
203732
  }
@@ -203279,7 +203756,7 @@ async function workspaceCommand(args) {
203279
203756
  const revision = optionValue(args, "--revision");
203280
203757
  if (!workspaceId || !kind || !rawUri)
203281
203758
  throw new Error("Usage: keryx workspace add-resource <workspace-id> --kind <kind> --uri <workspace-relative-ref> [--revision <revision>]");
203282
- console.log(JSON.stringify(await service8().addResource({ request: undefined, requestCorrelationId: randomUUID54(), workspaceId, resource: { kind, uri: requireWorkspaceReference(rawUri), ...revision ? { revision } : {} } }), null, 2));
203759
+ console.log(JSON.stringify(await service8().addResource({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId, resource: { kind, uri: requireWorkspaceReference(rawUri), ...revision ? { revision } : {} } }), null, 2));
203283
203760
  return;
203284
203761
  }
203285
203762
  if (subcommand === "archive") {
@@ -203287,7 +203764,7 @@ async function workspaceCommand(args) {
203287
203764
  const workspaceId = args[1];
203288
203765
  if (!workspaceId)
203289
203766
  throw new Error("Usage: keryx workspace archive <workspace-id>");
203290
- console.log(JSON.stringify(await service8().archive({ request: undefined, requestCorrelationId: randomUUID54(), workspaceId }), null, 2));
203767
+ console.log(JSON.stringify(await service8().archive({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId }), null, 2));
203291
203768
  return;
203292
203769
  }
203293
203770
  if (subcommand === "remove-resource") {
@@ -203296,7 +203773,7 @@ async function workspaceCommand(args) {
203296
203773
  const uri = optionValue(args, "--uri");
203297
203774
  if (!workspaceId || !uri)
203298
203775
  throw new Error("Usage: keryx workspace remove-resource <workspace-id> --uri <workspace-relative-ref>");
203299
- console.log(JSON.stringify(await service8().removeResource({ request: undefined, requestCorrelationId: randomUUID54(), workspaceId, uri }), null, 2));
203776
+ console.log(JSON.stringify(await service8().removeResource({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId, uri }), null, 2));
203300
203777
  return;
203301
203778
  }
203302
203779
  if (subcommand === "rename") {
@@ -203305,7 +203782,7 @@ async function workspaceCommand(args) {
203305
203782
  const title = optionValue(args, "--title");
203306
203783
  if (!workspaceId || !title)
203307
203784
  throw new Error("Usage: keryx workspace rename <workspace-id> --title <title>");
203308
- console.log(JSON.stringify(await service8().rename({ request: undefined, requestCorrelationId: randomUUID54(), workspaceId, title }), null, 2));
203785
+ console.log(JSON.stringify(await service8().rename({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId, title }), null, 2));
203309
203786
  return;
203310
203787
  }
203311
203788
  if (subcommand === "overview") {
@@ -203317,7 +203794,7 @@ async function workspaceCommand(args) {
203317
203794
  const maxTokens = Number(optionValue(args, "--max-tokens") ?? "4096");
203318
203795
  if (!Number.isInteger(maxItems) || !Number.isInteger(maxTokens) || maxItems < 0 || maxTokens < 0)
203319
203796
  throw new Error("--max-items and --max-tokens must be non-negative integers");
203320
- const result = await createLocalFwkReadService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID54(), budget: { maxItems, maxTokens } });
203797
+ const result = await createLocalFwkReadService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID55(), budget: { maxItems, maxTokens } });
203321
203798
  const normalized = normalizeFwkResult(result);
203322
203799
  console.log(JSON.stringify(normalized, null, 2));
203323
203800
  if (args.includes("--explain"))
@@ -203334,7 +203811,7 @@ async function workspaceCommand(args) {
203334
203811
  const maxTokens = Number(optionValue(args, "--max-tokens") ?? "4096");
203335
203812
  if (!Number.isInteger(maxItems) || !Number.isInteger(maxTokens) || maxItems < 0 || maxTokens < 0)
203336
203813
  throw new Error("--max-items and --max-tokens must be non-negative integers");
203337
- const result = await createLocalFwkReadService(process.cwd()).read({ workspaceId, itemId, request: undefined, requestCorrelationId: randomUUID54(), budget: { maxItems, maxTokens } });
203814
+ const result = await createLocalFwkReadService(process.cwd()).read({ workspaceId, itemId, request: undefined, requestCorrelationId: randomUUID55(), budget: { maxItems, maxTokens } });
203338
203815
  const normalized = normalizeFwkResult(result);
203339
203816
  console.log(JSON.stringify(normalized, null, 2));
203340
203817
  if (args.includes("--explain"))
@@ -203356,14 +203833,14 @@ async function workspaceCommand(args) {
203356
203833
  const session = findSession(cwd, sessionRef);
203357
203834
  if (!session)
203358
203835
  throw new Error(`no session matching "${sessionRef}" in this project \u2014 use \`keryx sessions list\``);
203359
- const proposalId = `proposal-${randomUUID54().replace(/-/g, "").slice(0, 16)}`;
203836
+ const proposalId = `proposal-${randomUUID55().replace(/-/g, "").slice(0, 16)}`;
203360
203837
  const notePath = proposalNotePath(cwd, workspaceId, proposalId);
203361
203838
  const materializedNote = note === undefined ? undefined : prepareOutputForPersistence(await guardOutput({ cwd, content: note, target: "task", source: "generated", path: notePath }), note);
203362
203839
  if (materializedNote !== undefined && !materializedNote.allowed)
203363
203840
  throw new Error(materializedNote.reason);
203364
203841
  const persistedNote = materializedNote?.allowed ? materializedNote.content : undefined;
203365
203842
  const { service, wrapUpAuthority, authorizationServer } = createHarnessProposalLifecycleService(cwd, { workspaceId, ...persistedNote ? { note: persistedNote } : {} });
203366
- const requestCorrelationId = randomUUID54();
203843
+ const requestCorrelationId = randomUUID55();
203367
203844
  const actor = await authorizationServer.actorContextFor(undefined, requestCorrelationId);
203368
203845
  if (!actor)
203369
203846
  throw new Error("trusted ActorContext is required");
@@ -203404,13 +203881,13 @@ async function workspaceCommand(args) {
203404
203881
  const proposalId = args[2];
203405
203882
  const decision = optionValue(args, "--decision");
203406
203883
  const reason = optionValue(args, "--reason");
203407
- const idempotencyKey = optionValue(args, "--idempotency-key") ?? randomUUID54();
203884
+ const idempotencyKey = optionValue(args, "--idempotency-key") ?? randomUUID55();
203408
203885
  const confirmToken = optionValue(args, "--confirm-token");
203409
203886
  if (!workspaceId || !proposalId || !decision)
203410
203887
  throw new Error("Usage: keryx workspace review <workspace-id> <proposal-id> --decision <accepted|rejected|dismissed> [--reason <reason>] [--idempotency-key <key>] [--confirm-token <token>]");
203411
203888
  if (decision === "accepted" && !confirmToken)
203412
203889
  throw new Error("--decision accepted requires --confirm-token \u2014 run `keryx workspace confirm-review " + workspaceId + " " + proposalId + "` first");
203413
- const result = await createHarnessProposalLifecycleService(process.cwd(), { workspaceId }).service.review({ request: undefined, requestCorrelationId: randomUUID54(), workspaceId, proposalId, decision, idempotencyKey, interactive: true, ...reason ? { reason } : {}, ...confirmToken ? { confirmToken } : {} });
203890
+ const result = await createHarnessProposalLifecycleService(process.cwd(), { workspaceId }).service.review({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId, proposalId, decision, idempotencyKey, interactive: true, ...reason ? { reason } : {}, ...confirmToken ? { confirmToken } : {} });
203414
203891
  console.log(JSON.stringify(normalizeProposalLifecycleResult(result), null, 2));
203415
203892
  return;
203416
203893
  }
@@ -203435,7 +203912,7 @@ async function workspaceCommand(args) {
203435
203912
  const artifactRef = optionValue(args, "--artifact");
203436
203913
  if (!workspaceId || !to || !artifactRef)
203437
203914
  throw new Error("Usage: keryx workspace handoff <workspace-id> --to <subject> --artifact <ref>");
203438
- const activity = await createLocalCollaborationService(process.cwd()).record({ request: undefined, requestCorrelationId: randomUUID54(), workspaceId, activity: { kind: "handoff-recorded", handoff: { to, artifactRef } } });
203915
+ const activity = await createLocalCollaborationService(process.cwd()).record({ request: undefined, requestCorrelationId: randomUUID55(), workspaceId, activity: { kind: "handoff-recorded", handoff: { to, artifactRef } } });
203439
203916
  console.log(JSON.stringify(activity, null, 2));
203440
203917
  return;
203441
203918
  }
@@ -203444,7 +203921,7 @@ async function workspaceCommand(args) {
203444
203921
  const workspaceId = args[1];
203445
203922
  if (!workspaceId)
203446
203923
  throw new Error("Usage: keryx workspace collaboration <workspace-id>");
203447
- console.log(JSON.stringify(await createLocalCollaborationService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID54() }), null, 2));
203924
+ console.log(JSON.stringify(await createLocalCollaborationService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID55() }), null, 2));
203448
203925
  return;
203449
203926
  }
203450
203927
  if (subcommand === "policy-readiness") {
@@ -203471,7 +203948,7 @@ async function workspaceCommand(args) {
203471
203948
  const workspaceId = args[1];
203472
203949
  const cwd = process.cwd();
203473
203950
  const authorizationServer = localWorkspaceAuthorizationServer();
203474
- const actor = await authorizationServer.actorContextFor(undefined, randomUUID54());
203951
+ const actor = await authorizationServer.actorContextFor(undefined, randomUUID55());
203475
203952
  if (!actor)
203476
203953
  throw new Error("trusted ActorContext is required");
203477
203954
  if (workspaceId) {
@@ -204614,6 +205091,8 @@ var init_forgetting = __esm(() => {
204614
205091
  });
204615
205092
 
204616
205093
  // src/commands/decisions.ts
205094
+ import { readFile as readFile190 } from "fs/promises";
205095
+ import path373 from "path";
204617
205096
  function rejectUnknownFlags2(sub, args, accepted) {
204618
205097
  const unknown = args.filter((argument) => argument.startsWith("--")).map((argument) => argument.split("=")[0]).filter((name) => !accepted.includes(name));
204619
205098
  if (unknown.length > 0) {
@@ -204729,8 +205208,33 @@ async function runReason(args) {
204729
205208
  }
204730
205209
  console.log(recorded ? `decision ${id}: reason recorded` : `decision ${id}: the human was already asked once; nothing written`);
204731
205210
  }
205211
+ async function runImport(args) {
205212
+ const file = positionalId(args);
205213
+ if (file === undefined)
205214
+ throw new Error("keryx decisions import needs the file: keryx decisions import <file.jsonl> [--dry-run] [--json]");
205215
+ const rest = args.slice(1);
205216
+ rejectUnknownFlags2("import", rest, IMPORT_FLAGS2);
205217
+ let text;
205218
+ try {
205219
+ text = await readFile190(path373.resolve(process.cwd(), file), "utf8");
205220
+ } catch {
205221
+ throw new Error(`cannot read ${file}`);
205222
+ }
205223
+ const result = await importBackfill(process.cwd(), text, { dryRun: rest.includes("--dry-run") });
205224
+ if (rest.includes("--json")) {
205225
+ console.log(JSON.stringify(result, null, 2));
205226
+ return;
205227
+ }
205228
+ console.log(renderImportResult(result));
205229
+ }
204732
205230
  async function runReport3(args) {
204733
205231
  rejectUnknownFlags2("report", args, REPORT_FLAGS);
205232
+ if (args.includes("--line") && args.includes("--json"))
205233
+ throw new Error("keryx decisions report: --line and --json cannot be combined");
205234
+ if (args.includes("--line")) {
205235
+ console.log(await reportLine(process.cwd()));
205236
+ return;
205237
+ }
204734
205238
  if (args.includes("--json")) {
204735
205239
  console.log(JSON.stringify(await loadReport(process.cwd()), null, 2));
204736
205240
  return;
@@ -204752,8 +205256,14 @@ async function decisionsCommand(args = []) {
204752
205256
  return await runReason(args.slice(1));
204753
205257
  if (command === "report")
204754
205258
  return await runReport3(args.slice(1));
205259
+ if (command === "import")
205260
+ return await runImport(args.slice(1));
204755
205261
  } catch (cause) {
204756
- console.error(cause instanceof Error ? cause.message : String(cause));
205262
+ const message = cause instanceof Error ? cause.message : String(cause);
205263
+ if (command === "import" && args.includes("--json"))
205264
+ console.log(JSON.stringify({ error: message }, null, 2));
205265
+ else
205266
+ console.error(message);
204757
205267
  process.exitCode = 1;
204758
205268
  return;
204759
205269
  }
@@ -204771,7 +205281,8 @@ Usage:
204771
205281
  keryx decisions open --question "<text>" --option <id>=<label> [--option ...] [--recommend <id> --reason "<why>"] [--stage <name>] [--flow <id>] [--action <tag>] [--json]
204772
205282
  keryx decisions answer <id> --choice <id> [--other] [--reason "<why>"] [--json]
204773
205283
  keryx decisions reason <id> --text "<why>" [--json]
204774
- keryx decisions report [--json]
205284
+ keryx decisions report [--json | --line]
205285
+ keryx decisions import <file.jsonl> [--dry-run] [--json]
204775
205286
 
204776
205287
  Every agent question with options leaves one record: what was asked, what the
204777
205288
  agent recommended and why, how it was shown, what the human chose and how long
@@ -204804,6 +205315,28 @@ it took. Call \`open\` BEFORE showing the question and \`answer\` after.
204804
205315
  its reason. It also counts the questions that looked irreversible
204805
205316
  and the ones where blind was refused because of it, per stage: a
204806
205317
  high number on ordinary questions means the list over-matches.
205318
+ Backfilled decisions (see import) are reported in a separate block
205319
+ "\u0434\u043E (\u0438\u0441\u0442\u043E\u0440\u0438\u0447\u0435\u0441\u043A\u043E\u0435, \u0434\u043E\u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u043E \u0437\u0430\u0434\u043D\u0438\u043C \u0447\u0438\u0441\u043B\u043E\u043C)" and never counted in
205320
+ the live shares or in the time to answer. --line prints ONE line in
205321
+ Russian for the daily topic message: the total (before, after) and the
205322
+ match share of the visible, the hidden and the historical decisions.
205323
+ import loads historical decisions from a JSON-lines file, one per line:
205324
+ {"id","at","flow","stage","question","options":[{"id","label"}],
205325
+ "recommendation":{"optionId","reason"}|null,"source",
205326
+ "answer":{"choice","other"?}|null,"reason"?}
205327
+ Every one is marked backfilled (its recommendation was written down
205328
+ after the fact), is never blind, and keeps the time it was asked in
205329
+ "at"; its time to answer is unknown and never used. The file is
205330
+ read line by line: a line that is not a decision is skipped, named
205331
+ (line number and why) and counted, and the rest is imported. An id
205332
+ already in the journal is skipped and reported, so the same file can
205333
+ be imported twice; a backfilled decision whose answer is missing from
205334
+ the journal (an interrupted write) gets just that answer on the next
205335
+ import. --dry-run checks and counts without writing. It prints:
205336
+ Imported: N, skipped: S, with recommendation: R, answered: A,
205337
+ deviations: D, plus ", repaired: R" and ", malformed: M" when
205338
+ there are any. With --json a failure is {"error": "..."}. A bare /decisions change never touches a backfilled
205339
+ decision.
204807
205340
 
204808
205341
  The journal is one file per repository, .metaproject/data/decisions/journal.jsonl
204809
205342
  under the main checkout (every worktree shares it; it is git-ignored). Inside a
@@ -204813,14 +205346,15 @@ the answer also adds a line to that flow's journal.md, except for an inferred
204813
205346
  flow, which only stays in the project-wide journal. A failure here never
204814
205347
  stops the question.`);
204815
205348
  }
204816
- var OPEN_FLAGS, ANSWER_FLAGS, REASON_FLAGS, REPORT_FLAGS;
205349
+ var OPEN_FLAGS, ANSWER_FLAGS, REASON_FLAGS, REPORT_FLAGS, IMPORT_FLAGS2;
204817
205350
  var init_decisions2 = __esm(() => {
204818
205351
  init_args();
204819
205352
  init_service13();
204820
205353
  OPEN_FLAGS = ["--question", "--option", "--options-json", "--recommend", "--reason", "--stage", "--flow", "--action", "--json"];
204821
205354
  ANSWER_FLAGS = ["--choice", "--other", "--reason", "--json"];
204822
205355
  REASON_FLAGS = ["--text", "--json"];
204823
- REPORT_FLAGS = ["--json"];
205356
+ REPORT_FLAGS = ["--json", "--line"];
205357
+ IMPORT_FLAGS2 = ["--dry-run", "--json"];
204824
205358
  });
204825
205359
 
204826
205360
  // src/commands/governance.ts
@@ -205034,7 +205568,7 @@ var init_product = __esm(() => {
205034
205568
 
205035
205569
  // src/commands/hooks.ts
205036
205570
  import { existsSync as existsSync58, readFileSync as readFileSync32 } from "fs";
205037
- import path373 from "path";
205571
+ import path374 from "path";
205038
205572
  function resolveHomeDir(deps) {
205039
205573
  return resolveHooksHomeDir(process.env, deps.homeDir);
205040
205574
  }
@@ -205045,10 +205579,10 @@ function optConfigDir(deps) {
205045
205579
  return deps.configDir !== undefined ? { configDir: deps.configDir } : {};
205046
205580
  }
205047
205581
  function userHooksPath(homeDir) {
205048
- return path373.join(homeDir, ".keryx", "hooks.json");
205582
+ return path374.join(homeDir, ".keryx", "hooks.json");
205049
205583
  }
205050
205584
  function projectHooksPath(projectRoot) {
205051
- return path373.join(projectRoot, ".metaproject", "hooks.json");
205585
+ return path374.join(projectRoot, ".metaproject", "hooks.json");
205052
205586
  }
205053
205587
  function fail6(message) {
205054
205588
  console.error(message);
@@ -205166,10 +205700,10 @@ async function runList7(args, deps) {
205166
205700
  function argv0Resolves(argv0) {
205167
205701
  if (argv0 === "keryx")
205168
205702
  return true;
205169
- if (path373.isAbsolute(argv0))
205703
+ if (path374.isAbsolute(argv0))
205170
205704
  return existsSync58(argv0);
205171
205705
  const pathEnv = process.env.PATH ?? "";
205172
- return pathEnv.split(path373.delimiter).filter((dir) => dir.length > 0).some((dir) => existsSync58(path373.join(dir, argv0)));
205706
+ return pathEnv.split(path374.delimiter).filter((dir) => dir.length > 0).some((dir) => existsSync58(path374.join(dir, argv0)));
205173
205707
  }
205174
205708
  function checkArgvResolutions(registrations) {
205175
205709
  const seen = new Set;
@@ -205623,7 +206157,7 @@ async function writeDocAtomic(filePath, doc, scope, cwd, homeDir) {
205623
206157
  if (scope === "project") {
205624
206158
  await writeContained(cwd, PROJECT_HOOKS_REL, body);
205625
206159
  } else {
205626
- const userConfigDir = path373.join(homeDir, ".keryx");
206160
+ const userConfigDir = path374.join(homeDir, ".keryx");
205627
206161
  if (!existsSync58(userConfigDir)) {
205628
206162
  await mkdirContained(homeDir, ".keryx");
205629
206163
  }
@@ -205938,13 +206472,13 @@ var init_types12 = __esm(() => {
205938
206472
  });
205939
206473
 
205940
206474
  // src/bundle/paths.ts
205941
- import { lstat as lstat20, readFile as readFile190 } from "fs/promises";
205942
- import path374 from "path";
206475
+ import { lstat as lstat20, readFile as readFile191 } from "fs/promises";
206476
+ import path375 from "path";
205943
206477
  function scopeRoot(scope, ctx) {
205944
206478
  if (scope === "user") {
205945
206479
  return userStoreRoot(ctx.env ?? process.env, ctx.homeDir);
205946
206480
  }
205947
- return path374.join(ctx.projectRoot, ".metaproject");
206481
+ return path375.join(ctx.projectRoot, ".metaproject");
205948
206482
  }
205949
206483
  function isPortablePath(relPath) {
205950
206484
  return relPath.split("/").every((segment) => PORTABLE_SEGMENT_RE.test(segment));
@@ -206118,10 +206652,10 @@ async function targetFor(entry, targetScope, ctx) {
206118
206652
  return { ok: true, absolutePath: containment.absolutePath };
206119
206653
  }
206120
206654
  async function resolveContainedPathForWrite(root, relPath) {
206121
- const absolute = path374.resolve(root, relPath);
206122
- const rootResolved = path374.resolve(root);
206123
- const relative = path374.relative(rootResolved, absolute);
206124
- if (relative === "" || relative === ".." || relative.startsWith(`..${path374.sep}`) || path374.isAbsolute(relative)) {
206655
+ const absolute = path375.resolve(root, relPath);
206656
+ const rootResolved = path375.resolve(root);
206657
+ const relative = path375.relative(rootResolved, absolute);
206658
+ if (relative === "" || relative === ".." || relative.startsWith(`..${path375.sep}`) || path375.isAbsolute(relative)) {
206125
206659
  return {
206126
206660
  ok: false,
206127
206661
  refusal: { reason: BUNDLE_REFUSAL.pathEscape, path: relPath, message: `${relPath} resolves outside the scope root` }
@@ -206130,7 +206664,7 @@ async function resolveContainedPathForWrite(root, relPath) {
206130
206664
  return { ok: true, absolutePath: absolute };
206131
206665
  }
206132
206666
  async function refuseSymlinkChain(root, relPath) {
206133
- const rootResolved = path374.resolve(root);
206667
+ const rootResolved = path375.resolve(root);
206134
206668
  try {
206135
206669
  const rootStat = await lstat20(rootResolved);
206136
206670
  if (rootStat.isSymbolicLink()) {
@@ -206143,7 +206677,7 @@ async function refuseSymlinkChain(root, relPath) {
206143
206677
  const segments = relPath.split("/");
206144
206678
  let current = rootResolved;
206145
206679
  for (const segment of segments) {
206146
- current = path374.join(current, segment);
206680
+ current = path375.join(current, segment);
206147
206681
  try {
206148
206682
  const stat = await lstat20(current);
206149
206683
  if (stat.isSymbolicLink()) {
@@ -206158,7 +206692,7 @@ async function refuseSymlinkChain(root, relPath) {
206158
206692
  }
206159
206693
  async function readTargetFile(absolutePath) {
206160
206694
  try {
206161
- const bytes = await readFile190(absolutePath);
206695
+ const bytes = await readFile191(absolutePath);
206162
206696
  return { ok: true, bytes };
206163
206697
  } catch (err) {
206164
206698
  const code = err.code;
@@ -206195,8 +206729,8 @@ var init_paths5 = __esm(() => {
206195
206729
  });
206196
206730
 
206197
206731
  // src/bundle/archive.ts
206198
- import { readdir as readdir65, readFile as readFile191, lstat as lstat21 } from "fs/promises";
206199
- import path375 from "path";
206732
+ import { readdir as readdir65, readFile as readFile192, lstat as lstat21 } from "fs/promises";
206733
+ import path376 from "path";
206200
206734
  import { gzipSync, gunzipSync } from "zlib";
206201
206735
  function resolveLimits(limits) {
206202
206736
  const maxTotalBytes = limits?.maxTotalBytes ?? DEFAULT_BUNDLE_LIMITS.maxTotalBytes;
@@ -206279,11 +206813,11 @@ function buildBundleArchive(files, manifestBytes) {
206279
206813
  const dirs = new Set;
206280
206814
  const sortedPaths = [...files.keys()].sort();
206281
206815
  for (const p of sortedPaths) {
206282
- let dir = path375.dirname(p);
206816
+ let dir = path376.dirname(p);
206283
206817
  const segs = [];
206284
206818
  while (dir !== "." && dir !== "/" && dir !== "") {
206285
206819
  segs.unshift(dir);
206286
- dir = path375.dirname(dir);
206820
+ dir = path376.dirname(dir);
206287
206821
  }
206288
206822
  for (const d of segs)
206289
206823
  dirs.add(d);
@@ -206351,7 +206885,7 @@ function parseUstar(tar, limits) {
206351
206885
  const name = prefix.length > 0 ? `${prefix}/${nameRaw}` : nameRaw;
206352
206886
  const typeflag = String.fromCharCode(header[156] ?? 0);
206353
206887
  const size = readOctal(header, 124, 12);
206354
- if (path375.isAbsolute(name) || name.split("/").includes("..") || name.length === 0) {
206888
+ if (path376.isAbsolute(name) || name.split("/").includes("..") || name.length === 0) {
206355
206889
  return { ok: false, refusal: { reason: BUNDLE_REFUSAL.archiveInvalid, path: name, message: `unsafe entry name: ${name}` } };
206356
206890
  }
206357
206891
  const isDir = typeflag === "5";
@@ -206415,7 +206949,7 @@ async function openBundle(bundlePath, limits) {
206415
206949
  async function walk(dir, relPrefix) {
206416
206950
  const entries = await readdir65(dir, { withFileTypes: true });
206417
206951
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
206418
- const abs = path375.join(dir, entry.name);
206952
+ const abs = path376.join(dir, entry.name);
206419
206953
  const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
206420
206954
  const entryStat = await lstat21(abs);
206421
206955
  if (entryStat.isSymbolicLink()) {
@@ -206434,7 +206968,7 @@ async function openBundle(bundlePath, limits) {
206434
206968
  if (entryStat.size > resolved.maxManifestBytes) {
206435
206969
  return { reason: BUNDLE_REFUSAL.archiveTooLarge, path: rel, message: `bundle.json is ${entryStat.size} bytes, over the ${resolved.maxManifestBytes}-byte manifest cap` };
206436
206970
  }
206437
- manifestBytes = await readFile191(abs);
206971
+ manifestBytes = await readFile192(abs);
206438
206972
  continue;
206439
206973
  }
206440
206974
  entryCount += 1;
@@ -206445,7 +206979,7 @@ async function openBundle(bundlePath, limits) {
206445
206979
  if (totalBytes > resolved.maxTotalBytes) {
206446
206980
  return { reason: BUNDLE_REFUSAL.archiveTooLarge, message: `bundle directory exceeds ${resolved.maxTotalBytes} bytes total` };
206447
206981
  }
206448
- const bytes = await readFile191(abs);
206982
+ const bytes = await readFile192(abs);
206449
206983
  files.set(rel, bytes);
206450
206984
  }
206451
206985
  return null;
@@ -206462,7 +206996,7 @@ async function openBundle(bundlePath, limits) {
206462
206996
  if (stat.size > resolved.maxCompressedBytes) {
206463
206997
  return { ok: false, refusal: { reason: BUNDLE_REFUSAL.archiveTooLarge, message: `${bundlePath} is ${stat.size} bytes, over the ${resolved.maxCompressedBytes}-byte compressed-size cap` } };
206464
206998
  }
206465
- const raw = await readFile191(bundlePath);
206999
+ const raw = await readFile192(bundlePath);
206466
207000
  let tar;
206467
207001
  try {
206468
207002
  tar = gunzipSync(raw, { maxOutputLength: resolved.maxDecompressedBytes });
@@ -207292,9 +207826,9 @@ var init_learned_pattern_schema = __esm(() => {
207292
207826
 
207293
207827
  // src/bundle/export.ts
207294
207828
  import { execFileSync as execFileSync3 } from "child_process";
207295
- import { mkdir as mkdir75, readdir as readdir66, readFile as readFile192, writeFile as writeFile52, lstat as lstat22 } from "fs/promises";
207829
+ import { mkdir as mkdir75, readdir as readdir66, readFile as readFile193, writeFile as writeFile52, lstat as lstat22 } from "fs/promises";
207296
207830
  import { existsSync as existsSync59 } from "fs";
207297
- import path376 from "path";
207831
+ import path377 from "path";
207298
207832
  function globToRegExp5(glob) {
207299
207833
  let out = "";
207300
207834
  for (let i = 0;i < glob.length; i += 1) {
@@ -207377,7 +207911,7 @@ async function walkFiles2(dir, relPrefix, out, skipped) {
207377
207911
  return;
207378
207912
  }
207379
207913
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
207380
- const abs = path376.join(dir, entry.name);
207914
+ const abs = path377.join(dir, entry.name);
207381
207915
  const rel = relPrefix.length > 0 ? `${relPrefix}/${entry.name}` : entry.name;
207382
207916
  const st = await lstat22(abs);
207383
207917
  if (st.isSymbolicLink()) {
@@ -207394,7 +207928,7 @@ async function walkFiles2(dir, relPrefix, out, skipped) {
207394
207928
  async function collectSkills(root, scope, skipped) {
207395
207929
  const candidates = [];
207396
207930
  for (const baseDirName of scope === "project" ? ["skills", "project-skills"] : ["skills"]) {
207397
- const base = path376.join(root, baseDirName);
207931
+ const base = path377.join(root, baseDirName);
207398
207932
  if (!existsSync59(base))
207399
207933
  continue;
207400
207934
  const files = [];
@@ -207407,7 +207941,7 @@ async function collectSkills(root, scope, skipped) {
207407
207941
  async function collectRules(root, scope, skipped) {
207408
207942
  if (scope === "user")
207409
207943
  return [];
207410
- const base = path376.join(root, "rules");
207944
+ const base = path377.join(root, "rules");
207411
207945
  if (!existsSync59(base))
207412
207946
  return [];
207413
207947
  const files = [];
@@ -207415,7 +207949,7 @@ async function collectRules(root, scope, skipped) {
207415
207949
  return files.filter((f) => /\.(md|mdc)$/.test(f.path)).map((f) => ({ bundlePath: f.path, kind: "rule", absolutePath: f.abs }));
207416
207950
  }
207417
207951
  async function collectAgents(root, skipped) {
207418
- const base = path376.join(root, "agents");
207952
+ const base = path377.join(root, "agents");
207419
207953
  if (!existsSync59(base))
207420
207954
  return [];
207421
207955
  let entries;
@@ -207426,7 +207960,7 @@ async function collectAgents(root, skipped) {
207426
207960
  }
207427
207961
  const candidates = [];
207428
207962
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
207429
- const abs = path376.join(base, entry.name);
207963
+ const abs = path377.join(base, entry.name);
207430
207964
  const st = await lstat22(abs);
207431
207965
  if (st.isSymbolicLink()) {
207432
207966
  skipped.push({ path: `agents/${entry.name}`, reason: "symlink" });
@@ -207441,7 +207975,7 @@ async function collectAgents(root, skipped) {
207441
207975
  async function collectMemory(root, skipped) {
207442
207976
  const candidates = [];
207443
207977
  for (const { folder } of MEMORY_TYPES) {
207444
- const base = path376.join(root, "memory", folder);
207978
+ const base = path377.join(root, "memory", folder);
207445
207979
  if (!existsSync59(base))
207446
207980
  continue;
207447
207981
  let entries;
@@ -207451,7 +207985,7 @@ async function collectMemory(root, skipped) {
207451
207985
  continue;
207452
207986
  }
207453
207987
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
207454
- const abs = path376.join(base, entry.name);
207988
+ const abs = path377.join(base, entry.name);
207455
207989
  const st = await lstat22(abs);
207456
207990
  if (st.isSymbolicLink()) {
207457
207991
  skipped.push({ path: `memory/${folder}/${entry.name}`, reason: "symlink" });
@@ -207465,7 +207999,7 @@ async function collectMemory(root, skipped) {
207465
207999
  return candidates;
207466
208000
  }
207467
208001
  async function collectHookConfig(root) {
207468
- const abs = path376.join(root, "hooks.json");
208002
+ const abs = path377.join(root, "hooks.json");
207469
208003
  if (!existsSync59(abs))
207470
208004
  return [];
207471
208005
  const st = await lstat22(abs);
@@ -207475,7 +208009,7 @@ async function collectHookConfig(root) {
207475
208009
  }
207476
208010
  async function collectLearnedPatterns(root, scope) {
207477
208011
  const relDir = scope === "user" ? "learning/patterns" : "data/learning/candidates";
207478
- const base = path376.join(root, ...relDir.split("/"));
208012
+ const base = path377.join(root, ...relDir.split("/"));
207479
208013
  if (!existsSync59(base))
207480
208014
  return [];
207481
208015
  let entries;
@@ -207487,7 +208021,7 @@ async function collectLearnedPatterns(root, scope) {
207487
208021
  const candidates = [];
207488
208022
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
207489
208023
  if (entry.isFile() && entry.name.endsWith(".json")) {
207490
- candidates.push({ bundlePath: `${relDir}/${entry.name}`, kind: "learned-pattern", absolutePath: path376.join(base, entry.name) });
208024
+ candidates.push({ bundlePath: `${relDir}/${entry.name}`, kind: "learned-pattern", absolutePath: path377.join(base, entry.name) });
207491
208025
  }
207492
208026
  }
207493
208027
  return candidates;
@@ -207528,10 +208062,10 @@ async function outDirIsEmpty(out) {
207528
208062
  }
207529
208063
  async function writeDirectoryBundle(out, manifestBytes, files) {
207530
208064
  await mkdir75(out, { recursive: true });
207531
- await writeFile52(path376.join(out, "bundle.json"), manifestBytes);
208065
+ await writeFile52(path377.join(out, "bundle.json"), manifestBytes);
207532
208066
  for (const [rel, bytes] of files) {
207533
- const abs = path376.join(out, ...rel.split("/"));
207534
- await mkdir75(path376.dirname(abs), { recursive: true });
208067
+ const abs = path377.join(out, ...rel.split("/"));
208068
+ await mkdir75(path377.dirname(abs), { recursive: true });
207535
208069
  await writeFile52(abs, bytes);
207536
208070
  }
207537
208071
  }
@@ -207563,7 +208097,7 @@ async function exportBundle(opts) {
207563
208097
  } else {
207564
208098
  const rawDigestEntries = [];
207565
208099
  for (const candidate of filtered) {
207566
- const bytes = await readFile192(candidate.absolutePath);
208100
+ const bytes = await readFile193(candidate.absolutePath);
207567
208101
  rawDigestEntries.push({ path: candidate.bundlePath, sha256: sha256Hex5(bytes) });
207568
208102
  }
207569
208103
  bundleId = contentDigestBundleId(opts.scope, rawDigestEntries);
@@ -207578,7 +208112,7 @@ async function exportBundle(opts) {
207578
208112
  skipped.push({ path: candidate.bundlePath, reason: `non-portable-name: ${portable.refusal.message}` });
207579
208113
  continue;
207580
208114
  }
207581
- let bytes = await readFile192(candidate.absolutePath);
208115
+ let bytes = await readFile193(candidate.absolutePath);
207582
208116
  if (candidate.kind === "hook-config") {
207583
208117
  let parsed;
207584
208118
  try {
@@ -207665,7 +208199,7 @@ async function exportBundle(opts) {
207665
208199
  const archive = buildBundleArchive(files, manifestBytes);
207666
208200
  if (!archive.ok)
207667
208201
  return { ok: false, refusals: [archive.refusal] };
207668
- await mkdir75(path376.dirname(opts.out), { recursive: true });
208202
+ await mkdir75(path377.dirname(opts.out), { recursive: true });
207669
208203
  await writeFile52(opts.out, archive.value);
207670
208204
  } else {
207671
208205
  if (existsSync59(opts.out) && !await outDirIsEmpty(opts.out)) {
@@ -207731,16 +208265,16 @@ var init_verify3 = __esm(() => {
207731
208265
  });
207732
208266
 
207733
208267
  // src/bundle/applied-state.ts
207734
- import { readFile as readFile193 } from "fs/promises";
207735
- import path377 from "path";
208268
+ import { readFile as readFile194 } from "fs/promises";
208269
+ import path378 from "path";
207736
208270
  function emptyState2() {
207737
208271
  return { schemaVersion: APPLIED_STATE_SCHEMA_VERSION, entries: {} };
207738
208272
  }
207739
208273
  function appliedStatePath(scope, ctx) {
207740
208274
  if (scope === "user") {
207741
- return path377.join(scopeRoot("user", ctx), "bundles", "applied-state.json");
208275
+ return path378.join(scopeRoot("user", ctx), "bundles", "applied-state.json");
207742
208276
  }
207743
- return path377.join(scopeRoot(scope, ctx), "data", "bundles", "applied-state.json");
208277
+ return path378.join(scopeRoot(scope, ctx), "data", "bundles", "applied-state.json");
207744
208278
  }
207745
208279
  function isPlainEntryShape(value) {
207746
208280
  if (typeof value !== "object" || value === null)
@@ -207799,7 +208333,7 @@ function migrateV1(v1) {
207799
208333
  async function readAppliedState(ledgerPath) {
207800
208334
  let raw;
207801
208335
  try {
207802
- raw = await readFile193(ledgerPath, "utf8");
208336
+ raw = await readFile194(ledgerPath, "utf8");
207803
208337
  } catch (err) {
207804
208338
  const code = err.code;
207805
208339
  if (code === "ENOENT") {
@@ -207822,14 +208356,14 @@ async function readAppliedState(ledgerPath) {
207822
208356
  return { ok: false, reason: "corrupt-ledger", message: `applied-state ledger at ${ledgerPath} has an unrecognized shape` };
207823
208357
  }
207824
208358
  function containedRootAndRel(ledgerPath) {
207825
- const marker = `${path377.sep}.metaproject${path377.sep}`;
208359
+ const marker = `${path378.sep}.metaproject${path378.sep}`;
207826
208360
  const idx = ledgerPath.indexOf(marker);
207827
208361
  if (idx >= 0) {
207828
- return { root: ledgerPath.slice(0, idx), rel: ledgerPath.slice(idx + path377.sep.length).split(path377.sep).join("/") };
208362
+ return { root: ledgerPath.slice(0, idx), rel: ledgerPath.slice(idx + path378.sep.length).split(path378.sep).join("/") };
207829
208363
  }
207830
- const bundlesDir = path377.dirname(ledgerPath);
207831
- const root = path377.dirname(bundlesDir);
207832
- const rel = path377.join(path377.basename(bundlesDir), path377.basename(ledgerPath)).split(path377.sep).join("/");
208364
+ const bundlesDir = path378.dirname(ledgerPath);
208365
+ const root = path378.dirname(bundlesDir);
208366
+ const rel = path378.join(path378.basename(bundlesDir), path378.basename(ledgerPath)).split(path378.sep).join("/");
207833
208367
  return { root, rel };
207834
208368
  }
207835
208369
  async function writeAppliedState(ledgerPath, state) {
@@ -207849,14 +208383,14 @@ var init_applied_state = __esm(() => {
207849
208383
  });
207850
208384
 
207851
208385
  // src/lib/private-dir.ts
207852
- import { lstat as lstat23, mkdir as mkdir76, open as open10, readFile as readFile194 } from "fs/promises";
207853
- import path378 from "path";
208386
+ import { lstat as lstat23, mkdir as mkdir76, open as open11, readFile as readFile195 } from "fs/promises";
208387
+ import path379 from "path";
207854
208388
  async function checkPrivateDirGitignore(dir, root) {
207855
208389
  if (root !== undefined) {
207856
- const rootResolved = path378.resolve(root);
207857
- const dirResolved = path378.resolve(dir);
207858
- const relative = path378.relative(rootResolved, dirResolved);
207859
- const relativePosix = relative.split(path378.sep).join("/");
208390
+ const rootResolved = path379.resolve(root);
208391
+ const dirResolved = path379.resolve(dir);
208392
+ const relative = path379.relative(rootResolved, dirResolved);
208393
+ const relativePosix = relative.split(path379.sep).join("/");
207860
208394
  const refusal = await refuseEscapingSymlink(rootResolved, relativePosix);
207861
208395
  if (refusal !== undefined) {
207862
208396
  return {
@@ -207886,7 +208420,7 @@ async function checkPrivateDirGitignore(dir, root) {
207886
208420
  message: `${dir} is a symlink; keryx will not manage a private directory reached through a symlink.`
207887
208421
  };
207888
208422
  }
207889
- const gitignorePath = path378.join(dir, ".gitignore");
208423
+ const gitignorePath = path379.join(dir, ".gitignore");
207890
208424
  let stats;
207891
208425
  try {
207892
208426
  stats = await lstat23(gitignorePath);
@@ -207916,7 +208450,7 @@ async function checkPrivateDirGitignore(dir, root) {
207916
208450
  }
207917
208451
  let bytes;
207918
208452
  try {
207919
- bytes = await readFile194(gitignorePath);
208453
+ bytes = await readFile195(gitignorePath);
207920
208454
  } catch (error) {
207921
208455
  return {
207922
208456
  ok: false,
@@ -207938,10 +208472,10 @@ async function ensurePrivateDirGitignore(dir, root) {
207938
208472
  if (!check.ok || check.action === "present") {
207939
208473
  return check;
207940
208474
  }
207941
- const gitignorePath = path378.join(dir, ".gitignore");
208475
+ const gitignorePath = path379.join(dir, ".gitignore");
207942
208476
  await mkdir76(dir, { recursive: true });
207943
208477
  try {
207944
- const handle = await open10(gitignorePath, "wx");
208478
+ const handle = await open11(gitignorePath, "wx");
207945
208479
  try {
207946
208480
  await handle.writeFile(PRIVATE_DIR_GITIGNORE, "utf8");
207947
208481
  } finally {
@@ -208354,9 +208888,9 @@ var init_plan2 = __esm(() => {
208354
208888
  });
208355
208889
 
208356
208890
  // src/bundle/audit.ts
208357
- import { mkdtemp as mkdtemp9, mkdir as mkdir77, rm as rm23, writeFile as writeFile53 } from "fs/promises";
208891
+ import { mkdtemp as mkdtemp9, mkdir as mkdir77, rm as rm24, writeFile as writeFile53 } from "fs/promises";
208358
208892
  import { tmpdir as tmpdir16 } from "os";
208359
- import path379 from "path";
208893
+ import path380 from "path";
208360
208894
  function entriesToStage(plan) {
208361
208895
  return plan.entries.filter((e) => e.bucket === "new" || e.bucket === "update" || e.bucket === "conflict" && e.forced);
208362
208896
  }
@@ -208366,12 +208900,12 @@ async function auditBundlePlan(plan, opts = {}) {
208366
208900
  return { ok: true, refusals: [], report: null };
208367
208901
  }
208368
208902
  const runAudit = opts.runAudit ?? runHarnessAudit;
208369
- const stagingDir = await mkdtemp9(path379.join(tmpdir16(), "keryx-bundle-audit-"));
208903
+ const stagingDir = await mkdtemp9(path380.join(tmpdir16(), "keryx-bundle-audit-"));
208370
208904
  try {
208371
208905
  try {
208372
208906
  for (const entry of toStage) {
208373
- const abs = path379.join(stagingDir, ...entry.path.split("/"));
208374
- await mkdir77(path379.dirname(abs), { recursive: true });
208907
+ const abs = path380.join(stagingDir, ...entry.path.split("/"));
208908
+ await mkdir77(path380.dirname(abs), { recursive: true });
208375
208909
  await writeFile53(abs, entry.bytes);
208376
208910
  }
208377
208911
  } catch (err) {
@@ -208396,7 +208930,7 @@ async function auditBundlePlan(plan, opts = {}) {
208396
208930
  }
208397
208931
  return { ok: refusals.length === 0, refusals, report };
208398
208932
  } finally {
208399
- await rm23(stagingDir, { recursive: true, force: true });
208933
+ await rm24(stagingDir, { recursive: true, force: true });
208400
208934
  }
208401
208935
  }
208402
208936
  var init_audit = __esm(() => {
@@ -208405,8 +208939,8 @@ var init_audit = __esm(() => {
208405
208939
  });
208406
208940
 
208407
208941
  // src/bundle/apply.ts
208408
- import { mkdir as mkdir78, rmdir as rmdir2, stat as stat37 } from "fs/promises";
208409
- import path380 from "path";
208942
+ import { mkdir as mkdir78, rmdir as rmdir2, stat as stat38 } from "fs/promises";
208943
+ import path381 from "path";
208410
208944
  function writableEntries(plan) {
208411
208945
  return plan.entries.filter((e) => e.bucket === "new" || e.bucket === "update" || e.bucket === "conflict" && e.forced);
208412
208946
  }
@@ -208477,7 +209011,7 @@ async function applyBundlePlan(plan, auditResult, opts = {}) {
208477
209011
  throw new ApplyAbort({ ...previousFile.refusal, path: entry.path });
208478
209012
  }
208479
209013
  const previousBytes = previousFile.bytes ?? null;
208480
- const createdDirs = await mkdirRecordingCreated(path380.dirname(entry.targetPath));
209014
+ const createdDirs = await mkdirRecordingCreated(path381.dirname(entry.targetPath));
208481
209015
  for (const dir of [...createdDirs].reverse())
208482
209016
  rollback.push({ kind: "dir", absolutePath: dir });
208483
209017
  rollback.push({ kind: "file", root, rel: entry.targetRelative, previousBytes });
@@ -208560,14 +209094,14 @@ async function applyBundlePlan(plan, auditResult, opts = {}) {
208560
209094
  }
208561
209095
  async function mkdirRecordingCreated(dir) {
208562
209096
  const missing = [];
208563
- let current = path380.resolve(dir);
209097
+ let current = path381.resolve(dir);
208564
209098
  for (;; ) {
208565
209099
  try {
208566
- await stat37(current);
209100
+ await stat38(current);
208567
209101
  break;
208568
209102
  } catch {
208569
209103
  missing.push(current);
208570
- const parent = path380.dirname(current);
209104
+ const parent = path381.dirname(current);
208571
209105
  if (parent === current)
208572
209106
  break;
208573
209107
  current = parent;
@@ -208582,9 +209116,9 @@ function resolveLedgerPathForEntry(entry, opts) {
208582
209116
  if (entry.targetScope === "user") {
208583
209117
  return userStorePaths(opts.env ?? process.env, opts.homeDir).appliedState;
208584
209118
  }
208585
- const metaprojectIdx = entry.targetPath.indexOf(`${path380.sep}.metaproject${path380.sep}`);
208586
- const metaprojectRoot = metaprojectIdx === -1 ? path380.join(path380.dirname(entry.targetPath), ".metaproject") : entry.targetPath.slice(0, metaprojectIdx + `${path380.sep}.metaproject`.length);
208587
- return path380.join(metaprojectRoot, "data", "bundles", "applied-state.json");
209119
+ const metaprojectIdx = entry.targetPath.indexOf(`${path381.sep}.metaproject${path381.sep}`);
209120
+ const metaprojectRoot = metaprojectIdx === -1 ? path381.join(path381.dirname(entry.targetPath), ".metaproject") : entry.targetPath.slice(0, metaprojectIdx + `${path381.sep}.metaproject`.length);
209121
+ return path381.join(metaprojectRoot, "data", "bundles", "applied-state.json");
208588
209122
  }
208589
209123
  var ApplyAbort;
208590
209124
  var init_apply4 = __esm(() => {
@@ -208660,26 +209194,26 @@ var init_inspect = __esm(() => {
208660
209194
  });
208661
209195
 
208662
209196
  // src/bundle/uninstall.ts
208663
- import path381 from "path";
209197
+ import path382 from "path";
208664
209198
  function isContained(root, candidate) {
208665
- const rel = path381.relative(root, candidate);
208666
- return rel === "" || !rel.startsWith(`..${path381.sep}`) && rel !== ".." && !path381.isAbsolute(rel);
209199
+ const rel = path382.relative(root, candidate);
209200
+ return rel === "" || !rel.startsWith(`..${path382.sep}`) && rel !== ".." && !path382.isAbsolute(rel);
208667
209201
  }
208668
209202
  async function removeNowEmptyParents(root, relFilePath) {
208669
- let relDir = path381.posix.dirname(relFilePath);
209203
+ let relDir = path382.posix.dirname(relFilePath);
208670
209204
  while (relDir !== "." && relDir !== "/" && relDir !== "") {
208671
209205
  if (PROTECTED_KIND_ROOTS.has(relDir))
208672
209206
  break;
208673
209207
  const removed = await rmdirIfEmptyContained(root, relDir).catch(() => false);
208674
209208
  if (!removed)
208675
209209
  break;
208676
- relDir = path381.posix.dirname(relDir);
209210
+ relDir = path382.posix.dirname(relDir);
208677
209211
  }
208678
209212
  }
208679
209213
  async function uninstallBundle(opts) {
208680
209214
  const ctx = { projectRoot: opts.projectRoot, env: opts.env, homeDir: opts.homeDir };
208681
209215
  const root = scopeRoot(opts.targetScope, ctx);
208682
- const rootResolved = path381.resolve(root);
209216
+ const rootResolved = path382.resolve(root);
208683
209217
  const ledgerPath = appliedStatePath(opts.targetScope, ctx);
208684
209218
  const ledgerRead = await readAppliedState(ledgerPath);
208685
209219
  if (!ledgerRead.ok) {
@@ -208719,7 +209253,7 @@ async function uninstallBundle(opts) {
208719
209253
  if (!kindCheck.ok) {
208720
209254
  return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.corruptLedger, path: relPath, message: `applied-state ledger record "${relPath}" does not match its recorded kind "${record.kind}": ${kindCheck.refusal.message}` }], removed: [], kept: [], missing: [] };
208721
209255
  }
208722
- const absolute = path381.resolve(rootResolved, normalized.path);
209256
+ const absolute = path382.resolve(rootResolved, normalized.path);
208723
209257
  if (!isContained(rootResolved, absolute)) {
208724
209258
  return { ok: false, refusals: [{ reason: BUNDLE_REFUSAL.corruptLedger, path: relPath, message: `applied-state ledger record "${relPath}" resolves outside the scope root` }], removed: [], kept: [], missing: [] };
208725
209259
  }
@@ -208798,7 +209332,7 @@ var init_service20 = __esm(() => {
208798
209332
  });
208799
209333
 
208800
209334
  // src/commands/bundle.ts
208801
- import path382 from "path";
209335
+ import path383 from "path";
208802
209336
  async function bundleCommand(args, cwd = process.cwd()) {
208803
209337
  const sub = args[0];
208804
209338
  if (sub === undefined || sub === "--help" || sub === "-h") {
@@ -208931,7 +209465,7 @@ async function handleExport(args, cwd) {
208931
209465
  const outcome = await exportBundle({
208932
209466
  projectRoot,
208933
209467
  scope: scopeArg,
208934
- out: path382.resolve(cwd, out),
209468
+ out: path383.resolve(cwd, out),
208935
209469
  include: include.length > 0 ? include : undefined,
208936
209470
  kinds: kindsRaw.length > 0 ? kindsRaw : undefined,
208937
209471
  bundleId,
@@ -208976,7 +209510,7 @@ async function handleImport(args, cwd) {
208976
209510
  }
208977
209511
  const projectRoot = resolveBundleProjectRoot(cwd);
208978
209512
  if (external) {
208979
- await handleImportExternal(path382.resolve(cwd, target), projectRoot, { dryRun, json });
209513
+ await handleImportExternal(path383.resolve(cwd, target), projectRoot, { dryRun, json });
208980
209514
  return;
208981
209515
  }
208982
209516
  const targetScopeArg = optionValue([...args], "--target-scope");
@@ -209003,7 +209537,7 @@ async function handleImport(args, cwd) {
209003
209537
  return;
209004
209538
  }
209005
209539
  }
209006
- const opened = await openBundle(path382.resolve(cwd, target));
209540
+ const opened = await openBundle(path383.resolve(cwd, target));
209007
209541
  if (!opened.ok) {
209008
209542
  printRefusals([opened.refusal], json);
209009
209543
  process.exitCode = 1;
@@ -209181,7 +209715,7 @@ async function handleInspect(args, cwd) {
209181
209715
  return;
209182
209716
  }
209183
209717
  const projectRoot = resolveBundleProjectRoot(cwd);
209184
- const result = await inspectBundle(path382.resolve(cwd, bundlePath), {
209718
+ const result = await inspectBundle(path383.resolve(cwd, bundlePath), {
209185
209719
  projectRoot,
209186
209720
  targetScope: targetScopeArg
209187
209721
  });
@@ -209225,7 +209759,7 @@ async function handleVerify(args, cwd) {
209225
209759
  failUsage("keryx bundle verify requires a <bundle> argument (or --external-imports)");
209226
209760
  return;
209227
209761
  }
209228
- const outcome = await verifyBundlePath(path382.resolve(cwd, bundlePath));
209762
+ const outcome = await verifyBundlePath(path383.resolve(cwd, bundlePath));
209229
209763
  if (!outcome.ok) {
209230
209764
  printRefusals(outcome.refusals, json);
209231
209765
  process.exitCode = 1;
@@ -209368,23 +209902,23 @@ var init_bundle = __esm(() => {
209368
209902
 
209369
209903
  // src/commands/learn.ts
209370
209904
  import { existsSync as existsSync60 } from "fs";
209371
- import { readFile as readFile195 } from "fs/promises";
209905
+ import { readFile as readFile196 } from "fs/promises";
209372
209906
  import { createInterface as createInterface4 } from "readline/promises";
209373
- import path383 from "path";
209907
+ import path384 from "path";
209374
209908
  function resolveRoot2(deps) {
209375
209909
  return resolveProjectRoot2(deps.cwd ?? process.cwd());
209376
209910
  }
209377
209911
  function resolveLearnRoot(startDir, env) {
209378
- const hasMetaproject = (dir) => existsSync60(path383.join(dir, ".metaproject"));
209912
+ const hasMetaproject = (dir) => existsSync60(path384.join(dir, ".metaproject"));
209379
209913
  const fromEnv = env.CLAUDE_PROJECT_DIR;
209380
209914
  if (typeof fromEnv === "string" && fromEnv.length > 0 && hasMetaproject(fromEnv)) {
209381
209915
  return fromEnv;
209382
209916
  }
209383
- let current = path383.resolve(startDir);
209917
+ let current = path384.resolve(startDir);
209384
209918
  for (;; ) {
209385
209919
  if (hasMetaproject(current))
209386
209920
  return current;
209387
- const parent = path383.dirname(current);
209921
+ const parent = path384.dirname(current);
209388
209922
  if (parent === current)
209389
209923
  return;
209390
209924
  current = parent;
@@ -209480,7 +210014,7 @@ async function runObserveHook(deps) {
209480
210014
  }
209481
210015
  async function countObservationLines(filePath) {
209482
210016
  try {
209483
- const raw = await readFile195(filePath, "utf8");
210017
+ const raw = await readFile196(filePath, "utf8");
209484
210018
  return raw.split(`
209485
210019
  `).filter((line) => line.length > 0).length;
209486
210020
  } catch {
@@ -210217,7 +210751,7 @@ var init_group_subcommands = __esm(() => {
210217
210751
  ["trigger", ["run", "install", "uninstall", "list", "status", "schedule", "resolve"]],
210218
210752
  ["schedule", ["add", "list", "show", "pause", "resume", "run", "remove"]],
210219
210753
  ["governance", ["report", "show"]],
210220
- ["decisions", ["open", "answer", "reason", "report"]],
210754
+ ["decisions", ["open", "answer", "reason", "report", "import"]],
210221
210755
  ["product", ["index", "open"]],
210222
210756
  ["hooks", ["list", "validate", "test", "enable", "disable", "trust", "untrust"]],
210223
210757
  ["bundle", ["export", "import", "inspect", "verify", "uninstall"]],
@@ -210521,9 +211055,11 @@ var VERSION3, CLI_ROUTES, MCP_KNOWN_SUBCOMMANDS, USAGE_BODY = `Usage:
210521
211055
  Spend, confirmations, signatures and gate outcomes,
210522
211056
  unified across flows; writes latest.md/latest.json
210523
211057
  keryx governance show [--json] Reprint the most recently written governance report
210524
- keryx decisions open|answer|reason|report Recommendation journal: record a question with options and its
211058
+ keryx decisions open|answer|reason|report [--json|--line]|import <file.jsonl> [--dry-run] [--json]
211059
+ Recommendation journal: record a question with options and its
210525
211060
  recommendation before showing it, the human's choice after;
210526
- report = match share by mode and stage, deviations (no model)
211061
+ report = match share by mode and stage, deviations (no model);
211062
+ import = earlier decisions from a JSON-lines file, kept apart
210527
211063
  keryx product index [--json] Read every flow and requirements package into a disposable intent index; reports entries with no stated intent
210528
211064
  keryx product open [--json] Intents closed in code with no recorded look back, each with its outcome criterion
210529
211065
  keryx hooks list [--json] Resolved keryx shell lifecycle hooks (built-in -> user -> project)