arcane-cli 1.10.0 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: Spell — Sync Pull Request
3
- description: Safely sync an open PR's branch with its target when it has fallen behind — recoverable pre-rebase ref, mechanical-vs-ambiguous conflict handling, force-with-lease push, provider-verified landing. Use when a PR needs rebasing onto a moved target, or was routed here from spell-create-pull-request/spell-ship's own conflict-stop points.
3
+ description: Safely sync an open PR's branch with its target when it has fallen behind — recoverable pre-rebase ref, mechanical / regenerable / ambiguous conflict handling, force-with-lease push, provider-verified landing. Use when a PR needs rebasing onto a moved target, or was routed here from spell-create-pull-request/spell-ship's own conflict-stop points.
4
4
  claude_description: Use PROACTIVELY whenever an open PR has fallen behind its target branch and needs a safe rebase/sync, or when spell-create-pull-request/spell-ship stop on a conflict they route here.
5
5
  argument-hint: '[PR number or branch name]'
6
6
  agent: agent
7
- last_updated: 2026-08-31
7
+ last_updated: 2026-10-01
8
8
  ---
9
9
 
10
10
  ## Executive Summary
@@ -13,7 +13,9 @@ last_updated: 2026-08-31
13
13
  - It is the recovery path `spell-create-pull-request` and `spell-ship` route to when they detect a
14
14
  conflict they deliberately don't try to resolve themselves.
15
15
  - It draws a hard line between conflicts safe to resolve mechanically (identical changes on both sides)
16
- and conflicts that need a human — it never guesses on the ambiguous side of that line.
16
+ and conflicts that need a human — it never guesses on the ambiguous side of that line. A third class,
17
+ a script-regenerable artifact, is neither merged nor handed off: it is regenerated against the rebased
18
+ tree and verified by its own check.
17
19
  - Every history-rewriting step is preceded by a recoverable ref, and every push uses
18
20
  `--force-with-lease`, never bare `--force`.
19
21
 
@@ -72,7 +74,7 @@ Resolve the repository's actual merge-strategy ladder from `git-conventions.md`
72
74
  - **Never** produce a squash or semi-linear result as part of this sync — those are never sanctioned,
73
75
  regardless of which of the two above applies.
74
76
 
75
- ## Step 3 — Classify any conflict: mechanical vs. ambiguous
77
+ ## Step 3 — Classify any conflict: mechanical, regenerable, or ambiguous
76
78
 
77
79
  If Step 2 completes with no conflicts, skip straight to Step 4 — **this is the common case and it must
78
80
  not be treated as a special case of conflict handling.**
@@ -84,6 +86,25 @@ then classify **each conflicted hunk independently** — a single file can conta
84
86
  same import added the same way), or one side's change is a strict superset of the other's with no
85
87
  semantic divergence. Resolve by keeping the superset/identical content, verify no line from either
86
88
  side's *unique* content was dropped, stage the file, and continue the rebase/merge.
89
+ - **Regenerable** — the file is a committed artifact that a script owns: a known command regenerates it
90
+ from other files in the tree and overwrites it unconditionally, ignoring any conflict markers already
91
+ in it. Neither side's content is the right answer, because both were computed from trees that no
92
+ longer exist; the correct content is a fresh regeneration against the post-rebase tree. **Do not
93
+ hand-merge the diff and do not pick a side.** Leave the conflicted file as it is, run its regeneration
94
+ command, verify with the file's own `--check` command, then stage the file and continue the
95
+ rebase/merge. Known artifacts and their commands:
96
+ - `docs/plans/*/show-report.{json,html}` — `npm run fix:report` in Arcane's own repository (`spell
97
+ report` in a consumer), verified by `npm run check:report`. On a program's own `completed:` day the
98
+ regeneration must go in a **trailer-free, report-only commit** that touches nothing else, because
99
+ the close-commit logic counts any other commit made that day (recorded in
100
+ `docs/plans/upstream-intake-2026-09/PLAN.md`, "What this program taught").
101
+ - Self-hosted parity copies and client shims under `.arcane/`, `.github/`, `.claude/` and `.agents/`
102
+ in Arcane's own repository — `npm run fix:self-host-parity`, verified by
103
+ `npm run check:self-host-parity`. A compiled asset with its own `fix:*`/`check:*` pair in
104
+ `package.json` follows the same rule.
105
+ - `package-lock.json` — `npm install` against the rebased `package.json`, verified by `npm ci`.
106
+ A file you cannot name a regeneration command for is not regenerable: classify its hunks as mechanical
107
+ or ambiguous like any other, and never promote a hand-edited file to this class to avoid a STOP.
87
108
  - **Ambiguous** — the same lines changed with different intent, or you cannot establish with confidence
88
109
  that one side's content is a strict superset of the other's. **STOP.** Do not guess, do not pick a
89
110
  side, do not attempt a "reasonable-looking" merge of the two. Abort the in-progress rebase/merge
@@ -177,6 +198,8 @@ report the discrepancy rather than declaring the sync done.
177
198
  ```
178
199
 
179
200
  - If Step 3 resolved any mechanical conflicts, list exactly which files and what was kept from each side.
201
+ - If Step 3 regenerated any artifact, name the file, the regeneration command that was run and the
202
+ `--check` command that verified the result.
180
203
  - If Step 3 aborted on an ambiguous conflict, this report never runs — Step 3's own STOP report is final.
181
204
  - Never delete the Step 1 recoverable ref as part of this report — that is the human's call.
182
205
 
@@ -185,6 +208,9 @@ report the discrepancy rather than declaring the sync done.
185
208
  - Never push with bare `--force` — only `--force-with-lease`, and never retry a rejected lease blindly.
186
209
  - Never guess on an ambiguous conflict — abort and hand off, every time, with no exception for
187
210
  "obviously trivial-looking" content on either side that this spell cannot independently verify.
211
+ - Never hand-merge a script-regenerable artifact — regenerate it against the rebased tree and verify it
212
+ with its own check; and never classify a file as regenerable without naming the command that
213
+ regenerates it.
188
214
  - Never skip the recoverable ref (Step 1), even for a sync expected to be clean — the ref costs nothing
189
215
  and the alternative is an unrecoverable mistake on the case that turns out not to be clean.
190
216
  - Never report a sync as complete on a push success alone — provider verification (Step 5) is mandatory.
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: Spell — Sync Pull Request
3
- description: Safely sync an open PR's branch with its target when it has fallen behind — recoverable pre-rebase ref, mechanical-vs-ambiguous conflict handling, force-with-lease push, provider-verified landing. Use when a PR needs rebasing onto a moved target, or was routed here from spell-create-pull-request/spell-ship's own conflict-stop points.
3
+ description: Safely sync an open PR's branch with its target when it has fallen behind — recoverable pre-rebase ref, mechanical / regenerable / ambiguous conflict handling, force-with-lease push, provider-verified landing. Use when a PR needs rebasing onto a moved target, or was routed here from spell-create-pull-request/spell-ship's own conflict-stop points.
4
4
  claude_description: Use PROACTIVELY whenever an open PR has fallen behind its target branch and needs a safe rebase/sync, or when spell-create-pull-request/spell-ship stop on a conflict they route here.
5
5
  argument-hint: '[PR number or branch name]'
6
6
  agent: agent
7
- last_updated: 2026-08-31
7
+ last_updated: 2026-10-01
8
8
  ---
9
9
 
10
10
  This prompt is the Arcane `spell-sync-pull-request` spell. Read [`.arcane/spells/spell-sync-pull-request.md`](../../.arcane/spells/spell-sync-pull-request.md) and follow it as the complete workflow.
package/dist/index.js CHANGED
@@ -4417,14 +4417,14 @@ async function runInitUser(options, storeRoot, assetsDir, packageVersion) {
4417
4417
  }
4418
4418
 
4419
4419
  // src/modules/component-install.ts
4420
- import { stat } from "fs/promises";
4420
+ import { readFile as readFile7, stat, writeFile as writeFile9 } from "fs/promises";
4421
4421
  import { join as join8 } from "path";
4422
4422
  async function planComponentInstall(component, targetDir, assetsDir, opts = {}) {
4423
4423
  const files = [];
4424
4424
  const stateOf = async (file, src) => {
4425
4425
  const dest = join8(targetDir, file);
4426
4426
  if (!await fileExists(dest)) return { file, src, state: "missing" };
4427
- if ((await stat(dest)).isDirectory()) return { file, src, state: "differs" };
4427
+ if ((await stat(dest)).isDirectory()) return { file, src, state: "directory" };
4428
4428
  const same = await hashFile(dest) === await hashFile(src);
4429
4429
  return { file, src, state: same ? "identical" : "differs" };
4430
4430
  };
@@ -4437,37 +4437,76 @@ async function planComponentInstall(component, targetDir, assetsDir, opts = {})
4437
4437
  files.push(await stateOf(file, join8(assetsDir, file)));
4438
4438
  }
4439
4439
  }
4440
- const present = files.filter((f) => f.state !== "missing");
4441
- const missing = files.filter((f) => f.state === "missing");
4442
- if (opts.force) return { component, files, toCopy: files, kept: [], conflicts: [] };
4443
- return component.skipExisting ? { component, files, toCopy: missing, kept: present, conflicts: [] } : { component, files, toCopy: missing, kept: [], conflicts: present };
4440
+ const of = (...states) => files.filter((f) => states.includes(f.state));
4441
+ if (opts.force) {
4442
+ return { component, files, toCopy: of("missing", "identical", "differs"), kept: [], conflicts: of("directory") };
4443
+ }
4444
+ if (component.skipExisting) {
4445
+ return { component, files, toCopy: of("missing"), kept: of("identical", "differs", "directory"), conflicts: [] };
4446
+ }
4447
+ return { component, files, toCopy: of("missing", "identical"), kept: [], conflicts: of("differs", "directory") };
4444
4448
  }
4445
4449
  async function executeInstallPlan(plan, targetDir) {
4446
4450
  const files = [];
4447
4451
  const fileHashes = {};
4448
- for (const { file, src } of plan.toCopy) {
4449
- fileHashes[file] = await copyFile(src, targetDir, file, { force: true });
4450
- files.push(file);
4452
+ const written = [];
4453
+ try {
4454
+ for (const { file, src, state } of plan.toCopy) {
4455
+ const previous = state === "missing" ? null : await readFile7(join8(targetDir, file));
4456
+ fileHashes[file] = await copyFile(src, targetDir, file, { force: true });
4457
+ written.push({ file, previous });
4458
+ files.push(file);
4459
+ }
4460
+ } catch (err) {
4461
+ await rollback(written, targetDir);
4462
+ throw err;
4451
4463
  }
4452
4464
  return { files, fileHashes };
4453
4465
  }
4466
+ async function rollback(written, targetDir) {
4467
+ for (const { file, previous } of [...written].reverse()) {
4468
+ try {
4469
+ if (previous === null) {
4470
+ await removeWithin(targetDir, file);
4471
+ await removeEmptyAncestors(targetDir, file);
4472
+ } else {
4473
+ await writeFile9(join8(targetDir, file), previous);
4474
+ }
4475
+ } catch {
4476
+ }
4477
+ }
4478
+ }
4454
4479
 
4455
4480
  // src/commands/add.ts
4456
4481
  function describeExisting(f) {
4482
+ if (f.state === "directory") return "is a directory";
4457
4483
  return f.state === "identical" ? "identical to the packaged file" : "differs from the packaged file";
4458
4484
  }
4485
+ function directoryConflict(plan) {
4486
+ return plan.conflicts.find((f) => f.state === "directory");
4487
+ }
4459
4488
  function printDryRun2(name, plan, options) {
4460
4489
  for (const f of plan.files) {
4461
4490
  if (f.state === "missing") {
4462
4491
  console.log(` [dry-run] Would copy: ${f.file}`);
4492
+ } else if (f.state === "directory" && !(plan.component.skipExisting && !options.force)) {
4493
+ console.log(` [dry-run] Would refuse: ${f.file} (exists, is a directory) \u2014 remove it first`);
4463
4494
  } else if (options.force) {
4464
4495
  console.log(` [dry-run] Would overwrite: ${f.file} (exists, ${describeExisting(f)})`);
4465
4496
  } else if (plan.component.skipExisting) {
4466
4497
  console.log(` [dry-run] Would keep: ${f.file} (exists, yours, ${describeExisting(f)})`);
4498
+ } else if (f.state === "identical") {
4499
+ console.log(` [dry-run] Would adopt: ${f.file} (exists, identical to the packaged file)`);
4467
4500
  } else {
4468
4501
  console.log(` [dry-run] Would refuse: ${f.file} (exists, ${describeExisting(f)}) \u2014 needs --force`);
4469
4502
  }
4470
4503
  }
4504
+ const dir = directoryConflict(plan);
4505
+ if (dir) {
4506
+ console.log(`
4507
+ [dry-run] Would refuse component "${name}": a directory is at "${dir.file}", which --force does not replace. Remove it first.`);
4508
+ return;
4509
+ }
4471
4510
  if (plan.conflicts.length > 0) {
4472
4511
  console.log(
4473
4512
  `
@@ -4501,6 +4540,13 @@ async function addOne(name, options, targetDir, assetsDir, packageVersion) {
4501
4540
  printDryRun2(name, plan, options);
4502
4541
  return plan.conflicts.length > 0 ? "failed" : "added";
4503
4542
  }
4543
+ const dir = directoryConflict(plan);
4544
+ if (dir) {
4545
+ console.error(
4546
+ `Cannot add "${name}": "${dir.file}" is a directory, which --force does not replace. Nothing was written. Remove it first.`
4547
+ );
4548
+ return "failed";
4549
+ }
4504
4550
  if (plan.conflicts.length > 0) {
4505
4551
  const others = plan.conflicts.length - 1;
4506
4552
  console.error(
@@ -4561,7 +4607,7 @@ async function runAdd(names, options, targetDir, assetsDir, packageVersion) {
4561
4607
 
4562
4608
  // src/commands/update.ts
4563
4609
  import { dirname as dirname5, join as join10 } from "path";
4564
- import { readFile as readFile7, writeFile as writeFile9 } from "fs/promises";
4610
+ import { readFile as readFile8, writeFile as writeFile10 } from "fs/promises";
4565
4611
 
4566
4612
  // src/modules/merge3.ts
4567
4613
  var CONFLICT_START = "<<<<<<< yours (edited)";
@@ -4819,7 +4865,7 @@ async function planUpdateInstalls(args) {
4819
4865
  if (component.files.length === 0) continue;
4820
4866
  const plan = await planComponentInstall(component, args.targetDir, args.assetsDir, {});
4821
4867
  if (plan.conflicts.length > 0) {
4822
- leftAlone.push({ name, kind: "prerequisite", reason: `${plan.conflicts[0].file} already exists${plan.conflicts.length > 1 ? ` (and ${plan.conflicts.length - 1} more)` : ""}, and update does not overwrite` });
4868
+ leftAlone.push({ name, kind: "prerequisite", reason: conflictReason(plan) });
4823
4869
  continue;
4824
4870
  }
4825
4871
  items.push({ plan, kind: "prerequisite", requiredBy });
@@ -4829,13 +4875,19 @@ async function planUpdateInstalls(args) {
4829
4875
  if (component.initOnly || component.files.length === 0) continue;
4830
4876
  const plan = await planComponentInstall(component, args.targetDir, args.assetsDir, {});
4831
4877
  if (plan.conflicts.length > 0) {
4832
- leftAlone.push({ name: candidate.name, kind: "new", reason: `${plan.conflicts[0].file} already exists, and update does not overwrite` });
4878
+ leftAlone.push({ name: candidate.name, kind: "new", reason: conflictReason(plan) });
4833
4879
  continue;
4834
4880
  }
4835
4881
  items.push({ plan, kind: "new", requiredBy: [] });
4836
4882
  }
4837
4883
  return { items, leftAlone };
4838
4884
  }
4885
+ function conflictReason(plan) {
4886
+ const first = plan.conflicts[0];
4887
+ if (first.state === "directory") return `${first.file} is a directory, which update does not replace`;
4888
+ const more = plan.conflicts.length > 1 ? ` (and ${plan.conflicts.length - 1} more)` : "";
4889
+ return `${first.file} already exists${more}, and update does not overwrite`;
4890
+ }
4839
4891
  function label(item) {
4840
4892
  return item.kind === "prerequisite" ? `prerequisite of ${item.requiredBy.join(", ")}` : "newly available";
4841
4893
  }
@@ -5348,11 +5400,11 @@ async function runUpdate(options, targetDir, assetsDir, packageVersion) {
5348
5400
  handled = true;
5349
5401
  } else {
5350
5402
  const [currentContent, newContent] = await Promise.all([
5351
- readFile7(join10(targetDir, file), "utf-8"),
5352
- readFile7(srcPath, "utf-8")
5403
+ readFile8(join10(targetDir, file), "utf-8"),
5404
+ readFile8(srcPath, "utf-8")
5353
5405
  ]);
5354
5406
  const result = merge3(oldVendorContent, currentContent, newContent);
5355
- await writeFile9(join10(targetDir, file), result.content, "utf-8");
5407
+ await writeFile10(join10(targetDir, file), result.content, "utf-8");
5356
5408
  fileHashes[file] = await hashFile(srcPath);
5357
5409
  if (result.hasConflict) {
5358
5410
  conflictedFiles.push(file);
@@ -5537,7 +5589,7 @@ ${verb} ${orphansToReport.length} orphaned file(s) (tracked before this update,
5537
5589
  import { dirname as dirname7 } from "path";
5538
5590
 
5539
5591
  // src/modules/version-check.ts
5540
- import { readFile as readFile8, writeFile as writeFile10, mkdir as mkdir6 } from "fs/promises";
5592
+ import { readFile as readFile9, writeFile as writeFile11, mkdir as mkdir6 } from "fs/promises";
5541
5593
  import { dirname as dirname6, join as join11 } from "path";
5542
5594
  import { homedir as homedir3 } from "os";
5543
5595
  import { createRequire } from "module";
@@ -5556,7 +5608,7 @@ var DEFAULT_CACHE_PATH = join11(homedir3(), ".arcane", "version-cache.json");
5556
5608
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
5557
5609
  async function readCache(cachePath) {
5558
5610
  try {
5559
- const content = await readFile8(cachePath, "utf-8");
5611
+ const content = await readFile9(cachePath, "utf-8");
5560
5612
  const parsed = JSON.parse(content);
5561
5613
  if (typeof parsed.latest !== "string" || typeof parsed.checkedAt !== "string") {
5562
5614
  return null;
@@ -5569,7 +5621,7 @@ async function readCache(cachePath) {
5569
5621
  async function writeCache(cachePath, latest) {
5570
5622
  await mkdir6(dirname6(cachePath), { recursive: true });
5571
5623
  const entry = { latest, checkedAt: (/* @__PURE__ */ new Date()).toISOString() };
5572
- await writeFile10(cachePath, JSON.stringify(entry, null, 2), "utf-8");
5624
+ await writeFile11(cachePath, JSON.stringify(entry, null, 2), "utf-8");
5573
5625
  }
5574
5626
  async function getLatestVersion(feedUrl) {
5575
5627
  const normalizedBase = feedUrl.endsWith("/") ? feedUrl : feedUrl + "/";
@@ -5940,7 +5992,7 @@ async function uninstallUserTier(options, storeRoot, manifest) {
5940
5992
  }
5941
5993
 
5942
5994
  // src/commands/doctor.ts
5943
- import { access as access4, readdir as readdir9, readFile as readFile11, mkdir as mkdir7, copyFile as fsCopyFile } from "fs/promises";
5995
+ import { access as access4, readdir as readdir9, readFile as readFile12, mkdir as mkdir7, copyFile as fsCopyFile } from "fs/promises";
5944
5996
  import { join as join15, dirname as dirname9 } from "path";
5945
5997
 
5946
5998
  // src/config/incidents.ts
@@ -6009,7 +6061,7 @@ function evaluateIncidentGate(records) {
6009
6061
  }
6010
6062
 
6011
6063
  // src/modules/denylist-scan.ts
6012
- import { readFile as readFile9, readdir as readdir7 } from "fs/promises";
6064
+ import { readFile as readFile10, readdir as readdir7 } from "fs/promises";
6013
6065
  import { join as join13, relative } from "path";
6014
6066
  function escapeRegExp(value) {
6015
6067
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -6027,7 +6079,7 @@ async function scanFile(absolutePath, displayPath, rules) {
6027
6079
  const findings = [];
6028
6080
  let content;
6029
6081
  try {
6030
- content = await readFile9(absolutePath, "utf8");
6082
+ content = await readFile10(absolutePath, "utf8");
6031
6083
  } catch {
6032
6084
  return findings;
6033
6085
  }
@@ -6321,7 +6373,7 @@ function parseAdoRemote(url) {
6321
6373
  }
6322
6374
 
6323
6375
  // src/modules/placeholders.ts
6324
- import { readdir as readdir8, readFile as readFile10 } from "fs/promises";
6376
+ import { readdir as readdir8, readFile as readFile11 } from "fs/promises";
6325
6377
  import { join as join14 } from "path";
6326
6378
  var PLACEHOLDER_STANDARD_FILE = "spell-authoring-standards.md";
6327
6379
  var RUNTIME_PLACEHOLDERS_START = "<!-- runtime-placeholders:start -->";
@@ -6417,7 +6469,7 @@ function parseRuntimePlaceholders(standardContent) {
6417
6469
  async function scanGovernancePlaceholders(governanceDir) {
6418
6470
  let standard;
6419
6471
  try {
6420
- standard = await readFile10(join14(governanceDir, PLACEHOLDER_STANDARD_FILE), "utf8");
6472
+ standard = await readFile11(join14(governanceDir, PLACEHOLDER_STANDARD_FILE), "utf8");
6421
6473
  } catch (err) {
6422
6474
  if (err.code === "ENOENT") {
6423
6475
  return { status: "skipped", reason: `${PLACEHOLDER_STANDARD_FILE} is not installed` };
@@ -6436,7 +6488,7 @@ async function scanGovernancePlaceholders(governanceDir) {
6436
6488
  const templateDocs = [];
6437
6489
  const findings = [];
6438
6490
  for (const file of files) {
6439
- const content = await readFile10(join14(governanceDir, file), "utf8");
6491
+ const content = await readFile11(join14(governanceDir, file), "utf8");
6440
6492
  const status = parseFrontmatterStatus(content);
6441
6493
  if (status === "template") templateDocs.push(file);
6442
6494
  if (status !== "active") continue;
@@ -6502,7 +6554,7 @@ async function checkArcaneManifest(targetDir) {
6502
6554
  } catch {
6503
6555
  const selfHostedManifestPath = join15(targetDir, "src", "assets", ".arcane.json");
6504
6556
  try {
6505
- const raw = await readFile11(selfHostedManifestPath, "utf8");
6557
+ const raw = await readFile12(selfHostedManifestPath, "utf8");
6506
6558
  const manifest = JSON.parse(raw);
6507
6559
  if (isRecord3(manifest) && manifest["selfHosted"] === true && manifest["tracking_mode"] === "internal") {
6508
6560
  return {
@@ -6521,7 +6573,7 @@ async function checkArcaneManifest(targetDir) {
6521
6573
  };
6522
6574
  }
6523
6575
  try {
6524
- const raw = await readFile11(manifestPath2, "utf8");
6576
+ const raw = await readFile12(manifestPath2, "utf8");
6525
6577
  const manifest = JSON.parse(raw);
6526
6578
  if (!isRecord3(manifest) || typeof manifest["version"] !== "string" || !manifest["version"] || !Array.isArray(manifest["components"])) {
6527
6579
  return {
@@ -6845,7 +6897,7 @@ async function checkMcpConfig(targetDir) {
6845
6897
  const filePath = join15(targetDir, ".mcp.json");
6846
6898
  let raw;
6847
6899
  try {
6848
- raw = await readFile11(filePath, "utf8");
6900
+ raw = await readFile12(filePath, "utf8");
6849
6901
  } catch {
6850
6902
  return { name, passed: true, blocking: false, message: "no .mcp.json \u2014 nothing to check" };
6851
6903
  }
@@ -6917,7 +6969,7 @@ async function checkDelegations(targetDir) {
6917
6969
  const filePath = join15(targetDir, ".arcane", "delegations.json");
6918
6970
  let raw;
6919
6971
  try {
6920
- raw = await readFile11(filePath, "utf8");
6972
+ raw = await readFile12(filePath, "utf8");
6921
6973
  } catch {
6922
6974
  return { name, passed: true, blocking: false, message: "no delegations recorded" };
6923
6975
  }
@@ -7137,16 +7189,16 @@ async function runDoctor(targetDir, options = {}, assetsDir) {
7137
7189
  }
7138
7190
 
7139
7191
  // src/commands/ward.ts
7140
- import { readFile as readFile13 } from "fs/promises";
7192
+ import { readFile as readFile14 } from "fs/promises";
7141
7193
 
7142
7194
  // src/modules/ward.ts
7143
- import { readdir as readdir10, readFile as readFile12 } from "fs/promises";
7195
+ import { readdir as readdir10, readFile as readFile13 } from "fs/promises";
7144
7196
  import { join as join16, relative as relative2 } from "path";
7145
7197
  async function scanFileAllRules(absolutePath, displayPath, rules) {
7146
7198
  const findings = [];
7147
7199
  let content;
7148
7200
  try {
7149
- content = await readFile12(absolutePath, "utf8");
7201
+ content = await readFile13(absolutePath, "utf8");
7150
7202
  } catch {
7151
7203
  return findings;
7152
7204
  }
@@ -7241,7 +7293,7 @@ async function runWard(repoRoot, options = {}) {
7241
7293
  const findings2 = await scanFileAllRules(absolutePath, displayPath, allRules);
7242
7294
  if (findings2.length > 0) {
7243
7295
  try {
7244
- fileLines.set(displayPath, (await readFile12(absolutePath, "utf8")).split("\n"));
7296
+ fileLines.set(displayPath, (await readFile13(absolutePath, "utf8")).split("\n"));
7245
7297
  } catch {
7246
7298
  }
7247
7299
  }
@@ -7269,7 +7321,7 @@ function parseTermsFileContent(raw) {
7269
7321
  }
7270
7322
  async function readTermsFile(filePath) {
7271
7323
  try {
7272
- return parseTermsFileContent(await readFile13(filePath, "utf8"));
7324
+ return parseTermsFileContent(await readFile14(filePath, "utf8"));
7273
7325
  } catch (error) {
7274
7326
  console.warn(
7275
7327
  `\u26A0 arcane: could not read --terms-file "${filePath}": ${error.message}`
@@ -7484,11 +7536,11 @@ import { access as access5 } from "fs/promises";
7484
7536
  import { join as join19 } from "path";
7485
7537
 
7486
7538
  // src/modules/show-report/generate.ts
7487
- import { mkdir as mkdir8, readdir as readdir11, readFile as readFile15, writeFile as writeFile11 } from "fs/promises";
7539
+ import { mkdir as mkdir8, readdir as readdir11, readFile as readFile16, writeFile as writeFile12 } from "fs/promises";
7488
7540
  import { basename as basename3, dirname as dirname10, isAbsolute, join as join18, relative as relative3, resolve as resolve4 } from "path";
7489
7541
 
7490
7542
  // src/modules/show-report/model.ts
7491
- import { readFile as readFile14 } from "fs/promises";
7543
+ import { readFile as readFile15 } from "fs/promises";
7492
7544
  import { join as join17 } from "path";
7493
7545
 
7494
7546
  // src/modules/show-report/plan-parser.ts
@@ -7762,7 +7814,7 @@ async function getCast(cwd, fromRef, toRef, generatedOutputs = []) {
7762
7814
  // src/modules/show-report/model.ts
7763
7815
  async function readOptional(path4) {
7764
7816
  try {
7765
- return await readFile14(path4, "utf8");
7817
+ return await readFile15(path4, "utf8");
7766
7818
  } catch {
7767
7819
  return null;
7768
7820
  }
@@ -7864,7 +7916,7 @@ async function buildShowReportModel(options) {
7864
7916
  const ledgerAbsPath = join17(options.rootDir, ledgerRelPath);
7865
7917
  const decisionsAbsPath = join17(options.rootDir, "DECISIONS.md");
7866
7918
  const [planContent, queueContent, ledgerContent, decisionsContent] = await Promise.all([
7867
- readFile14(planAbsPath, "utf8"),
7919
+ readFile15(planAbsPath, "utf8"),
7868
7920
  readOptional(queueAbsPath),
7869
7921
  readOptional(ledgerAbsPath),
7870
7922
  readOptional(decisionsAbsPath)
@@ -8060,7 +8112,7 @@ function toPosix(path4) {
8060
8112
  async function programFromPlan(rootDir, slug, planRelPath) {
8061
8113
  let planContent;
8062
8114
  try {
8063
- planContent = await readFile15(join18(rootDir, planRelPath), "utf8");
8115
+ planContent = await readFile16(join18(rootDir, planRelPath), "utf8");
8064
8116
  } catch {
8065
8117
  return { skipped: { slug, reason: `no PLAN.md at ${planRelPath}` } };
8066
8118
  }
@@ -8105,14 +8157,14 @@ function normalizeLineEndings2(content) {
8105
8157
  }
8106
8158
  async function readOptionalFile(path4) {
8107
8159
  try {
8108
- return await readFile15(path4, "utf8");
8160
+ return await readFile16(path4, "utf8");
8109
8161
  } catch (error) {
8110
8162
  if (error.code === "ENOENT") return null;
8111
8163
  throw error;
8112
8164
  }
8113
8165
  }
8114
8166
  async function generateReport(rootDir, program2, templateHtml, theme = "auto") {
8115
- const planContent = await readFile15(join18(rootDir, program2.planRelPath), "utf8");
8167
+ const planContent = await readFile16(join18(rootDir, program2.planRelPath), "utf8");
8116
8168
  const frontmatter = parseFrontmatter(planContent);
8117
8169
  const model = await buildShowReportModel({
8118
8170
  rootDir,
@@ -8132,7 +8184,7 @@ async function generateReport(rootDir, program2, templateHtml, theme = "auto") {
8132
8184
  };
8133
8185
  }
8134
8186
  async function runReportGeneration(options) {
8135
- const templateHtml = await readFile15(options.templatePath, "utf8");
8187
+ const templateHtml = await readFile16(options.templatePath, "utf8");
8136
8188
  const theme = options.theme ?? "auto";
8137
8189
  const drifted = [];
8138
8190
  const repaired = [];
@@ -8155,7 +8207,7 @@ async function runReportGeneration(options) {
8155
8207
  drifted.push(`${relPath} does not match a regeneration from its sources.`);
8156
8208
  if (options.mode === "write") {
8157
8209
  await mkdir8(outAbs, { recursive: true });
8158
- await writeFile11(join18(options.rootDir, relPath), expected, "utf8");
8210
+ await writeFile12(join18(options.rootDir, relPath), expected, "utf8");
8159
8211
  repaired.push(relPath);
8160
8212
  }
8161
8213
  }