gutterpress 0.11.23-alpha.1 → 0.11.23-alpha.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 (82) hide show
  1. package/README.md +27 -29
  2. package/dist/{README-8ef336pp.md → README-8db7btxb.md} +13 -19
  3. package/dist/api/index.d.ts +5 -5
  4. package/dist/api/index.js +16 -22
  5. package/dist/{build-09cd1n7s.js → build-m78jcpf7.js} +9 -10
  6. package/dist/{cli-5hkmp2wy.js → cli-1h17ktsg.js} +125 -187
  7. package/dist/{cli-nr6j6300.js → cli-5jzyw06s.js} +1 -1
  8. package/dist/{cli-habkc5ng.js → cli-a35w7wzg.js} +5 -4
  9. package/dist/{cli-dd115fa8.js → cli-h4x81x97.js} +152 -124
  10. package/dist/{cli-ccp7sxz3.js → cli-n2tsxqpn.js} +1 -1
  11. package/dist/{cli-b0vyjvmt.js → cli-s6djx4ma.js} +1 -1
  12. package/dist/{cli-h17e3mtz.js → cli-t8be9yeb.js} +380 -16
  13. package/dist/{cli-dtckwda1.js → cli-xsrffqzt.js} +192 -10
  14. package/dist/{index-r7jcsk6h.js → cli-y28j019d.js} +19 -10
  15. package/dist/cli.js +12 -12
  16. package/dist/{doctor-nddspx4n.js → doctor-j71jqce3.js} +3 -3
  17. package/dist/engine/shared/gcpm-extract.d.ts +8 -0
  18. package/dist/engine/shared/print-area.d.ts +16 -4
  19. package/dist/{engine-yjzknt0g.js → engine-1r6q80tq.js} +3 -3
  20. package/dist/{engine-892swzzc.js → engine-m4y10shc.js} +1 -2
  21. package/dist/{ext-zjpen4yx.js → ext-fq2hg9va.js} +18 -33
  22. package/dist/{extension-restore-jvs60x9b.js → extension-restore-9dh7c4tp.js} +4 -4
  23. package/dist/{extension-restore-w8xt4kbq.js → extension-restore-tmxtzkm0.js} +5 -6
  24. package/dist/{gutterpress-viewer-701vf4qp.js → gutterpress-viewer-mafsby5k.js} +9 -2
  25. package/dist/{index-2jpk25en.js → index-0wee4408.js} +380 -16
  26. package/dist/index-46ycxe6r.js +18 -0
  27. package/dist/{cli-h3phdstf.js → index-5x42amh8.js} +19 -10
  28. package/dist/{index-m4hhzg3c.js → index-7pck1q9c.js} +174 -142
  29. package/dist/{index-93pqkvty.js → index-h6yk5tjx.js} +5 -4
  30. package/dist/{index-apc8w9w8.js → index-nedd07bk.js} +187 -2
  31. package/dist/{index-0w2azsk1.js → index-nvmf22rt.js} +2 -4
  32. package/dist/{index-zrhyb967.js → index-prqvz3xm.js} +510 -587
  33. package/dist/index.js +17 -23
  34. package/dist/lib/extension-manager.d.ts +24 -50
  35. package/dist/lib/extension-manifest.d.ts +1 -13
  36. package/dist/lib/extension-scaffold.d.ts +3 -3
  37. package/dist/lib/extension-specifier.d.ts +23 -6
  38. package/dist/lib/manifest.d.ts +15 -1
  39. package/dist/lib/markdown/assemble.d.ts +4 -3
  40. package/dist/lib/markdown/math.d.ts +1 -1
  41. package/dist/lib/npm-plugin-installer.d.ts +1 -1
  42. package/dist/lib/page-size.d.ts +34 -27
  43. package/dist/lib/plugin-vendor.d.ts +11 -3
  44. package/dist/lib/printsafe.d.ts +1 -0
  45. package/dist/lib/project-gitignore.d.ts +2 -2
  46. package/dist/lib/project-scaffold.d.ts +5 -7
  47. package/dist/lib/project-templates.d.ts +9 -3
  48. package/dist/lib/snippets.d.ts +2 -1
  49. package/dist/lib/style-resolver.d.ts +1 -2
  50. package/dist/manifest-8afhrk30.yaml +19 -0
  51. package/dist/manifest-d4f9q79e.yaml +23 -0
  52. package/dist/manifest-gf13sjp8.yaml +27 -0
  53. package/dist/manifest-my7mdv8j.yaml +23 -0
  54. package/dist/{manifest.schema-9aeaered.json → manifest.schema-650pe0d1.json} +17 -5
  55. package/dist/{new-xhq8wczn.js → new-s4zcaepg.js} +22 -21
  56. package/dist/{package-aenwjew3.json → package-awwkt7sa.json} +0 -1
  57. package/dist/{page-rules-nsj3aw42.css → page-rules-fj09xct5.css} +12 -40
  58. package/dist/{plugin.test.js-xgxrd8hf.tpl → plugin.test.js-gxzqqfdh.tpl} +0 -1
  59. package/dist/{plugins-9en8m9y0.js → plugins-4vaf27n9.js} +4 -4
  60. package/dist/{plugins-gf0gkjmv.js → plugins-80emnf31.js} +2 -2
  61. package/dist/{preflight-negnxg7b.js → preflight-c7w1xdn3.js} +9 -10
  62. package/dist/{preview-cep2s9cg.js → preview-mzytcwyk.js} +9 -10
  63. package/dist/{publish-xery6qc6.js → publish-fez14ad4.js} +9 -10
  64. package/dist/render.js +24 -561
  65. package/dist/schema/manifest.types.d.ts +22 -0
  66. package/dist/{source-provider-qbfknhyy.js → source-provider-98k5deda.js} +2 -2
  67. package/dist/{source-provider-2r74a7wp.js → source-provider-knmcam50.js} +2 -2
  68. package/dist/{tokens-7984461t.css → tokens-ye64p899.css} +5 -12
  69. package/dist/{validate-3d0sgf4g.js → validate-p2chr6hr.js} +9 -10
  70. package/package.json +1 -1
  71. package/dist/cli-fe43evmf.js +0 -212
  72. package/dist/index-dsvk7q6s.js +0 -229
  73. package/dist/manifest-8f10dr4f.yaml +0 -17
  74. package/dist/manifest-n1gh3qw5.yaml +0 -9
  75. package/dist/package-97gm31sg.json +0 -10
  76. package/dist/package-gag6ykwn.json +0 -10
  77. package/dist/package-nrhkwf2m.json +0 -10
  78. package/dist/package-zttkgydq.json +0 -10
  79. package/dist/theme-9c58td2d.css +0 -76
  80. package/dist/theme-h5recz6c.css +0 -61
  81. package/dist/theme-j2bagrfx.css +0 -59
  82. package/dist/theme-nn6d53zy.css +0 -71
@@ -1,16 +1,17 @@
1
1
  import {
2
2
  PACKAGE_VERSION,
3
3
  debug
4
- } from "./cli-b0vyjvmt.js";
4
+ } from "./cli-s6djx4ma.js";
5
5
  import {
6
6
  isExactNpmVersion,
7
7
  isValidNpmPackageName,
8
8
  packageResolutionTargets,
9
+ parseNpmPluginSpec,
9
10
  resolvePackageEntry,
10
11
  resolveVendoredPluginInstallRoot,
11
12
  safePackageTarget,
12
13
  vendoredNpmPluginPackageDir
13
- } from "./cli-h3phdstf.js";
14
+ } from "./cli-y28j019d.js";
14
15
 
15
16
  // src/lib/markdown/plugins.ts
16
17
  import { existsSync as existsSync2, readFileSync, statSync, unlinkSync } from "node:fs";
@@ -19,6 +20,366 @@ import { isBuiltin } from "node:module";
19
20
  import { resolve as resolve2, join, dirname, basename, extname, isAbsolute, relative, sep } from "node:path";
20
21
  import { pathToFileURL } from "node:url";
21
22
 
23
+ // src/assets/themes/clean-book/theme.css
24
+ var theme_default = `/* =============================================================================
25
+ Clean Book — gutterpress built-in theme (theme.css)
26
+ A calm, classic long-form book look. Change the :root tokens from the book's own stylesheet.
27
+ The page SIZE comes from the manifest (Setup > Details), so it is deliberately not set here.
28
+ ============================================================================= */
29
+
30
+ :root {
31
+ --color-ink: #1a1a1a; /* body text */
32
+ --color-ink-muted: #555555; /* captions, secondary text */
33
+ --color-accent: #2b4c7e; /* headings, links */
34
+ --color-paper: #ffffff; /* page background */
35
+ --color-rule: #d9d9d9; /* borders, rules */
36
+
37
+ --font-body: "Georgia", "Times New Roman", serif;
38
+ --font-display: "Georgia", "Times New Roman", serif;
39
+ --font-mono: "Menlo", "Consolas", monospace;
40
+
41
+ --fs-body: 11pt;
42
+ --fs-h1: 2.1rem;
43
+ --fs-h2: 1.5rem;
44
+ --fs-h3: 1.2rem;
45
+ --leading: 1.55;
46
+
47
+ }
48
+
49
+ body {
50
+ color: var(--color-ink);
51
+ background: var(--color-paper);
52
+ font-family: var(--font-body);
53
+ line-height: var(--leading);
54
+ font-size: var(--fs-body);
55
+ }
56
+
57
+ h1, h2, h3 {
58
+ font-family: var(--font-display);
59
+ color: var(--color-accent);
60
+ line-height: 1.2;
61
+ font-weight: 600;
62
+ }
63
+ h1 { font-size: var(--fs-h1); margin: 0 0 0.6em; }
64
+ h2 { font-size: var(--fs-h2); margin: 1.4em 0 0.4em; }
65
+ h3 { font-size: var(--fs-h3); margin: 1.2em 0 0.3em; }
66
+
67
+ p { margin: 0 0 0.8em; text-align: justify; hyphens: auto; }
68
+
69
+ a { color: var(--color-accent); text-decoration: none; }
70
+
71
+ blockquote {
72
+ margin: 1em 0; padding: 0.2em 0 0.2em 1em;
73
+ border-left: 3px solid var(--color-rule);
74
+ color: var(--color-ink-muted); font-style: italic;
75
+ }
76
+
77
+ code, pre { font-family: var(--font-mono); font-size: 0.9em; }
78
+
79
+ hr { border: 0; border-top: 1px solid var(--color-rule); margin: 1.5em 0; }
80
+ `;
81
+
82
+ // src/assets/themes/zine/theme.css
83
+ var theme_default2 = `/* =============================================================================
84
+ Zine — gutterpress built-in theme (theme.css)
85
+ High-contrast, punchy, photocopier-friendly. Change the :root tokens from the book's own stylesheet.
86
+ The page SIZE comes from the manifest (Setup > Details), so it is deliberately not set here.
87
+ ============================================================================= */
88
+
89
+ :root {
90
+ --color-ink: #000000; /* body text */
91
+ --color-ink-muted: #333333; /* secondary text */
92
+ --color-accent: #000000; /* headings (mono, high ink) */
93
+ --color-paper: #ffffff; /* page background */
94
+ --color-rule: #000000; /* heavy borders, rules */
95
+
96
+ --font-body: "Helvetica Neue", "Arial", sans-serif;
97
+ --font-display: "Impact", "Haettenschweiler", "Arial Black", sans-serif;
98
+ --font-mono: "Courier New", monospace;
99
+
100
+ --fs-body: 10pt;
101
+ --fs-h1: 2.8rem;
102
+ --fs-h2: 1.8rem;
103
+ --fs-h3: 1.3rem;
104
+ --leading: 1.4;
105
+
106
+ }
107
+
108
+ body {
109
+ color: var(--color-ink);
110
+ background: var(--color-paper);
111
+ font-family: var(--font-body);
112
+ line-height: var(--leading);
113
+ font-size: var(--fs-body);
114
+ }
115
+
116
+ h1, h2, h3 {
117
+ font-family: var(--font-display);
118
+ color: var(--color-accent);
119
+ text-transform: uppercase;
120
+ letter-spacing: -0.01em;
121
+ line-height: 0.95;
122
+ font-weight: 900;
123
+ }
124
+ h1 { font-size: var(--fs-h1); margin: 0 0 0.4em; }
125
+ h2 { font-size: var(--fs-h2); margin: 1.1em 0 0.3em; }
126
+ h3 { font-size: var(--fs-h3); margin: 1em 0 0.25em; }
127
+
128
+ p { margin: 0 0 0.6em; }
129
+
130
+ a { color: var(--color-accent); text-decoration: underline; font-weight: 700; }
131
+
132
+ blockquote {
133
+ margin: 1em 0; padding: 0.5em 0.8em;
134
+ border: 2px solid var(--color-rule);
135
+ font-weight: 700;
136
+ }
137
+
138
+ hr { border: 0; border-top: 3px solid var(--color-rule); margin: 1em 0; }
139
+
140
+ code, pre { font-family: var(--font-mono); font-size: 0.95em; }
141
+ `;
142
+
143
+ // src/assets/themes/technical-doc/theme.css
144
+ var theme_default3 = `/* =============================================================================
145
+ Technical Document — gutterpress built-in theme (theme.css)
146
+ Clean sans-serif manual look with clear hierarchy. Change the :root tokens from the book's own stylesheet.
147
+ The page SIZE comes from the manifest (Setup > Details), so it is deliberately not set here.
148
+ ============================================================================= */
149
+
150
+ :root {
151
+ --color-ink: #1c1e21; /* body text */
152
+ --color-ink-muted: #5a5f66; /* captions, secondary text */
153
+ --color-accent: #0b5fff; /* headings, links */
154
+ --color-paper: #ffffff; /* page background */
155
+ /* @label Note and code background */
156
+ --color-tint: #f3f5f9; /* code / note fill */
157
+ --color-rule: #d6dae0; /* borders, rules */
158
+
159
+ --font-body: "Helvetica Neue", "Segoe UI", Arial, sans-serif;
160
+ --font-display: "Helvetica Neue", "Segoe UI", Arial, sans-serif;
161
+ --font-mono: "SFMono-Regular", "Consolas", "Menlo", monospace;
162
+
163
+ --fs-body: 10.5pt;
164
+ --fs-h1: 2.0rem;
165
+ --fs-h2: 1.45rem;
166
+ --fs-h3: 1.15rem;
167
+ --leading: 1.5;
168
+
169
+ }
170
+
171
+ body {
172
+ color: var(--color-ink);
173
+ background: var(--color-paper);
174
+ font-family: var(--font-body);
175
+ line-height: var(--leading);
176
+ font-size: var(--fs-body);
177
+ }
178
+
179
+ h1, h2, h3 {
180
+ font-family: var(--font-display);
181
+ color: var(--color-ink);
182
+ font-weight: 600;
183
+ line-height: 1.25;
184
+ }
185
+ h1 { font-size: var(--fs-h1); margin: 0 0 0.5em; color: var(--color-accent); }
186
+ h2 { font-size: var(--fs-h2); margin: 1.4em 0 0.4em; border-bottom: 1px solid var(--color-rule); padding-bottom: 0.15em; }
187
+ h3 { font-size: var(--fs-h3); margin: 1.2em 0 0.3em; }
188
+
189
+ p { margin: 0 0 0.7em; }
190
+
191
+ a { color: var(--color-accent); text-decoration: none; }
192
+
193
+ code {
194
+ font-family: var(--font-mono); font-size: 0.88em;
195
+ background: var(--color-tint); padding: 0.1em 0.35em; border-radius: 3px;
196
+ }
197
+ pre {
198
+ font-family: var(--font-mono); font-size: 0.85em;
199
+ background: var(--color-tint); border: 1px solid var(--color-rule);
200
+ border-radius: 4px; padding: 0.7em 0.9em; overflow: auto;
201
+ }
202
+ pre code { background: none; padding: 0; }
203
+
204
+ table { width: 100%; border-collapse: collapse; margin: 1em 0; font-size: 0.95em; }
205
+ th, td { border: 1px solid var(--color-rule); padding: 0.4em 0.6em; text-align: left; }
206
+ th { background: var(--color-tint); font-weight: 600; }
207
+
208
+ blockquote {
209
+ margin: 1em 0; padding: 0.5em 0.9em;
210
+ background: var(--color-tint); border-left: 3px solid var(--color-accent);
211
+ color: var(--color-ink-muted);
212
+ }
213
+ `;
214
+
215
+ // src/assets/themes/academic/theme.css
216
+ var theme_default4 = `/* =============================================================================
217
+ Academic — gutterpress built-in theme (theme.css)
218
+ A journal-article look in the spirit of LaTeX's \`article\` class: a serif
219
+ text face, justified and hyphenated text, 1in margins, a centred page
220
+ number, and the parts of a paper styled by the @section they sit in.
221
+ Change the :root tokens from the book's own stylesheet. The page SIZE comes from the manifest
222
+ (\`page:\` — US Letter or A4), so it is deliberately not set here.
223
+ ============================================================================= */
224
+
225
+ :root {
226
+ --color-ink: #111111; /* body text */
227
+ --color-ink-muted: #555555; /* captions, secondary text */
228
+ --color-accent: #111111; /* headings, links */
229
+ --color-paper: #ffffff; /* page background */
230
+ --color-rule: #111111; /* table rules */
231
+
232
+ --font-body: "Latin Modern Roman", "CMU Serif", "STIX Two Text", "Times New Roman", "Liberation Serif", serif;
233
+ --font-display: "Latin Modern Roman", "CMU Serif", "STIX Two Text", "Times New Roman", "Liberation Serif", serif;
234
+ --font-mono: "Latin Modern Mono", "Menlo", "Consolas", monospace;
235
+
236
+ --fs-body: 10.5pt;
237
+ --fs-h1: 1.65em;
238
+ --fs-h2: 1.2em;
239
+ --fs-h3: 1em;
240
+ --leading: 1.38;
241
+
242
+ }
243
+
244
+ @page {
245
+ @bottom-center { content: counter(page); font-family: var(--font-body); font-size: 9pt; }
246
+ }
247
+
248
+ body {
249
+ color: var(--color-ink);
250
+ background: var(--color-paper);
251
+ font-family: var(--font-body);
252
+ line-height: var(--leading);
253
+ font-size: var(--fs-body);
254
+ text-align: justify;
255
+ hyphens: auto;
256
+ }
257
+
258
+ h1, h2, h3 {
259
+ font-family: var(--font-display);
260
+ color: var(--color-accent);
261
+ line-height: 1.2;
262
+ font-weight: bold;
263
+ }
264
+ h1 { font-size: var(--fs-h1); margin: 0 0 0.7em; }
265
+ h2 { font-size: var(--fs-h2); margin: 1.4em 0 0.5em; }
266
+ h3 { font-size: var(--fs-h3); margin: 1.2em 0 0.4em; }
267
+
268
+ a { color: var(--color-accent); text-decoration: none; }
269
+
270
+ code, pre { font-family: var(--font-mono); }
271
+ pre { font-size: 0.8em; line-height: 1.3; }
272
+
273
+ /* @section .title — the title, authors, affiliations and date */
274
+ .title { text-align: center; hyphens: manual; margin-bottom: 2em; }
275
+
276
+ /* @section .abstract — the abstract, keywords and subject classes */
277
+ .abstract { font-size: 0.9em; margin: 0 2.5em 2em; }
278
+
279
+ /* @section .figure — a figure, table or listing kept on one page with its caption */
280
+ .figure { break-inside: avoid; margin: 1.4em 0; }
281
+ .caption { font-size: 0.9em; color: var(--color-ink-muted); }
282
+
283
+ /* Tables ruled above, below and under the header row, as journals set them */
284
+ table { border-collapse: collapse; margin: 0.6em auto; border-top: 1pt solid var(--color-rule); border-bottom: 1pt solid var(--color-rule); }
285
+ thead th { border-bottom: 0.5pt solid var(--color-rule); }
286
+ th, td { padding: 0.2em 0.8em; }
287
+
288
+ /* Notes (from [^1] footnotes) and @section .references, a size smaller than the text */
289
+ .footnotes, .references { font-size: 0.85em; }
290
+ .footnotes-sep { border: 0; border-top: 0.5pt solid var(--color-rule); width: 30%; margin: 1.5em 0 0.5em; }
291
+ .footnote-backref { display: none; }
292
+ `;
293
+
294
+ // src/lib/extension-specifier.ts
295
+ var BUNDLED_EXTENSIONS = [
296
+ {
297
+ name: "markdown-it-mark",
298
+ label: "Highlight",
299
+ description: "Highlight text by wrapping it in `==double equals==`."
300
+ },
301
+ {
302
+ name: "markdown-it-sub",
303
+ label: "Subscript",
304
+ description: "Lower text below the line, like the 2 in `H~2~O`."
305
+ },
306
+ {
307
+ name: "markdown-it-sup",
308
+ label: "Superscript",
309
+ description: "Raise text above the line, like the th in `29^th^`."
310
+ },
311
+ {
312
+ name: "markdown-it-abbr",
313
+ label: "Abbreviations",
314
+ description: "Explain an abbreviation when readers hover over it. Define it once, like `*[GPS]: Global Positioning System`."
315
+ },
316
+ {
317
+ name: "gutterpress-gfm-alerts",
318
+ label: "Callouts",
319
+ description: "Turn a quote into a boxed note: start it with `> [!NOTE]` (or `TIP`, `IMPORTANT`, `WARNING`, `CAUTION`)."
320
+ },
321
+ {
322
+ name: "gutterpress-math",
323
+ label: "Math",
324
+ description: "Write LaTeX math between dollar signs: `$E = mc^2$` in a line, or `$$` … `$$` on lines of their own."
325
+ },
326
+ {
327
+ name: "clean-book",
328
+ label: "Clean book",
329
+ description: "A calm, classic book look: serif body, generous margins, restrained accents.",
330
+ css: theme_default
331
+ },
332
+ {
333
+ name: "zine",
334
+ label: "Zine",
335
+ description: "High-contrast, punchy sans-serif look for short photocopier-friendly zines.",
336
+ css: theme_default2
337
+ },
338
+ {
339
+ name: "technical-doc",
340
+ label: "Technical doc",
341
+ description: "Clean sans-serif manual look with clear hierarchy, code styling, and tidy tables.",
342
+ css: theme_default3
343
+ },
344
+ {
345
+ name: "academic",
346
+ label: "Academic",
347
+ description: "A journal-article look: serif text, justified and hyphenated, ruled tables, notes and references set smaller.",
348
+ css: theme_default4
349
+ }
350
+ ];
351
+ function bundledExtension(name) {
352
+ return BUNDLED_EXTENSIONS.find((e) => e.name === name);
353
+ }
354
+ function isBundledExtension(name) {
355
+ return bundledExtension(name) !== undefined;
356
+ }
357
+ function isPathSpecifier(use) {
358
+ return use.startsWith("./") || use.startsWith("../") || use.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(use);
359
+ }
360
+ function parseExtensionSpecifier(use) {
361
+ const spec = use.trim();
362
+ if (!spec) {
363
+ throw new Error("An extension specifier is required — an npm package name, or a ./ path.");
364
+ }
365
+ if (isPathSpecifier(spec))
366
+ return { kind: "path", path: spec };
367
+ if (/\.(m?js|cjs)$/i.test(spec) || !spec.startsWith("@") && spec.includes("/")) {
368
+ throw new Error(`"${spec}" looks like a path; write it as "./${spec}". A specifier that does not ` + "start with ./, ../ or / is an npm package name.");
369
+ }
370
+ const parsed = parseNpmPluginSpec(spec);
371
+ if (isBundledExtension(parsed.name)) {
372
+ if (parsed.selector !== undefined) {
373
+ throw new Error(`"${parsed.name}" is bundled with Gutterpress and always resolves to the bundled copy — ` + `drop "@${parsed.selector}".`);
374
+ }
375
+ return { kind: "bundled", name: parsed.name };
376
+ }
377
+ return parsed.selector === undefined ? { kind: "npm", name: parsed.name } : { kind: "npm", name: parsed.name, version: parsed.selector };
378
+ }
379
+ function pinnedNpmSpecifier(name, version) {
380
+ return `${name}@${version}`;
381
+ }
382
+
22
383
  // src/lib/style-declarations.ts
23
384
  import { existsSync } from "node:fs";
24
385
  import { resolve } from "node:path";
@@ -64,7 +425,6 @@ function metaFromPackageJson(raw) {
64
425
  ...str(object(pkg.engines)?.gutterpress) ? { gutterpressRange: str(object(pkg.engines)?.gutterpress) } : {},
65
426
  ..."preview" in gp ? { preview: str(gp.preview) ?? null } : {},
66
427
  ...Array.isArray(gp.styles) ? { styles: declaredList(gp.styles) } : {},
67
- ...str(gp.tokensFile) ? { tokensFile: str(gp.tokensFile) } : {},
68
428
  ...str(gp.markdown) ? { markdown: str(gp.markdown) } : {},
69
429
  ...str(gp.components) ? { components: str(gp.components) } : {},
70
430
  ...str(gp.snippets) ? { snippets: str(gp.snippets) } : {},
@@ -130,8 +490,7 @@ function assertExtensionContained(meta) {
130
490
  ...entry ? [entry] : [],
131
491
  ...meta.publish && meta.main?.trim() ? [meta.main.trim()] : [],
132
492
  ...meta.components ? [meta.components] : [],
133
- ...meta.snippets ? [meta.snippets] : [],
134
- ...meta.tokensFile ? [meta.tokensFile] : []
493
+ ...meta.snippets ? [meta.snippets] : []
135
494
  ];
136
495
  for (const rel of declared) {
137
496
  if (pathEscapesFolder(rel)) {
@@ -148,7 +507,6 @@ function resolveExtension(dir, meta, subject) {
148
507
  return {
149
508
  ...markdown ? { markdown } : {},
150
509
  ...styles ? { styles } : {},
151
- ...meta.tokensFile?.trim() ? { tokensFile: meta.tokensFile.trim() } : {},
152
510
  ...components ? { components } : {},
153
511
  ...snippets ? { snippets } : {}
154
512
  };
@@ -3182,7 +3540,7 @@ async function importVendoredEntry(installRoot, packageDir, spec) {
3182
3540
  try {
3183
3541
  entry = await resolvePackageEntry(packageDir);
3184
3542
  } catch (cause) {
3185
- throw new Error(`the downloaded copy of ${spec} under plugins/npm/ is incomplete ` + `(${cause instanceof Error ? cause.message : String(cause)}). ` + `Reinstall it with \`gutterpress ext add ${spec}\`.`, { cause });
3543
+ throw new Error(`the downloaded copy of ${spec} under extensions/npm/ is incomplete ` + `(${cause instanceof Error ? cause.message : String(cause)}). ` + `Reinstall it with \`gutterpress ext add ${spec}\`.`, { cause });
3186
3544
  }
3187
3545
  const entryPath = join(packageDir, ...entry.split("/"));
3188
3546
  vendoredRootsOpened.add(installRoot);
@@ -3212,9 +3570,9 @@ async function loadNpmPackage(packageName, baseDir, version) {
3212
3570
  const looksLikeJsFilename = /\.(m?js|cjs)$/i.test(packageName);
3213
3571
  const suggestedPath = looksLikeJsFilename ? `./${packageName}` : `./plugins/${packageName}.js`;
3214
3572
  if (!looksLikeJsFilename && (!version || !isExactNpmVersion(version))) {
3215
- throw new Error(`Extension "${packageName}${version ? `@${version}` : ""}" is not pinned to an exact version, so it can't be downloaded automatically. Run \`gutterpress ext add ${packageName}\` (or use Book settings > Features in the desktop app) to download it and pin its version in your manifest.`);
3573
+ throw new Error(`Extension "${packageName}${version ? `@${version}` : ""}" is not pinned to an exact version, so it can't be downloaded automatically. Run \`gutterpress ext add ${packageName}\` (or use Book setup > Looks & features > Advanced in the desktop app) to download it and pin its version in your manifest.`);
3216
3574
  }
3217
- throw new Error(`Extension "${packageName}" not found. Install it with \`gutterpress ext add ${version ? `${packageName}@${version}` : packageName}\` (or Book settings > Features > Advanced in the desktop app),
3575
+ throw new Error(`Extension "${packageName}" not found. Install it with \`gutterpress ext add ${version ? `${packageName}@${version}` : packageName}\` (or Book setup > Looks & features > Advanced in the desktop app),
3218
3576
  or reference a local file under \`extensions:\`:
3219
3577
  extensions:
3220
3578
  - ${suggestedPath}`);
@@ -3402,12 +3760,18 @@ async function loadPlugin(config, baseDir) {
3402
3760
  if (!config.path && !config.name) {
3403
3761
  throw new Error("Plugin manifest entry must specify either `path` or `name`. Got an empty plugin config.");
3404
3762
  }
3405
- if (!config.path && !config.version && config.name && BUILTIN_OPTIONAL_PLUGINS[config.name]) {
3406
- return {
3407
- name: config.name,
3408
- plugin: BUILTIN_OPTIONAL_PLUGINS[config.name],
3409
- options: config.options
3410
- };
3763
+ if (!config.path && !config.version && config.name) {
3764
+ const bundled = bundledExtension(config.name);
3765
+ if (bundled?.css !== undefined) {
3766
+ return { name: config.name, plugin: noopPlugin, css: bundled.css, options: config.options };
3767
+ }
3768
+ if (BUILTIN_OPTIONAL_PLUGINS[config.name]) {
3769
+ return {
3770
+ name: config.name,
3771
+ plugin: BUILTIN_OPTIONAL_PLUGINS[config.name],
3772
+ options: config.options
3773
+ };
3774
+ }
3411
3775
  }
3412
3776
  if (config.path) {
3413
3777
  const candidatePath = resolve2(baseDir, config.path);
@@ -3528,4 +3892,4 @@ async function loadPluginsWithCss(configs, baseDir, onError) {
3528
3892
  };
3529
3893
  }
3530
3894
 
3531
- export { TWO_VERSIONS_OPEN, TWO_VERSIONS_CLOSE, MARKER_CSS, GUTTERPRESS_CSS, TWO_VERSIONS_CSS, TABLE_ALIGN_CSS, slugify, prettify, parseSrcsetUrlCandidates, collectHtmlImageRefs, createMarkdownRenderer, applyPlugins, collectPluginCss, collectPluginStylePaths, collectPluginStyleGroups, resolveDeclaredStyles, EXTENSION_MANIFEST_FILENAME, readExtensionMeta, extensionStyleList, extensionEntry, extensionCarries, assertExtensionContained, __resetPathPluginCacheForTests, loadPlugin, loadPublishFunction, loadPlugins, loadPluginsWithCss };
3895
+ export { bundledExtension, isPathSpecifier, parseExtensionSpecifier, pinnedNpmSpecifier, TWO_VERSIONS_OPEN, TWO_VERSIONS_CLOSE, MARKER_CSS, GUTTERPRESS_CSS, TWO_VERSIONS_CSS, TABLE_ALIGN_CSS, slugify, prettify, parseSrcsetUrlCandidates, collectHtmlImageRefs, createMarkdownRenderer, applyPlugins, collectPluginCss, collectPluginStylePaths, collectPluginStyleGroups, resolveDeclaredStyles, EXTENSION_MANIFEST_FILENAME, readExtensionMeta, extensionStyleList, extensionEntry, extensionCarries, assertExtensionContained, __resetPathPluginCacheForTests, loadPlugin, loadPublishFunction, loadPlugins, loadPluginsWithCss };