gutterpress 0.10.9 → 0.10.10-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.
- package/README.md +66 -5
- package/dist/{README-jntqyj1z.md → README-3zk4tgnj.md} +4 -4
- package/dist/{README-6c7fda1s.md → README-7x5akcns.md} +5 -4
- package/dist/api/index.d.ts +7 -4
- package/dist/api/index.js +22 -12
- package/dist/{audit-fq7s1gsz.js → audit-wcmbgh39.js} +5 -5
- package/dist/{build-dyat3fqd.js → build-c1w6kqpv.js} +6 -6
- package/dist/{cli-ypfvnhag.js → cli-2rswy18t.js} +1 -1
- package/dist/{cli-w692g6dx.js → cli-4mtf9ajw.js} +127 -1
- package/dist/{cli-bzxqtvrk.js → cli-75qkn0k5.js} +1 -1
- package/dist/{cli-bx950tb4.js → cli-k8f9eb12.js} +22 -26
- package/dist/{cli-8pg731p5.js → cli-n0vgey6x.js} +4914 -4707
- package/dist/{cli-rh05byck.js → cli-scqp638v.js} +1 -1
- package/dist/cli.js +16 -16
- package/dist/{components-0mmswvvm.yaml → components-dhgv2sm7.yaml} +2 -2
- package/dist/{doctor-yr85n080.js → doctor-drv36btj.js} +2 -2
- package/dist/{engine-d46wgg99.js → engine-pt2acjb5.js} +2 -2
- package/dist/{engine-19mshh07.js → engine-qtmvaqt7.js} +1 -1
- package/dist/{ext-jrg8c48s.js → ext-xqx26xvy.js} +52 -8
- package/dist/{index-mey5vraz.js → index-1he93sjd.js} +918 -796
- package/dist/{index-zwcv1njy.js → index-5dgxeevv.js} +22 -26
- package/dist/{index-dhgzkhs7.js → index-a0e2253t.js} +1 -1
- package/dist/{index-dtrftayr.js → index-y01v2fe0.js} +127 -1
- package/dist/index.js +102 -15
- package/dist/lib/build-error.d.ts +6 -5
- package/dist/lib/build-preflight.d.ts +11 -1
- package/dist/lib/build-runner.d.ts +49 -16
- package/dist/lib/extension-import.d.ts +4 -4
- package/dist/lib/extension-manager.d.ts +3 -3
- package/dist/lib/extension-manifest.d.ts +91 -87
- package/dist/lib/extension-scaffold.d.ts +1 -1
- package/dist/lib/extension-search.d.ts +46 -0
- package/dist/lib/host-policy.d.ts +10 -12
- package/dist/lib/lint-runner.d.ts +16 -9
- package/dist/lib/npm-registry.d.ts +22 -0
- package/dist/lib/source-provider.d.ts +71 -0
- package/dist/lib/validation-exec.d.ts +11 -0
- package/dist/{lint-enasqbqx.js → lint-ejzmx14j.js} +5 -5
- package/dist/{new-r9c99wsn.js → new-g3q3h4s5.js} +6 -6
- package/dist/package-97gm31sg.json +10 -0
- package/dist/{package-rm9d2tht.json → package-9rv69pxm.json} +4 -1
- package/dist/package-aenwjew3.json +28 -0
- package/dist/package-gag6ykwn.json +10 -0
- package/dist/package-nrhkwf2m.json +10 -0
- package/dist/{plugin.test.js-npnfhyca.tpl → plugin.test.js-k2r87k04.tpl} +9 -8
- package/dist/{preflight-shk7vqbs.js → preflight-w5z2vfhx.js} +5 -5
- package/dist/{preview-52918mxk.js → preview-9s22dq77.js} +6 -6
- package/dist/{publish-8s60vhx7.js → publish-mt22ewpk.js} +5 -5
- package/dist/{source-provider-2j5x2hyw.js → source-provider-51g6mt6y.js} +7 -1
- package/dist/{source-provider-kn41jmbs.js → source-provider-jkppq9fc.js} +7 -1
- package/dist/{tokens-e4xk3x4v.css → tokens-2sracx1w.css} +1 -1
- package/dist/{validate-awccx32r.js → validate-kkn8rmy5.js} +5 -5
- package/package.json +1 -1
- package/dist/gutterpress-m98e2w2d.json +0 -8
- package/dist/gutterpress-x2ycdsb8.json +0 -17
- package/dist/theme-etj4gxck.json +0 -9
- package/dist/theme-s2rg7xe7.json +0 -9
- package/dist/theme-vktedy8q.json +0 -9
|
@@ -40,7 +40,7 @@ export declare function classifyThemeCssFindings(findings: PrintSafeWarning[]):
|
|
|
40
40
|
};
|
|
41
41
|
/**
|
|
42
42
|
* From a theme folder's relative file paths, return the ones that are neither
|
|
43
|
-
* `theme.css`/`
|
|
43
|
+
* `theme.css`/`package.json`, a recognized bundled asset
|
|
44
44
|
* (font/image/css), nor one the metadata itself declared (#241 —
|
|
45
45
|
* `declaredExtras`: the extension's `markdown`/`components`/`snippets`
|
|
46
46
|
* entries, when present, passed as relative paths; a `snippets` folder
|
|
@@ -59,8 +59,8 @@ export declare function unexpectedThemeFiles(relPaths: string[], declaredExtras?
|
|
|
59
59
|
export declare function importExtensionFromZip(projectDir: string, archive: Uint8Array): Promise<ExtensionImportResult>;
|
|
60
60
|
/**
|
|
61
61
|
* Import a theme from a bare `.css` file by wrapping it into a one-file theme
|
|
62
|
-
* folder (`theme.css` + a synthesized `
|
|
63
|
-
* that fails to parse.
|
|
62
|
+
* folder (`theme.css` + a synthesized `package.json` naming it and declaring
|
|
63
|
+
* it). REJECTS a CSS that fails to parse.
|
|
64
64
|
*/
|
|
65
65
|
export declare function importExtensionFromCssText(projectDir: string, css: string, name: string): Promise<ExtensionImportResult>;
|
|
66
66
|
/**
|
|
@@ -73,7 +73,7 @@ export declare function importExtensionFromFile(projectDir: string, filePath: st
|
|
|
73
73
|
* Import a look from a URL using the global `fetch` (bundle-safe — no node
|
|
74
74
|
* http client). Two shapes: a `.css` URL is the look's `theme.css`, with
|
|
75
75
|
* metadata synthesised from the URL; a base URL (no `.css`) fetches
|
|
76
|
-
* `<base>/
|
|
76
|
+
* `<base>/package.json` (optional) and `<base>/theme.css` (required). Bundled
|
|
77
77
|
* fonts are not followed — authors wanting bundled assets use a folder or a
|
|
78
78
|
* `.zip`. The fetched files go through the same validation as a `.zip`.
|
|
79
79
|
*/
|
|
@@ -29,10 +29,10 @@ export interface ProjectExtensionEntry {
|
|
|
29
29
|
/** Preview image path relative to the extension folder, when declared. */
|
|
30
30
|
preview?: string | null;
|
|
31
31
|
/** The sheet carrying the `:root` token surface, relative to the folder,
|
|
32
|
-
* when declared (
|
|
32
|
+
* when declared (package.json's `gutterpress.tokensFile`). */
|
|
33
33
|
tokensFile?: string;
|
|
34
|
-
/** Declared stylesheets relative to the folder, in cascade order
|
|
35
|
-
*
|
|
34
|
+
/** Declared stylesheets relative to the folder, in cascade order
|
|
35
|
+
* (`gutterpress.styles`). Absent when the folder declares none. */
|
|
36
36
|
styles?: string[];
|
|
37
37
|
/** What the extension declares — the desktop shows styles-carrying entries
|
|
38
38
|
* in its Look view and markdown-carrying ones in Features; one list. */
|
|
@@ -1,92 +1,100 @@
|
|
|
1
|
-
/** The
|
|
2
|
-
|
|
3
|
-
export declare const EXTENSION_MANIFEST_FILENAME = "gutterpress.json";
|
|
4
|
-
/** The pre-#241 theme-only metadata filename. Still fully supported: a folder
|
|
5
|
-
* with only this file (no `gutterpress.json`) is a theme, i.e. "an extension
|
|
6
|
-
* with only styles" — see {@link readExtensionMeta}. */
|
|
7
|
-
export declare const LEGACY_THEME_MANIFEST_FILENAME = "theme.json";
|
|
1
|
+
/** The one file an extension describes itself in — npm's own manifest. */
|
|
2
|
+
export declare const EXTENSION_MANIFEST_FILENAME = "package.json";
|
|
8
3
|
/**
|
|
9
|
-
* Parsed extension metadata —
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* a
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `loadExtensionFromDir`, which only reaches this type for a
|
|
17
|
-
* names a folder
|
|
4
|
+
* Parsed extension metadata — npm's standard fields plus the `gutterpress`
|
|
5
|
+
* block's, flattened into the one shape every consumer reads. Every field is
|
|
6
|
+
* optional: a folder declaring only `gutterpress.styles` IS a valid extension
|
|
7
|
+
* ("a look ≡ an extension with only styles"), and a package.json whose `main`
|
|
8
|
+
* is a plain markdown-it plugin with no `gutterpress` key at all is one too
|
|
9
|
+
* ("a plugin ≡ an extension with only markdown"). A bare `.js` plugin file
|
|
10
|
+
* (no package.json beside it) never constructs one of these — see
|
|
11
|
+
* `plugins.ts`'s `loadExtensionFromDir`, which only reaches this type for a
|
|
12
|
+
* `path` that names a folder.
|
|
18
13
|
*/
|
|
19
14
|
export interface ExtensionMetadata {
|
|
15
|
+
/** npm `name`. */
|
|
20
16
|
name?: string;
|
|
17
|
+
/** npm `author`, as a string or the object form's `name`. */
|
|
21
18
|
author?: string;
|
|
19
|
+
/** npm `description`. */
|
|
22
20
|
description?: string;
|
|
23
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* npm `keywords` — informational. `gutterpress` marks a Gutterpress
|
|
23
|
+
* extension and `markdown-it-plugin` a markdown-it plugin, the two tags
|
|
24
|
+
* `gutterpress ext search` finds packages by; nothing here requires either.
|
|
25
|
+
*/
|
|
26
|
+
keywords?: string[];
|
|
27
|
+
/**
|
|
28
|
+
* npm `main` — the markdown-it plugin module of a FOLDER extension, by
|
|
29
|
+
* npm's own convention. See {@link extensionEntry} for the entry rule
|
|
30
|
+
* (`gutterpress.markdown` wins when present). NOT used for an npm-installed
|
|
31
|
+
* package: the installer resolves that entry with full `exports` semantics
|
|
32
|
+
* (`npm-plugin-installer.ts`'s `resolvePackageEntry`), and it is never
|
|
33
|
+
* re-derived from `main` here.
|
|
34
|
+
*/
|
|
35
|
+
main?: string;
|
|
36
|
+
/** `gutterpress.preview` — an optional preview image path, relative to the
|
|
37
|
+
* extension folder. */
|
|
24
38
|
preview?: string | null;
|
|
25
39
|
/**
|
|
26
|
-
*
|
|
27
|
-
* "no styles declared"
|
|
28
|
-
*
|
|
29
|
-
* top for its theme-shaped callers (a plain markdown-only extension folder
|
|
30
|
-
* has no reason to require a `theme.css` it never declared).
|
|
40
|
+
* `gutterpress.styles` — ordered stylesheets, relative to the extension
|
|
41
|
+
* folder. Absent/empty means exactly "no styles declared": a look declares
|
|
42
|
+
* its sheets, it does not get an implicit `theme.css`.
|
|
31
43
|
*/
|
|
32
44
|
styles?: string[];
|
|
33
|
-
/**
|
|
34
|
-
* `:root` token surface for the Design panel's
|
|
35
|
-
* advisory — nothing in this module enforces or
|
|
36
|
-
*
|
|
45
|
+
/** `gutterpress.tokensFile` — which declared sheet (a path from `styles`)
|
|
46
|
+
* carries the author-facing `:root` token surface for the Design panel's
|
|
47
|
+
* guided editor. Purely advisory — nothing in this module enforces or
|
|
48
|
+
* existence-checks it. */
|
|
37
49
|
tokensFile?: string;
|
|
38
50
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* `
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* contract every other plugin module does — no new plugin API is
|
|
47
|
-
* introduced.
|
|
51
|
+
* `gutterpress.markdown` — an EXPLICIT markdown-it entry, relative to the
|
|
52
|
+
* extension folder, for the one case npm's `main` can't express: a package
|
|
53
|
+
* whose `main` is not the plugin. Absent is the normal case ({@link
|
|
54
|
+
* extensionEntry} falls back to `main`). CLAUDE.md §5 is unaffected: this
|
|
55
|
+
* field is DATA a loader resolves to a file, then loads through the exact
|
|
56
|
+
* same plain-markdown-it-plugin contract every other plugin module does —
|
|
57
|
+
* no new plugin API is introduced.
|
|
48
58
|
*/
|
|
49
59
|
markdown?: string;
|
|
50
60
|
/**
|
|
51
|
-
*
|
|
52
|
-
* architecture review's `components.yaml`, #242).
|
|
53
|
-
* containment only by this module
|
|
54
|
-
* that reads it are #242's scope, not this one's.
|
|
61
|
+
* `gutterpress.components` — component catalog file, relative to the
|
|
62
|
+
* extension folder (the CSS architecture review's `components.yaml`, #242).
|
|
63
|
+
* Parsed for existence/containment only by this module.
|
|
55
64
|
*/
|
|
56
65
|
components?: string;
|
|
57
66
|
/**
|
|
58
|
-
*
|
|
59
|
-
* project's snippet picker under the extension's
|
|
60
|
-
* existence/containment only by this module
|
|
61
|
-
*
|
|
67
|
+
* `gutterpress.snippets` — snippets folder, relative to the extension
|
|
68
|
+
* folder, merged into the project's snippet picker under the extension's
|
|
69
|
+
* name. Parsed for existence/containment only by this module; `snippets.ts`
|
|
70
|
+
* does the merge.
|
|
62
71
|
*/
|
|
63
72
|
snippets?: string;
|
|
73
|
+
/**
|
|
74
|
+
* The removed `engineStyles` field (#266), carried through from the
|
|
75
|
+
* `gutterpress` block ONLY so {@link assertExtensionContained} can reject it
|
|
76
|
+
* by name at a write boundary. Never read as a declaration.
|
|
77
|
+
*/
|
|
78
|
+
engineStyles?: unknown;
|
|
64
79
|
}
|
|
65
80
|
/**
|
|
66
|
-
* Read an extension folder's
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* everywhere a real on-disk extension/theme folder is read (project themes,
|
|
70
|
-
* apply, import, revert). `gutterpress.json` wins outright when present (no
|
|
71
|
-
* silent merge with a sibling `theme.json` — a package declares itself
|
|
72
|
-
* through exactly one file), matching {@link readJsonMetaFile}'s tolerant
|
|
73
|
-
* contract when that one file is missing or broken.
|
|
81
|
+
* Read an extension folder's `package.json`. Tolerant: a missing or
|
|
82
|
+
* unparseable file, or one that is not an object, reads as `{}` — one bad or
|
|
83
|
+
* absent manifest must never take down listing/reading every extension.
|
|
74
84
|
*/
|
|
75
85
|
export declare function readExtensionMeta(dir: string): Promise<ExtensionMetadata>;
|
|
76
86
|
/**
|
|
77
87
|
* An extension's declared stylesheets, relative to its folder, in cascade
|
|
78
|
-
* order.
|
|
79
|
-
* `["theme.css"]` default on top of this for its theme-shaped callers), an
|
|
80
|
-
* absent/empty `styles` here means exactly "none declared" — a markdown-only
|
|
81
|
-
* extension folder must not be forced to carry a `theme.css` it never wanted.
|
|
88
|
+
* order. Absent/empty `gutterpress.styles` means exactly "none declared".
|
|
82
89
|
*/
|
|
83
90
|
export declare function extensionStyleList(meta: ExtensionMetadata): string[];
|
|
84
91
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* `
|
|
92
|
+
* The markdown-it entry of a FOLDER extension: an explicit
|
|
93
|
+
* `gutterpress.markdown` when the package's `main` is not the plugin,
|
|
94
|
+
* otherwise npm's own `main`. `undefined` for a folder that carries no
|
|
95
|
+
* markdown behaviour at all (a look).
|
|
88
96
|
*/
|
|
89
|
-
export declare function
|
|
97
|
+
export declare function extensionEntry(meta: ExtensionMetadata): string | undefined;
|
|
90
98
|
/** What an extension declares, by field — the desktop's one-list filter. */
|
|
91
99
|
export interface ExtensionCarries {
|
|
92
100
|
markdown: boolean;
|
|
@@ -94,7 +102,7 @@ export interface ExtensionCarries {
|
|
|
94
102
|
snippets: boolean;
|
|
95
103
|
components: boolean;
|
|
96
104
|
}
|
|
97
|
-
export declare function extensionCarries(meta: ExtensionMetadata
|
|
105
|
+
export declare function extensionCarries(meta: ExtensionMetadata): ExtensionCarries;
|
|
98
106
|
/**
|
|
99
107
|
* True when a declared relative path escapes its own folder (absolute, or a
|
|
100
108
|
* `..` segment) — the traversal shape every containment check in this
|
|
@@ -116,39 +124,30 @@ export declare function pathEscapesFolder(rel: string): boolean;
|
|
|
116
124
|
* extension is self-contained by contract (apply/install copies the whole
|
|
117
125
|
* folder), and an imported/vendored package is untrusted input: a `../` or
|
|
118
126
|
* absolute entry would make apply/load read a file from anywhere on disk.
|
|
119
|
-
*
|
|
120
|
-
* Generalizes the pre-#241 theme-only `assertThemeSheetsContained` (still
|
|
121
|
-
* once exported under that name from the theme manager, now this
|
|
122
|
-
* function) to the three new fields: a `gutterpress.json`-formatted theme
|
|
123
|
-
* folder can declare `markdown`/`components`/`snippets` too, so the SAME
|
|
124
|
-
* write-boundary guard must cover them, not just `styles`.
|
|
125
127
|
* `tokensFile` is included even though it is advisory/unenforced elsewhere —
|
|
126
128
|
* defense in depth against a future consumer reading it unchecked.
|
|
127
129
|
*
|
|
128
|
-
* A WRITE-BOUNDARY guard, not a read-path check
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* copied or wired, never while listing.
|
|
130
|
+
* A WRITE-BOUNDARY guard, not a read-path check: callers invoke this before
|
|
131
|
+
* copying anything or wiring a manifest, never from a plain listing/read
|
|
132
|
+
* path, so one hand-edited manifest cannot take down listing every extension.
|
|
133
|
+
* The removed `engineStyles` field (#266) is rejected here for the same
|
|
134
|
+
* reason: the error names the replacement, and it fires only where something
|
|
135
|
+
* would be copied or wired, never while listing.
|
|
135
136
|
*/
|
|
136
137
|
export declare function assertExtensionContained(meta: ExtensionMetadata): void;
|
|
137
138
|
/**
|
|
138
139
|
* An extension's declared paths, resolved to absolute, existence-checked
|
|
139
140
|
* filesystem paths — every list/single-path field goes through the SAME
|
|
140
|
-
* {@link resolveDeclaredStyles} a plugin's `styles` export and a
|
|
141
|
-
* `styles` already resolve through, so a broken
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* `snippets`, which nothing yet reads — #240/#242).
|
|
141
|
+
* {@link resolveDeclaredStyles} a plugin's `styles` export and a look's
|
|
142
|
+
* `styles` already resolve through, so a broken declaration (a missing file)
|
|
143
|
+
* throws HERE, at load/apply time, instead of failing silently deep in the
|
|
144
|
+
* render pipeline (or never, for `components`, which nothing yet reads).
|
|
145
145
|
*
|
|
146
146
|
* `tokensFile` is the one exception, kept as declared (relative, not
|
|
147
|
-
* existence-checked) — it stays purely advisory
|
|
148
|
-
* `ThemeInfo.tokensFile`'s pre-#241 contract.
|
|
147
|
+
* existence-checked) — it stays purely advisory.
|
|
149
148
|
*/
|
|
150
149
|
export interface ResolvedExtension {
|
|
151
|
-
/** Absolute path to the markdown-it entry module, when
|
|
150
|
+
/** Absolute path to the markdown-it entry module, when the folder has one. */
|
|
152
151
|
markdown?: string;
|
|
153
152
|
/** Absolute paths, in cascade order, when any are declared. */
|
|
154
153
|
styles?: string[];
|
|
@@ -156,17 +155,22 @@ export interface ResolvedExtension {
|
|
|
156
155
|
tokensFile?: string;
|
|
157
156
|
/** Absolute path to the component catalog file, when declared (#242). */
|
|
158
157
|
components?: string;
|
|
159
|
-
/** Absolute path to the snippets folder, when declared
|
|
158
|
+
/** Absolute path to the snippets folder, when declared. */
|
|
160
159
|
snippets?: string;
|
|
161
160
|
}
|
|
162
161
|
/**
|
|
163
162
|
* Resolve every path {@link ExtensionMetadata} declares, relative to `dir`
|
|
164
163
|
* (the extension's own folder). `subject` names the declaring thing for a
|
|
165
164
|
* resolution error, e.g. `Plugin "my-extension"` — passed straight through to
|
|
166
|
-
* `resolveDeclaredStyles`, so a broken
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
165
|
+
* `resolveDeclaredStyles`, so a broken entry throws the same "declares
|
|
166
|
+
* stylesheet ... but no file exists" shape a broken `styles` entry always has
|
|
167
|
+
* (the wording says "stylesheet" for every field — a small, accepted cost of
|
|
168
|
+
* resolving all of them through one function rather than inventing per-field
|
|
169
|
+
* messages).
|
|
170
|
+
*
|
|
171
|
+
* `markdown` resolves {@link extensionEntry} — the FOLDER rule. An
|
|
172
|
+
* npm-installed package's entry is whatever the installer resolved with full
|
|
173
|
+
* `exports` semantics, so `plugins.ts` calls this without `main` for that
|
|
174
|
+
* path; see its npm branch.
|
|
171
175
|
*/
|
|
172
176
|
export declare function resolveExtension(dir: string, meta: ExtensionMetadata, subject: string): ResolvedExtension;
|
|
@@ -34,7 +34,7 @@ export interface ScaffoldExtensionOptions {
|
|
|
34
34
|
export interface ScaffoldExtensionResult {
|
|
35
35
|
/** Absolute path of the created folder. */
|
|
36
36
|
extensionDir: string;
|
|
37
|
-
/** Absolute path of its `
|
|
37
|
+
/** Absolute path of its `package.json`. */
|
|
38
38
|
manifestPath: string;
|
|
39
39
|
kind: ExtensionKind;
|
|
40
40
|
/** Folder name / package name that was used. */
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Reject a response larger than this before parsing. */
|
|
2
|
+
export declare const MAX_SEARCH_BYTES: number;
|
|
3
|
+
/** What a match was found BY — the two conventions, in precedence order. */
|
|
4
|
+
export declare const SEARCH_KEYWORDS: readonly ["gutterpress", "markdown-it-plugin"];
|
|
5
|
+
export type ExtensionSearchKind = "gutterpress" | "markdown-it";
|
|
6
|
+
/** One npm package a book could install. */
|
|
7
|
+
export interface NpmExtensionMatch {
|
|
8
|
+
name: string;
|
|
9
|
+
version: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
/** `gutterpress` when the package tags itself as an extension; otherwise a
|
|
12
|
+
* plain markdown-it plugin found by the ecosystem keyword. */
|
|
13
|
+
kind: ExtensionSearchKind;
|
|
14
|
+
keywords: string[];
|
|
15
|
+
homepage?: string;
|
|
16
|
+
/** The package's page on the registry's website, when it published one. */
|
|
17
|
+
npmUrl?: string;
|
|
18
|
+
/** Last publish date, as the registry reported it. */
|
|
19
|
+
date?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface NpmExtensionSearchResult {
|
|
22
|
+
matches: NpmExtensionMatch[];
|
|
23
|
+
/** What the registry said it had, summed over both keyword queries — the
|
|
24
|
+
* "showing N of M" denominator, not a count of `matches`. */
|
|
25
|
+
total: number;
|
|
26
|
+
}
|
|
27
|
+
export interface SearchNpmExtensionsOptions {
|
|
28
|
+
/** Dependency injection for tests; production uses global fetch. */
|
|
29
|
+
fetch?: typeof globalThis.fetch;
|
|
30
|
+
/** How many matches to return, and the `size` of each registry query. */
|
|
31
|
+
limit?: number;
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Search npm for installable extensions.
|
|
36
|
+
*
|
|
37
|
+
* One request per keyword (`gutterpress`, then `markdown-it-plugin`), merged
|
|
38
|
+
* and de-duplicated by package name — a package carrying BOTH keywords is one
|
|
39
|
+
* row, reported as a Gutterpress extension. Ordering puts Gutterpress-tagged
|
|
40
|
+
* packages first (they are the ones built for this tool), then the registry's
|
|
41
|
+
* own relevance score.
|
|
42
|
+
*
|
|
43
|
+
* Throws a friendly, author-facing error on any failure (offline, timeout, bad
|
|
44
|
+
* HTTP status, oversize body, malformed JSON, or a shape that doesn't match).
|
|
45
|
+
*/
|
|
46
|
+
export declare function searchNpmExtensions(query: string, options?: SearchNpmExtensionsOptions): Promise<NpmExtensionSearchResult>;
|
|
@@ -16,13 +16,9 @@
|
|
|
16
16
|
export interface AutoSnapshotPolicy {
|
|
17
17
|
/** Master switch — automatic snapshots default ON. */
|
|
18
18
|
autoSnapshot: boolean;
|
|
19
|
-
/** Minutes of quiet after the last edit before a snapshot fires. */
|
|
20
|
-
autoSnapshotMinutes: number;
|
|
21
19
|
}
|
|
22
|
-
/**
|
|
23
|
-
*
|
|
24
|
-
export declare const AUTO_SNAPSHOT_MIN_MINUTES = 5;
|
|
25
|
-
export declare const AUTO_SNAPSHOT_MAX_MINUTES: number;
|
|
20
|
+
/** Quiet period before a snapshot fires. Fixed (#274) — no longer a settings
|
|
21
|
+
* knob, so there is nothing left to clamp. */
|
|
26
22
|
export declare const AUTO_SNAPSHOT_DEFAULT_MINUTES = 10;
|
|
27
23
|
/** User-facing auto-sync policy (mirrors the desktop's settings group). */
|
|
28
24
|
export interface AutoSyncPolicy {
|
|
@@ -32,10 +28,10 @@ export interface AutoSyncPolicy {
|
|
|
32
28
|
autoSyncMinutes: number;
|
|
33
29
|
}
|
|
34
30
|
/**
|
|
35
|
-
* Cadence bounds for the periodic safety sync. The floor (1 min) is
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
31
|
+
* Cadence bounds for the periodic safety sync. The floor (1 min) is low
|
|
32
|
+
* because a network round-trip is cheaper than a full tree walk, and the
|
|
33
|
+
* transparent-sync plan targets ~2 min as the default cadence. The ceiling
|
|
34
|
+
* (one day) means "effectively paused" for an absurdly large configured value.
|
|
39
35
|
*/
|
|
40
36
|
export declare const AUTO_SYNC_MIN_MINUTES = 1;
|
|
41
37
|
export declare const AUTO_SYNC_MAX_MINUTES: number;
|
|
@@ -56,9 +52,11 @@ export declare const AUTO_SYNC_PUSH_INTERVAL_MINUTES = 15;
|
|
|
56
52
|
* `null` when automatic snapshots are disabled. Pure — the testable core of
|
|
57
53
|
* the trigger policy (the timer itself lives in the Electron main process).
|
|
58
54
|
*
|
|
55
|
+
* The quiet period is fixed at `AUTO_SNAPSHOT_DEFAULT_MINUTES` (#274 — the
|
|
56
|
+
* minutes field this used to clamp was deleted from the settings schema, so
|
|
57
|
+
* there is nothing left to resolve here beyond the master switch).
|
|
59
58
|
* Defensive about persisted settings: a missing policy means "defaults"
|
|
60
|
-
* (enabled, 10 min)
|
|
61
|
-
* default and is then clamped into [5, 1440].
|
|
59
|
+
* (enabled, 10 min).
|
|
62
60
|
*/
|
|
63
61
|
export declare function autoSnapshotDelayMs(policy: Partial<AutoSnapshotPolicy> | undefined): number | null;
|
|
64
62
|
/**
|
|
@@ -2,21 +2,28 @@ export interface LintRunnerOptions {
|
|
|
2
2
|
files?: string;
|
|
3
3
|
manifest?: string;
|
|
4
4
|
/**
|
|
5
|
-
* Pre-loaded, absolute plugin `styles` file paths (#262)
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* as "unset".
|
|
5
|
+
* Pre-loaded, absolute plugin `styles` file paths (#262). `undefined` (the
|
|
6
|
+
* default — every standalone `gutterpress lint` invocation, which is now
|
|
7
|
+
* this function's only production caller since #272 removed the build
|
|
8
|
+
* pipeline's own separate lint gate) makes this function load plugins
|
|
9
|
+
* itself, degrade-and-report (warn-and-skip) for a plugin that fails to
|
|
10
|
+
* load. An explicit `[]` or a pre-loaded list from a caller that already
|
|
11
|
+
* knows the resolved plugin styles for this manifest is honored as-is, not
|
|
12
|
+
* treated as "unset".
|
|
14
13
|
*/
|
|
15
14
|
pluginStylePaths?: string[];
|
|
16
15
|
}
|
|
17
16
|
export interface LintRunnerResult {
|
|
18
17
|
ok: boolean;
|
|
18
|
+
/** Count of `printsafe/no-risky-print-effects` findings across every linted file. */
|
|
19
19
|
riskyCount: number;
|
|
20
|
+
/**
|
|
21
|
+
* Count of `printsafe/page-containment` findings across every linted file
|
|
22
|
+
* (#272). Kept separate from {@link riskyCount} rather than folded into it,
|
|
23
|
+
* so a consumer can tell the two finding kinds apart without re-parsing
|
|
24
|
+
* printed text.
|
|
25
|
+
*/
|
|
26
|
+
containmentCount: number;
|
|
20
27
|
filesLinted: number;
|
|
21
28
|
}
|
|
22
29
|
export declare function runLint(opts?: LintRunnerOptions): Promise<LintRunnerResult>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The npm registry Gutterpress talks to (#246) — ONE resolver for the two
|
|
3
|
+
* places that reach it: the installer (`npm-plugin-installer.ts`: metadata,
|
|
4
|
+
* tarballs, and the tarball-origin check) and extension search
|
|
5
|
+
* (`extension-search.ts`).
|
|
6
|
+
*
|
|
7
|
+
* `GUTTERPRESS_NPM_REGISTRY` points both at a private mirror, and is what the
|
|
8
|
+
* CLI's own tests serve a fake registry at. It is validated the same way every
|
|
9
|
+
* other author-supplied URL in this package is — http(s) only — because a
|
|
10
|
+
* `file:`/`data:` registry would turn "install a package" into "read an
|
|
11
|
+
* arbitrary path".
|
|
12
|
+
*
|
|
13
|
+
* Bundle-safe (CLAUDE.md §1/§3): pure string work over `process.env`, no deps.
|
|
14
|
+
*/
|
|
15
|
+
/** The public registry, used when nothing overrides it. */
|
|
16
|
+
export declare const DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
17
|
+
/**
|
|
18
|
+
* The configured registry's base URL, without a trailing slash (every caller
|
|
19
|
+
* builds `${registry}/<path>` and a doubled slash breaks path-sensitive
|
|
20
|
+
* mirrors). Throws on an override that is not an http(s) URL.
|
|
21
|
+
*/
|
|
22
|
+
export declare function npmRegistryUrl(): string;
|
|
@@ -239,4 +239,75 @@ export declare const AUTO_SNAPSHOT_MESSAGE = "Automatic snapshot";
|
|
|
239
239
|
* folder has no version history.
|
|
240
240
|
*/
|
|
241
241
|
export declare function restoreVersionWithBackup(options: RestoreVersionOptions): Promise<RestoreVersionResult>;
|
|
242
|
+
/** The project's copies (git branches) and which one is currently open. */
|
|
243
|
+
export interface LocalBranches {
|
|
244
|
+
/** Name of the branch HEAD points to, or `null` on a detached/unborn HEAD. */
|
|
245
|
+
current: string | null;
|
|
246
|
+
/**
|
|
247
|
+
* Every copy the project can switch to, sorted: local branches
|
|
248
|
+
* (`refs/heads/*`) plus copies that so far exist only on a remote.
|
|
249
|
+
*/
|
|
250
|
+
branches: string[];
|
|
251
|
+
/**
|
|
252
|
+
* The subset of {@link branches} with no local ref yet. Switching to one of
|
|
253
|
+
* these creates the local copy from the remote and tracks it; the UI uses
|
|
254
|
+
* this only to say so before it happens.
|
|
255
|
+
*/
|
|
256
|
+
remoteOnly: string[];
|
|
257
|
+
}
|
|
258
|
+
/** Inputs for {@link switchBranch}. */
|
|
259
|
+
export interface SwitchBranchOptions {
|
|
260
|
+
projectDir: string;
|
|
261
|
+
/** Branch name to check out — local, or one that so far exists only on a remote. */
|
|
262
|
+
branch: string;
|
|
263
|
+
/** Identity recorded on the automatic pre-switch safety snapshot, if one is taken. */
|
|
264
|
+
authorName?: string;
|
|
265
|
+
authorEmail?: string;
|
|
266
|
+
}
|
|
267
|
+
/** Result of a successful {@link switchBranch}. */
|
|
268
|
+
export interface SwitchBranchResult {
|
|
269
|
+
/** The branch now checked out (equals `options.branch`). */
|
|
270
|
+
current: string;
|
|
271
|
+
/**
|
|
272
|
+
* Absolute paths of every file the checkout added, removed, or changed the
|
|
273
|
+
* content of (a diff of the old HEAD's tree against the new branch's tree,
|
|
274
|
+
* computed before the checkout runs). The host uses this to drop crash-
|
|
275
|
+
* recovery drafts for these paths — see recovery.ts's header: a draft taken
|
|
276
|
+
* on the copy just left behind must never be offered over a DIFFERENT copy's
|
|
277
|
+
* version of the same file.
|
|
278
|
+
*/
|
|
279
|
+
changedFiles: string[];
|
|
280
|
+
}
|
|
281
|
+
/** Snapshot message for the safety snapshot {@link switchBranch} takes before checking out, when the working tree has changes. */
|
|
282
|
+
export declare const SWITCH_BRANCH_SNAPSHOT_MESSAGE = "Saved before switching copy";
|
|
283
|
+
/**
|
|
284
|
+
* List the project's copies (git branches) and which one is open, for a
|
|
285
|
+
* `local-git-folder` project. Returns `null` for any other source type —
|
|
286
|
+
* there is nothing to switch between, and the caller (the Saving settings row)
|
|
287
|
+
* hides the whole control on `null` rather than showing an error.
|
|
288
|
+
*
|
|
289
|
+
* Copies that exist only on a remote are included: they are as real to the
|
|
290
|
+
* author as the local ones, and {@link switchBranch} creates the local branch
|
|
291
|
+
* on the way in.
|
|
292
|
+
*/
|
|
293
|
+
export declare function listLocalBranches(dir: string): Promise<LocalBranches | null>;
|
|
294
|
+
/**
|
|
295
|
+
* Switch the project's working tree to another local copy (git branch).
|
|
296
|
+
*
|
|
297
|
+
* Safety, in order (see the issue's "what the switch has to take care of"):
|
|
298
|
+
* 1. If the working tree has uncommitted changes, snapshot them first (so
|
|
299
|
+
* nothing the author typed is lost) and tolerate the expected
|
|
300
|
+
* "no changes" rejection when it doesn't.
|
|
301
|
+
* 2. Check out the target branch WITHOUT `force` — isomorphic-git then
|
|
302
|
+
* refuses (CheckoutConflictError) rather than silently overwriting a
|
|
303
|
+
* working-tree file that moved after the snapshot above, which is
|
|
304
|
+
* reported as a friendly error instead of a forced checkout.
|
|
305
|
+
* 3. Report every path the checkout touched so the host can drop stale
|
|
306
|
+
* crash-recovery drafts for them (see {@link SwitchBranchResult}).
|
|
307
|
+
*
|
|
308
|
+
* Pause/resume of the auto-snapshot/auto-sync host timers around the
|
|
309
|
+
* checkout, and refreshing the open editor/file-tree/preview afterwards, are
|
|
310
|
+
* host (desktop) responsibilities — this function only does the git work.
|
|
311
|
+
*/
|
|
312
|
+
export declare function switchBranch(options: SwitchBranchOptions): Promise<SwitchBranchResult>;
|
|
242
313
|
export {};
|
|
@@ -26,6 +26,17 @@ export interface ValidationExecutionArgs {
|
|
|
26
26
|
* "unset".
|
|
27
27
|
*/
|
|
28
28
|
pluginStylePaths?: string[];
|
|
29
|
+
/**
|
|
30
|
+
* Disable the `source.stylelint` check (CSS print-safety) for this run
|
|
31
|
+
* only, without touching the manifest's `validate.source.stylelint`
|
|
32
|
+
* setting on disk (#272 — one CSS gate, not two). Set by the build
|
|
33
|
+
* pipeline's `runQualityGates` (build-runner.ts) from `--skip-lint` /
|
|
34
|
+
* `config.lint.enabled: false`, so that flag disables just the one check
|
|
35
|
+
* it always meant to gate rather than a whole separate lint pass. Every
|
|
36
|
+
* other caller (`gutterpress validate`/`preflight`/`audit`, the desktop
|
|
37
|
+
* Problems panel) leaves this unset and gets the manifest's own setting.
|
|
38
|
+
*/
|
|
39
|
+
skipStylelint?: boolean;
|
|
29
40
|
}
|
|
30
41
|
export interface ValidationExecutionResult {
|
|
31
42
|
config: ResolvedConfig;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MANIFEST_FILENAMES,
|
|
3
3
|
runLint
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-n0vgey6x.js";
|
|
5
5
|
import {
|
|
6
6
|
log
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-2rswy18t.js";
|
|
8
8
|
import {
|
|
9
9
|
UsageError,
|
|
10
10
|
rejectExtraPositionals,
|
|
11
11
|
rejectUnknownFlags
|
|
12
|
-
} from "./cli-
|
|
13
|
-
import"./cli-
|
|
12
|
+
} from "./cli-scqp638v.js";
|
|
13
|
+
import"./cli-k8f9eb12.js";
|
|
14
14
|
import"./cli-c41yr7he.js";
|
|
15
15
|
import {
|
|
16
16
|
EXIT_CODES
|
|
17
17
|
} from "./cli-46ycxe6r.js";
|
|
18
|
-
import"./cli-
|
|
18
|
+
import"./cli-4mtf9ajw.js";
|
|
19
19
|
import"./cli-v5mp7a6q.js";
|
|
20
20
|
import"./cli-37x76zdn.js";
|
|
21
21
|
|
|
@@ -7,23 +7,23 @@ import {
|
|
|
7
7
|
TARGET_IDS,
|
|
8
8
|
scaffoldExtension,
|
|
9
9
|
scaffoldProject
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-n0vgey6x.js";
|
|
11
11
|
import {
|
|
12
12
|
resolveGhostscript
|
|
13
|
-
} from "./cli-
|
|
13
|
+
} from "./cli-2rswy18t.js";
|
|
14
14
|
import {
|
|
15
15
|
UsageError,
|
|
16
16
|
rejectExtraPositionals,
|
|
17
17
|
rejectUnknownFlags
|
|
18
|
-
} from "./cli-
|
|
19
|
-
import"./cli-
|
|
18
|
+
} from "./cli-scqp638v.js";
|
|
19
|
+
import"./cli-k8f9eb12.js";
|
|
20
20
|
import {
|
|
21
21
|
isToolAvailable
|
|
22
22
|
} from "./cli-c41yr7he.js";
|
|
23
23
|
import {
|
|
24
24
|
EXIT_CODES
|
|
25
25
|
} from "./cli-46ycxe6r.js";
|
|
26
|
-
import"./cli-
|
|
26
|
+
import"./cli-4mtf9ajw.js";
|
|
27
27
|
import"./cli-v5mp7a6q.js";
|
|
28
28
|
import"./cli-37x76zdn.js";
|
|
29
29
|
|
|
@@ -163,7 +163,7 @@ async function runExtensionScaffold(kind, name, parentDir, args) {
|
|
|
163
163
|
console.log(` gutterpress ext add ./${result.slug} <book>`);
|
|
164
164
|
console.log("");
|
|
165
165
|
console.log(" (that lists the FOLDER under `extensions:` in the book's manifest —");
|
|
166
|
-
console.log(" not plugin.js — which is what makes Gutterpress read
|
|
166
|
+
console.log(" not plugin.js — which is what makes Gutterpress read package.json");
|
|
167
167
|
console.log(" and pick up the stylesheet too.)");
|
|
168
168
|
} else {
|
|
169
169
|
console.log("Next: add it to a book —");
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clean-book",
|
|
3
|
+
"description": "A calm, classic book look: serif body, generous margins, restrained accents.",
|
|
4
|
+
"author": "gutterpress",
|
|
5
|
+
"keywords": ["gutterpress", "gutterpress-look"],
|
|
6
|
+
"gutterpress": {
|
|
7
|
+
"styles": ["theme.css"],
|
|
8
|
+
"preview": null
|
|
9
|
+
}
|
|
10
|
+
}
|