@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
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { InconclusiveVerdictError } from '../errors/base.js';
|
|
4
4
|
import { toError } from '../utils/errors.js';
|
|
5
5
|
import { info, warn } from '../utils/logger.js';
|
|
6
|
+
import { sleep } from '../utils/sleep.js';
|
|
6
7
|
import { readLockStatus, withFileLock } from './file-lock.js';
|
|
7
8
|
import { git } from './git-base.js';
|
|
8
9
|
const ENGINE_SESSION_LOCK_PATH = join('.fireforge', 'engine-session.lock');
|
|
@@ -17,38 +18,38 @@ const MAX_WAIT_LOCK_MS = 3600 * 1000;
|
|
|
17
18
|
/**
|
|
18
19
|
* Formats the periodic operator-facing waiting line printed while `--wait-lock`
|
|
19
20
|
* polls a contended engine session lock. The holder identification comes from
|
|
20
|
-
* the lock's owner-metadata lines (`command=…`, `started=…`)
|
|
21
|
+
* the lock's owner-metadata lines (`command=…`, `started=…`). An unreadable
|
|
21
22
|
* owner file degrades to the anonymous form.
|
|
22
23
|
*/
|
|
23
24
|
function formatWaitProgressLine(waitedMs, timeoutMs, holder, queue) {
|
|
24
|
-
const progress = `${
|
|
25
|
+
const progress = `${Math.round(waitedMs / 1000)}s of up to ${Math.round(timeoutMs / 1000)}s`;
|
|
25
26
|
// Queue position: under several concurrent sessions the wait
|
|
26
27
|
// line alone left operators inferring their place from `ps`.
|
|
27
28
|
const position = queue === undefined || queue.depth === 0
|
|
28
29
|
? ''
|
|
29
30
|
: queue.ahead === 0
|
|
30
|
-
? ` You are next in a queue of ${
|
|
31
|
-
: ` ${
|
|
31
|
+
? ` You are next in a queue of ${queue.depth}.`
|
|
32
|
+
: ` ${queue.ahead} ahead of you (queue of ${queue.depth}).`;
|
|
32
33
|
if (holder === undefined) {
|
|
33
34
|
return `Waiting for the FireForge engine lock — ${progress}.${position}`;
|
|
34
35
|
}
|
|
35
36
|
const details = holder.metadata.length > 0 ? ` (${holder.metadata.join(', ')})` : '';
|
|
36
|
-
return `Waiting for the FireForge engine lock held by PID ${
|
|
37
|
+
return `Waiting for the FireForge engine lock held by PID ${holder.pid}${details} — ${progress}.${position}`;
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
|
-
* Formats the notice printed when the wait budget is
|
|
40
|
+
* Formats the notice printed when the wait budget is extended because the
|
|
40
41
|
* queue advanced.
|
|
41
42
|
*
|
|
42
|
-
* Exported for direct unit testing. It names both figures
|
|
43
|
-
* budget and the one now in force
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* Exported for direct unit testing. It names both figures, the requested
|
|
44
|
+
* budget and the one now in force, because they have diverged and an
|
|
45
|
+
* operator comparing the elapsed time against the number they typed would
|
|
46
|
+
* otherwise conclude the timeout is broken.
|
|
46
47
|
*/
|
|
47
48
|
export function formatWaitExtendedLine(ahead, budgetMs, requestedMs) {
|
|
48
|
-
const position = ahead === 0 ? 'you are now next' : `${
|
|
49
|
+
const position = ahead === 0 ? 'you are now next' : `${ahead} still ahead of you`;
|
|
49
50
|
return (`The queue advanced (${position}), so the engine-lock wait was extended to ` +
|
|
50
|
-
`${
|
|
51
|
-
`${
|
|
51
|
+
`${Math.round(budgetMs / 1000)}s total (you asked for ` +
|
|
52
|
+
`${Math.round(requestedMs / 1000)}s). A queue that stops moving still ` +
|
|
52
53
|
`gives up on the budget you asked for.`);
|
|
53
54
|
}
|
|
54
55
|
/**
|
|
@@ -56,11 +57,11 @@ export function formatWaitExtendedLine(ahead, budgetMs, requestedMs) {
|
|
|
56
57
|
* one engine-mutating FireForge command touches `engine/` at a time.
|
|
57
58
|
*/
|
|
58
59
|
export async function withEngineSessionLock(projectRoot, command, operation, options = {}) {
|
|
59
|
-
// The lock is bypassed under test by default,
|
|
60
|
+
// The lock is bypassed under test by default, on purpose: the
|
|
60
61
|
// suite runs many engine-mutating commands in-process, which would either
|
|
61
62
|
// serialise on this lock or deadlock outright.
|
|
62
63
|
// `FIREFORGE_ENABLE_ENGINE_SESSION_LOCK_IN_TEST=1` lets the lock's own
|
|
63
|
-
// tests opt back in. Do not delete this branch
|
|
64
|
+
// tests opt back in. Do not delete this branch. It is the reason the
|
|
64
65
|
// suite completes.
|
|
65
66
|
if (process.env['FIREFORGE_ENABLE_ENGINE_SESSION_LOCK_IN_TEST'] !== '1' &&
|
|
66
67
|
(process.env['NODE_ENV'] === 'test' || process.env['VITEST'] !== undefined)) {
|
|
@@ -77,30 +78,30 @@ export async function withEngineSessionLock(projectRoot, command, operation, opt
|
|
|
77
78
|
onWaitProgress: ({ waitedMs, timeoutMs, holder, queue }) => {
|
|
78
79
|
info(formatWaitProgressLine(waitedMs, timeoutMs, holder, queue));
|
|
79
80
|
},
|
|
80
|
-
//
|
|
81
|
+
// Announce it. An extension is the moment the budget the
|
|
81
82
|
// operator asked for stops being the budget in force, and a wait
|
|
82
83
|
// that silently outlives its own stated timeout is
|
|
83
|
-
// indistinguishable from a broken one
|
|
84
|
+
// indistinguishable from a broken one, which is how a downstream
|
|
84
85
|
// fork read it.
|
|
85
86
|
onWaitExtended: ({ ahead, budgetMs }) => {
|
|
86
87
|
info(formatWaitExtendedLine(ahead, budgetMs, waitLockSeconds * 1000));
|
|
87
88
|
},
|
|
88
89
|
// A budget that expires one position from the head pays the whole
|
|
89
|
-
// wait for nothing. While the queue is still
|
|
90
|
-
// working, so each advance renews the budget
|
|
91
|
-
// ceiling
|
|
92
|
-
// no-flag fail-fast path
|
|
90
|
+
// wait for nothing. While the queue is still moving the wait is
|
|
91
|
+
// working, so each advance renews the budget, up to a hard
|
|
92
|
+
// ceiling so a pathological queue cannot wait forever. The
|
|
93
|
+
// no-flag fail-fast path gets none of this.
|
|
93
94
|
extendWhileAdvancing: {
|
|
94
95
|
maxWaitMs: Math.min(waitLockSeconds * 1000 * WAIT_EXTENSION_FACTOR, MAX_WAIT_LOCK_MS),
|
|
95
96
|
},
|
|
96
97
|
}
|
|
97
98
|
: {}),
|
|
98
99
|
ownerMetadata: [`command=${command}`, `started=${new Date().toISOString()}`],
|
|
99
|
-
// Reason first, remedy second
|
|
100
|
+
// Reason first, remedy second: the no-flag default waits
|
|
100
101
|
// only ~1 s, so contention is the common case and `--wait-lock` is the
|
|
101
102
|
// genuine remedy. withFileLock appends the holder identification from
|
|
102
103
|
// the lock's owner metadata. The leading sentence is a message contract
|
|
103
|
-
// (pinned by engine-session-lock tests)
|
|
104
|
+
// (pinned by engine-session-lock tests). Extend, don't reword.
|
|
104
105
|
onTimeoutMessage: `Another FireForge engine-mutating command is already running. ` +
|
|
105
106
|
`Wait for it to finish, then retry \`${command}\` — or pass --wait-lock [seconds] ` +
|
|
106
107
|
`to wait for the lock (bare --wait-lock waits up to 60 seconds). ` +
|
|
@@ -109,8 +110,8 @@ export async function withEngineSessionLock(projectRoot, command, operation, opt
|
|
|
109
110
|
});
|
|
110
111
|
}
|
|
111
112
|
/**
|
|
112
|
-
* Inspects the project's engine-session lock without acquiring it
|
|
113
|
-
*
|
|
113
|
+
* Inspects the project's engine-session lock without acquiring it, backing
|
|
114
|
+
* `fireforge status --lock`.
|
|
114
115
|
*
|
|
115
116
|
* @param projectRoot - Project root containing `.fireforge/`
|
|
116
117
|
* @returns Holder identity, hold duration, and queue depth
|
|
@@ -128,21 +129,21 @@ export function formatEngineSessionLockStatus(snapshot, holderCpuSeconds) {
|
|
|
128
129
|
}
|
|
129
130
|
const elapsed = snapshot.heldForMs === undefined
|
|
130
131
|
? 'unknown duration'
|
|
131
|
-
: `${
|
|
132
|
+
: `${Math.round(snapshot.heldForMs / 1000)}s`;
|
|
132
133
|
const holder = snapshot.holder;
|
|
133
134
|
const identity = holder === undefined
|
|
134
135
|
? 'held by an unidentified process (no readable owner record)'
|
|
135
|
-
: `held by PID ${
|
|
136
|
+
: `held by PID ${holder.pid}${holder.alive ? '' : ' (NOT RUNNING — stale lock)'}` +
|
|
136
137
|
(holder.metadata.length > 0 ? ` (${holder.metadata.join(', ')})` : '');
|
|
137
138
|
const lines = [
|
|
138
139
|
`Engine session lock: ${identity}, for ${elapsed}.`,
|
|
139
|
-
`Queue depth: ${
|
|
140
|
+
`Queue depth: ${snapshot.queueDepth} waiter(s).`,
|
|
140
141
|
];
|
|
141
|
-
// Liveness answers "does the process exist"
|
|
142
|
+
// Liveness answers "does the process exist". It does not answer "is it
|
|
142
143
|
// getting anywhere". A holder alive for minutes having used a fraction of
|
|
143
144
|
// a second of CPU is the shape of a wedged command, and every waiter
|
|
144
145
|
// behind it inherits the stall. Stated as an observation with its own
|
|
145
|
-
// caveat
|
|
146
|
+
// caveat: a holder blocked on I/O is also idle, and this must not be read
|
|
146
147
|
// as licence to kill anything.
|
|
147
148
|
if (holder?.alive === true && holderCpuSeconds !== undefined) {
|
|
148
149
|
const cpu = `${holderCpuSeconds.toFixed(1)}s`;
|
|
@@ -174,15 +175,15 @@ export async function snapshotEngineGeneration(engineDir) {
|
|
|
174
175
|
}
|
|
175
176
|
catch (error) {
|
|
176
177
|
lastError = error;
|
|
177
|
-
// A contended `.git/index.lock` is
|
|
178
|
+
// A contended `.git/index.lock` is transient, not a state: some other
|
|
178
179
|
// writer held the index for the instant we looked. Treating it as
|
|
179
180
|
// "unmeasurable" turns a perfectly good suite into
|
|
180
181
|
// `FAIL reason=inconclusive` on a one-sided probe failure. Anything
|
|
181
|
-
// else
|
|
182
|
+
// else (an unreadable `.git`, a non-git `engine/`) is a real state
|
|
182
183
|
// and is reported immediately.
|
|
183
184
|
if (!isIndexLockError(error) || attempt === GENERATION_PROBE_ATTEMPTS - 1)
|
|
184
185
|
break;
|
|
185
|
-
await
|
|
186
|
+
await sleep(GENERATION_PROBE_RETRY_MS);
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
189
|
return `${UNAVAILABLE_PREFIX}${toError(lastError).message}`;
|
|
@@ -191,11 +192,6 @@ export async function snapshotEngineGeneration(engineDir) {
|
|
|
191
192
|
const GENERATION_PROBE_ATTEMPTS = 3;
|
|
192
193
|
/** Pause between generation-probe attempts. */
|
|
193
194
|
const GENERATION_PROBE_RETRY_MS = 250;
|
|
194
|
-
function delay(ms) {
|
|
195
|
-
return new Promise((resolveDelay) => {
|
|
196
|
-
setTimeout(resolveDelay, ms);
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
195
|
/**
|
|
200
196
|
* True when a git failure is the transient index-lock contention shape
|
|
201
197
|
* (`Unable to create '…/.git/index.lock': File exists`) rather than a
|
|
@@ -206,7 +202,7 @@ export function isIndexLockError(error) {
|
|
|
206
202
|
return /index\.lock/i.test(message);
|
|
207
203
|
}
|
|
208
204
|
/**
|
|
209
|
-
* True when a generation token records a failed probe
|
|
205
|
+
* True when a generation token records a failed probe, i.e. nothing was
|
|
210
206
|
* measured, so the token must never be compared (or hashed) as if it
|
|
211
207
|
* described the engine's state.
|
|
212
208
|
*/
|
|
@@ -232,9 +228,9 @@ function splitGenerationToken(token) {
|
|
|
232
228
|
/**
|
|
233
229
|
* Parses `git status --porcelain=v1 -z` into `XY path` records.
|
|
234
230
|
*
|
|
235
|
-
* The rename/copy shape
|
|
236
|
-
*
|
|
237
|
-
* one desynchronises every record after it
|
|
231
|
+
* The rename/copy shape needs care: `R`/`C` entries are followed by a
|
|
232
|
+
* second NUL-separated field carrying the original path, and consuming only
|
|
233
|
+
* one desynchronises every record after it, turning a one-file rename into
|
|
238
234
|
* a report that the whole tree moved. Both fields are consumed and the
|
|
239
235
|
* record renders as `orig -> new`.
|
|
240
236
|
*/
|
|
@@ -243,7 +239,7 @@ function parsePorcelainRecords(body) {
|
|
|
243
239
|
const records = [];
|
|
244
240
|
for (let i = 0; i < fields.length; i++) {
|
|
245
241
|
const field = fields[i] ?? '';
|
|
246
|
-
// `XY
|
|
242
|
+
// `XY `, two status characters and a space, then the path.
|
|
247
243
|
if (field.length < 4)
|
|
248
244
|
continue;
|
|
249
245
|
const status = field.slice(0, 2);
|
|
@@ -261,8 +257,8 @@ function parsePorcelainRecords(body) {
|
|
|
261
257
|
/**
|
|
262
258
|
* Describes what moved between two generation tokens, in operator terms.
|
|
263
259
|
*
|
|
264
|
-
* The refusal used to say only
|
|
265
|
-
* operator to reconstruct the writer by hand
|
|
260
|
+
* The refusal used to say only that the engine changed, which left the
|
|
261
|
+
* operator to reconstruct the writer by hand: `find -newermt` against the
|
|
266
262
|
* run window, minus the objdir, minus git's own bookkeeping. Everything
|
|
267
263
|
* needed to answer it is already in the two tokens, so the refusal answers
|
|
268
264
|
* it. Pure and total: an unparseable token yields an empty list rather than
|
|
@@ -271,7 +267,7 @@ function parsePorcelainRecords(body) {
|
|
|
271
267
|
*
|
|
272
268
|
* @param before - Token captured before the run
|
|
273
269
|
* @param after - Token captured after the run
|
|
274
|
-
* @returns Human-readable lines describing the delta
|
|
270
|
+
* @returns Human-readable lines describing the delta. Empty when nothing
|
|
275
271
|
* could be attributed
|
|
276
272
|
*/
|
|
277
273
|
export function describeEngineGenerationDelta(before, after) {
|
|
@@ -290,7 +286,7 @@ export function describeEngineGenerationDelta(before, after) {
|
|
|
290
286
|
return;
|
|
291
287
|
const head = records.slice(0, DELTA_ENTRY_LIMIT);
|
|
292
288
|
const truncated = records.length - head.length;
|
|
293
|
-
lines.push(`${label}: ${head.join(', ')}${truncated > 0 ? `, … (+${
|
|
289
|
+
lines.push(`${label}: ${head.join(', ')}${truncated > 0 ? `, … (+${truncated} more)` : ''}`);
|
|
294
290
|
};
|
|
295
291
|
render('Working-tree entries that appeared', appeared);
|
|
296
292
|
render('Working-tree entries that went away', disappeared);
|
|
@@ -300,25 +296,25 @@ export function describeEngineGenerationDelta(before, after) {
|
|
|
300
296
|
* Throws when the engine's generation token differs from `before`, i.e. the
|
|
301
297
|
* engine was mutated by another writer while a test run was in flight.
|
|
302
298
|
*
|
|
303
|
-
*
|
|
304
|
-
* always a git checkout
|
|
299
|
+
* An unmeasurable engine warns rather than throws. `engine/` is not
|
|
300
|
+
* always a git checkout (`fireforge download` extracts a source tarball),
|
|
305
301
|
* so a failed probe is a legitimate state and must not fail the run.
|
|
306
302
|
*
|
|
307
|
-
*
|
|
303
|
+
* It must also not pass silently. A failure token compared for
|
|
308
304
|
* equality like any other would let a git failure that reproduces across
|
|
309
305
|
* both probes (unreadable `.git`, a permissions problem, a corrupt index)
|
|
310
306
|
* take the `after === before` early return and bless a verdict the guard
|
|
311
|
-
* never verified. Two
|
|
307
|
+
* never verified. Two differing failure messages are worse still: they
|
|
312
308
|
* fall through to the mutation branch and report a spurious
|
|
313
309
|
* "engine/ changed". Hence the prefix comparison rather than a token
|
|
314
|
-
* comparison
|
|
310
|
+
* comparison: the token embeds the error message, and two genuine failures
|
|
315
311
|
* rarely phrase it identically.
|
|
316
312
|
*
|
|
317
|
-
* The tolerance is
|
|
313
|
+
* The tolerance is limited to a probe that failed both times:
|
|
318
314
|
* that is the steady state of a non-git `engine/`, and it warns. A one-sided
|
|
319
315
|
* transition is not that state. An `engine/` that was measurable and then
|
|
320
316
|
* was not means the second probe measured nothing about a checkout that
|
|
321
|
-
* demonstrably had something to measure
|
|
317
|
+
* demonstrably had something to measure. The reverse means there was never a
|
|
322
318
|
* baseline to compare against. Neither verdict can be trusted, so both throw.
|
|
323
319
|
*/
|
|
324
320
|
export async function assertEngineGenerationUnchanged(engineDir, before) {
|
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
* Detects the new-file-plus-moved-code slice shape and names the working
|
|
3
3
|
* sequence through it.
|
|
4
4
|
*
|
|
5
|
-
* A slice that
|
|
5
|
+
* A slice that adds new files and moves lines into them from an existing
|
|
6
6
|
* patch has no path through the two refusal flags:
|
|
7
7
|
*
|
|
8
8
|
* - `re-export --refuse-adjacent-unmanaged` refuses while the new files are
|
|
9
|
-
* still unmanaged
|
|
9
|
+
* still unmanaged, and
|
|
10
10
|
* - exporting the new files as their own patch fails cross-patch lint,
|
|
11
|
-
* because at the projected placement the
|
|
11
|
+
* because at the projected placement the old patch still contains the
|
|
12
12
|
* moved code.
|
|
13
13
|
*
|
|
14
14
|
* Each guard is individually correct. Together they dead-end, and the way out
|
|
15
|
-
* is non-obvious: adopt the new files into the
|
|
15
|
+
* is non-obvious: adopt the new files into the old patch first
|
|
16
16
|
* (`re-export --scan --scan-file`), then split them out into a patch of their
|
|
17
17
|
* own (`patch move-files --create --order N`).
|
|
18
18
|
*
|
|
19
|
-
* This module recognises the shape from evidence FireForge already has
|
|
19
|
+
* This module recognises the shape from evidence FireForge already has (the
|
|
20
20
|
* pending diff's new-file content versus the added lines the existing patches
|
|
21
|
-
* carry
|
|
21
|
+
* carry), so the refusal can name the sequence instead of leaving the
|
|
22
22
|
* operator to derive it.
|
|
23
23
|
*/
|
|
24
24
|
/** One existing patch that already carries lines the new files would add. */
|
|
@@ -37,7 +37,7 @@ export interface MovedCodeQueueEntry {
|
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Finds existing patches that still carry substantive lines the pending
|
|
40
|
-
* diff's
|
|
40
|
+
* diff's new files would add, the fingerprint of code moved out of an
|
|
41
41
|
* existing patch into a new file.
|
|
42
42
|
*
|
|
43
43
|
* Pure. Overlaps are returned strongest-first so the message names the
|
|
@@ -3,23 +3,23 @@
|
|
|
3
3
|
* Detects the new-file-plus-moved-code slice shape and names the working
|
|
4
4
|
* sequence through it.
|
|
5
5
|
*
|
|
6
|
-
* A slice that
|
|
6
|
+
* A slice that adds new files and moves lines into them from an existing
|
|
7
7
|
* patch has no path through the two refusal flags:
|
|
8
8
|
*
|
|
9
9
|
* - `re-export --refuse-adjacent-unmanaged` refuses while the new files are
|
|
10
|
-
* still unmanaged
|
|
10
|
+
* still unmanaged, and
|
|
11
11
|
* - exporting the new files as their own patch fails cross-patch lint,
|
|
12
|
-
* because at the projected placement the
|
|
12
|
+
* because at the projected placement the old patch still contains the
|
|
13
13
|
* moved code.
|
|
14
14
|
*
|
|
15
15
|
* Each guard is individually correct. Together they dead-end, and the way out
|
|
16
|
-
* is non-obvious: adopt the new files into the
|
|
16
|
+
* is non-obvious: adopt the new files into the old patch first
|
|
17
17
|
* (`re-export --scan --scan-file`), then split them out into a patch of their
|
|
18
18
|
* own (`patch move-files --create --order N`).
|
|
19
19
|
*
|
|
20
|
-
* This module recognises the shape from evidence FireForge already has
|
|
20
|
+
* This module recognises the shape from evidence FireForge already has (the
|
|
21
21
|
* pending diff's new-file content versus the added lines the existing patches
|
|
22
|
-
* carry
|
|
22
|
+
* carry), so the refusal can name the sequence instead of leaving the
|
|
23
23
|
* operator to derive it.
|
|
24
24
|
*/
|
|
25
25
|
import { extractAddedLinesPerFile } from './patch-lint-diff.js';
|
|
@@ -42,7 +42,7 @@ function isSubstantiveLine(line) {
|
|
|
42
42
|
const MOVED_CODE_LINE_THRESHOLD = 3;
|
|
43
43
|
/**
|
|
44
44
|
* Finds existing patches that still carry substantive lines the pending
|
|
45
|
-
* diff's
|
|
45
|
+
* diff's new files would add, the fingerprint of code moved out of an
|
|
46
46
|
* existing patch into a new file.
|
|
47
47
|
*
|
|
48
48
|
* Pure. Overlaps are returned strongest-first so the message names the
|
|
@@ -108,20 +108,20 @@ export function formatAdoptThenSplitRemedy(overlaps, newPatchName, insertionOrde
|
|
|
108
108
|
return [];
|
|
109
109
|
const fileArgs = strongest.files.map((file) => `--scan-file ${file}`).join(' ');
|
|
110
110
|
const moveArgs = strongest.files.map((file) => `--file ${file}`).join(' ');
|
|
111
|
-
// `patch move-files --create` takes the new patch's
|
|
111
|
+
// `patch move-files --create` takes the new patch's name, not a
|
|
112
112
|
// filename: strip the order prefix and the `.patch` suffix so the
|
|
113
113
|
// suggested command is copy-pasteable.
|
|
114
114
|
const suggestedName = newPatchName.replace(/^\d+-/, '').replace(/\.patch$/, '');
|
|
115
115
|
return [
|
|
116
116
|
'',
|
|
117
|
-
`This looks like a new-file + moved-code slice: ${
|
|
117
|
+
`This looks like a new-file + moved-code slice: ${strongest.sharedLines} substantive ` +
|
|
118
118
|
`line(s) the new file(s) would add are still carried by ${strongest.sourcePatch}. ` +
|
|
119
119
|
'Exporting them as their own patch cannot pass cross-patch lint while the source patch ' +
|
|
120
120
|
'still owns the same code, and re-exporting cannot adopt them while they are unmanaged — ' +
|
|
121
121
|
'each guard is right, and together they dead-end.',
|
|
122
122
|
'Working sequence (adopt, then split):',
|
|
123
123
|
` 1. fireforge re-export ${strongest.sourcePatch} --scan ${fileArgs}`,
|
|
124
|
-
` 2. fireforge patch move-files ${strongest.sourcePatch} ${suggestedName} --create --order ${
|
|
124
|
+
` 2. fireforge patch move-files ${strongest.sourcePatch} ${suggestedName} --create --order ${insertionOrder} ${moveArgs}`,
|
|
125
125
|
'Step 1 adopts the new files into the patch that already owns the moved lines; step 2 ' +
|
|
126
126
|
'splits them back out as one transaction, so the queue is never in a state where two ' +
|
|
127
127
|
'patches own the same code.',
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filename of a lock directory's owner record, relative to the lock dir.
|
|
3
|
+
*
|
|
4
|
+
* Re-exported by `file-lock.ts` so external readers (`tree-store.ts`) share
|
|
5
|
+
* the constant instead of re-spelling `'pid'`. The file format is
|
|
6
|
+
* documented on {@link readLockOwner}.
|
|
7
|
+
*/
|
|
8
|
+
export declare const LOCK_PID_FILE = "pid";
|
|
9
|
+
/**
|
|
10
|
+
* Owner record read back from a lock directory's PID file.
|
|
11
|
+
*
|
|
12
|
+
* `token` is the per-acquisition UUID written on line 2 of the PID file,
|
|
13
|
+
* `acquiredAtMs` the wall-clock time the record was written (diagnostic),
|
|
14
|
+
* and `startTick` the writer's boot-relative start tick (liveness). Records
|
|
15
|
+
* from releases before a field was introduced parse with it `undefined`.
|
|
16
|
+
* Readers must treat that as "unknown", never as a mismatch.
|
|
17
|
+
*/
|
|
18
|
+
export type LockOwner = {
|
|
19
|
+
present: false;
|
|
20
|
+
} | {
|
|
21
|
+
present: true;
|
|
22
|
+
pid: number;
|
|
23
|
+
token?: string;
|
|
24
|
+
acquiredAtMs?: number;
|
|
25
|
+
startTick?: number;
|
|
26
|
+
metadata: string[];
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Reads the owner PID (line 1), acquisition token (line 2), the mechanical
|
|
30
|
+
* `acquired-at-ms=` / `start-tick=` lines (when present), and diagnostic
|
|
31
|
+
* metadata (the remaining lines 3+) from a lock directory's PID file.
|
|
32
|
+
* Returns `{ present: false }` when the PID file is missing, unreadable, or
|
|
33
|
+
* the PID does not parse as a finite integer (caller falls back to the
|
|
34
|
+
* age-only staleness heuristic).
|
|
35
|
+
*
|
|
36
|
+
* File format note: external readers do `parseInt(content.trim(), 10)`,
|
|
37
|
+
* which parses the leading digits of a multi-line file, so the token and
|
|
38
|
+
* mechanical lines stay compatible.
|
|
39
|
+
*
|
|
40
|
+
* @param lockPath - Lock directory whose owner record to read
|
|
41
|
+
* @returns The parsed owner record, or `{ present: false }`
|
|
42
|
+
*/
|
|
43
|
+
export declare function readLockOwner(lockPath: string): Promise<LockOwner>;
|
|
44
|
+
/**
|
|
45
|
+
* Stamps this process's ownership (PID, per-acquisition token, acquisition
|
|
46
|
+
* time, own start tick, diagnostic metadata) into a lock directory it has
|
|
47
|
+
* just created, and reads the record back to prove it landed.
|
|
48
|
+
*
|
|
49
|
+
* The write is fatal. It used to be best-effort, on the theory that stale
|
|
50
|
+
* recovery would fall back to the age heuristic, but that heuristic reaps
|
|
51
|
+
* any owner-less lock after five minutes, and the build lock legitimately
|
|
52
|
+
* holds for hours. A holder whose record failed to write was therefore
|
|
53
|
+
* reaped mid-build and a second process entered the critical section. On
|
|
54
|
+
* failure the just-created lock directory is removed (nothing else can own
|
|
55
|
+
* it yet) and a {@link GeneralError} names the cause.
|
|
56
|
+
*
|
|
57
|
+
* @param lockPath - Lock directory this process has just `mkdir`'d
|
|
58
|
+
* @param token - Per-acquisition UUID, later checked by release
|
|
59
|
+
* @param ownerMetadata - Extra human-diagnostic lines (see `FileLockOptions.ownerMetadata`)
|
|
60
|
+
* @throws {GeneralError} When the record cannot be written or does not read back as written
|
|
61
|
+
*/
|
|
62
|
+
export declare function writeLockOwner(lockPath: string, token: string, ownerMetadata: readonly string[] | undefined): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Boot-relative start tick of a process, where the platform exposes it
|
|
65
|
+
* cheaply.
|
|
66
|
+
*
|
|
67
|
+
* Linux only: field 22 of `/proc/<pid>/stat`, in USER_HZ since boot.
|
|
68
|
+
* Elsewhere (macOS, Windows) obtaining a start time means spawning
|
|
69
|
+
* `ps`/`wmic` per probe, which is not worth paying on every poll of a
|
|
70
|
+
* contended lock. Those platforms return `undefined` and liveness stays
|
|
71
|
+
* PID-only.
|
|
72
|
+
*
|
|
73
|
+
* Not converted to wall-clock time via `/proc/stat` `btime`, on purpose:
|
|
74
|
+
* on current kernels `btime` is derived from the realtime clock and moves
|
|
75
|
+
* with every clock step, so a wall-clock comparison against a recorded
|
|
76
|
+
* acquisition time misjudges a live holder as a reused PID after NTP steps
|
|
77
|
+
* the clock forward, and reaps a lock that is in use.
|
|
78
|
+
*
|
|
79
|
+
* @param pid - Process to look up
|
|
80
|
+
* @param procRoot - procfs mount, overridable for tests
|
|
81
|
+
* @returns Start tick, or `undefined` when unobtainable
|
|
82
|
+
*/
|
|
83
|
+
export declare function readProcessStartTick(pid: number, procRoot?: string): number | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Whether the process named by a lock's owner record is the same process
|
|
86
|
+
* that acquired the lock, not merely a live process wearing its PID.
|
|
87
|
+
*
|
|
88
|
+
* `isProcessAlive` answers "does this PID exist". After a holder crashes,
|
|
89
|
+
* the kernel may hand its PID to a long-lived daemon, and a PID-only check
|
|
90
|
+
* then honours the dead lock until the waiter's timeout. Where the record
|
|
91
|
+
* carries the writer's start tick and the candidate's own tick is cheaply
|
|
92
|
+
* obtainable (see {@link readProcessStartTick}), the two must be equal: a
|
|
93
|
+
* different tick is a different process. Records without a start tick, and
|
|
94
|
+
* platforms without one, keep the PID-only answer.
|
|
95
|
+
*
|
|
96
|
+
* @param owner - Owner record fields that identify the holder
|
|
97
|
+
* @param procRoot - procfs mount, overridable for tests
|
|
98
|
+
* @returns True when the original holder is still running (or cannot be proven gone)
|
|
99
|
+
*/
|
|
100
|
+
export declare function isLockOwnerAlive(owner: {
|
|
101
|
+
pid: number;
|
|
102
|
+
startTick?: number | undefined;
|
|
103
|
+
}, procRoot?: string): boolean;
|