gutterpress 0.10.10-alpha.3 → 0.10.11-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,11 +12,11 @@ Download for your platform from the [latest release](https://github.com/dimm-cit
12
12
 
13
13
  | Platform | Binary |
14
14
  |---|---|
15
- | Linux x64 | `gutterpress-linux-x64` |
16
- | Linux ARM64 | `gutterpress-linux-arm64` |
17
- | macOS Apple Silicon | `gutterpress-macos-arm64` |
18
- | macOS Intel | `gutterpress-macos-x64` |
19
- | Windows x64 | `gutterpress-windows-x64.exe` |
15
+ | Linux x64 | `gutterpress-cli-linux-x64` |
16
+ | Linux ARM64 | `gutterpress-cli-linux-arm64` |
17
+ | macOS Apple Silicon | `gutterpress-cli-macos-arm64` |
18
+ | macOS Intel | `gutterpress-cli-macos-x64` |
19
+ | Windows x64 | `gutterpress-cli-windows-x64.exe` |
20
20
 
21
21
  Move the binary somewhere on your `PATH`, mark it executable (`chmod +x`), and you're done.
22
22
 
@@ -308,8 +308,22 @@ gutterpress validate [dir] [options]
308
308
  --format <fmt> text (default) | json
309
309
  --phase <p> pre | post | all | pre-build | post-build (default: all)
310
310
  --target <t> Publish targets to validate against (comma-separated, e.g. dtrpg,itch), overriding the manifest's `targets:`
311
+ --fix Rewrite the source markdown in place with markdownlint's auto-fixes (source.markdownlint only)
311
312
  ```
312
313
 
314
+ `--fix` is the only thing validation ever writes, and only when you ask for
315
+ it: it applies markdownlint's own auto-fixes to the markdown, prints every
316
+ file it rewrote, and still reports whatever cannot be fixed mechanically. It
317
+ uses the same `.markdownlint.*` config the `source.markdownlint` check uses,
318
+ and does nothing when no config is found. A file with uncommitted changes is
319
+ rewritten too — you get a notice, not a refusal.
320
+
321
+ It writes only when `source.markdownlint` is actually part of the run, so
322
+ `--skip source.markdownlint`, an `--only` that names other checks, or a
323
+ `--phase`/`--category` that filters the source checks out all leave your
324
+ markdown untouched — `--fix` can never rewrite a file for a check the report
325
+ does not mention.
326
+
313
327
  ### `gutterpress audit`
314
328
 
315
329
  Run asset-only validation checks (image DPI/format/color-space, print-readiness) without the rest of the validation pipeline.
@@ -546,7 +560,7 @@ The standalone binary is the easiest way — drop it in a GitHub Actions step an
546
560
  - name: Build PDF
547
561
  run: |
548
562
  curl -L -o gutterpress \
549
- https://github.com/dimm-city/gutterpress/releases/latest/download/gutterpress-linux-x64
563
+ https://github.com/dimm-city/gutterpress/releases/latest/download/gutterpress-cli-linux-x64
550
564
  chmod +x gutterpress
551
565
  sudo apt-get install -y google-chrome-stable ghostscript
552
566
  ./gutterpress build ./my-book --out dist/my-book.pdf
package/dist/api/index.js CHANGED
@@ -124,7 +124,7 @@ import {
124
124
  syncProject,
125
125
  testRemoteAccess,
126
126
  validateProjectExtensions
127
- } from "../index-ryjmpyq6.js";
127
+ } from "../index-fcfae175.js";
128
128
  import {
129
129
  BuildError,
130
130
  DEFAULT_PRINT_OPTS,
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  executeAndReport
3
- } from "./cli-x4krgssg.js";
3
+ } from "./cli-s6m6d0hx.js";
4
4
  import {
5
5
  log
6
- } from "./cli-d7k5ykyx.js";
6
+ } from "./cli-8x25pp3t.js";
7
7
  import {
8
8
  UsageError,
9
9
  rejectExtraPositionals,
10
10
  rejectUnknownFlags
11
- } from "./cli-1prnz7c8.js";
11
+ } from "./cli-wthscqa9.js";
12
12
  import"./cli-k8f9eb12.js";
13
13
  import"./cli-c41yr7he.js";
14
14
  import {
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  runBuild,
3
3
  splitOutPath
4
- } from "./cli-x4krgssg.js";
4
+ } from "./cli-s6m6d0hx.js";
5
5
  import {
6
6
  log
7
- } from "./cli-d7k5ykyx.js";
7
+ } from "./cli-8x25pp3t.js";
8
8
  import {
9
9
  UsageError,
10
10
  parseFormat,
11
11
  parsePdfxFlavor,
12
12
  rejectExtraPositionals,
13
13
  rejectUnknownFlags
14
- } from "./cli-1prnz7c8.js";
14
+ } from "./cli-wthscqa9.js";
15
15
  import"./cli-k8f9eb12.js";
16
16
  import"./cli-c41yr7he.js";
17
17
  import {
@@ -1,3 +1,19 @@
1
1
  import type { Check } from "../types";
2
+ /** Exported so `validate --fix` (lib/markdownlint-fix.ts) discovers config
3
+ * through THIS list, never a second copy of it. */
4
+ export declare const CONFIG_NAMES: string[];
5
+ /**
6
+ * Load a markdownlint config object from a discovered config file. The parser
7
+ * is selected by extension (.json → JSON, .jsonc → JSON minus comments, else
8
+ * YAML — which also accepts plain JSON). markdownlint-cli2-style files nest the
9
+ * rules under a `config:` key; plain markdownlint files are the rules object
10
+ * directly, so `parsed.config ?? parsed` handles both shapes.
11
+ *
12
+ * Exported for `validate --fix` (lib/markdownlint-fix.ts), so the fixer and
13
+ * this check can never disagree about which rules apply.
14
+ */
15
+ export declare function loadConfig(configPath: string): Promise<Record<string, unknown>>;
16
+ /** The registered id, shared with `validate --fix`'s selector gate (#275). */
17
+ export declare const MARKDOWNLINT_CHECK_ID = "source.markdownlint";
2
18
  declare const check: Check;
3
19
  export default check;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  package_default
3
- } from "./cli-1prnz7c8.js";
3
+ } from "./cli-wthscqa9.js";
4
4
  import {
5
5
  execCapture,
6
6
  findTool,
@@ -13,12 +13,12 @@ import {
13
13
  stampCreator,
14
14
  stripAnnotations,
15
15
  warn
16
- } from "./cli-d7k5ykyx.js";
16
+ } from "./cli-8x25pp3t.js";
17
17
  import {
18
18
  DEBOUNCE,
19
19
  UsageError,
20
20
  resolvePort
21
- } from "./cli-1prnz7c8.js";
21
+ } from "./cli-wthscqa9.js";
22
22
  import {
23
23
  MARGIN_BOX_IGNORED_PROPERTIES,
24
24
  RENDER_TIMEOUT_MS,
@@ -41,10 +41,12 @@ import {
41
41
  BuildError
42
42
  } from "./cli-46ycxe6r.js";
43
43
  import {
44
- hasUncommittedChanges
44
+ hasUncommittedChanges,
45
+ listWorkdirChanges
45
46
  } from "./cli-4mtf9ajw.js";
46
47
  import {
47
- detectProjectSource
48
+ detectProjectSource,
49
+ repoSubPath
48
50
  } from "./cli-v5mp7a6q.js";
49
51
  import {
50
52
  __require
@@ -2419,8 +2421,9 @@ async function loadConfig(configPath) {
2419
2421
  }
2420
2422
  return {};
2421
2423
  }
2424
+ var MARKDOWNLINT_CHECK_ID = "source.markdownlint";
2422
2425
  var check16 = {
2423
- id: "source.markdownlint",
2426
+ id: MARKDOWNLINT_CHECK_ID,
2424
2427
  name: "Markdownlint",
2425
2428
  description: "Runs markdownlint with project config to validate Markdown files",
2426
2429
  category: "source",
@@ -3587,7 +3590,7 @@ function attachDataAttrs(token, kind, name, attrs) {
3587
3590
  continue;
3588
3591
  if (k === "class" || k === "id" || k === "template" || k === "region")
3589
3592
  continue;
3590
- token.attrSet(`data-${k}`, v);
3593
+ token.attrSet(k.startsWith("data-") ? k : `data-${k}`, v);
3591
3594
  }
3592
3595
  }
3593
3596
  var DECLARED_NAME_RE = /^[a-z][a-z0-9-]*$/;
@@ -7713,6 +7716,69 @@ async function renderChaptersToFile(inputDir, outDir, opts = {}) {
7713
7716
  return outFile;
7714
7717
  }
7715
7718
 
7719
+ // src/lib/markdownlint-fix.ts
7720
+ import { readFile as readFile20, writeFile as writeFile3 } from "node:fs/promises";
7721
+ import { applyFixes } from "markdownlint";
7722
+ import { lint as lint2 } from "markdownlint/sync";
7723
+ async function uncommittedAmong(inputDir, files) {
7724
+ const source = await detectProjectSource(inputDir);
7725
+ if (source.type !== "local-git-folder")
7726
+ return [];
7727
+ const repoRoot = source.repoRoot;
7728
+ let changed;
7729
+ try {
7730
+ const { adds } = await listWorkdirChanges(repoRoot);
7731
+ changed = new Set(adds);
7732
+ } catch {
7733
+ return [];
7734
+ }
7735
+ return files.filter((file) => changed.has(repoSubPath(repoRoot, file)));
7736
+ }
7737
+ async function applyMarkdownlintFixes(ctx) {
7738
+ const sourceConfig = ctx.config.validate.source;
7739
+ if (sourceConfig.markdownlint === false) {
7740
+ log.warn("--fix: source.markdownlint is disabled for this project — no files were fixed.");
7741
+ return [];
7742
+ }
7743
+ const files = ctx.markdownFiles;
7744
+ if (!files || files.length === 0) {
7745
+ log.warn("--fix: no markdown files to fix.");
7746
+ return [];
7747
+ }
7748
+ const configPath = typeof sourceConfig.markdownlint === "string" ? sourceConfig.markdownlint : null;
7749
+ const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES, configPath);
7750
+ if (!resolvedConfig && !configPath) {
7751
+ log.warn(`--fix: no markdownlint config found in ${ctx.inputDir} (looked for ${CONFIG_NAMES.join(", ")}) — no files were fixed.`);
7752
+ return [];
7753
+ }
7754
+ const config = resolvedConfig ? await loadConfig(resolvedConfig) : { default: true };
7755
+ const results = lint2({ files, config });
7756
+ const pending = [];
7757
+ for (const [file, violations] of Object.entries(results)) {
7758
+ if (!Array.isArray(violations) || violations.length === 0)
7759
+ continue;
7760
+ const before = await readFile20(file, "utf8");
7761
+ const after = applyFixes(before, violations);
7762
+ if (after !== before)
7763
+ pending.push({ file, content: after });
7764
+ }
7765
+ if (pending.length === 0) {
7766
+ log.warn("--fix: no mechanically fixable markdownlint violations found.");
7767
+ return [];
7768
+ }
7769
+ const dirty = await uncommittedAmong(ctx.inputDir, pending.map((p) => p.file));
7770
+ for (const { file, content } of pending) {
7771
+ await writeFile3(file, content, "utf8");
7772
+ }
7773
+ log.warn(`--fix: rewrote ${pending.length} file(s):`);
7774
+ for (const { file } of pending)
7775
+ log.warn(` ${file}`);
7776
+ if (dirty.length > 0) {
7777
+ log.warn(`--fix: ${dirty.length} of those already had uncommitted changes and were rewritten anyway: ${dirty.join(", ")}`);
7778
+ }
7779
+ return pending.map((p) => p.file);
7780
+ }
7781
+
7716
7782
  // src/checks/formatter.ts
7717
7783
  function formatReport(report, format = "text") {
7718
7784
  if (format === "json") {
@@ -8106,6 +8172,14 @@ async function executeValidation(args) {
8106
8172
  only,
8107
8173
  skip
8108
8174
  };
8175
+ if (args.fix) {
8176
+ const selected = selectChecks(runnerOptions, config).checks;
8177
+ if (selected.some((check37) => check37.id === MARKDOWNLINT_CHECK_ID)) {
8178
+ await applyMarkdownlintFixes(context);
8179
+ } else {
8180
+ log.warn(`--fix: ${MARKDOWNLINT_CHECK_ID} is not part of this run — no files were fixed.`);
8181
+ }
8182
+ }
8109
8183
  const runs = planRuns({ manifest, baseConfig: config, targetIds, pdfPath, categories, only });
8110
8184
  const reports = [];
8111
8185
  const toolResults = [];
@@ -8187,7 +8261,7 @@ import { randomBytes } from "node:crypto";
8187
8261
 
8188
8262
  // src/lib/build-fingerprint.ts
8189
8263
  import * as fs from "node:fs";
8190
- import { mkdir as mkdir3, readFile as readFile20, writeFile as writeFile3 } from "node:fs/promises";
8264
+ import { mkdir as mkdir3, readFile as readFile21, writeFile as writeFile4 } from "node:fs/promises";
8191
8265
  import { createHash as createHash5 } from "node:crypto";
8192
8266
  import path8 from "node:path";
8193
8267
  import git from "isomorphic-git";
@@ -8274,8 +8348,8 @@ async function getEngineBundleHash() {
8274
8348
  getAssetPath("engine/gutterpress-agent.js")
8275
8349
  ]);
8276
8350
  const [viewerBytes, agentBytes] = await Promise.all([
8277
- readFile20(viewerPath),
8278
- readFile20(agentPath)
8351
+ readFile21(viewerPath),
8352
+ readFile21(agentPath)
8279
8353
  ]);
8280
8354
  const hash = createHash5("sha256");
8281
8355
  hash.update(viewerBytes);
@@ -8346,7 +8420,7 @@ async function writeBuildFingerprint(input) {
8346
8420
  tools
8347
8421
  };
8348
8422
  await mkdir3(outputDir, { recursive: true });
8349
- await writeFile3(outPath, stableJsonStringify(payload), "utf8");
8423
+ await writeFile4(outPath, stableJsonStringify(payload), "utf8");
8350
8424
  return outPath;
8351
8425
  }
8352
8426
 
@@ -8785,7 +8859,7 @@ function openPath(filePath) {
8785
8859
  import path11 from "path";
8786
8860
  import { tmpdir as tmpdir2 } from "os";
8787
8861
  import { randomBytes as randomBytes2 } from "crypto";
8788
- import { readdir as readdir4, readFile as readFile21, writeFile as writeFile4 } from "node:fs/promises";
8862
+ import { readdir as readdir4, readFile as readFile22, writeFile as writeFile5 } from "node:fs/promises";
8789
8863
 
8790
8864
  // src/utils/file-utils.ts
8791
8865
  import { promises as fs3 } from "fs";
@@ -9295,7 +9369,7 @@ async function cleanupOrphanTempDirs() {
9295
9369
  const dir = path11.join(TEMP_DIR_BASE, entry);
9296
9370
  const pidFile = path11.join(dir, PID_FILE_NAME);
9297
9371
  try {
9298
- const raw = await readFile21(pidFile, "utf8");
9372
+ const raw = await readFile22(pidFile, "utf8");
9299
9373
  const pid = parseInt(raw.trim(), 10);
9300
9374
  if (!isProcessAlive(pid)) {
9301
9375
  debug(`Removing orphan temp dir ${dir} (pid ${pid} not alive)`);
@@ -9310,7 +9384,7 @@ async function initializePreviewDirectories() {
9310
9384
  const tempDir = path11.join(TEMP_DIR_BASE, tempDirSuffix);
9311
9385
  await mkdir4(tempDir);
9312
9386
  debug(`Created temporary directory: ${tempDir}`);
9313
- await writeFile4(path11.join(tempDir, PID_FILE_NAME), `${process.pid}
9387
+ await writeFile5(path11.join(tempDir, PID_FILE_NAME), `${process.pid}
9314
9388
  `, "utf8");
9315
9389
  return tempDir;
9316
9390
  }
@@ -9401,7 +9475,7 @@ function createServerState(inputPath, tempDir, config, options) {
9401
9475
  import http from "node:http";
9402
9476
  import net from "node:net";
9403
9477
  import { createHash as createHash6, randomUUID } from "node:crypto";
9404
- import { readFile as readFile22, stat as stat4 } from "node:fs/promises";
9478
+ import { readFile as readFile23, stat as stat4 } from "node:fs/promises";
9405
9479
  import path13 from "path";
9406
9480
  import { WebSocket, WebSocketServer } from "ws";
9407
9481
 
@@ -9691,7 +9765,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
9691
9765
  }
9692
9766
  let data;
9693
9767
  try {
9694
- data = await readFile22(filePath);
9768
+ data = await readFile23(filePath);
9695
9769
  } catch {
9696
9770
  res.writeHead(404);
9697
9771
  res.end("Not Found");
@@ -9741,7 +9815,7 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
9741
9815
  let data;
9742
9816
  if (!validator || validator.stamp !== stamp) {
9743
9817
  try {
9744
- data = await readFile22(absPath);
9818
+ data = await readFile23(absPath);
9745
9819
  } catch {
9746
9820
  await serveStatic(absPath, res);
9747
9821
  return;
@@ -10080,7 +10154,7 @@ async function startPreviewServer(options) {
10080
10154
  }
10081
10155
 
10082
10156
  // src/lib/extension-manager.ts
10083
- import { cp as cp2, mkdir as mkdir7, readFile as readFile25, rm as rm4, stat as stat5 } from "node:fs/promises";
10157
+ import { cp as cp2, mkdir as mkdir7, readFile as readFile26, rm as rm4, stat as stat5 } from "node:fs/promises";
10084
10158
  import { existsSync as existsSync11 } from "node:fs";
10085
10159
  import path16 from "node:path";
10086
10160
  import { isSeq as isSeq2, isMap, isScalar, YAMLMap, Scalar } from "yaml";
@@ -10088,7 +10162,7 @@ import { isSeq as isSeq2, isMap, isScalar, YAMLMap, Scalar } from "yaml";
10088
10162
  // src/lib/manifest-doc.ts
10089
10163
  import { existsSync as existsSync10 } from "node:fs";
10090
10164
  import { randomUUID as randomUUID2 } from "node:crypto";
10091
- import { mkdir as mkdir5, open, readFile as readFile23, rename, rm as rm2 } from "node:fs/promises";
10165
+ import { mkdir as mkdir5, open, readFile as readFile24, rename, rm as rm2 } from "node:fs/promises";
10092
10166
  import path14 from "node:path";
10093
10167
  import { parseDocument, isSeq, YAMLSeq } from "yaml";
10094
10168
  function resolveManifestPath(projectDir) {
@@ -10099,7 +10173,7 @@ async function loadManifestDoc(projectDir) {
10099
10173
  const file = resolveManifestPath(projectDir);
10100
10174
  let text = "";
10101
10175
  try {
10102
- text = await readFile23(file, "utf8");
10176
+ text = await readFile24(file, "utf8");
10103
10177
  } catch (error2) {
10104
10178
  if (error2.code !== "ENOENT")
10105
10179
  throw error2;
@@ -10146,7 +10220,7 @@ import {
10146
10220
  mkdir as mkdir6,
10147
10221
  mkdtemp as mkdtemp2,
10148
10222
  open as open2,
10149
- readFile as readFile24,
10223
+ readFile as readFile25,
10150
10224
  realpath as realpath2,
10151
10225
  rename as rename2,
10152
10226
  rm as rm3
@@ -10544,7 +10618,7 @@ async function readInstalledManifest(packageDir, selected) {
10544
10618
  const info2 = await lstat2(packageJsonPath);
10545
10619
  if (!info2.isFile() || info2.isSymbolicLink())
10546
10620
  throw new Error("not a regular file");
10547
- manifest = object3(JSON.parse(await readFile24(packageJsonPath, "utf8")));
10621
+ manifest = object3(JSON.parse(await readFile25(packageJsonPath, "utf8")));
10548
10622
  } catch (error2) {
10549
10623
  throw new SecurityInstallError(`Downloaded ${selected.name}@${selected.version} has no valid package.json (${error2 instanceof Error ? error2.message : String(error2)}).`);
10550
10624
  }
@@ -11248,7 +11322,7 @@ async function addBuiltInStyleSet(projectDir, id) {
11248
11322
  }
11249
11323
 
11250
11324
  // src/lib/project-scaffold.ts
11251
- import { access, copyFile, cp as cp3, mkdir as mkdir8, readdir as readdir5, readFile as readFile26, stat as stat6, writeFile as writeFile5 } from "node:fs/promises";
11325
+ import { access, copyFile, cp as cp3, mkdir as mkdir8, readdir as readdir5, readFile as readFile27, stat as stat6, writeFile as writeFile6 } from "node:fs/promises";
11252
11326
  import { constants as FS, existsSync as existsSync12 } from "node:fs";
11253
11327
  import path17 from "node:path";
11254
11328
  var STARTER_THEME_FOR_TEMPLATE = {
@@ -11371,7 +11445,7 @@ async function scaffoldProject(options) {
11371
11445
  await copyFile(tplManifest, path17.join(projectDir, MANIFEST_FILENAMES[0]));
11372
11446
  await copyFile(tplChapter, path17.join(projectDir, "chapter-01.md"));
11373
11447
  await mkdir8(path17.join(projectDir, "styles"), { recursive: true });
11374
- await writeFile5(path17.join(projectDir, "styles", "book.css"), starterOverridesCss(starterThemeId), "utf8");
11448
+ await writeFile6(path17.join(projectDir, "styles", "book.css"), starterOverridesCss(starterThemeId), "utf8");
11375
11449
  }
11376
11450
  } catch (e) {
11377
11451
  throw new CreateProjectErrorImpl("scaffold-io", `Could not create the project files: ${e instanceof Error ? e.message : String(e)}`);
@@ -11451,10 +11525,10 @@ async function ensureGitignoreHasDist(projectDir) {
11451
11525
  const gitignorePath = path17.join(projectDir, ".gitignore");
11452
11526
  let existing = null;
11453
11527
  try {
11454
- existing = await readFile26(gitignorePath, "utf8");
11528
+ existing = await readFile27(gitignorePath, "utf8");
11455
11529
  } catch {}
11456
11530
  if (existing === null) {
11457
- await writeFile5(gitignorePath, `dist/
11531
+ await writeFile6(gitignorePath, `dist/
11458
11532
  `, "utf8");
11459
11533
  return;
11460
11534
  }
@@ -11464,14 +11538,14 @@ async function ensureGitignoreHasDist(projectDir) {
11464
11538
  return;
11465
11539
  const needsLeadingNewline = existing.length > 0 && !existing.endsWith(`
11466
11540
  `);
11467
- await writeFile5(gitignorePath, existing + (needsLeadingNewline ? `
11541
+ await writeFile6(gitignorePath, existing + (needsLeadingNewline ? `
11468
11542
  ` : "") + `dist/
11469
11543
  `, "utf8");
11470
11544
  }
11471
11545
  async function firstSourceFile(manifestPath) {
11472
11546
  let text;
11473
11547
  try {
11474
- text = await readFile26(manifestPath, "utf8");
11548
+ text = await readFile27(manifestPath, "utf8");
11475
11549
  } catch {
11476
11550
  return;
11477
11551
  }
@@ -11483,15 +11557,15 @@ async function firstSourceFile(manifestPath) {
11483
11557
  return m ? m[1].trim() : undefined;
11484
11558
  }
11485
11559
  async function fillTemplateFile(filePath, substitutions) {
11486
- let text = await readFile26(filePath, "utf8");
11560
+ let text = await readFile27(filePath, "utf8");
11487
11561
  for (const [token, value] of Object.entries(substitutions)) {
11488
11562
  text = text.split(token).join(value);
11489
11563
  }
11490
- await writeFile5(filePath, text, "utf8");
11564
+ await writeFile6(filePath, text, "utf8");
11491
11565
  }
11492
11566
 
11493
11567
  // src/lib/extension-scaffold.ts
11494
- import { access as access2, mkdir as mkdir9, readFile as readFile27, writeFile as writeFile6 } from "node:fs/promises";
11568
+ import { access as access2, mkdir as mkdir9, readFile as readFile28, writeFile as writeFile7 } from "node:fs/promises";
11495
11569
  import { constants as FS2 } from "node:fs";
11496
11570
  import path18 from "node:path";
11497
11571
  var EXTENSION_KINDS = ["plugin", "theme"];
@@ -11608,9 +11682,9 @@ async function scaffoldExtension(options) {
11608
11682
  const src = await getAssetPath(`extension-templates/${kind}/${assetName}`);
11609
11683
  const dest = path18.join(extensionDir, relDest);
11610
11684
  await mkdir9(path18.dirname(dest), { recursive: true });
11611
- const text = await readFile27(src, "utf8");
11685
+ const text = await readFile28(src, "utf8");
11612
11686
  const table = relDest.endsWith(".json") ? jsonSafe : plain;
11613
- await writeFile6(dest, substitute(text, table), "utf8");
11687
+ await writeFile7(dest, substitute(text, table), "utf8");
11614
11688
  written.push(relDest);
11615
11689
  }
11616
11690
  } catch (e) {
@@ -11653,7 +11727,7 @@ var SKIP_ENTRIES = new Set([
11653
11727
 
11654
11728
  // src/lib/extension-import.ts
11655
11729
  import { existsSync as existsSync13 } from "node:fs";
11656
- import { cp as cp4, mkdir as mkdir10, mkdtemp as mkdtemp3, readFile as readFile28, rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
11730
+ import { cp as cp4, mkdir as mkdir10, mkdtemp as mkdtemp3, readFile as readFile29, rm as rm5, writeFile as writeFile8 } from "node:fs/promises";
11657
11731
  import { tmpdir as tmpdir3 } from "node:os";
11658
11732
  import path19 from "node:path";
11659
11733
  import { unzipSync } from "fflate";
@@ -11726,7 +11800,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
11726
11800
  if (!existsSync13(cssPath)) {
11727
11801
  throw new Error("A theme must contain a theme.css file.");
11728
11802
  }
11729
- const css = await readFile28(cssPath, "utf8");
11803
+ const css = await readFile29(cssPath, "utf8");
11730
11804
  const { reject, warnings: printFindings } = classifyThemeCssFindings(checkCss(css, "theme.css"));
11731
11805
  if (reject) {
11732
11806
  throw new Error(`theme.css could not be parsed — ${reject.message}`);
@@ -11754,7 +11828,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
11754
11828
  for (let i = 0;i < extraSheets.length; i++) {
11755
11829
  const rel = extraSheets[i];
11756
11830
  const sheetPath = extraSheetPaths[i];
11757
- const sheetCss = await readFile28(sheetPath, "utf8");
11831
+ const sheetCss = await readFile29(sheetPath, "utf8");
11758
11832
  const { reject: sheetReject, warnings: sheetFindings } = classifyThemeCssFindings(checkCss(sheetCss, rel));
11759
11833
  if (sheetReject) {
11760
11834
  throw new Error(`${rel} could not be parsed — ${sheetReject.message}`);
@@ -11787,14 +11861,14 @@ async function completeLandedManifest(dest, id, meta, metaExists) {
11787
11861
  let pkg = {};
11788
11862
  if (metaExists) {
11789
11863
  try {
11790
- const parsed = JSON.parse(await readFile28(file, "utf8"));
11864
+ const parsed = JSON.parse(await readFile29(file, "utf8"));
11791
11865
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
11792
11866
  pkg = parsed;
11793
11867
  }
11794
11868
  } catch {}
11795
11869
  }
11796
11870
  const gutterpress = pkg.gutterpress && typeof pkg.gutterpress === "object" && !Array.isArray(pkg.gutterpress) ? pkg.gutterpress : {};
11797
- await writeFile7(file, JSON.stringify({
11871
+ await writeFile8(file, JSON.stringify({
11798
11872
  ...pkg,
11799
11873
  name: typeof pkg.name === "string" && pkg.name.trim() ? pkg.name : id,
11800
11874
  gutterpress: { ...gutterpress, styles: ["theme.css"] }
@@ -11859,7 +11933,7 @@ async function importExtensionFromZip(projectDir, archive) {
11859
11933
  }
11860
11934
  relPaths.push(rel);
11861
11935
  await mkdir10(path19.dirname(dest), { recursive: true });
11862
- await writeFile7(dest, data);
11936
+ await writeFile8(dest, data);
11863
11937
  }
11864
11938
  return await finalizeExtensionImport(projectDir, tmp, relPaths, root || "imported-look");
11865
11939
  } finally {
@@ -11874,8 +11948,8 @@ async function importExtensionFromCssText(projectDir, css, name) {
11874
11948
  const displayName = name.trim() || "Imported theme";
11875
11949
  const tmp = await mkdtemp3(path19.join(tmpdir3(), "gutterpress-theme-"));
11876
11950
  try {
11877
- await writeFile7(path19.join(tmp, "theme.css"), css, "utf8");
11878
- await writeFile7(path19.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify({ name: slugify(displayName, "look"), gutterpress: { styles: ["theme.css"] } }, null, 2), "utf8");
11951
+ await writeFile8(path19.join(tmp, "theme.css"), css, "utf8");
11952
+ await writeFile8(path19.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify({ name: slugify(displayName, "look"), gutterpress: { styles: ["theme.css"] } }, null, 2), "utf8");
11879
11953
  const result = await finalizeExtensionImport(projectDir, tmp, ["theme.css", EXTENSION_MANIFEST_FILENAME], displayName);
11880
11954
  result.warnings.unshift({
11881
11955
  code: "no-theme-json",
@@ -11889,11 +11963,11 @@ async function importExtensionFromCssText(projectDir, css, name) {
11889
11963
  async function importExtensionFromFile(projectDir, filePath) {
11890
11964
  const ext = path19.extname(filePath).toLowerCase();
11891
11965
  if (ext === ".zip") {
11892
- const buf = await readFile28(filePath);
11966
+ const buf = await readFile29(filePath);
11893
11967
  return importExtensionFromZip(projectDir, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
11894
11968
  }
11895
11969
  if (ext === ".css") {
11896
- const css = await readFile28(filePath, "utf8");
11970
+ const css = await readFile29(filePath, "utf8");
11897
11971
  return importExtensionFromCssText(projectDir, css, prettify(path19.basename(filePath, ".css")));
11898
11972
  }
11899
11973
  throw new Error("Choose a .zip extension package or a .css stylesheet.");
@@ -11958,7 +12032,7 @@ async function importExtensionFromUrl(projectDir, url) {
11958
12032
  assertLooksLikeCss(css, trimmed);
11959
12033
  const tmp = await mkdtemp3(path19.join(tmpdir3(), "gutterpress-ext-"));
11960
12034
  try {
11961
- await writeFile7(path19.join(tmp, "theme.css"), css, "utf8");
12035
+ await writeFile8(path19.join(tmp, "theme.css"), css, "utf8");
11962
12036
  const gp = meta.gutterpress && typeof meta.gutterpress === "object" && !Array.isArray(meta.gutterpress) ? meta.gutterpress : {};
11963
12037
  const finalMeta = {
11964
12038
  name: typeof meta.name === "string" && meta.name || slugify(baseName, "look"),
@@ -11970,7 +12044,7 @@ async function importExtensionFromUrl(projectDir, url) {
11970
12044
  preview: typeof gp.preview === "string" ? gp.preview : null
11971
12045
  }
11972
12046
  };
11973
- await writeFile7(path19.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify(finalMeta, null, 2), "utf8");
12047
+ await writeFile8(path19.join(tmp, EXTENSION_MANIFEST_FILENAME), JSON.stringify(finalMeta, null, 2), "utf8");
11974
12048
  return await finalizeExtensionImport(projectDir, tmp, ["theme.css", EXTENSION_MANIFEST_FILENAME], baseName);
11975
12049
  } finally {
11976
12050
  await rm5(tmp, { recursive: true, force: true });
@@ -12596,7 +12670,7 @@ ${tail}` : ""}`);
12596
12670
  };
12597
12671
 
12598
12672
  // src/lib/publish/providers/guided.ts
12599
- import { copyFile as copyFile2, mkdir as mkdir11, writeFile as writeFile8 } from "node:fs/promises";
12673
+ import { copyFile as copyFile2, mkdir as mkdir11, writeFile as writeFile9 } from "node:fs/promises";
12600
12674
  import path20 from "node:path";
12601
12675
  async function stageGuidedPackage(req, providerId, listingLines) {
12602
12676
  const packageDir = path20.join(path20.dirname(req.artifact.path), "publish", providerId);
@@ -12614,7 +12688,7 @@ async function stageGuidedPackage(req, providerId, listingLines) {
12614
12688
  ""
12615
12689
  ].join(`
12616
12690
  `);
12617
- await writeFile8(path20.join(packageDir, "LISTING.md"), sheet, "utf8");
12691
+ await writeFile9(path20.join(packageDir, "LISTING.md"), sheet, "utf8");
12618
12692
  return packageDir;
12619
12693
  }
12620
12694
 
@@ -12677,7 +12751,7 @@ var drivethrurpgProvider = {
12677
12751
  };
12678
12752
 
12679
12753
  // src/lib/publish/providers/gdrive.ts
12680
- import { mkdtemp as mkdtemp4, readFile as readFile29, readdir as readdir6, rm as rm6, stat as stat7, writeFile as writeFile9 } from "node:fs/promises";
12754
+ import { mkdtemp as mkdtemp4, readFile as readFile30, readdir as readdir6, rm as rm6, stat as stat7, writeFile as writeFile10 } from "node:fs/promises";
12681
12755
  import { tmpdir as tmpdir4 } from "node:os";
12682
12756
  import path21 from "node:path";
12683
12757
  import { Zip, ZipDeflate } from "fflate";
@@ -13069,12 +13143,12 @@ async function collectZipEntries(root, dir, out, onWarn) {
13069
13143
  await collectZipEntries(root, full, out, onWarn);
13070
13144
  } else if (entry.isFile()) {
13071
13145
  const rel = path21.relative(root, full).split(path21.sep).join("/");
13072
- out[rel] = await readFile29(full);
13146
+ out[rel] = await readFile30(full);
13073
13147
  } else if (entry.isSymbolicLink()) {
13074
13148
  const resolved = await stat7(full).catch(() => null);
13075
13149
  if (resolved?.isFile()) {
13076
13150
  const rel = path21.relative(root, full).split(path21.sep).join("/");
13077
- out[rel] = await readFile29(full);
13151
+ out[rel] = await readFile30(full);
13078
13152
  } else if (resolved?.isDirectory()) {
13079
13153
  await collectZipEntries(root, full, out, onWarn);
13080
13154
  } else {
@@ -13085,7 +13159,7 @@ async function collectZipEntries(root, dir, out, onWarn) {
13085
13159
  }
13086
13160
  }
13087
13161
  }
13088
- async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeFile9) {
13162
+ async function zipHtmlExport(exportDir, title, onWarn, writeArchiveImpl = writeFile10) {
13089
13163
  const entries = {};
13090
13164
  await collectZipEntries(exportDir, exportDir, entries, onWarn);
13091
13165
  const fileName = `${bookSlug(title)}-website.zip`;
@@ -13189,7 +13263,7 @@ var gdriveProvider = {
13189
13263
  };
13190
13264
 
13191
13265
  // src/lib/publish/butler.ts
13192
- import { chmod, mkdir as mkdir12, stat as stat8, writeFile as writeFile10 } from "node:fs/promises";
13266
+ import { chmod, mkdir as mkdir12, stat as stat8, writeFile as writeFile11 } from "node:fs/promises";
13193
13267
  import path22 from "node:path";
13194
13268
  import { unzipSync as unzipSync2 } from "fflate";
13195
13269
  var BUTLER_DOWNLOAD_TIMEOUT_MS = 300000;
@@ -13256,7 +13330,7 @@ async function ensureButler(deps) {
13256
13330
  if (name.endsWith("/"))
13257
13331
  continue;
13258
13332
  const target = path22.join(cacheDir, path22.basename(name));
13259
- await writeFile10(target, data);
13333
+ await writeFile11(target, data);
13260
13334
  if (path22.basename(name) === butlerBinaryName()) {
13261
13335
  await chmod(target, 493).catch(() => {});
13262
13336
  foundBinary = true;
@@ -14005,7 +14079,7 @@ import git6 from "isomorphic-git";
14005
14079
  import git5 from "isomorphic-git";
14006
14080
  import diff3Merge from "diff3";
14007
14081
  // src/lib/publish/selections.ts
14008
- import { chmod as chmod2, mkdir as mkdir13, readFile as readFile30, writeFile as writeFile11 } from "node:fs/promises";
14082
+ import { chmod as chmod2, mkdir as mkdir13, readFile as readFile31, writeFile as writeFile12 } from "node:fs/promises";
14009
14083
  import path24 from "node:path";
14010
14084
  class PublishSelectionsStore {
14011
14085
  filePath;
@@ -14015,7 +14089,7 @@ class PublishSelectionsStore {
14015
14089
  }
14016
14090
  async read() {
14017
14091
  try {
14018
- const raw = await readFile30(this.filePath, "utf8");
14092
+ const raw = await readFile31(this.filePath, "utf8");
14019
14093
  const parsed = JSON.parse(raw);
14020
14094
  if (parsed && typeof parsed === "object") {
14021
14095
  return {
@@ -14029,7 +14103,7 @@ class PublishSelectionsStore {
14029
14103
  }
14030
14104
  async write(data) {
14031
14105
  await mkdir13(path24.dirname(this.filePath), { recursive: true });
14032
- await writeFile11(this.filePath, JSON.stringify(data, null, 2), {
14106
+ await writeFile12(this.filePath, JSON.stringify(data, null, 2), {
14033
14107
  encoding: "utf8",
14034
14108
  mode: 384
14035
14109
  });
@@ -14096,7 +14170,7 @@ function normalizeProjectKey(projectDir) {
14096
14170
  import { isMap as isMap4 } from "yaml";
14097
14171
  // src/lib/lint-runner.ts
14098
14172
  import { resolve as resolve8 } from "node:path";
14099
- import { readFile as readFile31 } from "node:fs/promises";
14173
+ import { readFile as readFile32 } from "node:fs/promises";
14100
14174
  async function runLint(opts = {}) {
14101
14175
  const { glob } = await import("glob");
14102
14176
  const { manifest, manifestDir } = await loadManifestWithPath(opts.manifest, {
@@ -14127,7 +14201,7 @@ async function runLint(opts = {}) {
14127
14201
  for (const file of files) {
14128
14202
  let css;
14129
14203
  try {
14130
- css = await readFile31(file, "utf8");
14204
+ css = await readFile32(file, "utf8");
14131
14205
  } catch (err) {
14132
14206
  log.error(` ${file}`);
14133
14207
  log.error(` cannot read stylesheet: ${err instanceof Error ? err.message : String(err)}`);