gutterpress 0.11.11-alpha.1 → 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-ycaavzsb.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-kgd355eh.js → cli-1kdtzgxm.js} +1 -1
  9. package/dist/{cli-g3xd0x9z.js → cli-d2he8zph.js} +6 -6
  10. package/dist/{cli-wtw5nfsx.js → cli-ny50k8md.js} +1 -1
  11. package/dist/{cli-p40641zw.js → cli-tjhn2mdn.js} +3 -3
  12. package/dist/cli.js +12 -12
  13. package/dist/{doctor-71dxjkpz.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-fv61tyn7.js → engine-132czsq9.js} +1 -1
  17. package/dist/{engine-sq1kpg5s.js → engine-bgd4aa99.js} +2 -2
  18. package/dist/{ext-rkfntmtv.js → ext-271xnh70.js} +4 -4
  19. package/dist/{index-dxt4t7et.js → index-b6p1fh61.js} +1 -1
  20. package/dist/{index-b7q4wev1.js → index-mw8b25yx.js} +3 -3
  21. package/dist/{index-wdqymw2k.js → index-ssjh6tnd.js} +5 -5
  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-c6pmpvhw.js → new-7w4ezfpy.js} +4 -4
  78. package/dist/platform.d.ts +8 -41
  79. package/dist/{preflight-9vq1ygh4.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-x22vcqyw.js → preview-interface-twd6nsf5.js} +8 -10
  84. package/dist/{preview-shell-tqndvhbx.js → preview-shell-y8yrm3f0.js} +8 -19
  85. package/dist/{preview-6n5ava6c.js → preview-y39jrpbs.js} +4 -4
  86. package/dist/{publish-9an2a1ma.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-0rrjva48.js → validate-9enr4ecc.js} +4 -4
  92. package/package.json +1 -1
@@ -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
  /**
@@ -7,16 +7,16 @@ import {
7
7
  TARGET_IDS,
8
8
  scaffoldExtension,
9
9
  scaffoldProject
10
- } from "./cli-g3xd0x9z.js";
10
+ } from "./cli-d2he8zph.js";
11
11
  import {
12
12
  resolveGhostscript
13
- } from "./cli-kgd355eh.js";
13
+ } from "./cli-1kdtzgxm.js";
14
14
  import {
15
15
  UsageError,
16
16
  rejectExtraPositionals,
17
17
  rejectUnknownFlags
18
- } from "./cli-wtw5nfsx.js";
19
- import"./cli-p40641zw.js";
18
+ } from "./cli-ny50k8md.js";
19
+ import"./cli-tjhn2mdn.js";
20
20
  import {
21
21
  EXIT_CODES
22
22
  } from "./cli-46ycxe6r.js";
@@ -2,22 +2,19 @@
2
2
  * Platform abstraction contract (GitHub #41).
3
3
  *
4
4
  * The desktop talks to its host through ONE seam so that the app code never
5
- * branches on `electron` vs `web` directly. Today the only host is Electron
6
- * (IPC + native dialogs). When the PWA lands (0.6.0, #...), a `WebAdapter`
7
- * backed by the File System Access API drops in behind the same interface and
8
- * the app code does not change.
5
+ * branches on the host directly. The only host is Electron (IPC + native
6
+ * dialogs).
9
7
  *
10
8
  * This module is **types only** — it is imported by the browser SPA via
11
9
  * `import type`, so it must never pull in a Node runtime dependency.
12
10
  *
13
11
  * Canonical home: `gutterpress`. The desktop re-exports these types
14
- * from `src/lib/platform/` and implements them in `electron-adapter.ts` /
15
- * `web-adapter.ts`. Keep the implementations in lockstep with this contract.
12
+ * from `src/lib/platform/` and implements them in `electron-adapter.ts`.
13
+ * Keep the implementation in lockstep with this contract.
16
14
  */
17
15
  /**
18
- * The narrow set of capabilities whose implementation genuinely differs between
19
- * a desktop (Electron) host and a browser (PWA) host: native dialogs, raw file
20
- * IO, filesystem watching, and OS-keychain-backed secrets.
16
+ * The narrow set of host file primitives: raw file IO and filesystem
17
+ * watching.
21
18
  *
22
19
  * Host RPC services that are *also* host-divergent (preview/build/doctor/prefs/
23
20
  * updater) are modelled separately as {@link HostServices} so this primitive
@@ -45,56 +42,26 @@ export interface FileWriteResult {
45
42
  mtimeMs: number;
46
43
  }
47
44
  export interface PlatformAdapter {
48
- /** Which host backs this adapter. Lets the rare unavoidable branch be explicit. */
49
- readonly platform: "electron" | "web";
50
- /**
51
- * Prompt the user to choose a project folder.
52
- * @returns the absolute path, or `null` if the user cancelled.
53
- * Electron: native directory dialog. Web: File System Access API.
54
- */
55
- openFolder(): Promise<string | null>;
56
45
  /**
57
46
  * Read a UTF-8 text file by absolute path.
58
- * Editor seam for #38/#39 — no current consumer in 0.4.0.
59
47
  */
60
48
  readFile(path: string): Promise<string>;
61
49
  /**
62
50
  * Write a UTF-8 text file by absolute path, creating/overwriting it.
63
51
  * Resolves with the post-write {@link FileWriteResult} (`{ mtimeMs }`) so the
64
- * editor (#44) can record the on-disk baseline mtime; callers that ignore the
65
- * value are unaffected (additive widening — was `Promise<void>`).
52
+ * editor (#44) can record the on-disk baseline mtime.
66
53
  */
67
54
  writeFile(path: string, content: string): Promise<FileWriteResult>;
68
- /**
69
- * List the immediate entries of a directory (single level, no recursion).
70
- * @returns each entry's `name`, absolute `path`, and whether it `isDir`.
71
- * Editor seam for #38 (file-tree sidebar). Electron: `node:fs/promises`
72
- * `readdir`. Web: File System Access API (0.6.0).
73
- */
74
- listDir(path: string): Promise<Array<{
75
- name: string;
76
- path: string;
77
- isDir: boolean;
78
- }>>;
79
55
  /**
80
56
  * Stat a file by absolute path (GitHub #44). Used by the editor to confirm a
81
57
  * `watchFolder` event reflects a real on-disk change (mtime moved) versus the
82
58
  * self-echo of our own `writeFile`. Resolves with `exists: false` rather than
83
- * rejecting when the path is absent. Web throws until 0.6.0 (FS Access API).
59
+ * rejecting when the path is absent.
84
60
  */
85
61
  statFile(path: string): Promise<FileStat>;
86
62
  /**
87
63
  * Watch a folder for changes, invoking `cb` on each change.
88
64
  * @returns an unsubscribe function.
89
- * Web has no general recursive-watch primitive — `WebAdapter` throws here
90
- * until 0.6.0. Electron wiring lands with the in-app editor (#38).
91
65
  */
92
66
  watchFolder(path: string, cb: () => void): () => void;
93
- /**
94
- * Read a secret by key (e.g. a GitHub token). Lands with #12.
95
- * Electron: OS keychain via `safeStorage`. Web: encrypted localStorage.
96
- */
97
- getSecret(key: string): Promise<string | null>;
98
- /** Store a secret by key. Lands with #12. */
99
- setSecret(key: string, value: string): Promise<void>;
100
67
  }
@@ -2,16 +2,16 @@ import {
2
2
  executeValidation,
3
3
  publishTargetFor,
4
4
  reportMissingTools
5
- } from "./cli-g3xd0x9z.js";
5
+ } from "./cli-d2he8zph.js";
6
6
  import {
7
7
  log
8
- } from "./cli-kgd355eh.js";
8
+ } from "./cli-1kdtzgxm.js";
9
9
  import {
10
10
  UsageError,
11
11
  rejectExtraPositionals,
12
12
  rejectUnknownFlags
13
- } from "./cli-wtw5nfsx.js";
14
- import"./cli-p40641zw.js";
13
+ } from "./cli-ny50k8md.js";
14
+ import"./cli-tjhn2mdn.js";
15
15
  import {
16
16
  EXIT_CODES
17
17
  } from "./cli-46ycxe6r.js";
@@ -125,11 +125,9 @@ export declare function externalWatchTargets(projectDir: string, config: {
125
125
  * Create and configure a file watcher for the project's input directory plus
126
126
  * the book's declared external dependencies (see {@link externalWatchTargets}).
127
127
  *
128
- * Nothing is mirrored anywhere: the old external-asset-root watching (a sibling
129
- * `../_shared` directory copied under its own name into the temp dir) went away
130
- * with `copyAssets` and the manifest's `source.assets` field it depended on.
131
- * The project is served straight from disk and stylesheets are inlined at
132
- * render time, so an external dependency needs watching, not staging.
128
+ * Nothing is mirrored anywhere: the project is served straight from disk and
129
+ * stylesheets are inlined at render time, so an external dependency needs
130
+ * watching, not staging.
133
131
  */
134
132
  export declare function createFileWatcher(state: ServerState): FSWatcher;
135
133
  /**