@hominis/fireforge 0.45.0 → 0.46.1
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 +409 -446
- package/dist/bin/fireforge.d.ts +1 -1
- package/dist/bin/fireforge.js +21 -15
- package/dist/build-info.json +4 -4
- package/dist/src/cli-usage-error.d.ts +46 -0
- package/dist/src/cli-usage-error.js +81 -0
- package/dist/src/cli.d.ts +7 -2
- package/dist/src/cli.js +47 -47
- package/dist/src/commands/bootstrap-checks.js +2 -1
- package/dist/src/commands/bootstrap.js +3 -4
- package/dist/src/commands/build.js +27 -17
- package/dist/src/commands/config.js +9 -9
- package/dist/src/commands/destructive-decision.d.ts +19 -0
- package/dist/src/commands/destructive-decision.js +31 -0
- package/dist/src/commands/discard.js +5 -5
- package/dist/src/commands/doctor-check-core.d.ts +4 -10
- package/dist/src/commands/doctor-check-core.js +0 -8
- package/dist/src/commands/doctor-external-toolchains.js +2 -2
- package/dist/src/commands/doctor-furnace-config-sync.d.ts +2 -2
- package/dist/src/commands/doctor-furnace-config-sync.js +20 -20
- package/dist/src/commands/doctor-furnace-jar.d.ts +1 -1
- package/dist/src/commands/doctor-furnace-jar.js +1 -1
- package/dist/src/commands/doctor-furnace.js +22 -22
- package/dist/src/commands/doctor-orphaned-harness.d.ts +10 -17
- package/dist/src/commands/doctor-orphaned-harness.js +14 -23
- package/dist/src/commands/doctor-patch-manifest.d.ts +2 -1
- package/dist/src/commands/doctor-patch-manifest.js +7 -6
- package/dist/src/commands/doctor-post-rebase-audit.js +3 -3
- package/dist/src/commands/doctor-source-pin.d.ts +12 -12
- package/dist/src/commands/doctor-source-pin.js +14 -14
- package/dist/src/commands/doctor-working-tree.d.ts +3 -3
- package/dist/src/commands/doctor-working-tree.js +3 -3
- package/dist/src/commands/doctor.d.ts +3 -1
- package/dist/src/commands/doctor.js +15 -16
- package/dist/src/commands/download.js +50 -37
- package/dist/src/commands/export-all.js +29 -12
- package/dist/src/commands/export-flow.d.ts +5 -5
- package/dist/src/commands/export-flow.js +29 -59
- package/dist/src/commands/export-placement-conflicts.d.ts +3 -3
- package/dist/src/commands/export-placement-conflicts.js +12 -12
- package/dist/src/commands/export-placement-gate.d.ts +2 -2
- package/dist/src/commands/export-placement-gate.js +7 -13
- package/dist/src/commands/export-placement-policy.d.ts +1 -1
- package/dist/src/commands/export-placement-policy.js +4 -6
- package/dist/src/commands/export-shared.d.ts +51 -32
- package/dist/src/commands/export-shared.js +17 -32
- package/dist/src/commands/export.js +14 -5
- package/dist/src/commands/furnace/apply.js +16 -16
- package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
- package/dist/src/commands/furnace/authoring-config.js +19 -0
- package/dist/src/commands/furnace/chrome-doc-remove.d.ts +1 -1
- package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
- package/dist/src/commands/furnace/chrome-doc-templates.d.ts +14 -14
- package/dist/src/commands/furnace/chrome-doc-templates.js +17 -17
- package/dist/src/commands/furnace/chrome-doc-tests.d.ts +2 -2
- package/dist/src/commands/furnace/chrome-doc-tests.js +4 -4
- package/dist/src/commands/furnace/chrome-doc.d.ts +8 -8
- package/dist/src/commands/furnace/chrome-doc.js +18 -18
- package/dist/src/commands/furnace/create-browser-test.d.ts +1 -1
- package/dist/src/commands/furnace/create-browser-test.js +7 -12
- package/dist/src/commands/furnace/create-dry-run.d.ts +4 -4
- package/dist/src/commands/furnace/create-dry-run.js +6 -9
- package/dist/src/commands/furnace/create-features.d.ts +2 -2
- package/dist/src/commands/furnace/create-features.js +2 -2
- package/dist/src/commands/furnace/create-mochikit.d.ts +4 -4
- package/dist/src/commands/furnace/create-mochikit.js +7 -7
- package/dist/src/commands/furnace/create-templates.d.ts +31 -15
- package/dist/src/commands/furnace/create-templates.js +20 -19
- package/dist/src/commands/furnace/create-xpcshell.d.ts +5 -5
- package/dist/src/commands/furnace/create-xpcshell.js +8 -8
- package/dist/src/commands/furnace/create.d.ts +1 -1
- package/dist/src/commands/furnace/create.js +35 -29
- package/dist/src/commands/furnace/deploy.js +15 -6
- package/dist/src/commands/furnace/diff.js +7 -7
- package/dist/src/commands/furnace/index.js +1 -1
- package/dist/src/commands/furnace/init.js +17 -16
- package/dist/src/commands/furnace/list.js +2 -2
- package/dist/src/commands/furnace/override.d.ts +1 -1
- package/dist/src/commands/furnace/override.js +43 -34
- package/dist/src/commands/furnace/preview.js +17 -17
- package/dist/src/commands/furnace/refresh.js +15 -7
- package/dist/src/commands/furnace/remove-mutations.d.ts +9 -10
- package/dist/src/commands/furnace/remove-mutations.js +19 -19
- package/dist/src/commands/furnace/remove-state.d.ts +1 -1
- package/dist/src/commands/furnace/remove-state.js +1 -1
- package/dist/src/commands/furnace/remove.js +4 -8
- package/dist/src/commands/furnace/rename-browser-test.js +10 -15
- package/dist/src/commands/furnace/rename-xpcshell.d.ts +2 -2
- package/dist/src/commands/furnace/rename-xpcshell.js +3 -3
- package/dist/src/commands/furnace/rename.js +36 -36
- package/dist/src/commands/furnace/scan.js +3 -3
- package/dist/src/commands/furnace/status.js +19 -16
- package/dist/src/commands/furnace/sync.js +6 -6
- package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
- package/dist/src/commands/furnace/test-file-name.js +39 -0
- package/dist/src/commands/furnace/validate.js +11 -12
- package/dist/src/commands/furnace/validation-output.d.ts +21 -9
- package/dist/src/commands/furnace/validation-output.js +3 -8
- package/dist/src/commands/import.js +22 -29
- package/dist/src/commands/lint-per-patch.d.ts +2 -2
- package/dist/src/commands/lint-per-patch.js +27 -12
- package/dist/src/commands/lint-per-run-checkjs.d.ts +14 -15
- package/dist/src/commands/lint-per-run-checkjs.js +14 -15
- package/dist/src/commands/lint-report.d.ts +3 -3
- package/dist/src/commands/lint-report.js +4 -4
- package/dist/src/commands/lint.d.ts +5 -4
- package/dist/src/commands/lint.js +36 -36
- package/dist/src/commands/manifest.d.ts +4 -4
- package/dist/src/commands/manifest.js +1 -1
- package/dist/src/commands/package.js +4 -6
- package/dist/src/commands/patch/compact.d.ts +2 -2
- package/dist/src/commands/patch/compact.js +19 -20
- package/dist/src/commands/patch/delete.d.ts +1 -1
- package/dist/src/commands/patch/delete.js +23 -33
- package/dist/src/commands/patch/entry-projection.d.ts +13 -0
- package/dist/src/commands/patch/entry-projection.js +24 -0
- package/dist/src/commands/patch/lint-ignore.d.ts +3 -12
- package/dist/src/commands/patch/lint-ignore.js +33 -44
- package/dist/src/commands/patch/move-files-create.d.ts +2 -2
- package/dist/src/commands/patch/move-files-create.js +29 -15
- package/dist/src/commands/patch/move-files-into.d.ts +2 -2
- package/dist/src/commands/patch/move-files-into.js +41 -37
- package/dist/src/commands/patch/move-files.js +5 -14
- package/dist/src/commands/patch/patch-context.d.ts +1 -1
- package/dist/src/commands/patch/rename.d.ts +4 -4
- package/dist/src/commands/patch/rename.js +35 -49
- package/dist/src/commands/patch/reorder.js +35 -48
- package/dist/src/commands/patch/split-plan.d.ts +7 -8
- package/dist/src/commands/patch/split-plan.js +10 -13
- package/dist/src/commands/patch/split.d.ts +2 -2
- package/dist/src/commands/patch/split.js +50 -48
- package/dist/src/commands/patch/staged-dependency-validate.d.ts +1 -1
- package/dist/src/commands/patch/staged-dependency-validate.js +3 -3
- package/dist/src/commands/patch/staged-dependency.d.ts +1 -1
- package/dist/src/commands/patch/staged-dependency.js +22 -28
- package/dist/src/commands/patch/tier.d.ts +2 -2
- package/dist/src/commands/patch/tier.js +20 -30
- package/dist/src/commands/patch-rename-map.d.ts +19 -0
- package/dist/src/commands/patch-rename-map.js +36 -0
- package/dist/src/commands/pending-resolution.d.ts +15 -0
- package/dist/src/commands/pending-resolution.js +25 -0
- package/dist/src/commands/re-export-adjacent.d.ts +25 -3
- package/dist/src/commands/re-export-adjacent.js +40 -24
- package/dist/src/commands/re-export-bulk-scan.d.ts +3 -3
- package/dist/src/commands/re-export-bulk-scan.js +23 -27
- package/dist/src/commands/re-export-drift.d.ts +10 -10
- package/dist/src/commands/re-export-drift.js +33 -33
- package/dist/src/commands/re-export-files.d.ts +2 -3
- package/dist/src/commands/re-export-files.js +52 -44
- package/dist/src/commands/re-export-lint.d.ts +29 -30
- package/dist/src/commands/re-export-lint.js +36 -29
- package/dist/src/commands/re-export-options.d.ts +1 -1
- package/dist/src/commands/re-export-options.js +1 -1
- package/dist/src/commands/re-export-register.d.ts +1 -1
- package/dist/src/commands/re-export-register.js +1 -1
- package/dist/src/commands/re-export-scan.d.ts +1 -1
- package/dist/src/commands/re-export-scan.js +12 -9
- package/dist/src/commands/re-export-single.d.ts +23 -4
- package/dist/src/commands/re-export-single.js +39 -31
- package/dist/src/commands/re-export.js +35 -17
- package/dist/src/commands/rebase/abort.js +9 -14
- package/dist/src/commands/rebase/continue.js +20 -19
- package/dist/src/commands/rebase/index.d.ts +1 -1
- package/dist/src/commands/rebase/index.js +5 -5
- package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
- package/dist/src/commands/rebase/patch-loop.js +20 -24
- package/dist/src/commands/register.js +5 -5
- package/dist/src/commands/reset.js +1 -1
- package/dist/src/commands/resolve.d.ts +2 -2
- package/dist/src/commands/resolve.js +21 -13
- package/dist/src/commands/run.d.ts +0 -13
- package/dist/src/commands/run.js +38 -51
- package/dist/src/commands/setup-support.d.ts +16 -4
- package/dist/src/commands/setup-support.js +20 -20
- package/dist/src/commands/setup.js +4 -10
- package/dist/src/commands/source.js +9 -2
- package/dist/src/commands/status-check.d.ts +3 -3
- package/dist/src/commands/status-check.js +6 -6
- package/dist/src/commands/status-json.d.ts +14 -13
- package/dist/src/commands/status-json.js +9 -8
- package/dist/src/commands/status-output.d.ts +3 -3
- package/dist/src/commands/status-output.js +5 -5
- package/dist/src/commands/status-ownership.d.ts +3 -3
- package/dist/src/commands/status-ownership.js +3 -3
- package/dist/src/commands/status.js +25 -26
- package/dist/src/commands/test-build-phase.d.ts +3 -3
- package/dist/src/commands/test-build-phase.js +48 -24
- package/dist/src/commands/test-diagnose.d.ts +1 -1
- package/dist/src/commands/test-diagnose.js +20 -20
- package/dist/src/commands/test-modes.d.ts +4 -4
- package/dist/src/commands/test-modes.js +4 -5
- package/dist/src/commands/test-register.js +5 -3
- package/dist/src/commands/test-run.d.ts +11 -11
- package/dist/src/commands/test-run.js +40 -33
- package/dist/src/commands/test-stale-gate.d.ts +12 -12
- package/dist/src/commands/test-stale-gate.js +17 -17
- package/dist/src/commands/test-verdict.d.ts +19 -5
- package/dist/src/commands/test-verdict.js +26 -11
- package/dist/src/commands/test.d.ts +3 -3
- package/dist/src/commands/test.js +73 -36
- package/dist/src/commands/token-coverage.js +3 -3
- package/dist/src/commands/token-list.d.ts +26 -0
- package/dist/src/commands/token-list.js +153 -0
- package/dist/src/commands/token.js +26 -10
- package/dist/src/commands/tree.js +26 -21
- package/dist/src/commands/typecheck.d.ts +6 -6
- package/dist/src/commands/typecheck.js +16 -16
- package/dist/src/commands/verify.d.ts +3 -3
- package/dist/src/commands/verify.js +10 -10
- package/dist/src/commands/watch.js +11 -11
- package/dist/src/commands/wire.js +17 -16
- package/dist/src/core/ast-utils.d.ts +7 -7
- package/dist/src/core/ast-utils.js +8 -8
- package/dist/src/core/branding.d.ts +5 -12
- package/dist/src/core/branding.js +6 -5
- package/dist/src/core/browser-wire.d.ts +1 -1
- package/dist/src/core/browser-wire.js +10 -7
- package/dist/src/core/build-audit-platform.d.ts +32 -3
- package/dist/src/core/build-audit-platform.js +153 -13
- package/dist/src/core/build-audit-registration.d.ts +5 -5
- package/dist/src/core/build-audit-registration.js +10 -9
- package/dist/src/core/build-audit-resolve.d.ts +5 -5
- package/dist/src/core/build-audit-resolve.js +6 -6
- package/dist/src/core/build-audit-skip.d.ts +57 -0
- package/dist/src/core/build-audit-skip.js +112 -0
- package/dist/src/core/build-audit-transforms.d.ts +2 -2
- package/dist/src/core/build-audit-transforms.js +3 -3
- package/dist/src/core/build-audit.d.ts +21 -8
- package/dist/src/core/build-audit.js +142 -40
- package/dist/src/core/build-baseline-types.d.ts +19 -18
- package/dist/src/core/build-baseline-types.js +1 -1
- package/dist/src/core/build-baseline.d.ts +48 -31
- package/dist/src/core/build-baseline.js +20 -43
- package/dist/src/core/build-jar-escalation.d.ts +8 -8
- package/dist/src/core/build-jar-escalation.js +18 -17
- package/dist/src/core/build-overwrite-guard.d.ts +4 -4
- package/dist/src/core/build-overwrite-guard.js +14 -14
- package/dist/src/core/build-prepare.d.ts +4 -12
- package/dist/src/core/build-prepare.js +22 -26
- package/dist/src/core/config-mutate.js +4 -4
- package/dist/src/core/config-paths.d.ts +2 -6
- package/dist/src/core/config-paths.js +4 -2
- package/dist/src/core/config-state.d.ts +0 -6
- package/dist/src/core/config-state.js +3 -21
- package/dist/src/core/config-validate-build-audit.d.ts +8 -0
- package/dist/src/core/config-validate-build-audit.js +80 -0
- package/dist/src/core/config-validate-file-size.d.ts +1 -1
- package/dist/src/core/config-validate-file-size.js +3 -3
- package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
- package/dist/src/core/config-validate-patch-policy.js +3 -3
- package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
- package/dist/src/core/config-validate-test-toolchains.js +4 -5
- package/dist/src/core/config-validate.js +22 -12
- package/dist/src/core/config.d.ts +12 -12
- package/dist/src/core/config.js +21 -25
- package/dist/src/core/coverage-extend.d.ts +16 -16
- package/dist/src/core/coverage-extend.js +20 -20
- package/dist/src/core/destructive.d.ts +14 -14
- package/dist/src/core/destructive.js +9 -9
- package/dist/src/core/diff-hunks.d.ts +2 -2
- package/dist/src/core/diff-hunks.js +7 -7
- package/dist/src/core/discard-baseline.d.ts +10 -10
- package/dist/src/core/discard-baseline.js +22 -23
- package/dist/src/core/display-state.d.ts +11 -11
- package/dist/src/core/display-state.js +12 -12
- package/dist/src/core/engine-changes.d.ts +2 -2
- package/dist/src/core/engine-changes.js +2 -2
- package/dist/src/core/engine-precondition.d.ts +5 -13
- package/dist/src/core/engine-precondition.js +5 -10
- package/dist/src/core/engine-session-lock.d.ts +18 -18
- package/dist/src/core/engine-session-lock.js +50 -54
- package/dist/src/core/export-moved-code-shape.d.ts +7 -7
- package/dist/src/core/export-moved-code-shape.js +10 -10
- package/dist/src/core/file-lock-owner.d.ts +103 -0
- package/dist/src/core/file-lock-owner.js +259 -0
- package/dist/src/core/file-lock.d.ts +14 -19
- package/dist/src/core/file-lock.js +90 -128
- package/dist/src/core/firefox-cache.d.ts +13 -1
- package/dist/src/core/firefox-cache.js +61 -36
- package/dist/src/core/firefox-download.d.ts +15 -0
- package/dist/src/core/firefox-download.js +38 -22
- package/dist/src/core/firefox-extract.d.ts +8 -7
- package/dist/src/core/firefox-extract.js +45 -27
- package/dist/src/core/firefox.d.ts +34 -36
- package/dist/src/core/firefox.js +13 -44
- package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
- package/dist/src/core/furnace-apply-dry-run.js +2 -8
- package/dist/src/core/furnace-apply-ftl.d.ts +5 -5
- package/dist/src/core/furnace-apply-ftl.js +8 -8
- package/dist/src/core/furnace-apply-helpers.d.ts +9 -20
- package/dist/src/core/furnace-apply-helpers.js +28 -39
- package/dist/src/core/furnace-apply-output.js +1 -1
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +9 -9
- package/dist/src/core/furnace-apply-overwrite-warn.js +13 -11
- package/dist/src/core/furnace-apply-undeploy-actions.d.ts +1 -1
- package/dist/src/core/furnace-apply-undeploy-actions.js +1 -1
- package/dist/src/core/furnace-apply.d.ts +4 -4
- package/dist/src/core/furnace-apply.js +50 -29
- package/dist/src/core/furnace-checksum-utils.d.ts +5 -5
- package/dist/src/core/furnace-checksum-utils.js +5 -5
- package/dist/src/core/furnace-config-custom.d.ts +1 -1
- package/dist/src/core/furnace-config-custom.js +2 -2
- package/dist/src/core/furnace-config-order.js +1 -1
- package/dist/src/core/furnace-config-tokens.d.ts +3 -3
- package/dist/src/core/furnace-config-tokens.js +3 -3
- package/dist/src/core/furnace-config-validate.js +2 -2
- package/dist/src/core/furnace-config.d.ts +5 -5
- package/dist/src/core/furnace-config.js +40 -53
- package/dist/src/core/furnace-constants.d.ts +6 -6
- package/dist/src/core/furnace-constants.js +9 -8
- package/dist/src/core/furnace-css-fragments.d.ts +6 -6
- package/dist/src/core/furnace-css-fragments.js +11 -11
- package/dist/src/core/furnace-dir-entry.d.ts +20 -0
- package/dist/src/core/furnace-dir-entry.js +21 -0
- package/dist/src/core/furnace-jsconfig.d.ts +7 -7
- package/dist/src/core/furnace-jsconfig.js +22 -20
- package/dist/src/core/furnace-operation.d.ts +22 -19
- package/dist/src/core/furnace-operation.js +38 -34
- package/dist/src/core/furnace-precondition.d.ts +10 -10
- package/dist/src/core/furnace-precondition.js +8 -8
- package/dist/src/core/furnace-refresh.d.ts +18 -6
- package/dist/src/core/furnace-refresh.js +5 -8
- package/dist/src/core/furnace-registration-ast.d.ts +2 -3
- package/dist/src/core/furnace-registration-ast.js +9 -12
- package/dist/src/core/furnace-registration-remove.d.ts +4 -4
- package/dist/src/core/furnace-registration-remove.js +6 -6
- package/dist/src/core/furnace-registration-validate.d.ts +2 -2
- package/dist/src/core/furnace-registration-validate.js +2 -2
- package/dist/src/core/furnace-registration.d.ts +7 -6
- package/dist/src/core/furnace-registration.js +29 -36
- package/dist/src/core/furnace-rollback.d.ts +1 -1
- package/dist/src/core/furnace-rollback.js +5 -5
- package/dist/src/core/furnace-scanner.js +3 -6
- package/dist/src/core/furnace-stale-export.d.ts +17 -16
- package/dist/src/core/furnace-stale-export.js +16 -15
- package/dist/src/core/furnace-staleness.d.ts +2 -2
- package/dist/src/core/furnace-staleness.js +2 -2
- package/dist/src/core/furnace-state-persist.d.ts +12 -12
- package/dist/src/core/furnace-state-persist.js +10 -10
- package/dist/src/core/furnace-step-errors.d.ts +6 -6
- package/dist/src/core/furnace-step-errors.js +6 -6
- package/dist/src/core/furnace-validate-accessibility.js +14 -14
- package/dist/src/core/furnace-validate-compatibility.js +9 -9
- package/dist/src/core/furnace-validate-registration.d.ts +2 -2
- package/dist/src/core/furnace-validate-registration.js +18 -20
- package/dist/src/core/furnace-validate-structure.d.ts +1 -1
- package/dist/src/core/furnace-validate-structure.js +4 -4
- package/dist/src/core/furnace-validate.js +9 -9
- package/dist/src/core/furnace-version-drift.d.ts +5 -5
- package/dist/src/core/furnace-version-drift.js +5 -5
- package/dist/src/core/git-base.d.ts +6 -4
- package/dist/src/core/git-base.js +29 -7
- package/dist/src/core/git-diff-new-file.d.ts +40 -0
- package/dist/src/core/git-diff-new-file.js +119 -0
- package/dist/src/core/git-diff.d.ts +13 -13
- package/dist/src/core/git-diff.js +121 -189
- package/dist/src/core/git-file-ops.d.ts +6 -13
- package/dist/src/core/git-file-ops.js +11 -35
- package/dist/src/core/git-readonly-index.d.ts +12 -14
- package/dist/src/core/git-readonly-index.js +12 -16
- package/dist/src/core/git-status.d.ts +9 -2
- package/dist/src/core/git-status.js +23 -11
- package/dist/src/core/git.d.ts +3 -9
- package/dist/src/core/git.js +28 -57
- package/dist/src/core/harness-orphans.d.ts +17 -17
- package/dist/src/core/harness-orphans.js +28 -27
- package/dist/src/core/history-log.d.ts +19 -0
- package/dist/src/core/history-log.js +29 -0
- package/dist/src/core/license-headers.d.ts +19 -18
- package/dist/src/core/license-headers.js +29 -28
- package/dist/src/core/mach-build-artifacts.d.ts +21 -21
- package/dist/src/core/mach-build-artifacts.js +23 -23
- package/dist/src/core/mach-error-hints.d.ts +5 -10
- package/dist/src/core/mach-error-hints.js +14 -14
- package/dist/src/core/mach-known-noise-filter.d.ts +42 -38
- package/dist/src/core/mach-known-noise-filter.js +57 -56
- package/dist/src/core/mach-mozconfig.d.ts +6 -6
- package/dist/src/core/mach-mozconfig.js +17 -16
- package/dist/src/core/mach-python.d.ts +3 -0
- package/dist/src/core/mach-python.js +13 -7
- package/dist/src/core/mach-resource-shim.d.ts +24 -12
- package/dist/src/core/mach-resource-shim.js +124 -21
- package/dist/src/core/mach.d.ts +59 -73
- package/dist/src/core/mach.js +47 -115
- package/dist/src/core/marionette-port.d.ts +15 -30
- package/dist/src/core/marionette-port.js +46 -89
- package/dist/src/core/marionette-preflight.d.ts +6 -6
- package/dist/src/core/marionette-preflight.js +32 -50
- package/dist/src/core/markdown-table.d.ts +9 -9
- package/dist/src/core/markdown-table.js +14 -14
- package/dist/src/core/mochitest-server-port.d.ts +8 -8
- package/dist/src/core/mochitest-server-port.js +17 -17
- package/dist/src/core/module-resolution-preflight.d.ts +8 -8
- package/dist/src/core/module-resolution-preflight.js +11 -11
- package/dist/src/core/moz-manifest-helpers.d.ts +7 -7
- package/dist/src/core/moz-manifest-helpers.js +7 -7
- package/dist/src/core/moz-manifest-register.d.ts +1 -1
- package/dist/src/core/moz-manifest-register.js +2 -2
- package/dist/src/core/moz-manifest-rules.js +46 -42
- package/dist/src/core/moz-manifest-tokenizers.js +1 -1
- package/dist/src/core/ownership-table.d.ts +5 -5
- package/dist/src/core/ownership-table.js +7 -7
- package/dist/src/core/parser-fallback.d.ts +3 -3
- package/dist/src/core/parser-fallback.js +3 -3
- package/dist/src/core/patch-apply-fuzz.d.ts +5 -5
- package/dist/src/core/patch-apply-fuzz.js +13 -13
- package/dist/src/core/patch-apply.d.ts +13 -14
- package/dist/src/core/patch-apply.js +36 -42
- package/dist/src/core/patch-export-coverage.d.ts +0 -9
- package/dist/src/core/patch-export-coverage.js +1 -30
- package/dist/src/core/patch-export-update.d.ts +21 -4
- package/dist/src/core/patch-export-update.js +7 -6
- package/dist/src/core/patch-export.d.ts +20 -30
- package/dist/src/core/patch-export.js +55 -77
- package/dist/src/core/patch-files.d.ts +0 -4
- package/dist/src/core/patch-files.js +0 -11
- package/dist/src/core/patch-identifier-suggest.d.ts +1 -1
- package/dist/src/core/patch-identifier-suggest.js +4 -4
- package/dist/src/core/patch-lint-binary.d.ts +12 -18
- package/dist/src/core/patch-lint-cache.d.ts +18 -2
- package/dist/src/core/patch-lint-cache.js +16 -19
- package/dist/src/core/patch-lint-checkjs.d.ts +55 -38
- package/dist/src/core/patch-lint-checkjs.js +78 -64
- package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +8 -9
- package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -11
- package/dist/src/core/patch-lint-creators.d.ts +5 -9
- package/dist/src/core/patch-lint-creators.js +3 -3
- package/dist/src/core/patch-lint-cross.d.ts +27 -19
- package/dist/src/core/patch-lint-cross.js +67 -110
- package/dist/src/core/patch-lint-css.d.ts +1 -1
- package/dist/src/core/patch-lint-css.js +15 -11
- package/dist/src/core/patch-lint-diff-tag.d.ts +5 -5
- package/dist/src/core/patch-lint-diff-tag.js +5 -5
- package/dist/src/core/patch-lint-diff.d.ts +4 -4
- package/dist/src/core/patch-lint-diff.js +4 -4
- package/dist/src/core/patch-lint-file-size.d.ts +3 -3
- package/dist/src/core/patch-lint-file-size.js +6 -6
- package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
- package/dist/src/core/patch-lint-forward-registration.js +210 -0
- package/dist/src/core/patch-lint-jsdoc.d.ts +2 -2
- package/dist/src/core/patch-lint-jsdoc.js +46 -46
- package/dist/src/core/patch-lint-module-registration.d.ts +3 -9
- package/dist/src/core/patch-lint-module-registration.js +1 -1
- package/dist/src/core/patch-lint-mozbuild.d.ts +1 -1
- package/dist/src/core/patch-lint-mozbuild.js +10 -10
- package/dist/src/core/patch-lint-observer.d.ts +3 -3
- package/dist/src/core/patch-lint-observer.js +7 -7
- package/dist/src/core/patch-lint-ownership.d.ts +6 -6
- package/dist/src/core/patch-lint-ownership.js +6 -6
- package/dist/src/core/patch-lint-prettier.d.ts +6 -6
- package/dist/src/core/patch-lint-prettier.js +7 -7
- package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
- package/dist/src/core/patch-lint-queue-types.js +12 -0
- package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
- package/dist/src/core/patch-lint-staged-registration.js +90 -0
- package/dist/src/core/patch-lint-unmanaged-companion.d.ts +23 -23
- package/dist/src/core/patch-lint-unmanaged-companion.js +26 -26
- package/dist/src/core/patch-lint.d.ts +41 -35
- package/dist/src/core/patch-lint.js +52 -49
- package/dist/src/core/patch-lock.d.ts +1 -1
- package/dist/src/core/patch-lock.js +11 -11
- package/dist/src/core/patch-manifest-consistency.d.ts +7 -7
- package/dist/src/core/patch-manifest-consistency.js +16 -17
- package/dist/src/core/patch-manifest-files-affected.d.ts +1 -1
- package/dist/src/core/patch-manifest-files-affected.js +3 -3
- package/dist/src/core/patch-manifest-io.d.ts +14 -14
- package/dist/src/core/patch-manifest-io.js +35 -34
- package/dist/src/core/patch-manifest-query.d.ts +1 -1
- package/dist/src/core/patch-manifest-query.js +4 -4
- package/dist/src/core/patch-manifest-resolve.d.ts +5 -5
- package/dist/src/core/patch-manifest-resolve.js +7 -7
- package/dist/src/core/patch-manifest-validate.js +3 -3
- package/dist/src/core/patch-manifest.d.ts +2 -2
- package/dist/src/core/patch-manifest.js +2 -2
- package/dist/src/core/patch-parse.d.ts +32 -21
- package/dist/src/core/patch-parse.js +40 -15
- package/dist/src/core/patch-policy.js +15 -27
- package/dist/src/core/patch-registration-refs.d.ts +4 -4
- package/dist/src/core/patch-registration-refs.js +7 -7
- package/dist/src/core/patch-source-metadata.d.ts +1 -3
- package/dist/src/core/patch-source-metadata.js +0 -4
- package/dist/src/core/patch-transform.d.ts +8 -16
- package/dist/src/core/patch-transform.js +13 -23
- package/dist/src/core/process-cpu-time.d.ts +1 -1
- package/dist/src/core/process-cpu-time.js +6 -6
- package/dist/src/core/rebase-session.d.ts +9 -15
- package/dist/src/core/rebase-session.js +13 -25
- package/dist/src/core/register-browser-content.js +3 -2
- package/dist/src/core/register-browser-test.js +2 -1
- package/dist/src/core/register-module.js +2 -1
- package/dist/src/core/register-result.d.ts +1 -1
- package/dist/src/core/register-result.js +1 -1
- package/dist/src/core/register-scaffold.d.ts +2 -2
- package/dist/src/core/register-scaffold.js +8 -7
- package/dist/src/core/register-shared-css.d.ts +3 -3
- package/dist/src/core/register-shared-css.js +6 -5
- package/dist/src/core/register-xpcshell-test.d.ts +2 -2
- package/dist/src/core/register-xpcshell-test.js +2 -2
- package/dist/src/core/run-log-redact.d.ts +38 -0
- package/dist/src/core/run-log-redact.js +69 -0
- package/dist/src/core/run-log.d.ts +21 -10
- package/dist/src/core/run-log.js +76 -27
- package/dist/src/core/shared-ftl.d.ts +2 -2
- package/dist/src/core/shared-ftl.js +6 -6
- package/dist/src/core/signal-critical.d.ts +2 -2
- package/dist/src/core/signal-critical.js +4 -6
- package/dist/src/core/smoke-patterns.d.ts +5 -6
- package/dist/src/core/smoke-patterns.js +15 -20
- package/dist/src/core/state-file.d.ts +15 -4
- package/dist/src/core/state-file.js +14 -1
- package/dist/src/core/status-binary.d.ts +8 -8
- package/dist/src/core/status-binary.js +12 -12
- package/dist/src/core/status-classify.d.ts +17 -17
- package/dist/src/core/status-classify.js +13 -12
- package/dist/src/core/test-changed-prefs.d.ts +12 -12
- package/dist/src/core/test-changed-prefs.js +40 -25
- package/dist/src/core/test-harness-crash.d.ts +39 -39
- package/dist/src/core/test-harness-crash.js +69 -69
- package/dist/src/core/test-harness-output.d.ts +7 -7
- package/dist/src/core/test-harness-output.js +7 -7
- package/dist/src/core/test-harness-verdict-notes.d.ts +13 -14
- package/dist/src/core/test-harness-verdict-notes.js +4 -4
- package/dist/src/core/test-path-scope.d.ts +8 -8
- package/dist/src/core/test-path-scope.js +11 -11
- package/dist/src/core/test-stale-check.d.ts +22 -23
- package/dist/src/core/test-stale-check.js +31 -30
- package/dist/src/core/test-stale-symlink.d.ts +1 -1
- package/dist/src/core/test-stale-symlink.js +1 -1
- package/dist/src/core/test-stall-triage.d.ts +9 -9
- package/dist/src/core/test-stall-triage.js +22 -22
- package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
- package/dist/src/core/test-xpcshell-retry.js +14 -11
- package/dist/src/core/token-category.d.ts +35 -2
- package/dist/src/core/token-category.js +67 -58
- package/dist/src/core/token-coverage.js +4 -5
- package/dist/src/core/token-dark-mode.d.ts +9 -9
- package/dist/src/core/token-dark-mode.js +13 -25
- package/dist/src/core/token-docs.d.ts +1 -1
- package/dist/src/core/token-inventory.d.ts +56 -0
- package/dist/src/core/token-inventory.js +109 -0
- package/dist/src/core/token-manager.d.ts +4 -4
- package/dist/src/core/token-manager.js +22 -22
- package/dist/src/core/token-scaffold.d.ts +4 -4
- package/dist/src/core/token-scaffold.js +4 -4
- package/dist/src/core/token-variant.d.ts +14 -14
- package/dist/src/core/token-variant.js +52 -53
- package/dist/src/core/toolchain-preflight.d.ts +15 -15
- package/dist/src/core/toolchain-preflight.js +23 -23
- package/dist/src/core/tree-cow.d.ts +3 -5
- package/dist/src/core/tree-cow.js +8 -8
- package/dist/src/core/tree-guard.d.ts +3 -3
- package/dist/src/core/tree-guard.js +23 -23
- package/dist/src/core/tree-store.d.ts +15 -15
- package/dist/src/core/tree-store.js +39 -38
- package/dist/src/core/typecheck-shim.d.ts +16 -15
- package/dist/src/core/typecheck-shim.js +26 -25
- package/dist/src/core/typecheck.d.ts +12 -12
- package/dist/src/core/typecheck.js +33 -33
- package/dist/src/core/wire-destroy.d.ts +2 -2
- package/dist/src/core/wire-destroy.js +5 -5
- package/dist/src/core/wire-dom-fragment.d.ts +3 -3
- package/dist/src/core/wire-dom-fragment.js +12 -23
- package/dist/src/core/wire-init.d.ts +2 -2
- package/dist/src/core/wire-init.js +7 -7
- package/dist/src/core/wire-subscript.d.ts +1 -1
- package/dist/src/core/wire-subscript.js +3 -3
- package/dist/src/core/wire-utils.d.ts +9 -9
- package/dist/src/core/wire-utils.js +16 -28
- package/dist/src/core/xpcshell-appdir.d.ts +20 -20
- package/dist/src/core/xpcshell-appdir.js +28 -30
- package/dist/src/core/xpcshell-profile-dir.d.ts +3 -3
- package/dist/src/core/xpcshell-profile-dir.js +7 -7
- package/dist/src/errors/base.d.ts +69 -16
- package/dist/src/errors/base.js +95 -26
- package/dist/src/errors/build.d.ts +6 -6
- package/dist/src/errors/build.js +26 -34
- package/dist/src/errors/codes.d.ts +10 -10
- package/dist/src/errors/codes.js +10 -10
- package/dist/src/errors/config.d.ts +0 -14
- package/dist/src/errors/config.js +13 -34
- package/dist/src/errors/download.d.ts +13 -0
- package/dist/src/errors/download.js +53 -24
- package/dist/src/errors/furnace.d.ts +2 -2
- package/dist/src/errors/furnace.js +8 -9
- package/dist/src/errors/git.d.ts +9 -9
- package/dist/src/errors/git.js +21 -31
- package/dist/src/errors/patch.d.ts +3 -3
- package/dist/src/errors/patch.js +11 -13
- package/dist/src/errors/rebase.d.ts +1 -1
- package/dist/src/errors/rebase.js +8 -8
- package/dist/src/errors/run.d.ts +1 -1
- package/dist/src/errors/run.js +1 -1
- package/dist/src/index.d.ts +4 -4
- package/dist/src/index.js +4 -4
- package/dist/src/types/commands/options.d.ts +155 -200
- package/dist/src/types/commands/patches.d.ts +19 -19
- package/dist/src/types/commands/project.d.ts +3 -3
- package/dist/src/types/config.d.ts +52 -19
- package/dist/src/types/furnace.d.ts +17 -17
- package/dist/src/types/index.d.ts +0 -1
- package/dist/src/types/json.d.ts +3 -3
- package/dist/src/types/json.js +2 -2
- package/dist/src/types/typecheck.d.ts +3 -3
- package/dist/src/utils/assert.d.ts +4 -16
- package/dist/src/utils/assert.js +7 -24
- package/dist/src/utils/build-info.d.ts +6 -6
- package/dist/src/utils/build-info.js +6 -6
- package/dist/src/utils/child-env.d.ts +7 -6
- package/dist/src/utils/child-env.js +5 -5
- package/dist/src/utils/concurrency.d.ts +2 -2
- package/dist/src/utils/concurrency.js +2 -2
- package/dist/src/utils/elapsed.js +10 -1
- package/dist/src/utils/errors.d.ts +8 -8
- package/dist/src/utils/errors.js +8 -8
- package/dist/src/utils/fs.d.ts +1 -1
- package/dist/src/utils/fs.js +15 -20
- package/dist/src/utils/hash.d.ts +12 -0
- package/dist/src/utils/hash.js +16 -0
- package/dist/src/utils/line-dispatch.d.ts +15 -0
- package/dist/src/utils/line-dispatch.js +48 -0
- package/dist/src/utils/logger.d.ts +4 -4
- package/dist/src/utils/logger.js +11 -11
- package/dist/src/utils/machine-output.js +2 -2
- package/dist/src/utils/options.d.ts +14 -20
- package/dist/src/utils/options.js +26 -27
- package/dist/src/utils/package-root.js +5 -14
- package/dist/src/utils/paths.d.ts +4 -4
- package/dist/src/utils/paths.js +4 -4
- package/dist/src/utils/platform.d.ts +0 -4
- package/dist/src/utils/process-group.d.ts +10 -9
- package/dist/src/utils/process-group.js +37 -36
- package/dist/src/utils/process.d.ts +70 -55
- package/dist/src/utils/process.js +129 -179
- package/dist/src/utils/ps-duration.d.ts +4 -4
- package/dist/src/utils/ps-duration.js +9 -9
- package/dist/src/utils/regex.d.ts +4 -4
- package/dist/src/utils/regex.js +7 -7
- package/dist/src/utils/sleep.d.ts +26 -0
- package/dist/src/utils/sleep.js +31 -0
- package/dist/src/utils/stdio-drain.d.ts +7 -7
- package/dist/src/utils/stdio-drain.js +8 -8
- package/dist/src/utils/validation.d.ts +12 -49
- package/dist/src/utils/validation.js +26 -36
- package/docs/README.md +2 -2
- package/docs/configuration.md +163 -69
- package/docs/exit-codes.md +66 -49
- package/docs/furnace.md +20 -19
- package/docs/lifecycle-invariants.md +414 -247
- package/docs/machine-output.md +58 -34
- package/docs/patch-workflow.md +48 -44
- package/docs/run-logs.md +72 -28
- package/docs/testing.md +105 -98
- package/docs/verification-trees.md +23 -22
- package/package.json +7 -6
- package/dist/src/commands/rebase.d.ts +0 -4
- package/dist/src/commands/rebase.js +0 -5
- package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
- package/dist/src/core/patch-artifact-normalize.js +0 -24
- package/dist/src/core/patch-lint-reexports.d.ts +0 -7
- package/dist/src/core/patch-lint-reexports.js +0 -8
- package/dist/src/core/wire-targets.d.ts +0 -7
- package/dist/src/core/wire-targets.js +0 -8
|
@@ -16,12 +16,12 @@ const PATCH_DIRECTORY_LOCK = '.fireforge-patches.lock';
|
|
|
16
16
|
* session lock's progress line so operators read one shape for both locks.
|
|
17
17
|
*/
|
|
18
18
|
function formatWaitProgressLine(waitedMs, timeoutMs, holder) {
|
|
19
|
-
const progress = `${
|
|
19
|
+
const progress = `${Math.round(waitedMs / 1000)}s of up to ${Math.round(timeoutMs / 1000)}s`;
|
|
20
20
|
if (holder === undefined) {
|
|
21
21
|
return `Waiting for the FireForge patch directory lock — ${progress}.`;
|
|
22
22
|
}
|
|
23
23
|
const details = holder.metadata.length > 0 ? ` (${holder.metadata.join(', ')})` : '';
|
|
24
|
-
return `Waiting for the FireForge patch directory lock held by PID ${
|
|
24
|
+
return `Waiting for the FireForge patch directory lock held by PID ${holder.pid}${details} — ${progress}.`;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Asserts that this process is inside {@link withPatchDirectoryLock} for the
|
|
@@ -34,7 +34,7 @@ function formatWaitProgressLine(waitedMs, timeoutMs, holder) {
|
|
|
34
34
|
* is held, so an unlocked caller silently reintroduces the interleaving the
|
|
35
35
|
* lock exists to prevent.
|
|
36
36
|
*
|
|
37
|
-
* Fail-open on an unreadable owner record,
|
|
37
|
+
* Fail-open on an unreadable owner record, on purpose: `withFileLock`
|
|
38
38
|
* treats writing that record as non-fatal, so a live holder can legitimately
|
|
39
39
|
* have no readable PID and asserting on its presence would fire on a lock we
|
|
40
40
|
* really do hold.
|
|
@@ -47,7 +47,7 @@ export async function assertPatchDirectoryLockHeld(patchesDir, context) {
|
|
|
47
47
|
const status = await readLockStatus(join(patchesDir, PATCH_DIRECTORY_LOCK));
|
|
48
48
|
assert(status.held, () => `patch directory lock is held before ${context}`);
|
|
49
49
|
assert(status.holder === undefined || status.holder.pid === process.pid, () => `patch directory lock is owned by this process before ${context} ` +
|
|
50
|
-
`(held by PID ${
|
|
50
|
+
`(held by PID ${status.holder?.pid}, we are ${process.pid})`);
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
53
|
* Runs a patch directory mutation while holding an exclusive filesystem lock.
|
|
@@ -56,7 +56,7 @@ export async function assertPatchDirectoryLockHeld(patchesDir, context) {
|
|
|
56
56
|
export async function withPatchDirectoryLock(patchesDir, operation, options = {}) {
|
|
57
57
|
const lockDir = join(patchesDir, PATCH_DIRECTORY_LOCK);
|
|
58
58
|
const { waitLockSeconds, command } = options;
|
|
59
|
-
// Tag whatever the
|
|
59
|
+
// Tag whatever the body throws so the catch below can tell it apart from a
|
|
60
60
|
// lock-acquire/release failure. Narrowing by origin rather than by error
|
|
61
61
|
// shape is what "the rewrap is for lock I/O" actually means: an errno test
|
|
62
62
|
// would still reclassify an EACCES raised while the body writes a .patch
|
|
@@ -90,10 +90,10 @@ export async function withPatchDirectoryLock(patchesDir, operation, options = {}
|
|
|
90
90
|
: {}),
|
|
91
91
|
// Reason first, remedy second. The remedy is waiting, not deleting: bulk
|
|
92
92
|
// exports/re-exports legitimately hold this lock for minutes, and
|
|
93
|
-
// FireForge reaps genuinely stale locks on its own
|
|
94
|
-
// while a holder is alive destroys a live lock. The leading
|
|
95
|
-
// a message contract
|
|
96
|
-
// holder identification.
|
|
93
|
+
// FireForge reaps genuinely stale locks on its own, and advice to
|
|
94
|
+
// `rm -rf` while a holder is alive destroys a live lock. The leading
|
|
95
|
+
// sentence is a message contract. Extend, do not reword. withFileLock
|
|
96
|
+
// appends the holder identification.
|
|
97
97
|
onTimeoutMessage: `Timed out waiting for another FireForge command mutating ${patchesDir}.\n` +
|
|
98
98
|
`Pass --wait-lock [seconds] to wait longer (bare --wait-lock waits up to 60 seconds). ` +
|
|
99
99
|
`FireForge removes genuinely stale locks automatically; only if no other fireforge ` +
|
|
@@ -105,7 +105,7 @@ export async function withPatchDirectoryLock(patchesDir, operation, options = {}
|
|
|
105
105
|
// reports an EACCES writing patches.json, a postcondition failure from
|
|
106
106
|
// renumberPatchesInManifest, or a plain TypeError from a FireForge bug
|
|
107
107
|
// as a "Patch Error" carrying three fixed remedies about Firefox-version
|
|
108
|
-
// compatibility and `fireforge reset
|
|
108
|
+
// compatibility and `fireforge reset`, none of which apply. Worse,
|
|
109
109
|
// src/cli.ts prints a stack only for non-FireForgeError throwables, so
|
|
110
110
|
// the rewrap moves real bugs into the branch that discards their stack.
|
|
111
111
|
if (bodyThrew && error === bodyFailure) {
|
|
@@ -114,7 +114,7 @@ export async function withPatchDirectoryLock(patchesDir, operation, options = {}
|
|
|
114
114
|
if (error instanceof FireForgeError) {
|
|
115
115
|
throw error;
|
|
116
116
|
}
|
|
117
|
-
// CommandError is the one class in src/errors/ that does
|
|
117
|
+
// CommandError is the one class in src/errors/ that does not extend
|
|
118
118
|
// FireForgeError: it is the sentinel carrying an already-rendered exit
|
|
119
119
|
// code to the entrypoint. The `instanceof FireForgeError` guard above
|
|
120
120
|
// misses it, so without this the exit code was replaced by PATCH_ERROR.
|
|
@@ -20,7 +20,7 @@ export declare function validatePatchesManifestConsistency(patchesDir: string):
|
|
|
20
20
|
*
|
|
21
21
|
* Drift that is only in `filesAffected` is a derived value disagreeing with
|
|
22
22
|
* the diff it describes, and the narrow repair fixes exactly that. Naming the
|
|
23
|
-
* whole-manifest rebuild for it
|
|
23
|
+
* whole-manifest rebuild for it (as this hint used to, unconditionally) puts
|
|
24
24
|
* an operator one keystroke from rewriting every row in the manifest to
|
|
25
25
|
* correct one list.
|
|
26
26
|
*/
|
|
@@ -30,19 +30,19 @@ export declare function recommendManifestRepair(issues: readonly PatchManifestCo
|
|
|
30
30
|
* lists patches whose manifest entry was reconstructed from filename,
|
|
31
31
|
* mtime, and diff alone (no pre-existing manifest entry to preserve).
|
|
32
32
|
* These entries carry generic descriptions and mtime-based
|
|
33
|
-
* timestamps
|
|
33
|
+
* timestamps. Callers like `doctor --repair-patches-manifest` surface
|
|
34
34
|
* a per-patch review warning so operators know which metadata was
|
|
35
35
|
* invented vs which was restored.
|
|
36
36
|
*/
|
|
37
37
|
export interface RebuildPatchesManifestResult {
|
|
38
38
|
/**
|
|
39
39
|
* Rebuilt manifest, ready to be re-applied by callers. Persisted unless
|
|
40
|
-
* the run was a dry run
|
|
40
|
+
* the run was a dry run. See {@link RebuildPatchesManifestResult.written}.
|
|
41
41
|
*/
|
|
42
42
|
manifest: PatchesManifest;
|
|
43
43
|
/**
|
|
44
44
|
* Filenames whose manifest entry had no pre-existing metadata to
|
|
45
|
-
* preserve
|
|
45
|
+
* preserve. Every descriptive field on these entries is inferred.
|
|
46
46
|
*/
|
|
47
47
|
recoveredFilenames: string[];
|
|
48
48
|
/**
|
|
@@ -59,7 +59,7 @@ export interface RebuildPatchesManifestOptions extends PatchDirectoryLockOptions
|
|
|
59
59
|
/**
|
|
60
60
|
* Proceed even when patches.json exists but cannot be parsed, in which case
|
|
61
61
|
* there is no existing metadata to preserve and every descriptive field on
|
|
62
|
-
* every entry is invented. Refused without this flag
|
|
62
|
+
* every entry is invented. Refused without this flag. See
|
|
63
63
|
* {@link rebuildPatchesManifest}.
|
|
64
64
|
*/
|
|
65
65
|
allowMetadataLoss?: boolean;
|
|
@@ -69,7 +69,7 @@ export interface RebuildPatchesManifestOptions extends PatchDirectoryLockOptions
|
|
|
69
69
|
/**
|
|
70
70
|
* Rebuilds patches.json from the patch files currently present on disk.
|
|
71
71
|
*
|
|
72
|
-
* This is a
|
|
72
|
+
* This is a merge, not a from-scratch rebuild: only `filesAffected` and
|
|
73
73
|
* `order` are recomputed from the patch files, and every other field on an
|
|
74
74
|
* existing entry is carried forward untouched. Entries with no pre-existing
|
|
75
75
|
* metadata are recovered from filename structure, patch contents, and file
|
|
@@ -82,7 +82,7 @@ export interface RebuildPatchesManifestOptions extends PatchDirectoryLockOptions
|
|
|
82
82
|
* @param patchesDir - Path to the patches directory
|
|
83
83
|
* @param fallbackSourceEsrVersion - source version to use for recovered legacy entries
|
|
84
84
|
* @param options - Lock options plus `allowMetadataLoss` / `dryRun`
|
|
85
|
-
* @returns {@link RebuildPatchesManifestResult}
|
|
85
|
+
* @returns {@link RebuildPatchesManifestResult}: the rebuilt manifest, the
|
|
86
86
|
* filenames that were reconstructed from generic defaults, and the rows
|
|
87
87
|
* dropped because their patch file is gone.
|
|
88
88
|
*/
|
|
@@ -86,7 +86,7 @@ export async function validatePatchesManifestConsistency(patchesDir) {
|
|
|
86
86
|
*
|
|
87
87
|
* Drift that is only in `filesAffected` is a derived value disagreeing with
|
|
88
88
|
* the diff it describes, and the narrow repair fixes exactly that. Naming the
|
|
89
|
-
* whole-manifest rebuild for it
|
|
89
|
+
* whole-manifest rebuild for it (as this hint used to, unconditionally) puts
|
|
90
90
|
* an operator one keystroke from rewriting every row in the manifest to
|
|
91
91
|
* correct one list.
|
|
92
92
|
*/
|
|
@@ -103,7 +103,7 @@ export function recommendManifestRepair(issues) {
|
|
|
103
103
|
/**
|
|
104
104
|
* Rebuilds patches.json from the patch files currently present on disk.
|
|
105
105
|
*
|
|
106
|
-
* This is a
|
|
106
|
+
* This is a merge, not a from-scratch rebuild: only `filesAffected` and
|
|
107
107
|
* `order` are recomputed from the patch files, and every other field on an
|
|
108
108
|
* existing entry is carried forward untouched. Entries with no pre-existing
|
|
109
109
|
* metadata are recovered from filename structure, patch contents, and file
|
|
@@ -116,7 +116,7 @@ export function recommendManifestRepair(issues) {
|
|
|
116
116
|
* @param patchesDir - Path to the patches directory
|
|
117
117
|
* @param fallbackSourceEsrVersion - source version to use for recovered legacy entries
|
|
118
118
|
* @param options - Lock options plus `allowMetadataLoss` / `dryRun`
|
|
119
|
-
* @returns {@link RebuildPatchesManifestResult}
|
|
119
|
+
* @returns {@link RebuildPatchesManifestResult}: the rebuilt manifest, the
|
|
120
120
|
* filenames that were reconstructed from generic defaults, and the rows
|
|
121
121
|
* dropped because their patch file is gone.
|
|
122
122
|
*/
|
|
@@ -125,7 +125,7 @@ export async function rebuildPatchesManifest(patchesDir, fallbackSourceEsrVersio
|
|
|
125
125
|
// patch-directory lock (invariant 2, docs/lifecycle-invariants.md):
|
|
126
126
|
// manifest writes serialize on this lock, so without it a repair racing a
|
|
127
127
|
// concurrent export/reorder can clobber the other writer's manifest. Not
|
|
128
|
-
// reentrant
|
|
128
|
+
// reentrant: callers must not already hold it.
|
|
129
129
|
//
|
|
130
130
|
// A dry run takes the lock too: it reads the same manifest and patch bodies
|
|
131
131
|
// a real run would, and a projection computed against a queue being
|
|
@@ -136,9 +136,9 @@ async function rebuildPatchesManifestUnderLock(patchesDir, fallbackSourceEsrVers
|
|
|
136
136
|
const manifestState = await loadPatchesManifestState(patchesDir);
|
|
137
137
|
const existingEntries = new Map();
|
|
138
138
|
// An unparseable manifest yields `manifest: null`, which the merge below
|
|
139
|
-
// cannot distinguish from "no manifest at all"
|
|
139
|
+
// cannot distinguish from "no manifest at all". Every entry would be
|
|
140
140
|
// treated as new and every descriptive field reinvented. `filesAffected`
|
|
141
|
-
// is the only field a .patch body can yield
|
|
141
|
+
// is the only field a .patch body can yield. `stagedDependencies`,
|
|
142
142
|
// `lintIgnore`, `tier`, `description`, `category`, `createdAt` and the
|
|
143
143
|
// source version cannot be reconstructed from a diff at all. Refuse rather
|
|
144
144
|
// than write that, since the write is what makes it unrecoverable on a
|
|
@@ -187,21 +187,20 @@ async function rebuildPatchesManifestUnderLock(patchesDir, fallbackSourceEsrVers
|
|
|
187
187
|
// callers can warn the operator per-patch. A missing entry means every
|
|
188
188
|
// descriptive field (`description`, `createdAt`, `category`) was
|
|
189
189
|
// invented rather than preserved, and FireForge patch files carry no
|
|
190
|
-
// header metadata that could carry a human description forward
|
|
190
|
+
// header metadata that could carry a human description forward, so
|
|
191
191
|
// visibility is the best available, and silent overwrites of
|
|
192
192
|
// human-written descriptions during a recovery run are the failure to
|
|
193
193
|
// avoid.
|
|
194
194
|
recoveredFilenames.push(patch.filename);
|
|
195
195
|
}
|
|
196
|
-
// The rebuild
|
|
196
|
+
// The rebuild owns exactly two fields: `filesAffected` (recomputed from
|
|
197
197
|
// the patch body) and `order` (from the filename ordinal). Everything
|
|
198
198
|
// else on an existing entry is carried forward by the spread, so a field
|
|
199
|
-
// a .patch cannot express
|
|
200
|
-
// and whatever is added to PatchMetadata next
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
// recurring.
|
|
199
|
+
// a .patch cannot express (`stagedDependencies`, `lintIgnore`, `tier`,
|
|
200
|
+
// and whatever is added to PatchMetadata next) survives a repair without
|
|
201
|
+
// anyone remembering to list it here. It was an enumerated literal until
|
|
202
|
+
// `stagedDependencies` was dropped from every entry that had one, which
|
|
203
|
+
// is the failure this shape prevents from recurring.
|
|
205
204
|
const rebuilt = {
|
|
206
205
|
...(existing ?? {}),
|
|
207
206
|
filename: patch.filename,
|
|
@@ -228,9 +227,9 @@ async function rebuildPatchesManifestUnderLock(patchesDir, fallbackSourceEsrVers
|
|
|
228
227
|
patches: rebuiltPatches,
|
|
229
228
|
};
|
|
230
229
|
// Whatever is left in the map had a manifest row but no patch file, so the
|
|
231
|
-
// rebuild drops it. That is the correct outcome
|
|
232
|
-
// truth
|
|
233
|
-
// never having had them.
|
|
230
|
+
// rebuild drops it. That is the correct outcome, since the file is the
|
|
231
|
+
// source of truth, but dropping rows without naming them is
|
|
232
|
+
// indistinguishable from never having had them.
|
|
234
233
|
const droppedFilenames = [...existingEntries.keys()].sort((left, right) => left.localeCompare(right));
|
|
235
234
|
if (options.dryRun === true) {
|
|
236
235
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
/**
|
|
3
|
-
* Narrow repair for `filesAffected
|
|
3
|
+
* Narrow repair for `filesAffected`, the one manifest field a `.patch` body
|
|
4
4
|
* can actually yield.
|
|
5
5
|
*
|
|
6
6
|
* A `files-affected-mismatch` is pure derived-value drift: the manifest's list
|
|
@@ -47,7 +47,7 @@ async function repairPatchesFilesAffectedUnderLock(patchesDir, filenames, option
|
|
|
47
47
|
const row = rowByFilename.get(filename);
|
|
48
48
|
if (patchPath === undefined || !row) {
|
|
49
49
|
// A missing patch file or a missing row is a different consistency
|
|
50
|
-
// issue with a different remedy
|
|
50
|
+
// issue with a different remedy. This repair reports it rather than
|
|
51
51
|
// inventing a row or deleting one.
|
|
52
52
|
skippedFilenames.push(filename);
|
|
53
53
|
continue;
|
|
@@ -63,7 +63,7 @@ async function repairPatchesFilesAffectedUnderLock(patchesDir, filenames, option
|
|
|
63
63
|
return { repairs, skippedFilenames, written: false };
|
|
64
64
|
}
|
|
65
65
|
const correctedByFilename = new Map(repairs.map((repair) => [repair.filename, repair.after]));
|
|
66
|
-
// Row-scoped mutation, so every untouched entry keeps its exact JSON shape
|
|
66
|
+
// Row-scoped mutation, so every untouched entry keeps its exact JSON shape:
|
|
67
67
|
// no re-sorted `filesAffected` lists and no reader-only fallback fields
|
|
68
68
|
// serialized into rows this repair has no business touching.
|
|
69
69
|
await mutatePatchRowsInManifest(patchesDir, [...correctedByFilename.keys()], (existing) => {
|
|
@@ -39,10 +39,10 @@ export declare function loadPatchesManifestState(patchesDir: string): Promise<Lo
|
|
|
39
39
|
/**
|
|
40
40
|
* Loads the patches manifest if it exists.
|
|
41
41
|
*
|
|
42
|
-
*
|
|
43
|
-
* Any code path that
|
|
44
|
-
* on its content) must use {@link loadPatchesManifestForWrite} instead
|
|
45
|
-
*
|
|
42
|
+
* Read-only callers only: this collapses "absent" and "corrupt" into null.
|
|
43
|
+
* Any code path that writes the manifest (or deletes patch files based
|
|
44
|
+
* on its content) must use {@link loadPatchesManifestForWrite} instead.
|
|
45
|
+
* Treating a corrupt manifest as empty and then saving destroys every
|
|
46
46
|
* existing patch's metadata.
|
|
47
47
|
*
|
|
48
48
|
* @param patchesDir - Path to the patches directory
|
|
@@ -52,7 +52,7 @@ export declare function loadPatchesManifest(patchesDir: string): Promise<Patches
|
|
|
52
52
|
/**
|
|
53
53
|
* Loads the patches manifest for a mutating operation.
|
|
54
54
|
*
|
|
55
|
-
* Returns null only when the manifest genuinely does not exist
|
|
55
|
+
* Returns null only when the manifest genuinely does not exist. A manifest
|
|
56
56
|
* that exists but fails to parse/validate throws
|
|
57
57
|
* {@link PatchManifestCorruptError} so the caller aborts instead of
|
|
58
58
|
* rebuilding an empty queue over the top of the corrupt file.
|
|
@@ -80,11 +80,11 @@ export declare function mutatePatchRowsInManifest(patchesDir: string, filenames:
|
|
|
80
80
|
export declare function addPatchToManifest(patchesDir: string, metadata: PatchMetadata, removeFilenames?: string[]): Promise<void>;
|
|
81
81
|
/**
|
|
82
82
|
* Removes a single patch entry from the manifest by filename. Leaves the
|
|
83
|
-
* ordinal gap in place
|
|
83
|
+
* ordinal gap in place. Callers wanting to close the gap must use
|
|
84
84
|
* {@link renumberPatchesInManifest} explicitly. This matches the spec: delete
|
|
85
85
|
* is a row removal, not a resequencing.
|
|
86
86
|
*
|
|
87
|
-
* Not atomic with any on-disk patch file deletion
|
|
87
|
+
* Not atomic with any on-disk patch file deletion. Callers are expected to
|
|
88
88
|
* remove the .patch file separately under the same lock.
|
|
89
89
|
*
|
|
90
90
|
* @param patchesDir - Path to the patches directory
|
|
@@ -99,7 +99,7 @@ export declare function removePatchFromManifest(patchesDir: string, filename: st
|
|
|
99
99
|
export interface PatchRenameEntry {
|
|
100
100
|
/** New filename (e.g. `005-ui-sidebar.patch`). */
|
|
101
101
|
newFilename: string;
|
|
102
|
-
/** New numeric order
|
|
102
|
+
/** New numeric order. Must match the prefix of `newFilename`. */
|
|
103
103
|
newOrder: number;
|
|
104
104
|
}
|
|
105
105
|
/**
|
|
@@ -129,7 +129,7 @@ export declare function rewriteStagedDependencyOwners(patch: PatchMetadata, rena
|
|
|
129
129
|
* orders. Failure semantics:
|
|
130
130
|
*
|
|
131
131
|
* - **Phase 1 (stage)**: rolls back by renaming staged files back to
|
|
132
|
-
* their originals. Manifest is untouched. Best-effort
|
|
132
|
+
* their originals. Manifest is untouched. Best-effort: a rollback
|
|
133
133
|
* rename failure is warned but not re-thrown.
|
|
134
134
|
* - **Phase 2 (stage → final)**: rolls back to the pre-operation state
|
|
135
135
|
* by reversing every partial step: files already at their final
|
|
@@ -138,13 +138,13 @@ export declare function rewriteStagedDependencyOwners(patch: PatchMetadata, rena
|
|
|
138
138
|
* the rollback itself fails midway, the thrown error is augmented
|
|
139
139
|
* with a description of the residue so the operator can inspect.
|
|
140
140
|
* - **Phase 3 (manifest write)**: by this point all files are on disk
|
|
141
|
-
* at their new names
|
|
141
|
+
* at their new names. A manifest write failure will roll the files
|
|
142
142
|
* back to their original names before re-throwing so the directory
|
|
143
143
|
* and manifest stay in agreement. A rollback failure at this stage
|
|
144
144
|
* is warned (manifest was never mutated) and the original error is
|
|
145
145
|
* re-thrown.
|
|
146
146
|
*
|
|
147
|
-
* Does not sort the rename map for the caller
|
|
147
|
+
* Does not sort the rename map for the caller. The map is the authoritative
|
|
148
148
|
* plan. Entries not present in the map keep their existing filename and
|
|
149
149
|
* order.
|
|
150
150
|
*
|
|
@@ -154,7 +154,7 @@ export declare function rewriteStagedDependencyOwners(patch: PatchMetadata, rena
|
|
|
154
154
|
export declare function renumberPatchesInManifest(patchesDir: string, renameMap: Map<string, PatchRenameEntry>): Promise<void>;
|
|
155
155
|
/**
|
|
156
156
|
* Thrown when {@link removePatchFileAndManifest} cannot complete the file
|
|
157
|
-
* delete
|
|
157
|
+
* delete and cannot restore the manifest row afterward, so the on-disk
|
|
158
158
|
* state and manifest state are known to disagree. Carries both the
|
|
159
159
|
* primary delete error and the rollback error so the caller (and the
|
|
160
160
|
* operator) can see the full failure chain instead of only the original
|
|
@@ -162,7 +162,7 @@ export declare function renumberPatchesInManifest(patchesDir: string, renameMap:
|
|
|
162
162
|
*
|
|
163
163
|
* Extends {@link FireForgeError} so the CLI top-level handler routes it
|
|
164
164
|
* through the rich-error formatter rather than the generic unexpected-error
|
|
165
|
-
* path
|
|
165
|
+
* path. The dedicated `.name` is kept so programmatic callers and tests
|
|
166
166
|
* can still distinguish it with `instanceof PatchDeleteRollbackError`.
|
|
167
167
|
*/
|
|
168
168
|
export declare class PatchDeleteRollbackError extends FireForgeError {
|
|
@@ -174,7 +174,7 @@ export declare class PatchDeleteRollbackError extends FireForgeError {
|
|
|
174
174
|
}
|
|
175
175
|
/**
|
|
176
176
|
* Deletes both a patch file on disk and its manifest row under the caller's
|
|
177
|
-
* lock. This is a convenience for the `patch delete` command
|
|
177
|
+
* lock. This is a convenience for the `patch delete` command. Callers that
|
|
178
178
|
* need different ordering (e.g. deleting the file first without touching the
|
|
179
179
|
* manifest) should call the primitives separately.
|
|
180
180
|
*
|
|
@@ -50,10 +50,10 @@ export async function loadPatchesManifestState(patchesDir) {
|
|
|
50
50
|
/**
|
|
51
51
|
* Loads the patches manifest if it exists.
|
|
52
52
|
*
|
|
53
|
-
*
|
|
54
|
-
* Any code path that
|
|
55
|
-
* on its content) must use {@link loadPatchesManifestForWrite} instead
|
|
56
|
-
*
|
|
53
|
+
* Read-only callers only: this collapses "absent" and "corrupt" into null.
|
|
54
|
+
* Any code path that writes the manifest (or deletes patch files based
|
|
55
|
+
* on its content) must use {@link loadPatchesManifestForWrite} instead.
|
|
56
|
+
* Treating a corrupt manifest as empty and then saving destroys every
|
|
57
57
|
* existing patch's metadata.
|
|
58
58
|
*
|
|
59
59
|
* @param patchesDir - Path to the patches directory
|
|
@@ -66,7 +66,7 @@ export async function loadPatchesManifest(patchesDir) {
|
|
|
66
66
|
/**
|
|
67
67
|
* Loads the patches manifest for a mutating operation.
|
|
68
68
|
*
|
|
69
|
-
* Returns null only when the manifest genuinely does not exist
|
|
69
|
+
* Returns null only when the manifest genuinely does not exist. A manifest
|
|
70
70
|
* that exists but fails to parse/validate throws
|
|
71
71
|
* {@link PatchManifestCorruptError} so the caller aborts instead of
|
|
72
72
|
* rebuilding an empty queue over the top of the corrupt file.
|
|
@@ -98,17 +98,18 @@ export async function mutatePatchRowsInManifest(patchesDir, filenames, mutator)
|
|
|
98
98
|
if (!(await pathExistsStrict(manifestPath)))
|
|
99
99
|
return null;
|
|
100
100
|
const rawManifest = await readJson(manifestPath);
|
|
101
|
+
// `validatePatchesManifest` has already rejected a manifest that is not an
|
|
102
|
+
// object with an array of object rows (it throws the corruption error the
|
|
103
|
+
// caller expects), so the shape re-checks below are FireForge's own
|
|
104
|
+
// invariants, not input validation: failing them means the validator and
|
|
105
|
+
// this walker disagree about the manifest schema, which is a bug here.
|
|
101
106
|
const beforeManifest = validatePatchesManifest(rawManifest);
|
|
102
|
-
|
|
103
|
-
throw new Error('patches.json must be a JSON object with a patches array');
|
|
104
|
-
}
|
|
107
|
+
assert(isObject(rawManifest) && isArray(rawManifest['patches']), 'validated patches.json is a JSON object with a patches array');
|
|
105
108
|
const filenameSet = new Set(filenames);
|
|
106
109
|
if (filenameSet.size === 0)
|
|
107
110
|
return [];
|
|
108
|
-
const rawPatches = rawManifest['patches'].map((entry) => {
|
|
109
|
-
|
|
110
|
-
throw new Error('patches.json patches entries must be objects');
|
|
111
|
-
}
|
|
111
|
+
const rawPatches = rawManifest['patches'].map((entry, index) => {
|
|
112
|
+
assert(isObject(entry), () => `validated patches.json row ${index} is an object`);
|
|
112
113
|
return { ...entry };
|
|
113
114
|
});
|
|
114
115
|
const changedIndexes = [];
|
|
@@ -174,11 +175,11 @@ export async function addPatchToManifest(patchesDir, metadata, removeFilenames)
|
|
|
174
175
|
}
|
|
175
176
|
/**
|
|
176
177
|
* Removes a single patch entry from the manifest by filename. Leaves the
|
|
177
|
-
* ordinal gap in place
|
|
178
|
+
* ordinal gap in place. Callers wanting to close the gap must use
|
|
178
179
|
* {@link renumberPatchesInManifest} explicitly. This matches the spec: delete
|
|
179
180
|
* is a row removal, not a resequencing.
|
|
180
181
|
*
|
|
181
|
-
* Not atomic with any on-disk patch file deletion
|
|
182
|
+
* Not atomic with any on-disk patch file deletion. Callers are expected to
|
|
182
183
|
* remove the .patch file separately under the same lock.
|
|
183
184
|
*
|
|
184
185
|
* @param patchesDir - Path to the patches directory
|
|
@@ -209,7 +210,7 @@ export async function removePatchFromManifest(patchesDir, filename) {
|
|
|
209
210
|
* sorted ascending (readers take manifest order as apply order without
|
|
210
211
|
* re-sorting).
|
|
211
212
|
*
|
|
212
|
-
* Contiguity itself is
|
|
213
|
+
* Contiguity itself is not checked, on purpose: `patchPolicy.ranges`
|
|
213
214
|
* reserves gaps on purpose, so a hole is a legitimate queue shape.
|
|
214
215
|
*
|
|
215
216
|
* @param patches - The manifest rows about to be written
|
|
@@ -287,7 +288,7 @@ export function rewriteStagedDependencyOwners(patch, renameLookup) {
|
|
|
287
288
|
* orders. Failure semantics:
|
|
288
289
|
*
|
|
289
290
|
* - **Phase 1 (stage)**: rolls back by renaming staged files back to
|
|
290
|
-
* their originals. Manifest is untouched. Best-effort
|
|
291
|
+
* their originals. Manifest is untouched. Best-effort: a rollback
|
|
291
292
|
* rename failure is warned but not re-thrown.
|
|
292
293
|
* - **Phase 2 (stage → final)**: rolls back to the pre-operation state
|
|
293
294
|
* by reversing every partial step: files already at their final
|
|
@@ -296,13 +297,13 @@ export function rewriteStagedDependencyOwners(patch, renameLookup) {
|
|
|
296
297
|
* the rollback itself fails midway, the thrown error is augmented
|
|
297
298
|
* with a description of the residue so the operator can inspect.
|
|
298
299
|
* - **Phase 3 (manifest write)**: by this point all files are on disk
|
|
299
|
-
* at their new names
|
|
300
|
+
* at their new names. A manifest write failure will roll the files
|
|
300
301
|
* back to their original names before re-throwing so the directory
|
|
301
302
|
* and manifest stay in agreement. A rollback failure at this stage
|
|
302
303
|
* is warned (manifest was never mutated) and the original error is
|
|
303
304
|
* re-thrown.
|
|
304
305
|
*
|
|
305
|
-
* Does not sort the rename map for the caller
|
|
306
|
+
* Does not sort the rename map for the caller. The map is the authoritative
|
|
306
307
|
* plan. Entries not present in the map keep their existing filename and
|
|
307
308
|
* order.
|
|
308
309
|
*
|
|
@@ -359,7 +360,7 @@ export async function renumberPatchesInManifest(patchesDir, renameMap) {
|
|
|
359
360
|
await rename(join(patchesDir, staged), targetPath);
|
|
360
361
|
// Postcondition assert: confirm the target actually exists on disk
|
|
361
362
|
// before marking the rename complete. A silent rename failure leaves
|
|
362
|
-
// the manifest and the filesystem disagreeing
|
|
363
|
+
// the manifest and the filesystem disagreeing: manifest rewritten to
|
|
363
364
|
// new filenames while the old files stay on disk. If the assert fires,
|
|
364
365
|
// the Phase 2 rollback undoes prior moves before re-throwing.
|
|
365
366
|
if (!(await pathExistsStrict(targetPath))) {
|
|
@@ -369,7 +370,7 @@ export async function renumberPatchesInManifest(patchesDir, renameMap) {
|
|
|
369
370
|
}
|
|
370
371
|
}
|
|
371
372
|
catch (error) {
|
|
372
|
-
// Phase 2 rollback
|
|
373
|
+
// Phase 2 rollback: reverse both the partial final-name moves and
|
|
373
374
|
// the phase-1 staging. This collapses the directory back to its
|
|
374
375
|
// pre-operation filenames so the manifest (which was never
|
|
375
376
|
// touched) remains consistent with what is on disk. If any
|
|
@@ -403,7 +404,7 @@ export async function renumberPatchesInManifest(patchesDir, renameMap) {
|
|
|
403
404
|
throw error;
|
|
404
405
|
}
|
|
405
406
|
// Phase 3: rewrite the manifest rows. Any entry without a rename keeps its
|
|
406
|
-
// existing metadata
|
|
407
|
+
// existing metadata. Entries in the map get their filename + order
|
|
407
408
|
// updated. Sort by the new order so the manifest remains ordered.
|
|
408
409
|
const filenameUpdates = new Map();
|
|
409
410
|
for (const [oldFilename, entry] of renameMap) {
|
|
@@ -427,13 +428,13 @@ export async function renumberPatchesInManifest(patchesDir, renameMap) {
|
|
|
427
428
|
try {
|
|
428
429
|
// Phase 3 is the one write that makes the renumber visible. Every file
|
|
429
430
|
// has already moved on disk, so a manifest that disagrees with the new
|
|
430
|
-
// filenames is the worst outcome available here
|
|
431
|
-
// in an order nothing on disk reflects. The callers compute
|
|
432
|
-
// map (compact, reorder, export placement) and each maintains
|
|
433
|
-
// on its own
|
|
434
|
-
// at the single point where it becomes durable. Inside the
|
|
435
|
-
// violation unwinds through the Phase 3 rollback that puts the
|
|
436
|
-
// back.
|
|
431
|
+
// filenames is the worst outcome available here, because the queue
|
|
432
|
+
// would apply in an order nothing on disk reflects. The callers compute
|
|
433
|
+
// the rename map (compact, reorder, export placement) and each maintains
|
|
434
|
+
// contiguity on its own. This checks the property they are all supposed
|
|
435
|
+
// to produce, at the single point where it becomes durable. Inside the
|
|
436
|
+
// try, so a violation unwinds through the Phase 3 rollback that puts the
|
|
437
|
+
// filenames back.
|
|
437
438
|
assertRenumberedOrderIsWellFormed(updatedPatches);
|
|
438
439
|
await savePatchesManifest(patchesDir, {
|
|
439
440
|
...manifest,
|
|
@@ -444,7 +445,7 @@ export async function renumberPatchesInManifest(patchesDir, renameMap) {
|
|
|
444
445
|
// Phase 3 rollback: reverse every completed rename. The manifest
|
|
445
446
|
// save failed before it could be persisted, so the on-disk state
|
|
446
447
|
// must match what the manifest still records. Best-effort: any
|
|
447
|
-
// individual step that fails gets warned
|
|
448
|
+
// individual step that fails gets warned. The original save
|
|
448
449
|
// error is always re-thrown so the caller sees the real cause.
|
|
449
450
|
for (const completed of completedFinalRenames) {
|
|
450
451
|
try {
|
|
@@ -459,7 +460,7 @@ export async function renumberPatchesInManifest(patchesDir, renameMap) {
|
|
|
459
460
|
}
|
|
460
461
|
/**
|
|
461
462
|
* Thrown when {@link removePatchFileAndManifest} cannot complete the file
|
|
462
|
-
* delete
|
|
463
|
+
* delete and cannot restore the manifest row afterward, so the on-disk
|
|
463
464
|
* state and manifest state are known to disagree. Carries both the
|
|
464
465
|
* primary delete error and the rollback error so the caller (and the
|
|
465
466
|
* operator) can see the full failure chain instead of only the original
|
|
@@ -467,7 +468,7 @@ export async function renumberPatchesInManifest(patchesDir, renameMap) {
|
|
|
467
468
|
*
|
|
468
469
|
* Extends {@link FireForgeError} so the CLI top-level handler routes it
|
|
469
470
|
* through the rich-error formatter rather than the generic unexpected-error
|
|
470
|
-
* path
|
|
471
|
+
* path. The dedicated `.name` is kept so programmatic callers and tests
|
|
471
472
|
* can still distinguish it with `instanceof PatchDeleteRollbackError`.
|
|
472
473
|
*/
|
|
473
474
|
export class PatchDeleteRollbackError extends FireForgeError {
|
|
@@ -489,7 +490,7 @@ export class PatchDeleteRollbackError extends FireForgeError {
|
|
|
489
490
|
}
|
|
490
491
|
/**
|
|
491
492
|
* Deletes both a patch file on disk and its manifest row under the caller's
|
|
492
|
-
* lock. This is a convenience for the `patch delete` command
|
|
493
|
+
* lock. This is a convenience for the `patch delete` command. Callers that
|
|
493
494
|
* need different ordering (e.g. deleting the file first without touching the
|
|
494
495
|
* manifest) should call the primitives separately.
|
|
495
496
|
*
|
|
@@ -507,8 +508,8 @@ export class PatchDeleteRollbackError extends FireForgeError {
|
|
|
507
508
|
export async function removePatchFileAndManifest(patchesDir, filename) {
|
|
508
509
|
await assertPatchDirectoryLockHeld(patchesDir, 'deleting a patch and its manifest row');
|
|
509
510
|
const patchPath = join(patchesDir, filename);
|
|
510
|
-
// ForWrite: deleting the patch
|
|
511
|
-
// references it would strand the queue
|
|
511
|
+
// ForWrite: deleting the patch file while a corrupt manifest still
|
|
512
|
+
// references it would strand the queue. Abort on corruption instead.
|
|
512
513
|
const originalManifest = await loadPatchesManifestForWrite(patchesDir);
|
|
513
514
|
const removedFromManifest = await removePatchFromManifest(patchesDir, filename);
|
|
514
515
|
try {
|
|
@@ -45,7 +45,7 @@ export declare function validatePatchIntegrity(patchesDir: string, engineDir: st
|
|
|
45
45
|
*
|
|
46
46
|
* Acquires the shared patch-directory lock for the read-modify-write, so a
|
|
47
47
|
* concurrent export/reorder/metadata update cannot interleave with the stamp.
|
|
48
|
-
* The lock is not reentrant
|
|
48
|
+
* The lock is not reentrant: callers must not invoke this while already
|
|
49
49
|
* holding {@link withPatchDirectoryLock} on the same patches directory.
|
|
50
50
|
*
|
|
51
51
|
* @param patchesDir - Path to the patches directory
|
|
@@ -80,9 +80,9 @@ export async function validatePatchIntegrity(patchesDir, engineDir) {
|
|
|
80
80
|
const issues = [];
|
|
81
81
|
const patches = await discoverPatches(patchesDir);
|
|
82
82
|
// Collect every modification target first, then resolve HEAD existence in
|
|
83
|
-
//
|
|
83
|
+
// one batched ls-tree pass (chunked for ARG_MAX). The per-file
|
|
84
84
|
// fileExistsInHead fan-out spawned one git process per (patch × target) on
|
|
85
|
-
// every import
|
|
85
|
+
// every import: a 56-file branding patch alone cost ~56 spawns before a
|
|
86
86
|
// single patch was applied.
|
|
87
87
|
const modificationTargets = [];
|
|
88
88
|
for (const patch of patches) {
|
|
@@ -90,7 +90,7 @@ export async function validatePatchIntegrity(patchesDir, engineDir) {
|
|
|
90
90
|
const patchContent = await readText(patch.path);
|
|
91
91
|
const targetFiles = await getAllTargetFilesFromPatch(patch.path);
|
|
92
92
|
for (const targetFile of targetFiles) {
|
|
93
|
-
// Skip new-file sections
|
|
93
|
+
// Skip new-file sections. They don't need to exist in HEAD
|
|
94
94
|
if (isNewFileInPatch(patchContent, targetFile))
|
|
95
95
|
continue;
|
|
96
96
|
modificationTargets.push({ filename: patch.filename, targetFile });
|
|
@@ -114,7 +114,7 @@ export async function validatePatchIntegrity(patchesDir, engineDir) {
|
|
|
114
114
|
*
|
|
115
115
|
* Acquires the shared patch-directory lock for the read-modify-write, so a
|
|
116
116
|
* concurrent export/reorder/metadata update cannot interleave with the stamp.
|
|
117
|
-
* The lock is not reentrant
|
|
117
|
+
* The lock is not reentrant: callers must not invoke this while already
|
|
118
118
|
* holding {@link withPatchDirectoryLock} on the same patches directory.
|
|
119
119
|
*
|
|
120
120
|
* @param patchesDir - Path to the patches directory
|
|
@@ -2,12 +2,12 @@ import type { PatchMetadata } from '../types/commands/index.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Resolves a patch identifier to its manifest entry. Accepts:
|
|
4
4
|
*
|
|
5
|
-
* 1. An ordinal number (e.g. `2`)
|
|
6
|
-
* 2. A full filename with `.patch` suffix (e.g. `002-ui-foo.patch`)
|
|
7
|
-
*
|
|
8
|
-
* 3. A filename without the `.patch` suffix
|
|
5
|
+
* 1. An ordinal number (e.g. `2`), matching `PatchMetadata.order`.
|
|
6
|
+
* 2. A full filename with `.patch` suffix (e.g. `002-ui-foo.patch`),
|
|
7
|
+
* matching `PatchMetadata.filename`.
|
|
8
|
+
* 3. A filename without the `.patch` suffix. The command appends it
|
|
9
9
|
* before matching (e.g. `002-ui-foo`).
|
|
10
|
-
* 4. The manifest `name` field (e.g. `furnace-token-override`)
|
|
10
|
+
* 4. The manifest `name` field (e.g. `furnace-token-override`), the short
|
|
11
11
|
* logical handle the export workflow stamps onto the patch and the
|
|
12
12
|
* natural identifier an operator keeps in their notes. The CLI help
|
|
13
13
|
* says `<name>`, so rejecting it forces the operator to copy the full
|