@hominis/fireforge 0.43.0 → 0.44.0
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/CHANGELOG.md +127 -0
- package/README.md +10 -1
- package/dist/bin/fireforge.d.ts +4 -9
- package/dist/bin/fireforge.js +42 -40
- package/dist/build-info.json +4 -4
- package/dist/src/cli.js +74 -8
- package/dist/src/commands/bootstrap.js +17 -20
- package/dist/src/commands/build.js +25 -32
- package/dist/src/commands/config.js +34 -41
- package/dist/src/commands/discard.js +8 -9
- package/dist/src/commands/doctor-check-core.d.ts +4 -18
- package/dist/src/commands/doctor-check-core.js +8 -35
- package/dist/src/commands/doctor-external-toolchains.js +2 -2
- package/dist/src/commands/doctor-furnace-config-sync.d.ts +18 -0
- package/dist/src/commands/{doctor-furnace-manifest-sync.js → doctor-furnace-config-sync.js} +27 -26
- package/dist/src/commands/doctor-furnace-jar.d.ts +7 -9
- package/dist/src/commands/doctor-furnace-jar.js +7 -9
- package/dist/src/commands/doctor-furnace.js +21 -24
- package/dist/src/commands/doctor-orphaned-harness.d.ts +16 -20
- package/dist/src/commands/doctor-orphaned-harness.js +18 -44
- package/dist/src/commands/doctor-post-rebase-audit.d.ts +2 -0
- package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
- package/dist/src/commands/doctor-working-tree.d.ts +10 -12
- package/dist/src/commands/doctor-working-tree.js +11 -18
- package/dist/src/commands/doctor.js +35 -53
- package/dist/src/commands/download.js +32 -48
- package/dist/src/commands/export-all.js +29 -33
- package/dist/src/commands/export-flow.js +6 -6
- package/dist/src/commands/export-placement-conflicts.js +10 -9
- package/dist/src/commands/export-placement-gate.js +5 -5
- package/dist/src/commands/export-shared.d.ts +30 -33
- package/dist/src/commands/export-shared.js +45 -43
- package/dist/src/commands/export.js +21 -27
- package/dist/src/commands/furnace/apply.js +14 -23
- package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
- package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
- package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
- package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
- package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
- package/dist/src/commands/furnace/chrome-doc.js +31 -41
- package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
- package/dist/src/commands/furnace/create-browser-test.js +8 -8
- package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
- package/dist/src/commands/furnace/create-mochikit.js +8 -9
- package/dist/src/commands/furnace/create-readback.d.ts +12 -13
- package/dist/src/commands/furnace/create-readback.js +12 -13
- package/dist/src/commands/furnace/create-templates.d.ts +22 -28
- package/dist/src/commands/furnace/create-templates.js +35 -30
- package/dist/src/commands/furnace/create-xpcshell.js +2 -2
- package/dist/src/commands/furnace/create.js +33 -23
- package/dist/src/commands/furnace/deploy.js +16 -24
- package/dist/src/commands/furnace/diff.js +9 -9
- package/dist/src/commands/furnace/init.js +33 -36
- package/dist/src/commands/furnace/override.js +23 -25
- package/dist/src/commands/furnace/preview.js +47 -67
- package/dist/src/commands/furnace/refresh.js +12 -16
- package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
- package/dist/src/commands/furnace/remove-mutations.js +9 -16
- package/dist/src/commands/furnace/remove-state.js +1 -1
- package/dist/src/commands/furnace/remove.js +33 -38
- package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
- package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
- package/dist/src/commands/furnace/rename.js +59 -69
- package/dist/src/commands/furnace/scan.js +19 -33
- package/dist/src/commands/furnace/status.js +12 -9
- package/dist/src/commands/furnace/sync.js +9 -16
- package/dist/src/commands/furnace/validate.js +20 -20
- package/dist/src/commands/import.js +42 -35
- package/dist/src/commands/lint-per-patch.js +15 -10
- package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
- package/dist/src/commands/lint-per-run-checkjs.js +13 -13
- package/dist/src/commands/lint-report.js +6 -7
- package/dist/src/commands/lint.d.ts +15 -16
- package/dist/src/commands/lint.js +86 -102
- package/dist/src/commands/package.js +6 -11
- package/dist/src/commands/patch/compact.js +1 -1
- package/dist/src/commands/patch/delete.js +24 -33
- package/dist/src/commands/patch/index.d.ts +5 -6
- package/dist/src/commands/patch/index.js +10 -12
- package/dist/src/commands/patch/lint-ignore.js +14 -13
- package/dist/src/commands/patch/move-files-create.d.ts +6 -6
- package/dist/src/commands/patch/move-files-create.js +8 -8
- package/dist/src/commands/patch/move-files-into.d.ts +6 -6
- package/dist/src/commands/patch/move-files-into.js +8 -8
- package/dist/src/commands/patch/patch-context.d.ts +2 -3
- package/dist/src/commands/patch/patch-context.js +2 -3
- package/dist/src/commands/patch/rename.d.ts +10 -11
- package/dist/src/commands/patch/rename.js +11 -12
- package/dist/src/commands/patch/reorder.js +8 -9
- package/dist/src/commands/patch/split-plan.js +1 -1
- package/dist/src/commands/patch/split.d.ts +8 -10
- package/dist/src/commands/patch/split.js +9 -11
- package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
- package/dist/src/commands/patch/staged-dependency.js +7 -3
- package/dist/src/commands/patch/tier.d.ts +9 -9
- package/dist/src/commands/patch/tier.js +18 -15
- package/dist/src/commands/re-export-adjacent.js +9 -8
- package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
- package/dist/src/commands/re-export-bulk-scan.js +22 -21
- package/dist/src/commands/re-export-drift.js +10 -10
- package/dist/src/commands/re-export-files.d.ts +6 -7
- package/dist/src/commands/re-export-files.js +34 -44
- package/dist/src/commands/re-export-lint.d.ts +10 -13
- package/dist/src/commands/re-export-lint.js +16 -14
- package/dist/src/commands/re-export-options.d.ts +6 -6
- package/dist/src/commands/re-export-options.js +6 -6
- package/dist/src/commands/re-export-register.d.ts +4 -10
- package/dist/src/commands/re-export-register.js +5 -11
- package/dist/src/commands/re-export-scan.js +1 -1
- package/dist/src/commands/re-export-single.d.ts +3 -3
- package/dist/src/commands/re-export-single.js +33 -25
- package/dist/src/commands/re-export.js +13 -21
- package/dist/src/commands/rebase/abort.js +3 -3
- package/dist/src/commands/rebase/confirm.js +2 -1
- package/dist/src/commands/rebase/continue.d.ts +1 -1
- package/dist/src/commands/rebase/continue.js +14 -9
- package/dist/src/commands/rebase/index.js +11 -11
- package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
- package/dist/src/commands/rebase/patch-loop.js +60 -39
- package/dist/src/commands/rebase/summary.js +1 -1
- package/dist/src/commands/register.js +5 -7
- package/dist/src/commands/reset.js +2 -1
- package/dist/src/commands/resolve.d.ts +16 -13
- package/dist/src/commands/resolve.js +30 -33
- package/dist/src/commands/run.js +33 -35
- package/dist/src/commands/setup-support.js +15 -19
- package/dist/src/commands/setup.js +13 -9
- package/dist/src/commands/status-check.d.ts +6 -6
- package/dist/src/commands/status-json.d.ts +6 -6
- package/dist/src/commands/status-json.js +5 -0
- package/dist/src/commands/status-output.d.ts +5 -5
- package/dist/src/commands/status-output.js +6 -6
- package/dist/src/commands/status-ownership.d.ts +16 -14
- package/dist/src/commands/status-ownership.js +16 -14
- package/dist/src/commands/status.js +42 -34
- package/dist/src/commands/test-build-phase.js +26 -13
- package/dist/src/commands/test-diagnose.js +44 -44
- package/dist/src/commands/test-register.js +1 -0
- package/dist/src/commands/test-run.d.ts +14 -16
- package/dist/src/commands/test-run.js +21 -13
- package/dist/src/commands/test-stale-gate.d.ts +15 -16
- package/dist/src/commands/test-stale-gate.js +15 -16
- package/dist/src/commands/test-verdict.d.ts +20 -3
- package/dist/src/commands/test-verdict.js +30 -0
- package/dist/src/commands/test.js +83 -76
- package/dist/src/commands/token-coverage.js +3 -4
- package/dist/src/commands/token.js +16 -18
- package/dist/src/commands/tree.js +47 -31
- package/dist/src/commands/typecheck.d.ts +10 -12
- package/dist/src/commands/typecheck.js +24 -27
- package/dist/src/commands/verify.js +13 -15
- package/dist/src/commands/watch.js +21 -23
- package/dist/src/commands/wire.js +52 -62
- package/dist/src/core/ast-utils.d.ts +8 -7
- package/dist/src/core/ast-utils.js +8 -7
- package/dist/src/core/branding.d.ts +9 -14
- package/dist/src/core/branding.js +7 -11
- package/dist/src/core/browser-wire.d.ts +1 -1
- package/dist/src/core/browser-wire.js +14 -19
- package/dist/src/core/build-audit-platform.js +25 -33
- package/dist/src/core/build-audit-registration.js +17 -25
- package/dist/src/core/build-audit-resolve.d.ts +15 -17
- package/dist/src/core/build-audit-resolve.js +27 -33
- package/dist/src/core/build-audit-transforms.js +18 -19
- package/dist/src/core/build-audit.js +28 -42
- package/dist/src/core/build-baseline-types.d.ts +29 -35
- package/dist/src/core/build-baseline.d.ts +5 -4
- package/dist/src/core/build-baseline.js +14 -14
- package/dist/src/core/build-overwrite-guard.d.ts +7 -14
- package/dist/src/core/build-overwrite-guard.js +62 -19
- package/dist/src/core/build-prepare.d.ts +2 -2
- package/dist/src/core/build-prepare.js +8 -9
- package/dist/src/core/config-state.js +12 -4
- package/dist/src/core/config-validate.js +8 -5
- package/dist/src/core/config.d.ts +5 -8
- package/dist/src/core/config.js +7 -16
- package/dist/src/core/coverage-extend.d.ts +15 -13
- package/dist/src/core/coverage-extend.js +15 -13
- package/dist/src/core/destructive.d.ts +31 -9
- package/dist/src/core/destructive.js +29 -26
- package/dist/src/core/diff-hunks.js +10 -12
- package/dist/src/core/discard-baseline.d.ts +8 -8
- package/dist/src/core/discard-baseline.js +16 -15
- package/dist/src/core/display-state.d.ts +12 -14
- package/dist/src/core/display-state.js +12 -14
- package/dist/src/core/engine-changes.d.ts +2 -4
- package/dist/src/core/engine-changes.js +2 -4
- package/dist/src/core/engine-precondition.d.ts +28 -13
- package/dist/src/core/engine-precondition.js +25 -10
- package/dist/src/core/engine-session-lock.d.ts +47 -21
- package/dist/src/core/engine-session-lock.js +168 -33
- package/dist/src/core/export-moved-code-shape.d.ts +10 -10
- package/dist/src/core/export-moved-code-shape.js +10 -10
- package/dist/src/core/file-lock.d.ts +62 -5
- package/dist/src/core/file-lock.js +196 -59
- package/dist/src/core/firefox-cache.js +1 -3
- package/dist/src/core/firefox-extract.js +10 -14
- package/dist/src/core/firefox.d.ts +7 -5
- package/dist/src/core/firefox.js +4 -5
- package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
- package/dist/src/core/furnace-apply-dry-run.js +3 -2
- package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
- package/dist/src/core/furnace-apply-ftl.js +12 -12
- package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
- package/dist/src/core/furnace-apply-helpers.js +19 -16
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
- package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
- package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
- package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
- package/dist/src/core/furnace-apply.d.ts +5 -8
- package/dist/src/core/furnace-apply.js +19 -24
- package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
- package/dist/src/core/furnace-checksum-utils.js +16 -0
- package/dist/src/core/furnace-config.d.ts +21 -30
- package/dist/src/core/furnace-config.js +32 -54
- package/dist/src/core/furnace-constants.d.ts +8 -0
- package/dist/src/core/furnace-constants.js +10 -2
- package/dist/src/core/furnace-css-fragments.d.ts +5 -5
- package/dist/src/core/furnace-css-fragments.js +5 -5
- package/dist/src/core/furnace-jsconfig.d.ts +11 -12
- package/dist/src/core/furnace-jsconfig.js +11 -12
- package/dist/src/core/furnace-marker.d.ts +7 -8
- package/dist/src/core/furnace-marker.js +7 -8
- package/dist/src/core/furnace-operation.d.ts +31 -0
- package/dist/src/core/furnace-operation.js +54 -17
- package/dist/src/core/furnace-precondition.d.ts +61 -0
- package/dist/src/core/furnace-precondition.js +67 -0
- package/dist/src/core/furnace-registration-remove.d.ts +5 -6
- package/dist/src/core/furnace-registration-remove.js +6 -7
- package/dist/src/core/furnace-registration-validate.d.ts +13 -0
- package/dist/src/core/furnace-registration-validate.js +20 -1
- package/dist/src/core/furnace-registration.d.ts +5 -6
- package/dist/src/core/furnace-registration.js +10 -12
- package/dist/src/core/furnace-rollback.js +7 -7
- package/dist/src/core/furnace-scanner.d.ts +1 -0
- package/dist/src/core/furnace-scanner.js +1 -2
- package/dist/src/core/furnace-stale-export.d.ts +10 -10
- package/dist/src/core/furnace-stale-export.js +10 -10
- package/dist/src/core/furnace-state-persist.d.ts +6 -8
- package/dist/src/core/furnace-state-persist.js +6 -8
- package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
- package/dist/src/core/furnace-validate-accessibility.js +310 -1
- package/dist/src/core/furnace-validate-compatibility.js +141 -1
- package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
- package/dist/src/core/furnace-validate-helpers.js +0 -491
- package/dist/src/core/furnace-validate-registration.d.ts +7 -0
- package/dist/src/core/furnace-validate-registration.js +115 -41
- package/dist/src/core/furnace-validate.d.ts +16 -0
- package/dist/src/core/furnace-validate.js +188 -145
- package/dist/src/core/furnace-version-drift.d.ts +10 -11
- package/dist/src/core/furnace-version-drift.js +10 -11
- package/dist/src/core/git-base.d.ts +7 -9
- package/dist/src/core/git-base.js +7 -9
- package/dist/src/core/git-diff.d.ts +20 -9
- package/dist/src/core/git-diff.js +148 -63
- package/dist/src/core/git-file-ops.d.ts +19 -19
- package/dist/src/core/git-file-ops.js +19 -19
- package/dist/src/core/git-readonly-index.d.ts +53 -19
- package/dist/src/core/git-readonly-index.js +75 -31
- package/dist/src/core/git-status.d.ts +5 -6
- package/dist/src/core/git-status.js +5 -6
- package/dist/src/core/git.d.ts +9 -10
- package/dist/src/core/git.js +54 -70
- package/dist/src/core/license-headers.d.ts +17 -23
- package/dist/src/core/license-headers.js +17 -23
- package/dist/src/core/mach-build-artifacts.d.ts +9 -9
- package/dist/src/core/mach-build-artifacts.js +57 -19
- package/dist/src/core/mach-error-hints.js +42 -29
- package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
- package/dist/src/core/mach-known-noise-filter.js +18 -20
- package/dist/src/core/mach-mozconfig.d.ts +14 -0
- package/dist/src/core/mach-mozconfig.js +30 -0
- package/dist/src/core/mach-resource-shim.d.ts +43 -58
- package/dist/src/core/mach-resource-shim.js +50 -67
- package/dist/src/core/mach.d.ts +37 -41
- package/dist/src/core/mach.js +50 -51
- package/dist/src/core/marionette-port.d.ts +36 -1
- package/dist/src/core/marionette-port.js +96 -31
- package/dist/src/core/marionette-preflight.d.ts +8 -12
- package/dist/src/core/marionette-preflight.js +86 -52
- package/dist/src/core/mochitest-server-port.d.ts +42 -0
- package/dist/src/core/mochitest-server-port.js +119 -0
- package/dist/src/core/module-resolution-preflight.d.ts +9 -11
- package/dist/src/core/module-resolution-preflight.js +9 -11
- package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
- package/dist/src/core/moz-manifest-helpers.js +163 -0
- package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
- package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
- package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
- package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
- package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
- package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
- package/dist/src/core/ownership-table.d.ts +14 -16
- package/dist/src/core/ownership-table.js +14 -16
- package/dist/src/core/parser-fallback.d.ts +15 -1
- package/dist/src/core/parser-fallback.js +22 -3
- package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
- package/dist/src/core/patch-apply-fuzz.js +15 -18
- package/dist/src/core/patch-apply.d.ts +13 -34
- package/dist/src/core/patch-apply.js +16 -76
- package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
- package/dist/src/core/patch-artifact-normalize.js +13 -15
- package/dist/src/core/patch-export-metadata.d.ts +12 -2
- package/dist/src/core/patch-export-metadata.js +13 -4
- package/dist/src/core/patch-export-update.d.ts +13 -1
- package/dist/src/core/patch-export-update.js +25 -8
- package/dist/src/core/patch-export.d.ts +15 -8
- package/dist/src/core/patch-export.js +10 -11
- package/dist/src/core/patch-files.d.ts +5 -6
- package/dist/src/core/patch-files.js +5 -6
- package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
- package/dist/src/core/patch-identifier-suggest.js +14 -19
- package/dist/src/core/patch-lint-binary.d.ts +51 -0
- package/dist/src/core/patch-lint-binary.js +39 -0
- package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
- package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
- package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
- package/dist/src/core/patch-lint-checkjs.js +16 -16
- package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
- package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
- package/dist/src/core/patch-lint-creators.d.ts +8 -8
- package/dist/src/core/patch-lint-creators.js +8 -8
- package/dist/src/core/patch-lint-cross.d.ts +17 -20
- package/dist/src/core/patch-lint-cross.js +16 -16
- package/dist/src/core/patch-lint-css.d.ts +3 -5
- package/dist/src/core/patch-lint-css.js +17 -22
- package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
- package/dist/src/core/patch-lint-diff-tag.js +14 -16
- package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
- package/dist/src/core/patch-lint-jsdoc.js +26 -19
- package/dist/src/core/patch-lint-mozbuild.js +20 -20
- package/dist/src/core/patch-lint-observer.d.ts +7 -7
- package/dist/src/core/patch-lint-observer.js +7 -7
- package/dist/src/core/patch-lint.d.ts +38 -29
- package/dist/src/core/patch-lint.js +89 -121
- package/dist/src/core/patch-lock.d.ts +1 -1
- package/dist/src/core/patch-lock.js +45 -9
- package/dist/src/core/patch-manifest-consistency.d.ts +2 -1
- package/dist/src/core/patch-manifest-consistency.js +25 -27
- package/dist/src/core/patch-manifest-io.js +14 -18
- package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
- package/dist/src/core/patch-manifest-resolve.js +9 -12
- package/dist/src/core/patch-manifest-validate.d.ts +6 -1
- package/dist/src/core/patch-manifest-validate.js +25 -13
- package/dist/src/core/patch-parse.d.ts +24 -13
- package/dist/src/core/patch-parse.js +19 -14
- package/dist/src/core/patch-policy.d.ts +2 -2
- package/dist/src/core/patch-policy.js +2 -2
- package/dist/src/core/patch-registration-refs.d.ts +7 -8
- package/dist/src/core/patch-registration-refs.js +9 -9
- package/dist/src/core/process-cpu-time.d.ts +12 -0
- package/dist/src/core/process-cpu-time.js +52 -0
- package/dist/src/core/rebase-session.d.ts +38 -26
- package/dist/src/core/rebase-session.js +55 -28
- package/dist/src/core/register-browser-content.js +9 -74
- package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
- package/dist/src/core/register-module.js +10 -43
- package/dist/src/core/register-scaffold.d.ts +8 -8
- package/dist/src/core/register-scaffold.js +10 -10
- package/dist/src/core/register-shared-css.d.ts +9 -12
- package/dist/src/core/register-shared-css.js +17 -87
- package/dist/src/core/register-xpcshell-test.d.ts +6 -7
- package/dist/src/core/register-xpcshell-test.js +7 -8
- package/dist/src/core/shared-ftl.js +12 -4
- package/dist/src/core/state-file.d.ts +45 -0
- package/dist/src/core/state-file.js +34 -0
- package/dist/src/core/status-binary.d.ts +18 -11
- package/dist/src/core/status-binary.js +19 -12
- package/dist/src/core/status-classify.d.ts +30 -36
- package/dist/src/core/status-classify.js +21 -26
- package/dist/src/core/test-changed-prefs.d.ts +30 -0
- package/dist/src/core/test-changed-prefs.js +78 -0
- package/dist/src/core/test-harness-crash.d.ts +25 -63
- package/dist/src/core/test-harness-crash.js +121 -142
- package/dist/src/core/test-harness-signature.d.ts +18 -0
- package/dist/src/core/test-harness-signature.js +13 -0
- package/dist/src/core/test-path-scope.d.ts +12 -15
- package/dist/src/core/test-path-scope.js +15 -18
- package/dist/src/core/test-stale-check.d.ts +17 -17
- package/dist/src/core/test-stale-check.js +50 -43
- package/dist/src/core/test-stall-triage.d.ts +51 -0
- package/dist/src/core/test-stall-triage.js +126 -0
- package/dist/src/core/token-category.js +5 -7
- package/dist/src/core/token-coverage.js +9 -9
- package/dist/src/core/token-dark-mode.d.ts +9 -11
- package/dist/src/core/token-dark-mode.js +9 -11
- package/dist/src/core/token-docs.d.ts +2 -0
- package/dist/src/core/token-docs.js +2 -0
- package/dist/src/core/token-manager.d.ts +10 -2
- package/dist/src/core/token-manager.js +17 -8
- package/dist/src/core/token-scaffold.d.ts +7 -7
- package/dist/src/core/token-scaffold.js +7 -7
- package/dist/src/core/token-variant.d.ts +4 -4
- package/dist/src/core/token-variant.js +4 -4
- package/dist/src/core/toolchain-preflight.d.ts +20 -21
- package/dist/src/core/toolchain-preflight.js +28 -31
- package/dist/src/core/tree-guard.js +12 -2
- package/dist/src/core/tree-store.d.ts +41 -27
- package/dist/src/core/tree-store.js +63 -42
- package/dist/src/core/typecheck-shim.d.ts +23 -24
- package/dist/src/core/typecheck-shim.js +23 -24
- package/dist/src/core/typecheck.js +8 -8
- package/dist/src/core/wire-destroy.d.ts +3 -3
- package/dist/src/core/wire-destroy.js +7 -15
- package/dist/src/core/wire-dom-fragment.d.ts +9 -17
- package/dist/src/core/wire-dom-fragment.js +11 -44
- package/dist/src/core/wire-init.d.ts +2 -3
- package/dist/src/core/wire-init.js +8 -19
- package/dist/src/core/wire-subscript.d.ts +2 -3
- package/dist/src/core/wire-subscript.js +4 -13
- package/dist/src/core/wire-utils.d.ts +7 -8
- package/dist/src/core/wire-utils.js +7 -8
- package/dist/src/core/xpcshell-appdir.d.ts +38 -45
- package/dist/src/core/xpcshell-appdir.js +38 -45
- package/dist/src/errors/base.d.ts +37 -16
- package/dist/src/errors/base.js +37 -16
- package/dist/src/errors/build.d.ts +13 -1
- package/dist/src/errors/build.js +14 -2
- package/dist/src/errors/codes.d.ts +16 -0
- package/dist/src/errors/codes.js +16 -0
- package/dist/src/errors/furnace.d.ts +4 -4
- package/dist/src/errors/git.d.ts +6 -10
- package/dist/src/errors/git.js +6 -10
- package/dist/src/errors/patch.d.ts +7 -7
- package/dist/src/errors/patch.js +7 -7
- package/dist/src/errors/rebase.d.ts +4 -4
- package/dist/src/errors/rebase.js +4 -4
- package/dist/src/index.d.ts +7 -1
- package/dist/src/index.js +5 -0
- package/dist/src/types/commands/index.d.ts +2 -2
- package/dist/src/types/commands/options.d.ts +88 -70
- package/dist/src/types/commands/patches.d.ts +24 -34
- package/dist/src/types/commands/project.d.ts +5 -34
- package/dist/src/types/config.d.ts +25 -23
- package/dist/src/types/config.js +6 -1
- package/dist/src/types/furnace.d.ts +37 -13
- package/dist/src/types/furnace.js +19 -1
- package/dist/src/types/index.d.ts +3 -3
- package/dist/src/utils/build-info.d.ts +7 -8
- package/dist/src/utils/build-info.js +12 -11
- package/dist/src/utils/errors.d.ts +6 -8
- package/dist/src/utils/errors.js +6 -8
- package/dist/src/utils/logger.d.ts +27 -10
- package/dist/src/utils/logger.js +28 -16
- package/dist/src/utils/machine-output.d.ts +12 -0
- package/dist/src/utils/machine-output.js +33 -0
- package/dist/src/utils/options.d.ts +31 -14
- package/dist/src/utils/options.js +86 -30
- package/dist/src/utils/paths.d.ts +10 -8
- package/dist/src/utils/paths.js +10 -8
- package/dist/src/utils/platform.d.ts +0 -25
- package/dist/src/utils/platform.js +1 -42
- package/dist/src/utils/process-group.d.ts +9 -4
- package/dist/src/utils/process-group.js +19 -5
- package/dist/src/utils/process.d.ts +42 -7
- package/dist/src/utils/process.js +44 -17
- package/dist/src/utils/ps-duration.d.ts +31 -0
- package/dist/src/utils/ps-duration.js +70 -0
- package/dist/src/utils/regex.d.ts +9 -10
- package/dist/src/utils/regex.js +9 -10
- package/dist/src/utils/validation.d.ts +58 -28
- package/dist/src/utils/validation.js +60 -33
- package/package.json +2 -2
- package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
- package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
- package/dist/src/core/manifest-helpers.d.ts +0 -38
- package/dist/src/core/manifest-helpers.js +0 -120
- /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
- /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
- /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
|
@@ -16,9 +16,9 @@ export async function handleAbort(projectRoot, yes) {
|
|
|
16
16
|
intro('FireForge Rebase — Abort');
|
|
17
17
|
// Abort is the escape hatch, so it deliberately does NOT require a *valid*
|
|
18
18
|
// session — only that one is present. Nothing below reads the session
|
|
19
|
-
// object (the restore works off `paths.engine` and `resetChanges`), and
|
|
20
|
-
//
|
|
21
|
-
//
|
|
19
|
+
// object (the restore works off `paths.engine` and `resetChanges`), and an
|
|
20
|
+
// `if (!session) throw` would refuse to run against a corrupt file, which
|
|
21
|
+
// is the only thing that could have cleared it.
|
|
22
22
|
const read = await readRebaseSession(projectRoot);
|
|
23
23
|
if (!read.present)
|
|
24
24
|
throw new NoRebaseSessionError();
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Dirty-engine confirmation/reset flow.
|
|
4
4
|
*/
|
|
5
5
|
import { confirm } from '@clack/prompts';
|
|
6
|
+
import { stdioIsInteractive } from '../../core/destructive.js';
|
|
6
7
|
import { hasChanges } from '../../core/git.js';
|
|
7
8
|
import { InvalidArgumentError } from '../../errors/base.js';
|
|
8
9
|
import { cancel, isCancel, warn } from '../../utils/logger.js';
|
|
@@ -15,7 +16,7 @@ export async function confirmDirtyEngineReset({ engineDir, yes, nonInteractiveCo
|
|
|
15
16
|
if (!(await hasChanges(engineDir)) || yes) {
|
|
16
17
|
return true;
|
|
17
18
|
}
|
|
18
|
-
const isInteractive =
|
|
19
|
+
const isInteractive = stdioIsInteractive();
|
|
19
20
|
if (!isInteractive) {
|
|
20
21
|
throw new InvalidArgumentError(`Engine has uncommitted changes and interactive confirmation is not available. Run: ${nonInteractiveCommand}`, argumentName);
|
|
21
22
|
}
|
|
@@ -18,7 +18,7 @@ import { runPatchLoop } from './patch-loop.js';
|
|
|
18
18
|
/**
|
|
19
19
|
* Handles `fireforge rebase --continue`.
|
|
20
20
|
*/
|
|
21
|
-
export async function handleContinue(projectRoot, maxFuzz) {
|
|
21
|
+
export async function handleContinue(projectRoot, maxFuzz, waitLockSeconds) {
|
|
22
22
|
intro('FireForge Rebase — Continue');
|
|
23
23
|
// A present-but-unreadable session is NOT "no session in progress" — that
|
|
24
24
|
// conflation is what made a corrupt file unrecoverable. Name the file and
|
|
@@ -39,7 +39,7 @@ export async function handleContinue(projectRoot, maxFuzz) {
|
|
|
39
39
|
// there is no failed patch to resolve, but the session is still active.
|
|
40
40
|
if (session.currentIndex >= session.patches.length) {
|
|
41
41
|
info('All patches already applied; retrying post-apply re-export and version stamping.');
|
|
42
|
-
await runPatchLoop(projectRoot, session, paths, maxFuzz);
|
|
42
|
+
await runPatchLoop(projectRoot, session, paths, maxFuzz, waitLockSeconds);
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
// The current patch should be in 'failed' state
|
|
@@ -73,11 +73,10 @@ export async function handleContinue(projectRoot, maxFuzz) {
|
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
75
|
// Write the patch body and the manifest metadata atomically under the
|
|
76
|
-
// shared patch-directory lock.
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
// v0.14.0 resolve.ts fix.
|
|
76
|
+
// shared patch-directory lock. A lock-free updatePatch +
|
|
77
|
+
// updatePatchMetadata sequence can interleave with a concurrent export /
|
|
78
|
+
// re-export / patch reorder / patch compact and leave the manifest
|
|
79
|
+
// disagreeing with the freshly-written patch body. Mirrors resolve.ts.
|
|
81
80
|
await updatePatchAndMetadata(paths.patches, currentPatch.filename, diffContent, {
|
|
82
81
|
sourceEsrVersion: session.toVersion,
|
|
83
82
|
sourceVersion: session.toVersion,
|
|
@@ -94,7 +93,13 @@ export async function handleContinue(projectRoot, maxFuzz) {
|
|
|
94
93
|
// clear is held until both writes land, matching the guarantee the apply
|
|
95
94
|
// loop in patch-loop.ts provides.
|
|
96
95
|
await runInSignalCriticalSection(`rebase-continue:${currentPatch.filename}`, async () => {
|
|
97
|
-
|
|
96
|
+
// Replaced, not mutated: flipping `status` in place leaves the
|
|
97
|
+
// failure's `error` and `conflictingFiles` on a now-resolved entry, and
|
|
98
|
+
// persist that to the session file. The union makes it impossible.
|
|
99
|
+
session.patches[session.currentIndex] = {
|
|
100
|
+
filename: currentPatch.filename,
|
|
101
|
+
status: 'resolved',
|
|
102
|
+
};
|
|
98
103
|
session.currentIndex++;
|
|
99
104
|
await saveRebaseSession(projectRoot, session);
|
|
100
105
|
// Clear pending resolution transactionally so concurrent state-file
|
|
@@ -109,5 +114,5 @@ export async function handleContinue(projectRoot, maxFuzz) {
|
|
|
109
114
|
});
|
|
110
115
|
success(`Resolved ${currentPatch.filename}`);
|
|
111
116
|
// Continue applying remaining patches
|
|
112
|
-
await runPatchLoop(projectRoot, session, paths, maxFuzz);
|
|
117
|
+
await runPatchLoop(projectRoot, session, paths, maxFuzz, waitLockSeconds);
|
|
113
118
|
}
|
|
@@ -22,7 +22,7 @@ import { getRebaseSessionPath, readRebaseSession, saveRebaseSession, } from '../
|
|
|
22
22
|
import { GeneralError } from '../../errors/base.js';
|
|
23
23
|
import { CorruptRebaseSessionError, RebaseSessionExistsError } from '../../errors/rebase.js';
|
|
24
24
|
import { info, intro, outro, spinner } from '../../utils/logger.js';
|
|
25
|
-
import { commanderArgParser, pickDefined } from '../../utils/options.js';
|
|
25
|
+
import { addWaitLockOption, commanderArgParser, pickDefined, resolveWaitLockSeconds, } from '../../utils/options.js';
|
|
26
26
|
import { parsePositiveIntegerFlag } from '../../utils/validation.js';
|
|
27
27
|
import { handleAbort } from './abort.js';
|
|
28
28
|
import { confirmDirtyEngineReset } from './confirm.js';
|
|
@@ -39,17 +39,17 @@ async function handleFreshStart(projectRoot, options) {
|
|
|
39
39
|
const existing = await readRebaseSession(projectRoot);
|
|
40
40
|
if (existing.present) {
|
|
41
41
|
// A corrupt session must not be reported as "already in progress": that
|
|
42
|
-
// message tells the operator to run --continue or --abort, and
|
|
43
|
-
//
|
|
42
|
+
// message tells the operator to run --continue or --abort, and both of
|
|
43
|
+
// those then report "no rebase session in progress".
|
|
44
44
|
if (!existing.valid) {
|
|
45
45
|
throw new CorruptRebaseSessionError(getRebaseSessionPath(projectRoot), existing.reason);
|
|
46
46
|
}
|
|
47
47
|
throw new RebaseSessionExistsError();
|
|
48
48
|
}
|
|
49
49
|
const paths = getProjectPaths(projectRoot);
|
|
50
|
-
// Keeps the rebase-specific tail on the unborn-HEAD remediation
|
|
51
|
-
//
|
|
52
|
-
//
|
|
50
|
+
// Keeps the rebase-specific tail on the unborn-HEAD remediation. Skipping
|
|
51
|
+
// this check in --dry-run leaves the real run to fail on
|
|
52
|
+
// `git rev-parse HEAD`.
|
|
53
53
|
await assertEngineGitReady(paths.engine, { unbornHeadSuffix: ', then retry the rebase.' });
|
|
54
54
|
const config = await loadConfig(projectRoot);
|
|
55
55
|
const currentVersion = config.firefox.version;
|
|
@@ -112,7 +112,7 @@ async function handleFreshStart(projectRoot, options) {
|
|
|
112
112
|
};
|
|
113
113
|
await saveRebaseSession(projectRoot, session);
|
|
114
114
|
// Run the patch loop
|
|
115
|
-
await runPatchLoop(projectRoot, session, paths, maxFuzz);
|
|
115
|
+
await runPatchLoop(projectRoot, session, paths, maxFuzz, resolveWaitLockSeconds(options.waitLock));
|
|
116
116
|
}
|
|
117
117
|
// ── Public API ──
|
|
118
118
|
/**
|
|
@@ -125,21 +125,21 @@ export async function rebaseCommand(projectRoot, options = {}) {
|
|
|
125
125
|
return handleAbort(projectRoot, options.yes);
|
|
126
126
|
}
|
|
127
127
|
if (options.continue) {
|
|
128
|
-
return handleContinue(projectRoot, options.maxFuzz ?? 3);
|
|
128
|
+
return handleContinue(projectRoot, options.maxFuzz ?? 3, resolveWaitLockSeconds(options.waitLock));
|
|
129
129
|
}
|
|
130
130
|
return handleFreshStart(projectRoot, options);
|
|
131
131
|
}
|
|
132
132
|
/** Registers the rebase command on the CLI program. */
|
|
133
133
|
export function registerRebase(program, { getProjectRoot, withErrorHandling }) {
|
|
134
|
-
program
|
|
134
|
+
const command = program
|
|
135
135
|
.command('rebase')
|
|
136
136
|
.description('Semi-automated Firefox source version upgrade — apply patches with drift tolerance and re-export')
|
|
137
137
|
.option('--continue', 'Resume after manually resolving a failed patch')
|
|
138
138
|
.option('--abort', 'Cancel the rebase and restore engine to pre-rebase state')
|
|
139
139
|
.option('--dry-run', 'Show what would happen without modifying anything')
|
|
140
140
|
.option('--max-fuzz <n>', 'Maximum context-reduction steps for git apply -C<n> (fuzz-like drift tolerance; default: 3)', commanderArgParser((v) => parsePositiveIntegerFlag('--max-fuzz', v)))
|
|
141
|
-
.option('-y, --yes', 'Skip dirty-tree confirmation prompt')
|
|
142
|
-
|
|
141
|
+
.option('-y, --yes', 'Skip dirty-tree confirmation prompt');
|
|
142
|
+
addWaitLockOption(command).action(withErrorHandling(async (options) => {
|
|
143
143
|
await rebaseCommand(getProjectRoot(), pickDefined(options));
|
|
144
144
|
}));
|
|
145
145
|
}
|
|
@@ -5,5 +5,11 @@ import type { getProjectPaths } from '../../core/config.js';
|
|
|
5
5
|
import type { RebaseSession } from '../../core/rebase-session.js';
|
|
6
6
|
/**
|
|
7
7
|
* Runs the patch application loop, re-exports applied patches, and stamps versions.
|
|
8
|
+
*
|
|
9
|
+
* @param projectRoot - Project root directory
|
|
10
|
+
* @param session - The active rebase session, mutated and persisted as it runs
|
|
11
|
+
* @param paths - Resolved project paths
|
|
12
|
+
* @param maxFuzz - Maximum context-reduction steps for `git apply -C<n>`
|
|
13
|
+
* @param waitLockSeconds - `--wait-lock` budget for the patch-directory lock
|
|
8
14
|
*/
|
|
9
|
-
export declare function runPatchLoop(projectRoot: string, session: RebaseSession, paths: ReturnType<typeof getProjectPaths>, maxFuzz: number): Promise<void>;
|
|
15
|
+
export declare function runPatchLoop(projectRoot: string, session: RebaseSession, paths: ReturnType<typeof getProjectPaths>, maxFuzz: number, waitLockSeconds?: number): Promise<void>;
|
|
@@ -12,7 +12,7 @@ import { discoverPatches } from '../../core/patch-files.js';
|
|
|
12
12
|
import { withPatchDirectoryLock } from '../../core/patch-lock.js';
|
|
13
13
|
import { loadPatchesManifest, stampPatchVersions } from '../../core/patch-manifest.js';
|
|
14
14
|
import { extractConflictingFiles } from '../../core/patch-parse.js';
|
|
15
|
-
import { clearRebaseSession, saveRebaseSession } from '../../core/rebase-session.js';
|
|
15
|
+
import { clearRebaseSession, saveRebaseSession, } from '../../core/rebase-session.js';
|
|
16
16
|
import { runInSignalCriticalSection } from '../../core/signal-critical.js';
|
|
17
17
|
import { RebaseError } from '../../errors/rebase.js';
|
|
18
18
|
import { elapsedSince } from '../../utils/elapsed.js';
|
|
@@ -22,10 +22,42 @@ import { error, info, outro, spinner, success, warn } from '../../utils/logger.j
|
|
|
22
22
|
import { isValidFirefoxVersion } from '../../utils/validation.js';
|
|
23
23
|
import { buildRebaseConflictSummary } from './conflict-summary.js';
|
|
24
24
|
import { printSummary } from './summary.js';
|
|
25
|
+
/**
|
|
26
|
+
* Builds the session entry for a patch-apply outcome.
|
|
27
|
+
*
|
|
28
|
+
* Constructing a whole entry rather than assigning fields is what the
|
|
29
|
+
* discriminated union buys: a status can never be flipped while the previous
|
|
30
|
+
* status's payload stays behind, which is how
|
|
31
|
+
* `{ status: 'resolved', error, conflictingFiles }` reaches the session file.
|
|
32
|
+
*
|
|
33
|
+
* @param filename - Patch filename the entry describes
|
|
34
|
+
* @param applyResult - Outcome from `applyPatchWithFuzz`
|
|
35
|
+
* @returns The entry to store at this patch's index
|
|
36
|
+
*/
|
|
37
|
+
function entryForApplyResult(filename, applyResult) {
|
|
38
|
+
if (!applyResult.success) {
|
|
39
|
+
return {
|
|
40
|
+
filename,
|
|
41
|
+
status: 'failed',
|
|
42
|
+
...(applyResult.error !== undefined ? { error: applyResult.error } : {}),
|
|
43
|
+
conflictingFiles: extractConflictingFiles(applyResult.error),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (applyResult.fuzzFactor === 0 || applyResult.fuzzFactor === undefined) {
|
|
47
|
+
return { filename, status: 'applied-clean' };
|
|
48
|
+
}
|
|
49
|
+
return { filename, status: 'applied-fuzz', fuzzFactor: applyResult.fuzzFactor };
|
|
50
|
+
}
|
|
25
51
|
/**
|
|
26
52
|
* Runs the patch application loop, re-exports applied patches, and stamps versions.
|
|
53
|
+
*
|
|
54
|
+
* @param projectRoot - Project root directory
|
|
55
|
+
* @param session - The active rebase session, mutated and persisted as it runs
|
|
56
|
+
* @param paths - Resolved project paths
|
|
57
|
+
* @param maxFuzz - Maximum context-reduction steps for `git apply -C<n>`
|
|
58
|
+
* @param waitLockSeconds - `--wait-lock` budget for the patch-directory lock
|
|
27
59
|
*/
|
|
28
|
-
export async function runPatchLoop(projectRoot, session, paths, maxFuzz) {
|
|
60
|
+
export async function runPatchLoop(projectRoot, session, paths, maxFuzz, waitLockSeconds) {
|
|
29
61
|
const allPatches = await discoverPatches(paths.patches);
|
|
30
62
|
const s = spinner('Applying patches...');
|
|
31
63
|
for (let i = session.currentIndex; i < session.patches.length; i++) {
|
|
@@ -35,7 +67,10 @@ export async function runPatchLoop(projectRoot, session, paths, maxFuzz) {
|
|
|
35
67
|
const patchFile = allPatches.find((p) => p.filename === entry.filename);
|
|
36
68
|
if (!patchFile) {
|
|
37
69
|
warn(`Patch file not found for ${entry.filename}, skipping.`);
|
|
38
|
-
entry
|
|
70
|
+
// Replaced, not mutated: the entry is a discriminated union, so a status
|
|
71
|
+
// change is a new value rather than a field assignment. That is what
|
|
72
|
+
// stops a status flip stranding the previous status's payload.
|
|
73
|
+
session.patches[i] = { filename: entry.filename, status: 'skipped' };
|
|
39
74
|
session.currentIndex = i + 1;
|
|
40
75
|
await saveRebaseSession(projectRoot, session);
|
|
41
76
|
continue;
|
|
@@ -50,26 +85,9 @@ export async function runPatchLoop(projectRoot, session, paths, maxFuzz) {
|
|
|
50
85
|
// divergent results).
|
|
51
86
|
const result = await runInSignalCriticalSection(`rebase-apply:${entry.filename}`, async () => {
|
|
52
87
|
const applyResult = await applyPatchWithFuzz(patchFile.path, paths.engine, maxFuzz);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
else {
|
|
58
|
-
entry.status = 'applied-fuzz';
|
|
59
|
-
entry.fuzzFactor = applyResult.fuzzFactor;
|
|
60
|
-
}
|
|
61
|
-
session.currentIndex = i + 1;
|
|
62
|
-
await saveRebaseSession(projectRoot, session);
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
entry.status = 'failed';
|
|
66
|
-
if (applyResult.error) {
|
|
67
|
-
entry.error = applyResult.error;
|
|
68
|
-
}
|
|
69
|
-
entry.conflictingFiles = extractConflictingFiles(applyResult.error);
|
|
70
|
-
session.currentIndex = i;
|
|
71
|
-
await saveRebaseSession(projectRoot, session);
|
|
72
|
-
}
|
|
88
|
+
session.patches[i] = entryForApplyResult(entry.filename, applyResult);
|
|
89
|
+
session.currentIndex = applyResult.success ? i + 1 : i;
|
|
90
|
+
await saveRebaseSession(projectRoot, session);
|
|
73
91
|
return applyResult;
|
|
74
92
|
});
|
|
75
93
|
if (result.success) {
|
|
@@ -130,7 +148,7 @@ export async function runPatchLoop(projectRoot, session, paths, maxFuzz) {
|
|
|
130
148
|
// patch was tested against if we proceeded to stamp. Refuse to claim
|
|
131
149
|
// success and leave the session in place so the user can recover via
|
|
132
150
|
// `fireforge rebase --continue` after fixing the underlying cause.
|
|
133
|
-
const { failures: reExportFailures, overlapSkipped } = await reExportAppliedPatches(session, paths);
|
|
151
|
+
const { failures: reExportFailures, overlapSkipped } = await reExportAppliedPatches(session, paths, waitLockSeconds);
|
|
134
152
|
if (reExportFailures.length > 0) {
|
|
135
153
|
for (const f of reExportFailures) {
|
|
136
154
|
error(` ${f.filename}: ${f.error}`);
|
|
@@ -157,21 +175,21 @@ export async function runPatchLoop(projectRoot, session, paths, maxFuzz) {
|
|
|
157
175
|
await stampPatchVersions(paths.patches, appliedFilenames, session.toVersion, session.toProduct);
|
|
158
176
|
}
|
|
159
177
|
// Stamp every Furnace override's `baseVersion` to match the rebased
|
|
160
|
-
// Firefox source version.
|
|
161
|
-
// overrides in a doctor-failing drift state
|
|
162
|
-
//
|
|
163
|
-
// `fireforge doctor`
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
//
|
|
178
|
+
// Firefox source version. Without it, a successful source bump leaves
|
|
179
|
+
// overrides in a doctor-failing drift state — each still claiming the
|
|
180
|
+
// pre-rebase source as its baseline — and every subsequent
|
|
181
|
+
// `fireforge doctor` fails `Furnace component validation`. The stamp is
|
|
182
|
+
// unconditional per the helper's contract: rebase already succeeded on
|
|
183
|
+
// the patch side, so the operator is committing to the new source
|
|
184
|
+
// baseline; per-component health checking stays with
|
|
167
185
|
// `fireforge furnace validate` / `doctor --repair-furnace`.
|
|
168
186
|
//
|
|
169
|
-
// "Unconditional" means unconditional on component health, not on the
|
|
170
|
-
// `stampFurnaceOverrideBaseVersions` assigns and persists whatever
|
|
171
|
-
// is handed, so a session whose `toVersion` is not a real
|
|
172
|
-
// would rewrite every override's baseline to that value.
|
|
173
|
-
//
|
|
174
|
-
// if a future caller reaches here another way.
|
|
187
|
+
// "Unconditional" means unconditional on component health, not on the
|
|
188
|
+
// value: `stampFurnaceOverrideBaseVersions` assigns and persists whatever
|
|
189
|
+
// string it is handed, so a session whose `toVersion` is not a real
|
|
190
|
+
// Firefox version would rewrite every override's baseline to that value.
|
|
191
|
+
// `isValidSession` rejects such a session at read time; this refuses to
|
|
192
|
+
// persist it even if a future caller reaches here another way.
|
|
175
193
|
if (!isValidFirefoxVersion(session.toVersion)) {
|
|
176
194
|
throw new RebaseError(`Refusing to stamp Furnace override baseVersion(s): the rebase session's target version ` +
|
|
177
195
|
`("${session.toVersion}") is not a valid Firefox version.`);
|
|
@@ -201,7 +219,7 @@ export async function runPatchLoop(projectRoot, session, paths, maxFuzz) {
|
|
|
201
219
|
success(`All patches re-exported with sourceVersion=${session.toVersion}`);
|
|
202
220
|
outro('Rebase complete!');
|
|
203
221
|
}
|
|
204
|
-
async function reExportAppliedPatches(session, paths) {
|
|
222
|
+
async function reExportAppliedPatches(session, paths, waitLockSeconds) {
|
|
205
223
|
const failures = [];
|
|
206
224
|
const overlapSkipped = [];
|
|
207
225
|
const manifest = await loadPatchesManifest(paths.patches);
|
|
@@ -253,7 +271,10 @@ async function reExportAppliedPatches(session, paths) {
|
|
|
253
271
|
// Rebase sessions are serialized against each other by
|
|
254
272
|
// `rebase-session.ts`, so this lock is only defending against other
|
|
255
273
|
// command classes, not peer rebases.
|
|
256
|
-
await withPatchDirectoryLock(paths.patches, () => updatePatch(patchPath, diffContent)
|
|
274
|
+
await withPatchDirectoryLock(paths.patches, () => updatePatch(patchPath, diffContent), {
|
|
275
|
+
waitLockSeconds,
|
|
276
|
+
command: 'rebase',
|
|
277
|
+
});
|
|
257
278
|
}
|
|
258
279
|
}
|
|
259
280
|
catch (err) {
|
|
@@ -34,7 +34,7 @@ export function printSummary(session) {
|
|
|
34
34
|
info(`Source Rebase Summary: ${from} → ${to}`);
|
|
35
35
|
info('='.repeat(55));
|
|
36
36
|
for (const patch of session.patches) {
|
|
37
|
-
const label = statusLabel(patch.status, patch.fuzzFactor);
|
|
37
|
+
const label = statusLabel(patch.status, patch.status === 'applied-fuzz' ? patch.fuzzFactor : undefined);
|
|
38
38
|
info(` ${patch.filename} ${'·'.repeat(Math.max(1, 45 - patch.filename.length - label.length))} ${label}`);
|
|
39
39
|
}
|
|
40
40
|
const clean = session.patches.filter((p) => p.status === 'applied-clean').length;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import { getProjectPaths } from '../core/config.js';
|
|
5
|
-
import { registerFile } from '../core/manifest-rules.js';
|
|
5
|
+
import { registerFile } from '../core/moz-manifest-rules.js';
|
|
6
6
|
import { InvalidArgumentError } from '../errors/base.js';
|
|
7
7
|
import { pathExists } from '../utils/fs.js';
|
|
8
8
|
import { info, intro, outro, success, warn } from '../utils/logger.js';
|
|
@@ -48,12 +48,10 @@ export async function registerCommand(projectRoot, filePath, options = {}) {
|
|
|
48
48
|
...(options.createManifest !== undefined ? { createManifest: options.createManifest } : {}),
|
|
49
49
|
});
|
|
50
50
|
if (options.dryRun) {
|
|
51
|
-
//
|
|
52
|
-
// register" even when the rule
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
// registered". Surface the idempotency decision in dry-run too so
|
|
56
|
-
// the plan mirrors the real command's outcome.
|
|
51
|
+
// Dry-run must surface the idempotency decision too. Always saying
|
|
52
|
+
// "Would register" — even when the rule already knows the entry is
|
|
53
|
+
// present — makes automation read the plan as "work to do" while the
|
|
54
|
+
// following real run reports "Already registered".
|
|
57
55
|
if (result.skipped) {
|
|
58
56
|
info(`[dry-run] Already registered: ${engineRelativePath} in ${result.manifest}`);
|
|
59
57
|
outro('Dry run complete');
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { confirm } from '@clack/prompts';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import { getProjectPaths } from '../core/config.js';
|
|
5
|
+
import { stdioIsInteractive } from '../core/destructive.js';
|
|
5
6
|
import { assertEngineGitReady } from '../core/engine-precondition.js';
|
|
6
7
|
import { clearAppliedFurnaceState } from '../core/furnace-config.js';
|
|
7
8
|
import { hasChanges, resetChanges } from '../core/git.js';
|
|
@@ -40,7 +41,7 @@ export async function resetCommand(projectRoot, options) {
|
|
|
40
41
|
// Confirm reset unless --yes is specified
|
|
41
42
|
if (!options.yes) {
|
|
42
43
|
// Check for non-interactive mode
|
|
43
|
-
const isInteractive =
|
|
44
|
+
const isInteractive = stdioIsInteractive();
|
|
44
45
|
if (!isInteractive) {
|
|
45
46
|
throw new InvalidArgumentError('Interactive confirmation not available. Use --yes flag to reset without confirmation.', 'Use: fireforge reset --yes');
|
|
46
47
|
}
|
|
@@ -5,23 +5,26 @@ import type { CommandContext } from '../types/cli.js';
|
|
|
5
5
|
*/
|
|
6
6
|
export interface ResolveCommandOptions {
|
|
7
7
|
/**
|
|
8
|
-
* Skip the interactive "Have you finished fixing the files?"
|
|
9
|
-
*
|
|
8
|
+
* Skip the interactive "Have you finished fixing the files?" confirmation
|
|
9
|
+
* prompt and treat the resolution as complete.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* straight to the patch-refresh + state-clear path.
|
|
11
|
+
* A scripted or CI-assisted recovery flow that has already completed the
|
|
12
|
+
* manual merge step cannot otherwise advance through `fireforge resolve`,
|
|
13
|
+
* because the TTY guard refuses non-interactive invocations outright.
|
|
14
|
+
* `--yes` is the explicit opt-in: the operator asserts the merge is done,
|
|
15
|
+
* and the command proceeds straight to the patch-refresh + state-clear
|
|
16
|
+
* path.
|
|
18
17
|
*
|
|
19
|
-
* The guard without `--yes` is preserved — running `resolve` with
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* to contain.
|
|
18
|
+
* The guard without `--yes` is preserved — running `resolve` with no TTY
|
|
19
|
+
* and no `--yes` still refuses, so an accidental pipe-into invocation does
|
|
20
|
+
* not silently commit whatever the engine happens to contain.
|
|
23
21
|
*/
|
|
24
22
|
yes?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Seconds to wait for the patch directory lock. `resolve` rewrites a patch
|
|
25
|
+
* body and its metadata under that lock.
|
|
26
|
+
*/
|
|
27
|
+
waitLock?: number | boolean;
|
|
25
28
|
}
|
|
26
29
|
/**
|
|
27
30
|
* Runs the resolve command to fix broken patches.
|
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { confirm } from '@clack/prompts';
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import { getProjectPaths, loadConfig, loadState, updateState } from '../core/config.js';
|
|
6
|
+
import { stdioIsInteractive } from '../core/destructive.js';
|
|
6
7
|
import { assertEngineGitReady } from '../core/engine-precondition.js';
|
|
7
8
|
import { getStagedDiffForFiles } from '../core/git-diff.js';
|
|
8
9
|
import { stageFiles, unstageFiles } from '../core/git-file-ops.js';
|
|
@@ -14,6 +15,7 @@ import { GeneralError, ResolutionError } from '../errors/base.js';
|
|
|
14
15
|
import { toError } from '../utils/errors.js';
|
|
15
16
|
import { pathExists } from '../utils/fs.js';
|
|
16
17
|
import { error as logError, info, intro, isCancel, outro, spinner, success, } from '../utils/logger.js';
|
|
18
|
+
import { addWaitLockOption, resolveWaitLockSeconds } from '../utils/options.js';
|
|
17
19
|
/**
|
|
18
20
|
* Runs the resolve command to fix broken patches.
|
|
19
21
|
* @param projectRoot - Root directory of the project
|
|
@@ -31,13 +33,12 @@ export async function resolveCommand(projectRoot, options = {}) {
|
|
|
31
33
|
const { patchFilename } = state.pendingResolution;
|
|
32
34
|
info(`Resolving conflict for patch: ${patchFilename}`);
|
|
33
35
|
await assertEngineGitReady(paths.engine);
|
|
34
|
-
// Non-interactive mode requires an explicit `--yes
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
if (!(process.stdin.isTTY && process.stdout.isTTY) && !options.yes) {
|
|
36
|
+
// Non-interactive mode requires an explicit `--yes`: the operator is
|
|
37
|
+
// asserting the manual merge is complete and the refreshed diff is the one
|
|
38
|
+
// to record. Without it, an accidental pipe or CI shell could commit
|
|
39
|
+
// whatever the engine currently contains — but an unconditional TTY
|
|
40
|
+
// refusal dead-ends a scripted recovery flow.
|
|
41
|
+
if (!stdioIsInteractive() && !options.yes) {
|
|
41
42
|
throw new GeneralError('Cannot run "fireforge resolve" in non-interactive mode. Use a terminal with TTY support, or pass "--yes" to skip the interactive confirmation once the manual merge is complete.');
|
|
42
43
|
}
|
|
43
44
|
if (!options.yes) {
|
|
@@ -106,35 +107,31 @@ export async function resolveCommand(projectRoot, options = {}) {
|
|
|
106
107
|
return;
|
|
107
108
|
}
|
|
108
109
|
// Atomically write the patch body and the metadata update under the
|
|
109
|
-
// shared patch-directory lock.
|
|
110
|
-
// sequence
|
|
111
|
-
// import / export / re-export / patch reorder / patch compact
|
|
112
|
-
//
|
|
113
|
-
// freshly-written patch body.
|
|
110
|
+
// shared patch-directory lock. A lock-free updatePatch +
|
|
111
|
+
// updatePatchMetadata sequence can be interleaved by a concurrent
|
|
112
|
+
// import / export / re-export / patch reorder / patch compact, leaving
|
|
113
|
+
// the manifest disagreeing with the freshly-written patch body.
|
|
114
114
|
//
|
|
115
|
-
// Always recompute `filesAffected` from the diff content itself.
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
// consistency — using it here keeps resolve in agreement with every
|
|
125
|
-
// other writer.
|
|
115
|
+
// Always recompute `filesAffected` from the diff content itself. When a
|
|
116
|
+
// manual fix removes every hunk for one file while the file still exists
|
|
117
|
+
// on disk, a gate of "update filesAffected only when files were deleted
|
|
118
|
+
// from disk" leaves the manifest claiming a file the patch body no longer
|
|
119
|
+
// targets, and the next `fireforge import` fails the patch-manifest
|
|
120
|
+
// consistency check even though resolve reported success.
|
|
121
|
+
// `extractAffectedFiles` already owns the canonical "parse a diff, return
|
|
122
|
+
// its target paths" logic used by export and consistency, so using it
|
|
123
|
+
// here keeps resolve in agreement with every other writer.
|
|
126
124
|
const diffFilesAffected = extractAffectedFiles(diffContent);
|
|
127
125
|
const config = await loadConfig(projectRoot);
|
|
128
126
|
await updatePatchAndMetadata(paths.patches, patchFilename, diffContent, {
|
|
129
127
|
filesAffected: diffFilesAffected,
|
|
130
128
|
...buildPatchSourceMetadata(config.firefox),
|
|
131
|
-
});
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
// affected.
|
|
129
|
+
}, undefined, undefined, { waitLockSeconds: resolveWaitLockSeconds(options.waitLock), command: 'resolve' });
|
|
130
|
+
// Clear pendingResolution from state.json transactionally so a
|
|
131
|
+
// concurrent update to unrelated keys (another command writing buildMode
|
|
132
|
+
// or baseCommit between our load and save) is not clobbered. The updater
|
|
133
|
+
// runs inside the state-file lock with the freshest on-disk state, so
|
|
134
|
+
// only pendingResolution is affected.
|
|
138
135
|
await updateState(projectRoot, (current) => {
|
|
139
136
|
const next = { ...current };
|
|
140
137
|
delete next.pendingResolution;
|
|
@@ -153,11 +150,11 @@ export async function resolveCommand(projectRoot, options = {}) {
|
|
|
153
150
|
}
|
|
154
151
|
/** Registers the resolve command on the CLI program. */
|
|
155
152
|
export function registerResolve(program, { getProjectRoot, withErrorHandling }) {
|
|
156
|
-
program
|
|
153
|
+
const command = program
|
|
157
154
|
.command('resolve')
|
|
158
155
|
.description('Update a broken patch with manual fixes (then run "fireforge import" to resume the queue)')
|
|
159
|
-
.option('-y, --yes', 'Skip the interactive confirmation prompt. Use for non-interactive automation flows (CI, scripted recovery) after the manual merge is complete.')
|
|
160
|
-
|
|
156
|
+
.option('-y, --yes', 'Skip the interactive confirmation prompt. Use for non-interactive automation flows (CI, scripted recovery) after the manual merge is complete.');
|
|
157
|
+
addWaitLockOption(command).action(withErrorHandling(async (options) => {
|
|
161
158
|
await resolveCommand(getProjectRoot(), options);
|
|
162
159
|
}));
|
|
163
160
|
}
|