@open-tomato/rafa 0.9.0 → 0.9.2

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 (4) hide show
  1. package/README.md +25 -8
  2. package/dist/cli.js +800 -505
  3. package/dist/index.js +401 -146
  4. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1534,7 +1534,7 @@ function routeLine(registry, argv) {
1534
1534
 
1535
1535
  // package.json
1536
1536
  var name = "@open-tomato/rafa";
1537
- var version = "0.9.0";
1537
+ var version = "0.9.2";
1538
1538
 
1539
1539
  // src/cli/version.ts
1540
1540
  var RAFA_VERSION = version;
@@ -3146,7 +3146,7 @@ var describeCommand2 = {
3146
3146
  var describe_default = Object.freeze(describeCommand2);
3147
3147
 
3148
3148
  // src/commands/doctor.ts
3149
- import { basename as basename5, relative, resolve as resolve7, sep as sep2 } from "path";
3149
+ import { basename as basename6, relative, resolve as resolve8, sep as sep2 } from "path";
3150
3150
 
3151
3151
  // src/adapters/tracker/issue-values.ts
3152
3152
  var TYPE_MEMBERS = {
@@ -3508,8 +3508,8 @@ function createGithubTracker(options) {
3508
3508
  }
3509
3509
 
3510
3510
  // src/board/status.ts
3511
- import { statSync as statSync5 } from "fs";
3512
- import { join as join10 } from "path";
3511
+ import { statSync as statSync6 } from "fs";
3512
+ import { join as join11 } from "path";
3513
3513
 
3514
3514
  // src/board/naming.ts
3515
3515
  import path from "path";
@@ -3842,8 +3842,8 @@ function withRoadmapIssue(text2, issue) {
3842
3842
  }
3843
3843
 
3844
3844
  // src/board/setup.ts
3845
- import { existsSync as existsSync6, lstatSync, mkdirSync as mkdirSync4, readFileSync as readFileSync9, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
3846
- import { dirname as dirname5, join as join9 } from "path";
3845
+ import { existsSync as existsSync6, lstatSync, mkdirSync as mkdirSync5, readFileSync as readFileSync9, statSync as statSync5, writeFileSync as writeFileSync4 } from "fs";
3846
+ import { dirname as dirname5, join as join10 } from "path";
3847
3847
  import { fileURLToPath } from "url";
3848
3848
 
3849
3849
  // src/board/blocked.ts
@@ -5394,9 +5394,89 @@ async function enforceSpecReview(options) {
5394
5394
  }
5395
5395
 
5396
5396
  // src/board/issue.ts
5397
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync8, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
5398
- import { dirname as dirname4, resolve as resolve4 } from "path";
5399
- var PREFIX3 = "board issue";
5397
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync8, statSync as statSync4, writeFileSync as writeFileSync3 } from "fs";
5398
+ import { dirname as dirname4, resolve as resolve5 } from "path";
5399
+
5400
+ // src/board/previous-copy.ts
5401
+ import { linkSync, mkdirSync as mkdirSync3, readdirSync as readdirSync2, statSync as statSync3, unlinkSync } from "fs";
5402
+ import { basename as basename4, extname, join as join9, resolve as resolve4 } from "path";
5403
+ var PREFIX3 = "board previous copy";
5404
+ var PREVIOUS_DIR_NAME = "previous";
5405
+ var PREVIOUS_COPY_WARN_ABOVE = 50;
5406
+ var COPY_EXTENSION = ".md";
5407
+ var FIRST_SUFFIX = 2;
5408
+ function previousDir(specsDir) {
5409
+ return join9(specsDir, PREVIOUS_DIR_NAME);
5410
+ }
5411
+ function two(value) {
5412
+ return String(value).padStart(2, "0");
5413
+ }
5414
+ function previousTimestamp(mtime) {
5415
+ const date = `${String(mtime.getUTCFullYear()).padStart(4, "0")}${two(mtime.getUTCMonth() + 1)}${two(mtime.getUTCDate())}`;
5416
+ const time = `${two(mtime.getUTCHours())}${two(mtime.getUTCMinutes())}${two(mtime.getUTCSeconds())}`;
5417
+ return `${date}T${time}Z`;
5418
+ }
5419
+ function previousCopyName(savedName, timestamp, attempt) {
5420
+ const stem = basename4(savedName, extname(savedName));
5421
+ const suffix = attempt < FIRST_SUFFIX ? "" : `-${String(attempt)}`;
5422
+ return `${stem}.${timestamp}${suffix}${COPY_EXTENSION}`;
5423
+ }
5424
+ function isTaken(error) {
5425
+ return error instanceof Error && "code" in error && error.code === "EEXIST";
5426
+ }
5427
+ function linkUnderFreeName(source, directory2, savedName, timestamp) {
5428
+ for (let attempt = 1;; attempt += 1) {
5429
+ const name2 = previousCopyName(savedName, timestamp, attempt);
5430
+ try {
5431
+ linkSync(source, join9(directory2, name2));
5432
+ return name2;
5433
+ } catch (error) {
5434
+ if (!isTaken(error))
5435
+ throw error;
5436
+ }
5437
+ }
5438
+ }
5439
+ function movePreviousCopy(options) {
5440
+ const { repoRoot, specsDir, path: path2 } = options;
5441
+ const source = resolve4(repoRoot, path2);
5442
+ const directory2 = previousDir(specsDir);
5443
+ const absoluteDirectory = resolve4(repoRoot, directory2);
5444
+ const savedName = basename4(path2);
5445
+ let name2;
5446
+ try {
5447
+ const timestamp = previousTimestamp(statSync3(source).mtime);
5448
+ mkdirSync3(absoluteDirectory, { recursive: true });
5449
+ name2 = linkUnderFreeName(source, absoluteDirectory, savedName, timestamp);
5450
+ } catch (error) {
5451
+ throw new Error(`${PREFIX3}: ${path2} could not be moved to ${directory2}: ${messageOf(error)}`, { cause: error });
5452
+ }
5453
+ const moved = {
5454
+ path: join9(directory2, name2),
5455
+ absolute: join9(absoluteDirectory, name2)
5456
+ };
5457
+ try {
5458
+ unlinkSync(source);
5459
+ } catch (error) {
5460
+ throw new Error(`${PREFIX3}: ${path2} was copied to ${moved.path} but could not be removed: ${messageOf(error)}`, { cause: error });
5461
+ }
5462
+ return moved;
5463
+ }
5464
+ function isMissing(error) {
5465
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
5466
+ }
5467
+ function countPreviousCopies(repoRoot, specsDir) {
5468
+ const directory2 = previousDir(specsDir);
5469
+ try {
5470
+ return readdirSync2(resolve4(repoRoot, directory2), { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(COPY_EXTENSION)).length;
5471
+ } catch (error) {
5472
+ if (isMissing(error))
5473
+ return 0;
5474
+ throw new Error(`${PREFIX3}: ${directory2} could not be read: ${messageOf(error)}`, { cause: error });
5475
+ }
5476
+ }
5477
+
5478
+ // src/board/issue.ts
5479
+ var PREFIX4 = "board issue";
5400
5480
  var ISSUE_VIEW_FIELDS = "number,title,body,state,labels,author";
5401
5481
  var SPEC_LABEL = "type:spec";
5402
5482
  var ISSUE_REFUSAL_EXIT = 2;
@@ -5407,7 +5487,7 @@ function detailOf4(result, command) {
5407
5487
  }
5408
5488
  function issueNumber2(value) {
5409
5489
  if (!Number.isSafeInteger(value) || value < 1) {
5410
- throw new TypeError(`${PREFIX3}: the read refused issue number ${describeValue(value)}, expected a positive whole number`);
5490
+ throw new TypeError(`${PREFIX4}: the read refused issue number ${describeValue(value)}, expected a positive whole number`);
5411
5491
  }
5412
5492
  return String(value);
5413
5493
  }
@@ -5442,11 +5522,11 @@ function readViewedIssue(stdout, number, command) {
5442
5522
  try {
5443
5523
  payload = JSON.parse(stdout);
5444
5524
  } catch (error) {
5445
- throw new Error(`${PREFIX3}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
5525
+ throw new Error(`${PREFIX4}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
5446
5526
  }
5447
5527
  const problem = viewProblem2(payload, number);
5448
5528
  if (problem !== null)
5449
- throw new Error(`${PREFIX3}: ${command} answered ${problem}`);
5529
+ throw new Error(`${PREFIX4}: ${command} answered ${problem}`);
5450
5530
  const checked = payload;
5451
5531
  return {
5452
5532
  number,
@@ -5464,7 +5544,7 @@ function createGhSpecIssueReader(options) {
5464
5544
  const command = `gh issue view ${number} --json ${ISSUE_VIEW_FIELDS}`;
5465
5545
  const result = await gh(["issue", "view", number, "--json", ISSUE_VIEW_FIELDS]);
5466
5546
  if (!result.ok)
5467
- throw new Error(`${PREFIX3}: ${detailOf4(result, command)}`);
5547
+ throw new Error(`${PREFIX4}: ${detailOf4(result, command)}`);
5468
5548
  return readViewedIssue(result.stdout, issue, command);
5469
5549
  };
5470
5550
  }
@@ -5502,10 +5582,91 @@ ${local}`
5502
5582
  `)}
5503
5583
  `;
5504
5584
  }
5585
+ var NOTES_SEPARATOR = `
5586
+
5587
+ ${LOCAL_NOTES_HEADING}
5588
+
5589
+ `;
5590
+ var HEADING = /^#{1,6}(?:[ \t]|$)/u;
5591
+ var FENCE2 = /^ {0,3}(?:`{3,}|~{3,})/u;
5592
+ function commonLines(before, after) {
5593
+ let previous = new Uint32Array(after.length + 1);
5594
+ for (const line of before) {
5595
+ const row2 = new Uint32Array(after.length + 1);
5596
+ after.forEach((other, index) => {
5597
+ row2[index + 1] = line === other ? (previous[index] ?? 0) + 1 : Math.max(previous[index + 1] ?? 0, row2[index] ?? 0);
5598
+ });
5599
+ previous = row2;
5600
+ }
5601
+ return previous[after.length] ?? 0;
5602
+ }
5603
+ function headingName(line) {
5604
+ const text2 = line.replace(/^#+/u, "").replace(/[ \t]+#+[ \t]*$/u, "").trim();
5605
+ return text2 === "" ? line.trim() : text2;
5606
+ }
5607
+ function headingSections(lines) {
5608
+ const sections = new Map;
5609
+ let fenced = false;
5610
+ let current = null;
5611
+ const close = () => {
5612
+ if (current === null)
5613
+ return;
5614
+ sections.set(current.key, [...sections.get(current.key) ?? [], current.lines.join(`
5615
+ `)]);
5616
+ };
5617
+ for (const line of lines) {
5618
+ if (FENCE2.test(line))
5619
+ fenced = !fenced;
5620
+ if (fenced || !HEADING.test(line)) {
5621
+ current?.lines.push(line);
5622
+ continue;
5623
+ }
5624
+ close();
5625
+ current = { key: line.trim(), lines: [] };
5626
+ }
5627
+ close();
5628
+ return sections;
5629
+ }
5630
+ function changedHeadings(before, after) {
5631
+ const old = headingSections(before);
5632
+ const now = headingSections(after);
5633
+ const keys = [...now.keys(), ...[...old.keys()].filter((key) => !now.has(key))];
5634
+ const changed = keys.filter((key) => JSON.stringify(old.get(key) ?? []) !== JSON.stringify(now.get(key) ?? []));
5635
+ return [...new Set(changed.map(headingName))];
5636
+ }
5637
+ function bodyChangeLine(before, after) {
5638
+ const old = before.split(`
5639
+ `);
5640
+ const now = after.split(`
5641
+ `);
5642
+ const common = commonLines(old, now);
5643
+ const headings = changedHeadings(old, now);
5644
+ const clause = headings.length === 0 ? "no heading changed" : `headings changed: ${headings.join(", ")}`;
5645
+ return `issue body: +${String(now.length - common)} -${String(old.length - common)} lines; ${clause}`;
5646
+ }
5647
+ function notesChangeLine(path2) {
5648
+ return `local notes: ${path2} changed since the saved copy`;
5649
+ }
5650
+ function readSnapshotChange(options) {
5651
+ const { saved, body, notes, notesPath: path2 } = options;
5652
+ if (saved === snapshotText(body, notes))
5653
+ return { kind: "unchanged", bodyLine: null, notesLine: null };
5654
+ const now = normalise(body);
5655
+ if (saved === `${now}
5656
+ ` || saved.startsWith(`${now}${NOTES_SEPARATOR}`)) {
5657
+ return { kind: "notes", bodyLine: null, notesLine: notesChangeLine(path2) };
5658
+ }
5659
+ const split = saved.lastIndexOf(NOTES_SEPARATOR);
5660
+ const oldBody = split === -1 ? saved : saved.slice(0, split);
5661
+ const oldNotes = split === -1 ? "" : normalise(saved.slice(split + NOTES_SEPARATOR.length)).trim();
5662
+ const newNotes = notes === null ? "" : normalise(notes).trim();
5663
+ const bodyLine = bodyChangeLine(normalise(oldBody), now);
5664
+ return oldNotes === newNotes ? { kind: "body", bodyLine, notesLine: null } : { kind: "both", bodyLine, notesLine: notesChangeLine(path2) };
5665
+ }
5505
5666
  function readIfFile(file, what) {
5506
5667
  if (!existsSync5(file))
5507
5668
  return null;
5508
- if (!statSync3(file).isFile()) {
5669
+ if (!statSync4(file).isFile()) {
5509
5670
  throw new CommandExit(ISSUE_REFUSAL_EXIT, `${what} ${file} is not a file, and a spec is one`);
5510
5671
  }
5511
5672
  try {
@@ -5515,7 +5676,7 @@ function readIfFile(file, what) {
5515
5676
  }
5516
5677
  }
5517
5678
  function readLocalNotes(repoRoot, specsDir, issue) {
5518
- return readIfFile(resolve4(repoRoot, notesPath(specsDir, issue)), "the local notes");
5679
+ return readIfFile(resolve5(repoRoot, notesPath(specsDir, issue)), "the local notes");
5519
5680
  }
5520
5681
  function snapshotDiffersMessage(path2, issue) {
5521
5682
  return `${path2} is a snapshot of issue #${String(issue)} that no longer matches it:` + " the issue body, or the local notes appended to it, changed since the snapshot was written;" + ` pass ${REFRESH_FLAG} to plan from the issue as it reads now, or --spec=${path2} to plan from` + " the snapshot as it stands";
@@ -5532,31 +5693,42 @@ function writeSpecSnapshot(options) {
5532
5693
  }
5533
5694
  const local = readLocalNotes(repoRoot, specsDir, issue.number);
5534
5695
  const text2 = snapshotText(issue.body, local);
5535
- const absolute = resolve4(repoRoot, path2);
5696
+ const absolute = resolve5(repoRoot, path2);
5536
5697
  const existing = readIfFile(absolute, "the spec snapshot");
5537
5698
  const written = {
5538
5699
  path: path2,
5539
5700
  absolute,
5540
5701
  action: "created",
5541
5702
  notes: local === null ? null : notes,
5703
+ previous: null,
5542
5704
  text: text2
5543
5705
  };
5544
5706
  if (existing === text2)
5545
5707
  return { ...written, action: "unchanged" };
5546
- if (existing !== null && !refresh) {
5708
+ const action = rewriteAction(existing, issue.body, local, notes, refresh);
5709
+ if (action === null) {
5547
5710
  throw new CommandExit(ISSUE_REFUSAL_EXIT, snapshotDiffersMessage(path2, issue.number));
5548
5711
  }
5712
+ const previous = action === "created" ? null : movePreviousCopy({ repoRoot, specsDir, path: path2 }).path;
5549
5713
  try {
5550
- mkdirSync3(dirname4(absolute), { recursive: true });
5714
+ mkdirSync4(dirname4(absolute), { recursive: true });
5551
5715
  writeFileSync3(absolute, text2);
5552
5716
  } catch (error) {
5553
- throw new Error(`${PREFIX3}: the snapshot ${path2} could not be written: ${messageOf(error)}`, { cause: error });
5717
+ throw new Error(`${PREFIX4}: the snapshot ${path2} could not be written: ${messageOf(error)}`, { cause: error });
5554
5718
  }
5555
- return existing === null ? written : { ...written, action: "refreshed" };
5719
+ return { ...written, action, previous };
5720
+ }
5721
+ function rewriteAction(existing, body, notes, notesFile, refresh) {
5722
+ if (existing === null)
5723
+ return "created";
5724
+ const { kind } = readSnapshotChange({ saved: existing, body, notes, notesPath: notesFile });
5725
+ if (kind === "notes")
5726
+ return "notes-rebuilt";
5727
+ return refresh ? "refreshed" : null;
5556
5728
  }
5557
5729
 
5558
5730
  // src/board/setup.ts
5559
- var PREFIX4 = "board setup";
5731
+ var PREFIX5 = "board setup";
5560
5732
  var MODULE_DIR = dirname5(fileURLToPath(import.meta.url));
5561
5733
  var BOARD_LABELS = Object.freeze([
5562
5734
  {
@@ -5589,7 +5761,7 @@ var BOARD_LABELS = Object.freeze([
5589
5761
  }
5590
5762
  ]);
5591
5763
  var LABEL_LIST_LIMIT = 100;
5592
- var SPEC_TEMPLATE_PATH = join9(".github", "ISSUE_TEMPLATE", "spec.md");
5764
+ var SPEC_TEMPLATE_PATH = join10(".github", "ISSUE_TEMPLATE", "spec.md");
5593
5765
  var TEMPLATES_DIRNAME = "templates";
5594
5766
  var SPEC_TEMPLATE_FILE = "spec.md";
5595
5767
  function boardChanged(report) {
@@ -5607,24 +5779,24 @@ function parseRows2(stdout, command) {
5607
5779
  try {
5608
5780
  payload = JSON.parse(stdout);
5609
5781
  } catch (error) {
5610
- throw new Error(`${PREFIX4}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
5782
+ throw new Error(`${PREFIX5}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
5611
5783
  }
5612
5784
  if (!Array.isArray(payload)) {
5613
- throw new Error(`${PREFIX4}: ${command} answered ${describeValue(payload)}, expected a list`);
5785
+ throw new Error(`${PREFIX5}: ${command} answered ${describeValue(payload)}, expected a list`);
5614
5786
  }
5615
5787
  return payload;
5616
5788
  }
5617
5789
  function rowText2(row2, key, command, where) {
5618
5790
  const value = isMapping(row2) ? row2[key] : null;
5619
5791
  if (typeof value !== "string") {
5620
- throw new Error(`${PREFIX4}: ${command} answered ${where}.${key} as ${describeValue(value)}, expected a string`);
5792
+ throw new Error(`${PREFIX5}: ${command} answered ${where}.${key} as ${describeValue(value)}, expected a string`);
5621
5793
  }
5622
5794
  return value;
5623
5795
  }
5624
5796
  function rowNumber2(row2, key, command, where) {
5625
5797
  const value = isMapping(row2) ? row2[key] : null;
5626
5798
  if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1) {
5627
- throw new Error(`${PREFIX4}: ${command} answered ${where}.${key} as ${describeValue(value)}, expected a positive whole number`);
5799
+ throw new Error(`${PREFIX5}: ${command} answered ${where}.${key} as ${describeValue(value)}, expected a positive whole number`);
5628
5800
  }
5629
5801
  return value;
5630
5802
  }
@@ -5634,7 +5806,7 @@ async function listBoardLabels(gh) {
5634
5806
  const command = `gh label list --limit ${limit} --json name`;
5635
5807
  const result = await gh(args);
5636
5808
  if (!result.ok)
5637
- throw new Error(`${PREFIX4}: ${detailOf5(result, command)}`);
5809
+ throw new Error(`${PREFIX5}: ${detailOf5(result, command)}`);
5638
5810
  return Object.freeze(parseRows2(result.stdout, command).map((row2, index) => rowText2(row2, "name", command, `label ${String(index)}`)));
5639
5811
  }
5640
5812
  function holdsLabel(held, name2) {
@@ -5667,7 +5839,7 @@ async function setUpLabels(gh) {
5667
5839
  }
5668
5840
  function statOrNull(path2) {
5669
5841
  try {
5670
- return statSync4(path2);
5842
+ return statSync5(path2);
5671
5843
  } catch {
5672
5844
  return null;
5673
5845
  }
@@ -5681,17 +5853,17 @@ function anythingAt(path2) {
5681
5853
  }
5682
5854
  }
5683
5855
  function specTemplateSource(moduleDir = MODULE_DIR) {
5684
- return join9(moduleDir, TEMPLATES_DIRNAME, SPEC_TEMPLATE_FILE);
5856
+ return join10(moduleDir, TEMPLATES_DIRNAME, SPEC_TEMPLATE_FILE);
5685
5857
  }
5686
5858
  function readSpecTemplate(moduleDir = MODULE_DIR) {
5687
5859
  const source = specTemplateSource(moduleDir);
5688
5860
  if (!existsSync6(source)) {
5689
- throw new Error(`${PREFIX4}: the spec issue template is missing: no file at ${source}`);
5861
+ throw new Error(`${PREFIX5}: the spec issue template is missing: no file at ${source}`);
5690
5862
  }
5691
5863
  return readFileSync9(source, "utf8");
5692
5864
  }
5693
5865
  function writeSpecTemplate(root, moduleDir = MODULE_DIR) {
5694
- const path2 = join9(root, SPEC_TEMPLATE_PATH);
5866
+ const path2 = join10(root, SPEC_TEMPLATE_PATH);
5695
5867
  const name2 = SPEC_TEMPLATE_PATH;
5696
5868
  const found = statOrNull(path2);
5697
5869
  if (found !== null) {
@@ -5702,7 +5874,7 @@ function writeSpecTemplate(root, moduleDir = MODULE_DIR) {
5702
5874
  }
5703
5875
  try {
5704
5876
  const text2 = readSpecTemplate(moduleDir);
5705
- mkdirSync4(dirname5(path2), { recursive: true });
5877
+ mkdirSync5(dirname5(path2), { recursive: true });
5706
5878
  writeFileSync4(path2, text2, { encoding: "utf8", flag: "wx" });
5707
5879
  return partOf("template", name2, "created", `written from ${specTemplateSource(moduleDir)}`);
5708
5880
  } catch (error) {
@@ -5776,7 +5948,7 @@ async function searchRoadmapIssues(gh) {
5776
5948
  const command = `gh issue list --state open --search "${search}" --json number,title`;
5777
5949
  const result = await gh(args);
5778
5950
  if (!result.ok)
5779
- throw new Error(`${PREFIX4}: ${detailOf5(result, command)}`);
5951
+ throw new Error(`${PREFIX5}: ${detailOf5(result, command)}`);
5780
5952
  const wanted = ROADMAP_TITLE.toLowerCase();
5781
5953
  return Object.freeze(parseRows2(result.stdout, command).map((row2, index) => ({
5782
5954
  number: rowNumber2(row2, "number", command, `issue ${String(index)}`),
@@ -5787,12 +5959,12 @@ async function createRoadmapIssue(gh) {
5787
5959
  const command = `gh issue create --title ${ROADMAP_TITLE}`;
5788
5960
  const result = await gh(["issue", "create", "--title", ROADMAP_TITLE, "--body", roadmapIssueBody()]);
5789
5961
  if (!result.ok)
5790
- throw new Error(`${PREFIX4}: ${detailOf5(result, command)}`);
5962
+ throw new Error(`${PREFIX5}: ${detailOf5(result, command)}`);
5791
5963
  const url = result.stdout.trim().split(`
5792
5964
  `).at(-1) ?? "";
5793
5965
  const number = CREATED_ISSUE_URL2.exec(url)?.[1];
5794
5966
  if (number === undefined) {
5795
- throw new Error(`${PREFIX4}: ${command} exited 0 and printed no issue URL, so the issue may exist` + ` unrecorded; it wrote ${describeValue(result.stdout)}`);
5967
+ throw new Error(`${PREFIX5}: ${command} exited 0 and printed no issue URL, so the issue may exist` + ` unrecorded; it wrote ${describeValue(result.stdout)}`);
5796
5968
  }
5797
5969
  return Number.parseInt(number, 10);
5798
5970
  }
@@ -5882,11 +6054,11 @@ async function readLabelRows(gh) {
5882
6054
  return Object.freeze(BOARD_LABELS.map((label) => missing2.includes(label) ? rowOf("label", label.name, "missing", "the repository carries no label of that name") : rowOf("label", label.name, "present", "the repository carries it")));
5883
6055
  }
5884
6056
  function readTemplateRow(root) {
5885
- const path2 = join10(root, SPEC_TEMPLATE_PATH);
6057
+ const path2 = join11(root, SPEC_TEMPLATE_PATH);
5886
6058
  const name2 = SPEC_TEMPLATE_PATH;
5887
6059
  let found;
5888
6060
  try {
5889
- found = statSync5(path2);
6061
+ found = statSync6(path2);
5890
6062
  } catch {
5891
6063
  return rowOf("template", name2, "missing", "the repository carries no spec issue template");
5892
6064
  }
@@ -5954,18 +6126,18 @@ async function readBoardStatus(options) {
5954
6126
  }
5955
6127
 
5956
6128
  // src/effort/store/legacy.ts
5957
- import { statSync as statSync6 } from "fs";
5958
- import { basename as basename4, join as join13 } from "path";
6129
+ import { statSync as statSync7 } from "fs";
6130
+ import { basename as basename5, join as join14 } from "path";
5959
6131
 
5960
6132
  // src/effort/store.ts
5961
6133
  import {
5962
6134
  appendFileSync,
5963
6135
  existsSync as existsSync7,
5964
- mkdirSync as mkdirSync5,
6136
+ mkdirSync as mkdirSync6,
5965
6137
  readFileSync as readFileSync10
5966
6138
  } from "fs";
5967
- import { dirname as dirname6, join as join11 } from "path";
5968
- var EFFORT_STORE_DIR = join11(".rafa", "effort");
6139
+ import { dirname as dirname6, join as join12 } from "path";
6140
+ var EFFORT_STORE_DIR = join12(".rafa", "effort");
5969
6141
  var STORE_FILE_NAMES = {
5970
6142
  sessions: "sessions.ndjson",
5971
6143
  commits: "commits.ndjson"
@@ -5977,7 +6149,7 @@ function normaliseKey(key) {
5977
6149
  return typeof key === "string" && key.length > 0 ? key : null;
5978
6150
  }
5979
6151
  function effortStorePath(repoRoot, kind) {
5980
- return join11(repoRoot, EFFORT_STORE_DIR, STORE_FILE_NAMES[kind]);
6152
+ return join12(repoRoot, EFFORT_STORE_DIR, STORE_FILE_NAMES[kind]);
5981
6153
  }
5982
6154
  function readStoreText(path2) {
5983
6155
  return existsSync7(path2) ? readFileSync10(path2, "utf8") : null;
@@ -6052,7 +6224,7 @@ function appendRows(path2, rows2, keyOf) {
6052
6224
  `);
6053
6225
  const lead = separatedPartialLine ? `
6054
6226
  ` : "";
6055
- mkdirSync5(dirname6(path2), { recursive: true });
6227
+ mkdirSync6(dirname6(path2), { recursive: true });
6056
6228
  appendFileSync(path2, `${lead}${lines.join(`
6057
6229
  `)}
6058
6230
  `, "utf8");
@@ -6065,8 +6237,8 @@ function appendRows(path2, rows2, keyOf) {
6065
6237
  }
6066
6238
 
6067
6239
  // src/effort/store/sqlite.ts
6068
- import { existsSync as existsSync8, mkdirSync as mkdirSync6 } from "fs";
6069
- import { dirname as dirname7, join as join12 } from "path";
6240
+ import { existsSync as existsSync8, mkdirSync as mkdirSync7 } from "fs";
6241
+ import { dirname as dirname7, join as join13 } from "path";
6070
6242
  import { Database } from "bun:sqlite";
6071
6243
 
6072
6244
  // src/effort/store/types.ts
@@ -6081,7 +6253,7 @@ var EFFORT_KEY_PROJECTIONS = {
6081
6253
  // src/effort/store/sqlite.ts
6082
6254
  var STORE_FILE_NAME = "effort.sqlite";
6083
6255
  function sqliteStorePath(repoRoot) {
6084
- return join12(repoRoot, EFFORT_STORE_DIR, STORE_FILE_NAME);
6256
+ return join13(repoRoot, EFFORT_STORE_DIR, STORE_FILE_NAME);
6085
6257
  }
6086
6258
  var SQLITE_MIGRATIONS = [
6087
6259
  `
@@ -6291,7 +6463,7 @@ function migrateSchema(db, path2, migrations = SQLITE_MIGRATIONS) {
6291
6463
  }
6292
6464
  function withSqliteStore(path2, create, use) {
6293
6465
  if (create)
6294
- mkdirSync6(dirname7(path2), { recursive: true });
6466
+ mkdirSync7(dirname7(path2), { recursive: true });
6295
6467
  const db = new Database(path2, { readwrite: true, create });
6296
6468
  try {
6297
6469
  migrateSchema(db, path2);
@@ -6361,11 +6533,11 @@ function openSqliteStore(repoRoot) {
6361
6533
  }
6362
6534
 
6363
6535
  // src/effort/store/legacy.ts
6364
- var LEGACY_EFFORT_STORE_DIR = join13(".ralph", "effort");
6536
+ var LEGACY_EFFORT_STORE_DIR = join14(".ralph", "effort");
6365
6537
  var NDJSON_KINDS = { sessions: true, commits: true };
6366
6538
  var STORE_FILE_NAMES2 = Object.freeze([
6367
- basename4(sqliteStorePath("")),
6368
- ...Object.keys(NDJSON_KINDS).map((kind) => basename4(effortStorePath("", kind)))
6539
+ basename5(sqliteStorePath("")),
6540
+ ...Object.keys(NDJSON_KINDS).map((kind) => basename5(effortStorePath("", kind)))
6369
6541
  ]);
6370
6542
  function isAbsence(error) {
6371
6543
  if (typeof error !== "object" || error === null || !("code" in error))
@@ -6374,7 +6546,7 @@ function isAbsence(error) {
6374
6546
  }
6375
6547
  function isStoreFile(path2) {
6376
6548
  try {
6377
- return statSync6(path2).isFile();
6549
+ return statSync7(path2).isFile();
6378
6550
  } catch (error) {
6379
6551
  if (isAbsence(error))
6380
6552
  return false;
@@ -6382,7 +6554,7 @@ function isStoreFile(path2) {
6382
6554
  }
6383
6555
  }
6384
6556
  function storeFilesIn(dir) {
6385
- return Object.freeze(STORE_FILE_NAMES2.filter((name2) => isStoreFile(join13(dir, name2))));
6557
+ return Object.freeze(STORE_FILE_NAMES2.filter((name2) => isStoreFile(join14(dir, name2))));
6386
6558
  }
6387
6559
  function shellQuoted(path2) {
6388
6560
  return `'${path2.replaceAll("'", "'\\''")}'`;
@@ -6392,8 +6564,8 @@ function legacyWarning(legacyDir, storeDir, legacyFiles) {
6392
6564
  return `${legacyDir} holds an effort store (${legacyFiles.join(", ")}) and ${storeDir} holds none;` + ` rafa reads ${storeDir} alone, so its reports start from an empty store. Once no loop is running,` + ` move it: ${move}`;
6393
6565
  }
6394
6566
  function readLegacyStore(root) {
6395
- const legacyDir = join13(root, LEGACY_EFFORT_STORE_DIR);
6396
- const storeDir = join13(root, EFFORT_STORE_DIR);
6567
+ const legacyDir = join14(root, LEGACY_EFFORT_STORE_DIR);
6568
+ const storeDir = join14(root, EFFORT_STORE_DIR);
6397
6569
  const legacyFiles = storeFilesIn(legacyDir);
6398
6570
  const storeFiles = storeFilesIn(storeDir);
6399
6571
  const warning = legacyFiles.length > 0 && storeFiles.length === 0 ? legacyWarning(legacyDir, storeDir, legacyFiles) : null;
@@ -6541,9 +6713,9 @@ function isFirstDispatch(planPath) {
6541
6713
  }
6542
6714
 
6543
6715
  // src/project/bin-path.ts
6544
- import { delimiter, isAbsolute as isAbsolute4, join as join14, resolve as resolve5 } from "path";
6545
- var RAFA_BIN_DIR = join14(SCOPE_DIR, "bin");
6546
- var BUN_BIN_DIR = join14(".bun", "bin");
6716
+ import { delimiter, isAbsolute as isAbsolute4, join as join15, resolve as resolve6 } from "path";
6717
+ var RAFA_BIN_DIR = join15(SCOPE_DIR, "bin");
6718
+ var BUN_BIN_DIR = join15(".bun", "bin");
6547
6719
  function exportLine(rafaBin) {
6548
6720
  return `export PATH="${rafaBin}:$PATH"`;
6549
6721
  }
@@ -6560,7 +6732,7 @@ function canonical(path2, fs2) {
6560
6732
  try {
6561
6733
  return fs2.realpath(path2);
6562
6734
  } catch {
6563
- return resolve5(path2);
6735
+ return resolve6(path2);
6564
6736
  }
6565
6737
  }
6566
6738
  function indexOf(entries, dir, fs2) {
@@ -6576,8 +6748,8 @@ function stateOf2(rafaIndex, bunIndex) {
6576
6748
  return "ahead";
6577
6749
  }
6578
6750
  function readBinPath(pathValue, home, fs2 = DISK_FILE_SYSTEM) {
6579
- const rafaBin = join14(home, RAFA_BIN_DIR);
6580
- const bunBin = join14(home, BUN_BIN_DIR);
6751
+ const rafaBin = join15(home, RAFA_BIN_DIR);
6752
+ const bunBin = join15(home, BUN_BIN_DIR);
6581
6753
  const entries = (pathValue ?? "").split(delimiter);
6582
6754
  const rafaIndex = indexOf(entries, rafaBin, fs2);
6583
6755
  const bunIndex = indexOf(entries, bunBin, fs2);
@@ -6620,20 +6792,20 @@ function readPreInitDirs(config) {
6620
6792
 
6621
6793
  // src/start/plan-path.ts
6622
6794
  import { existsSync as existsSync9 } from "fs";
6623
- import { resolve as resolve6 } from "path";
6795
+ import { resolve as resolve7 } from "path";
6624
6796
  var DEFAULT_PLAN_FILE = "PLAN.md";
6625
6797
  function resolvePlanPath(repoRoot, planDir, planArg) {
6626
6798
  if (planArg)
6627
- return resolve6(repoRoot, planArg);
6628
- const inPlanDir = resolve6(repoRoot, planDir, DEFAULT_PLAN_FILE);
6629
- return existsSync9(inPlanDir) ? inPlanDir : resolve6(repoRoot, DEFAULT_PLAN_FILE);
6799
+ return resolve7(repoRoot, planArg);
6800
+ const inPlanDir = resolve7(repoRoot, planDir, DEFAULT_PLAN_FILE);
6801
+ return existsSync9(inPlanDir) ? inPlanDir : resolve7(repoRoot, DEFAULT_PLAN_FILE);
6630
6802
  }
6631
6803
 
6632
6804
  // src/commands/doctor-blocked.ts
6633
6805
  var BLOCKED_HEADING = "Blocked issues:";
6634
6806
  var BLOCKED_LIST_LIMIT = 100;
6635
6807
  var KNOWN_LIST_LIMIT = 500;
6636
- var PREFIX5 = "board blocked";
6808
+ var PREFIX6 = "board blocked";
6637
6809
  function detailOf6(result, command) {
6638
6810
  const written = result.stderr.trim() || result.stdout.trim();
6639
6811
  return written === "" ? `${command} failed and wrote nothing` : `${command} failed: ${written}`;
@@ -6641,32 +6813,32 @@ function detailOf6(result, command) {
6641
6813
  async function rowsOf(gh, args, command) {
6642
6814
  const result = await gh(args);
6643
6815
  if (!result.ok)
6644
- throw new Error(`${PREFIX5}: ${detailOf6(result, command)}`);
6816
+ throw new Error(`${PREFIX6}: ${detailOf6(result, command)}`);
6645
6817
  let parsed;
6646
6818
  try {
6647
6819
  parsed = JSON.parse(result.stdout);
6648
6820
  } catch (error) {
6649
- throw new Error(`${PREFIX5}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
6821
+ throw new Error(`${PREFIX6}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
6650
6822
  }
6651
6823
  if (!Array.isArray(parsed)) {
6652
- throw new Error(`${PREFIX5}: ${command} answered ${describeValue(parsed)}, expected a list of issues`);
6824
+ throw new Error(`${PREFIX6}: ${command} answered ${describeValue(parsed)}, expected a list of issues`);
6653
6825
  }
6654
6826
  return parsed;
6655
6827
  }
6656
6828
  function rowNumber3(row2, command, where) {
6657
6829
  if (!isMapping(row2)) {
6658
- throw new Error(`${PREFIX5}: ${command} answered ${where} as ${describeValue(row2)}, expected a mapping`);
6830
+ throw new Error(`${PREFIX6}: ${command} answered ${where} as ${describeValue(row2)}, expected a mapping`);
6659
6831
  }
6660
6832
  const number = row2["number"];
6661
6833
  if (typeof number !== "number" || !Number.isSafeInteger(number) || number < 1) {
6662
- throw new Error(`${PREFIX5}: ${command} answered ${where}.number as ${describeValue(number)}, expected a positive whole number`);
6834
+ throw new Error(`${PREFIX6}: ${command} answered ${where}.number as ${describeValue(number)}, expected a positive whole number`);
6663
6835
  }
6664
6836
  return number;
6665
6837
  }
6666
6838
  function rowBody(row2, command, where) {
6667
6839
  const body = isMapping(row2) ? row2["body"] : null;
6668
6840
  if (typeof body !== "string") {
6669
- throw new Error(`${PREFIX5}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
6841
+ throw new Error(`${PREFIX6}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
6670
6842
  }
6671
6843
  return body;
6672
6844
  }
@@ -6756,6 +6928,16 @@ function renderBlockedIssues(report) {
6756
6928
  return [BLOCKED_HEADING, ...body, ...unchecked];
6757
6929
  }
6758
6930
 
6931
+ // src/commands/doctor-previous.ts
6932
+ function previousCopiesWarning(specsDir, count) {
6933
+ return `rafa doctor: ${previousDir(specsDir)}/ holds ${count} previous copies of issue specs; they are safe to delete`;
6934
+ }
6935
+ function readPreviousCopies(repoRoot, config) {
6936
+ const count = countPreviousCopies(repoRoot, config.specsDir);
6937
+ const warning = count > PREVIOUS_COPY_WARN_ABOVE ? previousCopiesWarning(config.specsDir, count) : null;
6938
+ return { count, warning };
6939
+ }
6940
+
6759
6941
  // src/commands/init-board.ts
6760
6942
  var YES_ANSWERS = ["y", "yes"];
6761
6943
  var BOARD_QUESTION = "Set up the GitHub board for this repo? [y/N] ";
@@ -6896,7 +7078,7 @@ function resolvedConfig3(project, warn) {
6896
7078
  }
6897
7079
  }
6898
7080
  function defaultPlanPaths(root, planDir) {
6899
- return [...new Set([resolve7(root, planDir, DEFAULT_PLAN_FILE), resolve7(root, DEFAULT_PLAN_FILE)])];
7081
+ return [...new Set([resolve8(root, planDir, DEFAULT_PLAN_FILE), resolve8(root, DEFAULT_PLAN_FILE)])];
6900
7082
  }
6901
7083
  function planFileAt(path2) {
6902
7084
  try {
@@ -6941,7 +7123,7 @@ function readStartTier(plan, items) {
6941
7123
  return { tier: NO_START_TIER, items: NO_ITEMS2 };
6942
7124
  if (isFirstDispatch(plan))
6943
7125
  return { tier: { checked: start.length, skipped: 0, tracker: null }, items: start };
6944
- const tracker = basename5(trackerPathFor(plan));
7126
+ const tracker = basename6(trackerPathFor(plan));
6945
7127
  return { tier: { checked: 0, skipped: start.length, tracker }, items: NO_ITEMS2 };
6946
7128
  }
6947
7129
  async function checkPreflight(context, project, seams) {
@@ -6998,24 +7180,37 @@ function readPreInit(project) {
6998
7180
  return null;
6999
7181
  }
7000
7182
  }
7183
+ function readPrevious(project) {
7184
+ try {
7185
+ const { config } = loadConfig({ root: project.root, home: project.home }, {}, () => {
7186
+ return;
7187
+ });
7188
+ return readPreviousCopies(project.root, config);
7189
+ } catch {
7190
+ return null;
7191
+ }
7192
+ }
7001
7193
  function readInstall(context, project) {
7002
7194
  const binPath = readBinPath(context.env["PATH"], project.home);
7003
7195
  const preInitDirs = readPreInit(project);
7196
+ const previousCopies = readPrevious(project);
7004
7197
  try {
7005
- return { binPath, legacyStore: readLegacyStore(project.root), preInitDirs, storeProblem: null };
7198
+ return { binPath, legacyStore: readLegacyStore(project.root), preInitDirs, previousCopies, storeProblem: null };
7006
7199
  } catch (error) {
7007
7200
  const storeProblem = `rafa doctor: the effort store directories could not be checked: ${messageOf(error)}`;
7008
- return { binPath, legacyStore: null, preInitDirs, storeProblem };
7201
+ return { binPath, legacyStore: null, preInitDirs, previousCopies, storeProblem };
7009
7202
  }
7010
7203
  }
7011
7204
  function writeInstall(context, install) {
7012
- const { binPath, legacyStore, preInitDirs, storeProblem } = install;
7205
+ const { binPath, legacyStore, preInitDirs, previousCopies, storeProblem } = install;
7013
7206
  if (storeProblem !== null)
7014
7207
  context.output.warn(storeProblem);
7015
7208
  if (legacyStore !== null && legacyStore.warning !== null)
7016
7209
  context.output.warn(legacyStore.warning);
7017
7210
  if (preInitDirs !== null && preInitDirs.warning !== null)
7018
7211
  context.output.warn(preInitDirs.warning);
7212
+ if (previousCopies !== null && previousCopies.warning !== null)
7213
+ context.output.warn(previousCopies.warning);
7019
7214
  if (binPath.warning !== null) {
7020
7215
  context.output.warn(binPath.warning);
7021
7216
  return;
@@ -7042,7 +7237,7 @@ function headLine(preflight) {
7042
7237
  const checked2 = checkedPhrase(count, automatic, "from the config ");
7043
7238
  return `Preflight with no plan, none being at ${where}: ${checked2}, no run started.`;
7044
7239
  }
7045
- const merged = prerequisitesFile === null ? "" : `, with ${basename5(prerequisitesFile)} merged in`;
7240
+ const merged = prerequisitesFile === null ? "" : `, with ${basename6(prerequisitesFile)} merged in`;
7046
7241
  const checked = checkedPhrase(count, automatic, "");
7047
7242
  return `Preflight for ${shownPath(plan, root)}${merged}: ${checked}, no run started.`;
7048
7243
  }
@@ -7064,7 +7259,7 @@ function reminderLines(preflight) {
7064
7259
  if (reminders.length === 0 || prerequisitesFile === null)
7065
7260
  return [];
7066
7261
  return [
7067
- `${basename5(prerequisitesFile)} names ${plural(reminders.length, "step")} the preflight does not check:`,
7262
+ `${basename6(prerequisitesFile)} names ${plural(reminders.length, "step")} the preflight does not check:`,
7068
7263
  ...reminders.map((reminder) => ` line ${String(reminder.line)}: ${reminder.description}`)
7069
7264
  ];
7070
7265
  }
@@ -7123,6 +7318,7 @@ function resultOf(preflight, install, readings) {
7123
7318
  binPath: install.binPath,
7124
7319
  legacyStore: install.legacyStore,
7125
7320
  preInitDirs: install.preInitDirs,
7321
+ previousCopies: install.previousCopies,
7126
7322
  board: readings.board,
7127
7323
  blocked: readings.blocked
7128
7324
  };
@@ -7164,7 +7360,7 @@ function createDoctorCommand(seams = DEFAULT_DOCTOR_SEAMS) {
7164
7360
  subject: "doctor",
7165
7361
  action: "doctor",
7166
7362
  summary: "check the prerequisites rafa loop start checks, and the install, starting no run",
7167
- description: "Checks the prerequisites `rafa loop start` checks before its first session and prints each" + " check, starting no run and storing nothing: the required and optional items of" + " `.rafa/config.yaml`, with the `PREREQUISITES-<stub>.md` beside the plan merged in, and, when the" + " repository resolves to `pr.provider: gh`, the two required items that provider adds ahead of them:" + " `gh` on PATH and `gh auth status` for the remote's host. A plan's `[start]` items are checked" + " after those and ahead of the configured tiers, on a first dispatch alone: a" + " `PLAN_TRACKER-<stub>.md` beside the plan already holding a ticked task makes the next run a" + " resume, which checks none of them and says in one line how many it passed over." + " The plan is the" + " one `--plan=<file>` names, relative to the project root, or the default plan `rafa loop start`" + ` runs. Each probe runs in the project root with stdin closed and a ${String(PROBE_TIMEOUT_MS / 1000)}-second` + " timeout. It exits 1 when a required item fails, naming the item, its probe and its exit code or" + " first line of stderr, where `rafa loop start` would halt, and 0 otherwise. It warns when" + " `.ralph/effort/` holds an effort store and `.rafa/effort/` holds none, and when `~/.rafa/bin` is" + " not on PATH ahead of `~/.bun/bin`; a warning never changes the exit code. On a repository whose" + " provider is `gh` it also reads the GitHub board `rafa init --board` sets up and prints one row per" + " part \u2014 the seven labels, the spec issue template, the Roadmap issue and `roadmap.issue` \u2014 as present," + " missing, or unknown for a reading that failed, naming `rafa init --board` as the fix; it writes" + " nothing to the board and a row never changes the exit code. It then names, under `Blocked" + " issues:`, every open issue labelled `spec:blocked` whose `Blocked by:` line is missing, names no" + " issue, names itself, or names an id the board has no issue for, with what an author does about" + " it; that reading writes nothing and never changes the exit code either. With `--output=json` the" + " checks, both readings, those rows and those issues are the data of the terminal result event," + " unless a required item failed.",
7363
+ description: "Checks the prerequisites `rafa loop start` checks before its first session and prints each" + " check, starting no run and storing nothing: the required and optional items of" + " `.rafa/config.yaml`, with the `PREREQUISITES-<stub>.md` beside the plan merged in, and, when the" + " repository resolves to `pr.provider: gh`, the two required items that provider adds ahead of them:" + " `gh` on PATH and `gh auth status` for the remote's host. A plan's `[start]` items are checked" + " after those and ahead of the configured tiers, on a first dispatch alone: a" + " `PLAN_TRACKER-<stub>.md` beside the plan already holding a ticked task makes the next run a" + " resume, which checks none of them and says in one line how many it passed over." + " The plan is the" + " one `--plan=<file>` names, relative to the project root, or the default plan `rafa loop start`" + ` runs. Each probe runs in the project root with stdin closed and a ${String(PROBE_TIMEOUT_MS / 1000)}-second` + " timeout. It exits 1 when a required item fails, naming the item, its probe and its exit code or" + " first line of stderr, where `rafa loop start` would halt, and 0 otherwise. It warns when" + " `.ralph/effort/` holds an effort store and `.rafa/effort/` holds none, and when `~/.rafa/bin` is" + " not on PATH ahead of `~/.bun/bin`, and when `previous/` under `specs.dir` holds more than fifty" + " previous copies of issue specs, which are safe to delete; a warning never changes the exit code. On a repository whose" + " provider is `gh` it also reads the GitHub board `rafa init --board` sets up and prints one row per" + " part \u2014 the seven labels, the spec issue template, the Roadmap issue and `roadmap.issue` \u2014 as present," + " missing, or unknown for a reading that failed, naming `rafa init --board` as the fix; it writes" + " nothing to the board and a row never changes the exit code. It then names, under `Blocked" + " issues:`, every open issue labelled `spec:blocked` whose `Blocked by:` line is missing, names no" + " issue, names itself, or names an id the board has no issue for, with what an author does about" + " it; that reading writes nothing and never changes the exit code either. With `--output=json` the" + " checks, both readings, those rows and those issues are the data of the terminal result event," + " unless a required item failed.",
7168
7364
  args: [],
7169
7365
  flags: [
7170
7366
  {
@@ -7191,13 +7387,13 @@ function createDoctorCommand(seams = DEFAULT_DOCTOR_SEAMS) {
7191
7387
  var doctor_default = createDoctorCommand();
7192
7388
 
7193
7389
  // src/effort/collect.ts
7194
- import { existsSync as existsSync11, readdirSync as readdirSync2, statSync as statSync7 } from "fs";
7390
+ import { existsSync as existsSync11, readdirSync as readdirSync3, statSync as statSync8 } from "fs";
7195
7391
  import { homedir as homedir2 } from "os";
7196
- import { join as join17, resolve as resolve9 } from "path";
7392
+ import { join as join18, resolve as resolve10 } from "path";
7197
7393
 
7198
7394
  // src/effort/session-log.ts
7199
7395
  import { createReadStream } from "fs";
7200
- import { basename as basename6 } from "path";
7396
+ import { basename as basename7 } from "path";
7201
7397
  import { createInterface } from "readline";
7202
7398
  function emptyUsageTotals() {
7203
7399
  return {
@@ -7225,7 +7421,7 @@ function bump(counts, key) {
7225
7421
  counts[key] = (counts[key] ?? 0) + 1;
7226
7422
  }
7227
7423
  function sessionIdFromPath(filePath) {
7228
- return basename6(filePath).replace(/\.jsonl$/i, "");
7424
+ return basename7(filePath).replace(/\.jsonl$/i, "");
7229
7425
  }
7230
7426
  async function* readLines2(filePath) {
7231
7427
  const stream = createReadStream(filePath, { encoding: "utf8" });
@@ -7782,8 +7978,8 @@ function openNdjsonStore(repoRoot) {
7782
7978
 
7783
7979
  // src/adapters/learning/local.ts
7784
7980
  import { appendFile, mkdir, readFile } from "fs/promises";
7785
- import { join as join15 } from "path";
7786
- var PREFIX6 = "local learning";
7981
+ import { join as join16 } from "path";
7982
+ var PREFIX7 = "local learning";
7787
7983
  var INSTINCTS_FILE = "instincts.ndjson";
7788
7984
  var FLAGS_FILE = "flags.ndjson";
7789
7985
  var MIN_CONFIDENCE = 0.3;
@@ -7910,21 +8106,21 @@ function warnThroughActiveOutput2(message) {
7910
8106
  activeOutput().warn(message);
7911
8107
  }
7912
8108
  function localInstinctsDir(repoRoot) {
7913
- return join15(repoRoot, ".rafa", "instincts");
8109
+ return join16(repoRoot, ".rafa", "instincts");
7914
8110
  }
7915
8111
  function createLocalLearning(options) {
7916
8112
  const { instinctsDir } = options;
7917
8113
  const now = options.now ?? (() => new Date().toISOString());
7918
8114
  const warn = options.warn ?? warnThroughActiveOutput2;
7919
- const instinctsPath = join15(instinctsDir, INSTINCTS_FILE);
7920
- const flagsPath = join15(instinctsDir, FLAGS_FILE);
8115
+ const instinctsPath = join16(instinctsDir, INSTINCTS_FILE);
8116
+ const flagsPath = join16(instinctsDir, FLAGS_FILE);
7921
8117
  async function heldInstincts() {
7922
8118
  const lines = numberedLines(await readIfPresent2(instinctsPath));
7923
8119
  return lines.flatMap(([number, line]) => {
7924
8120
  const reading2 = readLine2(line, heldInstinctProblem);
7925
8121
  if (reading2.ok)
7926
8122
  return [copyInstinct(reading2.value.instinct)];
7927
- warn(`${PREFIX6}: line ${number} of ${instinctsPath} is not a held instinct, so it was skipped: ${reading2.problem}`);
8123
+ warn(`${PREFIX7}: line ${number} of ${instinctsPath} is not a held instinct, so it was skipped: ${reading2.problem}`);
7928
8124
  return [];
7929
8125
  });
7930
8126
  }
@@ -7934,14 +8130,14 @@ function createLocalLearning(options) {
7934
8130
  const reading2 = readLine2(line, flagProblem);
7935
8131
  if (reading2.ok)
7936
8132
  return reading2.value.id;
7937
- throw new Error(`${PREFIX6}: line ${number} of ${flagsPath} is not a flag,` + ` and a bundle skipping it could hold an instinct it flags: ${reading2.problem}`);
8133
+ throw new Error(`${PREFIX7}: line ${number} of ${flagsPath} is not a flag,` + ` and a bundle skipping it could hold an instinct it flags: ${reading2.problem}`);
7938
8134
  }));
7939
8135
  }
7940
8136
  const learning = {
7941
8137
  push: async (payload) => {
7942
8138
  const problem = payloadProblem(payload);
7943
8139
  if (problem !== null) {
7944
- throw new TypeError(`${PREFIX6}: refused to store a push: ${problem}`);
8140
+ throw new TypeError(`${PREFIX7}: refused to store a push: ${problem}`);
7945
8141
  }
7946
8142
  const decisions = payload.instincts.map((incoming) => ({
7947
8143
  incoming,
@@ -7967,11 +8163,11 @@ function createLocalLearning(options) {
7967
8163
  const flag2 = { id, reason, flagged_at: now() };
7968
8164
  const problem = flagProblem(flag2);
7969
8165
  if (problem !== null) {
7970
- throw new TypeError(`${PREFIX6}: refused to write an invalid flag: ${problem}`);
8166
+ throw new TypeError(`${PREFIX7}: refused to write an invalid flag: ${problem}`);
7971
8167
  }
7972
8168
  const held = await heldInstincts();
7973
8169
  if (!held.some((instinct) => instinct.id === id)) {
7974
- throw new Error(`${PREFIX6}: no instinct ${describeValue(id)} is held under ${instinctsDir}`);
8170
+ throw new Error(`${PREFIX7}: no instinct ${describeValue(id)} is held under ${instinctsDir}`);
7975
8171
  }
7976
8172
  await appendLines(flagsPath, [JSON.stringify(flag2)]);
7977
8173
  }
@@ -7982,7 +8178,7 @@ function createLocalLearning(options) {
7982
8178
  // src/adapters/planner/claude.ts
7983
8179
  import { existsSync as existsSync10 } from "fs";
7984
8180
  import { mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
7985
- import { posix, resolve as resolve8 } from "path";
8181
+ import { posix, resolve as resolve9 } from "path";
7986
8182
 
7987
8183
  // src/board/spec-review.ts
7988
8184
  var SPEC_REVIEW_KIND = "spec-review";
@@ -8293,12 +8489,12 @@ function createClaudePlanner(options) {
8293
8489
  const create = async ({ specPath: specPath2, stub }) => {
8294
8490
  const planPath = planFilePath(planDir, `PLAN-${stub}.md`);
8295
8491
  const prerequisitesPath = planFilePath(planDir, `PREREQUISITES-${stub}.md`);
8296
- const isWritten = (path2) => existsSync10(resolve8(repoRoot, path2));
8492
+ const isWritten = (path2) => existsSync10(resolve9(repoRoot, path2));
8297
8493
  if (isWritten(planPath)) {
8298
8494
  throw new ClaudePlannerError(`${planPath} already exists`, FAILURE_EXIT_CODE);
8299
8495
  }
8300
- const specContent = await readFile2(resolve8(repoRoot, specPath2), "utf8");
8301
- await mkdir2(resolve8(repoRoot, planDir), { recursive: true });
8496
+ const specContent = await readFile2(resolve9(repoRoot, specPath2), "utf8");
8497
+ await mkdir2(resolve9(repoRoot, planDir), { recursive: true });
8302
8498
  const session = await runClaudeCaptured(buildPrompt(specContent, stub), settingSources, [], spawn);
8303
8499
  const review = parseSpecReview(session.stdout);
8304
8500
  const { exitCode } = session;
@@ -8319,8 +8515,8 @@ function createClaudePlanner(options) {
8319
8515
 
8320
8516
  // src/adapters/tracker/local.ts
8321
8517
  import { mkdir as mkdir3, readdir, readFile as readFile3, writeFile } from "fs/promises";
8322
- import { join as join16 } from "path";
8323
- var PREFIX7 = "local tracker";
8518
+ import { join as join17 } from "path";
8519
+ var PREFIX8 = "local tracker";
8324
8520
  var FRONTMATTER = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/;
8325
8521
  var ISSUE_NUMBER2 = /^[1-9]\d*$/;
8326
8522
  var ISSUE_EXTENSION = ".md";
@@ -8376,7 +8572,7 @@ function issueNumberOfFile(name2) {
8376
8572
  return name2.endsWith(ISSUE_EXTENSION) ? parseIssueNumber(name2.slice(0, -ISSUE_EXTENSION.length)) : null;
8377
8573
  }
8378
8574
  function issuePath(issuesDir, number) {
8379
- return join16(issuesDir, `${number}${ISSUE_EXTENSION}`);
8575
+ return join17(issuesDir, `${number}${ISSUE_EXTENSION}`);
8380
8576
  }
8381
8577
  async function issueNumbers(issuesDir) {
8382
8578
  let names;
@@ -8390,7 +8586,7 @@ async function issueNumbers(issuesDir) {
8390
8586
  return names.map(issueNumberOfFile).filter((number) => number !== null).sort((a, b) => a - b);
8391
8587
  }
8392
8588
  function localIssuesDir(repoRoot) {
8393
- return join16(repoRoot, ".rafa", "issues");
8589
+ return join17(repoRoot, ".rafa", "issues");
8394
8590
  }
8395
8591
  function renderLocalIssue(record) {
8396
8592
  const { draft } = record;
@@ -8409,7 +8605,7 @@ function renderLocalIssue(record) {
8409
8605
  };
8410
8606
  const problem = frontmatterProblem(frontmatter) ?? (typeof draft.body === "string" ? null : `body is ${describeValue(draft.body)}, expected a string`);
8411
8607
  if (problem !== null) {
8412
- throw new TypeError(`${PREFIX7}: refused to write an invalid issue: ${problem}`);
8608
+ throw new TypeError(`${PREFIX8}: refused to write an invalid issue: ${problem}`);
8413
8609
  }
8414
8610
  return `---
8415
8611
  ${Bun.YAML.stringify(frontmatter, null, 2)}
@@ -8420,18 +8616,18 @@ function parseLocalIssue(contents, sourcePath) {
8420
8616
  const at = sourcePath === undefined ? "" : ` at ${sourcePath}`;
8421
8617
  const match = FRONTMATTER.exec(contents);
8422
8618
  if (match === null) {
8423
- throw new Error(`${PREFIX7}: the issue${at} has no YAML frontmatter block`);
8619
+ throw new Error(`${PREFIX8}: the issue${at} has no YAML frontmatter block`);
8424
8620
  }
8425
8621
  const [, block2 = "", body = ""] = match;
8426
8622
  let meta;
8427
8623
  try {
8428
8624
  meta = Bun.YAML.parse(block2);
8429
8625
  } catch (error) {
8430
- throw new Error(`${PREFIX7}: invalid issue${at}: ${messageOf(error)}`, { cause: error });
8626
+ throw new Error(`${PREFIX8}: invalid issue${at}: ${messageOf(error)}`, { cause: error });
8431
8627
  }
8432
8628
  const problem = frontmatterProblem(meta);
8433
8629
  if (problem !== null) {
8434
- throw new Error(`${PREFIX7}: invalid issue${at}: ${problem}`);
8630
+ throw new Error(`${PREFIX8}: invalid issue${at}: ${problem}`);
8435
8631
  }
8436
8632
  const fields = meta;
8437
8633
  return {
@@ -8462,7 +8658,7 @@ async function listLocalIssues(issuesDir, warn = warnThroughActiveOutput3) {
8462
8658
  try {
8463
8659
  contents = await readFile3(path2, "utf8");
8464
8660
  } catch (error) {
8465
- throw new Error(`${PREFIX7}: could not read ${path2}: ${messageOf(error)}`, { cause: error });
8661
+ throw new Error(`${PREFIX8}: could not read ${path2}: ${messageOf(error)}`, { cause: error });
8466
8662
  }
8467
8663
  return { number, path: path2, record: parseLocalIssue(contents, path2) };
8468
8664
  }));
@@ -8491,11 +8687,11 @@ function refFor(number, opt) {
8491
8687
  }
8492
8688
  function issueNumberOfRef2(ref) {
8493
8689
  if (ref.kind !== "local") {
8494
- throw new Error(`${PREFIX7}: refused a ref of kind ${describeValue(ref.kind)}; this tracker reads local refs only`);
8690
+ throw new Error(`${PREFIX8}: refused a ref of kind ${describeValue(ref.kind)}; this tracker reads local refs only`);
8495
8691
  }
8496
8692
  const number = typeof ref.externalId === "string" ? parseIssueNumber(ref.externalId) : null;
8497
8693
  if (number === null) {
8498
- throw new Error(`${PREFIX7}: externalId ${describeValue(ref.externalId)} is not a local issue number,` + " expected a positive whole number with no leading zero");
8694
+ throw new Error(`${PREFIX8}: externalId ${describeValue(ref.externalId)} is not a local issue number,` + " expected a positive whole number with no leading zero");
8499
8695
  }
8500
8696
  return number;
8501
8697
  }
@@ -8510,7 +8706,7 @@ function createLocalTracker(options) {
8510
8706
  try {
8511
8707
  contents = await readFile3(path2, "utf8");
8512
8708
  } catch (cause) {
8513
- throw new Error(`${PREFIX7}: no issue ${number} under ${issuesDir}`, { cause });
8709
+ throw new Error(`${PREFIX8}: no issue ${number} under ${issuesDir}`, { cause });
8514
8710
  }
8515
8711
  return { number, record: parseLocalIssue(contents, path2) };
8516
8712
  }
@@ -8545,7 +8741,7 @@ function createLocalTracker(options) {
8545
8741
  throw error;
8546
8742
  }
8547
8743
  }
8548
- throw new Error(`${PREFIX7}: no issue number is left under ${issuesDir}`);
8744
+ throw new Error(`${PREFIX8}: no issue number is left under ${issuesDir}`);
8549
8745
  },
8550
8746
  get: async (ref) => {
8551
8747
  const { record } = await read(ref);
@@ -8728,20 +8924,20 @@ function projectLogDirName(repoRoot) {
8728
8924
  return repoRoot.replace(LOG_DIR_SEPARATORS, "-");
8729
8925
  }
8730
8926
  function sessionLogDir(repoRoot, home = homedir2()) {
8731
- return join17(home, ...PROJECT_LOG_ROOT, projectLogDirName(repoRoot));
8927
+ return join18(home, ...PROJECT_LOG_ROOT, projectLogDirName(repoRoot));
8732
8928
  }
8733
8929
  function listSessionLogs(dir) {
8734
8930
  if (!existsSync11(dir)) {
8735
8931
  throw new Error(`effort collect: no session log directory at ${dir}` + " (pass logDir, or run with --no-sessions)");
8736
8932
  }
8737
8933
  const candidates = [];
8738
- for (const entry of readdirSync2(dir, { withFileTypes: true })) {
8934
+ for (const entry of readdirSync3(dir, { withFileTypes: true })) {
8739
8935
  if (!entry.isFile())
8740
8936
  continue;
8741
8937
  if (!SESSION_LOG_NAME.test(entry.name))
8742
8938
  continue;
8743
- const path2 = join17(dir, entry.name);
8744
- const stats = statSync7(path2);
8939
+ const path2 = join18(dir, entry.name);
8940
+ const stats = statSync8(path2);
8745
8941
  candidates.push({
8746
8942
  path: path2,
8747
8943
  sessionId: sessionIdFromPath(path2),
@@ -8839,7 +9035,7 @@ function parseCollectArgs(args) {
8839
9035
  };
8840
9036
  }
8841
9037
  function readPlanStubs(plansDir) {
8842
- return existsSync11(plansDir) ? planStubsFromFileNames(readdirSync2(plansDir)) : [];
9038
+ return existsSync11(plansDir) ? planStubsFromFileNames(readdirSync3(plansDir)) : [];
8843
9039
  }
8844
9040
  async function collectSessionRow(candidate, planStubs) {
8845
9041
  const enqueue = await findFirstEnqueue(readLines2(candidate.path));
@@ -8920,7 +9116,7 @@ function resolveSources(options, log) {
8920
9116
  if (store !== undefined && plansDir !== undefined)
8921
9117
  return { store, plansDir };
8922
9118
  const { config } = loadConfig({ root, home: options.home }, {}, log);
8923
- return { store: store ?? selectEffortStore(root, config), plansDir: plansDir ?? resolve9(root, config.planDir) };
9119
+ return { store: store ?? selectEffortStore(root, config), plansDir: plansDir ?? resolve10(root, config.planDir) };
8924
9120
  }
8925
9121
  async function collectEffort(options) {
8926
9122
  const { repoRoot } = options;
@@ -10048,15 +10244,15 @@ var report_default = wrapPhaseZeroCommand({
10048
10244
  // src/commands/init.ts
10049
10245
  import { existsSync as existsSync17, readFileSync as readFileSync16 } from "fs";
10050
10246
  import { homedir as homedir4 } from "os";
10051
- import { join as join22, relative as relative2, sep as sep3 } from "path";
10247
+ import { join as join23, relative as relative2, sep as sep3 } from "path";
10052
10248
 
10053
10249
  // src/agents/vendorable.ts
10054
- import { readdirSync as readdirSync3, readFileSync as readFileSync12 } from "fs";
10055
- import { isAbsolute as isAbsolute5, join as join18 } from "path";
10250
+ import { readdirSync as readdirSync4, readFileSync as readFileSync12 } from "fs";
10251
+ import { isAbsolute as isAbsolute5, join as join19 } from "path";
10056
10252
  function planFiles(dir) {
10057
10253
  let entries;
10058
10254
  try {
10059
- entries = readdirSync3(dir, { withFileTypes: true });
10255
+ entries = readdirSync4(dir, { withFileTypes: true });
10060
10256
  } catch {
10061
10257
  return [];
10062
10258
  }
@@ -10070,11 +10266,11 @@ function readText3(path2) {
10070
10266
  }
10071
10267
  }
10072
10268
  function vendorableAgents(scan) {
10073
- const dir = isAbsolute5(scan.planDir) ? scan.planDir : join18(scan.repoRoot, scan.planDir);
10269
+ const dir = isAbsolute5(scan.planDir) ? scan.planDir : join19(scan.repoRoot, scan.planDir);
10074
10270
  const roster = resolveAgentRoster({ repoRoot: scan.repoRoot, home: scan.home }, scan.settingSources);
10075
10271
  const found = [];
10076
10272
  for (const file of planFiles(dir)) {
10077
- const path2 = join18(dir, file);
10273
+ const path2 = join19(dir, file);
10078
10274
  const markdown = readText3(path2);
10079
10275
  if (markdown === null)
10080
10276
  continue;
@@ -10100,12 +10296,12 @@ function vendorableAgentWarnings(agents, root) {
10100
10296
 
10101
10297
  // src/project/gitignore.ts
10102
10298
  import { createHash } from "crypto";
10103
- import { existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync5 } from "fs";
10104
- import { dirname as dirname8, isAbsolute as isAbsolute6, join as join19 } from "path";
10299
+ import { existsSync as existsSync15, mkdirSync as mkdirSync8, readFileSync as readFileSync13, writeFileSync as writeFileSync5 } from "fs";
10300
+ import { dirname as dirname8, isAbsolute as isAbsolute6, join as join20 } from "path";
10105
10301
  var GITIGNORE_FILE = ".gitignore";
10106
10302
  var DIGEST_NAME = "tracking.digest";
10107
10303
  var PRIVATE_TRIAGE = "triage/private";
10108
- var TRACKING_DIGEST_FILE = join19(SCOPE_DIR, DIGEST_NAME);
10304
+ var TRACKING_DIGEST_FILE = join20(SCOPE_DIR, DIGEST_NAME);
10109
10305
  var BLOCK_BEGIN = "# >>> rafa tracking: rafa rewrites the lines up to the end marker";
10110
10306
  var BLOCK_END = "# <<< rafa tracking";
10111
10307
  var SUB_PATHS = [
@@ -10193,7 +10389,7 @@ function readIfPresent3(file) {
10193
10389
  }
10194
10390
  function writeTrackingGitignore(root, flags) {
10195
10391
  requireAbsolute2(root);
10196
- const file = join19(root, GITIGNORE_FILE);
10392
+ const file = join20(root, GITIGNORE_FILE);
10197
10393
  const text2 = readIfPresent3(file);
10198
10394
  const next = withTrackingBlock(text2, flags, file);
10199
10395
  if (next === text2)
@@ -10215,7 +10411,7 @@ function trackingDigest(flags) {
10215
10411
  }
10216
10412
  function exposureNotice(root) {
10217
10413
  return [
10218
- `tracking.all is true, so ${join19(root, GITIGNORE_FILE)} no longer ignores ${SCOPE_DIR}/` + " and a commit can carry what it holds, including:",
10414
+ `tracking.all is true, so ${join20(root, GITIGNORE_FILE)} no longer ignores ${SCOPE_DIR}/` + " and a commit can carry what it holds, including:",
10219
10415
  " - unpatched issues described in specs and plans",
10220
10416
  " - effort rows with model names and token counts",
10221
10417
  " - instincts that may quote error output",
@@ -10228,7 +10424,7 @@ function printWarning2(message) {
10228
10424
  }
10229
10425
  function noticeTrackingChange(root, flags, print = printWarning2) {
10230
10426
  requireAbsolute2(root);
10231
- const digestFile = join19(root, TRACKING_DIGEST_FILE);
10427
+ const digestFile = join20(root, TRACKING_DIGEST_FILE);
10232
10428
  const recorded = `${trackingDigest(flags)}
10233
10429
  `;
10234
10430
  if (readIfPresent3(digestFile) === recorded) {
@@ -10237,7 +10433,7 @@ function noticeTrackingChange(root, flags, print = printWarning2) {
10237
10433
  if (flags.trackingAll)
10238
10434
  print(exposureNotice(root));
10239
10435
  attempt(digestFile, "cannot be written", () => {
10240
- mkdirSync7(dirname8(digestFile), { recursive: true });
10436
+ mkdirSync8(dirname8(digestFile), { recursive: true });
10241
10437
  writeFileSync5(digestFile, recorded);
10242
10438
  });
10243
10439
  return { digestFile, changed: true, printed: flags.trackingAll };
@@ -10248,13 +10444,13 @@ function applyTracking(root, flags, print = printWarning2) {
10248
10444
  }
10249
10445
 
10250
10446
  // src/project/root-choice.ts
10251
- import { resolve as resolve11 } from "path";
10447
+ import { resolve as resolve12 } from "path";
10252
10448
  import { createInterface as createInterface2 } from "readline";
10253
10449
 
10254
10450
  // src/project/roots.ts
10255
10451
  import { spawnSync as spawnSync2 } from "child_process";
10256
- import { accessSync, constants, readFileSync as readFileSync14, statSync as statSync8 } from "fs";
10257
- import { isAbsolute as isAbsolute7, join as join20, resolve as resolve10 } from "path";
10452
+ import { accessSync, constants, readFileSync as readFileSync14, statSync as statSync9 } from "fs";
10453
+ import { isAbsolute as isAbsolute7, join as join21, resolve as resolve11 } from "path";
10258
10454
  var REFUSED_ROOTS = Object.freeze([
10259
10455
  { path: "/", why: "is the filesystem root" },
10260
10456
  { path: "/var", why: "holds system state" },
@@ -10275,7 +10471,7 @@ var NOT_A_REPOSITORY = "fatal: not a git repository (or any ";
10275
10471
  var DISK_ROOTS_FILE_SYSTEM = Object.freeze({
10276
10472
  ...DISK_FILE_SYSTEM,
10277
10473
  readFile: (path2) => readFileSync14(path2, "utf8"),
10278
- isDirectory: (path2) => statSync8(path2).isDirectory(),
10474
+ isDirectory: (path2) => statSync9(path2).isDirectory(),
10279
10475
  assertWritable: (path2) => accessSync(path2, constants.W_OK)
10280
10476
  });
10281
10477
 
@@ -10317,7 +10513,7 @@ function realOrSpelled(path2, fs2) {
10317
10513
  try {
10318
10514
  return fs2.realpath(path2);
10319
10515
  } catch {
10320
- return resolve10(path2);
10516
+ return resolve11(path2);
10321
10517
  }
10322
10518
  }
10323
10519
  function namedRoots(home, fs2) {
@@ -10359,7 +10555,7 @@ function writeRefusal(given, real, fs2) {
10359
10555
  }
10360
10556
  function refusalOf(given, named, fs2) {
10361
10557
  const resolved = resolveReal(given, fs2);
10362
- const byName = namedRefusal(given, resolved.real ?? resolve10(given), named);
10558
+ const byName = namedRefusal(given, resolved.real ?? resolve11(given), named);
10363
10559
  if (byName !== null)
10364
10560
  return byName;
10365
10561
  if (resolved.real === null) {
@@ -10387,8 +10583,8 @@ function readManifest(file, fs2) {
10387
10583
  }
10388
10584
  }
10389
10585
  function readDir(dir, fs2) {
10390
- const manifest = readManifest(join20(dir, PACKAGE_JSON), fs2);
10391
- const files = MONOREPO_MARKER_FILES.filter((name2) => fs2.exists(join20(dir, name2)));
10586
+ const manifest = readManifest(join21(dir, PACKAGE_JSON), fs2);
10587
+ const files = MONOREPO_MARKER_FILES.filter((name2) => fs2.exists(join21(dir, name2)));
10392
10588
  const markers = manifest.marks ? [PACKAGE_JSON, ...files] : files;
10393
10589
  return { ...manifest, dir, markers };
10394
10590
  }
@@ -10458,7 +10654,7 @@ function firstCandidate(found) {
10458
10654
  return first.refusal === null ? chosen(first.path, first.source) : problem(first.refusal.reason);
10459
10655
  }
10460
10656
  function namedRoot(typed, start, source, seams) {
10461
- const path2 = resolve11(start, typed);
10657
+ const path2 = resolve12(start, typed);
10462
10658
  const refusal3 = rootRefusal(path2, seams);
10463
10659
  if (refusal3 !== null)
10464
10660
  return problem(refusal3.reason);
@@ -10537,8 +10733,8 @@ function createLinePrompter(input, output) {
10537
10733
  }
10538
10734
 
10539
10735
  // src/project/scaffold.ts
10540
- import { existsSync as existsSync16, lstatSync as lstatSync2, mkdirSync as mkdirSync8, statSync as statSync9, writeFileSync as writeFileSync6 } from "fs";
10541
- import { join as join21 } from "path";
10736
+ import { existsSync as existsSync16, lstatSync as lstatSync2, mkdirSync as mkdirSync9, statSync as statSync10, writeFileSync as writeFileSync6 } from "fs";
10737
+ import { join as join22 } from "path";
10542
10738
  var PROJECT_TREE = Object.freeze(["specs", "plans", "runs", "effort", "instincts"]);
10543
10739
  var USER_TREE = Object.freeze(["instincts"]);
10544
10740
  var CONFIG_SETTINGS_LINES = Object.freeze([
@@ -10617,13 +10813,13 @@ class ScaffoldError extends Error {
10617
10813
  }
10618
10814
  function layoutOf(base, tree) {
10619
10815
  const scope = scopeAt(base);
10620
- return { dirs: [scope.dir, ...tree.map((name2) => join21(scope.dir, name2))], configFile: configFilePath(base) };
10816
+ return { dirs: [scope.dir, ...tree.map((name2) => join22(scope.dir, name2))], configFile: configFilePath(base) };
10621
10817
  }
10622
10818
  function occupied(path2) {
10623
10819
  return lstatSync2(path2, { throwIfNoEntry: false }) !== undefined;
10624
10820
  }
10625
10821
  function isDirectory(path2) {
10626
- return statSync9(path2, { throwIfNoEntry: false })?.isDirectory() === true;
10822
+ return statSync10(path2, { throwIfNoEntry: false })?.isDirectory() === true;
10627
10823
  }
10628
10824
  function directoryConflict(dir) {
10629
10825
  if (!occupied(dir) || isDirectory(dir))
@@ -10653,7 +10849,7 @@ function ensureDirectory(path2) {
10653
10849
  if (existsSync16(path2))
10654
10850
  return { path: path2, kind: "directory", change: "unchanged" };
10655
10851
  attempt2(path2, "cannot be created", () => {
10656
- mkdirSync8(path2, { recursive: true });
10852
+ mkdirSync9(path2, { recursive: true });
10657
10853
  });
10658
10854
  return { path: path2, kind: "directory", change: "created" };
10659
10855
  }
@@ -10681,17 +10877,17 @@ function writeUserScope(home) {
10681
10877
  import { writeFileSync as writeFileSync7 } from "fs";
10682
10878
 
10683
10879
  // src/release/enabled.ts
10684
- import { statSync as statSync10 } from "fs";
10685
- import { resolve as resolve12 } from "path";
10880
+ import { statSync as statSync11 } from "fs";
10881
+ import { resolve as resolve13 } from "path";
10686
10882
  function isRegularFile(full) {
10687
10883
  try {
10688
- return statSync10(full).isFile();
10884
+ return statSync11(full).isFile();
10689
10885
  } catch {
10690
10886
  return false;
10691
10887
  }
10692
10888
  }
10693
10889
  function readFile4(repoRoot, path2) {
10694
- const resolved = resolve12(repoRoot, path2);
10890
+ const resolved = resolve13(repoRoot, path2);
10695
10891
  return { path: path2, resolved, present: isRegularFile(resolved) };
10696
10892
  }
10697
10893
  function resolveReleaseEnabled(settings, repoRoot) {
@@ -10992,7 +11188,7 @@ function resolvedConfig4(root, home, warn) {
10992
11188
  }
10993
11189
  }
10994
11190
  function checkGitignore(root, flags) {
10995
- const file = join22(root, GITIGNORE_FILE);
11191
+ const file = join23(root, GITIGNORE_FILE);
10996
11192
  try {
10997
11193
  const text2 = existsSync17(file) ? readFileSync16(file, "utf8") : null;
10998
11194
  withTrackingBlock(text2, flags, file);
@@ -11026,7 +11222,7 @@ function initialise(root, start, home, context) {
11026
11222
  const config = resolvedConfig4(root.path, home, warn);
11027
11223
  checkGitignore(root.path, config);
11028
11224
  const configExisted = existsSync17(configFilePath(root.path));
11029
- const digestExisted = existsSync17(join22(root.path, TRACKING_DIGEST_FILE));
11225
+ const digestExisted = existsSync17(join23(root.path, TRACKING_DIGEST_FILE));
11030
11226
  const project = writeProjectScope(root.path);
11031
11227
  const tracking = applyTracking(root.path, config, warn);
11032
11228
  const writes = [...project, ...trackingWrites(tracking, digestExisted), ...writeUserScope(home)];
@@ -11179,11 +11375,11 @@ function createInitCommand(seams = DEFAULT_INIT_SEAMS) {
11179
11375
  var init_default = createInitCommand();
11180
11376
 
11181
11377
  // src/commands/check-report.ts
11182
- import { resolve as resolve14 } from "path";
11378
+ import { resolve as resolve15 } from "path";
11183
11379
 
11184
11380
  // src/check/references.ts
11185
- import { existsSync as existsSync18, statSync as statSync11 } from "fs";
11186
- import { delimiter as delimiter2, isAbsolute as isAbsolute8, relative as relative3, resolve as resolve13 } from "path";
11381
+ import { existsSync as existsSync18, statSync as statSync12 } from "fs";
11382
+ import { delimiter as delimiter2, isAbsolute as isAbsolute8, relative as relative3, resolve as resolve14 } from "path";
11187
11383
 
11188
11384
  // src/schema/stack.ts
11189
11385
  var LANGUAGE_EXTENSIONS = {
@@ -11626,12 +11822,12 @@ function isAbsoluteReference(token) {
11626
11822
  return KNOWN_ROOTS.includes(`/${first}`) || EXTENSION.test(token);
11627
11823
  }
11628
11824
  function isInside(root, target) {
11629
- const step = relative3(resolve13(root), resolve13(target));
11825
+ const step = relative3(resolve14(root), resolve14(target));
11630
11826
  return step !== "" && !step.startsWith("..") && !isAbsolute8(step);
11631
11827
  }
11632
11828
  function isExecutableFile(path2) {
11633
11829
  try {
11634
- const stats = statSync11(path2);
11830
+ const stats = statSync12(path2);
11635
11831
  return stats.isFile() && (stats.mode & 73) !== 0;
11636
11832
  } catch {
11637
11833
  return false;
@@ -11751,21 +11947,21 @@ function issueOf2(code, ref, sentence) {
11751
11947
  };
11752
11948
  }
11753
11949
  function scriptIssue(ref, skillDir) {
11754
- if (existsSync18(resolve13(skillDir, ref.text)))
11950
+ if (existsSync18(resolve14(skillDir, ref.text)))
11755
11951
  return null;
11756
11952
  return issueOf2("missing-script", ref, `${ref.text} names nothing under the skill directory`);
11757
11953
  }
11758
11954
  function isSkillPath(token, skillDir) {
11759
- const target = resolve13(skillDir, token);
11955
+ const target = resolve14(skillDir, token);
11760
11956
  if (!isInside(skillDir, target))
11761
11957
  return false;
11762
11958
  if (existsSync18(target))
11763
11959
  return true;
11764
11960
  const head = token.split("/")[0] ?? "";
11765
- return head !== "" && head !== "." && head !== ".." && existsSync18(resolve13(skillDir, head));
11961
+ return head !== "" && head !== "." && head !== ".." && existsSync18(resolve14(skillDir, head));
11766
11962
  }
11767
11963
  function projectPathIssue(ref, projectRoot) {
11768
- const target = resolve13(projectRoot, ref.text);
11964
+ const target = resolve14(projectRoot, ref.text);
11769
11965
  if (!isInside(projectRoot, target)) {
11770
11966
  return issueOf2("unresolved-path", ref, `${ref.text} points outside the project root`);
11771
11967
  }
@@ -11809,7 +12005,7 @@ function isOffStack(stack) {
11809
12005
  function toolIssue(ref, pathDirs, functions, offStack) {
11810
12006
  if (functions.has(ref.text))
11811
12007
  return null;
11812
- if (pathDirs.some((dir) => isExecutableFile(resolve13(dir, ref.text))))
12008
+ if (pathDirs.some((dir) => isExecutableFile(resolve14(dir, ref.text))))
11813
12009
  return null;
11814
12010
  if (offStack) {
11815
12011
  return issueOf2("missing-tool-off-stack", ref, `the command ${ref.text} is in no directory of the PATH this run was given,` + " and this file declares a stack this machine need not carry");
@@ -11843,7 +12039,7 @@ function checkReferences(body, seams) {
11843
12039
 
11844
12040
  // src/check/run.ts
11845
12041
  import { readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "fs";
11846
- import { basename as basename7, dirname as dirname9 } from "path";
12042
+ import { basename as basename8, dirname as dirname9 } from "path";
11847
12043
 
11848
12044
  // src/schema/instinct.ts
11849
12045
  import { createHash as createHash2 } from "crypto";
@@ -12370,8 +12566,8 @@ function checkSkillFrontmatter(data) {
12370
12566
  }
12371
12567
 
12372
12568
  // src/check/layout.ts
12373
- import { readdirSync as readdirSync4, statSync as statSync12 } from "fs";
12374
- import { join as join23, relative as relative4 } from "path";
12569
+ import { readdirSync as readdirSync5, statSync as statSync13 } from "fs";
12570
+ import { join as join24, relative as relative4 } from "path";
12375
12571
  var SKILL_FILE = "SKILL.md";
12376
12572
  var MARKDOWN_EXTENSION = ".md";
12377
12573
  var LAYOUT_SEVERITY = Object.freeze({
@@ -12389,7 +12585,7 @@ function layoutIssue(code, message) {
12389
12585
  }
12390
12586
  function entryKind(path2) {
12391
12587
  try {
12392
- const stats = statSync12(path2);
12588
+ const stats = statSync13(path2);
12393
12589
  if (stats.isFile())
12394
12590
  return "file";
12395
12591
  if (stats.isDirectory())
@@ -12400,7 +12596,7 @@ function entryKind(path2) {
12400
12596
  }
12401
12597
  }
12402
12598
  function visibleNames(dir) {
12403
- return readdirSync4(dir).filter((name2) => !name2.startsWith(".")).sort((left, right) => left.localeCompare(right));
12599
+ return readdirSync5(dir).filter((name2) => !name2.startsWith(".")).sort((left, right) => left.localeCompare(right));
12404
12600
  }
12405
12601
  function isMarkdown(name2) {
12406
12602
  return name2.endsWith(MARKDOWN_EXTENSION);
@@ -12488,7 +12684,7 @@ function scanGroupMember(root, dir, name2) {
12488
12684
  const children = visibleNames(dir);
12489
12685
  if (children.length === 0)
12490
12686
  return [dotfileOnlyEntry("skill", root, dir)];
12491
- const skillPath = join23(dir, SKILL_FILE);
12687
+ const skillPath = join24(dir, SKILL_FILE);
12492
12688
  if (children.includes(SKILL_FILE) && entryKind(skillPath) === "file") {
12493
12689
  return [nestedGroupEntry(root, skillPath, name2)];
12494
12690
  }
@@ -12497,7 +12693,7 @@ function scanGroupMember(root, dir, name2) {
12497
12693
  function scanSkillGroup(root, dir, children) {
12498
12694
  const entries = [];
12499
12695
  for (const child of children) {
12500
- const path2 = join23(dir, child);
12696
+ const path2 = join24(dir, child);
12501
12697
  const found = entryKind(path2);
12502
12698
  if (found === null) {
12503
12699
  entries.push(unreadableEntry("skill", root, path2));
@@ -12518,7 +12714,7 @@ function scanSkillDirectory(root, dir, name2) {
12518
12714
  const children = visibleNames(dir);
12519
12715
  if (children.length === 0)
12520
12716
  return [dotfileOnlyEntry("skill", root, dir)];
12521
- const skillPath = join23(dir, SKILL_FILE);
12717
+ const skillPath = join24(dir, SKILL_FILE);
12522
12718
  if (children.includes(SKILL_FILE) && entryKind(skillPath) === "file") {
12523
12719
  return [skillFileEntry(skillPath, name2)];
12524
12720
  }
@@ -12527,7 +12723,7 @@ function scanSkillDirectory(root, dir, name2) {
12527
12723
  function scanSkillRoot(root) {
12528
12724
  const entries = [];
12529
12725
  for (const name2 of visibleNames(root)) {
12530
- const path2 = join23(root, name2);
12726
+ const path2 = join24(root, name2);
12531
12727
  const found = entryKind(path2);
12532
12728
  if (found === null) {
12533
12729
  entries.push(unreadableEntry("skill", root, path2));
@@ -12548,7 +12744,7 @@ function scanInstinctSubdirectory(root, dir) {
12548
12744
  return [dotfileOnlyEntry("instinct", root, dir)];
12549
12745
  const entries = [];
12550
12746
  for (const child of children) {
12551
- const path2 = join23(dir, child);
12747
+ const path2 = join24(dir, child);
12552
12748
  const found = entryKind(path2);
12553
12749
  if (found === null) {
12554
12750
  entries.push(unreadableEntry("instinct", root, path2));
@@ -12566,7 +12762,7 @@ function scanInstinctSubdirectory(root, dir) {
12566
12762
  function scanInstinctRoot(root) {
12567
12763
  const entries = [];
12568
12764
  for (const name2 of visibleNames(root)) {
12569
- const path2 = join23(root, name2);
12765
+ const path2 = join24(root, name2);
12570
12766
  const found = entryKind(path2);
12571
12767
  if (found === null) {
12572
12768
  entries.push(unreadableEntry("instinct", root, path2));
@@ -12672,7 +12868,7 @@ function isMarkdown2(name2) {
12672
12868
  return name2.endsWith(MARKDOWN_EXTENSION);
12673
12869
  }
12674
12870
  function fileEntry(path2, kind) {
12675
- const base = basename7(path2);
12871
+ const base = basename8(path2);
12676
12872
  const stem = isMarkdown2(base) ? base.slice(0, -MARKDOWN_EXTENSION.length) : base;
12677
12873
  if (kind === "instinct") {
12678
12874
  return {
@@ -12684,10 +12880,10 @@ function fileEntry(path2, kind) {
12684
12880
  issues: []
12685
12881
  };
12686
12882
  }
12687
- return base === SKILL_FILE ? { kind, path: path2, isFile: true, shape: "skill-file", name: basename7(dirname9(path2)), issues: [] } : { kind, path: path2, isFile: true, shape: "loose-file", name: stem, issues: [] };
12883
+ return base === SKILL_FILE ? { kind, path: path2, isFile: true, shape: "skill-file", name: basename8(dirname9(path2)), issues: [] } : { kind, path: path2, isFile: true, shape: "loose-file", name: stem, issues: [] };
12688
12884
  }
12689
12885
  function unregisteredIssue(path2, kind) {
12690
- const base = basename7(path2);
12886
+ const base = basename8(path2);
12691
12887
  if (kind === "instinct") {
12692
12888
  return isMarkdown2(base) ? null : checkerIssue("layout", "unregistered-path", `${base} is not a ${MARKDOWN_EXTENSION} file, so it is no instinct record`);
12693
12889
  }
@@ -12696,7 +12892,7 @@ function unregisteredIssue(path2, kind) {
12696
12892
  function skillDirectoryOf(entry) {
12697
12893
  if (entry.kind !== "skill" || !entry.isFile)
12698
12894
  return null;
12699
- return basename7(entry.path) === SKILL_FILE ? dirname9(entry.path) : null;
12895
+ return basename8(entry.path) === SKILL_FILE ? dirname9(entry.path) : null;
12700
12896
  }
12701
12897
  function declaredStack(data) {
12702
12898
  const value = data["stack"];
@@ -12857,7 +13053,7 @@ Usage: ${usage}`);
12857
13053
  throw new CommandExit(1, `\u274C Expected one directory, and read "${extra}" as a second
12858
13054
  Usage: ${usage}`);
12859
13055
  }
12860
- return resolve14(cwd(), dir);
13056
+ return resolve15(cwd(), dir);
12861
13057
  }
12862
13058
  function readFix(value, usage) {
12863
13059
  if (value === undefined || value === false || value === "false")
@@ -12874,7 +13070,7 @@ function readProjectRoot(value, usage, cwd) {
12874
13070
  throw new CommandExit(1, `\u274C --project needs a path, and the line gave it none
12875
13071
  Usage: ${usage}`);
12876
13072
  }
12877
- return resolve14(cwd(), value);
13073
+ return resolve15(cwd(), value);
12878
13074
  }
12879
13075
  function reportMarker(report2) {
12880
13076
  if (report2.failed)
@@ -12987,16 +13183,16 @@ function createInstinctCheckCommand(seams = DEFAULT_CHECK_SEAMS) {
12987
13183
  var check_default = createInstinctCheckCommand();
12988
13184
 
12989
13185
  // src/commands/instinct/instinct-records.ts
12990
- import { readdirSync as readdirSync5, readFileSync as readFileSync18, statSync as statSync13 } from "fs";
12991
- import { join as join25 } from "path";
13186
+ import { readdirSync as readdirSync6, readFileSync as readFileSync18, statSync as statSync14 } from "fs";
13187
+ import { join as join26 } from "path";
12992
13188
 
12993
13189
  // src/schema/tiers.ts
12994
13190
  import { existsSync as existsSync19, realpathSync as realpathSync3 } from "fs";
12995
- import { dirname as dirname10, join as join24 } from "path";
13191
+ import { dirname as dirname10, join as join25 } from "path";
12996
13192
  var SKILL_TIERS = ["project", "rafa", "user"];
12997
13193
  var INSTINCT_SCOPES2 = ["project", "user"];
12998
- var CLAUDE_SKILLS_PATH = join24(".claude", "skills");
12999
- var RAFA_INSTINCTS_PATH = join24(".rafa", "instincts");
13194
+ var CLAUDE_SKILLS_PATH = join25(".claude", "skills");
13195
+ var RAFA_INSTINCTS_PATH = join25(".rafa", "instincts");
13000
13196
  var BUNDLED_SKILLS_DIR = "skills";
13001
13197
  function isSkillTier(value) {
13002
13198
  return SKILL_TIERS.includes(value);
@@ -13009,14 +13205,14 @@ function realEntry(entry) {
13009
13205
  }
13010
13206
  }
13011
13207
  function bundledSkillsDirectory(entry) {
13012
- return join24(dirname10(realEntry(entry ?? Bun.main)), BUNDLED_SKILLS_DIR);
13208
+ return join25(dirname10(realEntry(entry ?? Bun.main)), BUNDLED_SKILLS_DIR);
13013
13209
  }
13014
13210
  function skillTierDirectory(tier, seams) {
13015
13211
  if (tier === "user")
13016
- return join24(seams.home, CLAUDE_SKILLS_PATH);
13212
+ return join25(seams.home, CLAUDE_SKILLS_PATH);
13017
13213
  if (tier === "rafa")
13018
13214
  return bundledSkillsDirectory(seams.entry);
13019
- return seams.projectRoot === null ? null : join24(seams.projectRoot, CLAUDE_SKILLS_PATH);
13215
+ return seams.projectRoot === null ? null : join25(seams.projectRoot, CLAUDE_SKILLS_PATH);
13020
13216
  }
13021
13217
  function resolveSkillTiers(seams) {
13022
13218
  const located = [];
@@ -13029,8 +13225,8 @@ function resolveSkillTiers(seams) {
13029
13225
  }
13030
13226
  function instinctScopeDirectory(scope, seams) {
13031
13227
  if (scope === "user")
13032
- return join24(seams.home, RAFA_INSTINCTS_PATH);
13033
- return seams.projectRoot === null ? null : join24(seams.projectRoot, RAFA_INSTINCTS_PATH);
13228
+ return join25(seams.home, RAFA_INSTINCTS_PATH);
13229
+ return seams.projectRoot === null ? null : join25(seams.projectRoot, RAFA_INSTINCTS_PATH);
13034
13230
  }
13035
13231
  function resolveInstinctScopes(seams) {
13036
13232
  const located = [];
@@ -13068,13 +13264,13 @@ function readRecord(path2, scope, id) {
13068
13264
  }
13069
13265
  function isFile2(path2) {
13070
13266
  try {
13071
- return statSync13(path2).isFile();
13267
+ return statSync14(path2).isFile();
13072
13268
  } catch {
13073
13269
  return false;
13074
13270
  }
13075
13271
  }
13076
13272
  function recordFiles(dir) {
13077
- return readdirSync5(dir).filter((name2) => isRecordFile(name2) && isFile2(join25(dir, name2))).sort((left, right) => left.localeCompare(right));
13273
+ return readdirSync6(dir).filter((name2) => isRecordFile(name2) && isFile2(join26(dir, name2))).sort((left, right) => left.localeCompare(right));
13078
13274
  }
13079
13275
  function readScope(scope, dir) {
13080
13276
  if (!tierExists(dir))
@@ -13083,7 +13279,7 @@ function readScope(scope, dir) {
13083
13279
  scope,
13084
13280
  dir,
13085
13281
  exists: true,
13086
- records: recordFiles(dir).map((name2) => readRecord(join25(dir, name2), scope, recordId(name2)))
13282
+ records: recordFiles(dir).map((name2) => readRecord(join26(dir, name2), scope, recordId(name2)))
13087
13283
  };
13088
13284
  }
13089
13285
  function readScopes(seams) {
@@ -13310,7 +13506,7 @@ function createInstinctShowCommand() {
13310
13506
  var show_default = createInstinctShowCommand();
13311
13507
 
13312
13508
  // src/adapters/tracker/resolve.ts
13313
- var PREFIX8 = "tracker chain";
13509
+ var PREFIX9 = "tracker chain";
13314
13510
  var FAILURE_SEPARATOR = "; ";
13315
13511
  function warnThroughActiveOutput4(message) {
13316
13512
  activeOutput().warn(message);
@@ -13351,9 +13547,9 @@ async function resolveTracker(options) {
13351
13547
  }
13352
13548
  attempts = [...attempts, Object.freeze({ kind, ok: false, reason: outcome.reason })];
13353
13549
  failures = [...failures, `${kind}: ${outcome.reason}`];
13354
- log(`${PREFIX8}: ${kind} unavailable: ${outcome.reason}`);
13550
+ log(`${PREFIX9}: ${kind} unavailable: ${outcome.reason}`);
13355
13551
  }
13356
- throw new Error(`${PREFIX8}: no tracker available; tried ${failures.join(FAILURE_SEPARATOR)}`);
13552
+ throw new Error(`${PREFIX9}: no tracker available; tried ${failures.join(FAILURE_SEPARATOR)}`);
13357
13553
  }
13358
13554
 
13359
13555
  // src/commands/issue/issue-tracker.ts
@@ -13507,7 +13703,7 @@ function createIssueCommentCommand(seams = DEFAULT_ISSUE_SEAMS) {
13507
13703
  var comment_default = createIssueCommentCommand();
13508
13704
 
13509
13705
  // src/triage/triage.ts
13510
- import { basename as basename8, join as join26 } from "path";
13706
+ import { basename as basename9, join as join27 } from "path";
13511
13707
 
13512
13708
  // src/effort/store/tracker-refs.ts
13513
13709
  import { randomUUID as randomUUID3 } from "crypto";
@@ -13712,7 +13908,7 @@ function machineFaultSentence(fault) {
13712
13908
  }
13713
13909
 
13714
13910
  // src/triage/triage.ts
13715
- var PRIVATE_TRIAGE_DIR = join26(".rafa", "triage", "private");
13911
+ var PRIVATE_TRIAGE_DIR = join27(".rafa", "triage", "private");
13716
13912
  var SECRET_ENV_NAMES = ["GITHUB_TOKEN", "ANTHROPIC_API_KEY", "LINEAR_API_KEY"];
13717
13913
  var TRIAGE_MODULE = "unassigned";
13718
13914
  var BLOCKER_SEPARATOR = "; ";
@@ -13723,7 +13919,7 @@ var MIN_FENCE_LENGTH = 3;
13723
13919
  var ISSUE_OPENING = "An out-of-scope bug a rafa task session reported. The loop filed it and" + " dispatches no task for it: a plan that wants it fixed declares a task.";
13724
13920
  var COMMENT_OPENING = "Reported again by a rafa task session.";
13725
13921
  function privateTriageDir(repoRoot) {
13726
- return join26(repoRoot, PRIVATE_TRIAGE_DIR);
13922
+ return join27(repoRoot, PRIVATE_TRIAGE_DIR);
13727
13923
  }
13728
13924
  function createPrivateTriageTracker(repoRoot, options = {}) {
13729
13925
  return createLocalTracker({
@@ -13786,7 +13982,7 @@ function oneLine3(text2) {
13786
13982
  return text2.replace(/\s+/g, " ").trim();
13787
13983
  }
13788
13984
  function bugKeyOf(trackerPath, artifact) {
13789
- return `${basename8(trackerPath)}${KEY_SEPARATOR}${oneLine3(artifact)}`;
13985
+ return `${basename9(trackerPath)}${KEY_SEPARATOR}${oneLine3(artifact)}`;
13790
13986
  }
13791
13987
  function fenced(value) {
13792
13988
  const runs = Array.from(value.matchAll(/`+/g), (run) => run[0].length);
@@ -14225,7 +14421,7 @@ function createIssueMoveCommand(seams = DEFAULT_ISSUE_SEAMS) {
14225
14421
  var move_default = createIssueMoveCommand();
14226
14422
 
14227
14423
  // src/board/issue-board.ts
14228
- var PREFIX9 = "board issue";
14424
+ var PREFIX10 = "board issue";
14229
14425
  var REPO_PATH2 = "{owner}/{repo}";
14230
14426
  var COMMENT_ID = /^[1-9]\d*$/;
14231
14427
  function detailOf7(result, command) {
@@ -14233,29 +14429,29 @@ function detailOf7(result, command) {
14233
14429
  return written === "" ? `${command} failed and wrote nothing` : `${command} failed: ${written}`;
14234
14430
  }
14235
14431
  function failure2(command, result) {
14236
- return new Error(`${PREFIX9}: ${detailOf7(result, command)}`);
14432
+ return new Error(`${PREFIX10}: ${detailOf7(result, command)}`);
14237
14433
  }
14238
14434
  function issueNumber3(value, member) {
14239
14435
  if (!Number.isSafeInteger(value) || value < 1) {
14240
- throw new TypeError(`${PREFIX9}: ${member} refused issue number ${describeValue(value)}, expected a positive whole number`);
14436
+ throw new TypeError(`${PREFIX10}: ${member} refused issue number ${describeValue(value)}, expected a positive whole number`);
14241
14437
  }
14242
14438
  return String(value);
14243
14439
  }
14244
14440
  function commentId(value) {
14245
14441
  if (typeof value !== "string" || !COMMENT_ID.test(value)) {
14246
- throw new TypeError(`${PREFIX9}: editComment refused comment id ${describeValue(value)},` + " expected a positive whole number with no leading zero");
14442
+ throw new TypeError(`${PREFIX10}: editComment refused comment id ${describeValue(value)},` + " expected a positive whole number with no leading zero");
14247
14443
  }
14248
14444
  return value;
14249
14445
  }
14250
14446
  function commentBody2(value, member) {
14251
14447
  if (typeof value !== "string") {
14252
- throw new TypeError(`${PREFIX9}: ${member} refused a body ${describeValue(value)}, expected a string`);
14448
+ throw new TypeError(`${PREFIX10}: ${member} refused a body ${describeValue(value)}, expected a string`);
14253
14449
  }
14254
14450
  return value;
14255
14451
  }
14256
14452
  function labelName(value, member, what) {
14257
14453
  if (typeof value !== "string" || value === "" || value.startsWith("-")) {
14258
- throw new TypeError(`${PREFIX9}: ${member} refused ${what} ${describeValue(value)},` + " expected a non-empty name that does not open with a hyphen");
14454
+ throw new TypeError(`${PREFIX10}: ${member} refused ${what} ${describeValue(value)},` + " expected a non-empty name that does not open with a hyphen");
14259
14455
  }
14260
14456
  return value;
14261
14457
  }
@@ -14263,20 +14459,20 @@ function parseJson2(stdout, command) {
14263
14459
  try {
14264
14460
  return JSON.parse(stdout);
14265
14461
  } catch (error) {
14266
- throw new Error(`${PREFIX9}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
14462
+ throw new Error(`${PREFIX10}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
14267
14463
  }
14268
14464
  }
14269
14465
  function readComment(value, command, where) {
14270
14466
  if (!isMapping(value)) {
14271
- throw new Error(`${PREFIX9}: ${command} answered ${where} as ${describeValue(value)}, expected a mapping`);
14467
+ throw new Error(`${PREFIX10}: ${command} answered ${where} as ${describeValue(value)}, expected a mapping`);
14272
14468
  }
14273
14469
  const id = value["id"];
14274
14470
  if (typeof id !== "number" || !Number.isSafeInteger(id) || id < 1) {
14275
- throw new Error(`${PREFIX9}: ${command} answered ${where}.id as ${describeValue(id)}, expected a positive whole number`);
14471
+ throw new Error(`${PREFIX10}: ${command} answered ${where}.id as ${describeValue(id)}, expected a positive whole number`);
14276
14472
  }
14277
14473
  const body = value["body"];
14278
14474
  if (typeof body !== "string") {
14279
- throw new Error(`${PREFIX9}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
14475
+ throw new Error(`${PREFIX10}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
14280
14476
  }
14281
14477
  const user = value["user"];
14282
14478
  const login = isMapping(user) ? user["login"] : null;
@@ -14301,7 +14497,7 @@ function createGhIssueBoard(options) {
14301
14497
  const command = `gh api ${path2}`;
14302
14498
  const rows2 = parseJson2(await succeed(["api", path2], command), command);
14303
14499
  if (!Array.isArray(rows2)) {
14304
- throw new Error(`${PREFIX9}: ${command} answered ${describeValue(rows2)}, expected a list of comments`);
14500
+ throw new Error(`${PREFIX10}: ${command} answered ${describeValue(rows2)}, expected a list of comments`);
14305
14501
  }
14306
14502
  return rows2.map((row2, index) => readComment(row2, command, `comment ${String(index)}`));
14307
14503
  },
@@ -14546,8 +14742,74 @@ function declinedMessage(alternative) {
14546
14742
  return `#${String(alternative)} was not planned, and nothing was written`;
14547
14743
  }
14548
14744
 
14745
+ // src/board/snapshot-settle.ts
14746
+ import { existsSync as existsSync21, readFileSync as readFileSync19, statSync as statSync15 } from "fs";
14747
+ import { resolve as resolve16 } from "path";
14748
+ var PREFIX11 = "board snapshot settle";
14749
+ var DATE_LENGTH = 10;
14750
+ function savedCopyDate(savedAt) {
14751
+ return savedAt.toISOString().slice(0, DATE_LENGTH);
14752
+ }
14753
+ function refreshQuestion(issue3, savedAt) {
14754
+ return `Issue #${String(issue3)} changed since the saved copy of ${savedCopyDate(savedAt)}.` + " Plan from it as it reads now? [y/N] ";
14755
+ }
14756
+ function notesRebuiltLine(path2, issue3, previous) {
14757
+ return `local notes changed; rebuilt ${path2} from issue #${String(issue3)} and the notes,` + ` the old copy is at ${previous}`;
14758
+ }
14759
+ function readSavedCopy(absolute, path2) {
14760
+ if (!existsSync21(absolute))
14761
+ return null;
14762
+ try {
14763
+ const stat = statSync15(absolute);
14764
+ if (!stat.isFile())
14765
+ return null;
14766
+ return { text: readFileSync19(absolute, "utf8"), savedAt: stat.mtime };
14767
+ } catch (error) {
14768
+ throw new Error(`${PREFIX11}: the saved copy ${path2} could not be read: ${messageOf(error)}`, { cause: error });
14769
+ }
14770
+ }
14771
+ function printChange(change, output) {
14772
+ for (const line of [change.bodyLine, change.notesLine]) {
14773
+ if (line !== null)
14774
+ output.info(line);
14775
+ }
14776
+ }
14777
+ async function settleSpecSnapshot(options) {
14778
+ const { repoRoot, specsDir, issue: issue3, refresh, output } = options;
14779
+ const write = (rewrite) => writeSpecSnapshot({ repoRoot, specsDir, issue: issue3, refresh: rewrite });
14780
+ const path2 = specPath(specsDir, issue3.number, issue3.title);
14781
+ const notes = notesPath(specsDir, issue3.number);
14782
+ if (path2 === notes)
14783
+ return write(refresh);
14784
+ const saved = readSavedCopy(resolve16(repoRoot, path2), path2);
14785
+ if (saved === null)
14786
+ return write(refresh);
14787
+ const change = readSnapshotChange({
14788
+ saved: saved.text,
14789
+ body: issue3.body,
14790
+ notes: readLocalNotes(repoRoot, specsDir, issue3.number),
14791
+ notesPath: notes
14792
+ });
14793
+ if (change.kind === "unchanged")
14794
+ return write(refresh);
14795
+ printChange(change, output);
14796
+ if (change.kind === "notes") {
14797
+ const rebuilt = write(refresh);
14798
+ if (rebuilt.previous !== null)
14799
+ output.info(notesRebuiltLine(rebuilt.path, issue3.number, rebuilt.previous));
14800
+ return rebuilt;
14801
+ }
14802
+ if (refresh)
14803
+ return write(true);
14804
+ const offer = options.offerRefresh ?? null;
14805
+ const accepted2 = offer !== null && await offer({ issue: issue3.number, path: path2, savedAt: saved.savedAt });
14806
+ if (!accepted2)
14807
+ throw new CommandExit(ISSUE_REFUSAL_EXIT, snapshotDiffersMessage(path2, issue3.number));
14808
+ return write(true);
14809
+ }
14810
+
14549
14811
  // src/board/spec-source.ts
14550
- var PREFIX10 = "board spec source";
14812
+ var PREFIX12 = "board spec source";
14551
14813
  var SOURCE_FLAGS = [SPEC_FLAG, ISSUE_FLAG, NEXT_FLAG];
14552
14814
  var SOURCE_REFUSAL_EXIT = 1;
14553
14815
  function severalSourcesMessage(given) {
@@ -14666,7 +14928,7 @@ async function settleBlockedPick(options) {
14666
14928
  async function pickRoadmapIssue(request, options, issues, output) {
14667
14929
  const seams = options.roadmap;
14668
14930
  if (seams === undefined) {
14669
- throw new TypeError(`${PREFIX10}: ${NEXT_FLAG} was resolved with no roadmap seams`);
14931
+ throw new TypeError(`${PREFIX12}: ${NEXT_FLAG} was resolved with no roadmap seams`);
14670
14932
  }
14671
14933
  const roadmap = await resolveRoadmapIssue({
14672
14934
  configured: request.roadmap ?? seams.configured,
@@ -14739,7 +15001,14 @@ async function resolveSpecSource(options) {
14739
15001
  output.info(dryRunLine(describeIssue(read)));
14740
15002
  return stopped("dry-run");
14741
15003
  }
14742
- const snapshot = writeSpecSnapshot({ repoRoot, specsDir, issue: read, refresh });
15004
+ const snapshot = await settleSpecSnapshot({
15005
+ repoRoot,
15006
+ specsDir,
15007
+ issue: read,
15008
+ refresh,
15009
+ offerRefresh: options.offerRefresh ?? null,
15010
+ output
15011
+ });
14743
15012
  return Object.freeze({
14744
15013
  outcome: "spec",
14745
15014
  spec: Object.freeze({
@@ -14812,6 +15081,7 @@ async function resolvePlanSpec(options) {
14812
15081
  const offer = offerReady === null || options.dryRun ? undefined : (issue3) => offerReady({ issue: issue3, gh, trust: trust(), output });
14813
15082
  const offerAlternative = options.offerAlternative ?? null;
14814
15083
  const alternative = offerAlternative === null || options.dryRun ? undefined : offerAlternative;
15084
+ const offerRefresh = options.dryRun ? null : options.offerRefresh ?? null;
14815
15085
  const resolution = await resolveSpecSource({
14816
15086
  request: options.request,
14817
15087
  refresh: options.refresh,
@@ -14821,6 +15091,7 @@ async function resolvePlanSpec(options) {
14821
15091
  findSpec: options.findSpec,
14822
15092
  issues: createGhSpecIssueReader({ gh }),
14823
15093
  inspect: (issue3) => inspectSpecIssue(issue3, trust(), offer),
15094
+ offerRefresh,
14824
15095
  roadmap: {
14825
15096
  configured: options.roadmapIssue,
14826
15097
  search: createGhRoadmapSearch({ gh }),
@@ -14916,8 +15187,8 @@ function formatRows(rows2) {
14916
15187
  `);
14917
15188
  }
14918
15189
  function defaultSleep(ms) {
14919
- return new Promise((resolve15) => {
14920
- setTimeout(resolve15, ms);
15190
+ return new Promise((resolve17) => {
15191
+ setTimeout(resolve17, ms);
14921
15192
  });
14922
15193
  }
14923
15194
  async function waitForChecks(options) {
@@ -15163,7 +15434,7 @@ function compareUrl(remote, branch) {
15163
15434
  return `https://${segments[0] ?? host}/${path2}/compare/${encodeBranch(branch)}${COMPARE_QUERY}`;
15164
15435
  }
15165
15436
  // src/pr/gh.ts
15166
- var PREFIX11 = "gh pull requests";
15437
+ var PREFIX13 = "gh pull requests";
15167
15438
  var REPO_PATH3 = "{owner}/{repo}";
15168
15439
  var SUMMARY_FIELDS = "author,baseRefName,headRefName,isCrossRepository,number,state,title,updatedAt,url";
15169
15440
  var DETAIL_FIELDS = `${SUMMARY_FIELDS},body,headRefOid,labels,mergeStateStatus,mergeable`;
@@ -15192,16 +15463,16 @@ function detailOf8(result, command) {
15192
15463
  return result.ok ? `${command} exited 0 and wrote nothing` : `${command} exited non-zero and wrote nothing`;
15193
15464
  }
15194
15465
  function failure3(command, result) {
15195
- return new Error(`${PREFIX11}: ${command} failed: ${detailOf8(result, command)}`);
15466
+ return new Error(`${PREFIX13}: ${command} failed: ${detailOf8(result, command)}`);
15196
15467
  }
15197
15468
  function refuse3(command, problem2) {
15198
- throw new Error(`${PREFIX11}: ${command} answered ${problem2}`);
15469
+ throw new Error(`${PREFIX13}: ${command} answered ${problem2}`);
15199
15470
  }
15200
15471
  function parseJson3(stdout, command) {
15201
15472
  try {
15202
15473
  return JSON.parse(stdout);
15203
15474
  } catch (error) {
15204
- throw new Error(`${PREFIX11}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
15475
+ throw new Error(`${PREFIX13}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
15205
15476
  }
15206
15477
  }
15207
15478
  function readString2(value, command, where) {
@@ -15304,7 +15575,7 @@ function readWorkflowCount(stdout) {
15304
15575
  }
15305
15576
  function pullNumber(value, member) {
15306
15577
  if (!Number.isSafeInteger(value) || value < 1) {
15307
- throw new TypeError(`${PREFIX11}: ${member} refused pull request number ${describeValue(value)},` + " expected a positive whole number");
15578
+ throw new TypeError(`${PREFIX13}: ${member} refused pull request number ${describeValue(value)},` + " expected a positive whole number");
15308
15579
  }
15309
15580
  return String(value);
15310
15581
  }
@@ -15312,13 +15583,13 @@ function textArgument(value, member, what, whole) {
15312
15583
  const bad = typeof value !== "string" || value === "" || whole && !(WHOLE_NUMBER.test(value) && Number.isSafeInteger(Number(value)));
15313
15584
  if (bad) {
15314
15585
  const expected = whole ? "a positive whole number with no leading zero" : "a non-empty string";
15315
- throw new TypeError(`${PREFIX11}: ${member} refused ${what} ${describeValue(value)}, expected ${expected}`);
15586
+ throw new TypeError(`${PREFIX13}: ${member} refused ${what} ${describeValue(value)}, expected ${expected}`);
15316
15587
  }
15317
15588
  return value;
15318
15589
  }
15319
15590
  function bodyText(value, member) {
15320
15591
  if (typeof value !== "string") {
15321
- throw new TypeError(`${PREFIX11}: ${member} refused a body ${describeValue(value)}, expected a string`);
15592
+ throw new TypeError(`${PREFIX13}: ${member} refused a body ${describeValue(value)}, expected a string`);
15322
15593
  }
15323
15594
  return value;
15324
15595
  }
@@ -15388,7 +15659,7 @@ function createGhPullRequests(options) {
15388
15659
  merge: async (number, method) => {
15389
15660
  const target = pullNumber(number, "merge");
15390
15661
  if (!isMergeMethod(method)) {
15391
- throw new TypeError(`${PREFIX11}: merge refused method ${describeValue(method)},` + ` expected one of: ${MERGE_METHODS.join(", ")}`);
15662
+ throw new TypeError(`${PREFIX13}: merge refused method ${describeValue(method)},` + ` expected one of: ${MERGE_METHODS.join(", ")}`);
15392
15663
  }
15393
15664
  const command = `gh pr merge ${target} --${method}`;
15394
15665
  const result = await gh(["pr", "merge", target, `--${method}`]);
@@ -15623,11 +15894,11 @@ function readStepOutcome(step2, result, plan) {
15623
15894
 
15624
15895
  // src/commands/loop/loop-sessions.ts
15625
15896
  import { execFileSync as execFileSync2 } from "child_process";
15626
- import { readFileSync as readFileSync20 } from "fs";
15627
- import { join as join28, relative as relative5 } from "path";
15897
+ import { readFileSync as readFileSync21 } from "fs";
15898
+ import { join as join29, relative as relative5 } from "path";
15628
15899
 
15629
15900
  // src/effort/store/task-finishes.ts
15630
- import { existsSync as existsSync21 } from "fs";
15901
+ import { existsSync as existsSync22 } from "fs";
15631
15902
  var SELECT_FINISHES = `
15632
15903
  SELECT collected_at FROM task_reports
15633
15904
  WHERE plan_stub IS ? AND outcome = 'done' AND collected_at >= ?
@@ -15638,7 +15909,7 @@ var SELECT_FINISHES = `
15638
15909
  `;
15639
15910
  function readTaskFinishes(repoRoot, query) {
15640
15911
  const path2 = sqliteStorePath(repoRoot);
15641
- if (!existsSync21(path2))
15912
+ if (!existsSync22(path2))
15642
15913
  return [];
15643
15914
  const bound = [query.planStub, query.since, query.planStub, query.since];
15644
15915
  const rows2 = withSqliteStore(path2, false, (db) => db.query(SELECT_FINISHES).all(...bound));
@@ -15647,15 +15918,15 @@ function readTaskFinishes(repoRoot, query) {
15647
15918
 
15648
15919
  // src/loop/sessions.ts
15649
15920
  import {
15650
- linkSync,
15651
- mkdirSync as mkdirSync9,
15652
- readdirSync as readdirSync6,
15653
- readFileSync as readFileSync19,
15921
+ linkSync as linkSync2,
15922
+ mkdirSync as mkdirSync10,
15923
+ readdirSync as readdirSync7,
15924
+ readFileSync as readFileSync20,
15654
15925
  renameSync as renameSync2,
15655
15926
  rmSync,
15656
15927
  writeFileSync as writeFileSync9
15657
15928
  } from "fs";
15658
- import { basename as basename9, dirname as dirname11, join as join27 } from "path";
15929
+ import { basename as basename10, dirname as dirname11, join as join28 } from "path";
15659
15930
  var SESSION_STATES = Object.freeze(["running", "paused", "stopped", "done"]);
15660
15931
  var RUNS_DIR = "runs";
15661
15932
  var RECORD_EXTENSION = ".json";
@@ -15695,13 +15966,13 @@ function isSessionId(value) {
15695
15966
  return SESSION_ID_PATTERN.test(value);
15696
15967
  }
15697
15968
  function runsDir(root) {
15698
- return join27(scopeAt(root).dir, RUNS_DIR);
15969
+ return join28(scopeAt(root).dir, RUNS_DIR);
15699
15970
  }
15700
15971
  function sessionFilePath(root, sessionId) {
15701
15972
  if (!isSessionId(sessionId)) {
15702
15973
  throw new Error(`session record: unusable session id ${JSON.stringify(sessionId)}`);
15703
15974
  }
15704
- return join27(runsDir(root), `${sessionId}${RECORD_EXTENSION}`);
15975
+ return join28(runsDir(root), `${sessionId}${RECORD_EXTENSION}`);
15705
15976
  }
15706
15977
  function describeValue7(value) {
15707
15978
  return value === undefined ? "missing" : JSON.stringify(value) ?? String(value);
@@ -15732,7 +16003,7 @@ function sessionIdProblem(sessionId, file) {
15732
16003
  if (typeof sessionId !== "string" || !isSessionId(sessionId)) {
15733
16004
  return `sessionId is ${describeValue7(sessionId)}, expected a plain file name`;
15734
16005
  }
15735
- return basename9(file) === `${sessionId}${RECORD_EXTENSION}` ? null : `sessionId ${JSON.stringify(sessionId)} is not the file's name`;
16006
+ return basename10(file) === `${sessionId}${RECORD_EXTENSION}` ? null : `sessionId ${JSON.stringify(sessionId)} is not the file's name`;
15736
16007
  }
15737
16008
  function planStubProblem(planStub2) {
15738
16009
  return planStub2 === null || typeof planStub2 === "string" && isStampableStub(planStub2) ? null : `planStub is ${describeValue7(planStub2)}, expected null or a plan stub`;
@@ -15803,7 +16074,7 @@ function readState2(record, isAlive = isPidAlive) {
15803
16074
  function readRecordFile(file) {
15804
16075
  let text2;
15805
16076
  try {
15806
- text2 = readFileSync19(file, "utf8");
16077
+ text2 = readFileSync20(file, "utf8");
15807
16078
  } catch (error) {
15808
16079
  throw new SessionRecordError(file, `cannot be read: ${messageOf(error)}`);
15809
16080
  }
@@ -15811,7 +16082,7 @@ function readRecordFile(file) {
15811
16082
  }
15812
16083
  function recordNames(dir) {
15813
16084
  try {
15814
- return readdirSync6(dir);
16085
+ return readdirSync7(dir);
15815
16086
  } catch (error) {
15816
16087
  if (errorCode(error) === "ENOENT")
15817
16088
  return [];
@@ -15824,7 +16095,7 @@ function byStart(a, b) {
15824
16095
  function readSessions(root, seams = {}) {
15825
16096
  const dir = runsDir(root);
15826
16097
  const isAlive = seams.isAlive ?? isPidAlive;
15827
- const records = recordNames(dir).filter((name2) => name2.endsWith(RECORD_EXTENSION)).map((name2) => readRecordFile(join27(dir, name2))).map((record) => Object.freeze({ ...record, state: readState2(record, isAlive) }));
16098
+ const records = recordNames(dir).filter((name2) => name2.endsWith(RECORD_EXTENSION)).map((name2) => readRecordFile(join28(dir, name2))).map((record) => Object.freeze({ ...record, state: readState2(record, isAlive) }));
15828
16099
  return Object.freeze(records.sort(byStart));
15829
16100
  }
15830
16101
  function readSession(root, sessionId, seams = {}) {
@@ -15850,13 +16121,13 @@ function checkRecord(record, file) {
15850
16121
  }
15851
16122
  function writeRecordFile(file, record, isNew) {
15852
16123
  checkRecord(record, file);
15853
- mkdirSync9(dirname11(file), { recursive: true });
16124
+ mkdirSync10(dirname11(file), { recursive: true });
15854
16125
  const temporary = `${file}.${process.pid}.tmp`;
15855
16126
  writeFileSync9(temporary, `${JSON.stringify(record, null, 2)}
15856
16127
  `);
15857
16128
  try {
15858
16129
  if (isNew)
15859
- linkSync(temporary, file);
16130
+ linkSync2(temporary, file);
15860
16131
  else
15861
16132
  renameSync2(temporary, file);
15862
16133
  } finally {
@@ -16010,11 +16281,11 @@ function writeSession(root, record, change) {
16010
16281
  }
16011
16282
  }
16012
16283
  function readSessionChecklist(root, record) {
16013
- const plan = join28(root, record.plan);
16284
+ const plan = join29(root, record.plan);
16014
16285
  const file = [trackerPathFor(plan), plan].find((path2) => isFile(path2));
16015
16286
  if (file === undefined)
16016
16287
  return null;
16017
- const content = readFileSync20(file, "utf8");
16288
+ const content = readFileSync21(file, "utf8");
16018
16289
  return { file, tasks: parsePlan(content).tasks, lines: content.split(`
16019
16290
  `) };
16020
16291
  }
@@ -16052,7 +16323,7 @@ function etaLine(eta) {
16052
16323
  }
16053
16324
 
16054
16325
  // src/next/sources.ts
16055
- var PREFIX12 = "rafa next";
16326
+ var PREFIX14 = "rafa next";
16056
16327
  var DEFAULT_BASE_BRANCH = "main";
16057
16328
  var DEFAULT_NEXT_SOURCE_SEAMS = Object.freeze({});
16058
16329
  function memoiseIssues2(issues) {
@@ -16090,7 +16361,7 @@ function ghNextBoard(options) {
16090
16361
  }
16091
16362
  function nextProject(context) {
16092
16363
  if (context.project === null)
16093
- throw new Error(`${PREFIX12} runs inside a project, and was handed none`);
16364
+ throw new Error(`${PREFIX14} runs inside a project, and was handed none`);
16094
16365
  return context.project;
16095
16366
  }
16096
16367
  function nextConfig(project, warn) {
@@ -16100,7 +16371,7 @@ function nextConfig(project, warn) {
16100
16371
  if (!(error instanceof ConfigError))
16101
16372
  throw error;
16102
16373
  throw new CommandExit(1, [
16103
- `\u274C ${PREFIX12}: the config cannot be used:`,
16374
+ `\u274C ${PREFIX14}: the config cannot be used:`,
16104
16375
  ...error.problems.map((problem2) => ` ${problem2}`)
16105
16376
  ].join(`
16106
16377
  `));
@@ -16119,33 +16390,38 @@ function openNextSources(context, seams = DEFAULT_NEXT_SOURCE_SEAMS) {
16119
16390
  const git = (seams.openGit ?? createGitRunner)(project.root);
16120
16391
  const gh = (seams.openGh ?? ((root) => createGhRunner({ cwd: root })))(project.root);
16121
16392
  const loop = resolveLoopSeams({ isAlive: seams.isAlive });
16122
- return Object.freeze({
16393
+ const board = () => ghNextBoard({ gh, git, configured: config.roadmapIssue });
16394
+ const held = {
16123
16395
  base: config.prBase ?? DEFAULT_BASE_BRANCH,
16124
16396
  plans: plansDirAt(project.root, config.planDir),
16125
16397
  runs: () => readRecords(project.root, loop),
16126
16398
  git,
16127
- pulls: (seams.pullRequests ?? ghPullRequestsIn)(project.root),
16128
- board: ghNextBoard({ gh, git, configured: config.roadmapIssue })
16399
+ pulls: (seams.pullRequests ?? ghPullRequestsIn)(project.root)
16400
+ };
16401
+ return Object.freeze({
16402
+ ...held,
16403
+ board: board(),
16404
+ answer: () => Object.freeze({ ...held, board: board() })
16129
16405
  });
16130
16406
  }
16131
16407
 
16132
16408
  // src/commands/plan/list.ts
16133
- import { existsSync as existsSync22, readdirSync as readdirSync7, readFileSync as readFileSync21 } from "fs";
16134
- import { join as join29 } from "path";
16409
+ import { existsSync as existsSync23, readdirSync as readdirSync8, readFileSync as readFileSync22 } from "fs";
16410
+ import { join as join30 } from "path";
16135
16411
  var USAGE10 = "rafa plan list";
16136
16412
  function listing(dir, stub) {
16137
- const plan = join29(dir, planFileName(stub, false));
16138
- const trackerPath = join29(dir, planFileName(stub, true));
16413
+ const plan = join30(dir, planFileName(stub, false));
16414
+ const trackerPath = join30(dir, planFileName(stub, true));
16139
16415
  const tracker = isFile(trackerPath) ? trackerPath : null;
16140
- const planModel = parsePlan(readFileSync21(plan, "utf8"));
16141
- const counted3 = tracker === null ? planModel : parsePlan(readFileSync21(tracker, "utf8"));
16416
+ const planModel = parsePlan(readFileSync22(plan, "utf8"));
16417
+ const counted3 = tracker === null ? planModel : parsePlan(readFileSync22(tracker, "utf8"));
16142
16418
  return { stub, plan, tracker, tasks: countTasks(counted3.tasks), issues: planModel.issues.length };
16143
16419
  }
16144
16420
  function listPlans(plans) {
16145
16421
  const dir = plans.path;
16146
- if (!existsSync22(dir))
16422
+ if (!existsSync23(dir))
16147
16423
  return { dir, plans: [] };
16148
- const stubs = readdirSync7(dir).filter((name2) => isFile(join29(dir, name2))).map((name2) => stubOfPlanFile(name2)).filter((stub) => stub !== null).sort((a, b) => a.localeCompare(b));
16424
+ const stubs = readdirSync8(dir).filter((name2) => isFile(join30(dir, name2))).map((name2) => stubOfPlanFile(name2)).filter((stub) => stub !== null).sort((a, b) => a.localeCompare(b));
16149
16425
  return { dir, plans: stubs.map((stub) => listing(dir, stub)) };
16150
16426
  }
16151
16427
  function rowNotes(plan) {
@@ -16340,7 +16616,7 @@ function branchLabel(world) {
16340
16616
  }
16341
16617
 
16342
16618
  // src/next/state.ts
16343
- var PREFIX13 = "rafa next";
16619
+ var PREFIX15 = "rafa next";
16344
16620
  var MAX_NAMED_FILES = 5;
16345
16621
  var NEXT_PRECONDITIONS = Object.freeze([
16346
16622
  "tree-modified",
@@ -16618,7 +16894,7 @@ async function readNextState(sources) {
16618
16894
  if (found !== null)
16619
16895
  return answer(found, world.problems());
16620
16896
  }
16621
- throw new Error(`${PREFIX13}: no row of the table answered, and the last row answers for every reading`);
16897
+ throw new Error(`${PREFIX15}: no row of the table answered, and the last row answers for every reading`);
16622
16898
  }
16623
16899
 
16624
16900
  // src/next/hint.ts
@@ -16644,8 +16920,8 @@ function wantsHint(flags) {
16644
16920
  }
16645
16921
  var DEFAULT_HINT_SEAMS = Object.freeze({});
16646
16922
  function afterDelay(ms) {
16647
- return new Promise((resolve15) => {
16648
- setTimeout(resolve15, ms).unref();
16923
+ return new Promise((resolve17) => {
16924
+ setTimeout(resolve17, ms).unref();
16649
16925
  });
16650
16926
  }
16651
16927
  function silenced() {
@@ -16699,10 +16975,10 @@ async function nextStepHint(context, seams = DEFAULT_HINT_SEAMS) {
16699
16975
  }
16700
16976
 
16701
16977
  // src/next/actions.ts
16702
- var PREFIX14 = "rafa next";
16978
+ var PREFIX16 = "rafa next";
16703
16979
  function needed(state, value, what) {
16704
16980
  if (value === null) {
16705
- throw new Error(`${PREFIX14}: state "${state.id}" proposes "${state.action}" and names no ${what}`);
16981
+ throw new Error(`${PREFIX16}: state "${state.id}" proposes "${state.action}" and names no ${what}`);
16706
16982
  }
16707
16983
  return String(value);
16708
16984
  }
@@ -16752,12 +17028,12 @@ function actionContext(caller, command, argv) {
16752
17028
  async function runAction(caller, state) {
16753
17029
  const invocation = actionInvocation(state);
16754
17030
  if (invocation === null) {
16755
- throw new Error(`${PREFIX14}: the action "${state.action}" of state "${state.id}" runs no registered command`);
17031
+ throw new Error(`${PREFIX16}: the action "${state.action}" of state "${state.id}" runs no registered command`);
16756
17032
  }
16757
17033
  const spec = ACTION_COMMANDS[invocation.action];
16758
17034
  const command = caller.registry.find(spec.subject, spec.action);
16759
17035
  if (command === undefined) {
16760
- throw new CommandExit(1, `\u274C ${PREFIX14}: the "${invocation.action}" step runs "rafa ${invocation.command}", which is registered by nothing`);
17036
+ throw new CommandExit(1, `\u274C ${PREFIX16}: the "${invocation.action}" step runs "rafa ${invocation.command}", which is registered by nothing`);
16761
17037
  }
16762
17038
  await command.run(actionContext(caller, command, invocation.argv));
16763
17039
  }
@@ -17042,7 +17318,7 @@ var UNBLOCK_USAGE = "rafa issue unblock [<n>] [--all]";
17042
17318
  var ALL_FLAG = "all";
17043
17319
  var ISSUE_NUMBER4 = /^[1-9]\d*$/u;
17044
17320
  var YES_ANSWERS3 = ["y", "yes"];
17045
- var PREFIX15 = "board unblock";
17321
+ var PREFIX17 = "board unblock";
17046
17322
  function nameIds2(ids) {
17047
17323
  return ids.map((id) => `#${String(id)}`).join(" ");
17048
17324
  }
@@ -17056,32 +17332,32 @@ function detailOf9(result, command) {
17056
17332
  async function rowsOf2(gh, args, command) {
17057
17333
  const result = await gh(args);
17058
17334
  if (!result.ok)
17059
- throw new Error(`${PREFIX15}: ${detailOf9(result, command)}`);
17335
+ throw new Error(`${PREFIX17}: ${detailOf9(result, command)}`);
17060
17336
  let parsed;
17061
17337
  try {
17062
17338
  parsed = JSON.parse(result.stdout);
17063
17339
  } catch (error) {
17064
- throw new Error(`${PREFIX15}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
17340
+ throw new Error(`${PREFIX17}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
17065
17341
  }
17066
17342
  if (!Array.isArray(parsed)) {
17067
- throw new Error(`${PREFIX15}: ${command} answered ${describeValue(parsed)}, expected a list of issues`);
17343
+ throw new Error(`${PREFIX17}: ${command} answered ${describeValue(parsed)}, expected a list of issues`);
17068
17344
  }
17069
17345
  return parsed;
17070
17346
  }
17071
17347
  function rowNumber4(row2, command, where) {
17072
17348
  if (!isMapping(row2)) {
17073
- throw new Error(`${PREFIX15}: ${command} answered ${where} as ${describeValue(row2)}, expected a mapping`);
17349
+ throw new Error(`${PREFIX17}: ${command} answered ${where} as ${describeValue(row2)}, expected a mapping`);
17074
17350
  }
17075
17351
  const number = row2["number"];
17076
17352
  if (typeof number !== "number" || !Number.isSafeInteger(number) || number < 1) {
17077
- throw new Error(`${PREFIX15}: ${command} answered ${where}.number as ${describeValue(number)}, expected a positive whole number`);
17353
+ throw new Error(`${PREFIX17}: ${command} answered ${where}.number as ${describeValue(number)}, expected a positive whole number`);
17078
17354
  }
17079
17355
  return number;
17080
17356
  }
17081
17357
  function rowBody2(row2, command, where) {
17082
17358
  const body = isMapping(row2) ? row2["body"] : null;
17083
17359
  if (typeof body !== "string") {
17084
- throw new Error(`${PREFIX15}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
17360
+ throw new Error(`${PREFIX17}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
17085
17361
  }
17086
17362
  return body;
17087
17363
  }
@@ -17723,9 +17999,9 @@ async function handleRedChecks(io, branch, prNumber, rows2) {
17723
17999
  }
17724
18000
 
17725
18001
  // src/start/runtime.ts
17726
- import { existsSync as existsSync23, readdirSync as readdirSync8, realpathSync as realpathSync4, statSync as statSync14 } from "fs";
18002
+ import { existsSync as existsSync24, readdirSync as readdirSync9, realpathSync as realpathSync4, statSync as statSync16 } from "fs";
17727
18003
  import { homedir as homedir5 } from "os";
17728
- import { isAbsolute as isAbsolute9, join as join30, relative as relative7, resolve as resolve15, sep as sep4 } from "path";
18004
+ import { isAbsolute as isAbsolute9, join as join31, relative as relative7, resolve as resolve17, sep as sep4 } from "path";
17729
18005
 
17730
18006
  // src/start/session.ts
17731
18007
  import { randomUUID as randomUUID4 } from "crypto";
@@ -17876,7 +18152,7 @@ function announcePlanIssues(planContent) {
17876
18152
 
17877
18153
  // src/start/runtime.ts
17878
18154
  var RUNTIME_FLAG = "--runtime";
17879
- var RUNTIME_SUBDIR = join30(".rafa", "runtime");
18155
+ var RUNTIME_SUBDIR = join31(".rafa", "runtime");
17880
18156
  var RUNTIME_ENTRY = "cli.js";
17881
18157
  var SOURCE_DIR = "src";
17882
18158
  var RUNTIME_COMMAND = ["start"];
@@ -17903,7 +18179,7 @@ function resolveRuntime(value, places) {
17903
18179
  throw refusal5([`\u274C Refusing to start: \`--runtime\` names no runtime. Spell it ${SPELLING}.`]);
17904
18180
  }
17905
18181
  const isVersion = VERSION_SHAPE.test(value);
17906
- const named = isVersion ? join30(places.home, RUNTIME_SUBDIR, value, RUNTIME_ENTRY) : resolve15(places.cwd, value);
18182
+ const named = isVersion ? join31(places.home, RUNTIME_SUBDIR, value, RUNTIME_ENTRY) : resolve17(places.cwd, value);
17907
18183
  refuseInsideSource(value, named, places);
17908
18184
  const entry = entryOf(value, named, isVersion, places.home);
17909
18185
  const real = realpathSync4(entry);
@@ -17914,7 +18190,7 @@ function entryOf(value, named, isVersion, home) {
17914
18190
  if (isVersion) {
17915
18191
  if (isFile3(named))
17916
18192
  return named;
17917
- const root = join30(home, RUNTIME_SUBDIR);
18193
+ const root = join31(home, RUNTIME_SUBDIR);
17918
18194
  const installed = installedVersions(root);
17919
18195
  throw refusal5([
17920
18196
  `\u274C Refusing to start: \`--runtime=${value}\` names no installed runtime: ${named} is no file.`,
@@ -17923,7 +18199,7 @@ function entryOf(value, named, isVersion, home) {
17923
18199
  }
17924
18200
  if (isFile3(named))
17925
18201
  return named;
17926
- const inside = join30(named, RUNTIME_ENTRY);
18202
+ const inside = join31(named, RUNTIME_ENTRY);
17927
18203
  if (isDirectory2(named) && isFile3(inside))
17928
18204
  return inside;
17929
18205
  throw refusal5([
@@ -17941,8 +18217,8 @@ function refuseInsideSource(value, path2, places) {
17941
18217
  ]);
17942
18218
  }
17943
18219
  function sourceDirs({ cwd, root }) {
17944
- const dirs = [join30(cwd, SOURCE_DIR), join30(root, SOURCE_DIR)];
17945
- const real = dirs.filter((dir) => existsSync23(dir)).map((dir) => realpathSync4(dir));
18220
+ const dirs = [join31(cwd, SOURCE_DIR), join31(root, SOURCE_DIR)];
18221
+ const real = dirs.filter((dir) => existsSync24(dir)).map((dir) => realpathSync4(dir));
17946
18222
  return [...new Set([...dirs, ...real])];
17947
18223
  }
17948
18224
  function isInside2(path2, dir) {
@@ -17951,21 +18227,21 @@ function isInside2(path2, dir) {
17951
18227
  }
17952
18228
  function installedVersions(root) {
17953
18229
  try {
17954
- return readdirSync8(root).filter((name2) => isFile3(join30(root, name2, RUNTIME_ENTRY))).sort((a, b) => a.localeCompare(b));
18230
+ return readdirSync9(root).filter((name2) => isFile3(join31(root, name2, RUNTIME_ENTRY))).sort((a, b) => a.localeCompare(b));
17955
18231
  } catch {
17956
18232
  return [];
17957
18233
  }
17958
18234
  }
17959
18235
  function isFile3(path2) {
17960
18236
  try {
17961
- return statSync14(path2).isFile();
18237
+ return statSync16(path2).isFile();
17962
18238
  } catch {
17963
18239
  return false;
17964
18240
  }
17965
18241
  }
17966
18242
  function isDirectory2(path2) {
17967
18243
  try {
17968
- return statSync14(path2).isDirectory();
18244
+ return statSync16(path2).isDirectory();
17969
18245
  } catch {
17970
18246
  return false;
17971
18247
  }
@@ -17996,7 +18272,7 @@ function realOrResolved(path2) {
17996
18272
  try {
17997
18273
  return realpathSync4(path2);
17998
18274
  } catch {
17999
- return resolve15(path2);
18275
+ return resolve17(path2);
18000
18276
  }
18001
18277
  }
18002
18278
  async function runRuntime(entry, words, run) {
@@ -18091,13 +18367,13 @@ import { fileURLToPath as fileURLToPath2 } from "url";
18091
18367
  import { homedir as homedir6 } from "os";
18092
18368
 
18093
18369
  // src/notices/notices.ts
18094
- import { mkdirSync as mkdirSync10, readFileSync as readFileSync22, writeFileSync as writeFileSync10 } from "fs";
18095
- import { dirname as dirname12, join as join31 } from "path";
18370
+ import { mkdirSync as mkdirSync11, readFileSync as readFileSync23, writeFileSync as writeFileSync10 } from "fs";
18371
+ import { dirname as dirname12, join as join32 } from "path";
18096
18372
  var NOTICE_IDS = Object.freeze(["alpha", "danger"]);
18097
18373
  var FEEDBACK_URL = "https://github.com/open-tomato/rafa/issues/new/choose";
18098
18374
  var ROADMAP_URL = "https://github.com/open-tomato/rafa/issues/31";
18099
18375
  function noticesPath(home) {
18100
- return join31(home, ".rafa", "notices.json");
18376
+ return join32(home, ".rafa", "notices.json");
18101
18377
  }
18102
18378
  function isNoticeId(value) {
18103
18379
  return typeof value === "string" && NOTICE_IDS.includes(value);
@@ -18105,7 +18381,7 @@ function isNoticeId(value) {
18105
18381
  function readDismissed(home) {
18106
18382
  let raw;
18107
18383
  try {
18108
- raw = readFileSync22(noticesPath(home), "utf8");
18384
+ raw = readFileSync23(noticesPath(home), "utf8");
18109
18385
  } catch {
18110
18386
  return [];
18111
18387
  }
@@ -18124,7 +18400,7 @@ function readDismissed(home) {
18124
18400
  function writeDismissed(home, ids) {
18125
18401
  const all = NOTICE_IDS.filter((id) => ids.includes(id) || readDismissed(home).includes(id));
18126
18402
  const path2 = noticesPath(home);
18127
- mkdirSync10(dirname12(path2), { recursive: true });
18403
+ mkdirSync11(dirname12(path2), { recursive: true });
18128
18404
  writeFileSync10(path2, `${JSON.stringify({ dismissed: all }, null, 2)}
18129
18405
  `);
18130
18406
  }
@@ -18667,7 +18943,7 @@ import { randomUUID as randomUUID9 } from "crypto";
18667
18943
 
18668
18944
  // src/effort/store/absences.ts
18669
18945
  import { randomUUID as randomUUID5 } from "crypto";
18670
- import { existsSync as existsSync24 } from "fs";
18946
+ import { existsSync as existsSync25 } from "fs";
18671
18947
  var ABSENCE_REASONS = {
18672
18948
  "no-block": true,
18673
18949
  "unclosed-block": true,
@@ -18726,13 +19002,13 @@ function writeReportAbsence(repoRoot, write, seams = {}) {
18726
19002
  write.outcome,
18727
19003
  collectedAt
18728
19004
  ];
18729
- const appended3 = withSqliteStore(path2, !existsSync24(path2), (db) => db.query(INSERT_ABSENCE).run(...values).changes);
19005
+ const appended3 = withSqliteStore(path2, !existsSync25(path2), (db) => db.query(INSERT_ABSENCE).run(...values).changes);
18730
19006
  return { path: path2, appended: appended3, skipped: 1 - appended3 };
18731
19007
  }
18732
19008
 
18733
19009
  // src/effort/store/changes.ts
18734
19010
  import { randomUUID as randomUUID6 } from "crypto";
18735
- import { existsSync as existsSync25 } from "fs";
19011
+ import { existsSync as existsSync26 } from "fs";
18736
19012
  var INSERT_CHANGE = `
18737
19013
  INSERT INTO changes (
18738
19014
  id, session_id, plan_stub, task_line,
@@ -18811,7 +19087,7 @@ var SELECT_PLAN_CHANGES = `
18811
19087
  `;
18812
19088
  function readPlanChanges(repoRoot, planStub2) {
18813
19089
  const path2 = sqliteStorePath(repoRoot);
18814
- if (!existsSync25(path2))
19090
+ if (!existsSync26(path2))
18815
19091
  return [];
18816
19092
  const rows2 = withSqliteStore(path2, false, (db) => db.query(SELECT_PLAN_CHANGES).all(planStub2));
18817
19093
  return rows2.map((row2) => ({
@@ -18980,8 +19256,8 @@ function describeTaskReportRecord(record) {
18980
19256
  }
18981
19257
 
18982
19258
  // src/utils/progress.ts
18983
- import { existsSync as existsSync26, writeFileSync as writeFileSync11 } from "fs";
18984
- import { join as join32 } from "path";
19259
+ import { existsSync as existsSync27, writeFileSync as writeFileSync11 } from "fs";
19260
+ import { join as join33 } from "path";
18985
19261
  var PROGRESS_FILE_NAME = "progress.txt";
18986
19262
  var PROGRESS_CAP_BYTES = 16000;
18987
19263
  var LISTED_FIELDS = [
@@ -19023,7 +19299,7 @@ var ESCAPED_CODE_POINTS = new Set([
19023
19299
  8233
19024
19300
  ]);
19025
19301
  function progressFilePath(repoRoot) {
19026
- return join32(repoRoot, PROGRESS_FILE_NAME);
19302
+ return join33(repoRoot, PROGRESS_FILE_NAME);
19027
19303
  }
19028
19304
  function escapeValue(value) {
19029
19305
  let escaped = "";
@@ -19084,7 +19360,7 @@ function renderProgressText(findings, capBytes = PROGRESS_CAP_BYTES) {
19084
19360
  }
19085
19361
  function readProgressFindings(repoRoot, planStub2) {
19086
19362
  const path2 = sqliteStorePath(repoRoot);
19087
- if (!existsSync26(path2))
19363
+ if (!existsSync27(path2))
19088
19364
  return [];
19089
19365
  const rows2 = withSqliteStore(path2, false, (db) => {
19090
19366
  const query = db.query(SELECT_FINDINGS);
@@ -19111,20 +19387,20 @@ function writeProgress(repoRoot, planStub2) {
19111
19387
 
19112
19388
  // src/start/preflight.ts
19113
19389
  import { randomUUID as randomUUID8 } from "crypto";
19114
- import { existsSync as existsSync27, readFileSync as readFileSync23 } from "fs";
19390
+ import { existsSync as existsSync28, readFileSync as readFileSync24 } from "fs";
19115
19391
  import { homedir as homedir7 } from "os";
19116
- import { basename as basename10 } from "path";
19392
+ import { basename as basename11 } from "path";
19117
19393
  var KNOWN_MISSING_SENTENCE = "A known-missing item is neither a bug to fix nor a credential to patch" + " around: the preflight found it unavailable on this machine, so do the task without it.";
19118
19394
  function knownMissingNotice(lines) {
19119
19395
  return lines.length === 0 ? [] : [...lines, KNOWN_MISSING_SENTENCE];
19120
19396
  }
19121
19397
  function agentSourcePath(planPath) {
19122
19398
  const tracker = trackerPathFor(planPath);
19123
- return existsSync27(tracker) ? tracker : planPath;
19399
+ return existsSync28(tracker) ? tracker : planPath;
19124
19400
  }
19125
19401
  function readIfReadable2(path2) {
19126
19402
  try {
19127
- return readFileSync23(path2, "utf8");
19403
+ return readFileSync24(path2, "utf8");
19128
19404
  } catch {
19129
19405
  return null;
19130
19406
  }
@@ -19140,7 +19416,7 @@ function refuseUnresolvableAgents(options) {
19140
19416
  if (missing2.length === 0)
19141
19417
  return;
19142
19418
  throw new CommandExit(1, [
19143
- `\u274C Refusing to start: ${basename10(path2)} names ${missing2.length} agent(s) no loaded scope` + ` defines (loop.settingSources: ${settingSources.join(", ")}).`,
19419
+ `\u274C Refusing to start: ${basename11(path2)} names ${missing2.length} agent(s) no loaded scope` + ` defines (loop.settingSources: ${settingSources.join(", ")}).`,
19144
19420
  ...missing2.map((agent) => ` ${missingAgentLine(agent)}`),
19145
19421
  " Nothing was checked and nothing was dispatched."
19146
19422
  ].join(`
@@ -19173,7 +19449,7 @@ function skippedStartLine(item, tracker) {
19173
19449
  return `\u23ED start-only item ${item.kind} ${JSON.stringify(item.name)} was not checked:` + " it is probed on a first dispatch alone," + ` and ${tracker} already holds a ticked task`;
19174
19450
  }
19175
19451
  function announceSkippedStart(planPath, skipped) {
19176
- const tracker = basename10(trackerPathFor(planPath));
19452
+ const tracker = basename11(trackerPathFor(planPath));
19177
19453
  const output = activeOutput();
19178
19454
  for (const [index, item] of skipped.entries()) {
19179
19455
  const lead = index === 0 ? `
@@ -19192,7 +19468,7 @@ function startTier(planPath, items) {
19192
19468
  function announceReminders(planPath, reminders) {
19193
19469
  if (reminders.length === 0)
19194
19470
  return;
19195
- const file = basename10(prerequisitesPathForPlan(planPath) ?? planPath);
19471
+ const file = basename11(prerequisitesPathForPlan(planPath) ?? planPath);
19196
19472
  const output = activeOutput();
19197
19473
  output.info(`
19198
19474
  \uD83D\uDCCC ${file} names ${reminders.length} step(s) the preflight does not check:`);
@@ -19419,7 +19695,7 @@ async function holdWhilePaused(options) {
19419
19695
  }
19420
19696
 
19421
19697
  // src/release/prepare.ts
19422
- import { readFileSync as readFileSync25, writeFileSync as writeFileSync13 } from "fs";
19698
+ import { readFileSync as readFileSync26, writeFileSync as writeFileSync13 } from "fs";
19423
19699
 
19424
19700
  // src/release/changelog.ts
19425
19701
  var RELEASE_HEADING_FIELDS = ["version", "date", "title"];
@@ -19623,7 +19899,7 @@ function resolveReleaseLevel(declared, notes) {
19623
19899
  }
19624
19900
 
19625
19901
  // src/release/version.ts
19626
- import { readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "fs";
19902
+ import { readFileSync as readFileSync25, writeFileSync as writeFileSync12 } from "fs";
19627
19903
  var RELEASE_REMOTE = "origin";
19628
19904
  var RELEASE_BASE_BRANCH = "main";
19629
19905
  var VERSION_SHAPE2 = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?(?:\+([0-9A-Za-z.-]+))?$/;
@@ -19715,7 +19991,7 @@ function writeManifestVersion(path2, next) {
19715
19991
  const unwritten = { path: path2, written: false, previous: null, version: next };
19716
19992
  let text2;
19717
19993
  try {
19718
- text2 = readFileSync24(path2, "utf8");
19994
+ text2 = readFileSync25(path2, "utf8");
19719
19995
  } catch (error) {
19720
19996
  return { ...unwritten, problem: `${path2} could not be read: ${messageOf(error)}` };
19721
19997
  }
@@ -19818,7 +20094,7 @@ function planVersion(input, versionFile, level) {
19818
20094
  }
19819
20095
  function textOf(path2) {
19820
20096
  try {
19821
- return readFileSync25(path2, "utf8");
20097
+ return readFileSync26(path2, "utf8");
19822
20098
  } catch {
19823
20099
  return null;
19824
20100
  }
@@ -19931,7 +20207,7 @@ function changelogFailure(failed2, versionEdit, restored) {
19931
20207
  }
19932
20208
 
19933
20209
  // src/release/verify.ts
19934
- import { readFileSync as readFileSync26, writeFileSync as writeFileSync14 } from "fs";
20210
+ import { readFileSync as readFileSync27, writeFileSync as writeFileSync14 } from "fs";
19935
20211
  function changelogInsertionSpan(before, after) {
19936
20212
  const beforeLines = before.split(`
19937
20213
  `);
@@ -19948,7 +20224,7 @@ function changelogInsertionSpan(before, after) {
19948
20224
  }
19949
20225
  function textOf2(path2) {
19950
20226
  try {
19951
- return readFileSync26(path2, "utf8");
20227
+ return readFileSync27(path2, "utf8");
19952
20228
  } catch {
19953
20229
  return null;
19954
20230
  }
@@ -20340,9 +20616,9 @@ function describeStartTriage(result) {
20340
20616
  };
20341
20617
  }
20342
20618
  async function resolvePublicTracker(options, redact) {
20343
- const resolve16 = options.resolve ?? resolveTracker;
20619
+ const resolve18 = options.resolve ?? resolveTracker;
20344
20620
  try {
20345
- const { tracker, attempts } = await resolve16({
20621
+ const { tracker, attempts } = await resolve18({
20346
20622
  config: options.config,
20347
20623
  context: { repoRoot: options.repoRoot }
20348
20624
  });
@@ -20513,8 +20789,8 @@ function msUntil(startAt, now = new Date) {
20513
20789
  return target.getTime() - now.getTime();
20514
20790
  }
20515
20791
  function sleepFor(ms) {
20516
- return new Promise((resolve16) => {
20517
- setTimeout(resolve16, ms);
20792
+ return new Promise((resolve18) => {
20793
+ setTimeout(resolve18, ms);
20518
20794
  });
20519
20795
  }
20520
20796
  async function deferUntil(startAt, now = new Date, sleep = sleepFor) {
@@ -21070,8 +21346,8 @@ Usage: ${USAGE17}`);
21070
21346
  var exec_default = Object.freeze(execCommand);
21071
21347
 
21072
21348
  // src/modules/load.ts
21073
- import { readFileSync as readFileSync27 } from "fs";
21074
- import { isAbsolute as isAbsolute10, join as join33, relative as relative8, resolve as resolve16 } from "path";
21349
+ import { readFileSync as readFileSync28 } from "fs";
21350
+ import { isAbsolute as isAbsolute10, join as join34, relative as relative8, resolve as resolve18 } from "path";
21075
21351
 
21076
21352
  // src/modules/manifest.ts
21077
21353
  var MANIFEST_VERSION = 1;
@@ -21356,11 +21632,11 @@ function unread(name2, directory2, ...problems) {
21356
21632
  return { name: name2, version: null, directory: directory2, manifest: null, problems };
21357
21633
  }
21358
21634
  function readPathSource(source, settings, seams) {
21359
- const directory2 = resolve16(settings.base, source.location);
21360
- const file = join33(directory2, "package.json");
21635
+ const directory2 = resolve18(settings.base, source.location);
21636
+ const file = join34(directory2, "package.json");
21361
21637
  let parsed;
21362
21638
  try {
21363
- parsed = JSON.parse((seams.readText ?? ((path3) => readFileSync27(path3, "utf8")))(file));
21639
+ parsed = JSON.parse((seams.readText ?? ((path3) => readFileSync28(path3, "utf8")))(file));
21364
21640
  } catch (error) {
21365
21641
  return unread(null, directory2, `${file} cannot be read as JSON: ${firstLine2(error)}`);
21366
21642
  }
@@ -21391,7 +21667,7 @@ function readSource(source, settings, seams) {
21391
21667
  return unread(source.location, null, `${source.kind} source ${describeValue(source.location)} is refused: ${PHASE_7}`);
21392
21668
  }
21393
21669
  function resolveEntry(directory2, entry, label) {
21394
- const path3 = resolve16(directory2, entry);
21670
+ const path3 = resolve18(directory2, entry);
21395
21671
  const inside = relative8(directory2, path3);
21396
21672
  return inside === "" || inside.startsWith("..") || isAbsolute10(inside) ? { problem: `${label} is ${describeValue(entry)}, which resolves outside the module directory ${directory2}` } : { path: path3 };
21397
21673
  }
@@ -21859,7 +22135,7 @@ async function runNext(context, seams) {
21859
22135
  const prompter = lazyPrompter(openPrompter);
21860
22136
  try {
21861
22137
  return await runNextChain({
21862
- read: () => readNextState(sources),
22138
+ read: () => readNextState(sources.answer()),
21863
22139
  run: (state) => runStateAction(context, sources, state),
21864
22140
  ask: prompter.ask,
21865
22141
  handOver: prompter.close,
@@ -22063,6 +22339,23 @@ function createPlanReadyOffer(seams = DEFAULT_OFFER_SEAMS) {
22063
22339
  };
22064
22340
  }
22065
22341
 
22342
+ // src/commands/plan/refresh-offer.ts
22343
+ var DEFAULT_REFRESH_OFFER_SEAMS = Object.freeze({});
22344
+ function createPlanRefreshOffer(seams = DEFAULT_REFRESH_OFFER_SEAMS) {
22345
+ const isTerminal = seams.isTerminal ?? (() => process.stdin.isTTY === true);
22346
+ if (!isTerminal())
22347
+ return null;
22348
+ const openPrompter = seams.openPrompter ?? (() => createLinePrompter(process.stdin, process.stderr));
22349
+ return async (request) => {
22350
+ const prompter = lazyPrompter(openPrompter);
22351
+ try {
22352
+ return await prompter.ask(refreshQuestion(request.issue, request.savedAt));
22353
+ } finally {
22354
+ prompter.close();
22355
+ }
22356
+ };
22357
+ }
22358
+
22066
22359
  // src/commands/plan/spec-route.ts
22067
22360
  function specCandidates(specArg, specsDir) {
22068
22361
  if (path4.isAbsolute(specArg))
@@ -22092,10 +22385,11 @@ async function resolveCreateSpec(options, seams = DEFAULT_ROUTE_SEAMS) {
22092
22385
  const source = readSpecSourceFlags(options.args);
22093
22386
  if (source.request === null)
22094
22387
  throw new CommandExit(SOURCE_REFUSAL_EXIT, usageRefusal(specsDir));
22095
- const resolve17 = seams.resolve ?? resolvePlanSpec;
22388
+ const resolve19 = seams.resolve ?? resolvePlanSpec;
22096
22389
  const makeReadyOffer = seams.makeReadyOffer ?? createPlanReadyOffer;
22097
22390
  const makeAlternativeOffer = seams.makeAlternativeOffer ?? createPlanBlockedOffer;
22098
- return await resolve17({
22391
+ const makeRefreshOffer = seams.makeRefreshOffer ?? createPlanRefreshOffer;
22392
+ return await resolve19({
22099
22393
  request: source.request,
22100
22394
  refresh: source.refresh,
22101
22395
  dryRun: source.dryRun,
@@ -22105,7 +22399,8 @@ async function resolveCreateSpec(options, seams = DEFAULT_ROUTE_SEAMS) {
22105
22399
  trustedAuthors: options.trustedAuthors,
22106
22400
  findSpec: (spec) => findSpec(repoRoot, spec, specsDir),
22107
22401
  offerReady: makeReadyOffer(),
22108
- offerAlternative: makeAlternativeOffer()
22402
+ offerAlternative: makeAlternativeOffer(),
22403
+ offerRefresh: makeRefreshOffer()
22109
22404
  });
22110
22405
  }
22111
22406
 
@@ -22277,7 +22572,7 @@ var wrapped2 = wrapPhaseZeroCommand({
22277
22572
  },
22278
22573
  {
22279
22574
  name: "refresh",
22280
- description: "Rewrites a snapshot that no longer matches the issue, which is otherwise refused.",
22575
+ description: "Rebuilds a snapshot that no longer matches the issue without asking; the old copy moves under" + " `previous/`.",
22281
22576
  type: "boolean"
22282
22577
  },
22283
22578
  {
@@ -22337,8 +22632,8 @@ var wrapped2 = wrapPhaseZeroCommand({
22337
22632
  var create_default2 = endingWith(wrapped2);
22338
22633
 
22339
22634
  // src/commands/plan/show.ts
22340
- import { readFileSync as readFileSync28 } from "fs";
22341
- import { join as join34 } from "path";
22635
+ import { readFileSync as readFileSync29 } from "fs";
22636
+ import { join as join35 } from "path";
22342
22637
  var USAGE19 = "rafa plan show <stub> [--tracker]";
22343
22638
  var COMMAND = "rafa plan show";
22344
22639
  function readTrackerFlag(value) {
@@ -22356,10 +22651,10 @@ function showPlan(plans, stub, tracker) {
22356
22651
  throw new CommandExit(1, `\u274C "${stub}" is no plan stub: a stub is letters, digits, ".", "_" and "-"`);
22357
22652
  }
22358
22653
  const name2 = planFileName(stub, tracker);
22359
- const file = join34(plans.path, name2);
22654
+ const file = join35(plans.path, name2);
22360
22655
  if (!isFile(file))
22361
- throw new CommandExit(1, missingText(stub, tracker, join34(plans.label, name2)));
22362
- const model = parsePlan(readFileSync28(file, "utf8"));
22656
+ throw new CommandExit(1, missingText(stub, tracker, join35(plans.label, name2)));
22657
+ const model = parsePlan(readFileSync29(file, "utf8"));
22363
22658
  const { header } = model;
22364
22659
  return {
22365
22660
  stub,
@@ -22382,7 +22677,7 @@ function taskLine2(task) {
22382
22677
  return ` ${checkbox(task.status)} ${task.text}`;
22383
22678
  }
22384
22679
  function renderShownPlan(shown2, dirLabel) {
22385
- const relative9 = join34(dirLabel, planFileName(shown2.stub, shown2.tracker));
22680
+ const relative9 = join35(dirLabel, planFileName(shown2.stub, shown2.tracker));
22386
22681
  const fileLabel = shown2.tracker ? "Tracker" : "File";
22387
22682
  const lines = [`Plan: ${shown2.stub}`, `${fileLabel}: ${relative9}`];
22388
22683
  if (shown2.header.issue !== null)
@@ -22801,11 +23096,11 @@ function createPrListCommand(seams = DEFAULT_PR_SEAMS) {
22801
23096
  var list_default7 = createPrListCommand();
22802
23097
 
22803
23098
  // src/commands/pr/merge.ts
22804
- import { existsSync as existsSync29, readFileSync as readFileSync30 } from "fs";
22805
- import { join as join36 } from "path";
23099
+ import { existsSync as existsSync30, readFileSync as readFileSync31 } from "fs";
23100
+ import { join as join37 } from "path";
22806
23101
 
22807
23102
  // src/board/roadmap-tick.ts
22808
- var PREFIX16 = "board roadmap";
23103
+ var PREFIX18 = "board roadmap";
22809
23104
  var REPO_PATH4 = "{owner}/{repo}";
22810
23105
  var TICK_ATTEMPTS = 2;
22811
23106
  var UNTICKED = /\[ \]/u;
@@ -22856,17 +23151,17 @@ function bodyOf(stdout, command) {
22856
23151
  try {
22857
23152
  payload = JSON.parse(stdout);
22858
23153
  } catch (error) {
22859
- throw new Error(`${PREFIX16}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
23154
+ throw new Error(`${PREFIX18}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
22860
23155
  }
22861
23156
  const body = isMapping(payload) ? payload["body"] : null;
22862
23157
  if (typeof body !== "string") {
22863
- throw new Error(`${PREFIX16}: ${command} answered body as ${describeValue(body)}, expected a string`);
23158
+ throw new Error(`${PREFIX18}: ${command} answered body as ${describeValue(body)}, expected a string`);
22864
23159
  }
22865
23160
  return body;
22866
23161
  }
22867
23162
  function issueSegment(value, member) {
22868
23163
  if (!Number.isSafeInteger(value) || value < 1) {
22869
- throw new TypeError(`${PREFIX16}: ${member} refused issue number ${describeValue(value)}, expected a positive whole number`);
23164
+ throw new TypeError(`${PREFIX18}: ${member} refused issue number ${describeValue(value)}, expected a positive whole number`);
22870
23165
  }
22871
23166
  return String(value);
22872
23167
  }
@@ -22876,23 +23171,23 @@ function createGhRoadmapBody(options) {
22876
23171
  return Object.freeze({
22877
23172
  read: async (issue3) => {
22878
23173
  const path6 = pathOf(issue3, "read");
22879
- const result = await gh([path6]);
23174
+ const result = await gh(["api", path6]);
22880
23175
  if (!result.ok)
22881
- throw new Error(`${PREFIX16}: ${detailOf10(result, `gh api ${path6}`)}`);
23176
+ throw new Error(`${PREFIX18}: ${detailOf10(result, `gh api ${path6}`)}`);
22882
23177
  return bodyOf(result.stdout, `gh api ${path6}`);
22883
23178
  },
22884
23179
  write: async (issue3, body) => {
22885
23180
  const path6 = pathOf(issue3, "write");
22886
- const result = await gh([path6, "-X", "PATCH", "-f", `body=${body}`]);
23181
+ const result = await gh(["api", path6, "-X", "PATCH", "-f", `body=${body}`]);
22887
23182
  const command = `gh api ${path6} -X PATCH -f body=<body>`;
22888
23183
  if (!result.ok)
22889
- throw new Error(`${PREFIX16}: ${detailOf10(result, command)}`);
23184
+ throw new Error(`${PREFIX18}: ${detailOf10(result, command)}`);
22890
23185
  return bodyOf(result.stdout, command);
22891
23186
  }
22892
23187
  });
22893
23188
  }
22894
23189
  function conflictProblem(issue3) {
22895
- return `${PREFIX16}: issue #${String(issue3)} answered a body other than the one that was written,` + " so somebody edited it in between";
23190
+ return `${PREFIX18}: issue #${String(issue3)} answered a body other than the one that was written,` + " so somebody edited it in between";
22896
23191
  }
22897
23192
  async function attemptTick(roadmap, issues, board, attempt4) {
22898
23193
  let edit;
@@ -22957,17 +23252,17 @@ function tickSentence(result) {
22957
23252
  import {
22958
23253
  chmodSync,
22959
23254
  copyFileSync as copyFileSync2,
22960
- existsSync as existsSync28,
22961
- mkdirSync as mkdirSync11,
22962
- readdirSync as readdirSync9,
22963
- readFileSync as readFileSync29,
23255
+ existsSync as existsSync29,
23256
+ mkdirSync as mkdirSync12,
23257
+ readdirSync as readdirSync10,
23258
+ readFileSync as readFileSync30,
22964
23259
  realpathSync as realpathSync5,
22965
23260
  renameSync as renameSync3,
22966
23261
  rmSync as rmSync2,
22967
- statSync as statSync15,
23262
+ statSync as statSync17,
22968
23263
  symlinkSync
22969
23264
  } from "fs";
22970
- import { basename as basename11, delimiter as delimiter3, dirname as dirname13, join as join35, relative as relative9, resolve as resolve17 } from "path";
23265
+ import { basename as basename12, delimiter as delimiter3, dirname as dirname13, join as join36, relative as relative9, resolve as resolve19 } from "path";
22971
23266
  var LINK_NAME = "rafa";
22972
23267
  var FORCE_FLAG = "--force";
22973
23268
  var EXIT_DONE = 0;
@@ -23028,20 +23323,20 @@ function runtimeRefusalLines(runtimeDir, version2) {
23028
23323
  ];
23029
23324
  }
23030
23325
  function listTrackers(repoRoot, planDir) {
23031
- const dir = resolve17(repoRoot, planDir);
23032
- return entryNames(dir).filter((entry) => TRACKER_NAME.test(entry)).sort((a, b) => a.localeCompare(b)).map((entry) => join35(dir, entry)).filter((path6) => statSync15(path6).isFile()).map((path6) => relative9(repoRoot, path6));
23326
+ const dir = resolve19(repoRoot, planDir);
23327
+ return entryNames(dir).filter((entry) => TRACKER_NAME.test(entry)).sort((a, b) => a.localeCompare(b)).map((entry) => join36(dir, entry)).filter((path6) => statSync17(path6).isFile()).map((path6) => relative9(repoRoot, path6));
23033
23328
  }
23034
23329
  function openTrackers(repoRoot, planDir) {
23035
23330
  return listTrackers(repoRoot, planDir).flatMap((path6) => {
23036
- const task = findNextTask(readFileSync29(join35(repoRoot, path6), "utf8"));
23331
+ const task = findNextTask(readFileSync30(join36(repoRoot, path6), "utf8"));
23037
23332
  return task ? [{ path: path6, task }] : [];
23038
23333
  });
23039
23334
  }
23040
23335
  function readManifestVersion2(repoRoot) {
23041
- const manifest = JSON.parse(readFileSync29(join35(repoRoot, "package.json"), "utf8"));
23336
+ const manifest = JSON.parse(readFileSync30(join36(repoRoot, "package.json"), "utf8"));
23042
23337
  const record = typeof manifest === "object" && manifest !== null ? manifest : {};
23043
23338
  if (record["name"] !== name) {
23044
- throw new Error(`${join35(repoRoot, "package.json")} names ${JSON.stringify(record["name"])}, not ${name}: this is no rafa checkout`);
23339
+ throw new Error(`${join36(repoRoot, "package.json")} names ${JSON.stringify(record["name"])}, not ${name}: this is no rafa checkout`);
23045
23340
  }
23046
23341
  const version2 = record["version"];
23047
23342
  if (typeof version2 !== "string" || !VERSION_SHAPE.test(version2)) {
@@ -23050,12 +23345,12 @@ function readManifestVersion2(repoRoot) {
23050
23345
  return version2;
23051
23346
  }
23052
23347
  function copyTree(from, to) {
23053
- mkdirSync11(to, { recursive: true });
23348
+ mkdirSync12(to, { recursive: true });
23054
23349
  let copied = 0;
23055
- const entries = readdirSync9(from, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
23350
+ const entries = readdirSync10(from, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
23056
23351
  for (const entry of entries) {
23057
- const source = join35(from, entry.name);
23058
- const target = join35(to, entry.name);
23352
+ const source = join36(from, entry.name);
23353
+ const target = join36(to, entry.name);
23059
23354
  if (entry.isDirectory()) {
23060
23355
  copied += copyTree(source, target);
23061
23356
  } else if (entry.isFile()) {
@@ -23080,7 +23375,7 @@ function replaceTree(from, to) {
23080
23375
  }
23081
23376
  }
23082
23377
  function swapIn(staging, to) {
23083
- if (!existsSync28(to)) {
23378
+ if (!existsSync29(to)) {
23084
23379
  renameSync3(staging, to);
23085
23380
  return;
23086
23381
  }
@@ -23096,7 +23391,7 @@ function swapIn(staging, to) {
23096
23391
  rmSync2(outgoing, { recursive: true, force: true });
23097
23392
  }
23098
23393
  function relink(linkPath, target) {
23099
- mkdirSync11(dirname13(linkPath), { recursive: true });
23394
+ mkdirSync12(dirname13(linkPath), { recursive: true });
23100
23395
  const temporary = temporaryName(linkPath);
23101
23396
  rmSync2(temporary, { force: true });
23102
23397
  try {
@@ -23150,20 +23445,20 @@ function installRuntime(seams, options = {}) {
23150
23445
  }
23151
23446
  function runInstall(seams, options) {
23152
23447
  const { repoRoot, home, log } = seams;
23153
- const runtimeRoot = join35(home, RUNTIME_SUBDIR);
23154
- const linkPath = join35(home, RAFA_BIN_DIR, LINK_NAME);
23448
+ const runtimeRoot = join36(home, RUNTIME_SUBDIR);
23449
+ const linkPath = join36(home, RAFA_BIN_DIR, LINK_NAME);
23155
23450
  log(`repo root: ${repoRoot}`);
23156
23451
  log(`runtime root: ${runtimeRoot}`);
23157
23452
  log(`link: ${linkPath}`);
23158
23453
  const version2 = inStage("manifest", () => readManifestVersion2(repoRoot));
23159
- const planDir = inStage("config", () => resolve17(repoRoot, loadConfig({ root: repoRoot, home }, {}, seams.warn).config.planDir));
23454
+ const planDir = inStage("config", () => resolve19(repoRoot, loadConfig({ root: repoRoot, home }, {}, seams.warn).config.planDir));
23160
23455
  log(`plan dir: ${planDir}`);
23161
23456
  const open = inStage("trackers", () => openTrackers(repoRoot, planDir));
23162
23457
  if (open.length > 0)
23163
23458
  return { kind: "refused", reason: "trackers", planDir, trackers: open };
23164
- const distDir = join35(repoRoot, "dist");
23165
- const runtimeDir = join35(runtimeRoot, version2);
23166
- const installed = existsSync28(runtimeDir);
23459
+ const distDir = join36(repoRoot, "dist");
23460
+ const runtimeDir = join36(runtimeRoot, version2);
23461
+ const installed = existsSync29(runtimeDir);
23167
23462
  if (installed && options.force !== true) {
23168
23463
  return { kind: "refused", reason: "runtime-exists", version: version2, runtimeDir };
23169
23464
  }
@@ -23171,13 +23466,13 @@ function runInstall(seams, options) {
23171
23466
  const code = inStage("build", () => seams.build(repoRoot));
23172
23467
  if (code !== 0)
23173
23468
  throw new StageFailure("build", `the build exited ${code}`);
23174
- if (!existsSync28(join35(distDir, RUNTIME_ENTRY))) {
23175
- throw new StageFailure("build", `the build exited 0 and left no ${join35(distDir, RUNTIME_ENTRY)}`);
23469
+ if (!existsSync29(join36(distDir, RUNTIME_ENTRY))) {
23470
+ throw new StageFailure("build", `the build exited 0 and left no ${join36(distDir, RUNTIME_ENTRY)}`);
23176
23471
  }
23177
23472
  log(installed ? `copying ${distDir} over ${runtimeDir}, replacing it whole` : `copying ${distDir} into ${runtimeDir}`);
23178
23473
  const copied = inStage("copy", () => replaceTree(distDir, runtimeDir));
23179
23474
  log(`copied ${copied} file(s)`);
23180
- const resolved = inStage("link", () => relink(linkPath, join35(runtimeDir, RUNTIME_ENTRY)));
23475
+ const resolved = inStage("link", () => relink(linkPath, join36(runtimeDir, RUNTIME_ENTRY)));
23181
23476
  log(`${linkPath} resolves to ${resolved}`);
23182
23477
  return { kind: "done", version: version2, runtimeDir, linkPath, resolved, copied };
23183
23478
  }
@@ -23192,7 +23487,7 @@ function inStage(stage, run) {
23192
23487
  }
23193
23488
  function entryNames(dir) {
23194
23489
  try {
23195
- return readdirSync9(dir);
23490
+ return readdirSync10(dir);
23196
23491
  } catch (err) {
23197
23492
  if (typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT")
23198
23493
  return [];
@@ -23203,7 +23498,7 @@ function replaceFile(source, target) {
23203
23498
  const temporary = temporaryName(target);
23204
23499
  try {
23205
23500
  copyFileSync2(source, temporary);
23206
- chmodSync(temporary, statSync15(source).mode & 4095);
23501
+ chmodSync(temporary, statSync17(source).mode & 4095);
23207
23502
  renameSync3(temporary, target);
23208
23503
  } catch (err) {
23209
23504
  rmSync2(temporary, { force: true });
@@ -23211,7 +23506,7 @@ function replaceFile(source, target) {
23211
23506
  }
23212
23507
  }
23213
23508
  function temporaryName(path6) {
23214
- return join35(dirname13(path6), `.${basename11(path6)}.snapshot-${process.pid}`);
23509
+ return join36(dirname13(path6), `.${basename12(path6)}.snapshot-${process.pid}`);
23215
23510
  }
23216
23511
 
23217
23512
  // src/commands/pr/merge-followups.ts
@@ -23502,13 +23797,13 @@ function remoteHoldsBranch(git, branch, warn) {
23502
23797
  }
23503
23798
  function textOf3(path6) {
23504
23799
  try {
23505
- return readFileSync30(path6, "utf8");
23800
+ return readFileSync31(path6, "utf8");
23506
23801
  } catch {
23507
23802
  return "";
23508
23803
  }
23509
23804
  }
23510
23805
  function followUpsFor(pr, git) {
23511
- const facts = readPackageFacts(textOf3(join36(pr.project.root, "package.json")));
23806
+ const facts = readPackageFacts(textOf3(join37(pr.project.root, "package.json")));
23512
23807
  if (facts.version === null)
23513
23808
  return [];
23514
23809
  const tags = git(["tag", "--list", versionTag(facts.version)]);
@@ -23516,7 +23811,7 @@ function followUpsFor(pr, git) {
23516
23811
  version: facts.version,
23517
23812
  tagged: tags.ok && tags.stdout.trim() !== "",
23518
23813
  rafaCheckout: facts.rafaCheckout,
23519
- runtimeInstalled: existsSync29(join36(pr.project.home, RUNTIME_SUBDIR, facts.version))
23814
+ runtimeInstalled: existsSync30(join37(pr.project.home, RUNTIME_SUBDIR, facts.version))
23520
23815
  });
23521
23816
  }
23522
23817
  function openGh(pr, seams) {
@@ -23767,7 +24062,7 @@ var COLUMN = "\t";
23767
24062
  var BOM = "\uFEFF";
23768
24063
  var TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z /;
23769
24064
  var COLOUR = new RegExp(`(?:${String.fromCharCode(27)}|\\^\\[)\\[[0-9;]*m`, "g");
23770
- var PREFIX17 = "pr triage evidence";
24065
+ var PREFIX19 = "pr triage evidence";
23771
24066
  function named2(value) {
23772
24067
  return value === "" ? undefined : value;
23773
24068
  }
@@ -23833,7 +24128,7 @@ function readCap(value) {
23833
24128
  if (value === undefined)
23834
24129
  return FAILED_LOG_TAIL_LINES;
23835
24130
  if (!Number.isSafeInteger(value) || value < 1) {
23836
- throw new TypeError(`${PREFIX17}: readFailedLog refused a line cap ${describeValue(value)},` + " expected a positive whole number");
24131
+ throw new TypeError(`${PREFIX19}: readFailedLog refused a line cap ${describeValue(value)},` + " expected a positive whole number");
23837
24132
  }
23838
24133
  return value;
23839
24134
  }
@@ -24720,8 +25015,8 @@ function describeAge(updatedAt, now) {
24720
25015
  return `${plural4(hours, "hour", "hours")} ago`;
24721
25016
  return `${plural4(Math.floor(age / DAY_MS2), "day", "days")} ago`;
24722
25017
  }
24723
- function triageCommand(number, resolve18 = false) {
24724
- return resolve18 ? `rafa pr triage ${number} --resolve` : `rafa pr triage ${number}`;
25018
+ function triageCommand(number, resolve20 = false) {
25019
+ return resolve20 ? `rafa pr triage ${number} --resolve` : `rafa pr triage ${number}`;
24725
25020
  }
24726
25021
  function joinNumbers(pulls) {
24727
25022
  const names = pulls.map((pull) => `#${pull.number}`);
@@ -24732,14 +25027,14 @@ function joinNumbers(pulls) {
24732
25027
  function byNumber(pulls) {
24733
25028
  return Object.freeze([...pulls].sort((left, right) => left.number - right.number));
24734
25029
  }
24735
- function skipped(pull, now, resolve18) {
25030
+ function skipped(pull, now, resolve20) {
24736
25031
  return Object.freeze({
24737
25032
  number: pull.number,
24738
25033
  title: pull.title,
24739
25034
  updatedAt: pull.updatedAt,
24740
25035
  age: describeAge(pull.updatedAt, now),
24741
25036
  fresh: isFreshCandidate(pull.updatedAt, now),
24742
- command: triageCommand(pull.number, resolve18)
25037
+ command: triageCommand(pull.number, resolve20)
24743
25038
  });
24744
25039
  }
24745
25040
  function skippedLine(one) {
@@ -24783,15 +25078,15 @@ function listReading(rest, count) {
24783
25078
  return listing2("list", Object.freeze([]), rest, headline);
24784
25079
  }
24785
25080
  function selectTriagePullRequests(input) {
24786
- const resolve18 = input.resolve === true;
25081
+ const resolve20 = input.resolve === true;
24787
25082
  const { current, now } = input;
24788
25083
  if (current !== null) {
24789
25084
  return plain("branch", Object.freeze([current]), `assessing #${current.number}, the pull request open on ${current.headRefName}`);
24790
25085
  }
24791
25086
  const candidates = byNumber(input.candidates);
24792
25087
  const count = candidates.length;
24793
- const lines = candidates.map((pull) => skipped(pull, now, resolve18));
24794
- if (resolve18 && count > 1)
25088
+ const lines = candidates.map((pull) => skipped(pull, now, resolve20));
25089
+ if (resolve20 && count > 1)
24795
25090
  return refusal9(lines, count);
24796
25091
  if (count === 0) {
24797
25092
  return plain("none", Object.freeze([]), "no red pull request to triage, and no pull request on the current branch");
@@ -25093,11 +25388,11 @@ function renderTriages(readings) {
25093
25388
  var BUDGET_KEY = "budget";
25094
25389
  var TASK_LINE2 = /^- \[[^\]]*\] /;
25095
25390
  var TRAILING_BLOCK = /\{([^{}]*)\}$/;
25096
- var PREFIX18 = "pr triage --resolve budget";
25391
+ var PREFIX20 = "pr triage --resolve budget";
25097
25392
  function budgetEntry(usd) {
25098
25393
  const spelled = String(usd);
25099
25394
  if (parseBudgetUsd(spelled) === null) {
25100
- throw new TypeError(`${PREFIX18}: refused an amount of ${JSON.stringify(usd)}, expected US dollars above zero` + " with at most six whole digits and six decimal places");
25395
+ throw new TypeError(`${PREFIX20}: refused an amount of ${JSON.stringify(usd)}, expected US dollars above zero` + " with at most six whole digits and six decimal places");
25101
25396
  }
25102
25397
  return `${BUDGET_KEY}=${spelled}`;
25103
25398
  }
@@ -25126,8 +25421,8 @@ function withTaskBudget(plan2, usd) {
25126
25421
  }
25127
25422
 
25128
25423
  // src/pr/plans/load.ts
25129
- import { existsSync as existsSync30, readFileSync as readFileSync31 } from "fs";
25130
- import { dirname as dirname14, join as join37 } from "path";
25424
+ import { existsSync as existsSync31, readFileSync as readFileSync32 } from "fs";
25425
+ import { dirname as dirname14, join as join38 } from "path";
25131
25426
  import { fileURLToPath as fileURLToPath4 } from "url";
25132
25427
  var MODULE_DIR2 = dirname14(fileURLToPath4(import.meta.url));
25133
25428
  var PINNED_PLANS_DIRNAME = "plans";
@@ -25144,8 +25439,8 @@ function hasPinnedPlan(triageClass) {
25144
25439
  function pinnedPlanCandidates(moduleDir, triageClass) {
25145
25440
  const name2 = pinnedPlanFileName(triageClass);
25146
25441
  return [
25147
- join37(moduleDir, PINNED_PLANS_DIRNAME, name2),
25148
- join37(moduleDir, name2)
25442
+ join38(moduleDir, PINNED_PLANS_DIRNAME, name2),
25443
+ join38(moduleDir, name2)
25149
25444
  ];
25150
25445
  }
25151
25446
  function readPinnedPlan(triageClass, lookup = {}) {
@@ -25153,11 +25448,11 @@ function readPinnedPlan(triageClass, lookup = {}) {
25153
25448
  throw new Error(`No pinned resolve plan ships for ${triageClass}; ` + `one ships for ${PINNED_PLAN_CLASSES.join(", ")}`);
25154
25449
  }
25155
25450
  const candidates = pinnedPlanCandidates(lookup.moduleDir ?? MODULE_DIR2, triageClass);
25156
- const found = candidates.find((candidate) => existsSync30(candidate));
25451
+ const found = candidates.find((candidate) => existsSync31(candidate));
25157
25452
  if (found === undefined) {
25158
25453
  throw new Error(`The pinned resolve plan for ${triageClass} is missing: ` + `no file at ${candidates.join(" or ")}`);
25159
25454
  }
25160
- return readFileSync31(found, "utf8");
25455
+ return readFileSync32(found, "utf8");
25161
25456
  }
25162
25457
  var SLOT_PATTERN2 = /\{[A-Z][A-Z0-9_]*\}/g;
25163
25458
  var CONFLICT_SENTENCE_SLOT = "CONFLICT_SENTENCE";
@@ -25220,12 +25515,12 @@ var ATTEMPT_STOPS = Object.freeze([
25220
25515
  "cap",
25221
25516
  "repeat"
25222
25517
  ]);
25223
- var PREFIX19 = "pr triage attempts";
25518
+ var PREFIX21 = "pr triage attempts";
25224
25519
  var WHITESPACE2 = /\s+/g;
25225
25520
  var NO_STEP_KEY = "";
25226
25521
  function readCap2(maxAttempts) {
25227
25522
  if (!Number.isSafeInteger(maxAttempts) || maxAttempts < 1) {
25228
- throw new TypeError(`${PREFIX19}: refused a cap of ${JSON.stringify(maxAttempts)},` + " expected a positive whole number");
25523
+ throw new TypeError(`${PREFIX21}: refused a cap of ${JSON.stringify(maxAttempts)},` + " expected a positive whole number");
25229
25524
  }
25230
25525
  return maxAttempts;
25231
25526
  }
@@ -25297,13 +25592,13 @@ function readAttemptRepeat(input) {
25297
25592
  }
25298
25593
 
25299
25594
  // src/pr/worktree.ts
25300
- import { existsSync as existsSync31, realpathSync as realpathSync6 } from "fs";
25301
- import { join as join38 } from "path";
25302
- var WORKTREES_SUBDIR = join38(".rafa", "worktrees");
25595
+ import { existsSync as existsSync32, realpathSync as realpathSync6 } from "fs";
25596
+ import { join as join39 } from "path";
25597
+ var WORKTREES_SUBDIR = join39(".rafa", "worktrees");
25303
25598
  var WORKTREE_PREFIX = "pr-";
25304
25599
  var REFUSAL_PREFIX3 = "rafa pr triage --resolve refuses";
25305
25600
  function resolveWorktreePath(home, number) {
25306
- return join38(home, WORKTREES_SUBDIR, `${WORKTREE_PREFIX}${number}`);
25601
+ return join39(home, WORKTREES_SUBDIR, `${WORKTREE_PREFIX}${number}`);
25307
25602
  }
25308
25603
  function crossRepositoryRefusal(pr) {
25309
25604
  if (!pr.isCrossRepository)
@@ -25346,7 +25641,7 @@ function removeResolveWorktree(git, path6) {
25346
25641
  return runStep(git, removeWorktreeStep(path6));
25347
25642
  }
25348
25643
  function pathForms(path6) {
25349
- if (!existsSync31(path6))
25644
+ if (!existsSync32(path6))
25350
25645
  return [path6];
25351
25646
  return [path6, realpathSync6(path6)];
25352
25647
  }
@@ -25359,20 +25654,20 @@ function worktreeAt(git, path6) {
25359
25654
  }
25360
25655
 
25361
25656
  // src/commands/pr/resolve-loop.ts
25362
- import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync15 } from "fs";
25363
- import { join as join39 } from "path";
25364
- var RESOLVE_SUBDIR = join39(".rafa", "resolve");
25657
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync15 } from "fs";
25658
+ import { join as join40 } from "path";
25659
+ var RESOLVE_SUBDIR = join40(".rafa", "resolve");
25365
25660
  var RUN_PREFIX = "pr-";
25366
25661
  var ATTEMPT_PREFIX = "attempt-";
25367
25662
  var LOOP_WORDS = Object.freeze(["loop", "start"]);
25368
25663
  var CHILD_OUTPUT = "text";
25369
25664
  function resolveRunDir(home, number, attempt4) {
25370
- return join39(home, RESOLVE_SUBDIR, `${RUN_PREFIX}${number}`, `${ATTEMPT_PREFIX}${attempt4}`);
25665
+ return join40(home, RESOLVE_SUBDIR, `${RUN_PREFIX}${number}`, `${ATTEMPT_PREFIX}${attempt4}`);
25371
25666
  }
25372
25667
  function writeResolvePlan(write) {
25373
25668
  const dir = resolveRunDir(write.home, write.number, write.attempt);
25374
- mkdirSync12(dir, { recursive: true });
25375
- const path6 = join39(dir, pinnedPlanFileName(write.triageClass));
25669
+ mkdirSync13(dir, { recursive: true });
25670
+ const path6 = join40(dir, pinnedPlanFileName(write.triageClass));
25376
25671
  writeFileSync15(path6, write.plan, "utf8");
25377
25672
  return path6;
25378
25673
  }
@@ -25772,16 +26067,16 @@ async function redPullRequests(pr) {
25772
26067
  }
25773
26068
  return red;
25774
26069
  }
25775
- async function selectTargets(pr, warn, now, resolve18) {
26070
+ async function selectTargets(pr, warn, now, resolve20) {
25776
26071
  const branch = readBranchOrNone(pr, warn);
25777
26072
  const current = branch === null ? null : await onProvider(`read the open pull request for the branch "${branch}"`, () => pr.pulls.findOpen(branch));
25778
26073
  if (current !== null)
25779
- return selectTriagePullRequests({ current, candidates: [], now, resolve: resolve18 });
26074
+ return selectTriagePullRequests({ current, candidates: [], now, resolve: resolve20 });
25780
26075
  return selectTriagePullRequests({
25781
26076
  current: null,
25782
26077
  candidates: await redPullRequests(pr),
25783
26078
  now,
25784
- resolve: resolve18
26079
+ resolve: resolve20
25785
26080
  });
25786
26081
  }
25787
26082
  async function detailOf11(pr, number) {
@@ -25902,7 +26197,7 @@ async function runTriage(context, seams) {
25902
26197
  }
25903
26198
  const numbers = asked === null ? (selection?.assess ?? []).map((one) => one.number) : [asked];
25904
26199
  const readings = [];
25905
- let resolve18 = null;
26200
+ let resolve20 = null;
25906
26201
  for (const number of numbers) {
25907
26202
  const assess = () => assessOne({
25908
26203
  pr,
@@ -25918,7 +26213,7 @@ async function runTriage(context, seams) {
25918
26213
  readings.push(reading2);
25919
26214
  continue;
25920
26215
  }
25921
- resolve18 = await resolvePullRequest({
26216
+ resolve20 = await resolvePullRequest({
25922
26217
  trust: {
25923
26218
  permissions,
25924
26219
  trustedAuthors: pr.trustedAuthors,
@@ -25939,16 +26234,16 @@ async function runTriage(context, seams) {
25939
26234
  ...seams.clock === undefined ? {} : { clock: seams.clock },
25940
26235
  ...seams.sleep === undefined ? {} : { sleep: seams.sleep }
25941
26236
  });
25942
- readings.push(resolve18.reading);
26237
+ readings.push(resolve20.reading);
25943
26238
  }
25944
26239
  const text2 = [
25945
26240
  ...selection === null ? [] : [selection.message],
25946
26241
  ...readings.length === 0 ? [] : [renderTriages(readings)],
25947
- ...resolve18 === null ? [] : resolve18.lines
26242
+ ...resolve20 === null ? [] : resolve20.lines
25948
26243
  ].join(`
25949
26244
 
25950
26245
  `);
25951
- return { selection, readings, resolve: resolve18, text: text2, exitCode: resolve18?.exitCode ?? 0 };
26246
+ return { selection, readings, resolve: resolve20, text: text2, exitCode: resolve20?.exitCode ?? 0 };
25952
26247
  }
25953
26248
  function createPrTriageCommand(seams = DEFAULT_TRIAGE_SEAMS) {
25954
26249
  const command = {
@@ -26236,8 +26531,8 @@ function createPrWaitCommand(seams = DEFAULT_WAIT_SEAMS) {
26236
26531
  var wait_default = createPrWaitCommand();
26237
26532
 
26238
26533
  // src/commands/release/status.ts
26239
- import { existsSync as existsSync32, readdirSync as readdirSync10, readFileSync as readFileSync32 } from "fs";
26240
- import { join as join40 } from "path";
26534
+ import { existsSync as existsSync33, readdirSync as readdirSync11, readFileSync as readFileSync33 } from "fs";
26535
+ import { join as join41 } from "path";
26241
26536
  var RELEASE_STATUS_USAGE = "rafa release status [--plan=<stub>]";
26242
26537
  var UNREADABLE2 = "?";
26243
26538
  var NOTHING = "none";
@@ -26338,13 +26633,13 @@ function untaggedVersions(released, tags) {
26338
26633
  }
26339
26634
  function textOf4(path6) {
26340
26635
  try {
26341
- return readFileSync32(path6, "utf8");
26636
+ return readFileSync33(path6, "utf8");
26342
26637
  } catch {
26343
26638
  return null;
26344
26639
  }
26345
26640
  }
26346
26641
  function readVersionFile(root, configured) {
26347
- const resolved = join40(root, configured);
26642
+ const resolved = join41(root, configured);
26348
26643
  const text2 = textOf4(resolved);
26349
26644
  if (text2 === null) {
26350
26645
  return { path: configured, version: null, problem: `the version file could not be read at ${resolved}` };
@@ -26361,7 +26656,7 @@ function readTags(git) {
26361
26656
  return { tags, latest: tags[0] ?? null, problem: null };
26362
26657
  }
26363
26658
  function readUntagged(root, configured, tags) {
26364
- const resolved = join40(root, configured);
26659
+ const resolved = join41(root, configured);
26365
26660
  const text2 = textOf4(resolved);
26366
26661
  if (text2 === null) {
26367
26662
  return {
@@ -26380,11 +26675,11 @@ function readBranch2(git) {
26380
26675
  return result.ok && branch !== "" && branch !== "HEAD" ? branch : null;
26381
26676
  }
26382
26677
  function planStubsUnder(root, planDir) {
26383
- const resolved = join40(root, planDir);
26384
- if (!existsSync32(resolved))
26678
+ const resolved = join41(root, planDir);
26679
+ if (!existsSync33(resolved))
26385
26680
  return [];
26386
26681
  try {
26387
- return planStubsFromFileNames(readdirSync10(resolved));
26682
+ return planStubsFromFileNames(readdirSync11(resolved));
26388
26683
  } catch {
26389
26684
  return [];
26390
26685
  }
@@ -26582,8 +26877,8 @@ function createReleaseStatusCommand(seams = DEFAULT_RELEASE_SEAMS) {
26582
26877
  var status_default2 = createReleaseStatusCommand();
26583
26878
 
26584
26879
  // src/commands/release/tag.ts
26585
- import { readFileSync as readFileSync33 } from "fs";
26586
- import { join as join41 } from "path";
26880
+ import { readFileSync as readFileSync34 } from "fs";
26881
+ import { join as join42 } from "path";
26587
26882
  var RELEASE_TAG_USAGE = "rafa release tag";
26588
26883
  var DEFAULT_RELEASE_BRANCH = "main";
26589
26884
  var DEFAULT_REGISTRY = "https://registry.npmjs.org";
@@ -26602,13 +26897,13 @@ function readBranch3(git) {
26602
26897
  }
26603
26898
  function textOf5(path6) {
26604
26899
  try {
26605
- return readFileSync33(path6, "utf8");
26900
+ return readFileSync34(path6, "utf8");
26606
26901
  } catch {
26607
26902
  return null;
26608
26903
  }
26609
26904
  }
26610
26905
  function readVersion(root, configured) {
26611
- const resolved = join41(root, configured);
26906
+ const resolved = join42(root, configured);
26612
26907
  const text2 = textOf5(resolved);
26613
26908
  if (text2 === null) {
26614
26909
  return {
@@ -26622,7 +26917,7 @@ function readVersion(root, configured) {
26622
26917
  return version2 === null ? { path: configured, text: text2, version: null, problem: `${resolved} declares no version this can read` } : { path: configured, text: text2, version: version2, problem: null };
26623
26918
  }
26624
26919
  function readNewestRelease(root, configured) {
26625
- const resolved = join41(root, configured);
26920
+ const resolved = join42(root, configured);
26626
26921
  const text2 = textOf5(resolved);
26627
26922
  if (text2 === null) {
26628
26923
  return { path: configured, version: null, problem: `the changelog could not be read at ${resolved}` };
@@ -26887,17 +27182,17 @@ function createSelfUpdateCommand(seams = DEFAULT_SELF_UPDATE_SEAMS) {
26887
27182
  var self_update_default = createSelfUpdateCommand();
26888
27183
 
26889
27184
  // src/commands/skill/backfill.ts
26890
- import { statSync as statSync17 } from "fs";
26891
- import { join as join46, resolve as resolve20 } from "path";
27185
+ import { statSync as statSync19 } from "fs";
27186
+ import { join as join47, resolve as resolve22 } from "path";
26892
27187
 
26893
27188
  // src/backfill/backup.ts
26894
- import { copyFileSync as copyFileSync3, existsSync as existsSync33, mkdirSync as mkdirSync13 } from "fs";
26895
- import { dirname as dirname15, isAbsolute as isAbsolute11, join as join43, relative as relative10, resolve as resolve18, sep as sep5 } from "path";
27189
+ import { copyFileSync as copyFileSync3, existsSync as existsSync34, mkdirSync as mkdirSync14 } from "fs";
27190
+ import { dirname as dirname15, isAbsolute as isAbsolute11, join as join44, relative as relative10, resolve as resolve20, sep as sep5 } from "path";
26896
27191
 
26897
27192
  // src/backfill/proposal-file.ts
26898
- import { readdirSync as readdirSync11, readFileSync as readFileSync34 } from "fs";
26899
- import { join as join42 } from "path";
26900
- var BACKFILL_PATH = join42(".rafa", "backfill");
27193
+ import { readdirSync as readdirSync12, readFileSync as readFileSync35 } from "fs";
27194
+ import { join as join43 } from "path";
27195
+ var BACKFILL_PATH = join43(".rafa", "backfill");
26901
27196
  var PROPOSAL_FILE_PREFIX = "proposals-";
26902
27197
  var PROPOSAL_FILE_EXTENSION = ".yaml";
26903
27198
  var SHA256_PATTERN = /^[0-9a-f]{64}$/;
@@ -26923,7 +27218,7 @@ var PROPOSAL_FILE_HEADER = [
26923
27218
  ].join(`
26924
27219
  `);
26925
27220
  function proposalPath(dir, batch) {
26926
- return join42(dir, `${PROPOSAL_FILE_PREFIX}${String(batch).padStart(2, "0")}${PROPOSAL_FILE_EXTENSION}`);
27221
+ return join43(dir, `${PROPOSAL_FILE_PREFIX}${String(batch).padStart(2, "0")}${PROPOSAL_FILE_EXTENSION}`);
26927
27222
  }
26928
27223
  function isProposalFileName(name2) {
26929
27224
  return name2.startsWith(PROPOSAL_FILE_PREFIX) && name2.endsWith(PROPOSAL_FILE_EXTENSION);
@@ -27054,14 +27349,14 @@ function parseProposalFile(text2) {
27054
27349
  function readProposalFiles(dir) {
27055
27350
  let names;
27056
27351
  try {
27057
- names = readdirSync11(dir);
27352
+ names = readdirSync12(dir);
27058
27353
  } catch {
27059
27354
  return [];
27060
27355
  }
27061
27356
  return names.filter((name2) => isProposalFileName(name2)).sort((left, right) => left.localeCompare(right)).map((name2) => {
27062
- const path6 = join42(dir, name2);
27357
+ const path6 = join43(dir, name2);
27063
27358
  try {
27064
- return { path: path6, result: parseProposalFile(readFileSync34(path6, "utf8")) };
27359
+ return { path: path6, result: parseProposalFile(readFileSync35(path6, "utf8")) };
27065
27360
  } catch (error) {
27066
27361
  return { path: path6, result: unreadable2(`the file cannot be read (${error instanceof Error ? error.message : String(error)})`) };
27067
27362
  }
@@ -27069,19 +27364,19 @@ function readProposalFiles(dir) {
27069
27364
  }
27070
27365
 
27071
27366
  // src/backfill/backup.ts
27072
- var BACKUP_PATH = join43(BACKFILL_PATH, "backup");
27367
+ var BACKUP_PATH = join44(BACKFILL_PATH, "backup");
27073
27368
  var BACKUP_KINDS = ["copied", "kept", "tracked", "outside", "missing"];
27074
27369
  function backupDirectory(base) {
27075
- return join43(base, BACKUP_PATH);
27370
+ return join44(base, BACKUP_PATH);
27076
27371
  }
27077
27372
  function isUnder(root, path6) {
27078
- const step2 = relative10(resolve18(root), resolve18(path6));
27373
+ const step2 = relative10(resolve20(root), resolve20(path6));
27079
27374
  return step2 === "" || !step2.startsWith(`..${sep5}`) && step2 !== ".." && !isAbsolute11(step2);
27080
27375
  }
27081
27376
  function backupPathFor(path6, root, backupDir) {
27082
27377
  if (!isUnder(root, path6))
27083
27378
  return null;
27084
- return join43(backupDir, relative10(resolve18(root), resolve18(path6)));
27379
+ return join44(backupDir, relative10(resolve20(root), resolve20(path6)));
27085
27380
  }
27086
27381
  function backupFile(path6, options) {
27087
27382
  if (options.repoRoot !== null && isUnder(options.repoRoot, path6)) {
@@ -27090,11 +27385,11 @@ function backupFile(path6, options) {
27090
27385
  const backup = backupPathFor(path6, options.root, options.backupDir);
27091
27386
  if (backup === null)
27092
27387
  return { path: path6, kind: "outside", backup: null };
27093
- if (!existsSync33(path6))
27388
+ if (!existsSync34(path6))
27094
27389
  return { path: path6, kind: "missing", backup: null };
27095
- if (existsSync33(backup))
27390
+ if (existsSync34(backup))
27096
27391
  return { path: path6, kind: "kept", backup };
27097
- mkdirSync13(dirname15(backup), { recursive: true });
27392
+ mkdirSync14(dirname15(backup), { recursive: true });
27098
27393
  copyFileSync3(path6, backup);
27099
27394
  return { path: path6, kind: "copied", backup };
27100
27395
  }
@@ -27117,8 +27412,8 @@ function countBackups(results) {
27117
27412
  }
27118
27413
 
27119
27414
  // src/backfill/derive.ts
27120
- import { readFileSync as readFileSync35, writeFileSync as writeFileSync16 } from "fs";
27121
- import { basename as basename12 } from "path";
27415
+ import { readFileSync as readFileSync36, writeFileSync as writeFileSync16 } from "fs";
27416
+ import { basename as basename13 } from "path";
27122
27417
 
27123
27418
  // src/demote/classify.ts
27124
27419
  var LEARNED_DIRECTORY = "learned";
@@ -27575,15 +27870,15 @@ function fileChanges(name2, data, body, options) {
27575
27870
  return { changes, notes };
27576
27871
  }
27577
27872
  function planFile(entry, options) {
27578
- if (basename12(entry.path) !== SKILL_FILE) {
27579
- return inert(entry, "skipped", `${basename12(entry.path)} is no ${SKILL_FILE}, so it registers no skill`);
27873
+ if (basename13(entry.path) !== SKILL_FILE) {
27874
+ return inert(entry, "skipped", `${basename13(entry.path)} is no ${SKILL_FILE}, so it registers no skill`);
27580
27875
  }
27581
27876
  if (entry.name === null) {
27582
27877
  return inert(entry, "skipped", "its place implies no skill name, so no stack can be derived from it");
27583
27878
  }
27584
27879
  let original;
27585
27880
  try {
27586
- original = readFileSync35(entry.path, "utf8");
27881
+ original = readFileSync36(entry.path, "utf8");
27587
27882
  } catch (error) {
27588
27883
  return inert(entry, "skipped", `the file cannot be read (${error instanceof Error ? error.message : String(error)})`);
27589
27884
  }
@@ -27627,7 +27922,7 @@ function planDerivation(root, options) {
27627
27922
  function applyFile(action, options) {
27628
27923
  if (action.text === null || action.original === null)
27629
27924
  return action;
27630
- const current = readFileSync35(action.path, "utf8");
27925
+ const current = readFileSync36(action.path, "utf8");
27631
27926
  if (current !== action.original) {
27632
27927
  return {
27633
27928
  ...action,
@@ -27658,7 +27953,7 @@ function applyDerivation(plan2, options) {
27658
27953
  }
27659
27954
 
27660
27955
  // src/backfill/proposal-batch.ts
27661
- import { readFileSync as readFileSync36 } from "fs";
27956
+ import { readFileSync as readFileSync37 } from "fs";
27662
27957
  import { relative as relative11 } from "path";
27663
27958
 
27664
27959
  // src/demote/report.ts
@@ -27957,7 +28252,7 @@ function readCandidate(root, entry) {
27957
28252
  return null;
27958
28253
  let text2;
27959
28254
  try {
27960
- text2 = readFileSync36(entry.path, "utf8");
28255
+ text2 = readFileSync37(entry.path, "utf8");
27961
28256
  } catch {
27962
28257
  return null;
27963
28258
  }
@@ -28063,8 +28358,8 @@ function parseSessionAnswer(stdout) {
28063
28358
  }
28064
28359
 
28065
28360
  // src/backfill/propose.ts
28066
- import { mkdirSync as mkdirSync14, readFileSync as readFileSync37, writeFileSync as writeFileSync17 } from "fs";
28067
- import { join as join44, resolve as resolve19 } from "path";
28361
+ import { mkdirSync as mkdirSync15, readFileSync as readFileSync38, writeFileSync as writeFileSync17 } from "fs";
28362
+ import { join as join45, resolve as resolve21 } from "path";
28068
28363
  var PROPOSAL_ACTION_KINDS = [
28069
28364
  "applied",
28070
28365
  "unchanged",
@@ -28143,7 +28438,7 @@ async function runProposalPass(options) {
28143
28438
  const batches = batchCandidates(candidates);
28144
28439
  const written = [];
28145
28440
  if (batches.length > 0)
28146
- mkdirSync14(options.backfillDir, { recursive: true });
28441
+ mkdirSync15(options.backfillDir, { recursive: true });
28147
28442
  for (const [index, batch] of batches.entries()) {
28148
28443
  const number = index + 1;
28149
28444
  const file = await runProposalBatch(number, batch, options);
@@ -28213,7 +28508,7 @@ function writeRow(path6, row2, original, options) {
28213
28508
  };
28214
28509
  }
28215
28510
  function applyRow(root, row2, options) {
28216
- const path6 = join44(root, ...row2.path.split("/"));
28511
+ const path6 = join45(root, ...row2.path.split("/"));
28217
28512
  if (row2.status === UNANSWERED_ROW) {
28218
28513
  return inert2(path6, row2, "unanswered", row2.note ?? "the row carries no answer");
28219
28514
  }
@@ -28222,7 +28517,7 @@ function applyRow(root, row2, options) {
28222
28517
  }
28223
28518
  let original;
28224
28519
  try {
28225
- original = readFileSync37(path6, "utf8");
28520
+ original = readFileSync38(path6, "utf8");
28226
28521
  } catch {
28227
28522
  return inert2(path6, row2, "refused", "the file the row names is gone");
28228
28523
  }
@@ -28236,7 +28531,7 @@ function fileRefusal(file, root) {
28236
28531
  if (file.status !== REVIEWED_FILE) {
28237
28532
  return `the proposal file is still marked ${file.status}: review it and mark it ${REVIEWED_FILE}`;
28238
28533
  }
28239
- return resolve19(file.skills) === resolve19(root) ? null : `the proposal file names the skills directory ${file.skills}, not ${root}`;
28534
+ return resolve21(file.skills) === resolve21(root) ? null : `the proposal file names the skills directory ${file.skills}, not ${root}`;
28240
28535
  }
28241
28536
  function countProposalActions(actions) {
28242
28537
  const counts = Object.fromEntries(PROPOSAL_ACTION_KINDS.map((kind) => [kind, 0]));
@@ -28250,7 +28545,7 @@ function applyProposals(files, root, options) {
28250
28545
  for (const file of files) {
28251
28546
  const refusal10 = fileRefusal(file, root);
28252
28547
  for (const row2 of file.rows) {
28253
- const action = refusal10 === null ? applyRow(root, row2, options) : inert2(join44(root, ...row2.path.split("/")), row2, "refused", refusal10);
28548
+ const action = refusal10 === null ? applyRow(root, row2, options) : inert2(join45(root, ...row2.path.split("/")), row2, "refused", refusal10);
28254
28549
  actions.push(action);
28255
28550
  if (row2.trigger !== null && action.kind !== "refused" && action.kind !== "unanswered") {
28256
28551
  triggers[row2.name] = row2.trigger;
@@ -28261,13 +28556,13 @@ function applyProposals(files, root, options) {
28261
28556
  }
28262
28557
 
28263
28558
  // src/demote/select.ts
28264
- import { readdirSync as readdirSync12, readFileSync as readFileSync38, realpathSync as realpathSync7, statSync as statSync16 } from "fs";
28265
- import { basename as basename13, dirname as dirname16, join as join45 } from "path";
28559
+ import { readdirSync as readdirSync13, readFileSync as readFileSync39, realpathSync as realpathSync7, statSync as statSync18 } from "fs";
28560
+ import { basename as basename14, dirname as dirname16, join as join46 } from "path";
28266
28561
  var SKILLS_DIRECTORY = "skills";
28267
28562
  var CLAUDE_DIRECTORY = ".claude";
28268
28563
  var AUTO_EXTRACTED_ORIGIN = "auto-extracted";
28269
- var DEMOTED_PATH = join45(".rafa", "demoted");
28270
- var INSTINCTS_PATH = join45(".rafa", "instincts");
28564
+ var DEMOTED_PATH = join46(".rafa", "demoted");
28565
+ var INSTINCTS_PATH = join46(".rafa", "instincts");
28271
28566
  var REPORT_FILE = "report.md";
28272
28567
  function realOrSelf(path6) {
28273
28568
  try {
@@ -28284,25 +28579,25 @@ function samePath(left, right) {
28284
28579
  return resolved === other || resolved.toLowerCase() === other.toLowerCase();
28285
28580
  }
28286
28581
  function resolveDemotionScope(dir, home) {
28287
- if (basename13(dir) !== SKILLS_DIRECTORY)
28582
+ if (basename14(dir) !== SKILLS_DIRECTORY)
28288
28583
  return null;
28289
28584
  const claude = dirname16(dir);
28290
- if (basename13(claude) !== CLAUDE_DIRECTORY)
28585
+ if (basename14(claude) !== CLAUDE_DIRECTORY)
28291
28586
  return null;
28292
28587
  const base = dirname16(claude);
28293
- const demotedDir = join45(base, DEMOTED_PATH);
28588
+ const demotedDir = join46(base, DEMOTED_PATH);
28294
28589
  return {
28295
28590
  scope: samePath(base, home) ? "user" : "project",
28296
28591
  dir,
28297
28592
  base,
28298
28593
  demotedDir,
28299
- instinctsDir: join45(base, INSTINCTS_PATH),
28300
- reportPath: join45(demotedDir, REPORT_FILE)
28594
+ instinctsDir: join46(base, INSTINCTS_PATH),
28595
+ reportPath: join46(demotedDir, REPORT_FILE)
28301
28596
  };
28302
28597
  }
28303
28598
  function entryKind2(path6) {
28304
28599
  try {
28305
- const stats = statSync16(path6);
28600
+ const stats = statSync18(path6);
28306
28601
  if (stats.isFile())
28307
28602
  return "file";
28308
28603
  if (stats.isDirectory())
@@ -28314,7 +28609,7 @@ function entryKind2(path6) {
28314
28609
  }
28315
28610
  function visibleNames2(dir) {
28316
28611
  try {
28317
- return readdirSync12(dir).filter((name2) => !name2.startsWith(".")).sort((left, right) => left.localeCompare(right));
28612
+ return readdirSync13(dir).filter((name2) => !name2.startsWith(".")).sort((left, right) => left.localeCompare(right));
28318
28613
  } catch {
28319
28614
  return [];
28320
28615
  }
@@ -28323,8 +28618,8 @@ function readSelected(absolute, path6, entries) {
28323
28618
  let text2;
28324
28619
  let mtime;
28325
28620
  try {
28326
- text2 = readFileSync38(absolute, "utf8");
28327
- mtime = statSync16(absolute).mtime.toISOString();
28621
+ text2 = readFileSync39(absolute, "utf8");
28622
+ mtime = statSync18(absolute).mtime.toISOString();
28328
28623
  } catch {
28329
28624
  return null;
28330
28625
  }
@@ -28339,14 +28634,14 @@ function selectsLearned(text2, scope) {
28339
28634
  return origin === AUTO_EXTRACTED_ORIGIN;
28340
28635
  }
28341
28636
  function selectLearned(scope) {
28342
- const dir = join45(scope.dir, LEARNED_DIRECTORY);
28637
+ const dir = join46(scope.dir, LEARNED_DIRECTORY);
28343
28638
  if (entryKind2(dir) !== "directory")
28344
28639
  return [];
28345
28640
  const selected = [];
28346
28641
  for (const name2 of visibleNames2(dir)) {
28347
28642
  if (!name2.endsWith(MARKDOWN_EXTENSION) || name2 === MARKDOWN_EXTENSION)
28348
28643
  continue;
28349
- const absolute = join45(dir, name2);
28644
+ const absolute = join46(dir, name2);
28350
28645
  if (entryKind2(absolute) !== "file")
28351
28646
  continue;
28352
28647
  const file = readSelected(absolute, `${LEARNED_DIRECTORY}/${name2}`, undefined);
@@ -28360,10 +28655,10 @@ function selectSkillFiles(scope) {
28360
28655
  for (const name2 of visibleNames2(scope.dir)) {
28361
28656
  if (name2 === LEARNED_DIRECTORY)
28362
28657
  continue;
28363
- const skillDir = join45(scope.dir, name2);
28658
+ const skillDir = join46(scope.dir, name2);
28364
28659
  if (entryKind2(skillDir) !== "directory")
28365
28660
  continue;
28366
- const absolute = join45(skillDir, SKILL_FILE);
28661
+ const absolute = join46(skillDir, SKILL_FILE);
28367
28662
  if (entryKind2(absolute) !== "file")
28368
28663
  continue;
28369
28664
  const file = readSelected(absolute, `${name2}/${SKILL_FILE}`, visibleNames2(skillDir));
@@ -28411,7 +28706,7 @@ Usage: ${BACKFILL_USAGE}`);
28411
28706
  throw new CommandExit(1, `\u274C Expected one directory, and read "${extra}" as a second
28412
28707
  Usage: ${BACKFILL_USAGE}`);
28413
28708
  }
28414
- return resolve20(cwd(), dir);
28709
+ return resolve22(cwd(), dir);
28415
28710
  }
28416
28711
  function readConsumerRoot(value, cwd) {
28417
28712
  if (value === undefined || value === false)
@@ -28420,11 +28715,11 @@ function readConsumerRoot(value, cwd) {
28420
28715
  throw new CommandExit(1, `\u274C --project needs a path, and the line gave it none
28421
28716
  Usage: ${BACKFILL_USAGE}`);
28422
28717
  }
28423
- return resolve20(cwd(), value);
28718
+ return resolve22(cwd(), value);
28424
28719
  }
28425
28720
  function isDirectory3(path6) {
28426
28721
  try {
28427
- return statSync17(path6).isDirectory();
28722
+ return statSync19(path6).isDirectory();
28428
28723
  } catch {
28429
28724
  return false;
28430
28725
  }
@@ -28548,7 +28843,7 @@ function reviewedProposals(dir) {
28548
28843
  return read2.flatMap((entry) => entry.result.file === null ? [] : [entry.result.file]);
28549
28844
  }
28550
28845
  function rowPaths(files, root) {
28551
- return files.flatMap((file) => file.status !== REVIEWED_FILE ? [] : file.rows.filter((row2) => row2.status === ANSWERED_ROW).map((row2) => join46(root, ...row2.path.split("/"))));
28846
+ return files.flatMap((file) => file.status !== REVIEWED_FILE ? [] : file.rows.filter((row2) => row2.status === ANSWERED_ROW).map((row2) => join47(root, ...row2.path.split("/"))));
28552
28847
  }
28553
28848
  function runApply(context, scope, backfillDir, projectRoot3) {
28554
28849
  const options = checkOptions(context, projectRoot3);
@@ -28594,7 +28889,7 @@ async function runBackfill(context, seams) {
28594
28889
  const dir = readBackfillDirectory(context.args, seams.cwd);
28595
28890
  const projectRoot3 = readConsumerRoot(context.flags["project"], seams.cwd);
28596
28891
  const scope = backfillScopeOf(dir, projectOf8(context).home);
28597
- const backfillDir = join46(scope.base, BACKFILL_PATH);
28892
+ const backfillDir = join47(scope.base, BACKFILL_PATH);
28598
28893
  if (mode === "propose") {
28599
28894
  await runPropose(context, scope, backfillDir, seams);
28600
28895
  return;
@@ -28707,13 +29002,13 @@ function createSkillCheckCommand(seams = DEFAULT_CHECK_SEAMS) {
28707
29002
  var check_default2 = createSkillCheckCommand();
28708
29003
 
28709
29004
  // src/commands/skill/demote.ts
28710
- import { existsSync as existsSync35, mkdirSync as mkdirSync16, readFileSync as readFileSync40, statSync as statSync19, writeFileSync as writeFileSync19 } from "fs";
28711
- import { dirname as dirname18, resolve as resolve21 } from "path";
29005
+ import { existsSync as existsSync36, mkdirSync as mkdirSync17, readFileSync as readFileSync41, statSync as statSync21, writeFileSync as writeFileSync19 } from "fs";
29006
+ import { dirname as dirname18, resolve as resolve23 } from "path";
28712
29007
 
28713
29008
  // src/demote/apply.ts
28714
- import { copyFileSync as copyFileSync4, existsSync as existsSync34, mkdirSync as mkdirSync15, mkdtempSync, readdirSync as readdirSync13, readFileSync as readFileSync39, renameSync as renameSync4, rmSync as rmSync3, statSync as statSync18, unlinkSync, writeFileSync as writeFileSync18 } from "fs";
29009
+ import { copyFileSync as copyFileSync4, existsSync as existsSync35, mkdirSync as mkdirSync16, mkdtempSync, readdirSync as readdirSync14, readFileSync as readFileSync40, renameSync as renameSync4, rmSync as rmSync3, statSync as statSync20, unlinkSync as unlinkSync2, writeFileSync as writeFileSync18 } from "fs";
28715
29010
  import { tmpdir } from "os";
28716
- import { dirname as dirname17, join as join47 } from "path";
29011
+ import { dirname as dirname17, join as join48 } from "path";
28717
29012
  var DEMOTION_ACTION_KINDS = [
28718
29013
  "demoted",
28719
29014
  "kept",
@@ -28734,18 +29029,18 @@ function learnedSkillName(path6) {
28734
29029
  return base.slice(0, -MARKDOWN_EXTENSION.length);
28735
29030
  }
28736
29031
  function sourcePath(scope, path6) {
28737
- return join47(scope.dir, ...path6.split("/"));
29032
+ return join48(scope.dir, ...path6.split("/"));
28738
29033
  }
28739
29034
  function demotedPath(scope, path6) {
28740
- return join47(scope.demotedDir, ...path6.split("/"));
29035
+ return join48(scope.demotedDir, ...path6.split("/"));
28741
29036
  }
28742
29037
  function promotedPath(scope, path6) {
28743
- return join47(scope.dir, learnedSkillName(path6), SKILL_FILE);
29038
+ return join48(scope.dir, learnedSkillName(path6), SKILL_FILE);
28744
29039
  }
28745
29040
  function takenInstinctIds(dir) {
28746
29041
  let names;
28747
29042
  try {
28748
- names = readdirSync13(dir);
29043
+ names = readdirSync14(dir);
28749
29044
  } catch {
28750
29045
  return [];
28751
29046
  }
@@ -28753,7 +29048,7 @@ function takenInstinctIds(dir) {
28753
29048
  }
28754
29049
  function readText6(path6) {
28755
29050
  try {
28756
- return statSync18(path6).isFile() ? readFileSync39(path6, "utf8") : null;
29051
+ return statSync20(path6).isFile() ? readFileSync40(path6, "utf8") : null;
28757
29052
  } catch {
28758
29053
  return null;
28759
29054
  }
@@ -28781,7 +29076,7 @@ function planKept(scope, row2, file) {
28781
29076
  return inert3(row2.path, "procedure", "kept", "procedure-shaped: left where it is, for the backfill");
28782
29077
  }
28783
29078
  const to = promotedPath(scope, row2.path);
28784
- if (existsSync34(to) || existsSync34(dirname17(to))) {
29079
+ if (existsSync35(to) || existsSync35(dirname17(to))) {
28785
29080
  return inert3(row2.path, "procedure", "refused", `kept as a skill, but ${to} is already there`);
28786
29081
  }
28787
29082
  return {
@@ -28795,7 +29090,7 @@ function planKept(scope, row2, file) {
28795
29090
  };
28796
29091
  }
28797
29092
  function checkCandidate(dir, id, text2, pathDirs) {
28798
- const path6 = join47(dir, `${id}${MARKDOWN_EXTENSION}`);
29093
+ const path6 = join48(dir, `${id}${MARKDOWN_EXTENSION}`);
28799
29094
  writeFileSync18(path6, text2, "utf8");
28800
29095
  const report3 = checkFile(path6, "instinct", { projectRoot: null, pathDirs });
28801
29096
  return failureLines2(report3.issues);
@@ -28816,11 +29111,11 @@ function planDemoted(scope, row2, file, context) {
28816
29111
  if (failures.length > 0) {
28817
29112
  return inert3(row2.path, "observation", "refused", `the record ${id} fails the checker \u2014 ${failures.join("; ")}`);
28818
29113
  }
28819
- const destination = join47(scope.instinctsDir, `${id}${MARKDOWN_EXTENSION}`);
29114
+ const destination = join48(scope.instinctsDir, `${id}${MARKDOWN_EXTENSION}`);
28820
29115
  const kept = demotedPath(scope, row2.path);
28821
- if (existsSync34(destination))
29116
+ if (existsSync35(destination))
28822
29117
  return inert3(row2.path, "observation", "refused", `${destination} is already there`);
28823
- if (existsSync34(kept))
29118
+ if (existsSync35(kept))
28824
29119
  return inert3(row2.path, "observation", "refused", `${kept} is already there`);
28825
29120
  context.taken.push(id);
28826
29121
  return {
@@ -28852,7 +29147,7 @@ function planRow(scope, row2, context) {
28852
29147
  entries: undefined,
28853
29148
  absolute,
28854
29149
  hash,
28855
- mtime: statSync18(absolute).mtime.toISOString()
29150
+ mtime: statSync20(absolute).mtime.toISOString()
28856
29151
  };
28857
29152
  return verdict === "procedure" ? planKept(scope, row2, file) : planDemoted(scope, row2, file, context);
28858
29153
  }
@@ -28863,7 +29158,7 @@ function countActions(actions) {
28863
29158
  return counts;
28864
29159
  }
28865
29160
  function planDemotion(report3, scope, seams = DEFAULT_APPLY_SEAMS) {
28866
- const temp = mkdtempSync(join47(tmpdir(), "rafa-demote-"));
29161
+ const temp = mkdtempSync(join48(tmpdir(), "rafa-demote-"));
28867
29162
  const taken = [...takenInstinctIds(scope.instinctsDir)];
28868
29163
  try {
28869
29164
  const actions = report3.rows.map((row2) => planRow(scope, row2, { temp, taken, seams }));
@@ -28873,18 +29168,18 @@ function planDemotion(report3, scope, seams = DEFAULT_APPLY_SEAMS) {
28873
29168
  }
28874
29169
  }
28875
29170
  function moveFile(move) {
28876
- mkdirSync15(dirname17(move.to), { recursive: true });
29171
+ mkdirSync16(dirname17(move.to), { recursive: true });
28877
29172
  try {
28878
29173
  renameSync4(move.from, move.to);
28879
29174
  } catch {
28880
29175
  copyFileSync4(move.from, move.to);
28881
- unlinkSync(move.from);
29176
+ unlinkSync2(move.from);
28882
29177
  }
28883
29178
  }
28884
29179
  function applyDemotion(plan2) {
28885
29180
  for (const action of plan2.actions) {
28886
29181
  if (action.write !== null) {
28887
- mkdirSync15(dirname17(action.write.path), { recursive: true });
29182
+ mkdirSync16(dirname17(action.write.path), { recursive: true });
28888
29183
  writeFileSync18(action.write.path, action.write.text, "utf8");
28889
29184
  }
28890
29185
  if (action.move !== null)
@@ -28950,11 +29245,11 @@ Usage: ${DEMOTE_USAGE}`);
28950
29245
  throw new CommandExit(1, `\u274C Expected one directory, and read "${extra}" as a second
28951
29246
  Usage: ${DEMOTE_USAGE}`);
28952
29247
  }
28953
- return resolve21(cwd(), dir);
29248
+ return resolve23(cwd(), dir);
28954
29249
  }
28955
29250
  function isDirectory4(path6) {
28956
29251
  try {
28957
- return statSync19(path6).isDirectory();
29252
+ return statSync21(path6).isDirectory();
28958
29253
  } catch {
28959
29254
  return false;
28960
29255
  }
@@ -28982,9 +29277,9 @@ function verdictLine(report3) {
28982
29277
  return `${String(report3.rows.length)} file(s): ${parts.join(", ")}`;
28983
29278
  }
28984
29279
  function previousReport(path6, context) {
28985
- if (!existsSync35(path6))
29280
+ if (!existsSync36(path6))
28986
29281
  return null;
28987
- const parsed = parseDemotionReport(readFileSync40(path6, "utf8"));
29282
+ const parsed = parseDemotionReport(readFileSync41(path6, "utf8"));
28988
29283
  if (parsed.report !== null)
28989
29284
  return parsed.report;
28990
29285
  context.output.warn(`the report already at ${path6} does not parse, so no override in it is carried forward:` + ` ${parsed.issues.map((issue4) => `line ${String(issue4.line)} ${issue4.code}`).join(", ")}`);
@@ -28993,7 +29288,7 @@ function previousReport(path6, context) {
28993
29288
  function runWrite(context, scope) {
28994
29289
  const files = selectSources(scope);
28995
29290
  const report3 = buildDemotionReport(files, previousReport(scope.reportPath, context));
28996
- mkdirSync16(dirname18(scope.reportPath), { recursive: true });
29291
+ mkdirSync17(dirname18(scope.reportPath), { recursive: true });
28997
29292
  writeFileSync19(scope.reportPath, writeDemotionReport(report3), "utf8");
28998
29293
  const result = {
28999
29294
  applied: false,
@@ -29017,10 +29312,10 @@ function runWrite(context, scope) {
29017
29312
  context.output.info(line);
29018
29313
  }
29019
29314
  function reviewedReport(scope) {
29020
- if (!existsSync35(scope.reportPath)) {
29315
+ if (!existsSync36(scope.reportPath)) {
29021
29316
  throw new CommandExit(1, `\u274C No report at ${scope.reportPath}; run "rafa skill demote ${scope.dir}" first, then review it`);
29022
29317
  }
29023
- const parsed = parseDemotionReport(readFileSync40(scope.reportPath, "utf8"));
29318
+ const parsed = parseDemotionReport(readFileSync41(scope.reportPath, "utf8"));
29024
29319
  if (parsed.report === null) {
29025
29320
  const lines = parsed.issues.map((issue4) => ` line ${String(issue4.line)} ${issue4.code}: ${issue4.message}`);
29026
29321
  throw new CommandExit(1, [`\u274C ${scope.reportPath} does not parse:`, ...lines].join(`
@@ -29125,7 +29420,7 @@ function createSkillDemoteCommand(seams = DEFAULT_DEMOTE_SEAMS) {
29125
29420
  var demote_default = createSkillDemoteCommand();
29126
29421
 
29127
29422
  // src/commands/skill/list.ts
29128
- import { readFileSync as readFileSync41 } from "fs";
29423
+ import { readFileSync as readFileSync42 } from "fs";
29129
29424
  var DEFAULT_SKILL_LIST_SEAMS = Object.freeze({
29130
29425
  entry: () => Bun.main
29131
29426
  });
@@ -29145,7 +29440,7 @@ Usage: ${USAGE28}`);
29145
29440
  function skillStack(path6) {
29146
29441
  let text2;
29147
29442
  try {
29148
- text2 = readFileSync41(path6, "utf8");
29443
+ text2 = readFileSync42(path6, "utf8");
29149
29444
  } catch {
29150
29445
  return [];
29151
29446
  }