gutterpress 0.11.10 → 0.11.11-alpha.2

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 (92) hide show
  1. package/README.md +3 -3
  2. package/dist/api/index.js +2 -2
  3. package/dist/{build-83dnh2qe.js → build-pjd42x09.js} +4 -4
  4. package/dist/checks/asset/extensions.d.ts +2 -2
  5. package/dist/checks/policy.d.ts +5 -7
  6. package/dist/checks/register-builtins.d.ts +6 -6
  7. package/dist/checks/registry.d.ts +1 -1
  8. package/dist/{cli-79tsqp3p.js → cli-1kdtzgxm.js} +1 -1
  9. package/dist/{cli-mv1mhpkk.js → cli-d2he8zph.js} +6 -6
  10. package/dist/{cli-b36za51e.js → cli-ny50k8md.js} +3 -3
  11. package/dist/{cli-30j93gzt.js → cli-tjhn2mdn.js} +3 -3
  12. package/dist/cli.js +12 -12
  13. package/dist/{doctor-sy4gc8r9.js → doctor-qkh9byxa.js} +2 -2
  14. package/dist/engine/shared/cdp.d.ts +5 -9
  15. package/dist/engine/shared/pdf-inspect.d.ts +0 -4
  16. package/dist/{engine-mwshptgf.js → engine-132czsq9.js} +1 -1
  17. package/dist/{engine-3gwctsty.js → engine-bgd4aa99.js} +2 -2
  18. package/dist/{ext-a7ffvyc0.js → ext-271xnh70.js} +4 -4
  19. package/dist/{index-dzp0hc2c.js → index-b6p1fh61.js} +1 -1
  20. package/dist/{index-r4wvy5v3.js → index-mw8b25yx.js} +3 -3
  21. package/dist/{index-0cvkvpkg.js → index-ssjh6tnd.js} +7 -7
  22. package/dist/index.js +3 -3
  23. package/dist/lib/asset-inline.d.ts +1 -2
  24. package/dist/lib/build-error.d.ts +4 -6
  25. package/dist/lib/build-fingerprint.d.ts +3 -4
  26. package/dist/lib/build-preflight.d.ts +4 -6
  27. package/dist/lib/build-runner.d.ts +24 -35
  28. package/dist/lib/build-staging.d.ts +3 -5
  29. package/dist/lib/cli-args.d.ts +1 -1
  30. package/dist/lib/desktop.d.ts +2 -8
  31. package/dist/lib/engine.d.ts +2 -2
  32. package/dist/lib/exec.d.ts +3 -6
  33. package/dist/lib/fetch-timeout.d.ts +3 -4
  34. package/dist/lib/ghostscript.d.ts +1 -1
  35. package/dist/lib/host-policy.d.ts +6 -8
  36. package/dist/lib/image-inspect.d.ts +2 -2
  37. package/dist/lib/install-hints.d.ts +2 -3
  38. package/dist/lib/manifest-config.d.ts +2 -3
  39. package/dist/lib/manifest-doc.d.ts +2 -3
  40. package/dist/lib/manifest.d.ts +4 -7
  41. package/dist/lib/markdown/assemble.d.ts +7 -13
  42. package/dist/lib/markdown/gutterpress-css.d.ts +6 -9
  43. package/dist/lib/markdown/images.d.ts +0 -7
  44. package/dist/lib/markdown/index.d.ts +7 -11
  45. package/dist/lib/markdown/markers.d.ts +3 -4
  46. package/dist/lib/markdown/plugins.d.ts +9 -12
  47. package/dist/lib/markdown/renderer.d.ts +10 -14
  48. package/dist/lib/missing-asset-placeholder.d.ts +2 -5
  49. package/dist/lib/output-paths.d.ts +4 -5
  50. package/dist/lib/pdf-inspect.d.ts +5 -5
  51. package/dist/lib/pdf-parse.d.ts +6 -7
  52. package/dist/lib/presets.d.ts +2 -3
  53. package/dist/lib/project-source.d.ts +3 -4
  54. package/dist/lib/publish/command-runner.d.ts +1 -1
  55. package/dist/lib/publish/connect-google.d.ts +2 -2
  56. package/dist/lib/publish/types.d.ts +3 -3
  57. package/dist/lib/remote-auth/clone.d.ts +2 -2
  58. package/dist/lib/remote-auth/converge-merge.d.ts +1 -1
  59. package/dist/lib/remote-auth/diagnose.d.ts +3 -3
  60. package/dist/lib/remote-auth/generic-auth.d.ts +1 -1
  61. package/dist/lib/remote-auth/git-http.d.ts +5 -5
  62. package/dist/lib/remote-auth/github-auth.d.ts +3 -3
  63. package/dist/lib/remote-auth/github-repos.d.ts +4 -4
  64. package/dist/lib/remote-auth/sync-types.d.ts +1 -1
  65. package/dist/lib/remote-auth/sync.d.ts +1 -1
  66. package/dist/lib/remote-auth/test-access.d.ts +1 -1
  67. package/dist/lib/remote-auth/token-store.d.ts +1 -1
  68. package/dist/lib/remote-auth/transport.d.ts +3 -3
  69. package/dist/lib/render-parity-raster.d.ts +28 -0
  70. package/dist/lib/render-parity.d.ts +4 -1
  71. package/dist/lib/source-provider.d.ts +4 -5
  72. package/dist/lib/static-serve.d.ts +8 -13
  73. package/dist/lib/style-resolver.d.ts +1 -1
  74. package/dist/lib/targets.d.ts +1 -5
  75. package/dist/lib/tool-probe.d.ts +2 -3
  76. package/dist/lib/validation-exec.d.ts +3 -4
  77. package/dist/{new-994trd8k.js → new-7w4ezfpy.js} +4 -4
  78. package/dist/platform.d.ts +8 -41
  79. package/dist/{preflight-2rtrakyf.js → preflight-f3h6arjp.js} +4 -4
  80. package/dist/preview/file-watcher.d.ts +3 -5
  81. package/dist/preview/lifecycle.d.ts +9 -17
  82. package/dist/{preview-bridge-b4jbtb79.js → preview-bridge-8jhd1wpb.js} +1 -1
  83. package/dist/{preview-interface-9rwz21yw.js → preview-interface-twd6nsf5.js} +74 -13
  84. package/dist/{preview-shell-tqndvhbx.js → preview-shell-y8yrm3f0.js} +8 -19
  85. package/dist/{preview-n9s46142.js → preview-y39jrpbs.js} +4 -4
  86. package/dist/{publish-wte9548r.js → publish-tvj3xh8m.js} +4 -4
  87. package/dist/render.d.ts +5 -5
  88. package/dist/render.js +2 -2
  89. package/dist/schema/manifest.types.d.ts +2 -2
  90. package/dist/utils/logger.d.ts +1 -2
  91. package/dist/{validate-jfsh3m1c.js → validate-9enr4ecc.js} +4 -4
  92. package/package.json +3 -3
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Pure (node-free) markdown rendering core.
3
3
  *
4
- * §1/§8 / ADR 0004: this module imports ONLY pure JS — markdown-it and its
4
+ * §1/§8: this module imports ONLY pure JS — markdown-it and its
5
5
  * plugins, Gutterpress's inlined marker parser (`markers.js`), and the node-free
6
6
  * leveled logger (console-only). It contains NO `node:*`,
7
7
  * NO `fs`/`path`/`url`, and NO filesystem access, so it can be imported by the
8
- * browser renderer (the PWA WebAdapter, #33) AND bundled into the
8
+ * browser AND bundled into the
9
9
  * `bun build --compile` CLI binary alike.
10
10
  *
11
11
  * The plugin *author* types and the markdown-it factory live here (not in
@@ -201,22 +201,18 @@ export declare const BUILTIN_OPTIONAL_PLUGINS: Record<string, GutterpressPlugin>
201
201
  * `<dl><dt><dd>`. It is not in CommonMark/markdown-it core; this is the
202
202
  * canonical markdown-it plugin for it.
203
203
  *
204
- * Block container syntax (`:::name ... :::`) was removed 2026-05-17 in favor
205
- * of the @marker family. See docs/migrations/2026-05-removing-container-syntax.md
206
- * for the migration mapping.
204
+ * There is no block container syntax (`:::name ... :::`): the @marker family
205
+ * is the wrapped-block surface. See
206
+ * docs/migrations/2026-05-removing-container-syntax.md for the mapping.
207
207
  *
208
- * GFM-style `> [!NOTE]` alerts were also moved into the DC plugin on the
209
- * same date because the emitted classes (dc-alert, dc-vibe-callout, etc.)
210
- * were DC-branded — core should not leak DC identifiers. #237 (0.10.7)
211
- * restored a core-owned, unbranded equivalent as an OPT-IN bundled feature —
208
+ * GFM-style `> [!NOTE]` alerts are an OPT-IN bundled feature (#237) —
212
209
  * `gfm-alerts.ts`, registered below as `gutterpress-gfm-alerts` — emitting
213
210
  * only the standard GitHub five (NOTE/TIP/IMPORTANT/WARNING/CAUTION) as
214
211
  * neutral `gp-alert`/`gp-alert-<type>` structure (see that file's header).
215
- * This does not re-converge with the DC plugin: DC's branded extra types
216
- * (`[!DM]`/`[!VIBE]`/`[!ORIGIN]`, etc.) and its own class names stay exactly
217
- * where they were moved to, layered on top of (or independent from) this
218
- * primitive. A project using neither plugin still renders `> [!NOTE]` as a
219
- * literal blockquote, unchanged — this feature is opt-in, not a default.
212
+ * Core emits no branded identifiers: branded extra types (e.g. DC's
213
+ * `[!DM]`/`[!VIBE]`/`[!ORIGIN]`) and their class names belong in project
214
+ * plugins, layered on top of (or independent from) this primitive. A project
215
+ * using neither renders `> [!NOTE]` as a literal blockquote.
220
216
  *
221
217
  * #240 — before `gutterpressMarkers` is applied, every loaded plugin's
222
218
  * declared `markers` table (if any) is merged into ONE registry via
@@ -1,15 +1,12 @@
1
1
  /**
2
2
  * A visible stand-in for an image the book references but does not have.
3
3
  *
4
- * WHY THIS EXISTS: a missing image used to abort the whole build
4
+ * WHY THIS EXISTS: without it, a missing image aborts the whole build
5
5
  * (`Could not copy asset … ENOENT`). For a non-technical author that is the
6
6
  * worst possible failure mode — one stale image path in a 273-page book and
7
7
  * nothing renders at all, with a filesystem error as the only explanation.
8
8
  * Worse, it makes the book unbuildable by anyone who does not already have
9
- * the missing file, which is exactly the state the dc-op-manual field guide
10
- * was in: two chapters referenced art that exists nowhere in the repo, so
11
- * every tool and every reviewer had to hand-patch placeholders in to build
12
- * it at all.
9
+ * the missing file.
13
10
  *
14
11
  * The fix is NOT to substitute something invisible. A silently-blank image
15
12
  * is how a missing illustration ships to print. This paints an unmistakable
@@ -2,11 +2,10 @@
2
2
  * Output location + artifact naming, by convention rather than configuration.
3
3
  *
4
4
  * A book builds to `<manifestDir>/dist/<title-slug>/`, and its artifacts are
5
- * `<title-slug>-<format>.pdf`. This replaces the manifest's `output.dir` /
6
- * `output.filename` / `output.html` block: the slug keeps several books in one
7
- * tree apart, and the format is in the artifact name because the extension
8
- * cannot tell a PDF from a PDF/X one (they previously shared a single
9
- * configured filename, so building both left only the last).
5
+ * `<title-slug>-<format>.pdf` — a convention, not manifest configuration: the
6
+ * slug keeps several books in one tree apart, and the format is in the
7
+ * artifact name because the extension cannot tell a PDF from a PDF/X one (a
8
+ * shared filename would leave only the last one built).
10
9
  *
11
10
  * `--out` remains for per-invocation placement (CI, one-offs).
12
11
  */
@@ -5,7 +5,7 @@
5
5
  * pdfimages, pdftotext) and the general qpdf inspection used by the post-build
6
6
  * validation checks. It has ZERO system dependency and — unlike raw pdfjs-dist,
7
7
  * whose `legacy` build eagerly evaluates canvas/DOMMatrix code — unpdf bundles
8
- * cleanly under `bun build --compile` (verified). See ADR 0002.
8
+ * cleanly under `bun build --compile` (verified).
9
9
  *
10
10
  * NOT replaced here (still system tools, by design):
11
11
  * - Ghostscript (gs): ink coverage + PDF/X CMYK conversion — no JS equivalent.
@@ -13,7 +13,7 @@
13
13
  * catalog/object access pdfjs has no public API for, and qpdf is already
14
14
  * mandatory whenever PDF/X is produced.
15
15
  *
16
- * Fidelity notes (accepted in ADR 0002):
16
+ * Fidelity notes (accepted):
17
17
  * - Structural integrity (`isLoadable`) is a "does it parse" gate, not a deep
18
18
  * `qpdf --check` of xref/stream-length integrity.
19
19
  * - Image DPI requires decoding the image to read its pixel dimensions and is
@@ -25,10 +25,10 @@
25
25
  */
26
26
  import type { PDFDocumentProxy, PDFPageProxy } from "unpdf/pdfjs";
27
27
  /**
28
- * Cap on distinct cached documents (audit B3). One validation run touches a
28
+ * Cap on distinct cached documents. One validation run touches a
29
29
  * single PDF across ~13 checks (one entry), so this only bounds accumulation
30
30
  * ACROSS runs in a long-lived host (the Electron desktop validating many
31
- * projects over a session). Without it, `docCache` grew one never-freed parsed
31
+ * projects over a session). Without it, `docCache` grows one never-freed parsed
32
32
  * document per distinct path ever validated. LRU eviction destroys the evicted
33
33
  * document so its decoded pages/fonts/images are released, not just unreferenced.
34
34
  * (Exported so tests derive their eviction fixtures from the real cap.)
@@ -146,6 +146,6 @@ export declare function getImageResolutions(doc: PDFDocumentProxy): Promise<Arra
146
146
  /**
147
147
  * "Does it parse" gate: load every page. Returns true if the whole document is
148
148
  * traversable. This is NOT a deep xref/stream-length integrity check — it only
149
- * catches PDFs that are actually broken/unparseable (ADR 0002).
149
+ * catches PDFs that are actually broken/unparseable.
150
150
  */
151
151
  export declare function isLoadable(doc: PDFDocumentProxy): Promise<boolean>;
@@ -15,7 +15,7 @@ export declare function readPdfBytes(pdfPath: string): Promise<string>;
15
15
  /**
16
16
  * Parse ink coverage from `gs -sDEVICE=inkcov` output.
17
17
  *
18
- * Ghostscript has no pure-JS equivalent (it stays a system tool — see ADR 0002),
18
+ * Ghostscript has no pure-JS equivalent (it stays a system tool),
19
19
  * so the inkcov path remains shell-based here.
20
20
  */
21
21
  export declare function parseInkCov(out: string): {
@@ -34,12 +34,11 @@ interface InkCoveragePage {
34
34
  tac: number;
35
35
  }
36
36
  /**
37
- * Discriminated result for {@link getPerPageInkCoverage} (finding #51).
38
- * Ghostscript failing (crash, corrupt PDF, missing binary, a Windows PATH
39
- * mismatch — see finding #3) must be distinguishable from a legitimately
40
- * measured, empty-pages result: both used to collapse to the same `[]`,
41
- * which let the ink-coverage check silently PASS a book it never actually
42
- * measured.
37
+ * Discriminated result for {@link getPerPageInkCoverage}. Ghostscript failing
38
+ * (crash, corrupt PDF, missing binary, a Windows PATH mismatch) must be
39
+ * distinguishable from a legitimately measured, empty-pages result:
40
+ * collapsing both to the same `[]` would let the ink-coverage check silently
41
+ * PASS a book it never actually measured.
43
42
  */
44
43
  export type InkCoverageResult = {
45
44
  ok: true;
@@ -24,7 +24,7 @@ export type PresetId = (typeof PRESET_IDS)[number];
24
24
  export declare const DTRPG_PRESET: VendorPreset;
25
25
  /**
26
26
  * A neutral, vendor-agnostic default for authors who aren't targeting a
27
- * specific print vendor (UX finding M48). Standard 6x9in trade-book trim size,
27
+ * specific print vendor. Standard 6x9in trade-book trim size,
28
28
  * no vendor total-area-coverage (TAC) cap, and no PDF/X forcing:
29
29
  *
30
30
  * - `page`: 6in x 9in (432 x 648pt) — the common generic trade paperback trim.
@@ -57,8 +57,7 @@ export declare function warnOnce(id: string, message: string, sink?: (msg: strin
57
57
  /** Test-only reset hook — clears all warn-once dedup state. */
58
58
  export declare function resetWarnOnce(): void;
59
59
  /**
60
- * Resolve a manifest/CLI `preset` value to the {@link VendorPreset} it names
61
- * (UX finding M48).
60
+ * Resolve a manifest/CLI `preset` value to the {@link VendorPreset} it names.
62
61
  *
63
62
  * - Unset (`undefined`): defaults to `dtrpg`. That is the PRODUCT default,
64
63
  * not a compatibility accident (ADR 0008): Gutterpress's primary audience
@@ -41,7 +41,7 @@ export type ProjectSource = {
41
41
  * What the UI may offer for a given source. Derived purely from the source
42
42
  * type; no I/O.
43
43
  *
44
- * NOTE (audit D5): today the desktop only reads `canSnapshot` (it gates the
44
+ * NOTE: today the desktop only reads `canSnapshot` (it gates the
45
45
  * StatusBar "Version history" affordance). The other flags —
46
46
  * `canEnableVersionHistory`, `canViewHistory`, `canRestoreSnapshot`, `canRead`,
47
47
  * `canWriteLocal`, `authManagedByApp` — are computed and part of the DTO but
@@ -51,9 +51,8 @@ export type ProjectSource = {
51
51
  *
52
52
  * Deliberately NO `canSync` here: syncability is a credential-aware question
53
53
  * only `diagnoseProjectRemote().canSync` (remote-auth/diagnose.ts) can answer.
54
- * This interface used to carry a second, weaker `canSync` (= hasRemote, any
55
- * protocol, no credential check), and the two same-named-but-different gates
56
- * were a recurring source of contradictory sync behavior. Remote PRESENCE, for
54
+ * A second, weaker `canSync` here (= hasRemote, any protocol, no credential
55
+ * check) would be a source of contradictory sync behavior. Remote PRESENCE, for
57
56
  * display purposes, lives on the classification itself (`source.hasRemote`).
58
57
  */
59
58
  export interface ProjectCapabilities {
@@ -1,6 +1,6 @@
1
1
  import type { CommandRunner } from "./types.ts";
2
2
  /**
3
- * Default idle budget (audit B2 / review): applied BY THE RUNNER whenever
3
+ * Default idle budget: applied BY THE RUNNER whenever
4
4
  * `timeoutMs` is omitted, so no call site (a provider upload, a
5
5
  * `commandExists` probe) can silently regain hang-forever behavior by
6
6
  * forgetting to pass it. `timeoutMs: 0` is the explicit opt-out. Idle, not
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Shared Google Drive connect flow (#221) — the ONE implementation behind
3
- * both the CLI's `--connect` branch and (Phase 2) the desktop's connect
4
- * route, mirroring how `connect.ts` is shared for pasted-token providers.
3
+ * both the CLI's `--connect` branch and the desktop's connect route, mirroring
4
+ * how `connect.ts` is shared for pasted-token providers.
5
5
  *
6
6
  * Unlike `connectPublishProvider` (verify-before-store for a PASTED token),
7
7
  * this flow is verify-by-construction: `GoogleAuthProvider.connect()` only
@@ -6,7 +6,7 @@
6
6
  * (DriveThruRPG, Amazon KDP), stages a validated upload package and hands the
7
7
  * author a checklist + the platform's upload URL ("guided" publishing).
8
8
  *
9
- * Architecture mirrors the remote-auth subsystem (ADR 0006):
9
+ * Architecture mirrors the remote-auth subsystem:
10
10
  * - The lib NEVER touches OS keychains, the network, or child processes
11
11
  * directly through ambient globals — hosts inject a {@link TokenStore},
12
12
  * and tests inject {@link PublishDeps.fetch} / {@link PublishDeps.runCommand}.
@@ -89,7 +89,7 @@ export interface PublishProviderInfo {
89
89
  * browser consent flow (see `google-auth.ts`'s `GoogleAuthProvider` for
90
90
  * the gdrive precedent). UIs branch on this to swap the paste-a-key form
91
91
  * for a "Connect …" button; {@link connectPublishProvider} REJECTS oauth
92
- * providers outright so the old paste-a-token path can never store an
92
+ * providers outright so the paste-a-token path can never store an
93
93
  * unverifiable credential for one (#221).
94
94
  */
95
95
  connect?: "token" | "oauth";
@@ -135,7 +135,7 @@ export type CommandRunner = (cmd: string, args: string[], options?: {
135
135
  /** Called once per output line — drives live progress logs. */
136
136
  onOutput?: (line: string) => void;
137
137
  /**
138
- * Idle-kill budget in ms (audit B2). If the child produces no output and
138
+ * Idle-kill budget in ms. If the child produces no output and
139
139
  * has not exited within this window, it is SIGKILL'd and the run rejects
140
140
  * with a timeout error, so a stalled upload can't hang publish forever.
141
141
  * Omitted / undefined = the runner's default (defaultCommandRunner applies
@@ -54,9 +54,9 @@ export interface CloneRepositoryResult {
54
54
  */
55
55
  export declare function sanitizeCloneFolderName(name: string): string;
56
56
  /**
57
- * Clone a remote repository over smart HTTPS into `dir` (ADR 0006 D2).
57
+ * Clone a remote repository over smart HTTPS into `dir`.
58
58
  *
59
- * - HTTPS only (isomorphic-git has no SSH — ADR 0006 D6).
59
+ * - HTTPS only (isomorphic-git has no SSH).
60
60
  * - `singleBranch` always; `depth` opts into shallow (full by default — see
61
61
  * the WHY on {@link CloneRepositoryOptions.depth}).
62
62
  * - Tokens embedded in the URL are stripped and (when a `tokenStore` is
@@ -32,7 +32,7 @@ export interface ConvergeResult {
32
32
  export declare const CONVERGE_PREPARE_MESSAGE = "Getting your changes ready to combine with the online version";
33
33
  /** Snapshot message for the post-merge restore commit (kept-both/edits). */
34
34
  export declare const CONVERGE_RESTORE_MESSAGE = "Kept both versions of the files that can't be combined";
35
- /** The merge commit message (same wording the old sync used). */
35
+ /** The merge commit message. */
36
36
  export declare const CONVERGE_MERGE_MESSAGE = "Combined your changes with the online version";
37
37
  /**
38
38
  * diff3 merge that NEVER reports a conflict: clean hunks merge exactly like
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Project remote diagnostics (#14, ADR 0006 D7).
2
+ * Project remote diagnostics (#14).
3
3
  *
4
4
  * Pure-lib replacement for the issue's original shell diagnostics
5
5
  * (`git status` / `git remote -v` / `git branch --show-current` — all
@@ -26,7 +26,7 @@ export type ForgeKind = "github" | "gitea" | "forgejo" | "gitlab" | "bitbucket"
26
26
  * - `ready-to-sync` — HTTPS remote with a stored credential (sync lands
27
27
  * with #15's sync phase; the plumbing is in place).
28
28
  * - `ssh-use-own-tools` — SSH remote: full local features, sync externally
29
- * (ADR 0006 D6). The UI layers the "switch to HTTPS" hint on recognized hosts.
29
+ * . The UI layers the "switch to HTTPS" hint on recognized hosts.
30
30
  */
31
31
  export type RemoteGuidanceId = "local-only" | "connect-github-to-sync" | "https-connect-server" | "ready-to-sync" | "ssh-use-own-tools";
32
32
  export interface ProjectRemoteDiagnosis {
@@ -45,7 +45,7 @@ export interface ProjectRemoteDiagnosis {
45
45
  /** Token-settings deep link for recognized non-GitHub forges. */
46
46
  tokenSettingsUrl: string | null;
47
47
  /**
48
- * ADR 0006 D4: hasRemote && smart-HTTPS && credential stored. The sync
48
+ * hasRemote && smart-HTTPS && credential stored. The sync
49
49
  * flow (#15 D5) is live, so this is the real "offer the Sync action"
50
50
  * gate, not a future-capability hint.
51
51
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Generic token auth provider (#14, ADR 0006 D3 layer 3).
2
+ * Generic token auth provider (#14).
3
3
  *
4
4
  * The universal floor for every smart-HTTPS Git host that is not github.com:
5
5
  * the user pastes a host URL + (optional) username + access token collected by
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Timeout wrapper for the isomorphic-git HTTP client (audit B1).
2
+ * Timeout wrapper for the isomorphic-git HTTP client.
3
3
  *
4
4
  * Every git transport call in this subsystem (`git.fetch`/`git.push`/
5
5
  * `git.clone`) is invoked with no timeout: if the TCP connection succeeds but
@@ -11,7 +11,7 @@
11
11
  * guard every fetch with `AbortSignal.timeout`; this brings the same discipline
12
12
  * to the git transport, at the one place a default client is chosen.
13
13
  *
14
- * Design (review finding: a naive deadline on `request()` is WRONG for pushes):
14
+ * Design (a naive deadline on `request()` is WRONG for pushes):
15
15
  * isomorphic-git passes upload bodies as an ARRAY of buffers, which the node
16
16
  * client collects and sends with Content-Length — `request()` then resolves
17
17
  * only when the response HEADERS arrive, i.e. after the ENTIRE pack upload.
@@ -67,9 +67,9 @@ export declare const SMALL_BODY_MAX_BYTES: number;
67
67
  * {@link SMALL_BODY_MAX_BYTES}. isomorphic-git always passes bodies as arrays
68
68
  * of byte chunks, so small ones are sizable synchronously. Any chunk WITHOUT
69
69
  * a numeric byteLength makes the body unsizable → NOT small, so it gets the
70
- * long upload backstop rather than the idle deadline as a total cap (review
71
- * finding: the old reduce counted unsizable chunks as 0 bytes — the exact
72
- * opposite of that intent).
70
+ * long upload backstop rather than the idle deadline as a total cap (do not
71
+ * count unsizable chunks as 0 bytes — that is the exact opposite of that
72
+ * intent).
73
73
  */
74
74
  export declare function isSmallBody(body: unknown): boolean;
75
75
  /**
@@ -10,7 +10,7 @@ export interface DeviceCodeInfo {
10
10
  /** Minimum seconds between token polls. */
11
11
  interval: number;
12
12
  }
13
- /** Host-supplied callbacks for the interactive connect flow (ADR 0006 D3). */
13
+ /** Host-supplied callbacks for the interactive connect flow. */
14
14
  export interface HostCallbacks {
15
15
  /** Called once with the code/URL so the UI can display them. */
16
16
  onUserCode(info: DeviceCodeInfo): void;
@@ -25,7 +25,7 @@ export interface HostCallbacks {
25
25
  */
26
26
  export declare function resolveGitHubClientId(explicit?: string): string;
27
27
  export declare const GITHUB_HOST = "github.com";
28
- /** Author-friendly message for connectivity failures (ADR 0006 D7). */
28
+ /** Author-friendly message for connectivity failures. */
29
29
  export declare const OFFLINE_MESSAGE = "Couldn't reach GitHub. Check your connection and try again.";
30
30
  export interface GitHubAuthProviderOptions {
31
31
  /** Explicit client id (overrides env + default). */
@@ -35,7 +35,7 @@ export interface GitHubAuthProviderOptions {
35
35
  /** Injectable sleep for tests (so polling tests run instantly). */
36
36
  sleepImpl?: (ms: number) => Promise<void>;
37
37
  }
38
- /** GitHub device-flow credential acquisition (ADR 0006 D1). */
38
+ /** GitHub device-flow credential acquisition. */
39
39
  export declare class GitHubAuthProvider {
40
40
  private readonly clientId;
41
41
  private readonly fetchImpl;
@@ -1,9 +1,9 @@
1
1
  /**
2
- * GitHub repo discovery (#15, ADR 0006 D3 layer 4).
2
+ * GitHub repo discovery (#15).
3
3
  *
4
4
  * Plain `fetch` against the GitHub REST API — deliberately no `@octokit`
5
5
  * dependency. Lists every repository the user can access (`GET /user/repos`,
6
- * the OAuth `repo`-scope model — ADR 0006 D1 amendment 2026-06-10), the
6
+ * the OAuth `repo`-scope model), the
7
7
  * branches of a chosen repository, and (via the Git Trees API) the gutterpress
8
8
  * book projects inside a repo. The two REST listings paginate; the Git Trees
9
9
  * call is a single request that handles the API's `truncated` flag instead. All
@@ -31,8 +31,8 @@ export interface GitHubApiOptions {
31
31
  /**
32
32
  * List every repository the user can access — own, collaborator, and org
33
33
  * member — via `GET /user/repos` (paginated). The OAuth `repo` scope makes
34
- * the full set visible with zero install/selection steps (ADR 0006 D1
35
- * amendment). `sort=pushed` puts recently-active books first; callers must
34
+ * the full set visible with zero install/selection steps. `sort=pushed` puts
35
+ * recently-active books first; callers must
36
36
  * PRESERVE this order (the picker renders it as "most recent first").
37
37
  */
38
38
  export declare function listGitHubRepositories(credential: HostCredential, options?: GitHubApiOptions): Promise<RemoteRepository[]>;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Type/interface declarations for snapshot-first sync
3
- * (#15, ADR 0006 D5). Shared by the orchestrator, transport and
3
+ * (#15). Shared by the orchestrator, transport and
4
4
  * convergence modules share ONE definition of each result/option shape.
5
5
  * Pure type surface — no runtime code.
6
6
  */
@@ -17,7 +17,7 @@ export declare function isPushRejected(e: unknown): boolean;
17
17
  */
18
18
  export declare function isUnrelatedHistories(e: unknown): boolean;
19
19
  /**
20
- * Snapshot-first sync (ADR 0006 D5). Serialized on the per-repo lock; one
20
+ * Snapshot-first sync. Serialized on the per-repo lock; one
21
21
  * function-scoped object cache, released on return.
22
22
  *
23
23
  * If someone pushes between our fetch and our push, the push is rejected and
@@ -39,7 +39,7 @@ export declare const FAILURE_MESSAGES: Record<RemoteAccessFailureReason, string>
39
39
  * - Never throws — every outcome is a classified {@link RemoteAccessResult}.
40
40
  * - SSH URLs return `ssh-unsupported` with zero network traffic.
41
41
  * - Credentials embedded in the URL are stripped and used for auth when no
42
- * explicit credential is supplied (ADR 0006 D7) — they never leak onward.
42
+ * explicit credential is supplied — they never leak onward.
43
43
  * - `defaultBranch` comes from the server's `HEAD` symref when advertised.
44
44
  */
45
45
  export declare function testRemoteAccess(options: TestRemoteAccessOptions): Promise<RemoteAccessResult>;
@@ -14,7 +14,7 @@ export interface HostCredential {
14
14
  createdAt: number;
15
15
  }
16
16
  /**
17
- * Host-keyed credential vault contract (ADR 0006 D3 layer 2). Implementations
17
+ * Host-keyed credential vault contract. Implementations
18
18
  * are provided by the HOST APP (Electron safeStorage, CLI 0600 file); the lib
19
19
  * only consumes this interface.
20
20
  */
@@ -19,8 +19,8 @@ export declare function isCredentialTransmissionSafe(url: string): boolean;
19
19
  /**
20
20
  * Thrown by {@link onAuthFor} when a stored credential EXISTS but the remote
21
21
  * URL fails {@link isCredentialTransmissionSafe} (non-loopback http). Loud and
22
- * typed on purpose: the old behavior (silently withholding the credential)
23
- * surfaced as a 401 → "auth" → "reconnect" loop. The `code` string is the
22
+ * typed on purpose: silently withholding the credential surfaces as a 401 →
23
+ * "auth" → "reconnect" loop. The `code` string is the
24
24
  * STABLE contract (matchable across dynamic-import boundaries).
25
25
  */
26
26
  export declare class InsecureTransportError extends Error {
@@ -70,7 +70,7 @@ export declare function failureOutcome(e: unknown, snapshotId?: string): {
70
70
  export declare function setupErrorMessage(e: unknown): string | null;
71
71
  /**
72
72
  * Snapshot-first step used by syncProject
73
- * (ADR 0006 D5): commit any unsaved work in the WHOLE repo BEFORE any network
73
+ *: commit any unsaved work in the WHOLE repo BEFORE any network
74
74
  * or merge step, so a forced post-merge checkout can never discard it. The
75
75
  * working-tree check runs lazily at action time on the caller's function-scoped
76
76
  * object cache (released with the operation).
@@ -0,0 +1,28 @@
1
+ import type { Diff } from "./render-parity.ts";
2
+ export interface RgbImage {
3
+ w: number;
4
+ h: number;
5
+ /** Packed RGB, 3 bytes per pixel. */
6
+ data: Uint8Array;
7
+ }
8
+ /** Parse a binary PPM (P6, maxval 255) — what `pdftoppm` writes by default. */
9
+ export declare function parsePpm(buf: Uint8Array): RgbImage;
10
+ /**
11
+ * Count pixels where any channel differs by more than `tolerance` (a fraction
12
+ * of 255; 0.01 = 1%), and return a copy of `cand` with those pixels painted
13
+ * red. Images of different sizes differ everywhere and get no diff image.
14
+ */
15
+ export declare function comparePixels(base: RgbImage, cand: RgbImage, tolerance: number): {
16
+ differing: number;
17
+ marked: RgbImage | null;
18
+ };
19
+ /** Encode an RGB image as a PNG (8-bit truecolour, no filtering). */
20
+ export declare function encodePng(img: RgbImage): Uint8Array;
21
+ /**
22
+ * Raster-compare the first `pageCount` pages of two PDFs. Returns one `raster`
23
+ * diff per differing page and writes `diff-NNN.png` for each into `outDir`.
24
+ */
25
+ export declare function rasterDiffs(basePdf: string, candPdf: string, pageCount: number, outDir: string, options?: {
26
+ dpi?: number;
27
+ tolerance?: number;
28
+ }): Promise<Diff[]>;
@@ -41,7 +41,7 @@ export declare function extractReport(pdfPath: string): Promise<Report>;
41
41
  * rounded to 3 decimals before it gets here.
42
42
  */
43
43
  export declare function serializeReport(report: Report): string;
44
- export type WaiverKind = "page-count" | "page-size" | "text" | "image";
44
+ export type WaiverKind = "page-count" | "page-size" | "text" | "image" | "raster";
45
45
  export interface Waiver {
46
46
  /** 1-based page number. Omit for kind "page-count" (there is no page). */
47
47
  page?: number;
@@ -70,6 +70,9 @@ export interface CompareOptions {
70
70
  /** Points. Applies to text run and image extents (x/y/w/h). Default 0.5. */
71
71
  tolerance?: number;
72
72
  waivers?: Waiver[];
73
+ /** Diffs found outside the report — the `raster` diffs of `compare
74
+ * --raster` (render-parity-raster.ts) — waived like every other kind. */
75
+ extraDiffs?: Diff[];
73
76
  }
74
77
  export interface CompareResult {
75
78
  /** Diffs NOT excused by any waiver — non-empty means the gate fails. */
@@ -105,7 +105,7 @@ export interface SourceProvider {
105
105
  /**
106
106
  * Run `fn` exclusively per resolved project dir (FIFO promise chaining).
107
107
  * Exported for the remote-clone surface (#15) so clone/fetch operations share
108
- * the SAME queue as snapshot/restore — ADR 0006 D2 requires one per-repo lock.
108
+ * the SAME queue as snapshot/restore — one per-repo lock.
109
109
  */
110
110
  export declare function withRepoLock<T>(projectDir: string, fn: () => Promise<T>): Promise<T>;
111
111
  /**
@@ -164,7 +164,7 @@ export declare function stageChanges(dir: string, changes: WorkdirChanges, cache
164
164
  /**
165
165
  * True when the working tree differs from the index (added/modified/deleted
166
166
  * files). Used to skip empty snapshots. Exported (lock-free) for the sync
167
- * surface (#15, ADR 0006 D5) — callers outside a lock should prefer the
167
+ * surface (#15) — callers outside a lock should prefer the
168
168
  * provider operations.
169
169
  */
170
170
  export declare function hasPendingChanges(dir: string, cache?: GitCache): Promise<boolean>;
@@ -177,14 +177,13 @@ export declare function hasPendingChanges(dir: string, cache?: GitCache): Promis
177
177
  * sync-check path per the sync-simplicity mandate): this is for build
178
178
  * *provenance* — the build fingerprint records whether the tree was clean at
179
179
  * build time, where a `git add`-ed-but-not-committed change must still count
180
- * as dirty (the old `git status --porcelain` fingerprint reported it; the
181
- * WORKDIR-vs-STAGE-only check silently dropped it).
180
+ * as dirty (the WORKDIR-vs-STAGE-only check silently drops it).
182
181
  */
183
182
  export declare function hasUncommittedChanges(dir: string, cache?: GitCache): Promise<boolean>;
184
183
  /**
185
184
  * Lock-free snapshot of the full working tree (stage everything + commit).
186
185
  *
187
- * Exported for the sync surface (#15, ADR 0006 D5): `syncProject` holds
186
+ * Exported for the sync surface (#15): `syncProject` holds
188
187
  * the per-repo lock for snapshot → fetch → merge → push as ONE sequence, so it
189
188
  * needs the lock-free internal rather than `provider.snapshot()` (taking the
190
189
  * per-method lock inside the sync lock would deadlock the FIFO queue).
@@ -4,20 +4,15 @@ import http from "node:http";
4
4
  * in this package: the build-time pagination server and PDF-render server
5
5
  * (build-runner.ts) and the live preview server (preview/http-server.ts).
6
6
  *
7
- * Previously two independent 17-entry tables that had to be edited in lockstep
8
- * (finding #17) — a new asset type added to only one would render differently
9
- * in preview vs build-time pagination with no error, a silent divergence
10
- * class. One table now; add a new extension once.
7
+ * One table for every server: a type added to only one would render
8
+ * differently in preview vs build-time pagination with no error.
11
9
  *
12
- * That same divergence class recurred once more (2026-07-28 duplication
13
- * audit): this table and `asset-inline.ts`'s `MIME_BY_EXT` — a separate table
14
- * answering a separate question, "what Content-Type does a data: URI need
15
- * when embedding this file inline," vs. this table's "what Content-Type does
16
- * an HTTP response need" — had drifted again, missing `.webp`/`.avif` here.
17
- * A copied WebP/AVIF image was served as `application/octet-stream` by both
18
- * servers above. Added below; if a third image format shows up, add it to
19
- * BOTH tables in the same commit (asset-inline.ts is out of scope for this
20
- * PR — see docs/reviews/duplication-audit-2026-07-28.md).
10
+ * `asset-inline.ts`'s `MIME_BY_EXT` is a separate table answering a separate
11
+ * question ("what Content-Type does a data: URI need when embedding this file
12
+ * inline" vs. this table's "what Content-Type does an HTTP response need"). A
13
+ * new image format must be added to BOTH tables in the same commit, or (as
14
+ * once happened with `.webp`/`.avif`) a copied image is served as
15
+ * `application/octet-stream`.
21
16
  */
22
17
  export declare const STATIC_MIME: Record<string, string>;
23
18
  /**
@@ -34,7 +34,7 @@ export declare function resolveActiveStyles(projectDir: string, manifestStyles?:
34
34
  * the way the manifest stores them — project-relative, e.g.
35
35
  * `../../shared/styles/components.css` — so toggling one on writes the right
36
36
  * entry. Omit it (or pass the project itself) for the single-project case, which
37
- * behaves exactly as before.
37
+ * scans only the project.
38
38
  */
39
39
  export declare function listProjectStyles(projectDir: string, opts?: {
40
40
  repoRoot?: string;
@@ -17,9 +17,6 @@ import { type VendorPreset } from "./presets";
17
17
  * skipped because its tools are missing becomes a synthetic error, so
18
18
  * "validated for dtrpg" can never silently mean "the dtrpg checks didn't
19
19
  * run".
20
- *
21
- * Grown from the old `validate --profile dtrpg` (validation-profile.ts,
22
- * deleted): the profile was this exact idea hardcoded for one destination.
23
20
  */
24
21
  /** The deep-partial preset shape a target may overlay. */
25
22
  export type TargetOverlay = {
@@ -77,8 +74,7 @@ export declare function overlayPreset(preset: VendorPreset, target: PublishTarge
77
74
  * The strict-PDF fill-ins applied to EVERY post-build PDF validation
78
75
  * regardless of preset/target: any of these left `undefined` by the config
79
76
  * becomes an error-severity check, without overwriting an author's explicit
80
- * choice (including an explicit disable). Moved verbatim from
81
- * validation-profile.ts (ARCH #21).
77
+ * choice (including an explicit disable).
82
78
  */
83
79
  export declare const DEFAULT_STRICT_PDF_CHECKS: readonly ["pdf.structure.qpdf", "pdf.print.pdfx-markers", "pdf.print.pdfx-metadata", "pdf.print.embedded-fonts"];
84
80
  export declare function applyDefaultPdfStrictChecks(config: ResolvedConfig): ResolvedConfig;
@@ -19,9 +19,8 @@
19
19
  *
20
20
  * One implementation; one place to fix bugs. Spawning goes through
21
21
  * exec.ts's `execCapture`, which also owns the shared, correctly
22
- * delimiter-joined `enhancedPath` (this file used to keep its own copy of
23
- * that PATH construction, and exec.ts's copy hardcoded `:` — see
24
- * docs/reviews 2026-07-10-architecture-critical-review.md, finding #3).
22
+ * delimiter-joined `enhancedPath` — do not keep a second copy of that PATH
23
+ * construction here.
25
24
  */
26
25
  /**
27
26
  * Returns true if `tool` is resolvable via the platform's path-probe command.
@@ -30,10 +30,9 @@ export interface ValidationExecutionArgs {
30
30
  * only, without touching the manifest's `validate.source.stylelint`
31
31
  * setting on disk (#272 — one CSS gate, not two). Set by the build
32
32
  * pipeline's `runQualityGates` (build-runner.ts) from `--skip-lint` /
33
- * `config.lint.enabled: false`, so that flag disables just the one check
34
- * it always meant to gate rather than a whole separate lint pass. Every
35
- * other caller (`gutterpress validate`/`preflight`, the desktop Problems
36
- * panel) leaves this unset and gets the manifest's own setting.
33
+ * `config.lint.enabled: false`, so that flag disables just this one check.
34
+ * Every other caller (`gutterpress validate`/`preflight`, the desktop
35
+ * Problems panel) leaves this unset and gets the manifest's own setting.
37
36
  */
38
37
  skipStylelint?: boolean;
39
38
  /**