arcane-cli 1.10.0 → 1.10.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.
- package/dist/index.js +94 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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: "
|
|
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
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
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
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
5352
|
-
|
|
5403
|
+
readFile8(join10(targetDir, file), "utf-8"),
|
|
5404
|
+
readFile8(srcPath, "utf-8")
|
|
5353
5405
|
]);
|
|
5354
5406
|
const result = merge3(oldVendorContent, currentContent, newContent);
|
|
5355
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
7192
|
+
import { readFile as readFile14 } from "fs/promises";
|
|
7141
7193
|
|
|
7142
7194
|
// src/modules/ward.ts
|
|
7143
|
-
import { readdir as readdir10, readFile as
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
8210
|
+
await writeFile12(join18(options.rootDir, relPath), expected, "utf8");
|
|
8159
8211
|
repaired.push(relPath);
|
|
8160
8212
|
}
|
|
8161
8213
|
}
|