@hominis/fireforge 0.43.1 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +126 -0
- package/README.md +10 -1
- package/dist/bin/fireforge.d.ts +4 -9
- package/dist/bin/fireforge.js +42 -40
- package/dist/build-info.json +4 -4
- package/dist/src/cli.js +74 -8
- package/dist/src/commands/bootstrap.js +17 -20
- package/dist/src/commands/build.js +25 -32
- package/dist/src/commands/config.js +34 -41
- package/dist/src/commands/discard.js +8 -9
- package/dist/src/commands/doctor-check-core.d.ts +4 -18
- package/dist/src/commands/doctor-check-core.js +8 -35
- package/dist/src/commands/doctor-external-toolchains.js +2 -2
- package/dist/src/commands/doctor-furnace-config-sync.d.ts +18 -0
- package/dist/src/commands/{doctor-furnace-manifest-sync.js → doctor-furnace-config-sync.js} +27 -26
- package/dist/src/commands/doctor-furnace-jar.d.ts +7 -9
- package/dist/src/commands/doctor-furnace-jar.js +7 -9
- package/dist/src/commands/doctor-furnace.js +21 -24
- package/dist/src/commands/doctor-orphaned-harness.d.ts +16 -20
- package/dist/src/commands/doctor-orphaned-harness.js +18 -44
- package/dist/src/commands/doctor-post-rebase-audit.d.ts +2 -0
- package/dist/src/commands/{doctor/post-rebase-audit.js → doctor-post-rebase-audit.js} +3 -3
- package/dist/src/commands/doctor-working-tree.d.ts +10 -12
- package/dist/src/commands/doctor-working-tree.js +11 -18
- package/dist/src/commands/doctor.js +35 -53
- package/dist/src/commands/download.js +32 -48
- package/dist/src/commands/export-all.js +29 -33
- package/dist/src/commands/export-flow.js +6 -6
- package/dist/src/commands/export-placement-conflicts.js +10 -9
- package/dist/src/commands/export-placement-gate.js +5 -5
- package/dist/src/commands/export-shared.d.ts +30 -33
- package/dist/src/commands/export-shared.js +45 -43
- package/dist/src/commands/export.js +21 -27
- package/dist/src/commands/furnace/apply.js +14 -23
- package/dist/src/commands/furnace/chrome-doc-remove.js +14 -21
- package/dist/src/commands/furnace/chrome-doc-templates.d.ts +23 -23
- package/dist/src/commands/furnace/chrome-doc-templates.js +23 -23
- package/dist/src/commands/furnace/chrome-doc-tests.js +26 -29
- package/dist/src/commands/furnace/chrome-doc.d.ts +16 -17
- package/dist/src/commands/furnace/chrome-doc.js +31 -41
- package/dist/src/commands/furnace/create-browser-test.d.ts +4 -4
- package/dist/src/commands/furnace/create-browser-test.js +8 -8
- package/dist/src/commands/furnace/create-mochikit.d.ts +6 -7
- package/dist/src/commands/furnace/create-mochikit.js +8 -9
- package/dist/src/commands/furnace/create-readback.d.ts +12 -13
- package/dist/src/commands/furnace/create-readback.js +12 -13
- package/dist/src/commands/furnace/create-templates.d.ts +22 -28
- package/dist/src/commands/furnace/create-templates.js +35 -30
- package/dist/src/commands/furnace/create-xpcshell.js +2 -2
- package/dist/src/commands/furnace/create.js +33 -23
- package/dist/src/commands/furnace/deploy.js +16 -24
- package/dist/src/commands/furnace/diff.js +9 -9
- package/dist/src/commands/furnace/init.js +33 -36
- package/dist/src/commands/furnace/override.js +23 -25
- package/dist/src/commands/furnace/preview.js +47 -67
- package/dist/src/commands/furnace/refresh.js +12 -16
- package/dist/src/commands/furnace/remove-mutations.d.ts +3 -6
- package/dist/src/commands/furnace/remove-mutations.js +9 -16
- package/dist/src/commands/furnace/remove-state.js +1 -1
- package/dist/src/commands/furnace/remove.js +33 -38
- package/dist/src/commands/furnace/rename-xpcshell.d.ts +8 -11
- package/dist/src/commands/furnace/rename-xpcshell.js +8 -11
- package/dist/src/commands/furnace/rename.js +59 -69
- package/dist/src/commands/furnace/scan.js +19 -33
- package/dist/src/commands/furnace/status.js +12 -9
- package/dist/src/commands/furnace/sync.js +9 -16
- package/dist/src/commands/furnace/validate.js +20 -20
- package/dist/src/commands/import.js +42 -35
- package/dist/src/commands/lint-per-patch.js +15 -10
- package/dist/src/commands/lint-per-run-checkjs.d.ts +13 -13
- package/dist/src/commands/lint-per-run-checkjs.js +13 -13
- package/dist/src/commands/lint-report.js +6 -7
- package/dist/src/commands/lint.d.ts +15 -16
- package/dist/src/commands/lint.js +86 -102
- package/dist/src/commands/package.js +6 -11
- package/dist/src/commands/patch/compact.js +1 -1
- package/dist/src/commands/patch/delete.js +24 -33
- package/dist/src/commands/patch/index.d.ts +5 -6
- package/dist/src/commands/patch/index.js +10 -12
- package/dist/src/commands/patch/lint-ignore.js +14 -13
- package/dist/src/commands/patch/move-files-create.d.ts +6 -6
- package/dist/src/commands/patch/move-files-create.js +8 -8
- package/dist/src/commands/patch/move-files-into.d.ts +6 -6
- package/dist/src/commands/patch/move-files-into.js +8 -8
- package/dist/src/commands/patch/patch-context.d.ts +2 -3
- package/dist/src/commands/patch/patch-context.js +2 -3
- package/dist/src/commands/patch/rename.d.ts +10 -11
- package/dist/src/commands/patch/rename.js +11 -12
- package/dist/src/commands/patch/reorder.js +8 -9
- package/dist/src/commands/patch/split-plan.js +1 -1
- package/dist/src/commands/patch/split.d.ts +8 -10
- package/dist/src/commands/patch/split.js +9 -11
- package/dist/src/commands/patch/staged-dependency-validate.js +8 -8
- package/dist/src/commands/patch/staged-dependency.js +7 -3
- package/dist/src/commands/patch/tier.d.ts +9 -9
- package/dist/src/commands/patch/tier.js +18 -15
- package/dist/src/commands/re-export-adjacent.js +9 -8
- package/dist/src/commands/re-export-bulk-scan.d.ts +9 -9
- package/dist/src/commands/re-export-bulk-scan.js +22 -21
- package/dist/src/commands/re-export-drift.js +10 -10
- package/dist/src/commands/re-export-files.d.ts +6 -7
- package/dist/src/commands/re-export-files.js +34 -44
- package/dist/src/commands/re-export-lint.d.ts +10 -13
- package/dist/src/commands/re-export-lint.js +16 -14
- package/dist/src/commands/re-export-options.d.ts +6 -6
- package/dist/src/commands/re-export-options.js +6 -6
- package/dist/src/commands/re-export-register.d.ts +4 -10
- package/dist/src/commands/re-export-register.js +5 -11
- package/dist/src/commands/re-export-scan.js +1 -1
- package/dist/src/commands/re-export-single.d.ts +3 -3
- package/dist/src/commands/re-export-single.js +33 -25
- package/dist/src/commands/re-export.js +13 -21
- package/dist/src/commands/rebase/abort.js +3 -3
- package/dist/src/commands/rebase/confirm.js +2 -1
- package/dist/src/commands/rebase/continue.d.ts +1 -1
- package/dist/src/commands/rebase/continue.js +14 -9
- package/dist/src/commands/rebase/index.js +11 -11
- package/dist/src/commands/rebase/patch-loop.d.ts +7 -1
- package/dist/src/commands/rebase/patch-loop.js +60 -39
- package/dist/src/commands/rebase/summary.js +1 -1
- package/dist/src/commands/register.js +5 -7
- package/dist/src/commands/reset.js +2 -1
- package/dist/src/commands/resolve.d.ts +16 -13
- package/dist/src/commands/resolve.js +30 -33
- package/dist/src/commands/run.js +33 -35
- package/dist/src/commands/setup-support.js +15 -19
- package/dist/src/commands/setup.js +13 -9
- package/dist/src/commands/status-check.d.ts +6 -6
- package/dist/src/commands/status-json.d.ts +6 -6
- package/dist/src/commands/status-json.js +5 -0
- package/dist/src/commands/status-output.d.ts +5 -5
- package/dist/src/commands/status-output.js +6 -6
- package/dist/src/commands/status-ownership.d.ts +16 -14
- package/dist/src/commands/status-ownership.js +16 -14
- package/dist/src/commands/status.js +42 -34
- package/dist/src/commands/test-build-phase.js +26 -13
- package/dist/src/commands/test-diagnose.js +44 -44
- package/dist/src/commands/test-register.js +1 -0
- package/dist/src/commands/test-run.d.ts +14 -16
- package/dist/src/commands/test-run.js +21 -13
- package/dist/src/commands/test-stale-gate.d.ts +15 -16
- package/dist/src/commands/test-stale-gate.js +15 -16
- package/dist/src/commands/test-verdict.d.ts +20 -3
- package/dist/src/commands/test-verdict.js +30 -0
- package/dist/src/commands/test.js +83 -76
- package/dist/src/commands/token-coverage.js +3 -4
- package/dist/src/commands/token.js +16 -18
- package/dist/src/commands/tree.js +47 -31
- package/dist/src/commands/typecheck.d.ts +10 -12
- package/dist/src/commands/typecheck.js +24 -27
- package/dist/src/commands/verify.js +13 -15
- package/dist/src/commands/watch.js +21 -23
- package/dist/src/commands/wire.js +52 -62
- package/dist/src/core/ast-utils.d.ts +8 -7
- package/dist/src/core/ast-utils.js +8 -7
- package/dist/src/core/branding.d.ts +9 -14
- package/dist/src/core/branding.js +7 -11
- package/dist/src/core/browser-wire.d.ts +1 -1
- package/dist/src/core/browser-wire.js +14 -19
- package/dist/src/core/build-audit-platform.js +25 -33
- package/dist/src/core/build-audit-registration.js +17 -25
- package/dist/src/core/build-audit-resolve.d.ts +15 -17
- package/dist/src/core/build-audit-resolve.js +27 -33
- package/dist/src/core/build-audit-transforms.js +18 -19
- package/dist/src/core/build-audit.js +28 -42
- package/dist/src/core/build-baseline-types.d.ts +29 -35
- package/dist/src/core/build-baseline.d.ts +5 -4
- package/dist/src/core/build-baseline.js +14 -14
- package/dist/src/core/build-overwrite-guard.d.ts +7 -14
- package/dist/src/core/build-overwrite-guard.js +17 -27
- package/dist/src/core/build-prepare.d.ts +2 -2
- package/dist/src/core/build-prepare.js +8 -9
- package/dist/src/core/config-state.js +12 -4
- package/dist/src/core/config-validate.js +8 -5
- package/dist/src/core/config.d.ts +5 -8
- package/dist/src/core/config.js +7 -16
- package/dist/src/core/coverage-extend.d.ts +15 -13
- package/dist/src/core/coverage-extend.js +15 -13
- package/dist/src/core/destructive.d.ts +31 -9
- package/dist/src/core/destructive.js +29 -26
- package/dist/src/core/diff-hunks.js +10 -12
- package/dist/src/core/discard-baseline.d.ts +8 -8
- package/dist/src/core/discard-baseline.js +16 -15
- package/dist/src/core/display-state.d.ts +12 -14
- package/dist/src/core/display-state.js +12 -14
- package/dist/src/core/engine-changes.d.ts +2 -4
- package/dist/src/core/engine-changes.js +2 -4
- package/dist/src/core/engine-precondition.d.ts +28 -13
- package/dist/src/core/engine-precondition.js +25 -10
- package/dist/src/core/engine-session-lock.d.ts +47 -21
- package/dist/src/core/engine-session-lock.js +168 -33
- package/dist/src/core/export-moved-code-shape.d.ts +10 -10
- package/dist/src/core/export-moved-code-shape.js +10 -10
- package/dist/src/core/file-lock.d.ts +62 -5
- package/dist/src/core/file-lock.js +196 -59
- package/dist/src/core/firefox-cache.js +1 -3
- package/dist/src/core/firefox-extract.js +10 -14
- package/dist/src/core/firefox.d.ts +7 -5
- package/dist/src/core/firefox.js +4 -5
- package/dist/src/core/furnace-apply-dry-run.d.ts +2 -2
- package/dist/src/core/furnace-apply-dry-run.js +3 -2
- package/dist/src/core/furnace-apply-ftl.d.ts +7 -9
- package/dist/src/core/furnace-apply-ftl.js +12 -12
- package/dist/src/core/furnace-apply-helpers.d.ts +7 -7
- package/dist/src/core/furnace-apply-helpers.js +19 -16
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +8 -9
- package/dist/src/core/furnace-apply-overwrite-warn.js +8 -9
- package/dist/src/core/furnace-apply-undeploy-actions.d.ts +3 -4
- package/dist/src/core/furnace-apply-undeploy-actions.js +3 -4
- package/dist/src/core/furnace-apply.d.ts +5 -8
- package/dist/src/core/furnace-apply.js +19 -24
- package/dist/src/core/furnace-checksum-utils.d.ts +14 -0
- package/dist/src/core/furnace-checksum-utils.js +16 -0
- package/dist/src/core/furnace-config.d.ts +21 -30
- package/dist/src/core/furnace-config.js +32 -54
- package/dist/src/core/furnace-constants.d.ts +8 -0
- package/dist/src/core/furnace-constants.js +10 -2
- package/dist/src/core/furnace-css-fragments.d.ts +5 -5
- package/dist/src/core/furnace-css-fragments.js +5 -5
- package/dist/src/core/furnace-jsconfig.d.ts +11 -12
- package/dist/src/core/furnace-jsconfig.js +11 -12
- package/dist/src/core/furnace-marker.d.ts +7 -8
- package/dist/src/core/furnace-marker.js +7 -8
- package/dist/src/core/furnace-operation.d.ts +31 -0
- package/dist/src/core/furnace-operation.js +54 -17
- package/dist/src/core/furnace-precondition.d.ts +61 -0
- package/dist/src/core/furnace-precondition.js +67 -0
- package/dist/src/core/furnace-registration-remove.d.ts +5 -6
- package/dist/src/core/furnace-registration-remove.js +6 -7
- package/dist/src/core/furnace-registration-validate.d.ts +13 -0
- package/dist/src/core/furnace-registration-validate.js +20 -1
- package/dist/src/core/furnace-registration.d.ts +5 -6
- package/dist/src/core/furnace-registration.js +10 -12
- package/dist/src/core/furnace-rollback.js +7 -7
- package/dist/src/core/furnace-scanner.d.ts +1 -0
- package/dist/src/core/furnace-scanner.js +1 -2
- package/dist/src/core/furnace-stale-export.d.ts +10 -10
- package/dist/src/core/furnace-stale-export.js +10 -10
- package/dist/src/core/furnace-state-persist.d.ts +6 -8
- package/dist/src/core/furnace-state-persist.js +6 -8
- package/dist/src/core/furnace-validate-accessibility.d.ts +22 -0
- package/dist/src/core/furnace-validate-accessibility.js +310 -1
- package/dist/src/core/furnace-validate-compatibility.js +141 -1
- package/dist/src/core/furnace-validate-helpers.d.ts +5 -116
- package/dist/src/core/furnace-validate-helpers.js +0 -491
- package/dist/src/core/furnace-validate-registration.d.ts +7 -0
- package/dist/src/core/furnace-validate-registration.js +115 -41
- package/dist/src/core/furnace-validate.d.ts +16 -0
- package/dist/src/core/furnace-validate.js +188 -145
- package/dist/src/core/furnace-version-drift.d.ts +10 -11
- package/dist/src/core/furnace-version-drift.js +10 -11
- package/dist/src/core/git-base.d.ts +7 -9
- package/dist/src/core/git-base.js +7 -9
- package/dist/src/core/git-diff.d.ts +20 -9
- package/dist/src/core/git-diff.js +148 -63
- package/dist/src/core/git-file-ops.d.ts +19 -19
- package/dist/src/core/git-file-ops.js +19 -19
- package/dist/src/core/git-readonly-index.d.ts +53 -19
- package/dist/src/core/git-readonly-index.js +75 -31
- package/dist/src/core/git-status.d.ts +5 -6
- package/dist/src/core/git-status.js +5 -6
- package/dist/src/core/git.d.ts +9 -10
- package/dist/src/core/git.js +54 -70
- package/dist/src/core/license-headers.d.ts +17 -23
- package/dist/src/core/license-headers.js +17 -23
- package/dist/src/core/mach-build-artifacts.d.ts +9 -9
- package/dist/src/core/mach-build-artifacts.js +57 -19
- package/dist/src/core/mach-error-hints.js +42 -29
- package/dist/src/core/mach-known-noise-filter.d.ts +15 -16
- package/dist/src/core/mach-known-noise-filter.js +18 -20
- package/dist/src/core/mach-mozconfig.d.ts +14 -0
- package/dist/src/core/mach-mozconfig.js +30 -0
- package/dist/src/core/mach-resource-shim.d.ts +43 -58
- package/dist/src/core/mach-resource-shim.js +50 -67
- package/dist/src/core/mach.d.ts +37 -41
- package/dist/src/core/mach.js +50 -51
- package/dist/src/core/marionette-port.d.ts +36 -1
- package/dist/src/core/marionette-port.js +96 -31
- package/dist/src/core/marionette-preflight.d.ts +8 -12
- package/dist/src/core/marionette-preflight.js +86 -52
- package/dist/src/core/mochitest-server-port.d.ts +42 -0
- package/dist/src/core/mochitest-server-port.js +119 -0
- package/dist/src/core/module-resolution-preflight.d.ts +9 -11
- package/dist/src/core/module-resolution-preflight.js +9 -11
- package/dist/src/core/moz-manifest-helpers.d.ts +79 -0
- package/dist/src/core/moz-manifest-helpers.js +163 -0
- package/dist/src/core/{manifest-register.d.ts → moz-manifest-register.d.ts} +1 -1
- package/dist/src/core/{manifest-register.js → moz-manifest-register.js} +13 -28
- package/dist/src/core/{manifest-rules.d.ts → moz-manifest-rules.d.ts} +10 -1
- package/dist/src/core/{manifest-rules.js → moz-manifest-rules.js} +31 -24
- package/dist/src/core/{manifest-tokenizers.d.ts → moz-manifest-tokenizers.d.ts} +3 -5
- package/dist/src/core/{manifest-tokenizers.js → moz-manifest-tokenizers.js} +9 -12
- package/dist/src/core/ownership-table.d.ts +14 -16
- package/dist/src/core/ownership-table.js +14 -16
- package/dist/src/core/parser-fallback.d.ts +15 -1
- package/dist/src/core/parser-fallback.js +22 -3
- package/dist/src/core/patch-apply-fuzz.d.ts +10 -12
- package/dist/src/core/patch-apply-fuzz.js +15 -18
- package/dist/src/core/patch-apply.d.ts +13 -34
- package/dist/src/core/patch-apply.js +16 -76
- package/dist/src/core/patch-artifact-normalize.d.ts +13 -15
- package/dist/src/core/patch-artifact-normalize.js +13 -15
- package/dist/src/core/patch-export-metadata.d.ts +12 -2
- package/dist/src/core/patch-export-metadata.js +13 -4
- package/dist/src/core/patch-export-update.d.ts +13 -1
- package/dist/src/core/patch-export-update.js +25 -8
- package/dist/src/core/patch-export.d.ts +15 -8
- package/dist/src/core/patch-export.js +10 -11
- package/dist/src/core/patch-files.d.ts +5 -6
- package/dist/src/core/patch-files.js +5 -6
- package/dist/src/core/patch-identifier-suggest.d.ts +7 -12
- package/dist/src/core/patch-identifier-suggest.js +14 -19
- package/dist/src/core/patch-lint-binary.d.ts +51 -0
- package/dist/src/core/patch-lint-binary.js +39 -0
- package/dist/src/core/{lint-cache.d.ts → patch-lint-cache.d.ts} +5 -5
- package/dist/src/core/{lint-cache.js → patch-lint-cache.js} +21 -23
- package/dist/src/core/patch-lint-checkjs.d.ts +16 -16
- package/dist/src/core/patch-lint-checkjs.js +16 -16
- package/dist/src/core/patch-lint-chrome-jsdoc.d.ts +6 -9
- package/dist/src/core/patch-lint-chrome-jsdoc.js +10 -14
- package/dist/src/core/patch-lint-creators.d.ts +8 -8
- package/dist/src/core/patch-lint-creators.js +8 -8
- package/dist/src/core/patch-lint-cross.d.ts +17 -20
- package/dist/src/core/patch-lint-cross.js +16 -16
- package/dist/src/core/patch-lint-css.d.ts +3 -5
- package/dist/src/core/patch-lint-css.js +17 -22
- package/dist/src/core/patch-lint-diff-tag.d.ts +14 -16
- package/dist/src/core/patch-lint-diff-tag.js +14 -16
- package/dist/src/core/patch-lint-jsdoc.d.ts +7 -8
- package/dist/src/core/patch-lint-jsdoc.js +26 -19
- package/dist/src/core/patch-lint-mozbuild.js +20 -20
- package/dist/src/core/patch-lint-observer.d.ts +7 -7
- package/dist/src/core/patch-lint-observer.js +7 -7
- package/dist/src/core/patch-lint.d.ts +38 -29
- package/dist/src/core/patch-lint.js +89 -121
- package/dist/src/core/patch-lock.d.ts +1 -1
- package/dist/src/core/patch-lock.js +45 -9
- package/dist/src/core/patch-manifest-consistency.d.ts +2 -1
- package/dist/src/core/patch-manifest-consistency.js +25 -27
- package/dist/src/core/patch-manifest-io.js +14 -18
- package/dist/src/core/patch-manifest-resolve.d.ts +9 -12
- package/dist/src/core/patch-manifest-resolve.js +9 -12
- package/dist/src/core/patch-manifest-validate.d.ts +6 -1
- package/dist/src/core/patch-manifest-validate.js +25 -13
- package/dist/src/core/patch-parse.d.ts +24 -13
- package/dist/src/core/patch-parse.js +19 -14
- package/dist/src/core/patch-policy.d.ts +2 -2
- package/dist/src/core/patch-policy.js +2 -2
- package/dist/src/core/patch-registration-refs.d.ts +7 -8
- package/dist/src/core/patch-registration-refs.js +9 -9
- package/dist/src/core/process-cpu-time.d.ts +12 -0
- package/dist/src/core/process-cpu-time.js +52 -0
- package/dist/src/core/rebase-session.d.ts +38 -26
- package/dist/src/core/rebase-session.js +55 -28
- package/dist/src/core/register-browser-content.js +9 -74
- package/dist/src/core/{register-test-manifest.js → register-browser-test.js} +7 -42
- package/dist/src/core/register-module.js +10 -43
- package/dist/src/core/register-scaffold.d.ts +8 -8
- package/dist/src/core/register-scaffold.js +10 -10
- package/dist/src/core/register-shared-css.d.ts +9 -12
- package/dist/src/core/register-shared-css.js +17 -87
- package/dist/src/core/register-xpcshell-test.d.ts +6 -7
- package/dist/src/core/register-xpcshell-test.js +7 -8
- package/dist/src/core/shared-ftl.js +12 -4
- package/dist/src/core/state-file.d.ts +45 -0
- package/dist/src/core/state-file.js +34 -0
- package/dist/src/core/status-binary.d.ts +18 -11
- package/dist/src/core/status-binary.js +19 -12
- package/dist/src/core/status-classify.d.ts +30 -36
- package/dist/src/core/status-classify.js +21 -26
- package/dist/src/core/test-changed-prefs.d.ts +30 -0
- package/dist/src/core/test-changed-prefs.js +78 -0
- package/dist/src/core/test-harness-crash.d.ts +25 -63
- package/dist/src/core/test-harness-crash.js +121 -142
- package/dist/src/core/test-harness-signature.d.ts +18 -0
- package/dist/src/core/test-harness-signature.js +13 -0
- package/dist/src/core/test-path-scope.d.ts +12 -15
- package/dist/src/core/test-path-scope.js +15 -18
- package/dist/src/core/test-stale-check.d.ts +17 -17
- package/dist/src/core/test-stale-check.js +50 -43
- package/dist/src/core/test-stall-triage.d.ts +51 -0
- package/dist/src/core/test-stall-triage.js +126 -0
- package/dist/src/core/token-category.js +5 -7
- package/dist/src/core/token-coverage.js +9 -9
- package/dist/src/core/token-dark-mode.d.ts +9 -11
- package/dist/src/core/token-dark-mode.js +9 -11
- package/dist/src/core/token-docs.d.ts +2 -0
- package/dist/src/core/token-docs.js +2 -0
- package/dist/src/core/token-manager.d.ts +10 -2
- package/dist/src/core/token-manager.js +17 -8
- package/dist/src/core/token-scaffold.d.ts +7 -7
- package/dist/src/core/token-scaffold.js +7 -7
- package/dist/src/core/token-variant.d.ts +4 -4
- package/dist/src/core/token-variant.js +4 -4
- package/dist/src/core/toolchain-preflight.d.ts +20 -21
- package/dist/src/core/toolchain-preflight.js +28 -31
- package/dist/src/core/tree-guard.js +12 -2
- package/dist/src/core/tree-store.d.ts +41 -27
- package/dist/src/core/tree-store.js +63 -42
- package/dist/src/core/typecheck-shim.d.ts +23 -24
- package/dist/src/core/typecheck-shim.js +23 -24
- package/dist/src/core/typecheck.js +8 -8
- package/dist/src/core/wire-destroy.d.ts +3 -3
- package/dist/src/core/wire-destroy.js +7 -15
- package/dist/src/core/wire-dom-fragment.d.ts +9 -17
- package/dist/src/core/wire-dom-fragment.js +11 -44
- package/dist/src/core/wire-init.d.ts +2 -3
- package/dist/src/core/wire-init.js +8 -19
- package/dist/src/core/wire-subscript.d.ts +2 -3
- package/dist/src/core/wire-subscript.js +4 -13
- package/dist/src/core/wire-utils.d.ts +7 -8
- package/dist/src/core/wire-utils.js +7 -8
- package/dist/src/core/xpcshell-appdir.d.ts +38 -45
- package/dist/src/core/xpcshell-appdir.js +38 -45
- package/dist/src/errors/base.d.ts +37 -16
- package/dist/src/errors/base.js +37 -16
- package/dist/src/errors/build.d.ts +13 -1
- package/dist/src/errors/build.js +14 -2
- package/dist/src/errors/codes.d.ts +16 -0
- package/dist/src/errors/codes.js +16 -0
- package/dist/src/errors/furnace.d.ts +4 -4
- package/dist/src/errors/git.d.ts +6 -10
- package/dist/src/errors/git.js +6 -10
- package/dist/src/errors/patch.d.ts +7 -7
- package/dist/src/errors/patch.js +7 -7
- package/dist/src/errors/rebase.d.ts +4 -4
- package/dist/src/errors/rebase.js +4 -4
- package/dist/src/index.d.ts +7 -1
- package/dist/src/index.js +5 -0
- package/dist/src/types/commands/index.d.ts +2 -2
- package/dist/src/types/commands/options.d.ts +88 -70
- package/dist/src/types/commands/patches.d.ts +24 -34
- package/dist/src/types/commands/project.d.ts +5 -34
- package/dist/src/types/config.d.ts +25 -23
- package/dist/src/types/config.js +6 -1
- package/dist/src/types/furnace.d.ts +37 -13
- package/dist/src/types/furnace.js +19 -1
- package/dist/src/types/index.d.ts +3 -3
- package/dist/src/utils/build-info.d.ts +7 -8
- package/dist/src/utils/build-info.js +12 -11
- package/dist/src/utils/errors.d.ts +6 -8
- package/dist/src/utils/errors.js +6 -8
- package/dist/src/utils/logger.d.ts +27 -10
- package/dist/src/utils/logger.js +28 -16
- package/dist/src/utils/machine-output.d.ts +12 -0
- package/dist/src/utils/machine-output.js +33 -0
- package/dist/src/utils/options.d.ts +31 -14
- package/dist/src/utils/options.js +86 -30
- package/dist/src/utils/paths.d.ts +10 -8
- package/dist/src/utils/paths.js +10 -8
- package/dist/src/utils/platform.d.ts +0 -25
- package/dist/src/utils/platform.js +1 -42
- package/dist/src/utils/process-group.d.ts +9 -4
- package/dist/src/utils/process-group.js +19 -5
- package/dist/src/utils/process.d.ts +42 -7
- package/dist/src/utils/process.js +44 -17
- package/dist/src/utils/ps-duration.d.ts +31 -0
- package/dist/src/utils/ps-duration.js +70 -0
- package/dist/src/utils/regex.d.ts +9 -10
- package/dist/src/utils/regex.js +9 -10
- package/dist/src/utils/validation.d.ts +58 -28
- package/dist/src/utils/validation.js +60 -33
- package/package.json +2 -2
- package/dist/src/commands/doctor/post-rebase-audit.d.ts +0 -2
- package/dist/src/commands/doctor-furnace-manifest-sync.d.ts +0 -18
- package/dist/src/core/manifest-helpers.d.ts +0 -38
- package/dist/src/core/manifest-helpers.js +0 -120
- /package/dist/src/core/{lint-projection.d.ts → patch-lint-projection.d.ts} +0 -0
- /package/dist/src/core/{lint-projection.js → patch-lint-projection.js} +0 -0
- /package/dist/src/core/{register-test-manifest.d.ts → register-browser-test.d.ts} +0 -0
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import {
|
|
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
6
|
import { readLockStatus, withFileLock } from './file-lock.js';
|
|
7
7
|
import { git } from './git-base.js';
|
|
8
8
|
const ENGINE_SESSION_LOCK_PATH = join('.fireforge', 'engine-session.lock');
|
|
9
|
+
/**
|
|
10
|
+
* How much longer than the requested budget a wait may run while its queue
|
|
11
|
+
* position keeps improving, and the absolute ceiling on that. The ceiling
|
|
12
|
+
* matches `--wait-lock`'s own upper bound: an operator who asked for a wait
|
|
13
|
+
* never gets one longer than the largest wait they could have asked for.
|
|
14
|
+
*/
|
|
15
|
+
const WAIT_EXTENSION_FACTOR = 4;
|
|
16
|
+
const MAX_WAIT_LOCK_MS = 3600 * 1000;
|
|
9
17
|
/**
|
|
10
18
|
* Formats the periodic operator-facing waiting line printed while `--wait-lock`
|
|
11
19
|
* polls a contended engine session lock. The holder identification comes from
|
|
@@ -27,6 +35,22 @@ function formatWaitProgressLine(waitedMs, timeoutMs, holder, queue) {
|
|
|
27
35
|
const details = holder.metadata.length > 0 ? ` (${holder.metadata.join(', ')})` : '';
|
|
28
36
|
return `Waiting for the FireForge engine lock held by PID ${String(holder.pid)}${details} — ${progress}.${position}`;
|
|
29
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Formats the notice printed when the wait budget is EXTENDED because the
|
|
40
|
+
* queue advanced.
|
|
41
|
+
*
|
|
42
|
+
* Exported for direct unit testing. It names both figures — the requested
|
|
43
|
+
* budget and the one now in force — because the whole point is that the two
|
|
44
|
+
* have diverged, and an operator comparing the elapsed time against the
|
|
45
|
+
* number they typed would otherwise conclude the timeout is broken.
|
|
46
|
+
*/
|
|
47
|
+
export function formatWaitExtendedLine(ahead, budgetMs, requestedMs) {
|
|
48
|
+
const position = ahead === 0 ? 'you are now next' : `${String(ahead)} still ahead of you`;
|
|
49
|
+
return (`The queue advanced (${position}), so the engine-lock wait was extended to ` +
|
|
50
|
+
`${String(Math.round(budgetMs / 1000))}s total (you asked for ` +
|
|
51
|
+
`${String(Math.round(requestedMs / 1000))}s). A queue that stops moving still ` +
|
|
52
|
+
`gives up on the budget you asked for.`);
|
|
53
|
+
}
|
|
30
54
|
/**
|
|
31
55
|
* Runs `operation` while holding the project's engine-session lock, so only
|
|
32
56
|
* one engine-mutating FireForge command touches `engine/` at a time.
|
|
@@ -35,9 +59,9 @@ export async function withEngineSessionLock(projectRoot, command, operation, opt
|
|
|
35
59
|
// The lock is bypassed under test by default, and that is deliberate: the
|
|
36
60
|
// suite runs many engine-mutating commands in-process, which would either
|
|
37
61
|
// serialise on this lock or deadlock outright.
|
|
38
|
-
// `FIREFORGE_ENABLE_ENGINE_SESSION_LOCK_IN_TEST=1`
|
|
39
|
-
//
|
|
40
|
-
// suite completes
|
|
62
|
+
// `FIREFORGE_ENABLE_ENGINE_SESSION_LOCK_IN_TEST=1` lets the lock's own
|
|
63
|
+
// tests opt back in. Do not delete this branch — it is the reason the
|
|
64
|
+
// suite completes.
|
|
41
65
|
if (process.env['FIREFORGE_ENABLE_ENGINE_SESSION_LOCK_IN_TEST'] !== '1' &&
|
|
42
66
|
(process.env['NODE_ENV'] === 'test' || process.env['VITEST'] !== undefined)) {
|
|
43
67
|
return operation();
|
|
@@ -53,6 +77,22 @@ export async function withEngineSessionLock(projectRoot, command, operation, opt
|
|
|
53
77
|
onWaitProgress: ({ waitedMs, timeoutMs, holder, queue }) => {
|
|
54
78
|
info(formatWaitProgressLine(waitedMs, timeoutMs, holder, queue));
|
|
55
79
|
},
|
|
80
|
+
// Say it out loud. An extension is the moment the budget the
|
|
81
|
+
// operator asked for stops being the budget in force, and a wait
|
|
82
|
+
// that silently outlives its own stated timeout is
|
|
83
|
+
// indistinguishable from a broken one — which is how a downstream
|
|
84
|
+
// fork read it.
|
|
85
|
+
onWaitExtended: ({ ahead, budgetMs }) => {
|
|
86
|
+
info(formatWaitExtendedLine(ahead, budgetMs, waitLockSeconds * 1000));
|
|
87
|
+
},
|
|
88
|
+
// A budget that expires one position from the head pays the whole
|
|
89
|
+
// wait for nothing. While the queue is still MOVING the wait is
|
|
90
|
+
// working, so each advance renews the budget — up to a hard
|
|
91
|
+
// ceiling, so a pathological queue cannot wait forever. The
|
|
92
|
+
// no-flag fail-fast path deliberately gets none of this.
|
|
93
|
+
extendWhileAdvancing: {
|
|
94
|
+
maxWaitMs: Math.min(waitLockSeconds * 1000 * WAIT_EXTENSION_FACTOR, MAX_WAIT_LOCK_MS),
|
|
95
|
+
},
|
|
56
96
|
}
|
|
57
97
|
: {}),
|
|
58
98
|
ownerMetadata: [`command=${command}`, `started=${new Date().toISOString()}`],
|
|
@@ -63,7 +103,8 @@ export async function withEngineSessionLock(projectRoot, command, operation, opt
|
|
|
63
103
|
// (pinned by engine-session-lock tests); extend, don't reword.
|
|
64
104
|
onTimeoutMessage: `Another FireForge engine-mutating command is already running. ` +
|
|
65
105
|
`Wait for it to finish, then retry \`${command}\` — or pass --wait-lock [seconds] ` +
|
|
66
|
-
`to wait for the lock (bare --wait-lock waits up to 60 seconds)
|
|
106
|
+
`to wait for the lock (bare --wait-lock waits up to 60 seconds). ` +
|
|
107
|
+
`Set FIREFORGE_WAIT_LOCK=<seconds> to apply a budget to every command in a session.`,
|
|
67
108
|
onStaleLockMessage: (ageMs) => `Removed stale FireForge engine session lock (${Math.round(ageMs / 1000)}s old).`,
|
|
68
109
|
});
|
|
69
110
|
}
|
|
@@ -81,7 +122,7 @@ export async function readEngineSessionLockStatus(projectRoot) {
|
|
|
81
122
|
* Renders the engine-session lock snapshot as operator-facing lines.
|
|
82
123
|
* Pure, so the wording is unit-testable without a lock on disk.
|
|
83
124
|
*/
|
|
84
|
-
export function formatEngineSessionLockStatus(snapshot) {
|
|
125
|
+
export function formatEngineSessionLockStatus(snapshot, holderCpuSeconds) {
|
|
85
126
|
if (!snapshot.held) {
|
|
86
127
|
return ['Engine session lock: free (no FireForge engine-mutating command is running).'];
|
|
87
128
|
}
|
|
@@ -93,10 +134,25 @@ export function formatEngineSessionLockStatus(snapshot) {
|
|
|
93
134
|
? 'held by an unidentified process (no readable owner record)'
|
|
94
135
|
: `held by PID ${String(holder.pid)}${holder.alive ? '' : ' (NOT RUNNING — stale lock)'}` +
|
|
95
136
|
(holder.metadata.length > 0 ? ` (${holder.metadata.join(', ')})` : '');
|
|
96
|
-
|
|
137
|
+
const lines = [
|
|
97
138
|
`Engine session lock: ${identity}, for ${elapsed}.`,
|
|
98
139
|
`Queue depth: ${String(snapshot.queueDepth)} waiter(s).`,
|
|
99
140
|
];
|
|
141
|
+
// Liveness answers "does the process exist"; it does not answer "is it
|
|
142
|
+
// getting anywhere". A holder alive for minutes having used a fraction of
|
|
143
|
+
// a second of CPU is the shape of a wedged command, and every waiter
|
|
144
|
+
// behind it inherits the stall. Stated as an observation with its own
|
|
145
|
+
// caveat — a holder blocked on I/O is also idle, and this must not be read
|
|
146
|
+
// as licence to kill anything.
|
|
147
|
+
if (holder?.alive === true && holderCpuSeconds !== undefined) {
|
|
148
|
+
const cpu = `${holderCpuSeconds.toFixed(1)}s`;
|
|
149
|
+
const idle = snapshot.heldForMs !== undefined && snapshot.heldForMs > 60_000 && holderCpuSeconds < 2
|
|
150
|
+
? ' — near-zero CPU over a long hold, which is what a WEDGED command looks like; ' +
|
|
151
|
+
'a holder blocked on I/O looks the same, so confirm before acting'
|
|
152
|
+
: '';
|
|
153
|
+
lines.push(`Holder CPU time: ${cpu}${idle}.`);
|
|
154
|
+
}
|
|
155
|
+
return lines;
|
|
100
156
|
}
|
|
101
157
|
/** Prefix marking a generation token whose probe failed. */
|
|
102
158
|
const UNAVAILABLE_PREFIX = 'unavailable:';
|
|
@@ -118,13 +174,12 @@ export async function snapshotEngineGeneration(engineDir) {
|
|
|
118
174
|
}
|
|
119
175
|
catch (error) {
|
|
120
176
|
lastError = error;
|
|
121
|
-
// A contended `.git/index.lock` is TRANSIENT, not a state: some
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
// `FAIL reason=inconclusive` on a one-sided probe failure
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
// is reported immediately.
|
|
177
|
+
// A contended `.git/index.lock` is TRANSIENT, not a state: some other
|
|
178
|
+
// writer held the index for the instant we looked. Treating it as
|
|
179
|
+
// "unmeasurable" turns a perfectly good suite into
|
|
180
|
+
// `FAIL reason=inconclusive` on a one-sided probe failure. Anything
|
|
181
|
+
// else — an unreadable `.git`, a non-git `engine/` — is a real state
|
|
182
|
+
// and is reported immediately.
|
|
128
183
|
if (!isIndexLockError(error) || attempt === GENERATION_PROBE_ATTEMPTS - 1)
|
|
129
184
|
break;
|
|
130
185
|
await delay(GENERATION_PROBE_RETRY_MS);
|
|
@@ -162,31 +217,109 @@ export function isUnavailableGenerationToken(token) {
|
|
|
162
217
|
export function unavailableGenerationReason(token) {
|
|
163
218
|
return token.slice(UNAVAILABLE_PREFIX.length);
|
|
164
219
|
}
|
|
220
|
+
/** How many changed entries the delta names before truncating. */
|
|
221
|
+
const DELTA_ENTRY_LIMIT = 5;
|
|
222
|
+
/**
|
|
223
|
+
* Splits a generation token into its HEAD and porcelain halves. The porcelain
|
|
224
|
+
* body is `-z` output, so it is NUL-separated and never quoted.
|
|
225
|
+
*/
|
|
226
|
+
function splitGenerationToken(token) {
|
|
227
|
+
const separator = token.indexOf('\0');
|
|
228
|
+
if (separator < 0)
|
|
229
|
+
return { head: token, body: '' };
|
|
230
|
+
return { head: token.slice(0, separator), body: token.slice(separator + 1) };
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Parses `git status --porcelain=v1 -z` into `XY path` records.
|
|
234
|
+
*
|
|
235
|
+
* The rename/copy shape is the trap: `R`/`C` entries are followed by a
|
|
236
|
+
* SECOND NUL-separated field carrying the original path, and consuming only
|
|
237
|
+
* one desynchronises every record after it — turning a one-file rename into
|
|
238
|
+
* a report that the whole tree moved. Both fields are consumed and the
|
|
239
|
+
* record renders as `orig -> new`.
|
|
240
|
+
*/
|
|
241
|
+
function parsePorcelainRecords(body) {
|
|
242
|
+
const fields = body.split('\0').filter((field) => field.length > 0);
|
|
243
|
+
const records = [];
|
|
244
|
+
for (let i = 0; i < fields.length; i++) {
|
|
245
|
+
const field = fields[i] ?? '';
|
|
246
|
+
// `XY ` — two status characters and a space — then the path.
|
|
247
|
+
if (field.length < 4)
|
|
248
|
+
continue;
|
|
249
|
+
const status = field.slice(0, 2);
|
|
250
|
+
const path = field.slice(3);
|
|
251
|
+
if (status.includes('R') || status.includes('C')) {
|
|
252
|
+
const origin = fields[i + 1];
|
|
253
|
+
i += 1;
|
|
254
|
+
records.push(`${status} ${origin ?? '?'} -> ${path}`);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
records.push(`${status} ${path}`);
|
|
258
|
+
}
|
|
259
|
+
return records;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Describes what moved between two generation tokens, in operator terms.
|
|
263
|
+
*
|
|
264
|
+
* The refusal used to say only THAT the engine changed, which left the
|
|
265
|
+
* operator to reconstruct the writer by hand — `find -newermt` against the
|
|
266
|
+
* run window, minus the objdir, minus git's own bookkeeping. Everything
|
|
267
|
+
* needed to answer it is already in the two tokens, so the refusal answers
|
|
268
|
+
* it. Pure and total: an unparseable token yields an empty list rather than
|
|
269
|
+
* an exception, because a diagnostic must never convert a refusal into a
|
|
270
|
+
* crash.
|
|
271
|
+
*
|
|
272
|
+
* @param before - Token captured before the run
|
|
273
|
+
* @param after - Token captured after the run
|
|
274
|
+
* @returns Human-readable lines describing the delta; empty when nothing
|
|
275
|
+
* could be attributed
|
|
276
|
+
*/
|
|
277
|
+
export function describeEngineGenerationDelta(before, after) {
|
|
278
|
+
const lines = [];
|
|
279
|
+
const from = splitGenerationToken(before);
|
|
280
|
+
const to = splitGenerationToken(after);
|
|
281
|
+
if (from.head !== to.head) {
|
|
282
|
+
lines.push(`HEAD moved: ${from.head} -> ${to.head}`);
|
|
283
|
+
}
|
|
284
|
+
const beforeRecords = new Set(parsePorcelainRecords(from.body));
|
|
285
|
+
const afterRecords = new Set(parsePorcelainRecords(to.body));
|
|
286
|
+
const appeared = [...afterRecords].filter((record) => !beforeRecords.has(record)).sort();
|
|
287
|
+
const disappeared = [...beforeRecords].filter((record) => !afterRecords.has(record)).sort();
|
|
288
|
+
const render = (label, records) => {
|
|
289
|
+
if (records.length === 0)
|
|
290
|
+
return;
|
|
291
|
+
const head = records.slice(0, DELTA_ENTRY_LIMIT);
|
|
292
|
+
const truncated = records.length - head.length;
|
|
293
|
+
lines.push(`${label}: ${head.join(', ')}${truncated > 0 ? `, … (+${String(truncated)} more)` : ''}`);
|
|
294
|
+
};
|
|
295
|
+
render('Working-tree entries that appeared', appeared);
|
|
296
|
+
render('Working-tree entries that went away', disappeared);
|
|
297
|
+
return lines;
|
|
298
|
+
}
|
|
165
299
|
/**
|
|
166
300
|
* Throws when the engine's generation token differs from `before`, i.e. the
|
|
167
301
|
* engine was mutated by another writer while a test run was in flight.
|
|
168
302
|
*
|
|
169
|
-
* **An unmeasurable engine warns rather than throws.** `engine/` is not
|
|
170
|
-
* a git checkout — `fireforge download` extracts a source tarball —
|
|
171
|
-
* failed probe is a legitimate state and must not fail the run.
|
|
303
|
+
* **An unmeasurable engine warns rather than throws.** `engine/` is not
|
|
304
|
+
* always a git checkout — `fireforge download` extracts a source tarball —
|
|
305
|
+
* so a failed probe is a legitimate state and must not fail the run.
|
|
172
306
|
*
|
|
173
|
-
* What it must also not do is pass *silently*.
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
307
|
+
* What it must also not do is pass *silently*. A failure token compared for
|
|
308
|
+
* equality like any other would let a git failure that reproduces across
|
|
309
|
+
* both probes (unreadable `.git`, a permissions problem, a corrupt index)
|
|
310
|
+
* take the `after === before` early return and bless a verdict the guard
|
|
311
|
+
* never verified. Two *differing* failure messages are worse still: they
|
|
312
|
+
* fall through to the mutation branch and report a spurious
|
|
313
|
+
* "engine/ changed". Hence the prefix comparison rather than a token
|
|
314
|
+
* comparison — the token embeds the error message, and two genuine failures
|
|
315
|
+
* rarely phrase it identically.
|
|
181
316
|
*
|
|
182
317
|
* The tolerance is deliberately limited to a probe that failed *both* times:
|
|
183
318
|
* that is the steady state of a non-git `engine/`, and it warns. A one-sided
|
|
184
|
-
* transition is not that state. `engine/` that was measurable and then
|
|
185
|
-
* means the second probe measured nothing about a checkout that
|
|
186
|
-
* had something to measure; the reverse means there was never a
|
|
187
|
-
* compare against. Neither
|
|
188
|
-
* throw. Compare on the prefix rather than the token, because the token embeds
|
|
189
|
-
* the error message and two genuine failures rarely phrase it identically.
|
|
319
|
+
* transition is not that state. An `engine/` that was measurable and then
|
|
320
|
+
* was not means the second probe measured nothing about a checkout that
|
|
321
|
+
* demonstrably had something to measure; the reverse means there was never a
|
|
322
|
+
* baseline to compare against. Neither verdict can be trusted, so both throw.
|
|
190
323
|
*/
|
|
191
324
|
export async function assertEngineGenerationUnchanged(engineDir, before) {
|
|
192
325
|
const after = await snapshotEngineGeneration(engineDir);
|
|
@@ -204,12 +337,14 @@ export async function assertEngineGenerationUnchanged(engineDir, before) {
|
|
|
204
337
|
'probed afterwards, so there is no baseline to compare against.'
|
|
205
338
|
: `engine/ was probed before the run but could not be probed afterwards ` +
|
|
206
339
|
`(${unavailableGenerationReason(after)}), so nothing was measured to compare against.`;
|
|
207
|
-
throw new
|
|
340
|
+
throw new InconclusiveVerdictError(`${detail}\n\n` +
|
|
208
341
|
'This test verdict is inconclusive. Restore engine/ to a readable state, then rebuild ' +
|
|
209
342
|
'and rerun the affected tests.');
|
|
210
343
|
}
|
|
211
344
|
if (after === before)
|
|
212
345
|
return;
|
|
213
|
-
|
|
346
|
+
const delta = describeEngineGenerationDelta(before, after);
|
|
347
|
+
throw new InconclusiveVerdictError('engine/ changed while `fireforge test` was running, so this test verdict is invalid/inconclusive.\n\n' +
|
|
348
|
+
(delta.length > 0 ? `What moved:\n${delta.map((line) => ` ${line}`).join('\n')}\n\n` : '') +
|
|
214
349
|
'Use one writer per engine checkout, then rebuild and rerun the affected tests.');
|
|
215
350
|
}
|
|
@@ -5,21 +5,21 @@
|
|
|
5
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
|
-
* - `re-export --refuse-adjacent-unmanaged` refuses while the new files
|
|
9
|
-
*
|
|
8
|
+
* - `re-export --refuse-adjacent-unmanaged` refuses while the new files are
|
|
9
|
+
* still unmanaged; and
|
|
10
10
|
* - exporting the new files as their own patch fails cross-patch lint,
|
|
11
11
|
* because at the projected placement the OLD patch still contains the
|
|
12
12
|
* moved code.
|
|
13
13
|
*
|
|
14
|
-
* Each guard is individually correct. Together they dead-end, and the way
|
|
15
|
-
*
|
|
16
|
-
* (`re-export --scan --scan-file`), then split them out into a patch of
|
|
17
|
-
*
|
|
14
|
+
* Each guard is individually correct. Together they dead-end, and the way out
|
|
15
|
+
* is non-obvious: adopt the new files into the OLD patch first
|
|
16
|
+
* (`re-export --scan --scan-file`), then split them out into a patch of their
|
|
17
|
+
* own (`patch move-files --create --order N`).
|
|
18
18
|
*
|
|
19
|
-
* This module recognises the shape from evidence FireForge already has —
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* This module recognises the shape from evidence FireForge already has — the
|
|
20
|
+
* pending diff's new-file content versus the added lines the existing patches
|
|
21
|
+
* carry — so the refusal can name the sequence instead of leaving the
|
|
22
|
+
* operator to derive it.
|
|
23
23
|
*/
|
|
24
24
|
/** One existing patch that already carries lines the new files would add. */
|
|
25
25
|
export interface MovedCodeOverlap {
|
|
@@ -6,21 +6,21 @@
|
|
|
6
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
|
-
* - `re-export --refuse-adjacent-unmanaged` refuses while the new files
|
|
10
|
-
*
|
|
9
|
+
* - `re-export --refuse-adjacent-unmanaged` refuses while the new files are
|
|
10
|
+
* still unmanaged; and
|
|
11
11
|
* - exporting the new files as their own patch fails cross-patch lint,
|
|
12
12
|
* because at the projected placement the OLD patch still contains the
|
|
13
13
|
* moved code.
|
|
14
14
|
*
|
|
15
|
-
* Each guard is individually correct. Together they dead-end, and the way
|
|
16
|
-
*
|
|
17
|
-
* (`re-export --scan --scan-file`), then split them out into a patch of
|
|
18
|
-
*
|
|
15
|
+
* Each guard is individually correct. Together they dead-end, and the way out
|
|
16
|
+
* is non-obvious: adopt the new files into the OLD patch first
|
|
17
|
+
* (`re-export --scan --scan-file`), then split them out into a patch of their
|
|
18
|
+
* own (`patch move-files --create --order N`).
|
|
19
19
|
*
|
|
20
|
-
* This module recognises the shape from evidence FireForge already has —
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* This module recognises the shape from evidence FireForge already has — the
|
|
21
|
+
* pending diff's new-file content versus the added lines the existing patches
|
|
22
|
+
* carry — so the refusal can name the sequence instead of leaving the
|
|
23
|
+
* operator to derive it.
|
|
24
24
|
*/
|
|
25
25
|
import { extractAddedLinesPerFile } from './patch-lint-diff.js';
|
|
26
26
|
/**
|
|
@@ -12,11 +12,10 @@ export interface LockHolder {
|
|
|
12
12
|
/**
|
|
13
13
|
* Live queue state around a contended lock.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
* gap
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* queued and how many are ahead of you.
|
|
15
|
+
* The lock itself behaves correctly under several concurrent sessions; the
|
|
16
|
+
* gap this closes is VISIBILITY. Waiters advertise themselves in a sibling
|
|
17
|
+
* directory so both the wait output and `fireforge status --lock` can say
|
|
18
|
+
* how many are queued and how many are ahead of you.
|
|
20
19
|
*/
|
|
21
20
|
export interface LockQueueState {
|
|
22
21
|
/** Live waiters currently queued for the lock, including this process. */
|
|
@@ -58,6 +57,37 @@ export interface FileLockOptions {
|
|
|
58
57
|
/** Queue state at this poll, when the waiter registry is available. */
|
|
59
58
|
queue?: LockQueueState | undefined;
|
|
60
59
|
}) => void;
|
|
60
|
+
/**
|
|
61
|
+
* When set, a wait whose QUEUE POSITION is still improving is granted a
|
|
62
|
+
* fresh `timeoutMs` budget on each advance, up to `maxWaitMs` total.
|
|
63
|
+
*
|
|
64
|
+
* A fixed wall-clock budget against a queue whose depth the tool knows is
|
|
65
|
+
* the wrong shape under several concurrent sessions: a wait that expires
|
|
66
|
+
* one position from the head pays the entire wait and gets nothing. The
|
|
67
|
+
* distinction that matters is not "how long have I waited" but "is this
|
|
68
|
+
* queue moving" — a stalled queue still starves on the original budget,
|
|
69
|
+
* which is the case the timeout exists for.
|
|
70
|
+
*
|
|
71
|
+
* Requires the waiter registry (see {@link LockQueueState}); a lock with
|
|
72
|
+
* no readable queue never extends, because nothing observed an advance.
|
|
73
|
+
*/
|
|
74
|
+
extendWhileAdvancing?: {
|
|
75
|
+
maxWaitMs: number;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Invoked when {@link extendWhileAdvancing} actually grants an extension.
|
|
79
|
+
*
|
|
80
|
+
* Separate from {@link onWaitProgress} on purpose: an extension is the one
|
|
81
|
+
* moment the budget the operator asked for stops being the budget in
|
|
82
|
+
* force, and a wait that silently outlives its stated timeout is
|
|
83
|
+
* indistinguishable from a broken one. `budgetMs` is the new TOTAL budget
|
|
84
|
+
* measured from the start of the wait, so it can be compared directly
|
|
85
|
+
* against the requested figure.
|
|
86
|
+
*/
|
|
87
|
+
onWaitExtended?: (extension: {
|
|
88
|
+
ahead: number;
|
|
89
|
+
budgetMs: number;
|
|
90
|
+
}) => void;
|
|
61
91
|
onTimeoutMessage?: string;
|
|
62
92
|
onStaleLockMessage?: (ageMs: number) => string | undefined;
|
|
63
93
|
/** Extra owner-file lines for human diagnostics; ignored by lock mechanics. */
|
|
@@ -99,5 +129,32 @@ export interface LockStatusSnapshot {
|
|
|
99
129
|
* lock is reported as free, never as an error.
|
|
100
130
|
*/
|
|
101
131
|
export declare function readLockStatus(lockPath: string): Promise<LockStatusSnapshot>;
|
|
132
|
+
/**
|
|
133
|
+
* Removes a lock directory only if this process still owns it, for callers
|
|
134
|
+
* that hold no acquisition token.
|
|
135
|
+
*
|
|
136
|
+
* The ownership half of {@link releaseLock}, minus the token check — a
|
|
137
|
+
* signal-time sweeper knows which lock paths its own operations opened, but
|
|
138
|
+
* not the per-acquisition UUID those acquisitions minted. The PID check is
|
|
139
|
+
* still the one that matters: it stops the sweeper deleting a lock a
|
|
140
|
+
* DIFFERENT process acquired in the window between our operation dying and
|
|
141
|
+
* the sweep running.
|
|
142
|
+
*
|
|
143
|
+
* Never throws: callers are shutdown paths where a slow or failing I/O must
|
|
144
|
+
* not prevent the process from exiting. Returns whether the directory was
|
|
145
|
+
* removed so callers can log accurately.
|
|
146
|
+
*
|
|
147
|
+
* @param lockPath - Lock directory to remove
|
|
148
|
+
* @returns True when the lock was removed, false when it was left in place
|
|
149
|
+
*/
|
|
150
|
+
export declare function releaseLockIfOwned(lockPath: string): Promise<boolean>;
|
|
151
|
+
/**
|
|
152
|
+
* Releases every lock this process still holds, for the signal path.
|
|
153
|
+
*
|
|
154
|
+
* Never throws and never rejects: a shutdown path must not be able to keep
|
|
155
|
+
* the process alive. Returns the paths actually removed so the caller can
|
|
156
|
+
* report accurately.
|
|
157
|
+
*/
|
|
158
|
+
export declare function forceReleaseHeldLocksForSignal(): Promise<string[]>;
|
|
102
159
|
/** Runs an async operation while holding a directory lock, with stale-lock recovery. */
|
|
103
160
|
export declare function withFileLock<T>(lockPath: string, operation: () => Promise<T>, options?: FileLockOptions): Promise<T>;
|