@hominis/fireforge 0.18.0 → 0.18.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 (52) hide show
  1. package/CHANGELOG.md +18 -2
  2. package/README.md +55 -34
  3. package/dist/src/commands/doctor.js +13 -1
  4. package/dist/src/commands/export-all.js +63 -1
  5. package/dist/src/commands/export-flow.d.ts +4 -0
  6. package/dist/src/commands/export-flow.js +8 -0
  7. package/dist/src/commands/export.js +26 -2
  8. package/dist/src/commands/furnace/create-xpcshell.js +4 -2
  9. package/dist/src/commands/furnace/preview.js +38 -0
  10. package/dist/src/commands/furnace/remove.js +67 -1
  11. package/dist/src/commands/furnace/rename-xpcshell.d.ts +35 -0
  12. package/dist/src/commands/furnace/rename-xpcshell.js +97 -0
  13. package/dist/src/commands/furnace/rename.js +9 -0
  14. package/dist/src/commands/patch/index.d.ts +5 -3
  15. package/dist/src/commands/patch/index.js +10 -4
  16. package/dist/src/commands/patch/lint-ignore.d.ts +39 -0
  17. package/dist/src/commands/patch/lint-ignore.js +200 -0
  18. package/dist/src/commands/patch/tier.d.ts +34 -0
  19. package/dist/src/commands/patch/tier.js +134 -0
  20. package/dist/src/commands/re-export-files.js +88 -45
  21. package/dist/src/commands/re-export.js +49 -6
  22. package/dist/src/commands/rebase/index.js +19 -1
  23. package/dist/src/commands/status.js +44 -5
  24. package/dist/src/commands/test.js +27 -16
  25. package/dist/src/commands/verify.js +81 -6
  26. package/dist/src/commands/watch.js +43 -7
  27. package/dist/src/core/furnace-constants.d.ts +14 -0
  28. package/dist/src/core/furnace-constants.js +16 -0
  29. package/dist/src/core/furnace-validate.js +67 -1
  30. package/dist/src/core/git-base.d.ts +27 -2
  31. package/dist/src/core/git-base.js +41 -3
  32. package/dist/src/core/git-diff.js +34 -2
  33. package/dist/src/core/git.js +53 -14
  34. package/dist/src/core/mach.d.ts +14 -2
  35. package/dist/src/core/mach.js +12 -2
  36. package/dist/src/core/marionette-preflight.d.ts +16 -0
  37. package/dist/src/core/marionette-preflight.js +19 -0
  38. package/dist/src/core/patch-export.d.ts +77 -2
  39. package/dist/src/core/patch-export.js +82 -3
  40. package/dist/src/core/patch-lint-diff-tag.d.ts +20 -0
  41. package/dist/src/core/patch-lint-diff-tag.js +25 -0
  42. package/dist/src/core/patch-lint.js +82 -32
  43. package/dist/src/core/patch-registration-refs.d.ts +42 -0
  44. package/dist/src/core/patch-registration-refs.js +117 -0
  45. package/dist/src/core/xpcshell-appdir.d.ts +19 -5
  46. package/dist/src/core/xpcshell-appdir.js +46 -20
  47. package/dist/src/errors/git.d.ts +20 -0
  48. package/dist/src/errors/git.js +39 -0
  49. package/dist/src/types/commands/index.d.ts +1 -1
  50. package/dist/src/types/commands/options.d.ts +67 -0
  51. package/dist/src/types/commands/patches.d.ts +6 -5
  52. package/package.json +1 -1
@@ -0,0 +1,117 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Extracts furnace-shaped registration references from a patch body.
4
+ *
5
+ * 2026-04-24 eval Finding 1: `export-all --exclude-furnace` can land a
6
+ * patch that registers a furnace component (via edits to
7
+ * `toolkit/content/customElements.js`, `toolkit/content/jar.mn`, or
8
+ * `toolkit/locales/jar.mn`) without including the component's source
9
+ * files in the patch. `fireforge verify` then reports "Verify clean" for
10
+ * the broken queue. This module provides a pattern-scoped scan so
11
+ * `verify` can cross-check registrations against available file bodies.
12
+ *
13
+ * The scan is deliberately narrow: it only matches component-shaped
14
+ * references (widget tag names, locale fluent names). Unrelated jar.mn
15
+ * or customElements.js edits pass through without spurious warnings.
16
+ */
17
+ /** Canonical file paths that registration-shaped diffs touch. */
18
+ const REGISTRATION_FILE_PATHS = new Set([
19
+ 'toolkit/content/customElements.js',
20
+ 'toolkit/content/jar.mn',
21
+ 'toolkit/locales/jar.mn',
22
+ ]);
23
+ /**
24
+ * Walks a unified-diff patch body and returns the set of
25
+ * component-shaped engine paths that the patch ADDS a registration for.
26
+ *
27
+ * Returns the empty array when no registration hunks are present OR
28
+ * when the registration hunks do not mention any component-shaped
29
+ * paths — that leaves the scan silent on the vast majority of patches
30
+ * (branding tweaks, behavioural fixes, module additions) so it only
31
+ * fires when a furnace-managed component is being newly registered.
32
+ *
33
+ * @param patchBody - Full unified-diff body of the patch file.
34
+ */
35
+ export function collectPatchRegistrationReferences(patchBody) {
36
+ if (!patchBody)
37
+ return [];
38
+ const refs = [];
39
+ let currentFile;
40
+ // Walk line-by-line. The canonical unified-diff header line is
41
+ // `diff --git a/<path> b/<path>` — we key the file state off the `b/`
42
+ // path because that names the target side and is stable against
43
+ // renames. Additional diff metadata lines (index/---/+++/@@) are
44
+ // ignored for the purposes of tracking the current file.
45
+ const lines = patchBody.split(/\r?\n/);
46
+ for (const line of lines) {
47
+ const diffHeader = /^diff --git a\/(.+?) b\/(.+)$/.exec(line);
48
+ if (diffHeader?.[2]) {
49
+ currentFile = diffHeader[2];
50
+ continue;
51
+ }
52
+ if (!currentFile)
53
+ continue;
54
+ if (!REGISTRATION_FILE_PATHS.has(currentFile))
55
+ continue;
56
+ if (!line.startsWith('+'))
57
+ continue;
58
+ // Skip the `+++ b/<path>` header line — only real hunk adds count.
59
+ if (line.startsWith('+++'))
60
+ continue;
61
+ const added = line.slice(1);
62
+ const extracted = extractTargetPathsFromRegistrationLine(currentFile, added);
63
+ for (const target of extracted) {
64
+ refs.push({ targetPath: target, source: currentFile, lineText: added });
65
+ }
66
+ }
67
+ return refs;
68
+ }
69
+ /**
70
+ * Per-source extractor. Each registration file has a distinct syntactic
71
+ * shape; we scope the match to that file so a jar.mn regex does not
72
+ * accidentally match a customElements.js line.
73
+ */
74
+ function extractTargetPathsFromRegistrationLine(sourceFile, added) {
75
+ if (sourceFile === 'toolkit/content/jar.mn') {
76
+ // Example (added line, leading `+` already stripped):
77
+ // ` content/global/elements/moz-qa-panel.mjs (widgets/moz-qa-panel/moz-qa-panel.mjs)`
78
+ // The parenthesised second half is the repo-relative path Firefox's
79
+ // packaging system reads. Widget registrations always live under
80
+ // `widgets/<tag>/<file>` — the enclosing tree is
81
+ // `toolkit/content/widgets/`. Reconstruct the engine-relative
82
+ // target path so callers can check it against patch bodies.
83
+ const widgetMatch = /\(\s*(widgets\/[^\s)]+)\s*\)/.exec(added);
84
+ if (widgetMatch?.[1]) {
85
+ return [`toolkit/content/${widgetMatch[1]}`];
86
+ }
87
+ return [];
88
+ }
89
+ if (sourceFile === 'toolkit/locales/jar.mn') {
90
+ // Example:
91
+ // ` locale/@AB_CD@/toolkit/global/moz-qa-panel.ftl (%toolkit/global/moz-qa-panel.ftl)`
92
+ // The `%`-prefixed repo-relative reference points at
93
+ // `toolkit/locales/en-US/<rel>`, which is the canonical FTL path.
94
+ const localeMatch = /\(%\s*([^\s)]+\.ftl)\s*\)/.exec(added);
95
+ if (localeMatch?.[1]) {
96
+ return [`toolkit/locales/en-US/${localeMatch[1]}`];
97
+ }
98
+ return [];
99
+ }
100
+ if (sourceFile === 'toolkit/content/customElements.js') {
101
+ // Example:
102
+ // ` ["moz-qa-panel", "chrome://global/content/elements/moz-qa-panel.mjs"],`
103
+ // The chrome URL maps back to
104
+ // `toolkit/content/widgets/<tag>/<tag>.mjs` by convention: the
105
+ // packager rewrites `chrome://global/content/elements/<file>` to the
106
+ // widget tree root. The tag name is the identifier we key off.
107
+ const elementMatch = /\[\s*"([a-z][a-z0-9-]*)"\s*,\s*"chrome:\/\/global\/content\/elements\/([a-zA-Z0-9_-]+)\.mjs"\s*\]/.exec(added);
108
+ if (elementMatch?.[1] && elementMatch[2]) {
109
+ const tag = elementMatch[1];
110
+ const fileStem = elementMatch[2];
111
+ return [`toolkit/content/widgets/${tag}/${fileStem}.mjs`];
112
+ }
113
+ return [];
114
+ }
115
+ return [];
116
+ }
117
+ //# sourceMappingURL=patch-registration-refs.js.map
@@ -96,11 +96,25 @@ export declare function readMozinfoAppname(objDirPath: string): Promise<string>;
96
96
  * (which fails with a different error than the original `firefox-appdir`
97
97
  * symptom and confuses triage).
98
98
  *
99
- * Probe order matches the on-disk layouts FireForge supports today:
100
- * 1. `<objDir>/dist/bin/<value>` — Linux primary, also macOS via the
101
- * `dist/bin -> dist/<App>.app/Contents/MacOS/` symlink.
102
- * 2. `<objDir>/dist/<bundle>.app/Contents/Resources/<value>` — macOS
103
- * packaged layout, where `dist/bin/` may not exist as a directory.
99
+ * Probe order differs by host platform:
100
+ *
101
+ * - **macOS (`darwin`)**: prefer `<objDir>/dist/<App>.app/Contents/Resources/
102
+ * <value>` FIRST, then fall back to `<objDir>/dist/bin/<value>`.
103
+ * 2026-04-24 eval Finding 8: on macOS `dist/bin` is symlinked to
104
+ * `dist/<App>.app/Contents/MacOS/` (the *binaries* directory), so
105
+ * `dist/bin/browser` actually resolves to `<App>.app/Contents/MacOS/
106
+ * browser/`. That is NOT where `resource:///modules/` is rooted — on
107
+ * macOS, `-a` for xpcshell must point at the `.app/Contents/Resources/
108
+ * <value>` subtree where modules / chrome.manifest live. Returning
109
+ * `dist/bin/browser` caused the injected `--app-path` to look
110
+ * successful (the info log showed it) but pointed at a directory
111
+ * without the modules tree, so every `resource:///modules/…` import
112
+ * still threw.
113
+ * - **non-macOS**: keep the historical order — `dist/bin/<value>` first,
114
+ * `.app/Contents/Resources/<value>` as fallback.
115
+ *
116
+ * On both platforms the final `.app` fallback iterates every `*.app`
117
+ * entry because a rebranded fork may pick an arbitrary app name.
104
118
  */
105
119
  export declare function resolveAbsoluteAppPath(objDirAbs: string, relativeAppdir: string): Promise<string | null>;
106
120
  /**
@@ -164,34 +164,60 @@ export async function readMozinfoAppname(objDirPath) {
164
164
  * (which fails with a different error than the original `firefox-appdir`
165
165
  * symptom and confuses triage).
166
166
  *
167
- * Probe order matches the on-disk layouts FireForge supports today:
168
- * 1. `<objDir>/dist/bin/<value>` — Linux primary, also macOS via the
169
- * `dist/bin -> dist/<App>.app/Contents/MacOS/` symlink.
170
- * 2. `<objDir>/dist/<bundle>.app/Contents/Resources/<value>` — macOS
171
- * packaged layout, where `dist/bin/` may not exist as a directory.
167
+ * Probe order differs by host platform:
168
+ *
169
+ * - **macOS (`darwin`)**: prefer `<objDir>/dist/<App>.app/Contents/Resources/
170
+ * <value>` FIRST, then fall back to `<objDir>/dist/bin/<value>`.
171
+ * 2026-04-24 eval Finding 8: on macOS `dist/bin` is symlinked to
172
+ * `dist/<App>.app/Contents/MacOS/` (the *binaries* directory), so
173
+ * `dist/bin/browser` actually resolves to `<App>.app/Contents/MacOS/
174
+ * browser/`. That is NOT where `resource:///modules/` is rooted — on
175
+ * macOS, `-a` for xpcshell must point at the `.app/Contents/Resources/
176
+ * <value>` subtree where modules / chrome.manifest live. Returning
177
+ * `dist/bin/browser` caused the injected `--app-path` to look
178
+ * successful (the info log showed it) but pointed at a directory
179
+ * without the modules tree, so every `resource:///modules/…` import
180
+ * still threw.
181
+ * - **non-macOS**: keep the historical order — `dist/bin/<value>` first,
182
+ * `.app/Contents/Resources/<value>` as fallback.
183
+ *
184
+ * On both platforms the final `.app` fallback iterates every `*.app`
185
+ * entry because a rebranded fork may pick an arbitrary app name.
172
186
  */
173
187
  export async function resolveAbsoluteAppPath(objDirAbs, relativeAppdir) {
174
188
  const distBinCandidate = join(objDirAbs, 'dist', 'bin', relativeAppdir);
175
- if (await pathExists(distBinCandidate))
176
- return distBinCandidate;
177
189
  const distDir = join(objDirAbs, 'dist');
178
- if (!(await pathExists(distDir)))
190
+ const isMacos = process.platform === 'darwin';
191
+ async function probeMacAppBundle() {
192
+ if (!(await pathExists(distDir)))
193
+ return null;
194
+ let entries;
195
+ try {
196
+ entries = await readdir(distDir);
197
+ }
198
+ catch {
199
+ return null;
200
+ }
201
+ for (const entry of entries) {
202
+ if (!entry.endsWith('.app'))
203
+ continue;
204
+ const candidate = join(distDir, entry, 'Contents', 'Resources', relativeAppdir);
205
+ if (await pathExists(candidate))
206
+ return candidate;
207
+ }
179
208
  return null;
180
- let entries;
181
- try {
182
- entries = await readdir(distDir);
183
209
  }
184
- catch {
210
+ if (isMacos) {
211
+ const appBundle = await probeMacAppBundle();
212
+ if (appBundle)
213
+ return appBundle;
214
+ if (await pathExists(distBinCandidate))
215
+ return distBinCandidate;
185
216
  return null;
186
217
  }
187
- for (const entry of entries) {
188
- if (!entry.endsWith('.app'))
189
- continue;
190
- const candidate = join(distDir, entry, 'Contents', 'Resources', relativeAppdir);
191
- if (await pathExists(candidate))
192
- return candidate;
193
- }
194
- return null;
218
+ if (await pathExists(distBinCandidate))
219
+ return distBinCandidate;
220
+ return probeMacAppBundle();
195
221
  }
196
222
  /**
197
223
  * Top-level resolver. Walks every test path, reads the nearest
@@ -39,3 +39,23 @@ export declare class GitIndexLockError extends GitError {
39
39
  constructor(lockPath: string, ageMs?: number | undefined);
40
40
  get userMessage(): string;
41
41
  }
42
+ /**
43
+ * Error thrown when `git add` (monolithic or chunked) exceeds the
44
+ * configured timeout while indexing the Firefox source tree.
45
+ *
46
+ * 2026-04-24 eval Finding 10: a 140.10.0esr bump on a previously-working
47
+ * 140.9.0esr workspace aborted after ~854s with a generic
48
+ * `AbortError: The operation was aborted`. The root cause was the
49
+ * `git add` timeout firing, but the surfaced error was indistinguishable
50
+ * from any other AbortError and gave the operator no actionable
51
+ * direction. This typed error carries the elapsed budget and the
52
+ * environment-variable override so the recovery path is
53
+ * self-documenting.
54
+ */
55
+ export declare class GitIndexingTimeoutError extends GitError {
56
+ readonly phase: 'monolithic' | 'chunked';
57
+ readonly timeoutMs: number;
58
+ readonly envVar: string;
59
+ constructor(phase: 'monolithic' | 'chunked', timeoutMs: number, envVar: string, cause?: Error);
60
+ get userMessage(): string;
61
+ }
@@ -96,4 +96,43 @@ export class GitIndexLockError extends GitError {
96
96
  ' 3. Re-run "fireforge download --force"');
97
97
  }
98
98
  }
99
+ /**
100
+ * Error thrown when `git add` (monolithic or chunked) exceeds the
101
+ * configured timeout while indexing the Firefox source tree.
102
+ *
103
+ * 2026-04-24 eval Finding 10: a 140.10.0esr bump on a previously-working
104
+ * 140.9.0esr workspace aborted after ~854s with a generic
105
+ * `AbortError: The operation was aborted`. The root cause was the
106
+ * `git add` timeout firing, but the surfaced error was indistinguishable
107
+ * from any other AbortError and gave the operator no actionable
108
+ * direction. This typed error carries the elapsed budget and the
109
+ * environment-variable override so the recovery path is
110
+ * self-documenting.
111
+ */
112
+ export class GitIndexingTimeoutError extends GitError {
113
+ phase;
114
+ timeoutMs;
115
+ envVar;
116
+ constructor(phase, timeoutMs, envVar, cause) {
117
+ super(`Git ${phase} indexing exceeded the ${Math.round(timeoutMs / 1000)}s timeout`, 'add -A', cause);
118
+ this.phase = phase;
119
+ this.timeoutMs = timeoutMs;
120
+ this.envVar = envVar;
121
+ }
122
+ get userMessage() {
123
+ const minutes = Math.max(1, Math.round(this.timeoutMs / 60_000));
124
+ const phaseDescription = this.phase === 'monolithic'
125
+ ? 'the monolithic `git add -A` pass'
126
+ : 'one of the chunked `git add -- <dir>` passes';
127
+ return (`Git Error: ${phaseDescription} exceeded the ${minutes}-minute timeout while indexing the Firefox source tree.\n\n` +
128
+ 'Common triggers:\n' +
129
+ ' - Slow or loaded disk (an external volume, encrypted filesystem, or heavily-used SSD under load).\n' +
130
+ ' - A Firefox source tree that has grown beyond what the default timeout accommodates.\n' +
131
+ ' - A background process (antivirus, backup, indexing) holding the working directory.\n\n' +
132
+ 'To recover:\n' +
133
+ ` 1. Extend the timeout via the ${this.envVar} environment variable (milliseconds; e.g. "export ${this.envVar}=1800000" for 30 minutes).\n` +
134
+ ' 2. Re-run "fireforge download --force" — the resume path resumes from the partial initialisation, so the repeat pass is not wasted work.\n' +
135
+ ' 3. If the problem persists, check disk throughput and free space; Firefox source indexing on a cold SSD typically completes in 1–3 minutes.');
136
+ }
137
+ }
99
138
  //# sourceMappingURL=git.js.map
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Re-exports all command-related types from focused sub-modules.
3
3
  */
4
- export type { BuildOptions, DiscardOptions, DoctorOptions, DownloadOptions, ExportOptions, FurnaceApplyOptions, FurnaceCreateOptions, FurnaceDeployOptions, FurnaceOverrideOptions, FurnacePreviewOptions, FurnaceRefreshOptions, FurnaceRemoveOptions, FurnaceSyncOptions, FurnaceValidateOptions, GlobalOptions, ImportOptions, PackageOptions, PatchCompactOptions, PatchDeleteOptions, PatchReorderOptions, RebaseOptions, ReExportOptions, RegisterOptions, ResetOptions, RunOptions, SetupOptions, StatusOptions, TestOptions, TokenAddOptions, WireOptions, } from './options.js';
4
+ export type { BuildOptions, DiscardOptions, DoctorOptions, DownloadOptions, ExportOptions, FurnaceApplyOptions, FurnaceCreateOptions, FurnaceDeployOptions, FurnaceOverrideOptions, FurnacePreviewOptions, FurnaceRefreshOptions, FurnaceRemoveOptions, FurnaceSyncOptions, FurnaceValidateOptions, GlobalOptions, ImportOptions, PackageOptions, PatchCompactOptions, PatchDeleteOptions, PatchLintIgnoreOptions, PatchReorderOptions, PatchTierOptions, RebaseOptions, ReExportOptions, RegisterOptions, ResetOptions, RunOptions, SetupOptions, StatusOptions, TestOptions, TokenAddOptions, WireOptions, } from './options.js';
5
5
  export type { ImportSummary, PatchCategory, PatchesManifest, PatchInfo, PatchLintIssue, PatchMetadata, PatchResult, } from './patches.js';
6
6
  export type { DoctorCheck, ProjectStatus, TokenCoverageFileEntry, TokenCoverageReport, } from './project.js';
@@ -93,6 +93,24 @@ export interface ExportOptions {
93
93
  * another patch, because the resulting queue fails `verify` immediately.
94
94
  */
95
95
  allowOverlap?: boolean;
96
+ /**
97
+ * Force a tier override on the new patch's `PatchMetadata.tier`. Only
98
+ * `"branding"` is currently recognised — Commander rejects other values
99
+ * before the handler runs. Use when a branding patch legitimately
100
+ * touches a non-allowlisted sibling that `isBrandingOnlyPatch` cannot
101
+ * reach (a fork-specific theme override under `browser/themes/<name>/`,
102
+ * a vendor-specific icon resource, etc.).
103
+ */
104
+ tier?: 'branding';
105
+ /**
106
+ * Lint check IDs to suppress on this patch. Writes to
107
+ * `PatchMetadata.lintIgnore`. Repeatable on the CLI; each occurrence
108
+ * appends to the list. Useful when a patch is advisory-noisy by nature
109
+ * (a cohesive branding bundle, an auto-generated manifest) and a
110
+ * specific check does not apply, but `--skip-lint` is too coarse a
111
+ * hammer.
112
+ */
113
+ lintIgnore?: string[];
96
114
  }
97
115
  /**
98
116
  * Options for the reset command.
@@ -172,6 +190,55 @@ export interface ReExportOptions {
172
190
  * `rebase`.
173
191
  */
174
192
  stamp?: boolean;
193
+ /**
194
+ * Force a tier override on the selected patch(es). Only `"branding"` is
195
+ * currently recognised. Mutually exclusive with `--all` — mass tier
196
+ * changes are virtually always footguns, since different patches in
197
+ * the queue have different shapes.
198
+ */
199
+ tier?: 'branding';
200
+ /**
201
+ * Lint check IDs to suppress, **appended** (union) to the patch's
202
+ * existing `lintIgnore` list. De-duplicated. Mutually exclusive with
203
+ * `--all`. To remove an entry or clear the list entirely, use the
204
+ * `fireforge patch lint-ignore` subcommand (which has explicit
205
+ * `--add` / `--remove` / `--clear` modes); re-export's append-only
206
+ * semantics match the operator's most common intent ("I want this
207
+ * patch to also suppress X").
208
+ */
209
+ lintIgnore?: string[];
210
+ }
211
+ /**
212
+ * Options for the `fireforge patch tier` subcommand. Sets or clears the
213
+ * `PatchMetadata.tier` field on a single patch without rewriting the
214
+ * `.patch` file body — the manifest is the only thing that changes.
215
+ */
216
+ export interface PatchTierOptions {
217
+ /** Force the named tier on the patch. Only `"branding"` is recognised. */
218
+ tier?: 'branding';
219
+ /** Remove the `tier` override entirely, restoring auto-detection. */
220
+ clear?: boolean;
221
+ /** Print the planned change without writing. */
222
+ dryRun?: boolean;
223
+ /** Skip the confirmation prompt (required for non-TTY). */
224
+ yes?: boolean;
225
+ }
226
+ /**
227
+ * Options for the `fireforge patch lint-ignore` subcommand. Modes are
228
+ * mutually exclusive — exactly one of `add`, `remove`, or `clear` must
229
+ * be set per invocation.
230
+ */
231
+ export interface PatchLintIgnoreOptions {
232
+ /** Lint check IDs to add to the patch's `lintIgnore` list (union, de-duped). */
233
+ add?: string[];
234
+ /** Lint check IDs to remove from the patch's `lintIgnore` list. */
235
+ remove?: string[];
236
+ /** Drop the `lintIgnore` field entirely. */
237
+ clear?: boolean;
238
+ /** Print the planned change without writing. */
239
+ dryRun?: boolean;
240
+ /** Skip the confirmation prompt (required for non-TTY). */
241
+ yes?: boolean;
175
242
  }
176
243
  /**
177
244
  * Options for the rebase command.
@@ -86,11 +86,12 @@ export interface PatchMetadata {
86
86
  * limit on what is legitimately one branding diff.
87
87
  *
88
88
  * Declaring `tier: "branding"` here forces the branding thresholds
89
- * (notice 3000 / warning 8000 / error 20000) regardless of
90
- * `filesAffected`. The tier is the weaker claim than test — a patch
91
- * of all-tests still lands in the test tier even if this field is
92
- * set, because the test-tier thresholds are already more permissive
93
- * and a test that is also branding-shaped is vanishingly rare.
89
+ * (notice 8000 / warning 18000 / error 30000 lines, ≤60 files)
90
+ * regardless of `filesAffected`. The tier is the weaker claim than
91
+ * test — a patch of all-tests still lands in the test tier even if
92
+ * this field is set, because the test-tier thresholds are already
93
+ * more permissive and a test that is also branding-shaped is
94
+ * vanishingly rare.
94
95
  *
95
96
  * Only `"branding"` is currently recognised. Unknown values are
96
97
  * rejected by the manifest validator, not silently stripped.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hominis/fireforge",
3
- "version": "0.18.0",
3
+ "version": "0.18.2",
4
4
  "description": "FireForge — a build tool for customizing Firefox",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",