@open-tomato/rafa 0.9.0 → 0.9.1

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 +791 -501
  3. package/dist/index.js +393 -143
  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.1";
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
  `));
@@ -16130,22 +16401,22 @@ function openNextSources(context, seams = DEFAULT_NEXT_SOURCE_SEAMS) {
16130
16401
  }
16131
16402
 
16132
16403
  // 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";
16404
+ import { existsSync as existsSync23, readdirSync as readdirSync8, readFileSync as readFileSync22 } from "fs";
16405
+ import { join as join30 } from "path";
16135
16406
  var USAGE10 = "rafa plan list";
16136
16407
  function listing(dir, stub) {
16137
- const plan = join29(dir, planFileName(stub, false));
16138
- const trackerPath = join29(dir, planFileName(stub, true));
16408
+ const plan = join30(dir, planFileName(stub, false));
16409
+ const trackerPath = join30(dir, planFileName(stub, true));
16139
16410
  const tracker = isFile(trackerPath) ? trackerPath : null;
16140
- const planModel = parsePlan(readFileSync21(plan, "utf8"));
16141
- const counted3 = tracker === null ? planModel : parsePlan(readFileSync21(tracker, "utf8"));
16411
+ const planModel = parsePlan(readFileSync22(plan, "utf8"));
16412
+ const counted3 = tracker === null ? planModel : parsePlan(readFileSync22(tracker, "utf8"));
16142
16413
  return { stub, plan, tracker, tasks: countTasks(counted3.tasks), issues: planModel.issues.length };
16143
16414
  }
16144
16415
  function listPlans(plans) {
16145
16416
  const dir = plans.path;
16146
- if (!existsSync22(dir))
16417
+ if (!existsSync23(dir))
16147
16418
  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));
16419
+ 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
16420
  return { dir, plans: stubs.map((stub) => listing(dir, stub)) };
16150
16421
  }
16151
16422
  function rowNotes(plan) {
@@ -16340,7 +16611,7 @@ function branchLabel(world) {
16340
16611
  }
16341
16612
 
16342
16613
  // src/next/state.ts
16343
- var PREFIX13 = "rafa next";
16614
+ var PREFIX15 = "rafa next";
16344
16615
  var MAX_NAMED_FILES = 5;
16345
16616
  var NEXT_PRECONDITIONS = Object.freeze([
16346
16617
  "tree-modified",
@@ -16618,7 +16889,7 @@ async function readNextState(sources) {
16618
16889
  if (found !== null)
16619
16890
  return answer(found, world.problems());
16620
16891
  }
16621
- throw new Error(`${PREFIX13}: no row of the table answered, and the last row answers for every reading`);
16892
+ throw new Error(`${PREFIX15}: no row of the table answered, and the last row answers for every reading`);
16622
16893
  }
16623
16894
 
16624
16895
  // src/next/hint.ts
@@ -16644,8 +16915,8 @@ function wantsHint(flags) {
16644
16915
  }
16645
16916
  var DEFAULT_HINT_SEAMS = Object.freeze({});
16646
16917
  function afterDelay(ms) {
16647
- return new Promise((resolve15) => {
16648
- setTimeout(resolve15, ms).unref();
16918
+ return new Promise((resolve17) => {
16919
+ setTimeout(resolve17, ms).unref();
16649
16920
  });
16650
16921
  }
16651
16922
  function silenced() {
@@ -16699,10 +16970,10 @@ async function nextStepHint(context, seams = DEFAULT_HINT_SEAMS) {
16699
16970
  }
16700
16971
 
16701
16972
  // src/next/actions.ts
16702
- var PREFIX14 = "rafa next";
16973
+ var PREFIX16 = "rafa next";
16703
16974
  function needed(state, value, what) {
16704
16975
  if (value === null) {
16705
- throw new Error(`${PREFIX14}: state "${state.id}" proposes "${state.action}" and names no ${what}`);
16976
+ throw new Error(`${PREFIX16}: state "${state.id}" proposes "${state.action}" and names no ${what}`);
16706
16977
  }
16707
16978
  return String(value);
16708
16979
  }
@@ -16752,12 +17023,12 @@ function actionContext(caller, command, argv) {
16752
17023
  async function runAction(caller, state) {
16753
17024
  const invocation = actionInvocation(state);
16754
17025
  if (invocation === null) {
16755
- throw new Error(`${PREFIX14}: the action "${state.action}" of state "${state.id}" runs no registered command`);
17026
+ throw new Error(`${PREFIX16}: the action "${state.action}" of state "${state.id}" runs no registered command`);
16756
17027
  }
16757
17028
  const spec = ACTION_COMMANDS[invocation.action];
16758
17029
  const command = caller.registry.find(spec.subject, spec.action);
16759
17030
  if (command === undefined) {
16760
- throw new CommandExit(1, `\u274C ${PREFIX14}: the "${invocation.action}" step runs "rafa ${invocation.command}", which is registered by nothing`);
17031
+ throw new CommandExit(1, `\u274C ${PREFIX16}: the "${invocation.action}" step runs "rafa ${invocation.command}", which is registered by nothing`);
16761
17032
  }
16762
17033
  await command.run(actionContext(caller, command, invocation.argv));
16763
17034
  }
@@ -17042,7 +17313,7 @@ var UNBLOCK_USAGE = "rafa issue unblock [<n>] [--all]";
17042
17313
  var ALL_FLAG = "all";
17043
17314
  var ISSUE_NUMBER4 = /^[1-9]\d*$/u;
17044
17315
  var YES_ANSWERS3 = ["y", "yes"];
17045
- var PREFIX15 = "board unblock";
17316
+ var PREFIX17 = "board unblock";
17046
17317
  function nameIds2(ids) {
17047
17318
  return ids.map((id) => `#${String(id)}`).join(" ");
17048
17319
  }
@@ -17056,32 +17327,32 @@ function detailOf9(result, command) {
17056
17327
  async function rowsOf2(gh, args, command) {
17057
17328
  const result = await gh(args);
17058
17329
  if (!result.ok)
17059
- throw new Error(`${PREFIX15}: ${detailOf9(result, command)}`);
17330
+ throw new Error(`${PREFIX17}: ${detailOf9(result, command)}`);
17060
17331
  let parsed;
17061
17332
  try {
17062
17333
  parsed = JSON.parse(result.stdout);
17063
17334
  } catch (error) {
17064
- throw new Error(`${PREFIX15}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
17335
+ throw new Error(`${PREFIX17}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
17065
17336
  }
17066
17337
  if (!Array.isArray(parsed)) {
17067
- throw new Error(`${PREFIX15}: ${command} answered ${describeValue(parsed)}, expected a list of issues`);
17338
+ throw new Error(`${PREFIX17}: ${command} answered ${describeValue(parsed)}, expected a list of issues`);
17068
17339
  }
17069
17340
  return parsed;
17070
17341
  }
17071
17342
  function rowNumber4(row2, command, where) {
17072
17343
  if (!isMapping(row2)) {
17073
- throw new Error(`${PREFIX15}: ${command} answered ${where} as ${describeValue(row2)}, expected a mapping`);
17344
+ throw new Error(`${PREFIX17}: ${command} answered ${where} as ${describeValue(row2)}, expected a mapping`);
17074
17345
  }
17075
17346
  const number = row2["number"];
17076
17347
  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`);
17348
+ throw new Error(`${PREFIX17}: ${command} answered ${where}.number as ${describeValue(number)}, expected a positive whole number`);
17078
17349
  }
17079
17350
  return number;
17080
17351
  }
17081
17352
  function rowBody2(row2, command, where) {
17082
17353
  const body = isMapping(row2) ? row2["body"] : null;
17083
17354
  if (typeof body !== "string") {
17084
- throw new Error(`${PREFIX15}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
17355
+ throw new Error(`${PREFIX17}: ${command} answered ${where}.body as ${describeValue(body)}, expected a string`);
17085
17356
  }
17086
17357
  return body;
17087
17358
  }
@@ -17723,9 +17994,9 @@ async function handleRedChecks(io, branch, prNumber, rows2) {
17723
17994
  }
17724
17995
 
17725
17996
  // src/start/runtime.ts
17726
- import { existsSync as existsSync23, readdirSync as readdirSync8, realpathSync as realpathSync4, statSync as statSync14 } from "fs";
17997
+ import { existsSync as existsSync24, readdirSync as readdirSync9, realpathSync as realpathSync4, statSync as statSync16 } from "fs";
17727
17998
  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";
17999
+ import { isAbsolute as isAbsolute9, join as join31, relative as relative7, resolve as resolve17, sep as sep4 } from "path";
17729
18000
 
17730
18001
  // src/start/session.ts
17731
18002
  import { randomUUID as randomUUID4 } from "crypto";
@@ -17876,7 +18147,7 @@ function announcePlanIssues(planContent) {
17876
18147
 
17877
18148
  // src/start/runtime.ts
17878
18149
  var RUNTIME_FLAG = "--runtime";
17879
- var RUNTIME_SUBDIR = join30(".rafa", "runtime");
18150
+ var RUNTIME_SUBDIR = join31(".rafa", "runtime");
17880
18151
  var RUNTIME_ENTRY = "cli.js";
17881
18152
  var SOURCE_DIR = "src";
17882
18153
  var RUNTIME_COMMAND = ["start"];
@@ -17903,7 +18174,7 @@ function resolveRuntime(value, places) {
17903
18174
  throw refusal5([`\u274C Refusing to start: \`--runtime\` names no runtime. Spell it ${SPELLING}.`]);
17904
18175
  }
17905
18176
  const isVersion = VERSION_SHAPE.test(value);
17906
- const named = isVersion ? join30(places.home, RUNTIME_SUBDIR, value, RUNTIME_ENTRY) : resolve15(places.cwd, value);
18177
+ const named = isVersion ? join31(places.home, RUNTIME_SUBDIR, value, RUNTIME_ENTRY) : resolve17(places.cwd, value);
17907
18178
  refuseInsideSource(value, named, places);
17908
18179
  const entry = entryOf(value, named, isVersion, places.home);
17909
18180
  const real = realpathSync4(entry);
@@ -17914,7 +18185,7 @@ function entryOf(value, named, isVersion, home) {
17914
18185
  if (isVersion) {
17915
18186
  if (isFile3(named))
17916
18187
  return named;
17917
- const root = join30(home, RUNTIME_SUBDIR);
18188
+ const root = join31(home, RUNTIME_SUBDIR);
17918
18189
  const installed = installedVersions(root);
17919
18190
  throw refusal5([
17920
18191
  `\u274C Refusing to start: \`--runtime=${value}\` names no installed runtime: ${named} is no file.`,
@@ -17923,7 +18194,7 @@ function entryOf(value, named, isVersion, home) {
17923
18194
  }
17924
18195
  if (isFile3(named))
17925
18196
  return named;
17926
- const inside = join30(named, RUNTIME_ENTRY);
18197
+ const inside = join31(named, RUNTIME_ENTRY);
17927
18198
  if (isDirectory2(named) && isFile3(inside))
17928
18199
  return inside;
17929
18200
  throw refusal5([
@@ -17941,8 +18212,8 @@ function refuseInsideSource(value, path2, places) {
17941
18212
  ]);
17942
18213
  }
17943
18214
  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));
18215
+ const dirs = [join31(cwd, SOURCE_DIR), join31(root, SOURCE_DIR)];
18216
+ const real = dirs.filter((dir) => existsSync24(dir)).map((dir) => realpathSync4(dir));
17946
18217
  return [...new Set([...dirs, ...real])];
17947
18218
  }
17948
18219
  function isInside2(path2, dir) {
@@ -17951,21 +18222,21 @@ function isInside2(path2, dir) {
17951
18222
  }
17952
18223
  function installedVersions(root) {
17953
18224
  try {
17954
- return readdirSync8(root).filter((name2) => isFile3(join30(root, name2, RUNTIME_ENTRY))).sort((a, b) => a.localeCompare(b));
18225
+ return readdirSync9(root).filter((name2) => isFile3(join31(root, name2, RUNTIME_ENTRY))).sort((a, b) => a.localeCompare(b));
17955
18226
  } catch {
17956
18227
  return [];
17957
18228
  }
17958
18229
  }
17959
18230
  function isFile3(path2) {
17960
18231
  try {
17961
- return statSync14(path2).isFile();
18232
+ return statSync16(path2).isFile();
17962
18233
  } catch {
17963
18234
  return false;
17964
18235
  }
17965
18236
  }
17966
18237
  function isDirectory2(path2) {
17967
18238
  try {
17968
- return statSync14(path2).isDirectory();
18239
+ return statSync16(path2).isDirectory();
17969
18240
  } catch {
17970
18241
  return false;
17971
18242
  }
@@ -17996,7 +18267,7 @@ function realOrResolved(path2) {
17996
18267
  try {
17997
18268
  return realpathSync4(path2);
17998
18269
  } catch {
17999
- return resolve15(path2);
18270
+ return resolve17(path2);
18000
18271
  }
18001
18272
  }
18002
18273
  async function runRuntime(entry, words, run) {
@@ -18091,13 +18362,13 @@ import { fileURLToPath as fileURLToPath2 } from "url";
18091
18362
  import { homedir as homedir6 } from "os";
18092
18363
 
18093
18364
  // 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";
18365
+ import { mkdirSync as mkdirSync11, readFileSync as readFileSync23, writeFileSync as writeFileSync10 } from "fs";
18366
+ import { dirname as dirname12, join as join32 } from "path";
18096
18367
  var NOTICE_IDS = Object.freeze(["alpha", "danger"]);
18097
18368
  var FEEDBACK_URL = "https://github.com/open-tomato/rafa/issues/new/choose";
18098
18369
  var ROADMAP_URL = "https://github.com/open-tomato/rafa/issues/31";
18099
18370
  function noticesPath(home) {
18100
- return join31(home, ".rafa", "notices.json");
18371
+ return join32(home, ".rafa", "notices.json");
18101
18372
  }
18102
18373
  function isNoticeId(value) {
18103
18374
  return typeof value === "string" && NOTICE_IDS.includes(value);
@@ -18105,7 +18376,7 @@ function isNoticeId(value) {
18105
18376
  function readDismissed(home) {
18106
18377
  let raw;
18107
18378
  try {
18108
- raw = readFileSync22(noticesPath(home), "utf8");
18379
+ raw = readFileSync23(noticesPath(home), "utf8");
18109
18380
  } catch {
18110
18381
  return [];
18111
18382
  }
@@ -18124,7 +18395,7 @@ function readDismissed(home) {
18124
18395
  function writeDismissed(home, ids) {
18125
18396
  const all = NOTICE_IDS.filter((id) => ids.includes(id) || readDismissed(home).includes(id));
18126
18397
  const path2 = noticesPath(home);
18127
- mkdirSync10(dirname12(path2), { recursive: true });
18398
+ mkdirSync11(dirname12(path2), { recursive: true });
18128
18399
  writeFileSync10(path2, `${JSON.stringify({ dismissed: all }, null, 2)}
18129
18400
  `);
18130
18401
  }
@@ -18667,7 +18938,7 @@ import { randomUUID as randomUUID9 } from "crypto";
18667
18938
 
18668
18939
  // src/effort/store/absences.ts
18669
18940
  import { randomUUID as randomUUID5 } from "crypto";
18670
- import { existsSync as existsSync24 } from "fs";
18941
+ import { existsSync as existsSync25 } from "fs";
18671
18942
  var ABSENCE_REASONS = {
18672
18943
  "no-block": true,
18673
18944
  "unclosed-block": true,
@@ -18726,13 +18997,13 @@ function writeReportAbsence(repoRoot, write, seams = {}) {
18726
18997
  write.outcome,
18727
18998
  collectedAt
18728
18999
  ];
18729
- const appended3 = withSqliteStore(path2, !existsSync24(path2), (db) => db.query(INSERT_ABSENCE).run(...values).changes);
19000
+ const appended3 = withSqliteStore(path2, !existsSync25(path2), (db) => db.query(INSERT_ABSENCE).run(...values).changes);
18730
19001
  return { path: path2, appended: appended3, skipped: 1 - appended3 };
18731
19002
  }
18732
19003
 
18733
19004
  // src/effort/store/changes.ts
18734
19005
  import { randomUUID as randomUUID6 } from "crypto";
18735
- import { existsSync as existsSync25 } from "fs";
19006
+ import { existsSync as existsSync26 } from "fs";
18736
19007
  var INSERT_CHANGE = `
18737
19008
  INSERT INTO changes (
18738
19009
  id, session_id, plan_stub, task_line,
@@ -18811,7 +19082,7 @@ var SELECT_PLAN_CHANGES = `
18811
19082
  `;
18812
19083
  function readPlanChanges(repoRoot, planStub2) {
18813
19084
  const path2 = sqliteStorePath(repoRoot);
18814
- if (!existsSync25(path2))
19085
+ if (!existsSync26(path2))
18815
19086
  return [];
18816
19087
  const rows2 = withSqliteStore(path2, false, (db) => db.query(SELECT_PLAN_CHANGES).all(planStub2));
18817
19088
  return rows2.map((row2) => ({
@@ -18980,8 +19251,8 @@ function describeTaskReportRecord(record) {
18980
19251
  }
18981
19252
 
18982
19253
  // src/utils/progress.ts
18983
- import { existsSync as existsSync26, writeFileSync as writeFileSync11 } from "fs";
18984
- import { join as join32 } from "path";
19254
+ import { existsSync as existsSync27, writeFileSync as writeFileSync11 } from "fs";
19255
+ import { join as join33 } from "path";
18985
19256
  var PROGRESS_FILE_NAME = "progress.txt";
18986
19257
  var PROGRESS_CAP_BYTES = 16000;
18987
19258
  var LISTED_FIELDS = [
@@ -19023,7 +19294,7 @@ var ESCAPED_CODE_POINTS = new Set([
19023
19294
  8233
19024
19295
  ]);
19025
19296
  function progressFilePath(repoRoot) {
19026
- return join32(repoRoot, PROGRESS_FILE_NAME);
19297
+ return join33(repoRoot, PROGRESS_FILE_NAME);
19027
19298
  }
19028
19299
  function escapeValue(value) {
19029
19300
  let escaped = "";
@@ -19084,7 +19355,7 @@ function renderProgressText(findings, capBytes = PROGRESS_CAP_BYTES) {
19084
19355
  }
19085
19356
  function readProgressFindings(repoRoot, planStub2) {
19086
19357
  const path2 = sqliteStorePath(repoRoot);
19087
- if (!existsSync26(path2))
19358
+ if (!existsSync27(path2))
19088
19359
  return [];
19089
19360
  const rows2 = withSqliteStore(path2, false, (db) => {
19090
19361
  const query = db.query(SELECT_FINDINGS);
@@ -19111,20 +19382,20 @@ function writeProgress(repoRoot, planStub2) {
19111
19382
 
19112
19383
  // src/start/preflight.ts
19113
19384
  import { randomUUID as randomUUID8 } from "crypto";
19114
- import { existsSync as existsSync27, readFileSync as readFileSync23 } from "fs";
19385
+ import { existsSync as existsSync28, readFileSync as readFileSync24 } from "fs";
19115
19386
  import { homedir as homedir7 } from "os";
19116
- import { basename as basename10 } from "path";
19387
+ import { basename as basename11 } from "path";
19117
19388
  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
19389
  function knownMissingNotice(lines) {
19119
19390
  return lines.length === 0 ? [] : [...lines, KNOWN_MISSING_SENTENCE];
19120
19391
  }
19121
19392
  function agentSourcePath(planPath) {
19122
19393
  const tracker = trackerPathFor(planPath);
19123
- return existsSync27(tracker) ? tracker : planPath;
19394
+ return existsSync28(tracker) ? tracker : planPath;
19124
19395
  }
19125
19396
  function readIfReadable2(path2) {
19126
19397
  try {
19127
- return readFileSync23(path2, "utf8");
19398
+ return readFileSync24(path2, "utf8");
19128
19399
  } catch {
19129
19400
  return null;
19130
19401
  }
@@ -19140,7 +19411,7 @@ function refuseUnresolvableAgents(options) {
19140
19411
  if (missing2.length === 0)
19141
19412
  return;
19142
19413
  throw new CommandExit(1, [
19143
- `\u274C Refusing to start: ${basename10(path2)} names ${missing2.length} agent(s) no loaded scope` + ` defines (loop.settingSources: ${settingSources.join(", ")}).`,
19414
+ `\u274C Refusing to start: ${basename11(path2)} names ${missing2.length} agent(s) no loaded scope` + ` defines (loop.settingSources: ${settingSources.join(", ")}).`,
19144
19415
  ...missing2.map((agent) => ` ${missingAgentLine(agent)}`),
19145
19416
  " Nothing was checked and nothing was dispatched."
19146
19417
  ].join(`
@@ -19173,7 +19444,7 @@ function skippedStartLine(item, tracker) {
19173
19444
  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
19445
  }
19175
19446
  function announceSkippedStart(planPath, skipped) {
19176
- const tracker = basename10(trackerPathFor(planPath));
19447
+ const tracker = basename11(trackerPathFor(planPath));
19177
19448
  const output = activeOutput();
19178
19449
  for (const [index, item] of skipped.entries()) {
19179
19450
  const lead = index === 0 ? `
@@ -19192,7 +19463,7 @@ function startTier(planPath, items) {
19192
19463
  function announceReminders(planPath, reminders) {
19193
19464
  if (reminders.length === 0)
19194
19465
  return;
19195
- const file = basename10(prerequisitesPathForPlan(planPath) ?? planPath);
19466
+ const file = basename11(prerequisitesPathForPlan(planPath) ?? planPath);
19196
19467
  const output = activeOutput();
19197
19468
  output.info(`
19198
19469
  \uD83D\uDCCC ${file} names ${reminders.length} step(s) the preflight does not check:`);
@@ -19419,7 +19690,7 @@ async function holdWhilePaused(options) {
19419
19690
  }
19420
19691
 
19421
19692
  // src/release/prepare.ts
19422
- import { readFileSync as readFileSync25, writeFileSync as writeFileSync13 } from "fs";
19693
+ import { readFileSync as readFileSync26, writeFileSync as writeFileSync13 } from "fs";
19423
19694
 
19424
19695
  // src/release/changelog.ts
19425
19696
  var RELEASE_HEADING_FIELDS = ["version", "date", "title"];
@@ -19623,7 +19894,7 @@ function resolveReleaseLevel(declared, notes) {
19623
19894
  }
19624
19895
 
19625
19896
  // src/release/version.ts
19626
- import { readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "fs";
19897
+ import { readFileSync as readFileSync25, writeFileSync as writeFileSync12 } from "fs";
19627
19898
  var RELEASE_REMOTE = "origin";
19628
19899
  var RELEASE_BASE_BRANCH = "main";
19629
19900
  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 +19986,7 @@ function writeManifestVersion(path2, next) {
19715
19986
  const unwritten = { path: path2, written: false, previous: null, version: next };
19716
19987
  let text2;
19717
19988
  try {
19718
- text2 = readFileSync24(path2, "utf8");
19989
+ text2 = readFileSync25(path2, "utf8");
19719
19990
  } catch (error) {
19720
19991
  return { ...unwritten, problem: `${path2} could not be read: ${messageOf(error)}` };
19721
19992
  }
@@ -19818,7 +20089,7 @@ function planVersion(input, versionFile, level) {
19818
20089
  }
19819
20090
  function textOf(path2) {
19820
20091
  try {
19821
- return readFileSync25(path2, "utf8");
20092
+ return readFileSync26(path2, "utf8");
19822
20093
  } catch {
19823
20094
  return null;
19824
20095
  }
@@ -19931,7 +20202,7 @@ function changelogFailure(failed2, versionEdit, restored) {
19931
20202
  }
19932
20203
 
19933
20204
  // src/release/verify.ts
19934
- import { readFileSync as readFileSync26, writeFileSync as writeFileSync14 } from "fs";
20205
+ import { readFileSync as readFileSync27, writeFileSync as writeFileSync14 } from "fs";
19935
20206
  function changelogInsertionSpan(before, after) {
19936
20207
  const beforeLines = before.split(`
19937
20208
  `);
@@ -19948,7 +20219,7 @@ function changelogInsertionSpan(before, after) {
19948
20219
  }
19949
20220
  function textOf2(path2) {
19950
20221
  try {
19951
- return readFileSync26(path2, "utf8");
20222
+ return readFileSync27(path2, "utf8");
19952
20223
  } catch {
19953
20224
  return null;
19954
20225
  }
@@ -20340,9 +20611,9 @@ function describeStartTriage(result) {
20340
20611
  };
20341
20612
  }
20342
20613
  async function resolvePublicTracker(options, redact) {
20343
- const resolve16 = options.resolve ?? resolveTracker;
20614
+ const resolve18 = options.resolve ?? resolveTracker;
20344
20615
  try {
20345
- const { tracker, attempts } = await resolve16({
20616
+ const { tracker, attempts } = await resolve18({
20346
20617
  config: options.config,
20347
20618
  context: { repoRoot: options.repoRoot }
20348
20619
  });
@@ -20513,8 +20784,8 @@ function msUntil(startAt, now = new Date) {
20513
20784
  return target.getTime() - now.getTime();
20514
20785
  }
20515
20786
  function sleepFor(ms) {
20516
- return new Promise((resolve16) => {
20517
- setTimeout(resolve16, ms);
20787
+ return new Promise((resolve18) => {
20788
+ setTimeout(resolve18, ms);
20518
20789
  });
20519
20790
  }
20520
20791
  async function deferUntil(startAt, now = new Date, sleep = sleepFor) {
@@ -21070,8 +21341,8 @@ Usage: ${USAGE17}`);
21070
21341
  var exec_default = Object.freeze(execCommand);
21071
21342
 
21072
21343
  // 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";
21344
+ import { readFileSync as readFileSync28 } from "fs";
21345
+ import { isAbsolute as isAbsolute10, join as join34, relative as relative8, resolve as resolve18 } from "path";
21075
21346
 
21076
21347
  // src/modules/manifest.ts
21077
21348
  var MANIFEST_VERSION = 1;
@@ -21356,11 +21627,11 @@ function unread(name2, directory2, ...problems) {
21356
21627
  return { name: name2, version: null, directory: directory2, manifest: null, problems };
21357
21628
  }
21358
21629
  function readPathSource(source, settings, seams) {
21359
- const directory2 = resolve16(settings.base, source.location);
21360
- const file = join33(directory2, "package.json");
21630
+ const directory2 = resolve18(settings.base, source.location);
21631
+ const file = join34(directory2, "package.json");
21361
21632
  let parsed;
21362
21633
  try {
21363
- parsed = JSON.parse((seams.readText ?? ((path3) => readFileSync27(path3, "utf8")))(file));
21634
+ parsed = JSON.parse((seams.readText ?? ((path3) => readFileSync28(path3, "utf8")))(file));
21364
21635
  } catch (error) {
21365
21636
  return unread(null, directory2, `${file} cannot be read as JSON: ${firstLine2(error)}`);
21366
21637
  }
@@ -21391,7 +21662,7 @@ function readSource(source, settings, seams) {
21391
21662
  return unread(source.location, null, `${source.kind} source ${describeValue(source.location)} is refused: ${PHASE_7}`);
21392
21663
  }
21393
21664
  function resolveEntry(directory2, entry, label) {
21394
- const path3 = resolve16(directory2, entry);
21665
+ const path3 = resolve18(directory2, entry);
21395
21666
  const inside = relative8(directory2, path3);
21396
21667
  return inside === "" || inside.startsWith("..") || isAbsolute10(inside) ? { problem: `${label} is ${describeValue(entry)}, which resolves outside the module directory ${directory2}` } : { path: path3 };
21397
21668
  }
@@ -22063,6 +22334,23 @@ function createPlanReadyOffer(seams = DEFAULT_OFFER_SEAMS) {
22063
22334
  };
22064
22335
  }
22065
22336
 
22337
+ // src/commands/plan/refresh-offer.ts
22338
+ var DEFAULT_REFRESH_OFFER_SEAMS = Object.freeze({});
22339
+ function createPlanRefreshOffer(seams = DEFAULT_REFRESH_OFFER_SEAMS) {
22340
+ const isTerminal = seams.isTerminal ?? (() => process.stdin.isTTY === true);
22341
+ if (!isTerminal())
22342
+ return null;
22343
+ const openPrompter = seams.openPrompter ?? (() => createLinePrompter(process.stdin, process.stderr));
22344
+ return async (request) => {
22345
+ const prompter = lazyPrompter(openPrompter);
22346
+ try {
22347
+ return await prompter.ask(refreshQuestion(request.issue, request.savedAt));
22348
+ } finally {
22349
+ prompter.close();
22350
+ }
22351
+ };
22352
+ }
22353
+
22066
22354
  // src/commands/plan/spec-route.ts
22067
22355
  function specCandidates(specArg, specsDir) {
22068
22356
  if (path4.isAbsolute(specArg))
@@ -22092,10 +22380,11 @@ async function resolveCreateSpec(options, seams = DEFAULT_ROUTE_SEAMS) {
22092
22380
  const source = readSpecSourceFlags(options.args);
22093
22381
  if (source.request === null)
22094
22382
  throw new CommandExit(SOURCE_REFUSAL_EXIT, usageRefusal(specsDir));
22095
- const resolve17 = seams.resolve ?? resolvePlanSpec;
22383
+ const resolve19 = seams.resolve ?? resolvePlanSpec;
22096
22384
  const makeReadyOffer = seams.makeReadyOffer ?? createPlanReadyOffer;
22097
22385
  const makeAlternativeOffer = seams.makeAlternativeOffer ?? createPlanBlockedOffer;
22098
- return await resolve17({
22386
+ const makeRefreshOffer = seams.makeRefreshOffer ?? createPlanRefreshOffer;
22387
+ return await resolve19({
22099
22388
  request: source.request,
22100
22389
  refresh: source.refresh,
22101
22390
  dryRun: source.dryRun,
@@ -22105,7 +22394,8 @@ async function resolveCreateSpec(options, seams = DEFAULT_ROUTE_SEAMS) {
22105
22394
  trustedAuthors: options.trustedAuthors,
22106
22395
  findSpec: (spec) => findSpec(repoRoot, spec, specsDir),
22107
22396
  offerReady: makeReadyOffer(),
22108
- offerAlternative: makeAlternativeOffer()
22397
+ offerAlternative: makeAlternativeOffer(),
22398
+ offerRefresh: makeRefreshOffer()
22109
22399
  });
22110
22400
  }
22111
22401
 
@@ -22277,7 +22567,7 @@ var wrapped2 = wrapPhaseZeroCommand({
22277
22567
  },
22278
22568
  {
22279
22569
  name: "refresh",
22280
- description: "Rewrites a snapshot that no longer matches the issue, which is otherwise refused.",
22570
+ description: "Rebuilds a snapshot that no longer matches the issue without asking; the old copy moves under" + " `previous/`.",
22281
22571
  type: "boolean"
22282
22572
  },
22283
22573
  {
@@ -22337,8 +22627,8 @@ var wrapped2 = wrapPhaseZeroCommand({
22337
22627
  var create_default2 = endingWith(wrapped2);
22338
22628
 
22339
22629
  // src/commands/plan/show.ts
22340
- import { readFileSync as readFileSync28 } from "fs";
22341
- import { join as join34 } from "path";
22630
+ import { readFileSync as readFileSync29 } from "fs";
22631
+ import { join as join35 } from "path";
22342
22632
  var USAGE19 = "rafa plan show <stub> [--tracker]";
22343
22633
  var COMMAND = "rafa plan show";
22344
22634
  function readTrackerFlag(value) {
@@ -22356,10 +22646,10 @@ function showPlan(plans, stub, tracker) {
22356
22646
  throw new CommandExit(1, `\u274C "${stub}" is no plan stub: a stub is letters, digits, ".", "_" and "-"`);
22357
22647
  }
22358
22648
  const name2 = planFileName(stub, tracker);
22359
- const file = join34(plans.path, name2);
22649
+ const file = join35(plans.path, name2);
22360
22650
  if (!isFile(file))
22361
- throw new CommandExit(1, missingText(stub, tracker, join34(plans.label, name2)));
22362
- const model = parsePlan(readFileSync28(file, "utf8"));
22651
+ throw new CommandExit(1, missingText(stub, tracker, join35(plans.label, name2)));
22652
+ const model = parsePlan(readFileSync29(file, "utf8"));
22363
22653
  const { header } = model;
22364
22654
  return {
22365
22655
  stub,
@@ -22382,7 +22672,7 @@ function taskLine2(task) {
22382
22672
  return ` ${checkbox(task.status)} ${task.text}`;
22383
22673
  }
22384
22674
  function renderShownPlan(shown2, dirLabel) {
22385
- const relative9 = join34(dirLabel, planFileName(shown2.stub, shown2.tracker));
22675
+ const relative9 = join35(dirLabel, planFileName(shown2.stub, shown2.tracker));
22386
22676
  const fileLabel = shown2.tracker ? "Tracker" : "File";
22387
22677
  const lines = [`Plan: ${shown2.stub}`, `${fileLabel}: ${relative9}`];
22388
22678
  if (shown2.header.issue !== null)
@@ -22801,11 +23091,11 @@ function createPrListCommand(seams = DEFAULT_PR_SEAMS) {
22801
23091
  var list_default7 = createPrListCommand();
22802
23092
 
22803
23093
  // src/commands/pr/merge.ts
22804
- import { existsSync as existsSync29, readFileSync as readFileSync30 } from "fs";
22805
- import { join as join36 } from "path";
23094
+ import { existsSync as existsSync30, readFileSync as readFileSync31 } from "fs";
23095
+ import { join as join37 } from "path";
22806
23096
 
22807
23097
  // src/board/roadmap-tick.ts
22808
- var PREFIX16 = "board roadmap";
23098
+ var PREFIX18 = "board roadmap";
22809
23099
  var REPO_PATH4 = "{owner}/{repo}";
22810
23100
  var TICK_ATTEMPTS = 2;
22811
23101
  var UNTICKED = /\[ \]/u;
@@ -22856,17 +23146,17 @@ function bodyOf(stdout, command) {
22856
23146
  try {
22857
23147
  payload = JSON.parse(stdout);
22858
23148
  } catch (error) {
22859
- throw new Error(`${PREFIX16}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
23149
+ throw new Error(`${PREFIX18}: ${command} wrote output that is not JSON: ${messageOf(error)}`, { cause: error });
22860
23150
  }
22861
23151
  const body = isMapping(payload) ? payload["body"] : null;
22862
23152
  if (typeof body !== "string") {
22863
- throw new Error(`${PREFIX16}: ${command} answered body as ${describeValue(body)}, expected a string`);
23153
+ throw new Error(`${PREFIX18}: ${command} answered body as ${describeValue(body)}, expected a string`);
22864
23154
  }
22865
23155
  return body;
22866
23156
  }
22867
23157
  function issueSegment(value, member) {
22868
23158
  if (!Number.isSafeInteger(value) || value < 1) {
22869
- throw new TypeError(`${PREFIX16}: ${member} refused issue number ${describeValue(value)}, expected a positive whole number`);
23159
+ throw new TypeError(`${PREFIX18}: ${member} refused issue number ${describeValue(value)}, expected a positive whole number`);
22870
23160
  }
22871
23161
  return String(value);
22872
23162
  }
@@ -22876,23 +23166,23 @@ function createGhRoadmapBody(options) {
22876
23166
  return Object.freeze({
22877
23167
  read: async (issue3) => {
22878
23168
  const path6 = pathOf(issue3, "read");
22879
- const result = await gh([path6]);
23169
+ const result = await gh(["api", path6]);
22880
23170
  if (!result.ok)
22881
- throw new Error(`${PREFIX16}: ${detailOf10(result, `gh api ${path6}`)}`);
23171
+ throw new Error(`${PREFIX18}: ${detailOf10(result, `gh api ${path6}`)}`);
22882
23172
  return bodyOf(result.stdout, `gh api ${path6}`);
22883
23173
  },
22884
23174
  write: async (issue3, body) => {
22885
23175
  const path6 = pathOf(issue3, "write");
22886
- const result = await gh([path6, "-X", "PATCH", "-f", `body=${body}`]);
23176
+ const result = await gh(["api", path6, "-X", "PATCH", "-f", `body=${body}`]);
22887
23177
  const command = `gh api ${path6} -X PATCH -f body=<body>`;
22888
23178
  if (!result.ok)
22889
- throw new Error(`${PREFIX16}: ${detailOf10(result, command)}`);
23179
+ throw new Error(`${PREFIX18}: ${detailOf10(result, command)}`);
22890
23180
  return bodyOf(result.stdout, command);
22891
23181
  }
22892
23182
  });
22893
23183
  }
22894
23184
  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";
23185
+ return `${PREFIX18}: issue #${String(issue3)} answered a body other than the one that was written,` + " so somebody edited it in between";
22896
23186
  }
22897
23187
  async function attemptTick(roadmap, issues, board, attempt4) {
22898
23188
  let edit;
@@ -22957,17 +23247,17 @@ function tickSentence(result) {
22957
23247
  import {
22958
23248
  chmodSync,
22959
23249
  copyFileSync as copyFileSync2,
22960
- existsSync as existsSync28,
22961
- mkdirSync as mkdirSync11,
22962
- readdirSync as readdirSync9,
22963
- readFileSync as readFileSync29,
23250
+ existsSync as existsSync29,
23251
+ mkdirSync as mkdirSync12,
23252
+ readdirSync as readdirSync10,
23253
+ readFileSync as readFileSync30,
22964
23254
  realpathSync as realpathSync5,
22965
23255
  renameSync as renameSync3,
22966
23256
  rmSync as rmSync2,
22967
- statSync as statSync15,
23257
+ statSync as statSync17,
22968
23258
  symlinkSync
22969
23259
  } from "fs";
22970
- import { basename as basename11, delimiter as delimiter3, dirname as dirname13, join as join35, relative as relative9, resolve as resolve17 } from "path";
23260
+ import { basename as basename12, delimiter as delimiter3, dirname as dirname13, join as join36, relative as relative9, resolve as resolve19 } from "path";
22971
23261
  var LINK_NAME = "rafa";
22972
23262
  var FORCE_FLAG = "--force";
22973
23263
  var EXIT_DONE = 0;
@@ -23028,20 +23318,20 @@ function runtimeRefusalLines(runtimeDir, version2) {
23028
23318
  ];
23029
23319
  }
23030
23320
  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));
23321
+ const dir = resolve19(repoRoot, planDir);
23322
+ 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
23323
  }
23034
23324
  function openTrackers(repoRoot, planDir) {
23035
23325
  return listTrackers(repoRoot, planDir).flatMap((path6) => {
23036
- const task = findNextTask(readFileSync29(join35(repoRoot, path6), "utf8"));
23326
+ const task = findNextTask(readFileSync30(join36(repoRoot, path6), "utf8"));
23037
23327
  return task ? [{ path: path6, task }] : [];
23038
23328
  });
23039
23329
  }
23040
23330
  function readManifestVersion2(repoRoot) {
23041
- const manifest = JSON.parse(readFileSync29(join35(repoRoot, "package.json"), "utf8"));
23331
+ const manifest = JSON.parse(readFileSync30(join36(repoRoot, "package.json"), "utf8"));
23042
23332
  const record = typeof manifest === "object" && manifest !== null ? manifest : {};
23043
23333
  if (record["name"] !== name) {
23044
- throw new Error(`${join35(repoRoot, "package.json")} names ${JSON.stringify(record["name"])}, not ${name}: this is no rafa checkout`);
23334
+ throw new Error(`${join36(repoRoot, "package.json")} names ${JSON.stringify(record["name"])}, not ${name}: this is no rafa checkout`);
23045
23335
  }
23046
23336
  const version2 = record["version"];
23047
23337
  if (typeof version2 !== "string" || !VERSION_SHAPE.test(version2)) {
@@ -23050,12 +23340,12 @@ function readManifestVersion2(repoRoot) {
23050
23340
  return version2;
23051
23341
  }
23052
23342
  function copyTree(from, to) {
23053
- mkdirSync11(to, { recursive: true });
23343
+ mkdirSync12(to, { recursive: true });
23054
23344
  let copied = 0;
23055
- const entries = readdirSync9(from, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
23345
+ const entries = readdirSync10(from, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
23056
23346
  for (const entry of entries) {
23057
- const source = join35(from, entry.name);
23058
- const target = join35(to, entry.name);
23347
+ const source = join36(from, entry.name);
23348
+ const target = join36(to, entry.name);
23059
23349
  if (entry.isDirectory()) {
23060
23350
  copied += copyTree(source, target);
23061
23351
  } else if (entry.isFile()) {
@@ -23080,7 +23370,7 @@ function replaceTree(from, to) {
23080
23370
  }
23081
23371
  }
23082
23372
  function swapIn(staging, to) {
23083
- if (!existsSync28(to)) {
23373
+ if (!existsSync29(to)) {
23084
23374
  renameSync3(staging, to);
23085
23375
  return;
23086
23376
  }
@@ -23096,7 +23386,7 @@ function swapIn(staging, to) {
23096
23386
  rmSync2(outgoing, { recursive: true, force: true });
23097
23387
  }
23098
23388
  function relink(linkPath, target) {
23099
- mkdirSync11(dirname13(linkPath), { recursive: true });
23389
+ mkdirSync12(dirname13(linkPath), { recursive: true });
23100
23390
  const temporary = temporaryName(linkPath);
23101
23391
  rmSync2(temporary, { force: true });
23102
23392
  try {
@@ -23150,20 +23440,20 @@ function installRuntime(seams, options = {}) {
23150
23440
  }
23151
23441
  function runInstall(seams, options) {
23152
23442
  const { repoRoot, home, log } = seams;
23153
- const runtimeRoot = join35(home, RUNTIME_SUBDIR);
23154
- const linkPath = join35(home, RAFA_BIN_DIR, LINK_NAME);
23443
+ const runtimeRoot = join36(home, RUNTIME_SUBDIR);
23444
+ const linkPath = join36(home, RAFA_BIN_DIR, LINK_NAME);
23155
23445
  log(`repo root: ${repoRoot}`);
23156
23446
  log(`runtime root: ${runtimeRoot}`);
23157
23447
  log(`link: ${linkPath}`);
23158
23448
  const version2 = inStage("manifest", () => readManifestVersion2(repoRoot));
23159
- const planDir = inStage("config", () => resolve17(repoRoot, loadConfig({ root: repoRoot, home }, {}, seams.warn).config.planDir));
23449
+ const planDir = inStage("config", () => resolve19(repoRoot, loadConfig({ root: repoRoot, home }, {}, seams.warn).config.planDir));
23160
23450
  log(`plan dir: ${planDir}`);
23161
23451
  const open = inStage("trackers", () => openTrackers(repoRoot, planDir));
23162
23452
  if (open.length > 0)
23163
23453
  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);
23454
+ const distDir = join36(repoRoot, "dist");
23455
+ const runtimeDir = join36(runtimeRoot, version2);
23456
+ const installed = existsSync29(runtimeDir);
23167
23457
  if (installed && options.force !== true) {
23168
23458
  return { kind: "refused", reason: "runtime-exists", version: version2, runtimeDir };
23169
23459
  }
@@ -23171,13 +23461,13 @@ function runInstall(seams, options) {
23171
23461
  const code = inStage("build", () => seams.build(repoRoot));
23172
23462
  if (code !== 0)
23173
23463
  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)}`);
23464
+ if (!existsSync29(join36(distDir, RUNTIME_ENTRY))) {
23465
+ throw new StageFailure("build", `the build exited 0 and left no ${join36(distDir, RUNTIME_ENTRY)}`);
23176
23466
  }
23177
23467
  log(installed ? `copying ${distDir} over ${runtimeDir}, replacing it whole` : `copying ${distDir} into ${runtimeDir}`);
23178
23468
  const copied = inStage("copy", () => replaceTree(distDir, runtimeDir));
23179
23469
  log(`copied ${copied} file(s)`);
23180
- const resolved = inStage("link", () => relink(linkPath, join35(runtimeDir, RUNTIME_ENTRY)));
23470
+ const resolved = inStage("link", () => relink(linkPath, join36(runtimeDir, RUNTIME_ENTRY)));
23181
23471
  log(`${linkPath} resolves to ${resolved}`);
23182
23472
  return { kind: "done", version: version2, runtimeDir, linkPath, resolved, copied };
23183
23473
  }
@@ -23192,7 +23482,7 @@ function inStage(stage, run) {
23192
23482
  }
23193
23483
  function entryNames(dir) {
23194
23484
  try {
23195
- return readdirSync9(dir);
23485
+ return readdirSync10(dir);
23196
23486
  } catch (err) {
23197
23487
  if (typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT")
23198
23488
  return [];
@@ -23203,7 +23493,7 @@ function replaceFile(source, target) {
23203
23493
  const temporary = temporaryName(target);
23204
23494
  try {
23205
23495
  copyFileSync2(source, temporary);
23206
- chmodSync(temporary, statSync15(source).mode & 4095);
23496
+ chmodSync(temporary, statSync17(source).mode & 4095);
23207
23497
  renameSync3(temporary, target);
23208
23498
  } catch (err) {
23209
23499
  rmSync2(temporary, { force: true });
@@ -23211,7 +23501,7 @@ function replaceFile(source, target) {
23211
23501
  }
23212
23502
  }
23213
23503
  function temporaryName(path6) {
23214
- return join35(dirname13(path6), `.${basename11(path6)}.snapshot-${process.pid}`);
23504
+ return join36(dirname13(path6), `.${basename12(path6)}.snapshot-${process.pid}`);
23215
23505
  }
23216
23506
 
23217
23507
  // src/commands/pr/merge-followups.ts
@@ -23502,13 +23792,13 @@ function remoteHoldsBranch(git, branch, warn) {
23502
23792
  }
23503
23793
  function textOf3(path6) {
23504
23794
  try {
23505
- return readFileSync30(path6, "utf8");
23795
+ return readFileSync31(path6, "utf8");
23506
23796
  } catch {
23507
23797
  return "";
23508
23798
  }
23509
23799
  }
23510
23800
  function followUpsFor(pr, git) {
23511
- const facts = readPackageFacts(textOf3(join36(pr.project.root, "package.json")));
23801
+ const facts = readPackageFacts(textOf3(join37(pr.project.root, "package.json")));
23512
23802
  if (facts.version === null)
23513
23803
  return [];
23514
23804
  const tags = git(["tag", "--list", versionTag(facts.version)]);
@@ -23516,7 +23806,7 @@ function followUpsFor(pr, git) {
23516
23806
  version: facts.version,
23517
23807
  tagged: tags.ok && tags.stdout.trim() !== "",
23518
23808
  rafaCheckout: facts.rafaCheckout,
23519
- runtimeInstalled: existsSync29(join36(pr.project.home, RUNTIME_SUBDIR, facts.version))
23809
+ runtimeInstalled: existsSync30(join37(pr.project.home, RUNTIME_SUBDIR, facts.version))
23520
23810
  });
23521
23811
  }
23522
23812
  function openGh(pr, seams) {
@@ -23767,7 +24057,7 @@ var COLUMN = "\t";
23767
24057
  var BOM = "\uFEFF";
23768
24058
  var TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z /;
23769
24059
  var COLOUR = new RegExp(`(?:${String.fromCharCode(27)}|\\^\\[)\\[[0-9;]*m`, "g");
23770
- var PREFIX17 = "pr triage evidence";
24060
+ var PREFIX19 = "pr triage evidence";
23771
24061
  function named2(value) {
23772
24062
  return value === "" ? undefined : value;
23773
24063
  }
@@ -23833,7 +24123,7 @@ function readCap(value) {
23833
24123
  if (value === undefined)
23834
24124
  return FAILED_LOG_TAIL_LINES;
23835
24125
  if (!Number.isSafeInteger(value) || value < 1) {
23836
- throw new TypeError(`${PREFIX17}: readFailedLog refused a line cap ${describeValue(value)},` + " expected a positive whole number");
24126
+ throw new TypeError(`${PREFIX19}: readFailedLog refused a line cap ${describeValue(value)},` + " expected a positive whole number");
23837
24127
  }
23838
24128
  return value;
23839
24129
  }
@@ -24720,8 +25010,8 @@ function describeAge(updatedAt, now) {
24720
25010
  return `${plural4(hours, "hour", "hours")} ago`;
24721
25011
  return `${plural4(Math.floor(age / DAY_MS2), "day", "days")} ago`;
24722
25012
  }
24723
- function triageCommand(number, resolve18 = false) {
24724
- return resolve18 ? `rafa pr triage ${number} --resolve` : `rafa pr triage ${number}`;
25013
+ function triageCommand(number, resolve20 = false) {
25014
+ return resolve20 ? `rafa pr triage ${number} --resolve` : `rafa pr triage ${number}`;
24725
25015
  }
24726
25016
  function joinNumbers(pulls) {
24727
25017
  const names = pulls.map((pull) => `#${pull.number}`);
@@ -24732,14 +25022,14 @@ function joinNumbers(pulls) {
24732
25022
  function byNumber(pulls) {
24733
25023
  return Object.freeze([...pulls].sort((left, right) => left.number - right.number));
24734
25024
  }
24735
- function skipped(pull, now, resolve18) {
25025
+ function skipped(pull, now, resolve20) {
24736
25026
  return Object.freeze({
24737
25027
  number: pull.number,
24738
25028
  title: pull.title,
24739
25029
  updatedAt: pull.updatedAt,
24740
25030
  age: describeAge(pull.updatedAt, now),
24741
25031
  fresh: isFreshCandidate(pull.updatedAt, now),
24742
- command: triageCommand(pull.number, resolve18)
25032
+ command: triageCommand(pull.number, resolve20)
24743
25033
  });
24744
25034
  }
24745
25035
  function skippedLine(one) {
@@ -24783,15 +25073,15 @@ function listReading(rest, count) {
24783
25073
  return listing2("list", Object.freeze([]), rest, headline);
24784
25074
  }
24785
25075
  function selectTriagePullRequests(input) {
24786
- const resolve18 = input.resolve === true;
25076
+ const resolve20 = input.resolve === true;
24787
25077
  const { current, now } = input;
24788
25078
  if (current !== null) {
24789
25079
  return plain("branch", Object.freeze([current]), `assessing #${current.number}, the pull request open on ${current.headRefName}`);
24790
25080
  }
24791
25081
  const candidates = byNumber(input.candidates);
24792
25082
  const count = candidates.length;
24793
- const lines = candidates.map((pull) => skipped(pull, now, resolve18));
24794
- if (resolve18 && count > 1)
25083
+ const lines = candidates.map((pull) => skipped(pull, now, resolve20));
25084
+ if (resolve20 && count > 1)
24795
25085
  return refusal9(lines, count);
24796
25086
  if (count === 0) {
24797
25087
  return plain("none", Object.freeze([]), "no red pull request to triage, and no pull request on the current branch");
@@ -25093,11 +25383,11 @@ function renderTriages(readings) {
25093
25383
  var BUDGET_KEY = "budget";
25094
25384
  var TASK_LINE2 = /^- \[[^\]]*\] /;
25095
25385
  var TRAILING_BLOCK = /\{([^{}]*)\}$/;
25096
- var PREFIX18 = "pr triage --resolve budget";
25386
+ var PREFIX20 = "pr triage --resolve budget";
25097
25387
  function budgetEntry(usd) {
25098
25388
  const spelled = String(usd);
25099
25389
  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");
25390
+ 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
25391
  }
25102
25392
  return `${BUDGET_KEY}=${spelled}`;
25103
25393
  }
@@ -25126,8 +25416,8 @@ function withTaskBudget(plan2, usd) {
25126
25416
  }
25127
25417
 
25128
25418
  // 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";
25419
+ import { existsSync as existsSync31, readFileSync as readFileSync32 } from "fs";
25420
+ import { dirname as dirname14, join as join38 } from "path";
25131
25421
  import { fileURLToPath as fileURLToPath4 } from "url";
25132
25422
  var MODULE_DIR2 = dirname14(fileURLToPath4(import.meta.url));
25133
25423
  var PINNED_PLANS_DIRNAME = "plans";
@@ -25144,8 +25434,8 @@ function hasPinnedPlan(triageClass) {
25144
25434
  function pinnedPlanCandidates(moduleDir, triageClass) {
25145
25435
  const name2 = pinnedPlanFileName(triageClass);
25146
25436
  return [
25147
- join37(moduleDir, PINNED_PLANS_DIRNAME, name2),
25148
- join37(moduleDir, name2)
25437
+ join38(moduleDir, PINNED_PLANS_DIRNAME, name2),
25438
+ join38(moduleDir, name2)
25149
25439
  ];
25150
25440
  }
25151
25441
  function readPinnedPlan(triageClass, lookup = {}) {
@@ -25153,11 +25443,11 @@ function readPinnedPlan(triageClass, lookup = {}) {
25153
25443
  throw new Error(`No pinned resolve plan ships for ${triageClass}; ` + `one ships for ${PINNED_PLAN_CLASSES.join(", ")}`);
25154
25444
  }
25155
25445
  const candidates = pinnedPlanCandidates(lookup.moduleDir ?? MODULE_DIR2, triageClass);
25156
- const found = candidates.find((candidate) => existsSync30(candidate));
25446
+ const found = candidates.find((candidate) => existsSync31(candidate));
25157
25447
  if (found === undefined) {
25158
25448
  throw new Error(`The pinned resolve plan for ${triageClass} is missing: ` + `no file at ${candidates.join(" or ")}`);
25159
25449
  }
25160
- return readFileSync31(found, "utf8");
25450
+ return readFileSync32(found, "utf8");
25161
25451
  }
25162
25452
  var SLOT_PATTERN2 = /\{[A-Z][A-Z0-9_]*\}/g;
25163
25453
  var CONFLICT_SENTENCE_SLOT = "CONFLICT_SENTENCE";
@@ -25220,12 +25510,12 @@ var ATTEMPT_STOPS = Object.freeze([
25220
25510
  "cap",
25221
25511
  "repeat"
25222
25512
  ]);
25223
- var PREFIX19 = "pr triage attempts";
25513
+ var PREFIX21 = "pr triage attempts";
25224
25514
  var WHITESPACE2 = /\s+/g;
25225
25515
  var NO_STEP_KEY = "";
25226
25516
  function readCap2(maxAttempts) {
25227
25517
  if (!Number.isSafeInteger(maxAttempts) || maxAttempts < 1) {
25228
- throw new TypeError(`${PREFIX19}: refused a cap of ${JSON.stringify(maxAttempts)},` + " expected a positive whole number");
25518
+ throw new TypeError(`${PREFIX21}: refused a cap of ${JSON.stringify(maxAttempts)},` + " expected a positive whole number");
25229
25519
  }
25230
25520
  return maxAttempts;
25231
25521
  }
@@ -25297,13 +25587,13 @@ function readAttemptRepeat(input) {
25297
25587
  }
25298
25588
 
25299
25589
  // 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");
25590
+ import { existsSync as existsSync32, realpathSync as realpathSync6 } from "fs";
25591
+ import { join as join39 } from "path";
25592
+ var WORKTREES_SUBDIR = join39(".rafa", "worktrees");
25303
25593
  var WORKTREE_PREFIX = "pr-";
25304
25594
  var REFUSAL_PREFIX3 = "rafa pr triage --resolve refuses";
25305
25595
  function resolveWorktreePath(home, number) {
25306
- return join38(home, WORKTREES_SUBDIR, `${WORKTREE_PREFIX}${number}`);
25596
+ return join39(home, WORKTREES_SUBDIR, `${WORKTREE_PREFIX}${number}`);
25307
25597
  }
25308
25598
  function crossRepositoryRefusal(pr) {
25309
25599
  if (!pr.isCrossRepository)
@@ -25346,7 +25636,7 @@ function removeResolveWorktree(git, path6) {
25346
25636
  return runStep(git, removeWorktreeStep(path6));
25347
25637
  }
25348
25638
  function pathForms(path6) {
25349
- if (!existsSync31(path6))
25639
+ if (!existsSync32(path6))
25350
25640
  return [path6];
25351
25641
  return [path6, realpathSync6(path6)];
25352
25642
  }
@@ -25359,20 +25649,20 @@ function worktreeAt(git, path6) {
25359
25649
  }
25360
25650
 
25361
25651
  // 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");
25652
+ import { mkdirSync as mkdirSync13, writeFileSync as writeFileSync15 } from "fs";
25653
+ import { join as join40 } from "path";
25654
+ var RESOLVE_SUBDIR = join40(".rafa", "resolve");
25365
25655
  var RUN_PREFIX = "pr-";
25366
25656
  var ATTEMPT_PREFIX = "attempt-";
25367
25657
  var LOOP_WORDS = Object.freeze(["loop", "start"]);
25368
25658
  var CHILD_OUTPUT = "text";
25369
25659
  function resolveRunDir(home, number, attempt4) {
25370
- return join39(home, RESOLVE_SUBDIR, `${RUN_PREFIX}${number}`, `${ATTEMPT_PREFIX}${attempt4}`);
25660
+ return join40(home, RESOLVE_SUBDIR, `${RUN_PREFIX}${number}`, `${ATTEMPT_PREFIX}${attempt4}`);
25371
25661
  }
25372
25662
  function writeResolvePlan(write) {
25373
25663
  const dir = resolveRunDir(write.home, write.number, write.attempt);
25374
- mkdirSync12(dir, { recursive: true });
25375
- const path6 = join39(dir, pinnedPlanFileName(write.triageClass));
25664
+ mkdirSync13(dir, { recursive: true });
25665
+ const path6 = join40(dir, pinnedPlanFileName(write.triageClass));
25376
25666
  writeFileSync15(path6, write.plan, "utf8");
25377
25667
  return path6;
25378
25668
  }
@@ -25772,16 +26062,16 @@ async function redPullRequests(pr) {
25772
26062
  }
25773
26063
  return red;
25774
26064
  }
25775
- async function selectTargets(pr, warn, now, resolve18) {
26065
+ async function selectTargets(pr, warn, now, resolve20) {
25776
26066
  const branch = readBranchOrNone(pr, warn);
25777
26067
  const current = branch === null ? null : await onProvider(`read the open pull request for the branch "${branch}"`, () => pr.pulls.findOpen(branch));
25778
26068
  if (current !== null)
25779
- return selectTriagePullRequests({ current, candidates: [], now, resolve: resolve18 });
26069
+ return selectTriagePullRequests({ current, candidates: [], now, resolve: resolve20 });
25780
26070
  return selectTriagePullRequests({
25781
26071
  current: null,
25782
26072
  candidates: await redPullRequests(pr),
25783
26073
  now,
25784
- resolve: resolve18
26074
+ resolve: resolve20
25785
26075
  });
25786
26076
  }
25787
26077
  async function detailOf11(pr, number) {
@@ -25902,7 +26192,7 @@ async function runTriage(context, seams) {
25902
26192
  }
25903
26193
  const numbers = asked === null ? (selection?.assess ?? []).map((one) => one.number) : [asked];
25904
26194
  const readings = [];
25905
- let resolve18 = null;
26195
+ let resolve20 = null;
25906
26196
  for (const number of numbers) {
25907
26197
  const assess = () => assessOne({
25908
26198
  pr,
@@ -25918,7 +26208,7 @@ async function runTriage(context, seams) {
25918
26208
  readings.push(reading2);
25919
26209
  continue;
25920
26210
  }
25921
- resolve18 = await resolvePullRequest({
26211
+ resolve20 = await resolvePullRequest({
25922
26212
  trust: {
25923
26213
  permissions,
25924
26214
  trustedAuthors: pr.trustedAuthors,
@@ -25939,16 +26229,16 @@ async function runTriage(context, seams) {
25939
26229
  ...seams.clock === undefined ? {} : { clock: seams.clock },
25940
26230
  ...seams.sleep === undefined ? {} : { sleep: seams.sleep }
25941
26231
  });
25942
- readings.push(resolve18.reading);
26232
+ readings.push(resolve20.reading);
25943
26233
  }
25944
26234
  const text2 = [
25945
26235
  ...selection === null ? [] : [selection.message],
25946
26236
  ...readings.length === 0 ? [] : [renderTriages(readings)],
25947
- ...resolve18 === null ? [] : resolve18.lines
26237
+ ...resolve20 === null ? [] : resolve20.lines
25948
26238
  ].join(`
25949
26239
 
25950
26240
  `);
25951
- return { selection, readings, resolve: resolve18, text: text2, exitCode: resolve18?.exitCode ?? 0 };
26241
+ return { selection, readings, resolve: resolve20, text: text2, exitCode: resolve20?.exitCode ?? 0 };
25952
26242
  }
25953
26243
  function createPrTriageCommand(seams = DEFAULT_TRIAGE_SEAMS) {
25954
26244
  const command = {
@@ -26236,8 +26526,8 @@ function createPrWaitCommand(seams = DEFAULT_WAIT_SEAMS) {
26236
26526
  var wait_default = createPrWaitCommand();
26237
26527
 
26238
26528
  // 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";
26529
+ import { existsSync as existsSync33, readdirSync as readdirSync11, readFileSync as readFileSync33 } from "fs";
26530
+ import { join as join41 } from "path";
26241
26531
  var RELEASE_STATUS_USAGE = "rafa release status [--plan=<stub>]";
26242
26532
  var UNREADABLE2 = "?";
26243
26533
  var NOTHING = "none";
@@ -26338,13 +26628,13 @@ function untaggedVersions(released, tags) {
26338
26628
  }
26339
26629
  function textOf4(path6) {
26340
26630
  try {
26341
- return readFileSync32(path6, "utf8");
26631
+ return readFileSync33(path6, "utf8");
26342
26632
  } catch {
26343
26633
  return null;
26344
26634
  }
26345
26635
  }
26346
26636
  function readVersionFile(root, configured) {
26347
- const resolved = join40(root, configured);
26637
+ const resolved = join41(root, configured);
26348
26638
  const text2 = textOf4(resolved);
26349
26639
  if (text2 === null) {
26350
26640
  return { path: configured, version: null, problem: `the version file could not be read at ${resolved}` };
@@ -26361,7 +26651,7 @@ function readTags(git) {
26361
26651
  return { tags, latest: tags[0] ?? null, problem: null };
26362
26652
  }
26363
26653
  function readUntagged(root, configured, tags) {
26364
- const resolved = join40(root, configured);
26654
+ const resolved = join41(root, configured);
26365
26655
  const text2 = textOf4(resolved);
26366
26656
  if (text2 === null) {
26367
26657
  return {
@@ -26380,11 +26670,11 @@ function readBranch2(git) {
26380
26670
  return result.ok && branch !== "" && branch !== "HEAD" ? branch : null;
26381
26671
  }
26382
26672
  function planStubsUnder(root, planDir) {
26383
- const resolved = join40(root, planDir);
26384
- if (!existsSync32(resolved))
26673
+ const resolved = join41(root, planDir);
26674
+ if (!existsSync33(resolved))
26385
26675
  return [];
26386
26676
  try {
26387
- return planStubsFromFileNames(readdirSync10(resolved));
26677
+ return planStubsFromFileNames(readdirSync11(resolved));
26388
26678
  } catch {
26389
26679
  return [];
26390
26680
  }
@@ -26582,8 +26872,8 @@ function createReleaseStatusCommand(seams = DEFAULT_RELEASE_SEAMS) {
26582
26872
  var status_default2 = createReleaseStatusCommand();
26583
26873
 
26584
26874
  // src/commands/release/tag.ts
26585
- import { readFileSync as readFileSync33 } from "fs";
26586
- import { join as join41 } from "path";
26875
+ import { readFileSync as readFileSync34 } from "fs";
26876
+ import { join as join42 } from "path";
26587
26877
  var RELEASE_TAG_USAGE = "rafa release tag";
26588
26878
  var DEFAULT_RELEASE_BRANCH = "main";
26589
26879
  var DEFAULT_REGISTRY = "https://registry.npmjs.org";
@@ -26602,13 +26892,13 @@ function readBranch3(git) {
26602
26892
  }
26603
26893
  function textOf5(path6) {
26604
26894
  try {
26605
- return readFileSync33(path6, "utf8");
26895
+ return readFileSync34(path6, "utf8");
26606
26896
  } catch {
26607
26897
  return null;
26608
26898
  }
26609
26899
  }
26610
26900
  function readVersion(root, configured) {
26611
- const resolved = join41(root, configured);
26901
+ const resolved = join42(root, configured);
26612
26902
  const text2 = textOf5(resolved);
26613
26903
  if (text2 === null) {
26614
26904
  return {
@@ -26622,7 +26912,7 @@ function readVersion(root, configured) {
26622
26912
  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
26913
  }
26624
26914
  function readNewestRelease(root, configured) {
26625
- const resolved = join41(root, configured);
26915
+ const resolved = join42(root, configured);
26626
26916
  const text2 = textOf5(resolved);
26627
26917
  if (text2 === null) {
26628
26918
  return { path: configured, version: null, problem: `the changelog could not be read at ${resolved}` };
@@ -26887,17 +27177,17 @@ function createSelfUpdateCommand(seams = DEFAULT_SELF_UPDATE_SEAMS) {
26887
27177
  var self_update_default = createSelfUpdateCommand();
26888
27178
 
26889
27179
  // src/commands/skill/backfill.ts
26890
- import { statSync as statSync17 } from "fs";
26891
- import { join as join46, resolve as resolve20 } from "path";
27180
+ import { statSync as statSync19 } from "fs";
27181
+ import { join as join47, resolve as resolve22 } from "path";
26892
27182
 
26893
27183
  // 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";
27184
+ import { copyFileSync as copyFileSync3, existsSync as existsSync34, mkdirSync as mkdirSync14 } from "fs";
27185
+ import { dirname as dirname15, isAbsolute as isAbsolute11, join as join44, relative as relative10, resolve as resolve20, sep as sep5 } from "path";
26896
27186
 
26897
27187
  // 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");
27188
+ import { readdirSync as readdirSync12, readFileSync as readFileSync35 } from "fs";
27189
+ import { join as join43 } from "path";
27190
+ var BACKFILL_PATH = join43(".rafa", "backfill");
26901
27191
  var PROPOSAL_FILE_PREFIX = "proposals-";
26902
27192
  var PROPOSAL_FILE_EXTENSION = ".yaml";
26903
27193
  var SHA256_PATTERN = /^[0-9a-f]{64}$/;
@@ -26923,7 +27213,7 @@ var PROPOSAL_FILE_HEADER = [
26923
27213
  ].join(`
26924
27214
  `);
26925
27215
  function proposalPath(dir, batch) {
26926
- return join42(dir, `${PROPOSAL_FILE_PREFIX}${String(batch).padStart(2, "0")}${PROPOSAL_FILE_EXTENSION}`);
27216
+ return join43(dir, `${PROPOSAL_FILE_PREFIX}${String(batch).padStart(2, "0")}${PROPOSAL_FILE_EXTENSION}`);
26927
27217
  }
26928
27218
  function isProposalFileName(name2) {
26929
27219
  return name2.startsWith(PROPOSAL_FILE_PREFIX) && name2.endsWith(PROPOSAL_FILE_EXTENSION);
@@ -27054,14 +27344,14 @@ function parseProposalFile(text2) {
27054
27344
  function readProposalFiles(dir) {
27055
27345
  let names;
27056
27346
  try {
27057
- names = readdirSync11(dir);
27347
+ names = readdirSync12(dir);
27058
27348
  } catch {
27059
27349
  return [];
27060
27350
  }
27061
27351
  return names.filter((name2) => isProposalFileName(name2)).sort((left, right) => left.localeCompare(right)).map((name2) => {
27062
- const path6 = join42(dir, name2);
27352
+ const path6 = join43(dir, name2);
27063
27353
  try {
27064
- return { path: path6, result: parseProposalFile(readFileSync34(path6, "utf8")) };
27354
+ return { path: path6, result: parseProposalFile(readFileSync35(path6, "utf8")) };
27065
27355
  } catch (error) {
27066
27356
  return { path: path6, result: unreadable2(`the file cannot be read (${error instanceof Error ? error.message : String(error)})`) };
27067
27357
  }
@@ -27069,19 +27359,19 @@ function readProposalFiles(dir) {
27069
27359
  }
27070
27360
 
27071
27361
  // src/backfill/backup.ts
27072
- var BACKUP_PATH = join43(BACKFILL_PATH, "backup");
27362
+ var BACKUP_PATH = join44(BACKFILL_PATH, "backup");
27073
27363
  var BACKUP_KINDS = ["copied", "kept", "tracked", "outside", "missing"];
27074
27364
  function backupDirectory(base) {
27075
- return join43(base, BACKUP_PATH);
27365
+ return join44(base, BACKUP_PATH);
27076
27366
  }
27077
27367
  function isUnder(root, path6) {
27078
- const step2 = relative10(resolve18(root), resolve18(path6));
27368
+ const step2 = relative10(resolve20(root), resolve20(path6));
27079
27369
  return step2 === "" || !step2.startsWith(`..${sep5}`) && step2 !== ".." && !isAbsolute11(step2);
27080
27370
  }
27081
27371
  function backupPathFor(path6, root, backupDir) {
27082
27372
  if (!isUnder(root, path6))
27083
27373
  return null;
27084
- return join43(backupDir, relative10(resolve18(root), resolve18(path6)));
27374
+ return join44(backupDir, relative10(resolve20(root), resolve20(path6)));
27085
27375
  }
27086
27376
  function backupFile(path6, options) {
27087
27377
  if (options.repoRoot !== null && isUnder(options.repoRoot, path6)) {
@@ -27090,11 +27380,11 @@ function backupFile(path6, options) {
27090
27380
  const backup = backupPathFor(path6, options.root, options.backupDir);
27091
27381
  if (backup === null)
27092
27382
  return { path: path6, kind: "outside", backup: null };
27093
- if (!existsSync33(path6))
27383
+ if (!existsSync34(path6))
27094
27384
  return { path: path6, kind: "missing", backup: null };
27095
- if (existsSync33(backup))
27385
+ if (existsSync34(backup))
27096
27386
  return { path: path6, kind: "kept", backup };
27097
- mkdirSync13(dirname15(backup), { recursive: true });
27387
+ mkdirSync14(dirname15(backup), { recursive: true });
27098
27388
  copyFileSync3(path6, backup);
27099
27389
  return { path: path6, kind: "copied", backup };
27100
27390
  }
@@ -27117,8 +27407,8 @@ function countBackups(results) {
27117
27407
  }
27118
27408
 
27119
27409
  // src/backfill/derive.ts
27120
- import { readFileSync as readFileSync35, writeFileSync as writeFileSync16 } from "fs";
27121
- import { basename as basename12 } from "path";
27410
+ import { readFileSync as readFileSync36, writeFileSync as writeFileSync16 } from "fs";
27411
+ import { basename as basename13 } from "path";
27122
27412
 
27123
27413
  // src/demote/classify.ts
27124
27414
  var LEARNED_DIRECTORY = "learned";
@@ -27575,15 +27865,15 @@ function fileChanges(name2, data, body, options) {
27575
27865
  return { changes, notes };
27576
27866
  }
27577
27867
  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`);
27868
+ if (basename13(entry.path) !== SKILL_FILE) {
27869
+ return inert(entry, "skipped", `${basename13(entry.path)} is no ${SKILL_FILE}, so it registers no skill`);
27580
27870
  }
27581
27871
  if (entry.name === null) {
27582
27872
  return inert(entry, "skipped", "its place implies no skill name, so no stack can be derived from it");
27583
27873
  }
27584
27874
  let original;
27585
27875
  try {
27586
- original = readFileSync35(entry.path, "utf8");
27876
+ original = readFileSync36(entry.path, "utf8");
27587
27877
  } catch (error) {
27588
27878
  return inert(entry, "skipped", `the file cannot be read (${error instanceof Error ? error.message : String(error)})`);
27589
27879
  }
@@ -27627,7 +27917,7 @@ function planDerivation(root, options) {
27627
27917
  function applyFile(action, options) {
27628
27918
  if (action.text === null || action.original === null)
27629
27919
  return action;
27630
- const current = readFileSync35(action.path, "utf8");
27920
+ const current = readFileSync36(action.path, "utf8");
27631
27921
  if (current !== action.original) {
27632
27922
  return {
27633
27923
  ...action,
@@ -27658,7 +27948,7 @@ function applyDerivation(plan2, options) {
27658
27948
  }
27659
27949
 
27660
27950
  // src/backfill/proposal-batch.ts
27661
- import { readFileSync as readFileSync36 } from "fs";
27951
+ import { readFileSync as readFileSync37 } from "fs";
27662
27952
  import { relative as relative11 } from "path";
27663
27953
 
27664
27954
  // src/demote/report.ts
@@ -27957,7 +28247,7 @@ function readCandidate(root, entry) {
27957
28247
  return null;
27958
28248
  let text2;
27959
28249
  try {
27960
- text2 = readFileSync36(entry.path, "utf8");
28250
+ text2 = readFileSync37(entry.path, "utf8");
27961
28251
  } catch {
27962
28252
  return null;
27963
28253
  }
@@ -28063,8 +28353,8 @@ function parseSessionAnswer(stdout) {
28063
28353
  }
28064
28354
 
28065
28355
  // 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";
28356
+ import { mkdirSync as mkdirSync15, readFileSync as readFileSync38, writeFileSync as writeFileSync17 } from "fs";
28357
+ import { join as join45, resolve as resolve21 } from "path";
28068
28358
  var PROPOSAL_ACTION_KINDS = [
28069
28359
  "applied",
28070
28360
  "unchanged",
@@ -28143,7 +28433,7 @@ async function runProposalPass(options) {
28143
28433
  const batches = batchCandidates(candidates);
28144
28434
  const written = [];
28145
28435
  if (batches.length > 0)
28146
- mkdirSync14(options.backfillDir, { recursive: true });
28436
+ mkdirSync15(options.backfillDir, { recursive: true });
28147
28437
  for (const [index, batch] of batches.entries()) {
28148
28438
  const number = index + 1;
28149
28439
  const file = await runProposalBatch(number, batch, options);
@@ -28213,7 +28503,7 @@ function writeRow(path6, row2, original, options) {
28213
28503
  };
28214
28504
  }
28215
28505
  function applyRow(root, row2, options) {
28216
- const path6 = join44(root, ...row2.path.split("/"));
28506
+ const path6 = join45(root, ...row2.path.split("/"));
28217
28507
  if (row2.status === UNANSWERED_ROW) {
28218
28508
  return inert2(path6, row2, "unanswered", row2.note ?? "the row carries no answer");
28219
28509
  }
@@ -28222,7 +28512,7 @@ function applyRow(root, row2, options) {
28222
28512
  }
28223
28513
  let original;
28224
28514
  try {
28225
- original = readFileSync37(path6, "utf8");
28515
+ original = readFileSync38(path6, "utf8");
28226
28516
  } catch {
28227
28517
  return inert2(path6, row2, "refused", "the file the row names is gone");
28228
28518
  }
@@ -28236,7 +28526,7 @@ function fileRefusal(file, root) {
28236
28526
  if (file.status !== REVIEWED_FILE) {
28237
28527
  return `the proposal file is still marked ${file.status}: review it and mark it ${REVIEWED_FILE}`;
28238
28528
  }
28239
- return resolve19(file.skills) === resolve19(root) ? null : `the proposal file names the skills directory ${file.skills}, not ${root}`;
28529
+ return resolve21(file.skills) === resolve21(root) ? null : `the proposal file names the skills directory ${file.skills}, not ${root}`;
28240
28530
  }
28241
28531
  function countProposalActions(actions) {
28242
28532
  const counts = Object.fromEntries(PROPOSAL_ACTION_KINDS.map((kind) => [kind, 0]));
@@ -28250,7 +28540,7 @@ function applyProposals(files, root, options) {
28250
28540
  for (const file of files) {
28251
28541
  const refusal10 = fileRefusal(file, root);
28252
28542
  for (const row2 of file.rows) {
28253
- const action = refusal10 === null ? applyRow(root, row2, options) : inert2(join44(root, ...row2.path.split("/")), row2, "refused", refusal10);
28543
+ const action = refusal10 === null ? applyRow(root, row2, options) : inert2(join45(root, ...row2.path.split("/")), row2, "refused", refusal10);
28254
28544
  actions.push(action);
28255
28545
  if (row2.trigger !== null && action.kind !== "refused" && action.kind !== "unanswered") {
28256
28546
  triggers[row2.name] = row2.trigger;
@@ -28261,13 +28551,13 @@ function applyProposals(files, root, options) {
28261
28551
  }
28262
28552
 
28263
28553
  // 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";
28554
+ import { readdirSync as readdirSync13, readFileSync as readFileSync39, realpathSync as realpathSync7, statSync as statSync18 } from "fs";
28555
+ import { basename as basename14, dirname as dirname16, join as join46 } from "path";
28266
28556
  var SKILLS_DIRECTORY = "skills";
28267
28557
  var CLAUDE_DIRECTORY = ".claude";
28268
28558
  var AUTO_EXTRACTED_ORIGIN = "auto-extracted";
28269
- var DEMOTED_PATH = join45(".rafa", "demoted");
28270
- var INSTINCTS_PATH = join45(".rafa", "instincts");
28559
+ var DEMOTED_PATH = join46(".rafa", "demoted");
28560
+ var INSTINCTS_PATH = join46(".rafa", "instincts");
28271
28561
  var REPORT_FILE = "report.md";
28272
28562
  function realOrSelf(path6) {
28273
28563
  try {
@@ -28284,25 +28574,25 @@ function samePath(left, right) {
28284
28574
  return resolved === other || resolved.toLowerCase() === other.toLowerCase();
28285
28575
  }
28286
28576
  function resolveDemotionScope(dir, home) {
28287
- if (basename13(dir) !== SKILLS_DIRECTORY)
28577
+ if (basename14(dir) !== SKILLS_DIRECTORY)
28288
28578
  return null;
28289
28579
  const claude = dirname16(dir);
28290
- if (basename13(claude) !== CLAUDE_DIRECTORY)
28580
+ if (basename14(claude) !== CLAUDE_DIRECTORY)
28291
28581
  return null;
28292
28582
  const base = dirname16(claude);
28293
- const demotedDir = join45(base, DEMOTED_PATH);
28583
+ const demotedDir = join46(base, DEMOTED_PATH);
28294
28584
  return {
28295
28585
  scope: samePath(base, home) ? "user" : "project",
28296
28586
  dir,
28297
28587
  base,
28298
28588
  demotedDir,
28299
- instinctsDir: join45(base, INSTINCTS_PATH),
28300
- reportPath: join45(demotedDir, REPORT_FILE)
28589
+ instinctsDir: join46(base, INSTINCTS_PATH),
28590
+ reportPath: join46(demotedDir, REPORT_FILE)
28301
28591
  };
28302
28592
  }
28303
28593
  function entryKind2(path6) {
28304
28594
  try {
28305
- const stats = statSync16(path6);
28595
+ const stats = statSync18(path6);
28306
28596
  if (stats.isFile())
28307
28597
  return "file";
28308
28598
  if (stats.isDirectory())
@@ -28314,7 +28604,7 @@ function entryKind2(path6) {
28314
28604
  }
28315
28605
  function visibleNames2(dir) {
28316
28606
  try {
28317
- return readdirSync12(dir).filter((name2) => !name2.startsWith(".")).sort((left, right) => left.localeCompare(right));
28607
+ return readdirSync13(dir).filter((name2) => !name2.startsWith(".")).sort((left, right) => left.localeCompare(right));
28318
28608
  } catch {
28319
28609
  return [];
28320
28610
  }
@@ -28323,8 +28613,8 @@ function readSelected(absolute, path6, entries) {
28323
28613
  let text2;
28324
28614
  let mtime;
28325
28615
  try {
28326
- text2 = readFileSync38(absolute, "utf8");
28327
- mtime = statSync16(absolute).mtime.toISOString();
28616
+ text2 = readFileSync39(absolute, "utf8");
28617
+ mtime = statSync18(absolute).mtime.toISOString();
28328
28618
  } catch {
28329
28619
  return null;
28330
28620
  }
@@ -28339,14 +28629,14 @@ function selectsLearned(text2, scope) {
28339
28629
  return origin === AUTO_EXTRACTED_ORIGIN;
28340
28630
  }
28341
28631
  function selectLearned(scope) {
28342
- const dir = join45(scope.dir, LEARNED_DIRECTORY);
28632
+ const dir = join46(scope.dir, LEARNED_DIRECTORY);
28343
28633
  if (entryKind2(dir) !== "directory")
28344
28634
  return [];
28345
28635
  const selected = [];
28346
28636
  for (const name2 of visibleNames2(dir)) {
28347
28637
  if (!name2.endsWith(MARKDOWN_EXTENSION) || name2 === MARKDOWN_EXTENSION)
28348
28638
  continue;
28349
- const absolute = join45(dir, name2);
28639
+ const absolute = join46(dir, name2);
28350
28640
  if (entryKind2(absolute) !== "file")
28351
28641
  continue;
28352
28642
  const file = readSelected(absolute, `${LEARNED_DIRECTORY}/${name2}`, undefined);
@@ -28360,10 +28650,10 @@ function selectSkillFiles(scope) {
28360
28650
  for (const name2 of visibleNames2(scope.dir)) {
28361
28651
  if (name2 === LEARNED_DIRECTORY)
28362
28652
  continue;
28363
- const skillDir = join45(scope.dir, name2);
28653
+ const skillDir = join46(scope.dir, name2);
28364
28654
  if (entryKind2(skillDir) !== "directory")
28365
28655
  continue;
28366
- const absolute = join45(skillDir, SKILL_FILE);
28656
+ const absolute = join46(skillDir, SKILL_FILE);
28367
28657
  if (entryKind2(absolute) !== "file")
28368
28658
  continue;
28369
28659
  const file = readSelected(absolute, `${name2}/${SKILL_FILE}`, visibleNames2(skillDir));
@@ -28411,7 +28701,7 @@ Usage: ${BACKFILL_USAGE}`);
28411
28701
  throw new CommandExit(1, `\u274C Expected one directory, and read "${extra}" as a second
28412
28702
  Usage: ${BACKFILL_USAGE}`);
28413
28703
  }
28414
- return resolve20(cwd(), dir);
28704
+ return resolve22(cwd(), dir);
28415
28705
  }
28416
28706
  function readConsumerRoot(value, cwd) {
28417
28707
  if (value === undefined || value === false)
@@ -28420,11 +28710,11 @@ function readConsumerRoot(value, cwd) {
28420
28710
  throw new CommandExit(1, `\u274C --project needs a path, and the line gave it none
28421
28711
  Usage: ${BACKFILL_USAGE}`);
28422
28712
  }
28423
- return resolve20(cwd(), value);
28713
+ return resolve22(cwd(), value);
28424
28714
  }
28425
28715
  function isDirectory3(path6) {
28426
28716
  try {
28427
- return statSync17(path6).isDirectory();
28717
+ return statSync19(path6).isDirectory();
28428
28718
  } catch {
28429
28719
  return false;
28430
28720
  }
@@ -28548,7 +28838,7 @@ function reviewedProposals(dir) {
28548
28838
  return read2.flatMap((entry) => entry.result.file === null ? [] : [entry.result.file]);
28549
28839
  }
28550
28840
  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("/"))));
28841
+ return files.flatMap((file) => file.status !== REVIEWED_FILE ? [] : file.rows.filter((row2) => row2.status === ANSWERED_ROW).map((row2) => join47(root, ...row2.path.split("/"))));
28552
28842
  }
28553
28843
  function runApply(context, scope, backfillDir, projectRoot3) {
28554
28844
  const options = checkOptions(context, projectRoot3);
@@ -28594,7 +28884,7 @@ async function runBackfill(context, seams) {
28594
28884
  const dir = readBackfillDirectory(context.args, seams.cwd);
28595
28885
  const projectRoot3 = readConsumerRoot(context.flags["project"], seams.cwd);
28596
28886
  const scope = backfillScopeOf(dir, projectOf8(context).home);
28597
- const backfillDir = join46(scope.base, BACKFILL_PATH);
28887
+ const backfillDir = join47(scope.base, BACKFILL_PATH);
28598
28888
  if (mode === "propose") {
28599
28889
  await runPropose(context, scope, backfillDir, seams);
28600
28890
  return;
@@ -28707,13 +28997,13 @@ function createSkillCheckCommand(seams = DEFAULT_CHECK_SEAMS) {
28707
28997
  var check_default2 = createSkillCheckCommand();
28708
28998
 
28709
28999
  // 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";
29000
+ import { existsSync as existsSync36, mkdirSync as mkdirSync17, readFileSync as readFileSync41, statSync as statSync21, writeFileSync as writeFileSync19 } from "fs";
29001
+ import { dirname as dirname18, resolve as resolve23 } from "path";
28712
29002
 
28713
29003
  // 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";
29004
+ 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
29005
  import { tmpdir } from "os";
28716
- import { dirname as dirname17, join as join47 } from "path";
29006
+ import { dirname as dirname17, join as join48 } from "path";
28717
29007
  var DEMOTION_ACTION_KINDS = [
28718
29008
  "demoted",
28719
29009
  "kept",
@@ -28734,18 +29024,18 @@ function learnedSkillName(path6) {
28734
29024
  return base.slice(0, -MARKDOWN_EXTENSION.length);
28735
29025
  }
28736
29026
  function sourcePath(scope, path6) {
28737
- return join47(scope.dir, ...path6.split("/"));
29027
+ return join48(scope.dir, ...path6.split("/"));
28738
29028
  }
28739
29029
  function demotedPath(scope, path6) {
28740
- return join47(scope.demotedDir, ...path6.split("/"));
29030
+ return join48(scope.demotedDir, ...path6.split("/"));
28741
29031
  }
28742
29032
  function promotedPath(scope, path6) {
28743
- return join47(scope.dir, learnedSkillName(path6), SKILL_FILE);
29033
+ return join48(scope.dir, learnedSkillName(path6), SKILL_FILE);
28744
29034
  }
28745
29035
  function takenInstinctIds(dir) {
28746
29036
  let names;
28747
29037
  try {
28748
- names = readdirSync13(dir);
29038
+ names = readdirSync14(dir);
28749
29039
  } catch {
28750
29040
  return [];
28751
29041
  }
@@ -28753,7 +29043,7 @@ function takenInstinctIds(dir) {
28753
29043
  }
28754
29044
  function readText6(path6) {
28755
29045
  try {
28756
- return statSync18(path6).isFile() ? readFileSync39(path6, "utf8") : null;
29046
+ return statSync20(path6).isFile() ? readFileSync40(path6, "utf8") : null;
28757
29047
  } catch {
28758
29048
  return null;
28759
29049
  }
@@ -28781,7 +29071,7 @@ function planKept(scope, row2, file) {
28781
29071
  return inert3(row2.path, "procedure", "kept", "procedure-shaped: left where it is, for the backfill");
28782
29072
  }
28783
29073
  const to = promotedPath(scope, row2.path);
28784
- if (existsSync34(to) || existsSync34(dirname17(to))) {
29074
+ if (existsSync35(to) || existsSync35(dirname17(to))) {
28785
29075
  return inert3(row2.path, "procedure", "refused", `kept as a skill, but ${to} is already there`);
28786
29076
  }
28787
29077
  return {
@@ -28795,7 +29085,7 @@ function planKept(scope, row2, file) {
28795
29085
  };
28796
29086
  }
28797
29087
  function checkCandidate(dir, id, text2, pathDirs) {
28798
- const path6 = join47(dir, `${id}${MARKDOWN_EXTENSION}`);
29088
+ const path6 = join48(dir, `${id}${MARKDOWN_EXTENSION}`);
28799
29089
  writeFileSync18(path6, text2, "utf8");
28800
29090
  const report3 = checkFile(path6, "instinct", { projectRoot: null, pathDirs });
28801
29091
  return failureLines2(report3.issues);
@@ -28816,11 +29106,11 @@ function planDemoted(scope, row2, file, context) {
28816
29106
  if (failures.length > 0) {
28817
29107
  return inert3(row2.path, "observation", "refused", `the record ${id} fails the checker \u2014 ${failures.join("; ")}`);
28818
29108
  }
28819
- const destination = join47(scope.instinctsDir, `${id}${MARKDOWN_EXTENSION}`);
29109
+ const destination = join48(scope.instinctsDir, `${id}${MARKDOWN_EXTENSION}`);
28820
29110
  const kept = demotedPath(scope, row2.path);
28821
- if (existsSync34(destination))
29111
+ if (existsSync35(destination))
28822
29112
  return inert3(row2.path, "observation", "refused", `${destination} is already there`);
28823
- if (existsSync34(kept))
29113
+ if (existsSync35(kept))
28824
29114
  return inert3(row2.path, "observation", "refused", `${kept} is already there`);
28825
29115
  context.taken.push(id);
28826
29116
  return {
@@ -28852,7 +29142,7 @@ function planRow(scope, row2, context) {
28852
29142
  entries: undefined,
28853
29143
  absolute,
28854
29144
  hash,
28855
- mtime: statSync18(absolute).mtime.toISOString()
29145
+ mtime: statSync20(absolute).mtime.toISOString()
28856
29146
  };
28857
29147
  return verdict === "procedure" ? planKept(scope, row2, file) : planDemoted(scope, row2, file, context);
28858
29148
  }
@@ -28863,7 +29153,7 @@ function countActions(actions) {
28863
29153
  return counts;
28864
29154
  }
28865
29155
  function planDemotion(report3, scope, seams = DEFAULT_APPLY_SEAMS) {
28866
- const temp = mkdtempSync(join47(tmpdir(), "rafa-demote-"));
29156
+ const temp = mkdtempSync(join48(tmpdir(), "rafa-demote-"));
28867
29157
  const taken = [...takenInstinctIds(scope.instinctsDir)];
28868
29158
  try {
28869
29159
  const actions = report3.rows.map((row2) => planRow(scope, row2, { temp, taken, seams }));
@@ -28873,18 +29163,18 @@ function planDemotion(report3, scope, seams = DEFAULT_APPLY_SEAMS) {
28873
29163
  }
28874
29164
  }
28875
29165
  function moveFile(move) {
28876
- mkdirSync15(dirname17(move.to), { recursive: true });
29166
+ mkdirSync16(dirname17(move.to), { recursive: true });
28877
29167
  try {
28878
29168
  renameSync4(move.from, move.to);
28879
29169
  } catch {
28880
29170
  copyFileSync4(move.from, move.to);
28881
- unlinkSync(move.from);
29171
+ unlinkSync2(move.from);
28882
29172
  }
28883
29173
  }
28884
29174
  function applyDemotion(plan2) {
28885
29175
  for (const action of plan2.actions) {
28886
29176
  if (action.write !== null) {
28887
- mkdirSync15(dirname17(action.write.path), { recursive: true });
29177
+ mkdirSync16(dirname17(action.write.path), { recursive: true });
28888
29178
  writeFileSync18(action.write.path, action.write.text, "utf8");
28889
29179
  }
28890
29180
  if (action.move !== null)
@@ -28950,11 +29240,11 @@ Usage: ${DEMOTE_USAGE}`);
28950
29240
  throw new CommandExit(1, `\u274C Expected one directory, and read "${extra}" as a second
28951
29241
  Usage: ${DEMOTE_USAGE}`);
28952
29242
  }
28953
- return resolve21(cwd(), dir);
29243
+ return resolve23(cwd(), dir);
28954
29244
  }
28955
29245
  function isDirectory4(path6) {
28956
29246
  try {
28957
- return statSync19(path6).isDirectory();
29247
+ return statSync21(path6).isDirectory();
28958
29248
  } catch {
28959
29249
  return false;
28960
29250
  }
@@ -28982,9 +29272,9 @@ function verdictLine(report3) {
28982
29272
  return `${String(report3.rows.length)} file(s): ${parts.join(", ")}`;
28983
29273
  }
28984
29274
  function previousReport(path6, context) {
28985
- if (!existsSync35(path6))
29275
+ if (!existsSync36(path6))
28986
29276
  return null;
28987
- const parsed = parseDemotionReport(readFileSync40(path6, "utf8"));
29277
+ const parsed = parseDemotionReport(readFileSync41(path6, "utf8"));
28988
29278
  if (parsed.report !== null)
28989
29279
  return parsed.report;
28990
29280
  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 +29283,7 @@ function previousReport(path6, context) {
28993
29283
  function runWrite(context, scope) {
28994
29284
  const files = selectSources(scope);
28995
29285
  const report3 = buildDemotionReport(files, previousReport(scope.reportPath, context));
28996
- mkdirSync16(dirname18(scope.reportPath), { recursive: true });
29286
+ mkdirSync17(dirname18(scope.reportPath), { recursive: true });
28997
29287
  writeFileSync19(scope.reportPath, writeDemotionReport(report3), "utf8");
28998
29288
  const result = {
28999
29289
  applied: false,
@@ -29017,10 +29307,10 @@ function runWrite(context, scope) {
29017
29307
  context.output.info(line);
29018
29308
  }
29019
29309
  function reviewedReport(scope) {
29020
- if (!existsSync35(scope.reportPath)) {
29310
+ if (!existsSync36(scope.reportPath)) {
29021
29311
  throw new CommandExit(1, `\u274C No report at ${scope.reportPath}; run "rafa skill demote ${scope.dir}" first, then review it`);
29022
29312
  }
29023
- const parsed = parseDemotionReport(readFileSync40(scope.reportPath, "utf8"));
29313
+ const parsed = parseDemotionReport(readFileSync41(scope.reportPath, "utf8"));
29024
29314
  if (parsed.report === null) {
29025
29315
  const lines = parsed.issues.map((issue4) => ` line ${String(issue4.line)} ${issue4.code}: ${issue4.message}`);
29026
29316
  throw new CommandExit(1, [`\u274C ${scope.reportPath} does not parse:`, ...lines].join(`
@@ -29125,7 +29415,7 @@ function createSkillDemoteCommand(seams = DEFAULT_DEMOTE_SEAMS) {
29125
29415
  var demote_default = createSkillDemoteCommand();
29126
29416
 
29127
29417
  // src/commands/skill/list.ts
29128
- import { readFileSync as readFileSync41 } from "fs";
29418
+ import { readFileSync as readFileSync42 } from "fs";
29129
29419
  var DEFAULT_SKILL_LIST_SEAMS = Object.freeze({
29130
29420
  entry: () => Bun.main
29131
29421
  });
@@ -29145,7 +29435,7 @@ Usage: ${USAGE28}`);
29145
29435
  function skillStack(path6) {
29146
29436
  let text2;
29147
29437
  try {
29148
- text2 = readFileSync41(path6, "utf8");
29438
+ text2 = readFileSync42(path6, "utf8");
29149
29439
  } catch {
29150
29440
  return [];
29151
29441
  }