@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
|
@@ -4,15 +4,15 @@ import { join } from 'node:path';
|
|
|
4
4
|
import { applyAllComponents } from '../core/furnace-apply.js';
|
|
5
5
|
import { hasCustomEngineDrift, hasOverrideEngineDrift } from '../core/furnace-apply-helpers.js';
|
|
6
6
|
import { getFurnacePaths, loadFurnaceConfig, loadFurnaceState, updateFurnaceState, } from '../core/furnace-config.js';
|
|
7
|
-
import { CUSTOM_ELEMENTS_JS, JAR_MN, resolveFtlDir } from '../core/furnace-constants.js';
|
|
7
|
+
import { CUSTOM_ELEMENTS_JS, JAR_MN, resolveFtlDir, WIDGETS_DIR, } from '../core/furnace-constants.js';
|
|
8
8
|
import { getFurnaceLockPath, runFurnaceMutation } from '../core/furnace-operation.js';
|
|
9
9
|
import { hasBlockingStepErrors } from '../core/furnace-step-errors.js';
|
|
10
10
|
import { validateAllComponents } from '../core/furnace-validate.js';
|
|
11
11
|
import { isProcessAlive, toError } from '../utils/errors.js';
|
|
12
12
|
import { pathExists } from '../utils/fs.js';
|
|
13
13
|
import { failure, ok, warning } from './doctor-check-core.js';
|
|
14
|
+
import { furnaceConfigSyncCheck } from './doctor-furnace-config-sync.js';
|
|
14
15
|
import { furnaceStaleJarRegistrationCheck } from './doctor-furnace-jar.js';
|
|
15
|
-
import { furnaceManifestSyncCheck } from './doctor-furnace-manifest-sync.js';
|
|
16
16
|
const ENGINE_REPAIRABLE_OPERATIONS = [
|
|
17
17
|
'preview-teardown',
|
|
18
18
|
'apply-rollback',
|
|
@@ -98,7 +98,7 @@ async function collectFurnaceDrift(projectRoot, engineDir, config, ftlDir) {
|
|
|
98
98
|
continue;
|
|
99
99
|
}
|
|
100
100
|
try {
|
|
101
|
-
if (await hasOverrideEngineDrift(engineDir, componentDir,
|
|
101
|
+
if (await hasOverrideEngineDrift({ engineDir, componentDir, ftlDir }, overrideConfig)) {
|
|
102
102
|
drifted.push(name);
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -115,7 +115,7 @@ async function collectFurnaceDrift(projectRoot, engineDir, config, ftlDir) {
|
|
|
115
115
|
continue;
|
|
116
116
|
}
|
|
117
117
|
try {
|
|
118
|
-
if (await hasCustomEngineDrift(projectRoot, name, componentDir,
|
|
118
|
+
if (await hasCustomEngineDrift({ root: projectRoot, name, componentDir, ftlDir }, customConfig)) {
|
|
119
119
|
drifted.push(name);
|
|
120
120
|
}
|
|
121
121
|
}
|
|
@@ -336,7 +336,7 @@ const furnaceEnginePathsCheck = {
|
|
|
336
336
|
const expectedPaths = [
|
|
337
337
|
CUSTOM_ELEMENTS_JS,
|
|
338
338
|
JAR_MN,
|
|
339
|
-
|
|
339
|
+
WIDGETS_DIR,
|
|
340
340
|
resolveFtlDir(ctx.furnaceConfig?.ftlBasePath),
|
|
341
341
|
...hostDocs,
|
|
342
342
|
];
|
|
@@ -437,18 +437,17 @@ async function readFurnaceLockPid(lockPath) {
|
|
|
437
437
|
}
|
|
438
438
|
}
|
|
439
439
|
/**
|
|
440
|
-
* "Furnace stale lock" check: detect and (under `--repair-furnace`)
|
|
441
|
-
*
|
|
442
|
-
*
|
|
440
|
+
* "Furnace stale lock" check: detect and (under `--repair-furnace`) remove a
|
|
441
|
+
* `.fireforge/furnace.lock` directory whose owner process is no longer
|
|
442
|
+
* alive.
|
|
443
443
|
*
|
|
444
444
|
* This is the recovery path when the signal-handler sweep
|
|
445
445
|
* (`forceReleaseFurnaceLocksForActiveOperations` in `bin/fireforge.ts`)
|
|
446
|
-
* misses —
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
* command runs immediately.
|
|
446
|
+
* misses — a SIGKILL'd process that never ran the handler, or a lock created
|
|
447
|
+
* by an older FireForge release without a PID file. SIGINT'ing `furnace
|
|
448
|
+
* preview` leaves the lock behind, and the next `fireforge test --build`
|
|
449
|
+
* then times out waiting for it; `doctor --repair-furnace` clears it so the
|
|
450
|
+
* next command runs immediately.
|
|
452
451
|
*/
|
|
453
452
|
const furnaceStaleLockCheck = {
|
|
454
453
|
name: 'Furnace lock',
|
|
@@ -466,16 +465,14 @@ const furnaceStaleLockCheck = {
|
|
|
466
465
|
// Two signals mark a lock as stale:
|
|
467
466
|
// 1. PID file says owner is dead → unambiguous, remove immediately.
|
|
468
467
|
// 2. PID file absent AND lock is older than 60s → older FireForge
|
|
469
|
-
// releases (or an externally-created lock directory) fall into
|
|
470
|
-
//
|
|
471
|
-
//
|
|
472
|
-
// written its PID yet.
|
|
468
|
+
// releases (or an externally-created lock directory) fall into this
|
|
469
|
+
// bucket; the age gate avoids false positives on a lock just
|
|
470
|
+
// acquired by a concurrent process that has not written its PID yet.
|
|
473
471
|
//
|
|
474
|
-
// `isProcessAlive` treats EPERM as ALIVE.
|
|
475
|
-
//
|
|
476
|
-
//
|
|
477
|
-
//
|
|
478
|
-
// concurrent furnace operation.
|
|
472
|
+
// `isProcessAlive` treats EPERM as ALIVE. Returning false for EPERM
|
|
473
|
+
// reports a furnace lock held by a live process owned by another uid as
|
|
474
|
+
// "owner is no longer running", and --repair-furnace then deletes it,
|
|
475
|
+
// dropping mutual exclusion under a concurrent furnace operation.
|
|
479
476
|
const ownerDead = pid !== null && !isProcessAlive(pid);
|
|
480
477
|
const pidMissingAndOld = pid === null && (ageMs ?? 0) > 60_000;
|
|
481
478
|
const isStale = ownerDead || pidMissingAndOld;
|
|
@@ -513,5 +510,5 @@ export const FURNACE_DOCTOR_CHECKS = [
|
|
|
513
510
|
furnaceStaleLockCheck,
|
|
514
511
|
furnaceEngineStateCheck,
|
|
515
512
|
furnaceComponentValidationCheck,
|
|
516
|
-
|
|
513
|
+
furnaceConfigSyncCheck,
|
|
517
514
|
];
|
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Doctor check for PRE-EXISTING orphaned test-harness workers
|
|
3
|
-
* item 9b).
|
|
2
|
+
* Doctor check for PRE-EXISTING orphaned test-harness workers.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* accumulated CPU TIME + a `multiprocessing.spawn`/`resource_tracker`
|
|
13
|
-
* command line.
|
|
4
|
+
* A mach invocation that dies at harness startup can strand a Python
|
|
5
|
+
* `multiprocessing` spawn worker plus its resource tracker; the worker
|
|
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
|
+
* this check covers orphans that predate it (or leaked from non-FireForge
|
|
9
|
+
* invocations), detecting them by PPID 1 + large accumulated CPU TIME + a
|
|
10
|
+
* `multiprocessing.spawn`/`resource_tracker` command line.
|
|
14
11
|
*
|
|
15
|
-
* Report-only by design: FireForge never kills pre-existing processes it
|
|
16
|
-
*
|
|
12
|
+
* Report-only by design: FireForge never kills pre-existing processes it did
|
|
13
|
+
* not spawn — the check names each candidate and suggests the kill.
|
|
17
14
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
15
|
+
* Deliberately not wired into `test --canary`: a system-wide process scan on
|
|
16
|
+
* the canary hot path buys no coverage the doctor check does not already
|
|
17
|
+
* give.
|
|
21
18
|
*/
|
|
22
19
|
import type { DoctorCheckDefinition } from './doctor-check-core.js';
|
|
23
20
|
/** One process matching the orphaned-harness-worker shape. */
|
|
@@ -31,10 +28,9 @@ export interface OrphanedHarnessWorker {
|
|
|
31
28
|
command: string;
|
|
32
29
|
}
|
|
33
30
|
/**
|
|
34
|
-
* Parses a `ps` TIME value in
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* Returns NaN for unrecognized shapes.
|
|
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.
|
|
38
34
|
*/
|
|
39
35
|
export declare function parseCpuTime(time: string): number;
|
|
40
36
|
/**
|
|
@@ -1,27 +1,25 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
/**
|
|
3
|
-
* Doctor check for PRE-EXISTING orphaned test-harness workers
|
|
4
|
-
* item 9b).
|
|
3
|
+
* Doctor check for PRE-EXISTING orphaned test-harness workers.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* accumulated CPU TIME + a `multiprocessing.spawn`/`resource_tracker`
|
|
14
|
-
* command line.
|
|
5
|
+
* A mach invocation that dies at harness startup can strand a Python
|
|
6
|
+
* `multiprocessing` spawn worker plus its resource tracker; the worker
|
|
7
|
+
* reparents to launchd (PPID 1) and busy-spins at 100% CPU indefinitely.
|
|
8
|
+
* The dispatch-side fix is the process-group reaping in `utils/process.ts`;
|
|
9
|
+
* this check covers orphans that predate it (or leaked from non-FireForge
|
|
10
|
+
* invocations), detecting them by PPID 1 + large accumulated CPU TIME + a
|
|
11
|
+
* `multiprocessing.spawn`/`resource_tracker` command line.
|
|
15
12
|
*
|
|
16
|
-
* Report-only by design: FireForge never kills pre-existing processes it
|
|
17
|
-
*
|
|
13
|
+
* Report-only by design: FireForge never kills pre-existing processes it did
|
|
14
|
+
* not spawn — the check names each candidate and suggests the kill.
|
|
18
15
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
16
|
+
* Deliberately not wired into `test --canary`: a system-wide process scan on
|
|
17
|
+
* the canary hot path buys no coverage the doctor check does not already
|
|
18
|
+
* give.
|
|
22
19
|
*/
|
|
23
20
|
import { toError } from '../utils/errors.js';
|
|
24
21
|
import { exec } from '../utils/process.js';
|
|
22
|
+
import { parsePsDuration } from '../utils/ps-duration.js';
|
|
25
23
|
import { ok, warning } from './doctor-check-core.js';
|
|
26
24
|
/**
|
|
27
25
|
* Command-line shapes of Python multiprocessing helper processes: the
|
|
@@ -32,36 +30,12 @@ const HARNESS_WORKER_COMMAND_PATTERN = /multiprocessing\.(?:spawn|forkserver)\b|
|
|
|
32
30
|
/** Minimum accumulated CPU time before a match is reported (10 minutes). */
|
|
33
31
|
const DEFAULT_MIN_CPU_SECONDS = 600;
|
|
34
32
|
/**
|
|
35
|
-
* Parses a `ps` TIME value in
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* Returns NaN for unrecognized shapes.
|
|
33
|
+
* Parses a `ps` TIME (accumulated CPU) value. Implemented in terms of
|
|
34
|
+
* {@link parsePsDuration} — `time=` and `etime=` share one grammar, and a
|
|
35
|
+
* second copy is how the two would drift.
|
|
39
36
|
*/
|
|
40
37
|
export function parseCpuTime(time) {
|
|
41
|
-
|
|
42
|
-
let days = 0;
|
|
43
|
-
let rest = trimmed;
|
|
44
|
-
const dayMatch = /^(\d+)-(.*)$/.exec(trimmed);
|
|
45
|
-
if (dayMatch) {
|
|
46
|
-
days = Number(dayMatch[1]);
|
|
47
|
-
rest = dayMatch[2] ?? '';
|
|
48
|
-
}
|
|
49
|
-
const parts = rest.split(':');
|
|
50
|
-
if (parts.length === 3) {
|
|
51
|
-
// hh:mm:ss (linux; seconds may not carry fractions but tolerate them)
|
|
52
|
-
const [h, m, s] = parts.map(Number);
|
|
53
|
-
if ([h, m, s].some((n) => Number.isNaN(n)))
|
|
54
|
-
return NaN;
|
|
55
|
-
return days * 86400 + (h ?? 0) * 3600 + (m ?? 0) * 60 + (s ?? 0);
|
|
56
|
-
}
|
|
57
|
-
if (parts.length === 2) {
|
|
58
|
-
// mm:ss.cc (darwin — the minutes field accumulates without wrapping)
|
|
59
|
-
const [m, s] = parts.map(Number);
|
|
60
|
-
if ([m, s].some((n) => Number.isNaN(n)))
|
|
61
|
-
return NaN;
|
|
62
|
-
return days * 86400 + (m ?? 0) * 60 + (s ?? 0);
|
|
63
|
-
}
|
|
64
|
-
return NaN;
|
|
38
|
+
return parsePsDuration(time);
|
|
65
39
|
}
|
|
66
40
|
/**
|
|
67
41
|
* Scans `ps -axo pid=,ppid=,time=,command=` output for orphaned harness
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
import { readdir } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
-
import { toError } from '
|
|
5
|
-
import { pathExists, readText } from '
|
|
6
|
-
import { ok, warning } from '
|
|
4
|
+
import { toError } from '../utils/errors.js';
|
|
5
|
+
import { pathExists, readText } from '../utils/fs.js';
|
|
6
|
+
import { ok, warning } from './doctor-check-core.js';
|
|
7
7
|
async function readEngineText(engineDir, relativePath) {
|
|
8
8
|
const fullPath = join(engineDir, relativePath);
|
|
9
9
|
if (!(await pathExists(fullPath)))
|
|
@@ -12,18 +12,16 @@
|
|
|
12
12
|
import type { DoctorCheck } from '../types/commands/index.js';
|
|
13
13
|
import type { DoctorCheckContext } from './doctor-check-core.js';
|
|
14
14
|
/**
|
|
15
|
-
* Inspects the engine working tree and returns a single
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* `fireforge
|
|
15
|
+
* Inspects the engine working tree and returns a single `DoctorCheck`.
|
|
16
|
+
* Ownership-aware: patch-backed / branding / furnace rows are reported as OK
|
|
17
|
+
* with an ownership summary; unmanaged drift warns; cross-patch conflicts
|
|
18
|
+
* warn loudly with a pointer at `fireforge status --ownership` +
|
|
19
|
+
* `fireforge verify`.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* import). Returns `undefined` when the worktree is clean so the
|
|
27
|
-
* caller can emit its own ok() row.
|
|
21
|
+
* Ownership is what makes the advice safe: warning on every dirty row and
|
|
22
|
+
* telling the operator to export/discard/reset is actively destructive on a
|
|
23
|
+
* patch-backed import, where the suggested fix would drop the entire patch
|
|
24
|
+
* stack. Returns `undefined` when the worktree is clean so the caller can
|
|
25
|
+
* emit its own ok() row.
|
|
28
26
|
*/
|
|
29
27
|
export declare function inspectEngineWorkingTree(ctx: DoctorCheckContext): Promise<DoctorCheck | undefined>;
|
|
@@ -28,19 +28,17 @@ function formatManagedDetail(counts) {
|
|
|
28
28
|
.join(', ');
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
* Inspects the engine working tree and returns a single
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* `fireforge
|
|
31
|
+
* Inspects the engine working tree and returns a single `DoctorCheck`.
|
|
32
|
+
* Ownership-aware: patch-backed / branding / furnace rows are reported as OK
|
|
33
|
+
* with an ownership summary; unmanaged drift warns; cross-patch conflicts
|
|
34
|
+
* warn loudly with a pointer at `fireforge status --ownership` +
|
|
35
|
+
* `fireforge verify`.
|
|
36
36
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* import). Returns `undefined` when the worktree is clean so the
|
|
43
|
-
* caller can emit its own ok() row.
|
|
37
|
+
* Ownership is what makes the advice safe: warning on every dirty row and
|
|
38
|
+
* telling the operator to export/discard/reset is actively destructive on a
|
|
39
|
+
* patch-backed import, where the suggested fix would drop the entire patch
|
|
40
|
+
* stack. Returns `undefined` when the worktree is clean so the caller can
|
|
41
|
+
* emit its own ok() row.
|
|
44
42
|
*/
|
|
45
43
|
export async function inspectEngineWorkingTree(ctx) {
|
|
46
44
|
const { paths } = ctx;
|
|
@@ -82,12 +80,7 @@ export async function inspectEngineWorkingTree(ctx) {
|
|
|
82
80
|
const managedTotal = counts.branding + counts.furnace + counts.patchBacked + counts.patchOwnedDrift;
|
|
83
81
|
if (counts.unmanaged === 0) {
|
|
84
82
|
const managedDetail = formatManagedDetail(counts);
|
|
85
|
-
return {
|
|
86
|
-
name: 'Engine working tree',
|
|
87
|
-
passed: true,
|
|
88
|
-
severity: 'ok',
|
|
89
|
-
message: `${managedTotal} tool-managed change${managedTotal === 1 ? '' : 's'} (${managedDetail}), 0 unmanaged. Use "fireforge status --ownership" for details.`,
|
|
90
|
-
};
|
|
83
|
+
return ok('Engine working tree', `${managedTotal} tool-managed change${managedTotal === 1 ? '' : 's'} (${managedDetail}), 0 unmanaged. Use "fireforge status --ownership" for details.`);
|
|
91
84
|
}
|
|
92
85
|
const managedTail = managedTotal > 0
|
|
93
86
|
? ` (${managedTotal} other change${managedTotal === 1 ? '' : 's'} are tool-managed: ${formatManagedDetail(counts)}).`
|
|
@@ -11,12 +11,13 @@ import { ExitCode } from '../errors/codes.js';
|
|
|
11
11
|
import { toError } from '../utils/errors.js';
|
|
12
12
|
import { pathExists } from '../utils/fs.js';
|
|
13
13
|
import { error, info, intro, outro, success, warn } from '../utils/logger.js';
|
|
14
|
+
import { addWaitLockOption, resolveWaitLockSeconds } from '../utils/options.js';
|
|
14
15
|
import { findExecutable } from '../utils/process.js';
|
|
15
|
-
import { POST_REBASE_AUDIT_CHECK } from './doctor/post-rebase-audit.js';
|
|
16
16
|
import { failure, ok, resolveDoctorSeverity, warning } from './doctor-check-core.js';
|
|
17
17
|
import { EXTERNAL_TOOLCHAIN_DOCTOR_CHECK } from './doctor-external-toolchains.js';
|
|
18
18
|
import { FURNACE_DOCTOR_CHECKS } from './doctor-furnace.js';
|
|
19
19
|
import { ORPHANED_HARNESS_DOCTOR_CHECK } from './doctor-orphaned-harness.js';
|
|
20
|
+
import { POST_REBASE_AUDIT_CHECK } from './doctor-post-rebase-audit.js';
|
|
20
21
|
import { inspectEngineWorkingTree } from './doctor-working-tree.js';
|
|
21
22
|
import { collectPatchQueueHealth } from './verify.js';
|
|
22
23
|
/**
|
|
@@ -236,31 +237,21 @@ const DOCTOR_CHECKS = [
|
|
|
236
237
|
fix: 'Firefox source may be corrupted. Re-download with "fireforge download --force"',
|
|
237
238
|
},
|
|
238
239
|
{
|
|
239
|
-
// `fireforge watch` has an undeclared hard dependency on watchman
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
// watchman should not fail `doctor` outright, but the information
|
|
245
|
-
// needs to be visible ahead of time rather than at the watch-mode
|
|
246
|
-
// failure site.
|
|
240
|
+
// `fireforge watch` has an undeclared hard dependency on watchman, and
|
|
241
|
+
// without a doctor row operators only discover the gap when they try to
|
|
242
|
+
// start watch mode. Warning severity is the right shape: most projects
|
|
243
|
+
// never run watch, so a missing watchman should not fail `doctor`
|
|
244
|
+
// outright, but the information needs to be visible ahead of time.
|
|
247
245
|
name: 'Watchman available',
|
|
248
246
|
run: async () => {
|
|
249
247
|
// Resolve the absolute path so the OK row names what doctor actually
|
|
250
|
-
// found.
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
// subprocess, and surfacing the resolved path makes the discrepancy
|
|
255
|
-
// visible without users having to re-run with a verbose flag.
|
|
248
|
+
// found. A PATH-export discrepancy between the operator's interactive
|
|
249
|
+
// shell and the spawned subprocess otherwise reads as doctor printing
|
|
250
|
+
// "OK" for a binary `which watchman` cannot find; surfacing the
|
|
251
|
+
// resolved path makes the discrepancy visible without a verbose flag.
|
|
256
252
|
const path = await findExecutable('watchman');
|
|
257
253
|
if (path) {
|
|
258
|
-
return {
|
|
259
|
-
name: 'Watchman available',
|
|
260
|
-
passed: true,
|
|
261
|
-
severity: 'ok',
|
|
262
|
-
message: `OK (${path})`,
|
|
263
|
-
};
|
|
254
|
+
return ok('Watchman available', `OK (${path})`);
|
|
264
255
|
}
|
|
265
256
|
return warning('Watchman available', 'watchman is not installed or not on PATH. "fireforge watch" requires it.', 'Install watchman (brew install watchman / dnf install watchman / https://facebook.github.io/watchman/), then re-run doctor.');
|
|
266
257
|
},
|
|
@@ -270,12 +261,7 @@ const DOCTOR_CHECKS = [
|
|
|
270
261
|
name: 'Patches directory exists',
|
|
271
262
|
run: async (ctx) => {
|
|
272
263
|
const patchesExist = await pathExists(ctx.paths.patches);
|
|
273
|
-
return
|
|
274
|
-
name: 'Patches directory exists',
|
|
275
|
-
passed: true,
|
|
276
|
-
severity: 'ok',
|
|
277
|
-
message: patchesExist ? 'OK' : 'No patches/ directory (optional)',
|
|
278
|
-
};
|
|
264
|
+
return ok('Patches directory exists', patchesExist ? 'OK' : 'No patches/ directory (optional)');
|
|
279
265
|
},
|
|
280
266
|
},
|
|
281
267
|
{
|
|
@@ -285,12 +271,7 @@ const DOCTOR_CHECKS = [
|
|
|
285
271
|
return [];
|
|
286
272
|
}
|
|
287
273
|
const patchCount = await countPatches(ctx.paths.patches);
|
|
288
|
-
return {
|
|
289
|
-
name: 'Patches found',
|
|
290
|
-
passed: true,
|
|
291
|
-
severity: 'ok',
|
|
292
|
-
message: `${patchCount} patch${patchCount === 1 ? '' : 'es'} found`,
|
|
293
|
-
};
|
|
274
|
+
return ok('Patches found', `${patchCount} patch${patchCount === 1 ? '' : 'es'} found`);
|
|
294
275
|
},
|
|
295
276
|
},
|
|
296
277
|
{
|
|
@@ -316,25 +297,26 @@ const DOCTOR_CHECKS = [
|
|
|
316
297
|
return failure('Patch manifest consistency', 'Cannot repair patches.json: fireforge.json could not be loaded, so the Firefox version to stamp into recovered manifest entries is unknown.', 'Fix the fireforge.json errors reported above and re-run "fireforge doctor --repair-patches-manifest".');
|
|
317
298
|
}
|
|
318
299
|
try {
|
|
319
|
-
const repaired = await rebuildPatchesManifest(ctx.paths.patches, ctx.config.firefox.version
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
//
|
|
300
|
+
const repaired = await rebuildPatchesManifest(ctx.paths.patches, ctx.config.firefox.version, {
|
|
301
|
+
waitLockSeconds: resolveWaitLockSeconds(ctx.options.waitLock),
|
|
302
|
+
command: 'doctor --repair-patches-manifest',
|
|
303
|
+
});
|
|
304
|
+
// The repair path must not silently overwrite human-written
|
|
305
|
+
// descriptions on recovered entries, which leaves the queue less
|
|
306
|
+
// trustworthy as an audit trail. The rebuilder returns the list of
|
|
307
|
+
// filenames whose metadata was entirely invented, named explicitly
|
|
308
|
+
// here so the operator knows which patches to review. Entries that
|
|
309
|
+
// WERE preserved (only `filesAffected` / ordering drifted) are not
|
|
310
|
+
// flagged.
|
|
328
311
|
if (repaired.recoveredFilenames.length > 0) {
|
|
329
312
|
for (const filename of repaired.recoveredFilenames) {
|
|
330
|
-
//
|
|
331
|
-
//
|
|
332
|
-
//
|
|
333
|
-
//
|
|
334
|
-
//
|
|
335
|
-
//
|
|
336
|
-
//
|
|
337
|
-
// metadata and supersedes the mtime-based createdAt stamp.
|
|
313
|
+
// Telling the operator to hand-edit patches.json contradicts the
|
|
314
|
+
// README and downstream docs, which treat the manifest as
|
|
315
|
+
// FireForge-owned. Point at the existing `re-export` / `export`
|
|
316
|
+
// workflow so the fix stays inside the tool: re-exporting the
|
|
317
|
+
// same files with an explicit `--description` overwrites the
|
|
318
|
+
// recovered entry with operator-supplied metadata and supersedes
|
|
319
|
+
// the mtime-based createdAt stamp.
|
|
338
320
|
warn(`Recovered manifest entry for ${filename} with generic description and mtime-based createdAt. ` +
|
|
339
321
|
'Re-export the affected files with `fireforge re-export <filename> --description "<your description>"` ' +
|
|
340
322
|
'(or `fireforge export <paths...> --name <name> --category <category> --description "<your description>"`) ' +
|
|
@@ -468,14 +450,14 @@ export async function doctorCommand(projectRoot, options = {}) {
|
|
|
468
450
|
}
|
|
469
451
|
/** Registers the doctor command on the CLI program. */
|
|
470
452
|
export function registerDoctor(program, { getProjectRoot, withErrorHandling }) {
|
|
471
|
-
program
|
|
453
|
+
const command = program
|
|
472
454
|
.command('doctor')
|
|
473
455
|
.description('Diagnose project issues')
|
|
474
456
|
.option('--repair-patches-manifest', 'Rebuild patches/patches.json from the current patch files before reporting results')
|
|
475
457
|
.option('--repair-furnace', 'Reconcile furnace state: clear stale furnace-state.json entries, re-run furnace apply to fix engine drift, and clear the pending-repair marker set by a failed preview teardown')
|
|
476
458
|
.option('--clear-resolution', 'Clear stale pendingResolution state after the patch queue health check reports no errors')
|
|
477
|
-
.option('--post-rebase-audit', 'Check common registration surfaces after a Firefox source rebase')
|
|
478
|
-
|
|
459
|
+
.option('--post-rebase-audit', 'Check common registration surfaces after a Firefox source rebase');
|
|
460
|
+
addWaitLockOption(command).action(withErrorHandling(async (options) => {
|
|
479
461
|
const result = await doctorCommand(getProjectRoot(), options);
|
|
480
462
|
if (result.exitCode !== 0) {
|
|
481
463
|
process.exitCode = result.exitCode;
|
|
@@ -76,13 +76,12 @@ async function cleanPatchTouchedFiles(engineDir, patchesDir, preExistingDirty) {
|
|
|
76
76
|
}
|
|
77
77
|
/**
|
|
78
78
|
* Prints a one-line nudge pointing at `fireforge import` when the project
|
|
79
|
-
* carries a non-empty patch queue but the just-downloaded engine has not
|
|
80
|
-
*
|
|
79
|
+
* carries a non-empty patch queue but the just-downloaded engine has not yet
|
|
80
|
+
* had any patches applied. The post-download spinner closes with
|
|
81
81
|
* "Patch-touched files already match baseline" because a fresh tree IS at
|
|
82
|
-
* baseline,
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* stay quiet.
|
|
82
|
+
* baseline, which reads as "patches are restored" and invites skipping the
|
|
83
|
+
* import step. Suppressed when patches/ is missing or the manifest is empty
|
|
84
|
+
* so unconfigured projects stay quiet.
|
|
86
85
|
*/
|
|
87
86
|
async function noteUnappliedPatches(patchesDir) {
|
|
88
87
|
if (!(await pathExists(patchesDir)))
|
|
@@ -97,12 +96,8 @@ async function noteUnappliedPatches(patchesDir) {
|
|
|
97
96
|
* Stops `restoreSpinner` with a message that reflects what actually
|
|
98
97
|
* happened. Three branches: empty queue → explicit no-op; queue present but
|
|
99
98
|
* nothing dirty → "already clean"; queue with dirty files → the usual
|
|
100
|
-
* "Patch-touched files restored" success line.
|
|
101
|
-
*
|
|
102
|
-
* Before 0.16.0 the spinner always closed with "Patch-touched files
|
|
103
|
-
* restored", so a fresh project with zero patches saw a claim of restore
|
|
104
|
-
* work that had not happened — misleading and easy to mistake for a
|
|
105
|
-
* silent retry.
|
|
99
|
+
* "Patch-touched files restored" success line. Always closing with the third
|
|
100
|
+
* claims restore work that did not happen on a project with zero patches.
|
|
106
101
|
*/
|
|
107
102
|
function closeRestoreSpinner(restoreSpinner, result) {
|
|
108
103
|
if (!result.hadQueue) {
|
|
@@ -192,12 +187,11 @@ async function downloadAndExtractFirefox(args) {
|
|
|
192
187
|
}
|
|
193
188
|
}
|
|
194
189
|
/**
|
|
195
|
-
* Prints the major-version-hop toolchain nudge when this download moved
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* re-downloads.
|
|
190
|
+
* Prints the major-version-hop toolchain nudge when this download moved the
|
|
191
|
+
* engine across a Firefox MAJOR version — the first post-hop build otherwise
|
|
192
|
+
* dies in `mach configure` on a moved cbindgen minimum with nothing in the
|
|
193
|
+
* download output suggesting `fireforge bootstrap`. Quiet on first downloads
|
|
194
|
+
* and same-major re-downloads.
|
|
201
195
|
*/
|
|
202
196
|
function noteMajorVersionHop(previousVersion, version) {
|
|
203
197
|
const hopNotice = formatMajorVersionHopNotice(previousVersion, version);
|
|
@@ -207,9 +201,9 @@ function noteMajorVersionHop(previousVersion, version) {
|
|
|
207
201
|
}
|
|
208
202
|
async function initializeDownloadedEngine(args) {
|
|
209
203
|
const { projectRoot, patchesDir, version, previousVersion, engineDir, replacementActivated, backupEngineDir, } = args;
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
204
|
+
// The git indexing phase of `download` can block for minutes on a ~600 MB
|
|
205
|
+
// Firefox tree. Emit a one-line heads-up banner before the spinner starts
|
|
206
|
+
// so CI logs show the expected duration.
|
|
213
207
|
try {
|
|
214
208
|
info('Indexing downloaded source into git (one-time; typically 3–5 minutes on a ~600 MB Firefox tree)...');
|
|
215
209
|
info('Git phase: initializing/resetting source repository metadata.');
|
|
@@ -280,11 +274,11 @@ export async function downloadCommand(projectRoot, options) {
|
|
|
280
274
|
info(`Firefox version: ${version}`);
|
|
281
275
|
await checkDiskSpace(projectRoot, 5 * 1024 * 1024 * 1024, warn);
|
|
282
276
|
// A legitimate holder of this lock runs for 10+ minutes (download +
|
|
283
|
-
// extract + git indexing).
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
//
|
|
287
|
-
//
|
|
277
|
+
// extract + git indexing). A 30 s timeout fails the second invocation with
|
|
278
|
+
// "remove the lock directory if it is stale" advice while the lock is
|
|
279
|
+
// actively held — dangerous guidance mid-extraction. Wait generously
|
|
280
|
+
// instead: a dead holder is reaped within seconds by the PID-based stale
|
|
281
|
+
// probe, so a long timeout only ever waits on real work.
|
|
288
282
|
const downloadLockOptions = {
|
|
289
283
|
timeoutMs: 30 * 60_000,
|
|
290
284
|
onTimeoutMessage: 'Timed out waiting for another FireForge download to finish. ' +
|
|
@@ -329,11 +323,9 @@ export async function downloadCommand(projectRoot, options) {
|
|
|
329
323
|
// The non-TTY spinner fallback in `src/utils/logger.ts`
|
|
330
324
|
// already calls `p.log.step(msg)` from `message()`, so
|
|
331
325
|
// forwarding the progress message is the single authority
|
|
332
|
-
// in both TTY and non-TTY modes.
|
|
333
|
-
//
|
|
334
|
-
//
|
|
335
|
-
// twice in CI logs (once from the fallback, once from
|
|
336
|
-
// the explicit call).
|
|
326
|
+
// in both TTY and non-TTY modes. Calling `step(message)`
|
|
327
|
+
// explicitly here as well prints the same line twice in
|
|
328
|
+
// CI logs.
|
|
337
329
|
onProgress: (message) => {
|
|
338
330
|
resumeSpinner.message(message);
|
|
339
331
|
},
|
|
@@ -359,17 +351,14 @@ export async function downloadCommand(projectRoot, options) {
|
|
|
359
351
|
}
|
|
360
352
|
catch (error) {
|
|
361
353
|
resumeSpinner.error('Resume failed');
|
|
362
|
-
// Preserve the underlying cause so the
|
|
363
|
-
// resume failed (timeout, permission denied, corrupted
|
|
364
|
-
// disk full
|
|
365
|
-
// exists" story.
|
|
366
|
-
//
|
|
367
|
-
|
|
368
|
-
verbose
|
|
369
|
-
|
|
370
|
-
verbose(cause.stack);
|
|
371
|
-
}
|
|
372
|
-
throw new PartialEngineExistsError(paths.engine, cause);
|
|
354
|
+
// Preserve the underlying cause so the operator sees *why*
|
|
355
|
+
// the resume failed (timeout, permission denied, corrupted
|
|
356
|
+
// object, disk full) instead of only the generic "partial
|
|
357
|
+
// engine exists" story. The cause reaches them through the
|
|
358
|
+
// CLI boundary's chain walk under --verbose (src/cli.ts),
|
|
359
|
+
// which is what makes PartialEngineExistsError's "re-run
|
|
360
|
+
// with --verbose" promise true.
|
|
361
|
+
throw new PartialEngineExistsError(paths.engine, toError(error));
|
|
373
362
|
}
|
|
374
363
|
}
|
|
375
364
|
// Re-throw unexpected git errors (corrupted objects, permission
|
|
@@ -377,12 +366,7 @@ export async function downloadCommand(projectRoot, options) {
|
|
|
377
366
|
// both narratives: "we detected a partial engine and attempted
|
|
378
367
|
// resume" AND the underlying git failure. Without the wrap the
|
|
379
368
|
// raw git error loses the context that resume was in flight.
|
|
380
|
-
|
|
381
|
-
verbose(`Partial-engine probe failed with unexpected error: ${cause.message}`);
|
|
382
|
-
if (cause.stack) {
|
|
383
|
-
verbose(cause.stack);
|
|
384
|
-
}
|
|
385
|
-
throw new PartialEngineExistsError(paths.engine, cause);
|
|
369
|
+
throw new PartialEngineExistsError(paths.engine, toError(error));
|
|
386
370
|
}
|
|
387
371
|
}
|
|
388
372
|
throw new EngineExistsError(paths.engine);
|