gutterpress 0.11.23-beta.2 → 0.11.23-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +12 -2
  2. package/dist/api/index.d.ts +5 -5
  3. package/dist/api/index.js +19 -7
  4. package/dist/{build-3e18wnqj.js → build-fq3mexhy.js} +9 -9
  5. package/dist/checks/asset/approved-fonts.d.ts +8 -0
  6. package/dist/checks/asset/extensions.d.ts +1 -1
  7. package/dist/checks/asset/index.d.ts +1 -0
  8. package/dist/{cli-88arpdke.js → cli-5zbdb6mt.js} +296 -65
  9. package/dist/{cli-tgnyvra3.js → cli-7mt0dftw.js} +35 -16
  10. package/dist/{cli-pnrararp.js → cli-ah93yyzb.js} +162 -55
  11. package/dist/{cli-v0evdpdf.js → cli-eymdsefg.js} +1 -1
  12. package/dist/{cli-9n9kg58f.js → cli-fh685nqs.js} +1 -1
  13. package/dist/{cli-pd2cje5b.js → cli-fsjre61x.js} +1 -1
  14. package/dist/{cli-x7gcdg6w.js → cli-q7t04gjt.js} +1 -1
  15. package/dist/{cli-0ep11b0q.js → cli-rybz2dfs.js} +1 -1
  16. package/dist/cli.js +12 -12
  17. package/dist/{doctor-2f4s9dyn.js → doctor-tg9ht1n3.js} +3 -3
  18. package/dist/{engine-c4pxz79g.js → engine-17v87vq5.js} +1 -1
  19. package/dist/{engine-cs5g2ez0.js → engine-y9fnarfa.js} +2 -2
  20. package/dist/{ext-70gv86v5.js → ext-esz03jz4.js} +27 -10
  21. package/dist/{extension-restore-chj5nx3t.js → extension-restore-91gy1e28.js} +3 -3
  22. package/dist/{extension-restore-pd87p8r2.js → extension-restore-q70wqah5.js} +5 -5
  23. package/dist/{index-80vg3ed6.js → index-67g8f7r4.js} +35 -16
  24. package/dist/{index-swfdgn2n.js → index-d9w3r89w.js} +1 -1
  25. package/dist/{index-ytjkvwy5.js → index-fntpr44x.js} +321 -66
  26. package/dist/{index-5x42amh8.js → index-g3te5ey1.js} +2 -1
  27. package/dist/{index-7j3hkwya.js → index-kw4tbthz.js} +1 -1
  28. package/dist/{index-2t1gdma7.js → index-santcs4q.js} +1 -1
  29. package/dist/{index-0k43evt0.js → index-z6vzj3s5.js} +186 -60
  30. package/dist/index.js +35 -8
  31. package/dist/lib/check-options.d.ts +70 -0
  32. package/dist/lib/extension-manager.d.ts +16 -1
  33. package/dist/lib/extension-scaffold.d.ts +15 -2
  34. package/dist/lib/extension-specifier.d.ts +8 -1
  35. package/dist/lib/manifest-config.d.ts +3 -1
  36. package/dist/lib/manifest-old-spellings.d.ts +32 -9
  37. package/dist/lib/markdown/math.d.ts +1 -1
  38. package/dist/lib/markdown/typography.d.ts +1 -0
  39. package/dist/lib/page-size.d.ts +12 -4
  40. package/dist/lib/plugin-vendor.d.ts +6 -0
  41. package/dist/lib/presets.d.ts +2 -2
  42. package/dist/lib/root-tokens.d.ts +2 -1
  43. package/dist/lib/style-resolver.d.ts +2 -1
  44. package/dist/lib/version-changes.d.ts +9 -3
  45. package/dist/{manifest.schema-0jgj0jt1.json → manifest.schema-5cm13vr3.json} +215 -5
  46. package/dist/{new-d61n5cn0.js → new-rmfyb7va.js} +22 -15
  47. package/dist/{plugins-0hhw6s17.js → plugins-gs21xz5s.js} +2 -2
  48. package/dist/{plugins-e0n46s6m.js → plugins-tqv1s16f.js} +4 -4
  49. package/dist/{preflight-fjayhjr5.js → preflight-bjyeeq0d.js} +9 -9
  50. package/dist/{preview-h815jrfb.js → preview-ke03fk5d.js} +9 -9
  51. package/dist/{publish-ft39zgma.js → publish-wpnz0qng.js} +9 -9
  52. package/dist/render.js +43 -11
  53. package/dist/schema/manifest.types.d.ts +45 -7
  54. package/dist/{source-provider-j1w7byeq.js → source-provider-3g3yrn1f.js} +2 -2
  55. package/dist/{source-provider-tjaf303m.js → source-provider-azg9ywhb.js} +2 -2
  56. package/dist/{validate-b201dbrb.js → validate-zcwykb43.js} +9 -9
  57. package/package.json +1 -1
  58. /package/dist/{cli-y28j019d.js → cli-1dha1nxk.js} +0 -0
@@ -24,12 +24,14 @@ import {
24
24
  resolvePort,
25
25
  resolveTargets,
26
26
  restoreForCommand,
27
+ rewriteOldThresholds,
27
28
  scalarString,
29
+ setCheckOption,
28
30
  uniqueExtensionId,
29
31
  validatePageMargin,
30
32
  withFetchTimeout,
31
33
  writeManifestDoc
32
- } from "./index-ytjkvwy5.js";
34
+ } from "./index-fntpr44x.js";
33
35
  import {
34
36
  EXTENSION_MANIFEST_FILENAME,
35
37
  GUTTERPRESS_CSS,
@@ -65,7 +67,7 @@ import {
65
67
  setLogLevel,
66
68
  slugify,
67
69
  warn
68
- } from "./index-80vg3ed6.js";
70
+ } from "./index-67g8f7r4.js";
69
71
  import {
70
72
  blackTextToGray
71
73
  } from "./index-ht1bcqdd.js";
@@ -76,7 +78,7 @@ import {
76
78
  getAssetPath,
77
79
  lastPageMode,
78
80
  resolvePage
79
- } from "./index-swfdgn2n.js";
81
+ } from "./index-d9w3r89w.js";
80
82
  import {
81
83
  BuildError,
82
84
  cssLength,
@@ -133,13 +135,13 @@ import {
133
135
  snapshotWorkingTreeUnlocked,
134
136
  startHistoryWalk,
135
137
  withRepoLock
136
- } from "./index-7j3hkwya.js";
138
+ } from "./index-kw4tbthz.js";
137
139
  import {
138
140
  EXTENSIONS_DIR,
139
141
  resolveVendoredPluginInstallRoot,
140
142
  toPosixPath,
141
143
  vendoredNpmPluginPackageDir
142
- } from "./index-5x42amh8.js";
144
+ } from "./index-g3te5ey1.js";
143
145
  import {
144
146
  detectProjectSource,
145
147
  repoSubPath,
@@ -284,6 +286,14 @@ ${TABLE_ALIGN_CSS.trim()}`),
284
286
  ${pageGeometry}`)
285
287
  ];
286
288
  }
289
+ function resolveOldFootnoteLinks(html, ids) {
290
+ if (ids.size === 0)
291
+ return html;
292
+ return html.replace(/ href=(["'])#(fn(?:ref)?\d+(?::\d+)?)\1/g, (link, quote, old) => {
293
+ const id = ids.get(old);
294
+ return id && !html.includes(` id="${old}"`) ? ` href=${quote}#${id}${quote}` : link;
295
+ });
296
+ }
287
297
  async function assembleBookHtml(opts) {
288
298
  const title = opts.title ?? "Document";
289
299
  const projectCss = opts.projectCss ?? "";
@@ -296,6 +306,7 @@ async function assembleBookHtml(opts) {
296
306
  const md = createMarkdownRenderer(opts.plugins, { language });
297
307
  let bodyContent = "";
298
308
  const imageRefs = new Set;
309
+ const oldFootnoteIds = new Map;
299
310
  for (const file of files) {
300
311
  const chapterId = canonicalChapterId(file);
301
312
  let content;
@@ -314,9 +325,14 @@ async function assembleBookHtml(opts) {
314
325
  }
315
326
  for (const ref of env.imageRefs ?? [])
316
327
  imageRefs.add(ref);
328
+ for (const [, kind, n] of rendered.matchAll(new RegExp(` id="(fn|fnref)-${env.docId}-(\\d+(?::\\d+)?)"`, "g"))) {
329
+ if (!oldFootnoteIds.has(`${kind}${n}`))
330
+ oldFootnoteIds.set(`${kind}${n}`, `${kind}-${env.docId}-${n}`);
331
+ }
317
332
  bodyContent += rendered + `
318
333
  `;
319
334
  }
335
+ bodyContent = resolveOldFootnoteLinks(bodyContent, oldFootnoteIds);
320
336
  if (opts.onImageRefs) {
321
337
  for (const ref of collectHtmlImageRefs(bodyContent))
322
338
  imageRefs.add(ref);
@@ -355,7 +371,13 @@ import { existsSync } from "node:fs";
355
371
  import { readdir } from "node:fs/promises";
356
372
  import path from "node:path";
357
373
  var STYLES_SUBDIR = "styles";
358
- var DEFAULT_STYLESHEET = "styles/book.css";
374
+ var FALLBACK_PRIORITY = [
375
+ "styles/book.css",
376
+ "css/print.css",
377
+ "css/index.css",
378
+ "css/style.css",
379
+ "css/main.css"
380
+ ];
359
381
  function relDisplay(projectDir, absPath) {
360
382
  return path.relative(projectDir, absPath).split(path.sep).join("/");
361
383
  }
@@ -393,8 +415,10 @@ async function resolveActiveStyles(projectDir, manifestStyles) {
393
415
  const manifest = configured.filter((s) => typeof s === "string" && s.trim().length > 0);
394
416
  if (manifest.length > 0)
395
417
  return manifest;
396
- if (existsSync(path.join(projectDir, DEFAULT_STYLESHEET)))
397
- return [DEFAULT_STYLESHEET];
418
+ for (const rel of FALLBACK_PRIORITY) {
419
+ if (existsSync(path.join(projectDir, rel)))
420
+ return [rel];
421
+ }
398
422
  const discovered = await discoverCssFiles(projectDir);
399
423
  if (discovered.length > 0) {
400
424
  const first = discovered.map((abs) => relDisplay(projectDir, abs)).sort((a, b) => a.localeCompare(b))[0];
@@ -4578,6 +4602,58 @@ var check30 = {
4578
4602
  };
4579
4603
  registerCheck(check30);
4580
4604
 
4605
+ // src/checks/asset/approved-fonts.ts
4606
+ var check31 = {
4607
+ id: "asset.font.approved-files",
4608
+ name: "Approved Font Files",
4609
+ description: "Checks font files against the approved file patterns",
4610
+ category: "asset",
4611
+ phase: "pre-build",
4612
+ async run(ctx) {
4613
+ const patterns = ctx.config.validate.assets.approvedFontFiles;
4614
+ if (!patterns || patterns.length === 0)
4615
+ return [];
4616
+ const { glob } = await import("glob");
4617
+ const dirs = ctx.assetDirs ?? [ctx.inputDir];
4618
+ const allFonts = [];
4619
+ for (const dir of dirs) {
4620
+ const matches = await glob(`**/*.{${FONT_EXTS2.join(",")}}`, {
4621
+ cwd: dir,
4622
+ absolute: true,
4623
+ ignore: [...ASSET_SCAN_IGNORE_GLOBS]
4624
+ });
4625
+ allFonts.push(...matches);
4626
+ }
4627
+ if (allFonts.length === 0)
4628
+ return [];
4629
+ const approvedFonts = new Set;
4630
+ for (const dir of dirs) {
4631
+ for (const pattern of patterns) {
4632
+ const matches = await glob(pattern, {
4633
+ cwd: dir,
4634
+ absolute: true,
4635
+ ignore: [...ASSET_SCAN_IGNORE_GLOBS]
4636
+ });
4637
+ for (const m of matches)
4638
+ approvedFonts.add(m);
4639
+ }
4640
+ }
4641
+ const results = [];
4642
+ for (const font of allFonts) {
4643
+ if (!approvedFonts.has(font)) {
4644
+ results.push({
4645
+ checkId: check31.id,
4646
+ severity: "warning",
4647
+ message: "Font file not in approved list",
4648
+ file: font
4649
+ });
4650
+ }
4651
+ }
4652
+ return results;
4653
+ }
4654
+ };
4655
+ registerCheck(check31);
4656
+
4581
4657
  // src/checks/asset/font-license.ts
4582
4658
  import { existsSync as existsSync6 } from "node:fs";
4583
4659
  import { resolve as resolve4 } from "node:path";
@@ -4591,7 +4667,7 @@ var LICENSE_NAMES = [
4591
4667
  "OFL-1.1.txt",
4592
4668
  "COPYING"
4593
4669
  ];
4594
- var check31 = {
4670
+ var check32 = {
4595
4671
  id: "asset.font.license",
4596
4672
  name: "Font License",
4597
4673
  description: "Checks for license files in font directories",
@@ -4616,7 +4692,7 @@ var check31 = {
4616
4692
  const hasLicense = LICENSE_NAMES.some((name) => existsSync6(resolve4(fontDir, name)));
4617
4693
  if (!hasLicense) {
4618
4694
  results.push({
4619
- checkId: check31.id,
4695
+ checkId: check32.id,
4620
4696
  severity: "warning",
4621
4697
  message: `No font license file found in directory`,
4622
4698
  file: fontDir
@@ -4626,10 +4702,10 @@ var check31 = {
4626
4702
  return results;
4627
4703
  }
4628
4704
  };
4629
- registerCheck(check31);
4705
+ registerCheck(check32);
4630
4706
 
4631
4707
  // src/checks/heuristic/text-density.ts
4632
- var check32 = {
4708
+ var check33 = {
4633
4709
  id: "heuristic.whitespace.text-density",
4634
4710
  name: "Text Density",
4635
4711
  description: "Checks characters-per-page ratio",
@@ -4658,7 +4734,7 @@ var check32 = {
4658
4734
  });
4659
4735
  if (lowPages.length > 0) {
4660
4736
  results.push({
4661
- checkId: check32.id,
4737
+ checkId: check33.id,
4662
4738
  severity: "info",
4663
4739
  message: `Low text density on pages: ${lowPages.join(", ")} (below ${range.min} chars)`,
4664
4740
  file: ctx.pdfPath
@@ -4666,7 +4742,7 @@ var check32 = {
4666
4742
  }
4667
4743
  if (highPages.length > 0) {
4668
4744
  results.push({
4669
- checkId: check32.id,
4745
+ checkId: check33.id,
4670
4746
  severity: "info",
4671
4747
  message: `High text density on pages: ${highPages.join(", ")} (above ${range.max} chars)`,
4672
4748
  file: ctx.pdfPath
@@ -4675,11 +4751,11 @@ var check32 = {
4675
4751
  return results;
4676
4752
  }
4677
4753
  };
4678
- registerCheck(check32);
4754
+ registerCheck(check33);
4679
4755
 
4680
4756
  // src/checks/heuristic/section-density.ts
4681
4757
  import { readFile as readFile19 } from "node:fs/promises";
4682
- var check33 = {
4758
+ var check34 = {
4683
4759
  id: "heuristic.chunking.section-density",
4684
4760
  name: "Section Density",
4685
4761
  description: "Checks heading/paragraph/callout density from source Markdown",
@@ -4705,7 +4781,7 @@ var check33 = {
4705
4781
  const line = lines[i];
4706
4782
  if (/^#{1,6}\s/.test(line)) {
4707
4783
  if (paragraphCount > maxParas) {
4708
- results.push(finding(check33.id, {
4784
+ results.push(finding(check34.id, {
4709
4785
  severity: "info",
4710
4786
  message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
4711
4787
  file,
@@ -4725,7 +4801,7 @@ var check33 = {
4725
4801
  }
4726
4802
  }
4727
4803
  if (paragraphCount > maxParas) {
4728
- results.push(finding(check33.id, {
4804
+ results.push(finding(check34.id, {
4729
4805
  severity: "info",
4730
4806
  message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
4731
4807
  file,
@@ -4733,7 +4809,7 @@ var check33 = {
4733
4809
  }));
4734
4810
  }
4735
4811
  } catch {
4736
- results.push(inspectionFailed(check33.id, `Could not read source file: ${file}`, {
4812
+ results.push(inspectionFailed(check34.id, `Could not read source file: ${file}`, {
4737
4813
  file
4738
4814
  }));
4739
4815
  }
@@ -4741,10 +4817,10 @@ var check33 = {
4741
4817
  return results;
4742
4818
  }
4743
4819
  };
4744
- registerCheck(check33);
4820
+ registerCheck(check34);
4745
4821
 
4746
4822
  // src/checks/heuristic/layer-count.ts
4747
- var check34 = {
4823
+ var check35 = {
4748
4824
  id: "heuristic.decoration.layer-count",
4749
4825
  name: "Layer Count",
4750
4826
  description: "Counts image objects per page",
@@ -4769,7 +4845,7 @@ var check34 = {
4769
4845
  heavyPages.sort((a, b) => a - b);
4770
4846
  return [
4771
4847
  {
4772
- checkId: check34.id,
4848
+ checkId: check35.id,
4773
4849
  severity: "info",
4774
4850
  message: `Pages with many image layers (>${maxLayers}): ${heavyPages.join(", ")}`,
4775
4851
  file: ctx.pdfPath
@@ -4779,10 +4855,10 @@ var check34 = {
4779
4855
  return [];
4780
4856
  }
4781
4857
  };
4782
- registerCheck(check34);
4858
+ registerCheck(check35);
4783
4859
 
4784
4860
  // src/checks/heuristic/placement-variance.ts
4785
- var check35 = {
4861
+ var check36 = {
4786
4862
  id: "heuristic.layout.placement-variance",
4787
4863
  name: "Placement Variance",
4788
4864
  description: "Analyzes text baseline coordinates for layout consistency",
@@ -4800,7 +4876,7 @@ var check35 = {
4800
4876
  const uniqueX = new Set(positions.map((p) => Math.round(p.x)));
4801
4877
  return [
4802
4878
  {
4803
- checkId: check35.id,
4879
+ checkId: check36.id,
4804
4880
  severity: "info",
4805
4881
  message: `Layout analysis: ${uniqueX.size} unique horizontal text positions across ${positions.length} text blocks.`,
4806
4882
  file: ctx.pdfPath
@@ -4808,7 +4884,7 @@ var check35 = {
4808
4884
  ];
4809
4885
  }
4810
4886
  };
4811
- registerCheck(check35);
4887
+ registerCheck(check36);
4812
4888
 
4813
4889
  // src/checks/runner.ts
4814
4890
  function getCheckSeverityOverride(checkId, config) {
@@ -4833,25 +4909,25 @@ async function runChecks(ctx, opts = {}) {
4833
4909
  }
4834
4910
  const release = retainPdfCache();
4835
4911
  try {
4836
- for (const check36 of checks2) {
4912
+ for (const check37 of checks2) {
4837
4913
  try {
4838
- const results = await check36.run(ctx);
4839
- const severityOverride = getCheckSeverityOverride(check36.id, ctx.config);
4914
+ const results = await check37.run(ctx);
4915
+ const severityOverride = getCheckSeverityOverride(check37.id, ctx.config);
4840
4916
  if (severityOverride) {
4841
4917
  for (const r of results) {
4842
4918
  r.severity = severityOverride;
4843
4919
  }
4844
4920
  }
4845
4921
  if (results.length === 0) {
4846
- passed.push(check36.id);
4922
+ passed.push(check37.id);
4847
4923
  } else {
4848
4924
  allResults.push(...results);
4849
4925
  }
4850
4926
  } catch (err) {
4851
4927
  allResults.push({
4852
- checkId: check36.id,
4928
+ checkId: check37.id,
4853
4929
  severity: "error",
4854
- message: `Check "${check36.id}" threw: ${err instanceof Error ? err.message : String(err)}`
4930
+ message: `Check "${check37.id}" threw: ${err instanceof Error ? err.message : String(err)}`
4855
4931
  });
4856
4932
  }
4857
4933
  }
@@ -4881,15 +4957,15 @@ async function runChecks(ctx, opts = {}) {
4881
4957
  async function checkToolAvailability(config, opts = {}) {
4882
4958
  const { checks: checks2 } = selectChecks(opts, config);
4883
4959
  const toolToChecks = new Map;
4884
- for (const check36 of checks2) {
4885
- if (!check36.requiredTools?.length)
4960
+ for (const check37 of checks2) {
4961
+ if (!check37.requiredTools?.length)
4886
4962
  continue;
4887
- for (const tool of check36.requiredTools) {
4963
+ for (const tool of check37.requiredTools) {
4888
4964
  const existing = toolToChecks.get(tool);
4889
4965
  if (existing) {
4890
- existing.push(check36.id);
4966
+ existing.push(check37.id);
4891
4967
  } else {
4892
- toolToChecks.set(tool, [check36.id]);
4968
+ toolToChecks.set(tool, [check37.id]);
4893
4969
  }
4894
4970
  }
4895
4971
  }
@@ -4905,11 +4981,11 @@ async function checkToolAvailability(config, opts = {}) {
4905
4981
  const missing = results.filter((r) => !r.found).map((r) => r.tool);
4906
4982
  const missingSet = new Set(missing);
4907
4983
  const skippedChecks = [];
4908
- for (const check36 of checks2) {
4909
- if (!check36.requiredTools?.length)
4984
+ for (const check37 of checks2) {
4985
+ if (!check37.requiredTools?.length)
4910
4986
  continue;
4911
- if (check36.requiredTools.some((t) => missingSet.has(t))) {
4912
- skippedChecks.push(check36.id);
4987
+ if (check37.requiredTools.some((t) => missingSet.has(t))) {
4988
+ skippedChecks.push(check37.id);
4913
4989
  }
4914
4990
  }
4915
4991
  return { available, missing, skippedChecks, toolToChecks };
@@ -5210,7 +5286,7 @@ async function executeValidation(args) {
5210
5286
  };
5211
5287
  if (args.fix) {
5212
5288
  const selected = selectChecks(runnerOptions, config).checks;
5213
- if (selected.some((check36) => check36.id === MARKDOWNLINT_CHECK_ID)) {
5289
+ if (selected.some((check37) => check37.id === MARKDOWNLINT_CHECK_ID)) {
5214
5290
  await applyMarkdownlintFixes(context);
5215
5291
  } else {
5216
5292
  log.warn(`--fix: ${MARKDOWNLINT_CHECK_ID} is not part of this run — no files were fixed.`);
@@ -5579,7 +5655,7 @@ class PdfOutput {
5579
5655
  const rawPdf = pdfxMode ? path7.join(stage, "raw.pdf") : path7.resolve(pdfFile);
5580
5656
  await fsp2.mkdir(path7.dirname(path7.resolve(pdfFile)), { recursive: true });
5581
5657
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
5582
- const { buildNativePdf } = await import("./engine-cs5g2ez0.js");
5658
+ const { buildNativePdf } = await import("./engine-y9fnarfa.js");
5583
5659
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
5584
5660
  title: config.title,
5585
5661
  author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
@@ -7125,11 +7201,13 @@ import { existsSync as existsSync8 } from "node:fs";
7125
7201
  import { readFile as readFile24 } from "node:fs/promises";
7126
7202
  import path13 from "node:path";
7127
7203
  import { isMap } from "yaml";
7204
+ var PAGE_SIZE_CHECK = "pdf.print.page-size";
7128
7205
  function writePageBounds(doc, page) {
7129
7206
  ensurePageMap(doc);
7130
7207
  doc.setIn(["page", "width"], page.width);
7131
7208
  doc.setIn(["page", "height"], page.height);
7132
- doc.deleteIn(["page", "tolerance"]);
7209
+ if (page.tolerance !== undefined)
7210
+ setCheckOption(doc, PAGE_SIZE_CHECK, "tolerance", page.tolerance);
7133
7211
  }
7134
7212
  function deletePageBounds(doc) {
7135
7213
  const block = doc.get("page", true);
@@ -7137,7 +7215,7 @@ function deletePageBounds(doc) {
7137
7215
  doc.delete("page");
7138
7216
  return;
7139
7217
  }
7140
- for (const key of ["width", "height", "tolerance"])
7218
+ for (const key of ["width", "height"])
7141
7219
  block.delete(key);
7142
7220
  if (block.items.length === 0)
7143
7221
  doc.delete("page");
@@ -7185,7 +7263,7 @@ function manifestGeometry(doc) {
7185
7263
  const base = preset ? PRESETS[preset].page : null;
7186
7264
  const width = numberAt(doc, ["page", "width"]) ?? base?.width;
7187
7265
  const height = numberAt(doc, ["page", "height"]) ?? base?.height;
7188
- const tolerance = base?.tolerance ?? 0.5;
7266
+ const tolerance = numberAt(doc, ["checks", PAGE_SIZE_CHECK, "tolerance"]) ?? numberAt(doc, ["page", "tolerance"]) ?? base?.tolerance ?? 0.5;
7189
7267
  const bounds = width !== undefined && height !== undefined ? { width, height, tolerance } : null;
7190
7268
  const presetSizeOverridden = base !== null && (numberAt(doc, ["page", "width"]) !== undefined || numberAt(doc, ["page", "height"]) !== undefined);
7191
7269
  const at = (edge) => doc.getIn(["page", "margin", edge]);
@@ -7233,8 +7311,10 @@ async function readPageSetup(projectDir) {
7233
7311
  const { doc } = await loadManifestDoc(projectDir);
7234
7312
  return setupOf(projectDir, doc);
7235
7313
  }
7236
- async function setPageSetup(projectDir, change) {
7314
+ async function setPageSetup(projectDir, given) {
7315
+ const change = toPageSetupChange(given);
7237
7316
  const { doc, file } = await loadManifestDoc(projectDir);
7317
+ rewriteOldThresholds(doc);
7238
7318
  const size2 = change.size ? pageSizeForChoice(change.size) : null;
7239
7319
  let margins;
7240
7320
  if (change.margins) {
@@ -7257,6 +7337,16 @@ async function setPageSetup(projectDir, change) {
7257
7337
  await writeManifestDoc(file, doc);
7258
7338
  return setupOf(projectDir, doc);
7259
7339
  }
7340
+ function toPageSetupChange(change) {
7341
+ const keys = typeof change === "object" && change !== null ? Object.keys(change) : null;
7342
+ if (keys?.includes("preset") && !keys.includes("size") && !keys.includes("margins")) {
7343
+ return { size: change };
7344
+ }
7345
+ if (!keys || keys.some((k) => k !== "size" && k !== "margins")) {
7346
+ throw new UsageError(`setPageSetup takes { size?: { preset, page? }, margins? } (or 0.11.22's { preset, page? }), got ${JSON.stringify(change)}.`);
7347
+ }
7348
+ return change;
7349
+ }
7260
7350
 
7261
7351
  // src/lib/project-scaffold.ts
7262
7352
  function starterOverridesCss() {
@@ -7305,6 +7395,9 @@ function requirePreset(preset, customPage) {
7305
7395
  } else if (customPage && (!isPositivePoints(customPage.width) || !isPositivePoints(customPage.height))) {
7306
7396
  throw new CreateProjectErrorImpl("custom-page-required", "Page overrides need a positive width and height in points (72pt = 1in).");
7307
7397
  }
7398
+ if (customPage?.tolerance !== undefined && !isPositivePoints(customPage.tolerance)) {
7399
+ throw new CreateProjectErrorImpl("custom-page-required", "Page tolerance must be a positive number of points.");
7400
+ }
7308
7401
  return preset;
7309
7402
  }
7310
7403
  function resolveScaffoldTargets(requested, preset) {
@@ -7408,7 +7501,7 @@ async function scaffoldProject(options) {
7408
7501
  let versionHistoryError;
7409
7502
  if (requested === "local-git") {
7410
7503
  try {
7411
- const { providerFor } = await import("./source-provider-tjaf303m.js");
7504
+ const { providerFor } = await import("./source-provider-azg9ywhb.js");
7412
7505
  const provider = providerFor({ type: "local-folder", path: projectDir });
7413
7506
  await provider.initVersionHistory({
7414
7507
  projectDir,
@@ -7499,7 +7592,7 @@ styles:
7499
7592
  let versionHistoryError;
7500
7593
  if (requested === "local-git") {
7501
7594
  try {
7502
- const { providerFor } = await import("./source-provider-tjaf303m.js");
7595
+ const { providerFor } = await import("./source-provider-azg9ywhb.js");
7503
7596
  const provider = providerFor({ type: "local-folder", path: dir });
7504
7597
  await provider.initVersionHistory({
7505
7598
  projectDir: dir,
@@ -7548,6 +7641,12 @@ import { access as access2, mkdir as mkdir6, readFile as readFile26, writeFile a
7548
7641
  import { constants as FS2 } from "node:fs";
7549
7642
  import path15 from "node:path";
7550
7643
  var EXTENSION_KINDS = ["plugin", "look"];
7644
+ var EXTENSION_KIND_ALIASES = { theme: "look" };
7645
+ function extensionKindFor(word) {
7646
+ if (EXTENSION_KINDS.includes(word))
7647
+ return word;
7648
+ return Object.hasOwn(EXTENSION_KIND_ALIASES, word) ? EXTENSION_KIND_ALIASES[word] : undefined;
7649
+ }
7551
7650
  var RESERVED_PREFIX = "gp-";
7552
7651
  var TEMPLATE_FILES = {
7553
7652
  plugin: [
@@ -7610,9 +7709,9 @@ function escapeJsonScalar(value) {
7610
7709
  return JSON.stringify(value).slice(1, -1);
7611
7710
  }
7612
7711
  async function scaffoldExtension(options) {
7613
- const kind = options.kind;
7614
- if (kind !== "plugin" && kind !== "look") {
7615
- throw new ExtensionScaffoldError("invalid-name", `Unknown extension kind "${String(kind)}". Choose one of: ${EXTENSION_KINDS.join(", ")}.`);
7712
+ const kind = extensionKindFor(String(options.kind));
7713
+ if (!kind) {
7714
+ throw new ExtensionScaffoldError("invalid-name", `Unknown extension kind "${String(options.kind)}". Choose one of: ${EXTENSION_KINDS.join(", ")}.`);
7616
7715
  }
7617
7716
  const name = (options.name ?? "").trim();
7618
7717
  if (!name) {
@@ -8580,6 +8679,7 @@ function hasKey(obj, key) {
8580
8679
  }
8581
8680
  async function setManifestFields(projectDir, updates) {
8582
8681
  const { doc, file } = await loadManifestDoc(projectDir);
8682
+ rewriteOldThresholds(doc);
8583
8683
  if (hasKey(updates, "title")) {
8584
8684
  if (updates.title === undefined || updates.title === "") {
8585
8685
  doc.delete("title");
@@ -9156,8 +9256,9 @@ function changeHint(filepath, before, after) {
9156
9256
  return count > 0 ? `${plural(count, unit)} changed` : "changed";
9157
9257
  }
9158
9258
  async function listVersionChanges(projectDir, oid) {
9159
- const dir = await repoDirFor(projectDir);
9160
- const cache2 = {};
9259
+ return changesOf(await repoDirFor(projectDir), {}, oid);
9260
+ }
9261
+ async function changesOf(dir, cache2, oid) {
9161
9262
  const parent = (await git3.readCommit({ fs: gitFs, dir, cache: cache2, oid })).commit.parent[0] ?? null;
9162
9263
  const found = [];
9163
9264
  await git3.walk({
@@ -9355,8 +9456,12 @@ async function listOnlineVersions(options) {
9355
9456
  const local = await resolveOrNull(dir, branch);
9356
9457
  if (!tip || !local)
9357
9458
  return { entries: [] };
9358
- const entries = await commitsAhead(dir, tip, local, cache2);
9359
- return { entries: entries.map((entry) => ({ ...entry, backedUp: true })) };
9459
+ const entries = [];
9460
+ for (const entry of await commitsAhead(dir, tip, local, cache2)) {
9461
+ const { files, more } = await changesOf(dir, cache2, entry.id);
9462
+ entries.push({ ...entry, backedUp: true, changes: files, moreChanges: more });
9463
+ }
9464
+ return { entries };
9360
9465
  } catch (e) {
9361
9466
  const message = e?.message ?? "";
9362
9467
  if (message === MSG_NO_REMOTE || message === MSG_SSH_REMOTE)
@@ -12805,7 +12910,7 @@ async function resolvePublishProvider(id, book) {
12805
12910
  const ext = await bookExtensions(book);
12806
12911
  const npmEntry = ext.extensions.some((c) => !c.path && c.name === id);
12807
12912
  if (npmEntry) {
12808
- const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-chj5nx3t.js");
12913
+ const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-91gy1e28.js");
12809
12914
  await restoreForCommand2(book.projectDir, { manifestPath: book.manifestPath, failFast: true });
12810
12915
  }
12811
12916
  const publishers = await discover(ext);
@@ -12843,7 +12948,7 @@ function infoFor(p) {
12843
12948
  }
12844
12949
  function pluginProvider(p) {
12845
12950
  let loading;
12846
- const load = () => loading ??= import("./plugins-0hhw6s17.js").then((m) => m.loadPublishFunction(p));
12951
+ const load = () => loading ??= import("./plugins-gs21xz5s.js").then((m) => m.loadPublishFunction(p));
12847
12952
  return {
12848
12953
  info: infoFor(p),
12849
12954
  async authenticate() {
@@ -13143,7 +13248,7 @@ class PublishSelectionsStore {
13143
13248
  return {
13144
13249
  version: 1,
13145
13250
  global: parsed.global ?? {},
13146
- projects: parsed.projects ?? {}
13251
+ projects: readProjects(parsed.projects)
13147
13252
  };
13148
13253
  }
13149
13254
  } catch {}
@@ -13229,6 +13334,27 @@ class PublishSelectionsStore {
13229
13334
  });
13230
13335
  }
13231
13336
  }
13337
+ function readProjects(projects) {
13338
+ const out = {};
13339
+ if (!projects || typeof projects !== "object")
13340
+ return out;
13341
+ for (const [book, providers] of Object.entries(projects)) {
13342
+ if (!providers || typeof providers !== "object")
13343
+ continue;
13344
+ const values = {};
13345
+ for (const [provider, value] of Object.entries(providers)) {
13346
+ if (typeof value === "string") {
13347
+ if (value.trim())
13348
+ values[provider] = { credential: value };
13349
+ } else if (value && typeof value === "object") {
13350
+ values[provider] = value;
13351
+ }
13352
+ }
13353
+ if (Object.keys(values).length > 0)
13354
+ out[book] = values;
13355
+ }
13356
+ return out;
13357
+ }
13232
13358
  function normalizeProjectKey(projectDir) {
13233
13359
  return projectDir.replace(/[\\/]+$/, "");
13234
13360
  }
@@ -13314,4 +13440,4 @@ async function savePublishSettings(projectDir, providerId, values, selections) {
13314
13440
  await setPublishProviderConfig(projectDir, providerId, changes);
13315
13441
  return readPublishSettings(projectDir, selections);
13316
13442
  }
13317
- export { SYNC_SNAPSHOT_MESSAGE, assembleCssChunks, relDisplay, resolveActiveStyles, listProjectStyles, getChecks, getCheckById, resolveCheckSelectors, formatReport, ruleRemoteUrls, ruleRiskyProps, ruleSyntax, checkCss, inspectImage, runChecks, checkToolAvailability, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics, readPageSetup, setPageSetup, slugifyProjectName, escapeYamlScalar, scaffoldProject, adoptFolder, EXTENSION_KINDS, RESERVED_PREFIX, resolveExtensionPrefix, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, listBuiltInTemplates, saveProjectAsTemplate, listCustomTemplates, importTemplateFromFolder, SNIPPETS_DIR, extractVariables, substituteVariables, listSnippets, saveSnippet, deleteSnippet, listMergedSnippets, listMarkerComponents, listLocationVariants, importExtensionFromFile, importExtensionFromUrl, MAX_SEARCH_BYTES, SEARCH_KEYWORDS, searchNpmExtensions, setManifestFields, readManifestFields, setActiveStyles, VERSION_CHANGES_SHOWN, listVersionChanges, describeVersions, listOnlineVersions, compareVersionFile, exportVersionTree, 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, syncProject, refreshRemoteCopies, checkRemoteUpdates, isValidRepositoryName, setUpOnlineBackup, sanitizeCloneFolderName, cloneRepository, isSshRemoteUrl, testRemoteAccess, knownForgeTokenUrl, connectGenericHost, parseRemoteOrigin, forgeKindForHost, diagnoseProjectRemote, renameRevision, deleteRevision, REPAIR_SNAPSHOT_MESSAGE, repairOnlineBackup, scorchedEarth, listPublishProviders, publishProviderFor, listBookPublishProviders, resolvePublishProvider, resolvePublishFormat, resolvePublishRequest, runPublish, connectPublishProvider, disconnectPublishCredential, PublishSelectionsStore, readPublishSettings, setPublishProviderConfig, savePublishSettings };
13443
+ export { SYNC_SNAPSHOT_MESSAGE, assembleCssChunks, relDisplay, resolveActiveStyles, listProjectStyles, getChecks, getCheckById, resolveCheckSelectors, formatReport, ruleRemoteUrls, ruleRiskyProps, ruleSyntax, checkCss, inspectImage, runChecks, checkToolAvailability, reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, defaultConfigDir, FileTokenStore, extractUrlCredential, getSystemDiagnostics, readPageSetup, setPageSetup, slugifyProjectName, escapeYamlScalar, scaffoldProject, adoptFolder, EXTENSION_KINDS, EXTENSION_KIND_ALIASES, extensionKindFor, RESERVED_PREFIX, resolveExtensionPrefix, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, listBuiltInTemplates, saveProjectAsTemplate, listCustomTemplates, importTemplateFromFolder, SNIPPETS_DIR, extractVariables, substituteVariables, listSnippets, saveSnippet, deleteSnippet, listMergedSnippets, listMarkerComponents, listLocationVariants, importExtensionFromFile, importExtensionFromUrl, MAX_SEARCH_BYTES, SEARCH_KEYWORDS, searchNpmExtensions, setManifestFields, readManifestFields, setActiveStyles, VERSION_CHANGES_SHOWN, listVersionChanges, describeVersions, listOnlineVersions, compareVersionFile, exportVersionTree, 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, syncProject, refreshRemoteCopies, checkRemoteUpdates, isValidRepositoryName, setUpOnlineBackup, sanitizeCloneFolderName, cloneRepository, isSshRemoteUrl, testRemoteAccess, knownForgeTokenUrl, connectGenericHost, parseRemoteOrigin, forgeKindForHost, diagnoseProjectRemote, renameRevision, deleteRevision, REPAIR_SNAPSHOT_MESSAGE, repairOnlineBackup, scorchedEarth, listPublishProviders, publishProviderFor, listBookPublishProviders, resolvePublishProvider, resolvePublishFormat, resolvePublishRequest, runPublish, connectPublishProvider, disconnectPublishCredential, PublishSelectionsStore, readPublishSettings, setPublishProviderConfig, savePublishSettings };