gutterpress 0.10.10 → 0.10.11

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.
@@ -24,6 +24,7 @@ import {
24
24
  gitScopeFor,
25
25
  hasPendingChanges,
26
26
  hasUncommittedChanges,
27
+ listWorkdirChanges,
27
28
  resolveGitAuthor,
28
29
  resolveLogger,
29
30
  snapshotStagingMarkerPath,
@@ -32,6 +33,7 @@ import {
32
33
  } from "./index-y01v2fe0.js";
33
34
  import {
34
35
  detectProjectSource,
36
+ repoSubPath,
35
37
  syncRemoteFor
36
38
  } from "./index-v5mp7a6q.js";
37
39
  import {
@@ -1469,7 +1471,7 @@ function attachDataAttrs(token, kind, name, attrs) {
1469
1471
  continue;
1470
1472
  if (k === "class" || k === "id" || k === "template" || k === "region")
1471
1473
  continue;
1472
- token.attrSet(`data-${k}`, v);
1474
+ token.attrSet(k.startsWith("data-") ? k : `data-${k}`, v);
1473
1475
  }
1474
1476
  }
1475
1477
  var DECLARED_NAME_RE = /^[a-z][a-z0-9-]*$/;
@@ -4839,7 +4841,7 @@ import git from "isomorphic-git";
4839
4841
  // package.json
4840
4842
  var package_default = {
4841
4843
  name: "gutterpress",
4842
- version: "0.10.10",
4844
+ version: "0.10.11",
4843
4845
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
4844
4846
  author: "itlackey",
4845
4847
  license: "MPL-2.0",
@@ -5112,64 +5114,32 @@ async function writeBuildFingerprint(input) {
5112
5114
  import { existsSync as existsSync10 } from "node:fs";
5113
5115
  import { dirname as dirname4, join as join4, resolve as resolve8 } from "node:path";
5114
5116
 
5115
- // src/checks/formatter.ts
5116
- function formatReport(report, format = "text") {
5117
- if (format === "json") {
5118
- formatJson(report);
5119
- } else {
5120
- formatText(report);
5121
- }
5122
- }
5123
- function formatText(report) {
5124
- for (const r of report.infos) {
5125
- const loc = targetPrefix(r.target) + formatLocation(r.file, r.line, r.column);
5126
- log.info(`${loc}${r.message}`);
5127
- if (r.detail)
5128
- log.info(` ${r.detail}`);
5129
- }
5130
- for (const r of report.warnings) {
5131
- const loc = targetPrefix(r.target) + formatLocation(r.file, r.line, r.column);
5132
- log.warn(`${loc}${r.message}`);
5133
- if (r.detail)
5134
- log.warn(` ${r.detail}`);
5135
- }
5136
- for (const r of report.errors) {
5137
- const loc = targetPrefix(r.target) + formatLocation(r.file, r.line, r.column);
5138
- log.error(`${loc}${r.message}`);
5139
- if (r.detail)
5140
- log.error(` ${r.detail}`);
5141
- }
5142
- const { summary } = report;
5143
- if (summary.errors > 0) {
5144
- log.error(`VALIDATION FAILED (${summary.errors} error${summary.errors > 1 ? "s" : ""})`);
5145
- } else if (summary.warnings > 0) {
5146
- log.warn("VALIDATION PASSED (with warnings)");
5147
- } else {
5148
- log.success("VALIDATION PASSED");
5117
+ // src/lib/markdownlint-fix.ts
5118
+ import { readFile as readFile10, writeFile as writeFile5 } from "node:fs/promises";
5119
+ import { applyFixes } from "markdownlint";
5120
+ import { lint as lint2 } from "markdownlint/sync";
5121
+
5122
+ // src/checks/source/config-file.ts
5123
+ import { existsSync as existsSync6 } from "node:fs";
5124
+ import { resolve as resolve5 } from "node:path";
5125
+ function findConfigFile(inputDir, names, explicit) {
5126
+ if (explicit) {
5127
+ const p = resolve5(inputDir, explicit);
5128
+ return existsSync6(p) ? p : null;
5149
5129
  }
5150
- }
5151
- function targetPrefix(target) {
5152
- return target ? `[${target}] ` : "";
5153
- }
5154
- function formatJson(report) {
5155
- console.log(JSON.stringify({
5156
- results: report.results,
5157
- summary: report.summary,
5158
- passed: report.passed
5159
- }, null, 2));
5160
- }
5161
- function formatLocation(file, line, column) {
5162
- if (!file)
5163
- return "";
5164
- let loc = `${file}`;
5165
- if (line != null) {
5166
- loc += `:${line}`;
5167
- if (column != null)
5168
- loc += `:${column}`;
5130
+ for (const name of names) {
5131
+ const p = resolve5(inputDir, name);
5132
+ if (existsSync6(p))
5133
+ return p;
5169
5134
  }
5170
- return `${loc}: `;
5135
+ return null;
5171
5136
  }
5172
5137
 
5138
+ // src/checks/source/markdownlint.ts
5139
+ import { readFile as readFile9 } from "node:fs/promises";
5140
+ import { lint } from "markdownlint/sync";
5141
+ import { parse as parseYaml2 } from "yaml";
5142
+
5173
5143
  // src/checks/registry.ts
5174
5144
  var checks = new Map;
5175
5145
  function registerCheck(check) {
@@ -5235,15 +5205,205 @@ function selectorToRegex(selector) {
5235
5205
  return new RegExp(`^${escaped}$`);
5236
5206
  }
5237
5207
 
5208
+ // src/checks/source/markdownlint.ts
5209
+ var CONFIG_NAMES = [
5210
+ ".markdownlint.yaml",
5211
+ ".markdownlint.yml",
5212
+ ".markdownlint.json",
5213
+ ".markdownlint.jsonc",
5214
+ ".markdownlint-cli2.yaml",
5215
+ ".markdownlint-cli2.jsonc"
5216
+ ];
5217
+ function stripJsonComments(s) {
5218
+ return s.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
5219
+ }
5220
+ async function loadConfig(configPath) {
5221
+ const raw = await readFile9(configPath, "utf8");
5222
+ let parsed;
5223
+ if (configPath.endsWith(".json")) {
5224
+ parsed = JSON.parse(raw);
5225
+ } else if (configPath.endsWith(".jsonc")) {
5226
+ parsed = JSON.parse(stripJsonComments(raw));
5227
+ } else {
5228
+ parsed = parseYaml2(raw);
5229
+ }
5230
+ if (parsed && typeof parsed === "object") {
5231
+ const obj = parsed;
5232
+ if (obj.config && typeof obj.config === "object") {
5233
+ return obj.config;
5234
+ }
5235
+ return obj;
5236
+ }
5237
+ return {};
5238
+ }
5239
+ var MARKDOWNLINT_CHECK_ID = "source.markdownlint";
5240
+ var check = {
5241
+ id: MARKDOWNLINT_CHECK_ID,
5242
+ name: "Markdownlint",
5243
+ description: "Runs markdownlint with project config to validate Markdown files",
5244
+ category: "source",
5245
+ phase: "pre-build",
5246
+ async run(ctx) {
5247
+ const sourceConfig = ctx.config.validate.source;
5248
+ if (sourceConfig.markdownlint === false)
5249
+ return [];
5250
+ const files = ctx.markdownFiles;
5251
+ if (!files || files.length === 0)
5252
+ return [];
5253
+ const configPath = typeof sourceConfig.markdownlint === "string" ? sourceConfig.markdownlint : null;
5254
+ const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES, configPath);
5255
+ if (!resolvedConfig && !configPath)
5256
+ return [];
5257
+ const config = resolvedConfig ? await loadConfig(resolvedConfig) : { default: true };
5258
+ const results = lint({ files, config });
5259
+ const out = [];
5260
+ for (const [file, violations] of Object.entries(results)) {
5261
+ if (!Array.isArray(violations))
5262
+ continue;
5263
+ for (const v of violations) {
5264
+ out.push({
5265
+ checkId: check.id,
5266
+ severity: "warning",
5267
+ message: `${v.ruleDescription} (${v.ruleNames.join("/")})`,
5268
+ file,
5269
+ line: v.lineNumber,
5270
+ column: v.errorRange?.[0],
5271
+ code: v.ruleNames[0]
5272
+ });
5273
+ }
5274
+ }
5275
+ return out;
5276
+ }
5277
+ };
5278
+ registerCheck(check);
5279
+
5280
+ // src/lib/markdownlint-fix.ts
5281
+ async function uncommittedAmong(inputDir, files) {
5282
+ const source = await detectProjectSource(inputDir);
5283
+ if (source.type !== "local-git-folder")
5284
+ return [];
5285
+ const repoRoot = source.repoRoot;
5286
+ let changed;
5287
+ try {
5288
+ const { adds } = await listWorkdirChanges(repoRoot);
5289
+ changed = new Set(adds);
5290
+ } catch {
5291
+ return [];
5292
+ }
5293
+ return files.filter((file) => changed.has(repoSubPath(repoRoot, file)));
5294
+ }
5295
+ async function applyMarkdownlintFixes(ctx) {
5296
+ const sourceConfig = ctx.config.validate.source;
5297
+ if (sourceConfig.markdownlint === false) {
5298
+ log.warn("--fix: source.markdownlint is disabled for this project — no files were fixed.");
5299
+ return [];
5300
+ }
5301
+ const files = ctx.markdownFiles;
5302
+ if (!files || files.length === 0) {
5303
+ log.warn("--fix: no markdown files to fix.");
5304
+ return [];
5305
+ }
5306
+ const configPath = typeof sourceConfig.markdownlint === "string" ? sourceConfig.markdownlint : null;
5307
+ const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES, configPath);
5308
+ if (!resolvedConfig && !configPath) {
5309
+ log.warn(`--fix: no markdownlint config found in ${ctx.inputDir} (looked for ${CONFIG_NAMES.join(", ")}) — no files were fixed.`);
5310
+ return [];
5311
+ }
5312
+ const config = resolvedConfig ? await loadConfig(resolvedConfig) : { default: true };
5313
+ const results = lint2({ files, config });
5314
+ const pending = [];
5315
+ for (const [file, violations] of Object.entries(results)) {
5316
+ if (!Array.isArray(violations) || violations.length === 0)
5317
+ continue;
5318
+ const before = await readFile10(file, "utf8");
5319
+ const after = applyFixes(before, violations);
5320
+ if (after !== before)
5321
+ pending.push({ file, content: after });
5322
+ }
5323
+ if (pending.length === 0) {
5324
+ log.warn("--fix: no mechanically fixable markdownlint violations found.");
5325
+ return [];
5326
+ }
5327
+ const dirty = await uncommittedAmong(ctx.inputDir, pending.map((p) => p.file));
5328
+ for (const { file, content } of pending) {
5329
+ await writeFile5(file, content, "utf8");
5330
+ }
5331
+ log.warn(`--fix: rewrote ${pending.length} file(s):`);
5332
+ for (const { file } of pending)
5333
+ log.warn(` ${file}`);
5334
+ if (dirty.length > 0) {
5335
+ log.warn(`--fix: ${dirty.length} of those already had uncommitted changes and were rewritten anyway: ${dirty.join(", ")}`);
5336
+ }
5337
+ return pending.map((p) => p.file);
5338
+ }
5339
+
5340
+ // src/checks/formatter.ts
5341
+ function formatReport(report, format = "text") {
5342
+ if (format === "json") {
5343
+ formatJson(report);
5344
+ } else {
5345
+ formatText(report);
5346
+ }
5347
+ }
5348
+ function formatText(report) {
5349
+ for (const r of report.infos) {
5350
+ const loc = targetPrefix(r.target) + formatLocation(r.file, r.line, r.column);
5351
+ log.info(`${loc}${r.message}`);
5352
+ if (r.detail)
5353
+ log.info(` ${r.detail}`);
5354
+ }
5355
+ for (const r of report.warnings) {
5356
+ const loc = targetPrefix(r.target) + formatLocation(r.file, r.line, r.column);
5357
+ log.warn(`${loc}${r.message}`);
5358
+ if (r.detail)
5359
+ log.warn(` ${r.detail}`);
5360
+ }
5361
+ for (const r of report.errors) {
5362
+ const loc = targetPrefix(r.target) + formatLocation(r.file, r.line, r.column);
5363
+ log.error(`${loc}${r.message}`);
5364
+ if (r.detail)
5365
+ log.error(` ${r.detail}`);
5366
+ }
5367
+ const { summary } = report;
5368
+ if (summary.errors > 0) {
5369
+ log.error(`VALIDATION FAILED (${summary.errors} error${summary.errors > 1 ? "s" : ""})`);
5370
+ } else if (summary.warnings > 0) {
5371
+ log.warn("VALIDATION PASSED (with warnings)");
5372
+ } else {
5373
+ log.success("VALIDATION PASSED");
5374
+ }
5375
+ }
5376
+ function targetPrefix(target) {
5377
+ return target ? `[${target}] ` : "";
5378
+ }
5379
+ function formatJson(report) {
5380
+ console.log(JSON.stringify({
5381
+ results: report.results,
5382
+ summary: report.summary,
5383
+ passed: report.passed
5384
+ }, null, 2));
5385
+ }
5386
+ function formatLocation(file, line, column) {
5387
+ if (!file)
5388
+ return "";
5389
+ let loc = `${file}`;
5390
+ if (line != null) {
5391
+ loc += `:${line}`;
5392
+ if (column != null)
5393
+ loc += `:${column}`;
5394
+ }
5395
+ return `${loc}: `;
5396
+ }
5397
+
5238
5398
  // src/checks/policy.ts
5239
5399
  var INSPECT_FAILED_CODE = "inspect-failed";
5240
- function isCheckEnabled(check, config) {
5241
- const entry = config.validate.checks[check.id];
5400
+ function isCheckEnabled(check2, config) {
5401
+ const entry = config.validate.checks[check2.id];
5242
5402
  if (entry === false)
5243
5403
  return false;
5244
5404
  if (typeof entry === "object" && entry.enabled === false)
5245
5405
  return false;
5246
- if (check.enabledWhen && !check.enabledWhen(config))
5406
+ if (check2.enabledWhen && !check2.enabledWhen(config))
5247
5407
  return false;
5248
5408
  return true;
5249
5409
  }
@@ -5280,7 +5440,7 @@ function inspectionFailed(checkId, message, extra = {}) {
5280
5440
  }
5281
5441
 
5282
5442
  // src/lib/pdf-inspect.ts
5283
- import { stat, readFile as readFile9 } from "node:fs/promises";
5443
+ import { stat, readFile as readFile11 } from "node:fs/promises";
5284
5444
  import { getDocumentProxy } from "unpdf";
5285
5445
  import * as pdfjs from "unpdf/pdfjs";
5286
5446
  function getOps(mod) {
@@ -5335,7 +5495,7 @@ async function loadPdf(path7) {
5335
5495
  }
5336
5496
  if (hit)
5337
5497
  destroyEntry(hit);
5338
- const docPromise = readFile9(path7).then((buf) => getDocumentProxy(new Uint8Array(buf)));
5498
+ const docPromise = readFile11(path7).then((buf) => getDocumentProxy(new Uint8Array(buf)));
5339
5499
  docCache.delete(path7);
5340
5500
  docCache.set(path7, { mtimeMs: st.mtimeMs, size: st.size, doc: docPromise });
5341
5501
  evictLru();
@@ -5533,12 +5693,12 @@ function getOpPass(doc) {
5533
5693
  return p;
5534
5694
  }
5535
5695
  function getImagePixelSize(page, name, timeoutMs = 2000) {
5536
- return new Promise((resolve5) => {
5696
+ return new Promise((resolve6) => {
5537
5697
  let done = false;
5538
5698
  const finish = (v) => {
5539
5699
  if (!done) {
5540
5700
  done = true;
5541
- resolve5(v);
5701
+ resolve6(v);
5542
5702
  }
5543
5703
  };
5544
5704
  const t = setTimeout(() => finish(null), timeoutMs);
@@ -5594,7 +5754,7 @@ async function isLoadable(doc) {
5594
5754
  }
5595
5755
 
5596
5756
  // src/checks/pdf/qpdf-structure.ts
5597
- var check = {
5757
+ var check2 = {
5598
5758
  id: "pdf.structure.qpdf",
5599
5759
  name: "PDF Structure",
5600
5760
  description: "Validates the PDF parses and every page is traversable",
@@ -5606,16 +5766,16 @@ var check = {
5606
5766
  const doc = await loadPdf(ctx.pdfPath);
5607
5767
  if (!doc || !await isLoadable(doc)) {
5608
5768
  return [
5609
- inspectionFailed(check.id, "PDF could not be fully parsed — possible structural issues.", { file: ctx.pdfPath })
5769
+ inspectionFailed(check2.id, "PDF could not be fully parsed — possible structural issues.", { file: ctx.pdfPath })
5610
5770
  ];
5611
5771
  }
5612
5772
  return [];
5613
5773
  }
5614
5774
  };
5615
- registerCheck(check);
5775
+ registerCheck(check2);
5616
5776
 
5617
5777
  // src/checks/pdf/page-size.ts
5618
- var check2 = {
5778
+ var check3 = {
5619
5779
  id: "pdf.print.page-size",
5620
5780
  name: "Page Size",
5621
5781
  description: "Validates PDF page dimensions match expected size from config",
@@ -5627,7 +5787,7 @@ var check2 = {
5627
5787
  const doc = await loadPdf(ctx.pdfPath);
5628
5788
  if (!doc) {
5629
5789
  return [
5630
- inspectionFailed(check2.id, "Could not parse PDF page size.", {
5790
+ inspectionFailed(check3.id, "Could not parse PDF page size.", {
5631
5791
  file: ctx.pdfPath
5632
5792
  })
5633
5793
  ];
@@ -5637,7 +5797,7 @@ var check2 = {
5637
5797
  const { width, height, tolerance } = ctx.config.page;
5638
5798
  if (Math.abs(size.w - width) >= tolerance || Math.abs(size.h - height) >= tolerance) {
5639
5799
  return [
5640
- finding(check2.id, {
5800
+ finding(check3.id, {
5641
5801
  severity: "error",
5642
5802
  message: `Page size mismatch: expected ~${width}x${height} pts, got ${Math.round(size.w)}x${Math.round(size.h)} pts.`,
5643
5803
  file: ctx.pdfPath
@@ -5647,7 +5807,7 @@ var check2 = {
5647
5807
  return [];
5648
5808
  }
5649
5809
  };
5650
- registerCheck(check2);
5810
+ registerCheck(check3);
5651
5811
 
5652
5812
  // src/checks/pdf/pdfx-structure.ts
5653
5813
  function isObject(value) {
@@ -5757,7 +5917,7 @@ function getPdfxMetadataIssues(objects, flavor) {
5757
5917
  }
5758
5918
 
5759
5919
  // src/checks/pdf/pdfx-markers.ts
5760
- var check3 = {
5920
+ var check4 = {
5761
5921
  id: "pdf.print.pdfx-markers",
5762
5922
  name: "PDF/X Markers",
5763
5923
  description: "Checks PDF/X OutputIntent structure via qpdf JSON",
@@ -5776,27 +5936,27 @@ var check3 = {
5776
5936
  const objects = parseQpdfObjectsJson(stdout);
5777
5937
  if (!objects) {
5778
5938
  return [
5779
- inspectionFailed(check3.id, "Unable to parse qpdf JSON output for PDF/X checks.", { file: ctx.pdfPath })
5939
+ inspectionFailed(check4.id, "Unable to parse qpdf JSON output for PDF/X checks.", { file: ctx.pdfPath })
5780
5940
  ];
5781
5941
  }
5782
- return getPdfxOutputIntentIssues(objects).map((message) => finding(check3.id, {
5942
+ return getPdfxOutputIntentIssues(objects).map((message) => finding(check4.id, {
5783
5943
  severity: "error",
5784
5944
  message,
5785
5945
  file: ctx.pdfPath
5786
5946
  }));
5787
5947
  } catch {
5788
5948
  return [
5789
- inspectionFailed(check3.id, "Failed to inspect PDF objects with qpdf for PDF/X markers.", { file: ctx.pdfPath })
5949
+ inspectionFailed(check4.id, "Failed to inspect PDF objects with qpdf for PDF/X markers.", { file: ctx.pdfPath })
5790
5950
  ];
5791
5951
  }
5792
5952
  }
5793
5953
  };
5794
- registerCheck(check3);
5954
+ registerCheck(check4);
5795
5955
 
5796
5956
  // src/lib/pdf-parse.ts
5797
- import { readFile as readFile10 } from "node:fs/promises";
5957
+ import { readFile as readFile12 } from "node:fs/promises";
5798
5958
  async function readPdfBytes(pdfPath) {
5799
- return readFile10(pdfPath, "latin1");
5959
+ return readFile12(pdfPath, "latin1");
5800
5960
  }
5801
5961
  function parseInkCov(out) {
5802
5962
  const lines = out.split(/\r?\n/).filter((l) => l.includes("CMYK"));
@@ -5844,7 +6004,7 @@ async function getPerPageInkCoverage(pdfPath) {
5844
6004
  }
5845
6005
 
5846
6006
  // src/checks/pdf/color-spaces.ts
5847
- var check4 = {
6007
+ var check5 = {
5848
6008
  id: "pdf.print.color-spaces",
5849
6009
  name: "Color Spaces",
5850
6010
  description: "Checks for forbidden color spaces (DeviceRGB, Lab, Separation, DeviceN)",
@@ -5857,7 +6017,7 @@ var check4 = {
5857
6017
  const results = [];
5858
6018
  if (/\/DeviceRGB/.test(bytes)) {
5859
6019
  results.push({
5860
- checkId: check4.id,
6020
+ checkId: check5.id,
5861
6021
  severity: "error",
5862
6022
  message: "DeviceRGB found (interior must be CMYK or grayscale only).",
5863
6023
  file: ctx.pdfPath
@@ -5865,7 +6025,7 @@ var check4 = {
5865
6025
  }
5866
6026
  if (/\/Lab\b/.test(bytes)) {
5867
6027
  results.push({
5868
- checkId: check4.id,
6028
+ checkId: check5.id,
5869
6029
  severity: "error",
5870
6030
  message: "Lab color space found (not allowed).",
5871
6031
  file: ctx.pdfPath
@@ -5873,7 +6033,7 @@ var check4 = {
5873
6033
  }
5874
6034
  if (/\/Separation/.test(bytes)) {
5875
6035
  results.push({
5876
- checkId: check4.id,
6036
+ checkId: check5.id,
5877
6037
  severity: "error",
5878
6038
  message: "Spot color (Separation) found (not allowed).",
5879
6039
  file: ctx.pdfPath
@@ -5881,7 +6041,7 @@ var check4 = {
5881
6041
  }
5882
6042
  if (/\/DeviceN/.test(bytes)) {
5883
6043
  results.push({
5884
- checkId: check4.id,
6044
+ checkId: check5.id,
5885
6045
  severity: "error",
5886
6046
  message: "Spot color (DeviceN) found (not allowed).",
5887
6047
  file: ctx.pdfPath
@@ -5890,10 +6050,10 @@ var check4 = {
5890
6050
  return results;
5891
6051
  }
5892
6052
  };
5893
- registerCheck(check4);
6053
+ registerCheck(check5);
5894
6054
 
5895
6055
  // src/checks/pdf/embedded-fonts.ts
5896
- var check5 = {
6056
+ var check6 = {
5897
6057
  id: "pdf.print.embedded-fonts",
5898
6058
  name: "Embedded Fonts",
5899
6059
  description: "Verifies all fonts in the PDF are embedded",
@@ -5909,7 +6069,7 @@ var check5 = {
5909
6069
  if (fonts.length === 0) {
5910
6070
  return [
5911
6071
  {
5912
- checkId: check5.id,
6072
+ checkId: check6.id,
5913
6073
  severity: "warning",
5914
6074
  message: "No fonts detected (unexpected).",
5915
6075
  file: ctx.pdfPath,
@@ -5922,7 +6082,7 @@ var check5 = {
5922
6082
  const names = notEmbedded.map((f) => f.name);
5923
6083
  return [
5924
6084
  {
5925
- checkId: check5.id,
6085
+ checkId: check6.id,
5926
6086
  severity: "error",
5927
6087
  message: `Not all fonts are embedded (${names.join(", ")}). Check @font-face and Chromium output.`,
5928
6088
  file: ctx.pdfPath,
@@ -5934,10 +6094,10 @@ var check5 = {
5934
6094
  return [];
5935
6095
  }
5936
6096
  };
5937
- registerCheck(check5);
6097
+ registerCheck(check6);
5938
6098
 
5939
6099
  // src/checks/pdf/ink-coverage.ts
5940
- var check6 = {
6100
+ var check7 = {
5941
6101
  id: "pdf.print.ink-coverage",
5942
6102
  name: "Ink Coverage (TAC)",
5943
6103
  description: "Checks total area coverage (TAC) against maximum ink limits",
@@ -5951,7 +6111,7 @@ var check6 = {
5951
6111
  if (!inkResult.ok) {
5952
6112
  return [
5953
6113
  {
5954
- checkId: check6.id,
6114
+ checkId: check7.id,
5955
6115
  severity: "warning",
5956
6116
  message: "Ink coverage could not be measured",
5957
6117
  file: ctx.pdfPath,
@@ -5976,7 +6136,7 @@ var check6 = {
5976
6136
  }
5977
6137
  return [
5978
6138
  {
5979
- checkId: check6.id,
6139
+ checkId: check7.id,
5980
6140
  severity: "warning",
5981
6141
  message: `Total ink coverage too high on ${offending.length} page(s) (max ${maxTac.toFixed(1)}%, recommended <=${ctx.config.ink.maxTac}%)`,
5982
6142
  file: ctx.pdfPath,
@@ -6000,10 +6160,10 @@ var check6 = {
6000
6160
  ];
6001
6161
  }
6002
6162
  };
6003
- registerCheck(check6);
6163
+ registerCheck(check7);
6004
6164
 
6005
6165
  // src/checks/pdf/rasterized-pages.ts
6006
- var check7 = {
6166
+ var check8 = {
6007
6167
  id: "pdf.print.rasterized-pages",
6008
6168
  name: "Rasterized Pages",
6009
6169
  description: "Detects pages that appear to be fully rasterized (CSS filters, blend modes, transparency)",
@@ -6043,7 +6203,7 @@ var check7 = {
6043
6203
  rasterizedPages.sort((a, b) => a - b);
6044
6204
  return [
6045
6205
  {
6046
- checkId: check7.id,
6206
+ checkId: check8.id,
6047
6207
  severity: "warning",
6048
6208
  message: `Possible rasterized pages detected: ${rasterizedPages.join(", ")}`,
6049
6209
  file: ctx.pdfPath,
@@ -6054,10 +6214,10 @@ var check7 = {
6054
6214
  ];
6055
6215
  }
6056
6216
  };
6057
- registerCheck(check7);
6217
+ registerCheck(check8);
6058
6218
 
6059
6219
  // src/checks/pdf/bookmarks.ts
6060
- var check8 = {
6220
+ var check9 = {
6061
6221
  id: "pdf.nav.bookmarks",
6062
6222
  name: "Bookmarks",
6063
6223
  description: "Checks for PDF outline (bookmarks) tree",
@@ -6071,14 +6231,14 @@ var check8 = {
6071
6231
  const doc = await loadPdf(ctx.pdfPath);
6072
6232
  if (!doc) {
6073
6233
  return [
6074
- inspectionFailed(check8.id, "Could not inspect PDF for bookmarks.", {
6234
+ inspectionFailed(check9.id, "Could not inspect PDF for bookmarks.", {
6075
6235
  file: ctx.pdfPath
6076
6236
  })
6077
6237
  ];
6078
6238
  }
6079
6239
  if (await getOutlineCount(doc) === 0) {
6080
6240
  return [
6081
- finding(check8.id, {
6241
+ finding(check9.id, {
6082
6242
  severity: "warning",
6083
6243
  message: "PDF does not contain bookmarks (outline tree).",
6084
6244
  file: ctx.pdfPath
@@ -6088,10 +6248,10 @@ var check8 = {
6088
6248
  return [];
6089
6249
  }
6090
6250
  };
6091
- registerCheck(check8);
6251
+ registerCheck(check9);
6092
6252
 
6093
6253
  // src/checks/pdf/toc-links.ts
6094
- var check9 = {
6254
+ var check10 = {
6095
6255
  id: "pdf.nav.toc-links",
6096
6256
  name: "TOC Links",
6097
6257
  description: "Detects link annotations on TOC pages",
@@ -6106,7 +6266,7 @@ var check9 = {
6106
6266
  if (!doc) {
6107
6267
  return [
6108
6268
  {
6109
- checkId: check9.id,
6269
+ checkId: check10.id,
6110
6270
  severity: "warning",
6111
6271
  message: "Could not inspect PDF for TOC links.",
6112
6272
  file: ctx.pdfPath
@@ -6117,7 +6277,7 @@ var check9 = {
6117
6277
  if (!hasLinks) {
6118
6278
  return [
6119
6279
  {
6120
- checkId: check9.id,
6280
+ checkId: check10.id,
6121
6281
  severity: "warning",
6122
6282
  message: "No link annotations found in PDF (expected for TOC).",
6123
6283
  file: ctx.pdfPath
@@ -6127,10 +6287,10 @@ var check9 = {
6127
6287
  return [];
6128
6288
  }
6129
6289
  };
6130
- registerCheck(check9);
6290
+ registerCheck(check10);
6131
6291
 
6132
6292
  // src/checks/pdf/cross-refs.ts
6133
- var check10 = {
6293
+ var check11 = {
6134
6294
  id: "pdf.nav.cross-refs",
6135
6295
  name: "Cross References",
6136
6296
  description: "Counts and verifies internal link annotations",
@@ -6143,7 +6303,7 @@ var check10 = {
6143
6303
  if (!doc) {
6144
6304
  return [
6145
6305
  {
6146
- checkId: check10.id,
6306
+ checkId: check11.id,
6147
6307
  severity: "info",
6148
6308
  message: "Could not inspect PDF for cross-references.",
6149
6309
  file: ctx.pdfPath
@@ -6153,7 +6313,7 @@ var check10 = {
6153
6313
  const linkCount = await countLinkAnnotations(doc);
6154
6314
  return [
6155
6315
  {
6156
- checkId: check10.id,
6316
+ checkId: check11.id,
6157
6317
  severity: "info",
6158
6318
  message: `PDF contains ${linkCount} internal link annotation${linkCount !== 1 ? "s" : ""}.`,
6159
6319
  file: ctx.pdfPath
@@ -6161,10 +6321,10 @@ var check10 = {
6161
6321
  ];
6162
6322
  }
6163
6323
  };
6164
- registerCheck(check10);
6324
+ registerCheck(check11);
6165
6325
 
6166
6326
  // src/checks/pdf/page-labels.ts
6167
- var check11 = {
6327
+ var check12 = {
6168
6328
  id: "pdf.nav.page-labels",
6169
6329
  name: "Page Labels",
6170
6330
  description: "Verifies PDF page labels / folio numbering",
@@ -6179,7 +6339,7 @@ var check11 = {
6179
6339
  const labels = await getPageLabels(doc);
6180
6340
  return [
6181
6341
  {
6182
- checkId: check11.id,
6342
+ checkId: check12.id,
6183
6343
  severity: "info",
6184
6344
  message: labels && labels.length > 0 ? "PDF contains page labels." : "PDF does not contain explicit page labels.",
6185
6345
  file: ctx.pdfPath
@@ -6187,10 +6347,10 @@ var check11 = {
6187
6347
  ];
6188
6348
  }
6189
6349
  };
6190
- registerCheck(check11);
6350
+ registerCheck(check12);
6191
6351
 
6192
6352
  // src/checks/pdf/image-resolution.ts
6193
- var check12 = {
6353
+ var check13 = {
6194
6354
  id: "pdf.print.image-resolution",
6195
6355
  name: "Image Resolution",
6196
6356
  description: "Checks DPI of images embedded in the PDF",
@@ -6217,7 +6377,7 @@ var check12 = {
6217
6377
  lowResPages.sort((a, b) => a - b);
6218
6378
  return [
6219
6379
  {
6220
- checkId: check12.id,
6380
+ checkId: check13.id,
6221
6381
  severity: "warning",
6222
6382
  message: `Low-resolution images (below ${minDpi} DPI) found on pages: ${lowResPages.join(", ")}`,
6223
6383
  file: ctx.pdfPath
@@ -6227,10 +6387,10 @@ var check12 = {
6227
6387
  return [];
6228
6388
  }
6229
6389
  };
6230
- registerCheck(check12);
6390
+ registerCheck(check13);
6231
6391
 
6232
6392
  // src/checks/pdf/transparency.ts
6233
- var check13 = {
6393
+ var check14 = {
6234
6394
  id: "pdf.print.transparency",
6235
6395
  name: "Transparency",
6236
6396
  description: "Checks for transparency markers (/Transparency, /SMask, /BM) in the PDF",
@@ -6252,7 +6412,7 @@ var check13 = {
6252
6412
  if (found.length > 0) {
6253
6413
  return [
6254
6414
  {
6255
- checkId: check13.id,
6415
+ checkId: check14.id,
6256
6416
  severity: "warning",
6257
6417
  message: `Transparency detected in PDF: ${found.join(", ")}. This may cause issues with some printers.`,
6258
6418
  file: ctx.pdfPath
@@ -6262,7 +6422,7 @@ var check13 = {
6262
6422
  return [];
6263
6423
  }
6264
6424
  };
6265
- registerCheck(check13);
6425
+ registerCheck(check14);
6266
6426
 
6267
6427
  // src/checks/pdf/bleed.ts
6268
6428
  function findBox(bytes, box) {
@@ -6272,7 +6432,7 @@ function findBox(bytes, box) {
6272
6432
  return null;
6273
6433
  return [Number(m[1]), Number(m[2]), Number(m[3]), Number(m[4])];
6274
6434
  }
6275
- var check14 = {
6435
+ var check15 = {
6276
6436
  id: "pdf.print.bleed",
6277
6437
  name: "Bleed Box",
6278
6438
  description: "Compares MediaBox vs TrimBox/BleedBox to verify bleed area",
@@ -6286,7 +6446,7 @@ var check14 = {
6286
6446
  const bytes = await readPdfBytes(ctx.pdfPath).catch(() => "");
6287
6447
  if (!bytes) {
6288
6448
  return [
6289
- inspectionFailed(check14.id, "Could not inspect PDF for bleed boxes.", {
6449
+ inspectionFailed(check15.id, "Could not inspect PDF for bleed boxes.", {
6290
6450
  file: ctx.pdfPath
6291
6451
  })
6292
6452
  ];
@@ -6296,14 +6456,14 @@ var check14 = {
6296
6456
  const bleed = findBox(bytes, "BleedBox");
6297
6457
  if (!media) {
6298
6458
  return [
6299
- inspectionFailed(check14.id, "Could not parse MediaBox from PDF.", {
6459
+ inspectionFailed(check15.id, "Could not parse MediaBox from PDF.", {
6300
6460
  file: ctx.pdfPath
6301
6461
  })
6302
6462
  ];
6303
6463
  }
6304
6464
  if (!trim && !bleed) {
6305
6465
  return [
6306
- finding(check14.id, {
6466
+ finding(check15.id, {
6307
6467
  severity: "warning",
6308
6468
  message: "No TrimBox or BleedBox found. Bleed area cannot be verified.",
6309
6469
  file: ctx.pdfPath
@@ -6316,7 +6476,7 @@ var check14 = {
6316
6476
  const bleedSize = ctx.config.validate.pdf.bleedSize;
6317
6477
  if (mediaW - trimW < bleedSize * 2 * 0.9) {
6318
6478
  return [
6319
- finding(check14.id, {
6479
+ finding(check15.id, {
6320
6480
  severity: "warning",
6321
6481
  message: `Bleed area appears insufficient. Expected at least ${bleedSize}pt on each side.`,
6322
6482
  file: ctx.pdfPath
@@ -6327,10 +6487,10 @@ var check14 = {
6327
6487
  return [];
6328
6488
  }
6329
6489
  };
6330
- registerCheck(check14);
6490
+ registerCheck(check15);
6331
6491
 
6332
6492
  // src/checks/pdf/pdfx-metadata.ts
6333
- var check15 = {
6493
+ var check16 = {
6334
6494
  id: "pdf.print.pdfx-metadata",
6335
6495
  name: "PDF/X Metadata",
6336
6496
  description: "Verifies PDF/X DOCINFO metadata via qpdf JSON",
@@ -6349,118 +6509,26 @@ var check15 = {
6349
6509
  const objects = parseQpdfObjectsJson(stdout);
6350
6510
  if (!objects) {
6351
6511
  return [
6352
- inspectionFailed(check15.id, "Unable to parse qpdf JSON output for PDF/X metadata checks.", { file: ctx.pdfPath })
6512
+ inspectionFailed(check16.id, "Unable to parse qpdf JSON output for PDF/X metadata checks.", { file: ctx.pdfPath })
6353
6513
  ];
6354
6514
  }
6355
- return getPdfxMetadataIssues(objects, ctx.config.pdfx.flavor).map((message) => finding(check15.id, {
6515
+ return getPdfxMetadataIssues(objects, ctx.config.pdfx.flavor).map((message) => finding(check16.id, {
6356
6516
  severity: "error",
6357
6517
  message,
6358
6518
  file: ctx.pdfPath
6359
6519
  }));
6360
6520
  } catch {
6361
6521
  return [
6362
- inspectionFailed(check15.id, "Failed to inspect PDF objects with qpdf for PDF/X metadata.", { file: ctx.pdfPath })
6522
+ inspectionFailed(check16.id, "Failed to inspect PDF objects with qpdf for PDF/X metadata.", { file: ctx.pdfPath })
6363
6523
  ];
6364
6524
  }
6365
6525
  }
6366
6526
  };
6367
- registerCheck(check15);
6368
-
6369
- // src/checks/source/markdownlint.ts
6370
- import { readFile as readFile11 } from "node:fs/promises";
6371
- import { lint } from "markdownlint/sync";
6372
- import { parse as parseYaml2 } from "yaml";
6373
-
6374
- // src/checks/source/config-file.ts
6375
- import { existsSync as existsSync6 } from "node:fs";
6376
- import { resolve as resolve5 } from "node:path";
6377
- function findConfigFile(inputDir, names, explicit) {
6378
- if (explicit) {
6379
- const p = resolve5(inputDir, explicit);
6380
- return existsSync6(p) ? p : null;
6381
- }
6382
- for (const name of names) {
6383
- const p = resolve5(inputDir, name);
6384
- if (existsSync6(p))
6385
- return p;
6386
- }
6387
- return null;
6388
- }
6389
-
6390
- // src/checks/source/markdownlint.ts
6391
- var CONFIG_NAMES = [
6392
- ".markdownlint.yaml",
6393
- ".markdownlint.yml",
6394
- ".markdownlint.json",
6395
- ".markdownlint.jsonc",
6396
- ".markdownlint-cli2.yaml",
6397
- ".markdownlint-cli2.jsonc"
6398
- ];
6399
- function stripJsonComments(s) {
6400
- return s.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
6401
- }
6402
- async function loadConfig(configPath) {
6403
- const raw = await readFile11(configPath, "utf8");
6404
- let parsed;
6405
- if (configPath.endsWith(".json")) {
6406
- parsed = JSON.parse(raw);
6407
- } else if (configPath.endsWith(".jsonc")) {
6408
- parsed = JSON.parse(stripJsonComments(raw));
6409
- } else {
6410
- parsed = parseYaml2(raw);
6411
- }
6412
- if (parsed && typeof parsed === "object") {
6413
- const obj = parsed;
6414
- if (obj.config && typeof obj.config === "object") {
6415
- return obj.config;
6416
- }
6417
- return obj;
6418
- }
6419
- return {};
6420
- }
6421
- var check16 = {
6422
- id: "source.markdownlint",
6423
- name: "Markdownlint",
6424
- description: "Runs markdownlint with project config to validate Markdown files",
6425
- category: "source",
6426
- phase: "pre-build",
6427
- async run(ctx) {
6428
- const sourceConfig = ctx.config.validate.source;
6429
- if (sourceConfig.markdownlint === false)
6430
- return [];
6431
- const files = ctx.markdownFiles;
6432
- if (!files || files.length === 0)
6433
- return [];
6434
- const configPath = typeof sourceConfig.markdownlint === "string" ? sourceConfig.markdownlint : null;
6435
- const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES, configPath);
6436
- if (!resolvedConfig && !configPath)
6437
- return [];
6438
- const config = resolvedConfig ? await loadConfig(resolvedConfig) : { default: true };
6439
- const results = lint({ files, config });
6440
- const out = [];
6441
- for (const [file, violations] of Object.entries(results)) {
6442
- if (!Array.isArray(violations))
6443
- continue;
6444
- for (const v of violations) {
6445
- out.push({
6446
- checkId: check16.id,
6447
- severity: "warning",
6448
- message: `${v.ruleDescription} (${v.ruleNames.join("/")})`,
6449
- file,
6450
- line: v.lineNumber,
6451
- column: v.errorRange?.[0],
6452
- code: v.ruleNames[0]
6453
- });
6454
- }
6455
- }
6456
- return out;
6457
- }
6458
- };
6459
6527
  registerCheck(check16);
6460
6528
 
6461
6529
  // src/checks/source/htmlhint.ts
6462
6530
  import { existsSync as existsSync7 } from "node:fs";
6463
- import { readFile as readFile12 } from "node:fs/promises";
6531
+ import { readFile as readFile13 } from "node:fs/promises";
6464
6532
  import htmlhint from "htmlhint";
6465
6533
  var { HTMLHint } = htmlhint;
6466
6534
  var CONFIG_NAMES2 = [".htmlhintrc"];
@@ -6480,8 +6548,8 @@ var check17 = {
6480
6548
  const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES2, configPath);
6481
6549
  if (!resolvedConfig && !configPath)
6482
6550
  return [];
6483
- const ruleset = resolvedConfig ? JSON.parse(await readFile12(resolvedConfig, "utf8")) : HTMLHint.defaultRuleset;
6484
- const html = await readFile12(ctx.htmlPath, "utf8");
6551
+ const ruleset = resolvedConfig ? JSON.parse(await readFile13(resolvedConfig, "utf8")) : HTMLHint.defaultRuleset;
6552
+ const html = await readFile13(ctx.htmlPath, "utf8");
6485
6553
  const messages = HTMLHint.verify(html, ruleset);
6486
6554
  return messages.map((m) => ({
6487
6555
  checkId: check17.id,
@@ -6496,7 +6564,7 @@ var check17 = {
6496
6564
  registerCheck(check17);
6497
6565
 
6498
6566
  // src/checks/source/stylelint.ts
6499
- import { readFile as readFile13 } from "node:fs/promises";
6567
+ import { readFile as readFile14 } from "node:fs/promises";
6500
6568
 
6501
6569
  // src/lib/printsafe.ts
6502
6570
  import postcss2 from "postcss";
@@ -6772,7 +6840,7 @@ var check18 = {
6772
6840
  for (const file of files) {
6773
6841
  let css;
6774
6842
  try {
6775
- css = await readFile13(file, "utf8");
6843
+ css = await readFile14(file, "utf8");
6776
6844
  } catch (err) {
6777
6845
  results.push({
6778
6846
  checkId: check18.id,
@@ -6799,12 +6867,12 @@ var check18 = {
6799
6867
  registerCheck(check18);
6800
6868
 
6801
6869
  // src/checks/source/css-ownership.ts
6802
- import { readFile as readFile14 } from "node:fs/promises";
6870
+ import { readFile as readFile15 } from "node:fs/promises";
6803
6871
  import postcss3 from "postcss";
6804
6872
  import { parse as parseYaml3 } from "yaml";
6805
6873
  var CONFIG_NAMES3 = [".gutterpress/css-contract.yaml", ".gutterpress/css-contract.yml"];
6806
6874
  async function loadContract(configPath) {
6807
- const raw = await readFile14(configPath, "utf8");
6875
+ const raw = await readFile15(configPath, "utf8");
6808
6876
  const parsed = parseYaml3(raw);
6809
6877
  if (parsed && typeof parsed === "object")
6810
6878
  return parsed;
@@ -6955,7 +7023,7 @@ var check19 = {
6955
7023
  continue;
6956
7024
  let css;
6957
7025
  try {
6958
- css = await readFile14(absFile, "utf8");
7026
+ css = await readFile15(absFile, "utf8");
6959
7027
  } catch {
6960
7028
  continue;
6961
7029
  }
@@ -7001,7 +7069,7 @@ import { existsSync as existsSync8 } from "node:fs";
7001
7069
  import { dirname as dirname3, resolve as resolve6 } from "node:path";
7002
7070
 
7003
7071
  // src/checks/source/local-ref-parser.ts
7004
- import { readFile as readFile15 } from "node:fs/promises";
7072
+ import { readFile as readFile16 } from "node:fs/promises";
7005
7073
  function newlineOffsets(content) {
7006
7074
  const offsets = [];
7007
7075
  for (let i = 0;i < content.length; i++)
@@ -7070,7 +7138,7 @@ async function* renderedLocalRefs(ctx, checkId, results) {
7070
7138
  for (const file of files) {
7071
7139
  let refs;
7072
7140
  try {
7073
- refs = collectRenderedLocalRefs(await readFile15(file, "utf8"));
7141
+ refs = collectRenderedLocalRefs(await readFile16(file, "utf8"));
7074
7142
  } catch {
7075
7143
  results.push(inspectionFailed(checkId, `Could not read source file: ${file}`, { file }));
7076
7144
  continue;
@@ -7421,7 +7489,7 @@ var check21 = {
7421
7489
  registerCheck(check21);
7422
7490
 
7423
7491
  // src/checks/source/accessibility-alt-text.ts
7424
- import { readFile as readFile16 } from "node:fs/promises";
7492
+ import { readFile as readFile17 } from "node:fs/promises";
7425
7493
  var check22 = {
7426
7494
  id: "source.accessibility.alt-text",
7427
7495
  name: "Image Alt Text",
@@ -7435,7 +7503,7 @@ var check22 = {
7435
7503
  const results = [];
7436
7504
  for (const file of files) {
7437
7505
  try {
7438
- const content = await readFile16(file, "utf8");
7506
+ const content = await readFile17(file, "utf8");
7439
7507
  const lines = content.split(`
7440
7508
  `);
7441
7509
  let inFence = false;
@@ -7479,7 +7547,7 @@ function extractImageAlts(line) {
7479
7547
  registerCheck(check22);
7480
7548
 
7481
7549
  // src/checks/source/accessibility-heading-order.ts
7482
- import { readFile as readFile17 } from "node:fs/promises";
7550
+ import { readFile as readFile18 } from "node:fs/promises";
7483
7551
  var check23 = {
7484
7552
  id: "source.accessibility.heading-order",
7485
7553
  name: "Heading Order",
@@ -7493,7 +7561,7 @@ var check23 = {
7493
7561
  const results = [];
7494
7562
  for (const file of files) {
7495
7563
  try {
7496
- const content = await readFile17(file, "utf8");
7564
+ const content = await readFile18(file, "utf8");
7497
7565
  const lines = content.split(`
7498
7566
  `);
7499
7567
  let inFence = false;
@@ -7529,7 +7597,7 @@ var check23 = {
7529
7597
  registerCheck(check23);
7530
7598
 
7531
7599
  // src/checks/source/layout-markers.ts
7532
- import { readFile as readFile18 } from "node:fs/promises";
7600
+ import { readFile as readFile19 } from "node:fs/promises";
7533
7601
  var check24 = {
7534
7602
  id: "source.markdown.layout-markers",
7535
7603
  name: "Layout Markers",
@@ -7547,7 +7615,7 @@ var check24 = {
7547
7615
  const md = createMarkdownRenderer(plugins);
7548
7616
  for (const file of files) {
7549
7617
  try {
7550
- const content = await readFile18(file, "utf8");
7618
+ const content = await readFile19(file, "utf8");
7551
7619
  const env = {};
7552
7620
  md.render(content, env);
7553
7621
  for (const w of env.layoutWarnings ?? []) {
@@ -7569,7 +7637,7 @@ var check24 = {
7569
7637
  registerCheck(check24);
7570
7638
 
7571
7639
  // src/checks/source/merge-markers.ts
7572
- import { readFile as readFile19 } from "node:fs/promises";
7640
+ import { readFile as readFile20 } from "node:fs/promises";
7573
7641
  import path8 from "node:path";
7574
7642
 
7575
7643
  // src/checks/asset/extensions.ts
@@ -7611,7 +7679,7 @@ var check25 = {
7611
7679
  for (const file of textFiles) {
7612
7680
  let content;
7613
7681
  try {
7614
- content = await readFile19(file, "utf8");
7682
+ content = await readFile20(file, "utf8");
7615
7683
  } catch {
7616
7684
  results.push(inspectionFailed(check25.id, `Could not read source file: ${file}`, { file }));
7617
7685
  continue;
@@ -7674,7 +7742,7 @@ registerCheck(check25);
7674
7742
  import { stat as stat3 } from "node:fs/promises";
7675
7743
 
7676
7744
  // src/lib/image-inspect.ts
7677
- import { stat as stat2, readFile as readFile20 } from "node:fs/promises";
7745
+ import { stat as stat2, readFile as readFile21 } from "node:fs/promises";
7678
7746
  var DEFAULT_DPI = 72;
7679
7747
  var cache = new Map;
7680
7748
  async function inspectImage(path9) {
@@ -7689,7 +7757,7 @@ async function inspectImage(path9) {
7689
7757
  return hit.info;
7690
7758
  let info2 = null;
7691
7759
  try {
7692
- const buf = await readFile20(path9);
7760
+ const buf = await readFile21(path9);
7693
7761
  info2 = parseImage(buf);
7694
7762
  } catch {
7695
7763
  info2 = null;
@@ -8249,7 +8317,7 @@ var check33 = {
8249
8317
  registerCheck(check33);
8250
8318
 
8251
8319
  // src/checks/heuristic/section-density.ts
8252
- import { readFile as readFile21 } from "node:fs/promises";
8320
+ import { readFile as readFile22 } from "node:fs/promises";
8253
8321
  var check34 = {
8254
8322
  id: "heuristic.chunking.section-density",
8255
8323
  name: "Section Density",
@@ -8266,7 +8334,7 @@ var check34 = {
8266
8334
  const results = [];
8267
8335
  for (const file of files) {
8268
8336
  try {
8269
- const content = await readFile21(file, "utf8");
8337
+ const content = await readFile22(file, "utf8");
8270
8338
  const lines = content.split(`
8271
8339
  `);
8272
8340
  let currentSectionStart = 0;
@@ -8765,6 +8833,14 @@ async function executeValidation(args) {
8765
8833
  only,
8766
8834
  skip
8767
8835
  };
8836
+ if (args.fix) {
8837
+ const selected = selectChecks(runnerOptions, config).checks;
8838
+ if (selected.some((check37) => check37.id === MARKDOWNLINT_CHECK_ID)) {
8839
+ await applyMarkdownlintFixes(context);
8840
+ } else {
8841
+ log.warn(`--fix: ${MARKDOWNLINT_CHECK_ID} is not part of this run — no files were fixed.`);
8842
+ }
8843
+ }
8768
8844
  const runs = planRuns({ manifest, baseConfig: config, targetIds, pdfPath, categories, only });
8769
8845
  const reports = [];
8770
8846
  const toolResults = [];
@@ -9243,7 +9319,7 @@ async function runBuild(opts) {
9243
9319
  import path11 from "path";
9244
9320
  import { tmpdir as tmpdir2 } from "os";
9245
9321
  import { randomBytes as randomBytes2 } from "crypto";
9246
- import { readdir as readdir5, readFile as readFile22, writeFile as writeFile5 } from "node:fs/promises";
9322
+ import { readdir as readdir5, readFile as readFile23, writeFile as writeFile6 } from "node:fs/promises";
9247
9323
 
9248
9324
  // src/utils/file-utils.ts
9249
9325
  import { promises as fs3 } from "fs";
@@ -9753,7 +9829,7 @@ async function cleanupOrphanTempDirs() {
9753
9829
  const dir = path11.join(TEMP_DIR_BASE, entry);
9754
9830
  const pidFile = path11.join(dir, PID_FILE_NAME);
9755
9831
  try {
9756
- const raw = await readFile22(pidFile, "utf8");
9832
+ const raw = await readFile23(pidFile, "utf8");
9757
9833
  const pid = parseInt(raw.trim(), 10);
9758
9834
  if (!isProcessAlive(pid)) {
9759
9835
  debug(`Removing orphan temp dir ${dir} (pid ${pid} not alive)`);
@@ -9768,7 +9844,7 @@ async function initializePreviewDirectories() {
9768
9844
  const tempDir = path11.join(TEMP_DIR_BASE, tempDirSuffix);
9769
9845
  await mkdir4(tempDir);
9770
9846
  debug(`Created temporary directory: ${tempDir}`);
9771
- await writeFile5(path11.join(tempDir, PID_FILE_NAME), `${process.pid}
9847
+ await writeFile6(path11.join(tempDir, PID_FILE_NAME), `${process.pid}
9772
9848
  `, "utf8");
9773
9849
  return tempDir;
9774
9850
  }
@@ -9859,7 +9935,7 @@ function createServerState(inputPath, tempDir, config, options) {
9859
9935
  import http from "node:http";
9860
9936
  import net from "node:net";
9861
9937
  import { createHash as createHash6, randomUUID } from "node:crypto";
9862
- import { readFile as readFile23, stat as stat4 } from "node:fs/promises";
9938
+ import { readFile as readFile24, stat as stat4 } from "node:fs/promises";
9863
9939
  import path13 from "path";
9864
9940
  import { WebSocket, WebSocketServer } from "ws";
9865
9941
 
@@ -10177,7 +10253,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
10177
10253
  }
10178
10254
  let data;
10179
10255
  try {
10180
- data = await readFile23(filePath);
10256
+ data = await readFile24(filePath);
10181
10257
  } catch {
10182
10258
  res.writeHead(404);
10183
10259
  res.end("Not Found");
@@ -10227,7 +10303,7 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
10227
10303
  let data;
10228
10304
  if (!validator || validator.stamp !== stamp) {
10229
10305
  try {
10230
- data = await readFile23(absPath);
10306
+ data = await readFile24(absPath);
10231
10307
  } catch {
10232
10308
  await serveStatic(absPath, res);
10233
10309
  return;
@@ -10568,7 +10644,7 @@ async function startPreviewServer(options) {
10568
10644
  import { platform, arch, release } from "node:os";
10569
10645
 
10570
10646
  // src/lib/remote-auth/token-store.ts
10571
- import { chmod, mkdir as mkdir5, readFile as readFile24, rename as rename2, writeFile as writeFile6 } from "node:fs/promises";
10647
+ import { chmod, mkdir as mkdir5, readFile as readFile25, rename as rename2, writeFile as writeFile7 } from "node:fs/promises";
10572
10648
  import os3 from "node:os";
10573
10649
  import path14 from "node:path";
10574
10650
  function credentialHostKey(hostOrUrl) {
@@ -10612,7 +10688,7 @@ class FileTokenStore {
10612
10688
  async read() {
10613
10689
  let raw;
10614
10690
  try {
10615
- raw = await readFile24(this.filePath, "utf8");
10691
+ raw = await readFile25(this.filePath, "utf8");
10616
10692
  } catch (e) {
10617
10693
  if (e?.code === "ENOENT") {
10618
10694
  return { version: 1, credentials: {} };
@@ -10624,7 +10700,7 @@ class FileTokenStore {
10624
10700
  if (parsed && typeof parsed === "object" && parsed.credentials)
10625
10701
  return parsed;
10626
10702
  } catch {
10627
- await writeFile6(`${this.filePath}.corrupt`, raw, {
10703
+ await writeFile7(`${this.filePath}.corrupt`, raw, {
10628
10704
  encoding: "utf8",
10629
10705
  mode: 384
10630
10706
  }).catch(() => {});
@@ -10634,7 +10710,7 @@ class FileTokenStore {
10634
10710
  async write(data) {
10635
10711
  await mkdir5(path14.dirname(this.filePath), { recursive: true });
10636
10712
  const tmpPath = `${this.filePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
10637
- await writeFile6(tmpPath, JSON.stringify(data, null, 2), {
10713
+ await writeFile7(tmpPath, JSON.stringify(data, null, 2), {
10638
10714
  encoding: "utf8",
10639
10715
  mode: 384
10640
10716
  });
@@ -10812,14 +10888,14 @@ async function getSystemDiagnostics() {
10812
10888
  };
10813
10889
  }
10814
10890
  // src/lib/project-scaffold.ts
10815
- import { access, copyFile, cp as cp3, mkdir as mkdir9, readdir as readdir6, readFile as readFile28, stat as stat6, writeFile as writeFile7 } from "node:fs/promises";
10891
+ import { access, copyFile, cp as cp3, mkdir as mkdir9, readdir as readdir6, readFile as readFile29, stat as stat6, writeFile as writeFile8 } from "node:fs/promises";
10816
10892
  import { constants as FS, existsSync as existsSync13 } from "node:fs";
10817
10893
  import path18 from "node:path";
10818
10894
 
10819
10895
  // src/lib/manifest-doc.ts
10820
10896
  import { existsSync as existsSync11 } from "node:fs";
10821
10897
  import { randomUUID as randomUUID2 } from "node:crypto";
10822
- import { mkdir as mkdir6, open, readFile as readFile25, rename as rename3, rm as rm2 } from "node:fs/promises";
10898
+ import { mkdir as mkdir6, open, readFile as readFile26, rename as rename3, rm as rm2 } from "node:fs/promises";
10823
10899
  import path15 from "node:path";
10824
10900
  import { parseDocument, isSeq, YAMLSeq } from "yaml";
10825
10901
  function resolveManifestPath(projectDir) {
@@ -10830,7 +10906,7 @@ async function loadManifestDoc(projectDir) {
10830
10906
  const file = resolveManifestPath(projectDir);
10831
10907
  let text = "";
10832
10908
  try {
10833
- text = await readFile25(file, "utf8");
10909
+ text = await readFile26(file, "utf8");
10834
10910
  } catch (error2) {
10835
10911
  if (error2.code !== "ENOENT")
10836
10912
  throw error2;
@@ -10877,7 +10953,7 @@ function scalarString(item) {
10877
10953
  }
10878
10954
 
10879
10955
  // src/lib/extension-manager.ts
10880
- import { cp as cp2, mkdir as mkdir8, readFile as readFile27, rm as rm4, stat as stat5 } from "node:fs/promises";
10956
+ import { cp as cp2, mkdir as mkdir8, readFile as readFile28, rm as rm4, stat as stat5 } from "node:fs/promises";
10881
10957
  import { existsSync as existsSync12 } from "node:fs";
10882
10958
  import path17 from "node:path";
10883
10959
  import { isSeq as isSeq2, isMap, isScalar, YAMLMap, Scalar } from "yaml";
@@ -10890,7 +10966,7 @@ import {
10890
10966
  mkdir as mkdir7,
10891
10967
  mkdtemp as mkdtemp2,
10892
10968
  open as open2,
10893
- readFile as readFile26,
10969
+ readFile as readFile27,
10894
10970
  realpath as realpath2,
10895
10971
  rename as rename4,
10896
10972
  rm as rm3
@@ -11288,7 +11364,7 @@ async function readInstalledManifest(packageDir, selected) {
11288
11364
  const info2 = await lstat2(packageJsonPath);
11289
11365
  if (!info2.isFile() || info2.isSymbolicLink())
11290
11366
  throw new Error("not a regular file");
11291
- manifest = object3(JSON.parse(await readFile26(packageJsonPath, "utf8")));
11367
+ manifest = object3(JSON.parse(await readFile27(packageJsonPath, "utf8")));
11292
11368
  } catch (error2) {
11293
11369
  throw new SecurityInstallError(`Downloaded ${selected.name}@${selected.version} has no valid package.json (${error2 instanceof Error ? error2.message : String(error2)}).`);
11294
11370
  }
@@ -12060,7 +12136,7 @@ async function readExtensionCss(projectDir, use) {
12060
12136
  throw new Error(`Extension "${use}" declares no stylesheets.`);
12061
12137
  const parts = [];
12062
12138
  for (const sheet of sheets)
12063
- parts.push(await readFile27(sheet, "utf8"));
12139
+ parts.push(await readFile28(sheet, "utf8"));
12064
12140
  return parts.join(`
12065
12141
 
12066
12142
  `);
@@ -12187,7 +12263,7 @@ async function scaffoldProject(options) {
12187
12263
  await copyFile(tplManifest, path18.join(projectDir, MANIFEST_FILENAMES[0]));
12188
12264
  await copyFile(tplChapter, path18.join(projectDir, "chapter-01.md"));
12189
12265
  await mkdir9(path18.join(projectDir, "styles"), { recursive: true });
12190
- await writeFile7(path18.join(projectDir, "styles", "book.css"), starterOverridesCss(starterThemeId), "utf8");
12266
+ await writeFile8(path18.join(projectDir, "styles", "book.css"), starterOverridesCss(starterThemeId), "utf8");
12191
12267
  }
12192
12268
  } catch (e) {
12193
12269
  throw new CreateProjectErrorImpl("scaffold-io", `Could not create the project files: ${e instanceof Error ? e.message : String(e)}`);
@@ -12302,7 +12378,7 @@ async function adoptFolder(options) {
12302
12378
  const bookCssPath = path18.join(dir, "styles", "book.css");
12303
12379
  const hadOwnStylesheet = existsSync13(bookCssPath);
12304
12380
  if (!hadOwnStylesheet) {
12305
- await writeFile7(bookCssPath, starterOverridesCss(themeId), "utf8");
12381
+ await writeFile8(bookCssPath, starterOverridesCss(themeId), "utf8");
12306
12382
  }
12307
12383
  const filesYaml = mdFiles.map((f) => ` - "${escapeYamlScalar(f)}"`).join(`
12308
12384
  `);
@@ -12318,7 +12394,7 @@ ${filesYaml}
12318
12394
  styles:
12319
12395
  - styles/book.css
12320
12396
  `;
12321
- await writeFile7(path18.join(dir, MANIFEST_FILENAMES[0]), manifest, "utf8");
12397
+ await writeFile8(path18.join(dir, MANIFEST_FILENAMES[0]), manifest, "utf8");
12322
12398
  await mkdir9(path18.join(dir, "assets"), { recursive: true });
12323
12399
  if (!hadOwnStylesheet) {
12324
12400
  await addBuiltInStyleSet(dir, themeId);
@@ -12361,10 +12437,10 @@ async function ensureGitignoreHasDist(projectDir) {
12361
12437
  const gitignorePath = path18.join(projectDir, ".gitignore");
12362
12438
  let existing = null;
12363
12439
  try {
12364
- existing = await readFile28(gitignorePath, "utf8");
12440
+ existing = await readFile29(gitignorePath, "utf8");
12365
12441
  } catch {}
12366
12442
  if (existing === null) {
12367
- await writeFile7(gitignorePath, `dist/
12443
+ await writeFile8(gitignorePath, `dist/
12368
12444
  `, "utf8");
12369
12445
  return;
12370
12446
  }
@@ -12374,14 +12450,14 @@ async function ensureGitignoreHasDist(projectDir) {
12374
12450
  return;
12375
12451
  const needsLeadingNewline = existing.length > 0 && !existing.endsWith(`
12376
12452
  `);
12377
- await writeFile7(gitignorePath, existing + (needsLeadingNewline ? `
12453
+ await writeFile8(gitignorePath, existing + (needsLeadingNewline ? `
12378
12454
  ` : "") + `dist/
12379
12455
  `, "utf8");
12380
12456
  }
12381
12457
  async function firstSourceFile(manifestPath) {
12382
12458
  let text;
12383
12459
  try {
12384
- text = await readFile28(manifestPath, "utf8");
12460
+ text = await readFile29(manifestPath, "utf8");
12385
12461
  } catch {
12386
12462
  return;
12387
12463
  }
@@ -12393,14 +12469,14 @@ async function firstSourceFile(manifestPath) {
12393
12469
  return m ? m[1].trim() : undefined;
12394
12470
  }
12395
12471
  async function fillTemplateFile(filePath, substitutions) {
12396
- let text = await readFile28(filePath, "utf8");
12472
+ let text = await readFile29(filePath, "utf8");
12397
12473
  for (const [token, value] of Object.entries(substitutions)) {
12398
12474
  text = text.split(token).join(value);
12399
12475
  }
12400
- await writeFile7(filePath, text, "utf8");
12476
+ await writeFile8(filePath, text, "utf8");
12401
12477
  }
12402
12478
  // src/lib/extension-scaffold.ts
12403
- import { access as access2, mkdir as mkdir10, readFile as readFile29, writeFile as writeFile8 } from "node:fs/promises";
12479
+ import { access as access2, mkdir as mkdir10, readFile as readFile30, writeFile as writeFile9 } from "node:fs/promises";
12404
12480
  import { constants as FS2 } from "node:fs";
12405
12481
  import path19 from "node:path";
12406
12482
  var EXTENSION_KINDS = ["plugin", "theme"];
@@ -12517,9 +12593,9 @@ async function scaffoldExtension(options) {
12517
12593
  const src = await getAssetPath(`extension-templates/${kind}/${assetName}`);
12518
12594
  const dest = path19.join(extensionDir, relDest);
12519
12595
  await mkdir10(path19.dirname(dest), { recursive: true });
12520
- const text = await readFile29(src, "utf8");
12596
+ const text = await readFile30(src, "utf8");
12521
12597
  const table = relDest.endsWith(".json") ? jsonSafe : plain;
12522
- await writeFile8(dest, substitute(text, table), "utf8");
12598
+ await writeFile9(dest, substitute(text, table), "utf8");
12523
12599
  written.push(relDest);
12524
12600
  }
12525
12601
  } catch (e) {
@@ -12543,7 +12619,7 @@ function substitute(text, table) {
12543
12619
  return out;
12544
12620
  }
12545
12621
  // src/lib/project-templates.ts
12546
- import { cp as cp4, mkdir as mkdir11, readFile as readFile30, readdir as readdir7, stat as stat7, writeFile as writeFile9 } from "node:fs/promises";
12622
+ import { cp as cp4, mkdir as mkdir11, readFile as readFile31, readdir as readdir7, stat as stat7, writeFile as writeFile10 } from "node:fs/promises";
12547
12623
  import { constants as FS3, existsSync as existsSync14 } from "node:fs";
12548
12624
  import { access as access3 } from "node:fs/promises";
12549
12625
  import path20 from "node:path";
@@ -12555,7 +12631,7 @@ var BUILT_IN_TEMPLATE_IDS = [
12555
12631
  ];
12556
12632
  async function readTemplateChoices(manifestPath) {
12557
12633
  try {
12558
- const text = await readFile30(manifestPath, "utf8");
12634
+ const text = await readFile31(manifestPath, "utf8");
12559
12635
  const doc = parseDocument2(text);
12560
12636
  const out = {};
12561
12637
  const preset = doc.get("preset");
@@ -12724,7 +12800,7 @@ async function saveProjectAsTemplate(options) {
12724
12800
  const shared = manifestName ? await reconcileSharedRefs(dir, projectDir, options.sharedRefs ?? "vendor") : { vendoredRefs: [], excludedRefs: [] };
12725
12801
  if (manifestName)
12726
12802
  await retokeniseManifest(path20.join(dir, manifestName));
12727
- await writeFile9(path20.join(dir, TEMPLATE_META_FILE), JSON.stringify({ label: name }, null, 2), "utf8");
12803
+ await writeFile10(path20.join(dir, TEMPLATE_META_FILE), JSON.stringify({ label: name }, null, 2), "utf8");
12728
12804
  return {
12729
12805
  id,
12730
12806
  label: name,
@@ -12737,12 +12813,12 @@ async function saveProjectAsTemplate(options) {
12737
12813
  async function retokeniseManifest(manifestPath) {
12738
12814
  let text;
12739
12815
  try {
12740
- text = await readFile30(manifestPath, "utf8");
12816
+ text = await readFile31(manifestPath, "utf8");
12741
12817
  } catch {
12742
12818
  return;
12743
12819
  }
12744
12820
  text = text.replace(/^title:\s*.*$/m, 'title: "{{TITLE}}"').replace(/^(authors:[^\n]*\n[ \t]*-[ \t]*).*$/m, '$1"{{AUTHOR}}"');
12745
- await writeFile9(manifestPath, text, "utf8");
12821
+ await writeFile10(manifestPath, text, "utf8");
12746
12822
  }
12747
12823
  async function listCustomTemplates(templatesRoot) {
12748
12824
  let entries;
@@ -12758,7 +12834,7 @@ async function listCustomTemplates(templatesRoot) {
12758
12834
  const dir = path20.join(templatesRoot, entry.name);
12759
12835
  let label = prettify(entry.name);
12760
12836
  try {
12761
- const meta = JSON.parse(await readFile30(path20.join(dir, TEMPLATE_META_FILE), "utf8"));
12837
+ const meta = JSON.parse(await readFile31(path20.join(dir, TEMPLATE_META_FILE), "utf8"));
12762
12838
  if (typeof meta.label === "string" && meta.label)
12763
12839
  label = meta.label;
12764
12840
  } catch {}
@@ -12784,7 +12860,7 @@ async function importTemplateFromFolder(options) {
12784
12860
  return saveProjectAsTemplate({ projectDir: sourceDir, name, templatesRoot });
12785
12861
  }
12786
12862
  // src/lib/snippets.ts
12787
- import { readdir as readdir8, readFile as readFile31, writeFile as writeFile10, mkdir as mkdir12, rm as rm5 } from "node:fs/promises";
12863
+ import { readdir as readdir8, readFile as readFile32, writeFile as writeFile11, mkdir as mkdir12, rm as rm5 } from "node:fs/promises";
12788
12864
  import path21 from "node:path";
12789
12865
  var SNIPPETS_DIR = "snippets";
12790
12866
  var PLACEHOLDER_RE = /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g;
@@ -12826,7 +12902,7 @@ async function scanSnippetFiles(dir) {
12826
12902
  continue;
12827
12903
  let body = "";
12828
12904
  try {
12829
- body = await readFile31(path21.join(dir, fileName), "utf8");
12905
+ body = await readFile32(path21.join(dir, fileName), "utf8");
12830
12906
  } catch {
12831
12907
  continue;
12832
12908
  }
@@ -12844,7 +12920,7 @@ async function listSnippets(projectDir) {
12844
12920
  return files.map((file) => ({ ...file, source: { kind: "project" } }));
12845
12921
  }
12846
12922
  async function readSnippet(projectDir, fileName) {
12847
- return readFile31(resolveSnippetPath(projectDir, fileName), "utf8");
12923
+ return readFile32(resolveSnippetPath(projectDir, fileName), "utf8");
12848
12924
  }
12849
12925
  async function saveSnippet(projectDir, name, body) {
12850
12926
  const stem = slugify(name);
@@ -12853,7 +12929,7 @@ async function saveSnippet(projectDir, name, body) {
12853
12929
  const fileName = `${stem}.md`;
12854
12930
  const dir = path21.join(projectDir, SNIPPETS_DIR);
12855
12931
  await mkdir12(dir, { recursive: true });
12856
- await writeFile10(resolveSnippetPath(projectDir, fileName), body, "utf8");
12932
+ await writeFile11(resolveSnippetPath(projectDir, fileName), body, "utf8");
12857
12933
  return { name, fileName, variables: extractVariables(body), source: { kind: "project" } };
12858
12934
  }
12859
12935
  async function deleteSnippet(projectDir, fileName) {
@@ -12903,11 +12979,11 @@ async function readExtensionSnippet(projectDir, source, fileName) {
12903
12979
  if (!dir) {
12904
12980
  throw new Error(`Extension "${source.ref}" does not declare a usable snippets folder.`);
12905
12981
  }
12906
- return readFile31(resolveSafeChildFile(dir, fileName), "utf8");
12982
+ return readFile32(resolveSafeChildFile(dir, fileName), "utf8");
12907
12983
  }
12908
12984
  // src/lib/extension-import.ts
12909
12985
  import { existsSync as existsSync15 } from "node:fs";
12910
- import { cp as cp5, mkdir as mkdir13, mkdtemp as mkdtemp3, readFile as readFile32, rm as rm6, writeFile as writeFile11 } from "node:fs/promises";
12986
+ import { cp as cp5, mkdir as mkdir13, mkdtemp as mkdtemp3, readFile as readFile33, rm as rm6, writeFile as writeFile12 } from "node:fs/promises";
12911
12987
  import { tmpdir as tmpdir3 } from "node:os";
12912
12988
  import path22 from "node:path";
12913
12989
  import { unzipSync } from "fflate";
@@ -12980,7 +13056,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
12980
13056
  if (!existsSync15(cssPath)) {
12981
13057
  throw new Error("A theme must contain a theme.css file.");
12982
13058
  }
12983
- const css = await readFile32(cssPath, "utf8");
13059
+ const css = await readFile33(cssPath, "utf8");
12984
13060
  const { reject, warnings: printFindings } = classifyThemeCssFindings(checkCss(css, "theme.css"));
12985
13061
  if (reject) {
12986
13062
  throw new Error(`theme.css could not be parsed — ${reject.message}`);
@@ -13008,7 +13084,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
13008
13084
  for (let i = 0;i < extraSheets.length; i++) {
13009
13085
  const rel = extraSheets[i];
13010
13086
  const sheetPath = extraSheetPaths[i];
13011
- const sheetCss = await readFile32(sheetPath, "utf8");
13087
+ const sheetCss = await readFile33(sheetPath, "utf8");
13012
13088
  const { reject: sheetReject, warnings: sheetFindings } = classifyThemeCssFindings(checkCss(sheetCss, rel));
13013
13089
  if (sheetReject) {
13014
13090
  throw new Error(`${rel} could not be parsed — ${sheetReject.message}`);
@@ -13041,14 +13117,14 @@ async function completeLandedManifest(dest, id, meta, metaExists) {
13041
13117
  let pkg = {};
13042
13118
  if (metaExists) {
13043
13119
  try {
13044
- const parsed = JSON.parse(await readFile32(file, "utf8"));
13120
+ const parsed = JSON.parse(await readFile33(file, "utf8"));
13045
13121
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
13046
13122
  pkg = parsed;
13047
13123
  }
13048
13124
  } catch {}
13049
13125
  }
13050
13126
  const gutterpress = pkg.gutterpress && typeof pkg.gutterpress === "object" && !Array.isArray(pkg.gutterpress) ? pkg.gutterpress : {};
13051
- await writeFile11(file, JSON.stringify({
13127
+ await writeFile12(file, JSON.stringify({
13052
13128
  ...pkg,
13053
13129
  name: typeof pkg.name === "string" && pkg.name.trim() ? pkg.name : id,
13054
13130
  gutterpress: { ...gutterpress, styles: ["theme.css"] }
@@ -13113,7 +13189,7 @@ async function importExtensionFromZip(projectDir, archive) {
13113
13189
  }
13114
13190
  relPaths.push(rel);
13115
13191
  await mkdir13(path22.dirname(dest), { recursive: true });
13116
- await writeFile11(dest, data);
13192
+ await writeFile12(dest, data);
13117
13193
  }
13118
13194
  return await finalizeExtensionImport(projectDir, tmp, relPaths, root || "imported-look");
13119
13195
  } finally {
@@ -13128,8 +13204,8 @@ async function importExtensionFromCssText(projectDir, css, name) {
13128
13204
  const displayName = name.trim() || "Imported theme";
13129
13205
  const tmp = await mkdtemp3(path22.join(tmpdir3(), "gutterpress-theme-"));
13130
13206
  try {
13131
- await writeFile11(path22.join(tmp, "theme.css"), css, "utf8");
13132
- await writeFile11(path22.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify({ name: slugify(displayName, "look"), gutterpress: { styles: ["theme.css"] } }, null, 2), "utf8");
13207
+ await writeFile12(path22.join(tmp, "theme.css"), css, "utf8");
13208
+ await writeFile12(path22.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify({ name: slugify(displayName, "look"), gutterpress: { styles: ["theme.css"] } }, null, 2), "utf8");
13133
13209
  const result = await finalizeExtensionImport(projectDir, tmp, ["theme.css", EXTENSION_MANIFEST_FILENAME], displayName);
13134
13210
  result.warnings.unshift({
13135
13211
  code: "no-theme-json",
@@ -13143,11 +13219,11 @@ async function importExtensionFromCssText(projectDir, css, name) {
13143
13219
  async function importExtensionFromFile(projectDir, filePath) {
13144
13220
  const ext = path22.extname(filePath).toLowerCase();
13145
13221
  if (ext === ".zip") {
13146
- const buf = await readFile32(filePath);
13222
+ const buf = await readFile33(filePath);
13147
13223
  return importExtensionFromZip(projectDir, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
13148
13224
  }
13149
13225
  if (ext === ".css") {
13150
- const css = await readFile32(filePath, "utf8");
13226
+ const css = await readFile33(filePath, "utf8");
13151
13227
  return importExtensionFromCssText(projectDir, css, prettify(path22.basename(filePath, ".css")));
13152
13228
  }
13153
13229
  throw new Error("Choose a .zip extension package or a .css stylesheet.");
@@ -13212,7 +13288,7 @@ async function importExtensionFromUrl(projectDir, url) {
13212
13288
  assertLooksLikeCss(css, trimmed);
13213
13289
  const tmp = await mkdtemp3(path22.join(tmpdir3(), "gutterpress-ext-"));
13214
13290
  try {
13215
- await writeFile11(path22.join(tmp, "theme.css"), css, "utf8");
13291
+ await writeFile12(path22.join(tmp, "theme.css"), css, "utf8");
13216
13292
  const gp = meta.gutterpress && typeof meta.gutterpress === "object" && !Array.isArray(meta.gutterpress) ? meta.gutterpress : {};
13217
13293
  const finalMeta = {
13218
13294
  name: typeof meta.name === "string" && meta.name || slugify(baseName, "look"),
@@ -13224,7 +13300,7 @@ async function importExtensionFromUrl(projectDir, url) {
13224
13300
  preview: typeof gp.preview === "string" ? gp.preview : null
13225
13301
  }
13226
13302
  };
13227
- await writeFile11(path22.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify(finalMeta, null, 2), "utf8");
13303
+ await writeFile12(path22.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify(finalMeta, null, 2), "utf8");
13228
13304
  return await finalizeExtensionImport(projectDir, tmp, ["theme.css", EXTENSION_MANIFEST_FILENAME], baseName);
13229
13305
  } finally {
13230
13306
  await rm6(tmp, { recursive: true, force: true });
@@ -14680,7 +14756,7 @@ async function diagnoseProjectRemote(projectDir, options = {}) {
14680
14756
  import git6 from "isomorphic-git";
14681
14757
 
14682
14758
  // src/lib/remote-auth/converge-merge.ts
14683
- import { mkdir as mkdir15, unlink as unlink3, writeFile as writeFile12 } from "node:fs/promises";
14759
+ import { mkdir as mkdir15, unlink as unlink3, writeFile as writeFile13 } from "node:fs/promises";
14684
14760
  import path24 from "node:path";
14685
14761
  import git5 from "isomorphic-git";
14686
14762
  import diff3Merge from "diff3";
@@ -14730,7 +14806,7 @@ async function readBlobOrNull(dir, cache2, oid, filepath) {
14730
14806
  async function writeTreeFile(dir, filepath, content) {
14731
14807
  const abs = path24.join(dir, filepath);
14732
14808
  await mkdir15(path24.dirname(abs), { recursive: true });
14733
- await writeFile12(abs, content);
14809
+ await writeFile13(abs, content);
14734
14810
  }
14735
14811
  async function bothAddedPaths(dir, cache2, ourTip, theirTip, allowUnrelated) {
14736
14812
  const bases = await git5.findMergeBase({ fs: gitFs, dir, cache: cache2, oids: [ourTip, theirTip] });
@@ -15248,7 +15324,7 @@ ${tail}` : ""}`);
15248
15324
  };
15249
15325
 
15250
15326
  // src/lib/publish/providers/guided.ts
15251
- import { copyFile as copyFile2, mkdir as mkdir16, writeFile as writeFile13 } from "node:fs/promises";
15327
+ import { copyFile as copyFile2, mkdir as mkdir16, writeFile as writeFile14 } from "node:fs/promises";
15252
15328
  import path25 from "node:path";
15253
15329
  async function stageGuidedPackage(req, providerId, listingLines) {
15254
15330
  const packageDir = path25.join(path25.dirname(req.artifact.path), "publish", providerId);
@@ -15266,7 +15342,7 @@ async function stageGuidedPackage(req, providerId, listingLines) {
15266
15342
  ""
15267
15343
  ].join(`
15268
15344
  `);
15269
- await writeFile13(path25.join(packageDir, "LISTING.md"), sheet, "utf8");
15345
+ await writeFile14(path25.join(packageDir, "LISTING.md"), sheet, "utf8");
15270
15346
  return packageDir;
15271
15347
  }
15272
15348
 
@@ -15329,7 +15405,7 @@ var drivethrurpgProvider = {
15329
15405
  };
15330
15406
 
15331
15407
  // src/lib/publish/providers/gdrive.ts
15332
- import { mkdtemp as mkdtemp4, readFile as readFile33, readdir as readdir10, rm as rm8, stat as stat9, writeFile as writeFile14 } from "node:fs/promises";
15408
+ import { mkdtemp as mkdtemp4, readFile as readFile34, readdir as readdir10, rm as rm8, stat as stat9, writeFile as writeFile15 } from "node:fs/promises";
15333
15409
  import { tmpdir as tmpdir4 } from "node:os";
15334
15410
  import path26 from "node:path";
15335
15411
  import { Zip, ZipDeflate } from "fflate";
@@ -15721,12 +15797,12 @@ async function collectZipEntries(root, dir, out, onWarn) {
15721
15797
  await collectZipEntries(root, full, out, onWarn);
15722
15798
  } else if (entry.isFile()) {
15723
15799
  const rel = path26.relative(root, full).split(path26.sep).join("/");
15724
- out[rel] = await readFile33(full);
15800
+ out[rel] = await readFile34(full);
15725
15801
  } else if (entry.isSymbolicLink()) {
15726
15802
  const resolved = await stat9(full).catch(() => null);
15727
15803
  if (resolved?.isFile()) {
15728
15804
  const rel = path26.relative(root, full).split(path26.sep).join("/");
15729
- out[rel] = await readFile33(full);
15805
+ out[rel] = await readFile34(full);
15730
15806
  } else if (resolved?.isDirectory()) {
15731
15807
  await collectZipEntries(root, full, out, onWarn);
15732
15808
  } else {
@@ -15737,7 +15813,7 @@ async function collectZipEntries(root, dir, out, onWarn) {
15737
15813
  }
15738
15814
  }
15739
15815
  }
15740
- async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeFile14) {
15816
+ async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeFile15) {
15741
15817
  const entries = {};
15742
15818
  await collectZipEntries(exportDir, exportDir, entries, onWarn);
15743
15819
  const fileName = `${bookSlug(title)}-website.zip`;
@@ -15841,7 +15917,7 @@ var gdriveProvider = {
15841
15917
  };
15842
15918
 
15843
15919
  // src/lib/publish/butler.ts
15844
- import { chmod as chmod2, mkdir as mkdir17, stat as stat10, writeFile as writeFile15 } from "node:fs/promises";
15920
+ import { chmod as chmod2, mkdir as mkdir17, stat as stat10, writeFile as writeFile16 } from "node:fs/promises";
15845
15921
  import path27 from "node:path";
15846
15922
  import { unzipSync as unzipSync2 } from "fflate";
15847
15923
  var BUTLER_DOWNLOAD_TIMEOUT_MS = 300000;
@@ -15908,7 +15984,7 @@ async function ensureButler(deps) {
15908
15984
  if (name.endsWith("/"))
15909
15985
  continue;
15910
15986
  const target = path27.join(cacheDir, path27.basename(name));
15911
- await writeFile15(target, data);
15987
+ await writeFile16(target, data);
15912
15988
  if (path27.basename(name) === butlerBinaryName()) {
15913
15989
  await chmod2(target, 493).catch(() => {});
15914
15990
  foundBinary = true;
@@ -16543,7 +16619,7 @@ async function disconnectPublishCredential(key, deps, options = {}) {
16543
16619
  }
16544
16620
  }
16545
16621
  // src/lib/publish/selections.ts
16546
- import { chmod as chmod3, mkdir as mkdir18, readFile as readFile34, writeFile as writeFile16 } from "node:fs/promises";
16622
+ import { chmod as chmod3, mkdir as mkdir18, readFile as readFile35, writeFile as writeFile17 } from "node:fs/promises";
16547
16623
  import path29 from "node:path";
16548
16624
  class PublishSelectionsStore {
16549
16625
  filePath;
@@ -16553,7 +16629,7 @@ class PublishSelectionsStore {
16553
16629
  }
16554
16630
  async read() {
16555
16631
  try {
16556
- const raw = await readFile34(this.filePath, "utf8");
16632
+ const raw = await readFile35(this.filePath, "utf8");
16557
16633
  const parsed = JSON.parse(raw);
16558
16634
  if (parsed && typeof parsed === "object") {
16559
16635
  return {
@@ -16567,7 +16643,7 @@ class PublishSelectionsStore {
16567
16643
  }
16568
16644
  async write(data) {
16569
16645
  await mkdir18(path29.dirname(this.filePath), { recursive: true });
16570
- await writeFile16(this.filePath, JSON.stringify(data, null, 2), {
16646
+ await writeFile17(this.filePath, JSON.stringify(data, null, 2), {
16571
16647
  encoding: "utf8",
16572
16648
  mode: 384
16573
16649
  });
@@ -16669,4 +16745,4 @@ async function setPublishProviderConfig(projectDir, providerId, values) {
16669
16745
  await writeManifestDoc(file, doc);
16670
16746
  return settingsFromDoc(doc);
16671
16747
  }
16672
- export { DEFAULT_NPM_REGISTRY, npmRegistryUrl, PLUGINS_DIR, BUNDLED_EXTENSIONS, isBundledExtension, isPathSpecifier, parseExtensionSpecifier, PRESET_IDS, PRESETS, TARGETS, TARGET_IDS, publishTargetFor, MANIFEST_FILENAMES, hasProjectManifest, loadManifest, loadManifestWithPath, resolveConfig, SYNC_SNAPSHOT_MESSAGE, log, resolveActiveStyles, listProjectStyles, EXTENSION_MANIFEST_FILENAME, readExtensionMeta, extensionStyleList, extensionEntry, extensionCarries, pathEscapesFolder, assertExtensionContained, resolveExtension, loadPluginsWithCss, formatReport, getChecks, getCheckById, resolveCheckSelectors, ruleRemoteUrls, ruleRiskyProps, ruleSyntax, rulePageContainment, checkCss, inspectImage, runChecks, checkToolAvailability, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics, EXTENSIONS_DIR, RECOMMENDED_EXTENSIONS, BUILT_IN_STYLE_SET_IDS, sameExtension, listProjectExtensions, describeExtension, setExtensionEnabled, reorderExtensions, removeExtension, addExtension, listBuiltInStyleSets, addBuiltInStyleSet, validateProjectExtensions, readExtensionCss, slugifyProjectName, escapeYamlScalar, scaffoldProject, adoptFolder, EXTENSION_KINDS, RESERVED_PREFIX, resolveExtensionPrefix, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, listBuiltInTemplates, saveProjectAsTemplate, listCustomTemplates, importTemplateFromFolder, SNIPPETS_DIR, extractVariables, substituteVariables, listSnippets, readSnippet, saveSnippet, deleteSnippet, listMergedSnippets, readExtensionSnippet, importExtensionFromFile, importExtensionFromUrl, MAX_SEARCH_BYTES, SEARCH_KEYWORDS, searchNpmExtensions, setManifestFields, readManifestFields, setActiveStyles, AUTO_SNAPSHOT_DEFAULT_MINUTES, AUTO_SYNC_MIN_MINUTES, AUTO_SYNC_MAX_MINUTES, AUTO_SYNC_DEFAULT_MINUTES, AUTO_SYNC_PUSH_INTERVAL_MINUTES, autoSnapshotDelayMs, autoSyncDelayMs, isGitInternalPath, resolveGitHubClientId, GITHUB_HOST, GitHubAuthProvider, GDRIVE_HOST, resolveGoogleClientId, resolveGoogleClientSecret, GOOGLE_NOT_CONFIGURED_MESSAGE, requireGoogleClientCredentials, pkceChallengeFromVerifier, GoogleAuthProvider, revokeGoogleCredential, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listGitHubRepositories, listRepoBooks, listGitHubBranches, sanitizeCloneFolderName, cloneRepository, isSshRemoteUrl, testRemoteAccess, knownForgeTokenUrl, connectGenericHost, parseRemoteOrigin, forgeKindForHost, diagnoseProjectRemote, syncProject, refreshRemoteCopies, listPublishProviders, publishProviderFor, resolvePublishFormat, resolvePublishRequest, runPublish, connectPublishProvider, disconnectPublishCredential, PublishSelectionsStore, readPublishSettings, setPublishProviderConfig };
16748
+ export { DEFAULT_NPM_REGISTRY, npmRegistryUrl, PLUGINS_DIR, BUNDLED_EXTENSIONS, isBundledExtension, isPathSpecifier, parseExtensionSpecifier, PRESET_IDS, PRESETS, TARGETS, TARGET_IDS, publishTargetFor, MANIFEST_FILENAMES, hasProjectManifest, loadManifest, loadManifestWithPath, resolveConfig, SYNC_SNAPSHOT_MESSAGE, log, resolveActiveStyles, listProjectStyles, EXTENSION_MANIFEST_FILENAME, readExtensionMeta, extensionStyleList, extensionEntry, extensionCarries, pathEscapesFolder, assertExtensionContained, resolveExtension, loadPluginsWithCss, getChecks, getCheckById, resolveCheckSelectors, formatReport, ruleRemoteUrls, ruleRiskyProps, ruleSyntax, rulePageContainment, checkCss, inspectImage, runChecks, checkToolAvailability, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics, EXTENSIONS_DIR, RECOMMENDED_EXTENSIONS, BUILT_IN_STYLE_SET_IDS, sameExtension, listProjectExtensions, describeExtension, setExtensionEnabled, reorderExtensions, removeExtension, addExtension, listBuiltInStyleSets, addBuiltInStyleSet, validateProjectExtensions, readExtensionCss, slugifyProjectName, escapeYamlScalar, scaffoldProject, adoptFolder, EXTENSION_KINDS, RESERVED_PREFIX, resolveExtensionPrefix, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, listBuiltInTemplates, saveProjectAsTemplate, listCustomTemplates, importTemplateFromFolder, SNIPPETS_DIR, extractVariables, substituteVariables, listSnippets, readSnippet, saveSnippet, deleteSnippet, listMergedSnippets, readExtensionSnippet, importExtensionFromFile, importExtensionFromUrl, MAX_SEARCH_BYTES, SEARCH_KEYWORDS, searchNpmExtensions, setManifestFields, readManifestFields, setActiveStyles, AUTO_SNAPSHOT_DEFAULT_MINUTES, AUTO_SYNC_MIN_MINUTES, AUTO_SYNC_MAX_MINUTES, AUTO_SYNC_DEFAULT_MINUTES, AUTO_SYNC_PUSH_INTERVAL_MINUTES, autoSnapshotDelayMs, autoSyncDelayMs, isGitInternalPath, resolveGitHubClientId, GITHUB_HOST, GitHubAuthProvider, GDRIVE_HOST, resolveGoogleClientId, resolveGoogleClientSecret, GOOGLE_NOT_CONFIGURED_MESSAGE, requireGoogleClientCredentials, pkceChallengeFromVerifier, GoogleAuthProvider, revokeGoogleCredential, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listGitHubRepositories, listRepoBooks, listGitHubBranches, sanitizeCloneFolderName, cloneRepository, isSshRemoteUrl, testRemoteAccess, knownForgeTokenUrl, connectGenericHost, parseRemoteOrigin, forgeKindForHost, diagnoseProjectRemote, syncProject, refreshRemoteCopies, listPublishProviders, publishProviderFor, resolvePublishFormat, resolvePublishRequest, runPublish, connectPublishProvider, disconnectPublishCredential, PublishSelectionsStore, readPublishSettings, setPublishProviderConfig };