@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
|
@@ -89,7 +89,7 @@ export async function configCommand(projectRoot, key, value, options = {}) {
|
|
|
89
89
|
throw new GeneralError('No fireforge.json found. Run "fireforge setup" to create a project.');
|
|
90
90
|
}
|
|
91
91
|
if (value === undefined) {
|
|
92
|
-
// Get mode
|
|
92
|
+
// Get mode: read the raw document rather than the validated config so
|
|
93
93
|
// keys persisted via `fireforge config <key> --force` remain readable.
|
|
94
94
|
// `validateConfig` builds a typed clone containing only the known schema
|
|
95
95
|
// fields, so relying on it here would hide forced-write keys and surface
|
|
@@ -110,7 +110,7 @@ export async function configCommand(projectRoot, key, value, options = {}) {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
else {
|
|
113
|
-
// Set mode
|
|
113
|
+
// Set mode: validate key prefix
|
|
114
114
|
const topLevelKey = key.split('.')[0] ?? key;
|
|
115
115
|
if (!SUPPORTED_CONFIG_ROOT_KEYS.includes(topLevelKey) &&
|
|
116
116
|
!options.force) {
|
|
@@ -126,7 +126,7 @@ export async function configCommand(projectRoot, key, value, options = {}) {
|
|
|
126
126
|
// Serialise the read → mutate → write round-trip behind the sidecar
|
|
127
127
|
// config lock so two concurrent `fireforge config` invocations cannot
|
|
128
128
|
// each read the pre-state, mutate their own copy, and clobber each
|
|
129
|
-
// other on write
|
|
129
|
+
// other on write, both exiting 0 with one key silently lost. Atomic
|
|
130
130
|
// file writes (temp + rename) are not enough on their own: the lost
|
|
131
131
|
// update happens before the rename, inside the read-modify step.
|
|
132
132
|
// Readers stay lock-free (see `withConfigFileLock`).
|
|
@@ -143,12 +143,12 @@ export async function configCommand(projectRoot, key, value, options = {}) {
|
|
|
143
143
|
if (deepEqual(currentValue, parsedValue)) {
|
|
144
144
|
return true;
|
|
145
145
|
}
|
|
146
|
-
// `--force` is an escape hatch for
|
|
147
|
-
// let the user write a structurally invalid value for a
|
|
146
|
+
// `--force` is an escape hatch for unknown keys. It must not also
|
|
147
|
+
// let the user write a structurally invalid value for a known key.
|
|
148
148
|
// Strict validation applies whenever the key is listed in
|
|
149
149
|
// SUPPORTED_CONFIG_PATHS, regardless of --force.
|
|
150
150
|
//
|
|
151
|
-
//
|
|
151
|
+
// Both branches seed the mutation from the raw on-disk document.
|
|
152
152
|
// Round-tripping the known-key branch through `loadConfig` →
|
|
153
153
|
// `validateConfig` builds a typed clone containing only the known
|
|
154
154
|
// schema fields, so any ordinary `fireforge config <key> <value>`
|
|
@@ -160,7 +160,7 @@ export async function configCommand(projectRoot, key, value, options = {}) {
|
|
|
160
160
|
}
|
|
161
161
|
else {
|
|
162
162
|
// Mutate the raw document (preserving unknown keys), then run
|
|
163
|
-
// strict validation on the
|
|
163
|
+
// strict validation on the result. validateConfig checks the
|
|
164
164
|
// known schema fields and ignores unknown keys, so this keeps
|
|
165
165
|
// exactly the old validation strength while writing the
|
|
166
166
|
// unstripped document.
|
|
@@ -174,7 +174,7 @@ export async function configCommand(projectRoot, key, value, options = {}) {
|
|
|
174
174
|
catch (error) {
|
|
175
175
|
// Only value/validation problems are the user's "invalid value".
|
|
176
176
|
// Lock-acquisition timeouts and I/O failures must keep their own
|
|
177
|
-
// types and messages
|
|
177
|
+
// types and messages. Re-labelling a lock timeout as `Invalid value
|
|
178
178
|
// for "<key>"` points diagnosis at the value (and returns the wrong
|
|
179
179
|
// exit-code class) when the real problem is a concurrent fireforge
|
|
180
180
|
// process holding the config lock.
|
|
@@ -195,7 +195,7 @@ export async function configCommand(projectRoot, key, value, options = {}) {
|
|
|
195
195
|
/**
|
|
196
196
|
* Structural equality check covering the shapes `fireforge config` accepts:
|
|
197
197
|
* primitives (strings, numbers, booleans), `null`, arrays of primitives, and
|
|
198
|
-
* nested objects. Used to short-circuit no-op writes
|
|
198
|
+
* nested objects. Used to short-circuit no-op writes: when the parsed value
|
|
199
199
|
* matches the current on-disk value, the mutate + write step is skipped
|
|
200
200
|
* entirely.
|
|
201
201
|
*/
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DestructiveOpResult } from '../core/destructive.js';
|
|
2
|
+
/**
|
|
3
|
+
* Closes out a {@link DestructiveOpResult} and says whether to run the
|
|
4
|
+
* mutation.
|
|
5
|
+
*
|
|
6
|
+
* Eleven commands had copied the same tail: `if (decision === 'dry-run') {
|
|
7
|
+
* outro(…); return; } if (decision === 'declined') { outro(…); return; }`.
|
|
8
|
+
* The dry-run wording is a user-facing contract that must not drift between
|
|
9
|
+
* commands, so it lives here. The declined wording is per-command and stays
|
|
10
|
+
* a parameter.
|
|
11
|
+
*
|
|
12
|
+
* `confirmDestructive` never mutates on its own, so a caller that forgets this
|
|
13
|
+
* check silently performs a "dry run" for real. That is why this returns a
|
|
14
|
+
* boolean the caller must act on instead of being a helper that returns void.
|
|
15
|
+
* @param decision - The result from `confirmDestructive`.
|
|
16
|
+
* @param declinedOutro - Outro to print when the operator answered "no".
|
|
17
|
+
* @returns True when the caller should proceed with the mutation.
|
|
18
|
+
*/
|
|
19
|
+
export declare function proceedAfterDecision(decision: DestructiveOpResult, declinedOutro: string): boolean;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { outro } from '../utils/logger.js';
|
|
2
|
+
/** The dry-run outro every command prints, spelled once. */
|
|
3
|
+
const DRY_RUN_OUTRO = 'Dry run complete — no changes made';
|
|
4
|
+
/**
|
|
5
|
+
* Closes out a {@link DestructiveOpResult} and says whether to run the
|
|
6
|
+
* mutation.
|
|
7
|
+
*
|
|
8
|
+
* Eleven commands had copied the same tail: `if (decision === 'dry-run') {
|
|
9
|
+
* outro(…); return; } if (decision === 'declined') { outro(…); return; }`.
|
|
10
|
+
* The dry-run wording is a user-facing contract that must not drift between
|
|
11
|
+
* commands, so it lives here. The declined wording is per-command and stays
|
|
12
|
+
* a parameter.
|
|
13
|
+
*
|
|
14
|
+
* `confirmDestructive` never mutates on its own, so a caller that forgets this
|
|
15
|
+
* check silently performs a "dry run" for real. That is why this returns a
|
|
16
|
+
* boolean the caller must act on instead of being a helper that returns void.
|
|
17
|
+
* @param decision - The result from `confirmDestructive`.
|
|
18
|
+
* @param declinedOutro - Outro to print when the operator answered "no".
|
|
19
|
+
* @returns True when the caller should proceed with the mutation.
|
|
20
|
+
*/
|
|
21
|
+
export function proceedAfterDecision(decision, declinedOutro) {
|
|
22
|
+
if (decision === 'dry-run') {
|
|
23
|
+
outro(DRY_RUN_OUTRO);
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (decision === 'declined') {
|
|
27
|
+
outro(declinedOutro);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
@@ -103,7 +103,7 @@ async function discardDirectoryEntries(projectRoot, engineDir, patchesDir, dirPa
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
catch {
|
|
106
|
-
// Furnace config may not exist
|
|
106
|
+
// Furnace config may not exist, so skip silently.
|
|
107
107
|
}
|
|
108
108
|
if (failures.length > 0) {
|
|
109
109
|
throw new GeneralError(`Failed to discard ${failures.length} file(s) under ${dirPath}/. See warnings above.`);
|
|
@@ -131,7 +131,7 @@ export async function discardCommand(projectRoot, file, options = {}) {
|
|
|
131
131
|
const statusEntries = await expandUntrackedDirectoryEntries(paths.engine, await getWorkingTreeStatus(paths.engine));
|
|
132
132
|
const statusEntry = statusEntries.find((entry) => entry.file === file || entry.originalPath === file);
|
|
133
133
|
// Directory recursion fallback: when the explicit path does not match a
|
|
134
|
-
// single status entry but
|
|
134
|
+
// single status entry but does correspond to one or more entries below it,
|
|
135
135
|
// treat the input as a directory and discard everything inside. Otherwise
|
|
136
136
|
// `discard <dir> --yes` fails with "no changes to discard" even though
|
|
137
137
|
// `status --unmanaged` lists files under that directory, forcing the
|
|
@@ -159,8 +159,8 @@ export async function discardCommand(projectRoot, file, options = {}) {
|
|
|
159
159
|
throw new GeneralError(`File "${file}" has no changes to discard.`);
|
|
160
160
|
}
|
|
161
161
|
if (options.dryRun) {
|
|
162
|
-
// Show the rename pair regardless of which side the operator passed
|
|
163
|
-
//
|
|
162
|
+
// Show the rename pair regardless of which side the operator passed.
|
|
163
|
+
// Passing the new path of a rename used to hide that discarding also
|
|
164
164
|
// resurrects the old path, exactly when the full picture matters most.
|
|
165
165
|
info(`Would discard changes to: ${dryRunLabel(plan)}`);
|
|
166
166
|
outro('Dry run complete — no changes made');
|
|
@@ -182,7 +182,7 @@ export async function discardCommand(projectRoot, file, options = {}) {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
catch {
|
|
185
|
-
// Furnace config may not exist
|
|
185
|
+
// Furnace config may not exist, so skip silently.
|
|
186
186
|
}
|
|
187
187
|
outro(describeDiscardOutcome(plan, options.toUpstream === true));
|
|
188
188
|
}
|
|
@@ -37,21 +37,21 @@ export interface DoctorCheckContext {
|
|
|
37
37
|
/**
|
|
38
38
|
* The parsed furnace config, set by the "Furnace configuration" check
|
|
39
39
|
* when it succeeds. Later furnace checks read from this so they do not
|
|
40
|
-
* re-parse the file
|
|
40
|
+
* re-parse the file. Undefined when the config could not be loaded.
|
|
41
41
|
*/
|
|
42
42
|
furnaceConfig: FurnaceConfig | undefined;
|
|
43
43
|
/**
|
|
44
44
|
* State this run actually mutated, one human-readable line per write.
|
|
45
45
|
* Repairs run inside the check loop while the exit code is computed only
|
|
46
46
|
* after every check, so a repair can land and the run still exit non-zero
|
|
47
|
-
* on an unrelated check
|
|
47
|
+
* on an unrelated check, and a non-zero exit reads as "nothing happened".
|
|
48
48
|
* The runner prints these before the summary in every branch so a write is
|
|
49
49
|
* never invisible.
|
|
50
50
|
*/
|
|
51
51
|
mutations: string[];
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* Result a check may return. A single object is the common case
|
|
54
|
+
* Result a check may return. A single object is the common case. An array
|
|
55
55
|
* lets a single check emit multiple related rows (e.g. the engine branch
|
|
56
56
|
* check which may report on branch + detached state together).
|
|
57
57
|
*/
|
|
@@ -85,7 +85,7 @@ export interface DoctorCheckDefinition {
|
|
|
85
85
|
dependsOn?: readonly string[];
|
|
86
86
|
/**
|
|
87
87
|
* Runs the inspection. Throwing is shorthand for "this check failed with
|
|
88
|
-
* severity 'error'"
|
|
88
|
+
* severity 'error'": the runner converts the exception message into a
|
|
89
89
|
* DoctorCheck. Returning a DoctorCheck (or array) lets the check control
|
|
90
90
|
* severity, warnings, and fix hints directly.
|
|
91
91
|
*/
|
|
@@ -96,12 +96,6 @@ export interface DoctorCheckDefinition {
|
|
|
96
96
|
*/
|
|
97
97
|
fix?: string;
|
|
98
98
|
}
|
|
99
|
-
/**
|
|
100
|
-
* Resolves a {@link DoctorCheck} to its effective severity. `severity` is the
|
|
101
|
-
* single source of truth; this exists so every consumer of a
|
|
102
|
-
* `DoctorCheck[]` reads it the same way.
|
|
103
|
-
*/
|
|
104
|
-
export declare function resolveDoctorSeverity(check: DoctorCheck): 'ok' | 'warning' | 'error';
|
|
105
99
|
/**
|
|
106
100
|
* Builds a DoctorCheck object representing a successful "OK" check.
|
|
107
101
|
*/
|
|
@@ -4,14 +4,6 @@
|
|
|
4
4
|
* `doctor.ts` and sibling check modules. Kept separate so registries can import
|
|
5
5
|
* these symbols without creating cycles through `doctor.ts`.
|
|
6
6
|
*/
|
|
7
|
-
/**
|
|
8
|
-
* Resolves a {@link DoctorCheck} to its effective severity. `severity` is the
|
|
9
|
-
* single source of truth; this exists so every consumer of a
|
|
10
|
-
* `DoctorCheck[]` reads it the same way.
|
|
11
|
-
*/
|
|
12
|
-
export function resolveDoctorSeverity(check) {
|
|
13
|
-
return check.severity;
|
|
14
|
-
}
|
|
15
7
|
/**
|
|
16
8
|
* Builds a DoctorCheck object representing a successful "OK" check.
|
|
17
9
|
*/
|
|
@@ -15,8 +15,8 @@ async function resolveDeclaredTool(projectRoot, tool) {
|
|
|
15
15
|
return found.exitCode === 0 ? line?.trim() : undefined;
|
|
16
16
|
}
|
|
17
17
|
catch {
|
|
18
|
-
// `xcrun -find` is absent or the tool is unknown
|
|
19
|
-
// no resolvable path, which is what `undefined` means to the caller.
|
|
18
|
+
// `xcrun -find` is absent or the tool is unknown. Either way the tool
|
|
19
|
+
// has no resolvable path, which is what `undefined` means to the caller.
|
|
20
20
|
return undefined;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* "Furnace config sync" doctor check.
|
|
3
3
|
*
|
|
4
4
|
* Surfaces orphaned component directories on disk whose names are missing
|
|
5
|
-
* from `furnace.json
|
|
5
|
+
* from `furnace.json`, typically the concurrent-override race, where two
|
|
6
6
|
* parallel `furnace override` commands both leave their directory on disk
|
|
7
7
|
* but only the second reaches `writeFurnaceConfig`. Under
|
|
8
8
|
* `--repair-furnace`, override orphans are re-registered from the
|
|
9
|
-
* `override.json` sidecar the command wrote during the copy phase
|
|
9
|
+
* `override.json` sidecar the command wrote during the copy phase. Custom
|
|
10
10
|
* orphans are listed for the operator to either re-run `furnace create`
|
|
11
11
|
* against or delete manually, because custom components have no similar
|
|
12
12
|
* persisted metadata.
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* "Furnace config sync" doctor check.
|
|
4
4
|
*
|
|
5
5
|
* Surfaces orphaned component directories on disk whose names are missing
|
|
6
|
-
* from `furnace.json
|
|
6
|
+
* from `furnace.json`, typically the concurrent-override race, where two
|
|
7
7
|
* parallel `furnace override` commands both leave their directory on disk
|
|
8
8
|
* but only the second reaches `writeFurnaceConfig`. Under
|
|
9
9
|
* `--repair-furnace`, override orphans are re-registered from the
|
|
10
|
-
* `override.json` sidecar the command wrote during the copy phase
|
|
10
|
+
* `override.json` sidecar the command wrote during the copy phase. Custom
|
|
11
11
|
* orphans are listed for the operator to either re-run `furnace create`
|
|
12
12
|
* against or delete manually, because custom components have no similar
|
|
13
13
|
* persisted metadata.
|
|
@@ -32,10 +32,10 @@ import { failure, ok, warning } from './doctor-check-core.js';
|
|
|
32
32
|
* to catch. The caller surfaces the failure instead.
|
|
33
33
|
*/
|
|
34
34
|
async function listComponentDirs(dir) {
|
|
35
|
-
// `pathExistsStrict`, not `pathExists`: the latter answers `false` for
|
|
35
|
+
// `pathExistsStrict`, not `pathExists`: the latter answers `false` for every
|
|
36
36
|
// access error, so an unreadable components directory reported "no orphans",
|
|
37
|
-
// i.e. a clean check
|
|
38
|
-
// `readdir`. Only ENOENT means genuinely absent.
|
|
37
|
+
// i.e. a clean check. That is the same fail-open the comment above rejects
|
|
38
|
+
// for `readdir`. Only ENOENT means genuinely absent.
|
|
39
39
|
if (!(await pathExistsStrict(dir)))
|
|
40
40
|
return [];
|
|
41
41
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
@@ -48,7 +48,7 @@ async function recoverOverrideConfig(overrideDir, name) {
|
|
|
48
48
|
// outer-snapshot config and drops the sibling write's addition.
|
|
49
49
|
//
|
|
50
50
|
// No `pathExists` precheck: it collapses "absent" and "unreadable" into
|
|
51
|
-
// the same `false`, and both outcomes lead here anyway
|
|
51
|
+
// the same `false`, and both outcomes lead here anyway. A missing file
|
|
52
52
|
// lands in the catch below with the same `undefined` result.
|
|
53
53
|
const sidecarPath = join(overrideDir, name, 'override.json');
|
|
54
54
|
try {
|
|
@@ -79,7 +79,7 @@ async function recoverOverrideConfig(overrideDir, name) {
|
|
|
79
79
|
catch {
|
|
80
80
|
// Unreadable or malformed sidecar. Returning `undefined` here is the same
|
|
81
81
|
// value as "no sidecar present", so the caller reports the override as
|
|
82
|
-
// unrecoverable
|
|
82
|
+
// unrecoverable. That is the safe direction (it never invents config),
|
|
83
83
|
// but the operator sees "no valid override.json" rather than "the
|
|
84
84
|
// override.json is corrupt". The remediation is identical either way.
|
|
85
85
|
return undefined;
|
|
@@ -125,7 +125,7 @@ function emptyOutcome() {
|
|
|
125
125
|
}
|
|
126
126
|
/**
|
|
127
127
|
* Re-registers override orphans and deletes empty custom orphan directories,
|
|
128
|
-
* under
|
|
128
|
+
* under one furnace lock held across both.
|
|
129
129
|
*
|
|
130
130
|
* Two things this must not do, both of which reproduce the lost-write race the
|
|
131
131
|
* check exists to clean up after:
|
|
@@ -133,9 +133,9 @@ function emptyOutcome() {
|
|
|
133
133
|
* 1. Write back a decision made before the lock. The orphan list is computed
|
|
134
134
|
* from a config snapshot loaded well before we hold anything, so by the
|
|
135
135
|
* time we can write, a concurrent `furnace override` may have registered
|
|
136
|
-
* the same name
|
|
136
|
+
* the same name. Writing our sidecar-reconstructed entry over it discards
|
|
137
137
|
* a live write, and a concurrent `furnace create` registering the name
|
|
138
|
-
* under `custom` would leave it in
|
|
138
|
+
* under `custom` would leave it in both maps, a state nothing validates.
|
|
139
139
|
* Every orphan is therefore re-checked against `freshConfig` inside the
|
|
140
140
|
* lock and skipped when it is no longer orphaned.
|
|
141
141
|
* 2. Delete custom directories outside the lock. `repairCustomOrphans` used to
|
|
@@ -148,12 +148,12 @@ async function repairOrphans(projectRoot, orphans) {
|
|
|
148
148
|
if (orphans.overrides.length === 0 && orphans.customNames.length === 0)
|
|
149
149
|
return outcome;
|
|
150
150
|
const lockPath = getFurnaceLockPath(projectRoot);
|
|
151
|
-
// One catch covers four distinct phases
|
|
152
|
-
// the report honest
|
|
151
|
+
// One catch covers four distinct phases. Naming the one that failed keeps
|
|
152
|
+
// the report honest. A lock timeout otherwise renders as "failed while
|
|
153
153
|
// writing furnace.json", the phase least likely to have been reached.
|
|
154
154
|
// Held in an object rather than two `let`s: the lock callback mutates them
|
|
155
155
|
// from inside a closure, and TS's control-flow analysis does not propagate
|
|
156
|
-
// that through the call
|
|
156
|
+
// that through the call, so it would narrow both to their initial literals
|
|
157
157
|
// in the catch below.
|
|
158
158
|
const progress = { phase: 'waiting for the furnace lock', persisted: false };
|
|
159
159
|
try {
|
|
@@ -165,7 +165,7 @@ async function repairOrphans(projectRoot, orphans) {
|
|
|
165
165
|
progress.phase = 'writing furnace.json';
|
|
166
166
|
await writeFurnaceConfig(projectRoot, freshConfig);
|
|
167
167
|
}
|
|
168
|
-
// From here the restore (if any) is on disk
|
|
168
|
+
// From here the restore (if any) is on disk. A later failure must not
|
|
169
169
|
// report the whole repair as if it never happened.
|
|
170
170
|
progress.persisted = true;
|
|
171
171
|
progress.phase = 'cleaning custom orphan directories';
|
|
@@ -188,11 +188,11 @@ async function repairOrphans(projectRoot, orphans) {
|
|
|
188
188
|
}
|
|
189
189
|
return outcome;
|
|
190
190
|
}
|
|
191
|
-
/** Override half of {@link repairOrphans}
|
|
191
|
+
/** Override half of {@link repairOrphans}. Mutates `freshConfig` in place. */
|
|
192
192
|
function repairOverridesLocked(freshConfig, orphans, outcome) {
|
|
193
193
|
for (const orphan of orphans) {
|
|
194
194
|
if (orphan.name in freshConfig.overrides || orphan.name in freshConfig.custom) {
|
|
195
|
-
// Registered while we waited for the lock
|
|
195
|
+
// Registered while we waited for the lock, so no longer an orphan, and
|
|
196
196
|
// writing over it would either discard that write or duplicate the name
|
|
197
197
|
// across `overrides` and `custom`.
|
|
198
198
|
outcome.reconciled.push(orphan.name);
|
|
@@ -207,15 +207,15 @@ function repairOverridesLocked(freshConfig, orphans, outcome) {
|
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
|
-
/** Custom half of {@link repairOrphans}
|
|
210
|
+
/** Custom half of {@link repairOrphans}. Must run under the same lock. */
|
|
211
211
|
async function deleteEmptyCustomOrphans(projectRoot, freshConfig, customNames, outcome) {
|
|
212
212
|
if (customNames.length === 0)
|
|
213
213
|
return;
|
|
214
214
|
const furnacePaths = getFurnacePaths(projectRoot);
|
|
215
215
|
for (const name of customNames) {
|
|
216
216
|
if (name in freshConfig.custom || name in freshConfig.overrides) {
|
|
217
|
-
// A name
|
|
218
|
-
// per tree
|
|
217
|
+
// A name orphaned in both trees is reconciled once rather than once
|
|
218
|
+
// per tree. The report reads "Skipped 2 names (x, x)" otherwise.
|
|
219
219
|
if (!outcome.reconciled.includes(name))
|
|
220
220
|
outcome.reconciled.push(name);
|
|
221
221
|
continue;
|
|
@@ -237,7 +237,7 @@ async function deleteEmptyCustomOrphans(projectRoot, freshConfig, customNames, o
|
|
|
237
237
|
// `rmdir`, not `rm`: `rm` without `{ recursive: true }` throws EISDIR on
|
|
238
238
|
// a directory, so on a real filesystem this branch always failed and the
|
|
239
239
|
// "deleted N empty directories" report was unreachable. `rmdir` is also
|
|
240
|
-
// the exact semantics wanted here
|
|
240
|
+
// the exact semantics wanted here: it refuses a non-empty directory,
|
|
241
241
|
// which keeps the emptiness check above from being the only safeguard.
|
|
242
242
|
await rmdir(dir);
|
|
243
243
|
outcome.deleted.push(name);
|
|
@@ -8,7 +8,7 @@ import type { DoctorCheckDefinition } from './doctor-check-core.js';
|
|
|
8
8
|
/**
|
|
9
9
|
* "Furnace jar.mn registrations" check: detect widget registration lines
|
|
10
10
|
* pointing at component files that no longer exist in the workspace,
|
|
11
|
-
* typically left by a rename. These break `mach build` at packaging
|
|
11
|
+
* typically left by a rename. These break `mach build` at packaging.
|
|
12
12
|
* `--repair-furnace` prunes them.
|
|
13
13
|
*/
|
|
14
14
|
export declare const furnaceStaleJarRegistrationCheck: DoctorCheckDefinition;
|
|
@@ -12,7 +12,7 @@ import { failure, ok, warning } from './doctor-check-core.js';
|
|
|
12
12
|
/**
|
|
13
13
|
* "Furnace jar.mn registrations" check: detect widget registration lines
|
|
14
14
|
* pointing at component files that no longer exist in the workspace,
|
|
15
|
-
* typically left by a rename. These break `mach build` at packaging
|
|
15
|
+
* typically left by a rename. These break `mach build` at packaging.
|
|
16
16
|
* `--repair-furnace` prunes them.
|
|
17
17
|
*/
|
|
18
18
|
export const furnaceStaleJarRegistrationCheck = {
|
|
@@ -50,7 +50,7 @@ async function clearPendingRepairMarker(projectRoot) {
|
|
|
50
50
|
* `stock` and name is the tag name.
|
|
51
51
|
*
|
|
52
52
|
* Stock components are never checksummed by apply, so they never appear
|
|
53
|
-
* in the state file
|
|
53
|
+
* in the state file, so any stock-prefixed entry is automatically stale.
|
|
54
54
|
*/
|
|
55
55
|
function collectStaleChecksumKeys(appliedChecksums, config) {
|
|
56
56
|
const stale = [];
|
|
@@ -103,7 +103,7 @@ async function collectFurnaceDrift(projectRoot, engineDir, config, ftlDir) {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
catch {
|
|
106
|
-
// Drift check throws on unreadable paths
|
|
106
|
+
// Drift check throws on unreadable paths. Treat as drift so the
|
|
107
107
|
// operator is told to run apply rather than swallowing the error.
|
|
108
108
|
drifted.push(name);
|
|
109
109
|
}
|
|
@@ -120,9 +120,9 @@ async function collectFurnaceDrift(projectRoot, engineDir, config, ftlDir) {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
catch {
|
|
123
|
-
// A drift probe that cannot complete is reported
|
|
124
|
-
// must not claim a component is clean when it failed to look.
|
|
125
|
-
// documented twin above.
|
|
123
|
+
// A drift probe that cannot complete is reported as drift: the doctor
|
|
124
|
+
// check must not claim a component is clean when it failed to look.
|
|
125
|
+
// Mirrors the documented twin above.
|
|
126
126
|
drifted.push(name);
|
|
127
127
|
}
|
|
128
128
|
}
|
|
@@ -182,7 +182,7 @@ const furnaceStateConsistencyCheck = {
|
|
|
182
182
|
}
|
|
183
183
|
const ghostSet = new Set();
|
|
184
184
|
for (const key of staleKeys) {
|
|
185
|
-
// Keys look like "override/<name>/<file>"
|
|
185
|
+
// Keys look like "override/<name>/<file>", so the ghost component is
|
|
186
186
|
// the first two segments joined for display purposes.
|
|
187
187
|
const segments = key.split('/');
|
|
188
188
|
if (segments.length >= 2) {
|
|
@@ -214,14 +214,14 @@ const furnaceStateConsistencyCheck = {
|
|
|
214
214
|
};
|
|
215
215
|
/**
|
|
216
216
|
* "Furnace engine state" check: detect the `pendingRepair` marker set by
|
|
217
|
-
* a failed preview teardown
|
|
217
|
+
* a failed preview teardown and any on-disk drift between the workspace
|
|
218
218
|
* and the engine. Repair runs `applyAllComponents` to reconcile and
|
|
219
219
|
* clears the marker on success.
|
|
220
220
|
*/
|
|
221
221
|
const furnaceEngineStateCheck = {
|
|
222
222
|
name: 'Furnace engine state',
|
|
223
223
|
dependsOn: ['Furnace configuration'],
|
|
224
|
-
// Requires both a furnace project
|
|
224
|
+
// Requires both a furnace project and an engine checkout: the drift
|
|
225
225
|
// oracles resolve engine paths, so a missing engine dir would throw.
|
|
226
226
|
skipIf: (ctx) => !ctx.furnaceConfigExists || !ctx.furnaceConfig || !ctx.engineExists,
|
|
227
227
|
run: async (ctx) => {
|
|
@@ -286,16 +286,16 @@ const furnaceEngineStateCheck = {
|
|
|
286
286
|
}
|
|
287
287
|
// Repair path: run apply to reconcile the engine with the workspace
|
|
288
288
|
// state, then clear the pendingRepair marker on success. We re-run
|
|
289
|
-
// apply even when only the marker is set
|
|
290
|
-
// specifically because the last mutation could not clean up, so
|
|
291
|
-
// cheapest honest thing
|
|
289
|
+
// apply even when only the marker is set. The marker exists
|
|
290
|
+
// specifically because the last mutation could not clean up, so
|
|
291
|
+
// re-reconciling end-to-end is the cheapest honest thing to do.
|
|
292
292
|
try {
|
|
293
293
|
const applyResult = await runRepairApply(ctx.projectRoot);
|
|
294
294
|
const totalFailures = countApplyFailures(applyResult);
|
|
295
295
|
if (totalFailures > 0) {
|
|
296
296
|
return failure('Furnace engine state', `Repair attempted but apply reported ${totalFailures} failure${totalFailures === 1 ? '' : 's'} (first: ${firstApplyFailure(applyResult)}).`, 'Fix the underlying component issue and retry the doctor command.');
|
|
297
297
|
}
|
|
298
|
-
// Apply succeeded
|
|
298
|
+
// Apply succeeded, so clear the pendingRepair marker so subsequent
|
|
299
299
|
// doctor runs stop reporting the issue. updateFurnaceState merges
|
|
300
300
|
// its return value via `validateFurnaceState` which simply writes
|
|
301
301
|
// whatever object we return, so dropping the key from the spread
|
|
@@ -356,9 +356,9 @@ const furnaceEnginePathsCheck = {
|
|
|
356
356
|
/**
|
|
357
357
|
* Furnace Storybook backend check: verifies that the engine contains the
|
|
358
358
|
* Storybook workspace required by `furnace preview`. Missing Storybook
|
|
359
|
-
* support is a warning
|
|
360
|
-
* preview
|
|
361
|
-
* mid-command.
|
|
359
|
+
* support is a warning rather than a failure, since furnace works fine
|
|
360
|
+
* without preview. Operators should still know upfront rather than
|
|
361
|
+
* discovering it mid-command.
|
|
362
362
|
*/
|
|
363
363
|
const furnaceStorybookCheck = {
|
|
364
364
|
name: 'Furnace Storybook backend',
|
|
@@ -422,7 +422,7 @@ const furnaceComponentValidationCheck = {
|
|
|
422
422
|
/**
|
|
423
423
|
* Reads the owner PID from a furnace lock directory. Returns `null` when
|
|
424
424
|
* the PID file is missing, unreadable, or does not parse as a finite
|
|
425
|
-
* integer
|
|
425
|
+
* integer. The caller then falls back to an age-only heuristic.
|
|
426
426
|
*/
|
|
427
427
|
async function readFurnaceLockPid(lockPath) {
|
|
428
428
|
try {
|
|
@@ -443,10 +443,10 @@ async function readFurnaceLockPid(lockPath) {
|
|
|
443
443
|
*
|
|
444
444
|
* This is the recovery path when the signal-handler sweep
|
|
445
445
|
* (`forceReleaseFurnaceLocksForActiveOperations` in `bin/fireforge.ts`)
|
|
446
|
-
* misses
|
|
446
|
+
* misses: a SIGKILL'd process that never ran the handler, or a lock created
|
|
447
447
|
* by an older FireForge release without a PID file. SIGINT'ing `furnace
|
|
448
448
|
* preview` leaves the lock behind, and the next `fireforge test --build`
|
|
449
|
-
* then times out waiting for it
|
|
449
|
+
* then times out waiting for it. `doctor --repair-furnace` clears it so the
|
|
450
450
|
* next command runs immediately.
|
|
451
451
|
*/
|
|
452
452
|
const furnaceStaleLockCheck = {
|
|
@@ -464,12 +464,12 @@ const furnaceStaleLockCheck = {
|
|
|
464
464
|
const ageSuffix = ageMs !== undefined ? ` (age: ${Math.round(ageMs / 1000)}s)` : '';
|
|
465
465
|
// Two signals mark a lock as stale:
|
|
466
466
|
// 1. PID file says owner is dead → unambiguous, remove immediately.
|
|
467
|
-
// 2. PID file absent
|
|
467
|
+
// 2. PID file absent and lock is older than 60s → older FireForge
|
|
468
468
|
// releases (or an externally-created lock directory) fall into this
|
|
469
|
-
// bucket
|
|
469
|
+
// bucket. The age gate avoids false positives on a lock just
|
|
470
470
|
// acquired by a concurrent process that has not written its PID yet.
|
|
471
471
|
//
|
|
472
|
-
// `isProcessAlive` treats EPERM as
|
|
472
|
+
// `isProcessAlive` treats EPERM as alive. Returning false for EPERM
|
|
473
473
|
// reports a furnace lock held by a live process owned by another uid as
|
|
474
474
|
// "owner is no longer running", and --repair-furnace then deletes it,
|
|
475
475
|
// dropping mutual exclusion under a concurrent furnace operation.
|
|
@@ -477,7 +477,7 @@ const furnaceStaleLockCheck = {
|
|
|
477
477
|
const pidMissingAndOld = pid === null && (ageMs ?? 0) > 60_000;
|
|
478
478
|
const isStale = ownerDead || pidMissingAndOld;
|
|
479
479
|
if (!isStale) {
|
|
480
|
-
// Lock is held by a running FireForge process
|
|
480
|
+
// Lock is held by a running FireForge process, so nothing to report.
|
|
481
481
|
return ok('Furnace lock');
|
|
482
482
|
}
|
|
483
483
|
const description = ownerDead
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Doctor check for
|
|
2
|
+
* Doctor check for pre-existing orphaned test-harness workers.
|
|
3
3
|
*
|
|
4
4
|
* A mach invocation that dies at harness startup can strand a Python
|
|
5
|
-
* `multiprocessing` spawn worker plus its resource tracker
|
|
5
|
+
* `multiprocessing` spawn worker plus its resource tracker. The worker
|
|
6
6
|
* reparents to launchd (PPID 1) and busy-spins at 100% CPU indefinitely.
|
|
7
|
-
* The dispatch-side fix is the process-group reaping in `utils/process.ts
|
|
8
|
-
*
|
|
7
|
+
* The dispatch-side fix is the process-group reaping in `utils/process.ts`.
|
|
8
|
+
* This check covers orphans that predate it (or leaked from non-FireForge
|
|
9
9
|
* invocations), detecting them by PPID 1 + large accumulated CPU TIME + a
|
|
10
10
|
* `multiprocessing.spawn`/`resource_tracker` command line.
|
|
11
11
|
*
|
|
12
|
-
* Report-only
|
|
13
|
-
*
|
|
12
|
+
* Report-only: FireForge never kills pre-existing processes it did not
|
|
13
|
+
* spawn, so the check names each candidate and suggests the kill.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* give.
|
|
15
|
+
* Not wired into `test --canary`: a system-wide process scan on the canary
|
|
16
|
+
* hot path buys no coverage the doctor check does not already give.
|
|
18
17
|
*/
|
|
19
18
|
import type { DoctorCheckDefinition } from './doctor-check-core.js';
|
|
20
19
|
/** One process matching the orphaned-harness-worker shape. */
|
|
@@ -27,21 +26,15 @@ export interface OrphanedHarnessWorker {
|
|
|
27
26
|
cpuSeconds: number;
|
|
28
27
|
command: string;
|
|
29
28
|
}
|
|
30
|
-
/**
|
|
31
|
-
* Parses a `ps` TIME (accumulated CPU) value. Implemented in terms of
|
|
32
|
-
* {@link parsePsDuration} — `time=` and `etime=` share one grammar, and a
|
|
33
|
-
* second copy is how the two would drift.
|
|
34
|
-
*/
|
|
35
|
-
export declare function parseCpuTime(time: string): number;
|
|
36
29
|
/**
|
|
37
30
|
* Scans `ps -axo pid=,ppid=,time=,command=` output for orphaned harness
|
|
38
31
|
* workers: PPID 1 (reparented to init/launchd), a multiprocessing
|
|
39
32
|
* worker/tracker command line, and at least `minCpuSeconds` of accumulated
|
|
40
|
-
* CPU time. Pure
|
|
33
|
+
* CPU time. Pure, so it is fixture-testable without spawning anything.
|
|
41
34
|
*/
|
|
42
35
|
export declare function findOrphanedHarnessWorkers(psOutput: string, minCpuSeconds?: number): OrphanedHarnessWorker[];
|
|
43
36
|
/**
|
|
44
|
-
* Doctor check reporting orphaned harness workers. Windows has no `ps
|
|
37
|
+
* Doctor check reporting orphaned harness workers. Windows has no `ps`, so
|
|
45
38
|
* the check is skipped there (best-effort platform gap, matching the
|
|
46
39
|
* process-group reaper's POSIX-only sweep).
|
|
47
40
|
*/
|