@hominis/fireforge 0.46.0 → 0.46.2
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 +381 -498
- package/dist/bin/fireforge.d.ts +1 -1
- package/dist/bin/fireforge.js +17 -17
- package/dist/build-info.json +4 -4
- package/dist/src/cli-usage-error.d.ts +9 -9
- package/dist/src/cli-usage-error.js +12 -12
- package/dist/src/cli.d.ts +3 -2
- package/dist/src/cli.js +29 -28
- package/dist/src/commands/bootstrap-checks.js +2 -1
- package/dist/src/commands/bootstrap.js +2 -2
- package/dist/src/commands/build.js +12 -11
- package/dist/src/commands/config.js +9 -9
- package/dist/src/commands/destructive-decision.d.ts +4 -4
- package/dist/src/commands/destructive-decision.js +4 -4
- package/dist/src/commands/discard.js +5 -5
- package/dist/src/commands/doctor-check-core.d.ts +4 -4
- 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 -11
- package/dist/src/commands/doctor-orphaned-harness.js +10 -11
- 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 +2 -2
- 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 +2 -2
- package/dist/src/commands/doctor.js +9 -9
- package/dist/src/commands/download.js +15 -13
- package/dist/src/commands/export-all.js +8 -8
- package/dist/src/commands/export-flow.d.ts +5 -5
- package/dist/src/commands/export-flow.js +14 -14
- package/dist/src/commands/export-placement-conflicts.d.ts +3 -3
- package/dist/src/commands/export-placement-conflicts.js +9 -9
- package/dist/src/commands/export-placement-gate.d.ts +2 -2
- package/dist/src/commands/export-placement-gate.js +5 -5
- package/dist/src/commands/export-placement-policy.d.ts +1 -1
- package/dist/src/commands/export-placement-policy.js +1 -1
- package/dist/src/commands/export-shared.d.ts +10 -10
- package/dist/src/commands/export-shared.js +13 -13
- package/dist/src/commands/export.js +4 -4
- package/dist/src/commands/furnace/apply.js +16 -16
- package/dist/src/commands/furnace/chrome-doc-remove.d.ts +1 -1
- package/dist/src/commands/furnace/chrome-doc-remove.js +1 -1
- 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 +4 -4
- package/dist/src/commands/furnace/create-dry-run.d.ts +4 -4
- package/dist/src/commands/furnace/create-dry-run.js +4 -4
- 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 +14 -14
- package/dist/src/commands/furnace/create-templates.js +18 -18
- 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 +10 -10
- package/dist/src/commands/furnace/deploy.js +4 -4
- 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 +15 -15
- 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 +15 -15
- package/dist/src/commands/furnace/preview.js +17 -17
- package/dist/src/commands/furnace/refresh.js +6 -6
- package/dist/src/commands/furnace/remove-mutations.d.ts +3 -3
- package/dist/src/commands/furnace/remove-mutations.js +19 -18
- 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 +2 -2
- package/dist/src/commands/furnace/rename-browser-test.js +9 -8
- 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 +9 -9
- package/dist/src/commands/furnace/scan.js +3 -3
- package/dist/src/commands/furnace/status.js +7 -7
- package/dist/src/commands/furnace/sync.js +6 -6
- package/dist/src/commands/furnace/test-file-name.d.ts +2 -2
- package/dist/src/commands/furnace/test-file-name.js +2 -2
- package/dist/src/commands/furnace/validate.js +11 -12
- package/dist/src/commands/import.js +20 -20
- package/dist/src/commands/lint-per-patch.js +8 -8
- package/dist/src/commands/lint-per-run-checkjs.d.ts +12 -13
- 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 +3 -3
- package/dist/src/commands/lint.js +35 -35
- package/dist/src/commands/manifest.d.ts +4 -4
- package/dist/src/commands/package.js +2 -2
- package/dist/src/commands/patch/compact.d.ts +2 -2
- package/dist/src/commands/patch/compact.js +8 -8
- package/dist/src/commands/patch/delete.d.ts +1 -1
- package/dist/src/commands/patch/delete.js +8 -8
- package/dist/src/commands/patch/lint-ignore.d.ts +3 -4
- package/dist/src/commands/patch/lint-ignore.js +14 -15
- package/dist/src/commands/patch/move-files-create.d.ts +2 -2
- package/dist/src/commands/patch/move-files-create.js +5 -5
- package/dist/src/commands/patch/move-files-into.d.ts +2 -2
- package/dist/src/commands/patch/move-files-into.js +3 -3
- package/dist/src/commands/patch/move-files.js +1 -1
- 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 +8 -8
- package/dist/src/commands/patch/reorder.js +10 -10
- package/dist/src/commands/patch/split-plan.d.ts +3 -3
- package/dist/src/commands/patch/split-plan.js +6 -5
- package/dist/src/commands/patch/split.d.ts +2 -2
- package/dist/src/commands/patch/split.js +5 -5
- 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 +6 -6
- package/dist/src/commands/patch/tier.d.ts +2 -2
- package/dist/src/commands/patch/tier.js +5 -5
- package/dist/src/commands/patch-rename-map.d.ts +1 -1
- package/dist/src/commands/patch-rename-map.js +1 -1
- package/dist/src/commands/pending-resolution.d.ts +5 -5
- package/dist/src/commands/pending-resolution.js +5 -5
- package/dist/src/commands/re-export-adjacent.d.ts +3 -3
- package/dist/src/commands/re-export-adjacent.js +8 -8
- package/dist/src/commands/re-export-bulk-scan.d.ts +3 -3
- package/dist/src/commands/re-export-bulk-scan.js +17 -17
- package/dist/src/commands/re-export-drift.d.ts +10 -10
- package/dist/src/commands/re-export-drift.js +29 -29
- package/dist/src/commands/re-export-files.js +14 -15
- package/dist/src/commands/re-export-lint.d.ts +26 -26
- package/dist/src/commands/re-export-lint.js +27 -27
- 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 +7 -7
- package/dist/src/commands/re-export-single.d.ts +1 -1
- package/dist/src/commands/re-export-single.js +20 -20
- package/dist/src/commands/re-export.js +7 -6
- package/dist/src/commands/rebase/abort.js +6 -6
- package/dist/src/commands/rebase/continue.js +8 -7
- package/dist/src/commands/rebase/index.d.ts +1 -1
- package/dist/src/commands/rebase/index.js +3 -3
- package/dist/src/commands/rebase/patch-loop.js +18 -17
- 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 +3 -3
- package/dist/src/commands/run.js +26 -26
- package/dist/src/commands/setup-support.js +4 -4
- package/dist/src/commands/setup.js +1 -1
- package/dist/src/commands/source.js +1 -1
- package/dist/src/commands/status-check.d.ts +3 -3
- package/dist/src/commands/status-check.js +4 -4
- 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 +3 -3
- 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 +22 -22
- package/dist/src/commands/test-build-phase.d.ts +1 -1
- package/dist/src/commands/test-build-phase.js +17 -17
- 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 +2 -2
- package/dist/src/commands/test-modes.js +4 -4
- package/dist/src/commands/test-run.d.ts +11 -11
- package/dist/src/commands/test-run.js +15 -15
- package/dist/src/commands/test-stale-gate.d.ts +12 -12
- package/dist/src/commands/test-stale-gate.js +13 -13
- package/dist/src/commands/test-verdict.d.ts +6 -6
- package/dist/src/commands/test-verdict.js +11 -11
- package/dist/src/commands/test.d.ts +3 -3
- package/dist/src/commands/test.js +36 -36
- package/dist/src/commands/token-coverage.js +3 -3
- package/dist/src/commands/token-list.js +5 -5
- package/dist/src/commands/token.js +9 -9
- package/dist/src/commands/tree.js +19 -19
- package/dist/src/commands/typecheck.d.ts +6 -6
- package/dist/src/commands/typecheck.js +7 -7
- 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 +13 -13
- 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 -5
- package/dist/src/core/branding.js +3 -3
- package/dist/src/core/browser-wire.d.ts +1 -1
- package/dist/src/core/browser-wire.js +4 -4
- package/dist/src/core/build-audit-platform.d.ts +6 -6
- package/dist/src/core/build-audit-platform.js +26 -26
- package/dist/src/core/build-audit-registration.d.ts +5 -5
- package/dist/src/core/build-audit-registration.js +7 -7
- 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 +8 -8
- package/dist/src/core/build-audit-skip.js +12 -12
- 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 +8 -8
- package/dist/src/core/build-audit.js +39 -37
- 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 +8 -8
- package/dist/src/core/build-baseline.js +14 -14
- package/dist/src/core/build-jar-escalation.d.ts +8 -8
- package/dist/src/core/build-jar-escalation.js +15 -15
- package/dist/src/core/build-overwrite-guard.d.ts +4 -4
- package/dist/src/core/build-overwrite-guard.js +13 -13
- package/dist/src/core/build-prepare.d.ts +4 -4
- package/dist/src/core/build-prepare.js +16 -15
- package/dist/src/core/config-mutate.js +4 -4
- package/dist/src/core/config-state.js +2 -2
- package/dist/src/core/config-validate-build-audit.js +3 -3
- package/dist/src/core/config-validate-file-size.d.ts +1 -1
- package/dist/src/core/config-validate-file-size.js +2 -2
- package/dist/src/core/config-validate.js +8 -9
- package/dist/src/core/config.d.ts +10 -10
- package/dist/src/core/config.js +10 -10
- package/dist/src/core/coverage-extend.d.ts +16 -16
- package/dist/src/core/coverage-extend.js +16 -16
- 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 +15 -16
- 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 +4 -4
- package/dist/src/core/engine-precondition.js +2 -2
- package/dist/src/core/engine-session-lock.d.ts +18 -18
- package/dist/src/core/engine-session-lock.js +37 -37
- package/dist/src/core/export-moved-code-shape.d.ts +7 -7
- package/dist/src/core/export-moved-code-shape.js +8 -8
- package/dist/src/core/file-lock-owner.d.ts +11 -11
- package/dist/src/core/file-lock-owner.js +18 -18
- package/dist/src/core/file-lock.d.ts +12 -12
- package/dist/src/core/file-lock.js +52 -39
- package/dist/src/core/firefox-cache.d.ts +1 -1
- package/dist/src/core/firefox-cache.js +10 -10
- package/dist/src/core/firefox-download.d.ts +3 -3
- package/dist/src/core/firefox-download.js +6 -6
- package/dist/src/core/firefox-extract.d.ts +2 -2
- package/dist/src/core/firefox-extract.js +13 -13
- package/dist/src/core/firefox.d.ts +5 -5
- package/dist/src/core/firefox.js +8 -8
- package/dist/src/core/furnace-apply-dry-run.js +1 -1
- 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 -9
- package/dist/src/core/furnace-apply-helpers.js +21 -21
- 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 +9 -9
- 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 +3 -3
- package/dist/src/core/furnace-apply.js +22 -21
- 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 +4 -4
- package/dist/src/core/furnace-config.js +18 -18
- package/dist/src/core/furnace-constants.d.ts +6 -6
- package/dist/src/core/furnace-constants.js +6 -6
- 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 +1 -1
- package/dist/src/core/furnace-dir-entry.js +1 -1
- 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 +21 -20
- package/dist/src/core/furnace-operation.js +36 -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.js +2 -2
- package/dist/src/core/furnace-registration-ast.d.ts +2 -2
- package/dist/src/core/furnace-registration-ast.js +9 -9
- 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 +5 -5
- package/dist/src/core/furnace-registration.js +7 -7
- package/dist/src/core/furnace-rollback.d.ts +1 -1
- package/dist/src/core/furnace-rollback.js +5 -5
- 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 +10 -10
- 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 +13 -13
- 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 +4 -4
- package/dist/src/core/git-base.js +9 -9
- package/dist/src/core/git-diff-new-file.d.ts +4 -4
- package/dist/src/core/git-diff-new-file.js +8 -8
- package/dist/src/core/git-diff.d.ts +4 -4
- package/dist/src/core/git-diff.js +35 -34
- package/dist/src/core/git-file-ops.d.ts +6 -6
- package/dist/src/core/git-file-ops.js +7 -7
- package/dist/src/core/git-readonly-index.d.ts +12 -12
- package/dist/src/core/git-readonly-index.js +12 -12
- package/dist/src/core/git-status.d.ts +4 -4
- package/dist/src/core/git-status.js +4 -4
- package/dist/src/core/git.d.ts +3 -3
- package/dist/src/core/git.js +14 -14
- package/dist/src/core/harness-orphans.d.ts +17 -17
- package/dist/src/core/harness-orphans.js +20 -20
- package/dist/src/core/history-log.d.ts +3 -3
- package/dist/src/core/history-log.js +3 -3
- 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 -5
- package/dist/src/core/mach-error-hints.js +13 -13
- package/dist/src/core/mach-known-noise-filter.d.ts +41 -38
- package/dist/src/core/mach-known-noise-filter.js +53 -50
- package/dist/src/core/mach-mozconfig.d.ts +6 -6
- package/dist/src/core/mach-mozconfig.js +15 -15
- package/dist/src/core/mach-python.d.ts +2 -1
- package/dist/src/core/mach-python.js +4 -3
- package/dist/src/core/mach-resource-shim.d.ts +12 -12
- package/dist/src/core/mach-resource-shim.js +20 -20
- package/dist/src/core/mach.d.ts +23 -23
- package/dist/src/core/mach.js +36 -36
- package/dist/src/core/marionette-port.d.ts +15 -13
- package/dist/src/core/marionette-port.js +34 -31
- package/dist/src/core/marionette-preflight.d.ts +6 -6
- package/dist/src/core/marionette-preflight.js +23 -23
- 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 +14 -14
- 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 +11 -11
- 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 +9 -9
- package/dist/src/core/patch-apply.d.ts +9 -9
- package/dist/src/core/patch-apply.js +30 -30
- package/dist/src/core/patch-export-update.d.ts +4 -4
- package/dist/src/core/patch-export-update.js +3 -3
- package/dist/src/core/patch-export.d.ts +10 -10
- package/dist/src/core/patch-export.js +13 -13
- 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 +7 -7
- package/dist/src/core/patch-lint-cache.d.ts +2 -2
- package/dist/src/core/patch-lint-cache.js +13 -13
- package/dist/src/core/patch-lint-checkjs.d.ts +26 -26
- package/dist/src/core/patch-lint-checkjs.js +42 -41
- 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 +3 -3
- package/dist/src/core/patch-lint-creators.js +3 -3
- package/dist/src/core/patch-lint-cross.d.ts +13 -13
- package/dist/src/core/patch-lint-cross.js +21 -21
- package/dist/src/core/patch-lint-css.d.ts +1 -1
- package/dist/src/core/patch-lint-css.js +5 -5
- 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 +3 -3
- package/dist/src/core/patch-lint-forward-registration.d.ts +4 -4
- package/dist/src/core/patch-lint-forward-registration.js +12 -12
- package/dist/src/core/patch-lint-jsdoc.d.ts +2 -2
- package/dist/src/core/patch-lint-jsdoc.js +11 -11
- package/dist/src/core/patch-lint-module-registration.d.ts +1 -1
- 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 +6 -6
- package/dist/src/core/patch-lint-queue-types.d.ts +1 -1
- package/dist/src/core/patch-lint-queue-types.js +1 -1
- package/dist/src/core/patch-lint-staged-registration.d.ts +2 -2
- package/dist/src/core/patch-lint-staged-registration.js +6 -6
- 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 +27 -26
- package/dist/src/core/patch-lint.js +48 -46
- package/dist/src/core/patch-lock.d.ts +1 -1
- package/dist/src/core/patch-lock.js +8 -8
- 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 +27 -27
- 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 +14 -14
- package/dist/src/core/patch-parse.js +16 -16
- 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-transform.d.ts +8 -8
- package/dist/src/core/patch-transform.js +13 -13
- package/dist/src/core/process-cpu-time.d.ts +1 -1
- package/dist/src/core/process-cpu-time.js +5 -5
- package/dist/src/core/rebase-session.d.ts +7 -7
- package/dist/src/core/rebase-session.js +8 -8
- 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 +3 -3
- package/dist/src/core/register-shared-css.d.ts +3 -3
- package/dist/src/core/register-shared-css.js +4 -4
- 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 +12 -12
- package/dist/src/core/run-log-redact.js +16 -16
- package/dist/src/core/run-log.d.ts +9 -9
- package/dist/src/core/run-log.js +14 -14
- 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 +2 -2
- package/dist/src/core/smoke-patterns.d.ts +5 -5
- package/dist/src/core/smoke-patterns.js +9 -9
- package/dist/src/core/state-file.d.ts +3 -3
- 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 +11 -11
- package/dist/src/core/test-changed-prefs.d.ts +12 -12
- package/dist/src/core/test-changed-prefs.js +15 -15
- package/dist/src/core/test-harness-crash.d.ts +39 -39
- package/dist/src/core/test-harness-crash.js +67 -67
- 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 -21
- package/dist/src/core/test-stale-check.js +29 -28
- 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/token-category.d.ts +4 -4
- package/dist/src/core/token-category.js +13 -12
- package/dist/src/core/token-coverage.js +4 -5
- package/dist/src/core/token-dark-mode.d.ts +17 -9
- package/dist/src/core/token-dark-mode.js +41 -28
- package/dist/src/core/token-docs.d.ts +1 -1
- package/dist/src/core/token-inventory.d.ts +6 -6
- package/dist/src/core/token-inventory.js +7 -7
- package/dist/src/core/token-manager.d.ts +3 -3
- package/dist/src/core/token-manager.js +21 -21
- 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 +32 -32
- package/dist/src/core/toolchain-preflight.d.ts +15 -15
- package/dist/src/core/toolchain-preflight.js +22 -22
- package/dist/src/core/tree-cow.d.ts +3 -3
- package/dist/src/core/tree-cow.js +6 -6
- 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 +35 -33
- 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 +31 -31
- 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 +6 -6
- 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 +11 -11
- package/dist/src/core/xpcshell-appdir.d.ts +20 -20
- package/dist/src/core/xpcshell-appdir.js +26 -26
- 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 +22 -21
- package/dist/src/errors/base.js +22 -21
- package/dist/src/errors/build.d.ts +6 -6
- package/dist/src/errors/build.js +6 -6
- package/dist/src/errors/codes.d.ts +10 -10
- package/dist/src/errors/codes.js +10 -10
- package/dist/src/errors/furnace.d.ts +2 -2
- package/dist/src/errors/git.d.ts +1 -1
- package/dist/src/errors/git.js +1 -1
- package/dist/src/errors/patch.d.ts +3 -3
- package/dist/src/errors/patch.js +3 -3
- package/dist/src/errors/rebase.d.ts +1 -1
- package/dist/src/errors/rebase.js +1 -1
- 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 +86 -85
- 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 +24 -23
- package/dist/src/types/furnace.d.ts +17 -17
- 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 +1 -1
- package/dist/src/utils/assert.js +6 -6
- package/dist/src/utils/build-info.d.ts +5 -5
- package/dist/src/utils/build-info.js +6 -6
- package/dist/src/utils/child-env.d.ts +5 -5
- 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 +1 -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 +8 -8
- package/dist/src/utils/line-dispatch.d.ts +3 -3
- package/dist/src/utils/line-dispatch.js +5 -5
- 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 +13 -13
- package/dist/src/utils/options.js +20 -20
- package/dist/src/utils/package-root.js +2 -2
- package/dist/src/utils/paths.d.ts +4 -4
- package/dist/src/utils/paths.js +4 -4
- package/dist/src/utils/process-group.d.ts +8 -8
- package/dist/src/utils/process-group.js +19 -19
- package/dist/src/utils/process.d.ts +34 -33
- package/dist/src/utils/process.js +20 -19
- package/dist/src/utils/ps-duration.d.ts +4 -4
- package/dist/src/utils/ps-duration.js +6 -6
- package/dist/src/utils/regex.d.ts +4 -4
- package/dist/src/utils/regex.js +7 -7
- package/dist/src/utils/sleep.d.ts +7 -7
- package/dist/src/utils/sleep.js +7 -7
- 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 +11 -12
- package/dist/src/utils/validation.js +20 -21
- package/docs/README.md +2 -2
- package/docs/configuration.md +120 -114
- package/docs/exit-codes.md +63 -58
- package/docs/furnace.md +20 -19
- package/docs/lifecycle-invariants.md +412 -251
- package/docs/machine-output.md +33 -32
- package/docs/patch-workflow.md +48 -45
- package/docs/run-logs.md +62 -58
- package/docs/testing.md +101 -101
- package/docs/verification-trees.md +23 -22
- package/package.json +2 -2
|
@@ -9,13 +9,13 @@ export interface EngineSessionLockOptions {
|
|
|
9
9
|
waitLockSeconds?: number | undefined;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
* Formats the notice printed when the wait budget is
|
|
12
|
+
* Formats the notice printed when the wait budget is extended because the
|
|
13
13
|
* queue advanced.
|
|
14
14
|
*
|
|
15
|
-
* Exported for direct unit testing. It names both figures
|
|
16
|
-
* budget and the one now in force
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* Exported for direct unit testing. It names both figures, the requested
|
|
16
|
+
* budget and the one now in force, because they have diverged and an
|
|
17
|
+
* operator comparing the elapsed time against the number they typed would
|
|
18
|
+
* otherwise conclude the timeout is broken.
|
|
19
19
|
*/
|
|
20
20
|
export declare function formatWaitExtendedLine(ahead: number, budgetMs: number, requestedMs: number): string;
|
|
21
21
|
/**
|
|
@@ -24,8 +24,8 @@ export declare function formatWaitExtendedLine(ahead: number, budgetMs: number,
|
|
|
24
24
|
*/
|
|
25
25
|
export declare function withEngineSessionLock<T>(projectRoot: string, command: string, operation: () => Promise<T>, options?: EngineSessionLockOptions): Promise<T>;
|
|
26
26
|
/**
|
|
27
|
-
* Inspects the project's engine-session lock without acquiring it
|
|
28
|
-
*
|
|
27
|
+
* Inspects the project's engine-session lock without acquiring it, backing
|
|
28
|
+
* `fireforge status --lock`.
|
|
29
29
|
*
|
|
30
30
|
* @param projectRoot - Project root containing `.fireforge/`
|
|
31
31
|
* @returns Holder identity, hold duration, and queue depth
|
|
@@ -52,7 +52,7 @@ export declare function snapshotEngineGeneration(engineDir: string): Promise<str
|
|
|
52
52
|
*/
|
|
53
53
|
export declare function isIndexLockError(error: unknown): boolean;
|
|
54
54
|
/**
|
|
55
|
-
* True when a generation token records a failed probe
|
|
55
|
+
* True when a generation token records a failed probe, i.e. nothing was
|
|
56
56
|
* measured, so the token must never be compared (or hashed) as if it
|
|
57
57
|
* described the engine's state.
|
|
58
58
|
*/
|
|
@@ -62,8 +62,8 @@ export declare function unavailableGenerationReason(token: string): string;
|
|
|
62
62
|
/**
|
|
63
63
|
* Describes what moved between two generation tokens, in operator terms.
|
|
64
64
|
*
|
|
65
|
-
* The refusal used to say only
|
|
66
|
-
* operator to reconstruct the writer by hand
|
|
65
|
+
* The refusal used to say only that the engine changed, which left the
|
|
66
|
+
* operator to reconstruct the writer by hand: `find -newermt` against the
|
|
67
67
|
* run window, minus the objdir, minus git's own bookkeeping. Everything
|
|
68
68
|
* needed to answer it is already in the two tokens, so the refusal answers
|
|
69
69
|
* it. Pure and total: an unparseable token yields an empty list rather than
|
|
@@ -72,7 +72,7 @@ export declare function unavailableGenerationReason(token: string): string;
|
|
|
72
72
|
*
|
|
73
73
|
* @param before - Token captured before the run
|
|
74
74
|
* @param after - Token captured after the run
|
|
75
|
-
* @returns Human-readable lines describing the delta
|
|
75
|
+
* @returns Human-readable lines describing the delta. Empty when nothing
|
|
76
76
|
* could be attributed
|
|
77
77
|
*/
|
|
78
78
|
export declare function describeEngineGenerationDelta(before: string, after: string): string[];
|
|
@@ -80,25 +80,25 @@ export declare function describeEngineGenerationDelta(before: string, after: str
|
|
|
80
80
|
* Throws when the engine's generation token differs from `before`, i.e. the
|
|
81
81
|
* engine was mutated by another writer while a test run was in flight.
|
|
82
82
|
*
|
|
83
|
-
*
|
|
84
|
-
* always a git checkout
|
|
83
|
+
* An unmeasurable engine warns rather than throws. `engine/` is not
|
|
84
|
+
* always a git checkout (`fireforge download` extracts a source tarball),
|
|
85
85
|
* so a failed probe is a legitimate state and must not fail the run.
|
|
86
86
|
*
|
|
87
|
-
*
|
|
87
|
+
* It must also not pass silently. A failure token compared for
|
|
88
88
|
* equality like any other would let a git failure that reproduces across
|
|
89
89
|
* both probes (unreadable `.git`, a permissions problem, a corrupt index)
|
|
90
90
|
* take the `after === before` early return and bless a verdict the guard
|
|
91
|
-
* never verified. Two
|
|
91
|
+
* never verified. Two differing failure messages are worse still: they
|
|
92
92
|
* fall through to the mutation branch and report a spurious
|
|
93
93
|
* "engine/ changed". Hence the prefix comparison rather than a token
|
|
94
|
-
* comparison
|
|
94
|
+
* comparison: the token embeds the error message, and two genuine failures
|
|
95
95
|
* rarely phrase it identically.
|
|
96
96
|
*
|
|
97
|
-
* The tolerance is
|
|
97
|
+
* The tolerance is limited to a probe that failed both times:
|
|
98
98
|
* that is the steady state of a non-git `engine/`, and it warns. A one-sided
|
|
99
99
|
* transition is not that state. An `engine/` that was measurable and then
|
|
100
100
|
* was not means the second probe measured nothing about a checkout that
|
|
101
|
-
* demonstrably had something to measure
|
|
101
|
+
* demonstrably had something to measure. The reverse means there was never a
|
|
102
102
|
* baseline to compare against. Neither verdict can be trusted, so both throw.
|
|
103
103
|
*/
|
|
104
104
|
export declare function assertEngineGenerationUnchanged(engineDir: string, before: string): Promise<void>;
|
|
@@ -18,7 +18,7 @@ const MAX_WAIT_LOCK_MS = 3600 * 1000;
|
|
|
18
18
|
/**
|
|
19
19
|
* Formats the periodic operator-facing waiting line printed while `--wait-lock`
|
|
20
20
|
* polls a contended engine session lock. The holder identification comes from
|
|
21
|
-
* the lock's owner-metadata lines (`command=…`, `started=…`)
|
|
21
|
+
* the lock's owner-metadata lines (`command=…`, `started=…`). An unreadable
|
|
22
22
|
* owner file degrades to the anonymous form.
|
|
23
23
|
*/
|
|
24
24
|
function formatWaitProgressLine(waitedMs, timeoutMs, holder, queue) {
|
|
@@ -37,13 +37,13 @@ function formatWaitProgressLine(waitedMs, timeoutMs, holder, queue) {
|
|
|
37
37
|
return `Waiting for the FireForge engine lock held by PID ${holder.pid}${details} — ${progress}.${position}`;
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
|
-
* Formats the notice printed when the wait budget is
|
|
40
|
+
* Formats the notice printed when the wait budget is extended because the
|
|
41
41
|
* queue advanced.
|
|
42
42
|
*
|
|
43
|
-
* Exported for direct unit testing. It names both figures
|
|
44
|
-
* budget and the one now in force
|
|
45
|
-
*
|
|
46
|
-
*
|
|
43
|
+
* Exported for direct unit testing. It names both figures, the requested
|
|
44
|
+
* budget and the one now in force, because they have diverged and an
|
|
45
|
+
* operator comparing the elapsed time against the number they typed would
|
|
46
|
+
* otherwise conclude the timeout is broken.
|
|
47
47
|
*/
|
|
48
48
|
export function formatWaitExtendedLine(ahead, budgetMs, requestedMs) {
|
|
49
49
|
const position = ahead === 0 ? 'you are now next' : `${ahead} still ahead of you`;
|
|
@@ -57,11 +57,11 @@ export function formatWaitExtendedLine(ahead, budgetMs, requestedMs) {
|
|
|
57
57
|
* one engine-mutating FireForge command touches `engine/` at a time.
|
|
58
58
|
*/
|
|
59
59
|
export async function withEngineSessionLock(projectRoot, command, operation, options = {}) {
|
|
60
|
-
// The lock is bypassed under test by default,
|
|
60
|
+
// The lock is bypassed under test by default, on purpose: the
|
|
61
61
|
// suite runs many engine-mutating commands in-process, which would either
|
|
62
62
|
// serialise on this lock or deadlock outright.
|
|
63
63
|
// `FIREFORGE_ENABLE_ENGINE_SESSION_LOCK_IN_TEST=1` lets the lock's own
|
|
64
|
-
// tests opt back in. Do not delete this branch
|
|
64
|
+
// tests opt back in. Do not delete this branch. It is the reason the
|
|
65
65
|
// suite completes.
|
|
66
66
|
if (process.env['FIREFORGE_ENABLE_ENGINE_SESSION_LOCK_IN_TEST'] !== '1' &&
|
|
67
67
|
(process.env['NODE_ENV'] === 'test' || process.env['VITEST'] !== undefined)) {
|
|
@@ -78,30 +78,30 @@ export async function withEngineSessionLock(projectRoot, command, operation, opt
|
|
|
78
78
|
onWaitProgress: ({ waitedMs, timeoutMs, holder, queue }) => {
|
|
79
79
|
info(formatWaitProgressLine(waitedMs, timeoutMs, holder, queue));
|
|
80
80
|
},
|
|
81
|
-
//
|
|
81
|
+
// Announce it. An extension is the moment the budget the
|
|
82
82
|
// operator asked for stops being the budget in force, and a wait
|
|
83
83
|
// that silently outlives its own stated timeout is
|
|
84
|
-
// indistinguishable from a broken one
|
|
84
|
+
// indistinguishable from a broken one, which is how a downstream
|
|
85
85
|
// fork read it.
|
|
86
86
|
onWaitExtended: ({ ahead, budgetMs }) => {
|
|
87
87
|
info(formatWaitExtendedLine(ahead, budgetMs, waitLockSeconds * 1000));
|
|
88
88
|
},
|
|
89
89
|
// A budget that expires one position from the head pays the whole
|
|
90
|
-
// wait for nothing. While the queue is still
|
|
91
|
-
// working, so each advance renews the budget
|
|
92
|
-
// ceiling
|
|
93
|
-
// no-flag fail-fast path
|
|
90
|
+
// wait for nothing. While the queue is still moving the wait is
|
|
91
|
+
// working, so each advance renews the budget, up to a hard
|
|
92
|
+
// ceiling so a pathological queue cannot wait forever. The
|
|
93
|
+
// no-flag fail-fast path gets none of this.
|
|
94
94
|
extendWhileAdvancing: {
|
|
95
95
|
maxWaitMs: Math.min(waitLockSeconds * 1000 * WAIT_EXTENSION_FACTOR, MAX_WAIT_LOCK_MS),
|
|
96
96
|
},
|
|
97
97
|
}
|
|
98
98
|
: {}),
|
|
99
99
|
ownerMetadata: [`command=${command}`, `started=${new Date().toISOString()}`],
|
|
100
|
-
// Reason first, remedy second
|
|
100
|
+
// Reason first, remedy second: the no-flag default waits
|
|
101
101
|
// only ~1 s, so contention is the common case and `--wait-lock` is the
|
|
102
102
|
// genuine remedy. withFileLock appends the holder identification from
|
|
103
103
|
// the lock's owner metadata. The leading sentence is a message contract
|
|
104
|
-
// (pinned by engine-session-lock tests)
|
|
104
|
+
// (pinned by engine-session-lock tests). Extend, don't reword.
|
|
105
105
|
onTimeoutMessage: `Another FireForge engine-mutating command is already running. ` +
|
|
106
106
|
`Wait for it to finish, then retry \`${command}\` — or pass --wait-lock [seconds] ` +
|
|
107
107
|
`to wait for the lock (bare --wait-lock waits up to 60 seconds). ` +
|
|
@@ -110,8 +110,8 @@ export async function withEngineSessionLock(projectRoot, command, operation, opt
|
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
/**
|
|
113
|
-
* Inspects the project's engine-session lock without acquiring it
|
|
114
|
-
*
|
|
113
|
+
* Inspects the project's engine-session lock without acquiring it, backing
|
|
114
|
+
* `fireforge status --lock`.
|
|
115
115
|
*
|
|
116
116
|
* @param projectRoot - Project root containing `.fireforge/`
|
|
117
117
|
* @returns Holder identity, hold duration, and queue depth
|
|
@@ -139,11 +139,11 @@ export function formatEngineSessionLockStatus(snapshot, holderCpuSeconds) {
|
|
|
139
139
|
`Engine session lock: ${identity}, for ${elapsed}.`,
|
|
140
140
|
`Queue depth: ${snapshot.queueDepth} waiter(s).`,
|
|
141
141
|
];
|
|
142
|
-
// Liveness answers "does the process exist"
|
|
142
|
+
// Liveness answers "does the process exist". It does not answer "is it
|
|
143
143
|
// getting anywhere". A holder alive for minutes having used a fraction of
|
|
144
144
|
// a second of CPU is the shape of a wedged command, and every waiter
|
|
145
145
|
// behind it inherits the stall. Stated as an observation with its own
|
|
146
|
-
// caveat
|
|
146
|
+
// caveat: a holder blocked on I/O is also idle, and this must not be read
|
|
147
147
|
// as licence to kill anything.
|
|
148
148
|
if (holder?.alive === true && holderCpuSeconds !== undefined) {
|
|
149
149
|
const cpu = `${holderCpuSeconds.toFixed(1)}s`;
|
|
@@ -175,11 +175,11 @@ export async function snapshotEngineGeneration(engineDir) {
|
|
|
175
175
|
}
|
|
176
176
|
catch (error) {
|
|
177
177
|
lastError = error;
|
|
178
|
-
// A contended `.git/index.lock` is
|
|
178
|
+
// A contended `.git/index.lock` is transient, not a state: some other
|
|
179
179
|
// writer held the index for the instant we looked. Treating it as
|
|
180
180
|
// "unmeasurable" turns a perfectly good suite into
|
|
181
181
|
// `FAIL reason=inconclusive` on a one-sided probe failure. Anything
|
|
182
|
-
// else
|
|
182
|
+
// else (an unreadable `.git`, a non-git `engine/`) is a real state
|
|
183
183
|
// and is reported immediately.
|
|
184
184
|
if (!isIndexLockError(error) || attempt === GENERATION_PROBE_ATTEMPTS - 1)
|
|
185
185
|
break;
|
|
@@ -202,7 +202,7 @@ export function isIndexLockError(error) {
|
|
|
202
202
|
return /index\.lock/i.test(message);
|
|
203
203
|
}
|
|
204
204
|
/**
|
|
205
|
-
* True when a generation token records a failed probe
|
|
205
|
+
* True when a generation token records a failed probe, i.e. nothing was
|
|
206
206
|
* measured, so the token must never be compared (or hashed) as if it
|
|
207
207
|
* described the engine's state.
|
|
208
208
|
*/
|
|
@@ -228,9 +228,9 @@ function splitGenerationToken(token) {
|
|
|
228
228
|
/**
|
|
229
229
|
* Parses `git status --porcelain=v1 -z` into `XY path` records.
|
|
230
230
|
*
|
|
231
|
-
* The rename/copy shape
|
|
232
|
-
*
|
|
233
|
-
* one desynchronises every record after it
|
|
231
|
+
* The rename/copy shape needs care: `R`/`C` entries are followed by a
|
|
232
|
+
* second NUL-separated field carrying the original path, and consuming only
|
|
233
|
+
* one desynchronises every record after it, turning a one-file rename into
|
|
234
234
|
* a report that the whole tree moved. Both fields are consumed and the
|
|
235
235
|
* record renders as `orig -> new`.
|
|
236
236
|
*/
|
|
@@ -239,7 +239,7 @@ function parsePorcelainRecords(body) {
|
|
|
239
239
|
const records = [];
|
|
240
240
|
for (let i = 0; i < fields.length; i++) {
|
|
241
241
|
const field = fields[i] ?? '';
|
|
242
|
-
// `XY
|
|
242
|
+
// `XY `, two status characters and a space, then the path.
|
|
243
243
|
if (field.length < 4)
|
|
244
244
|
continue;
|
|
245
245
|
const status = field.slice(0, 2);
|
|
@@ -257,8 +257,8 @@ function parsePorcelainRecords(body) {
|
|
|
257
257
|
/**
|
|
258
258
|
* Describes what moved between two generation tokens, in operator terms.
|
|
259
259
|
*
|
|
260
|
-
* The refusal used to say only
|
|
261
|
-
* operator to reconstruct the writer by hand
|
|
260
|
+
* The refusal used to say only that the engine changed, which left the
|
|
261
|
+
* operator to reconstruct the writer by hand: `find -newermt` against the
|
|
262
262
|
* run window, minus the objdir, minus git's own bookkeeping. Everything
|
|
263
263
|
* needed to answer it is already in the two tokens, so the refusal answers
|
|
264
264
|
* it. Pure and total: an unparseable token yields an empty list rather than
|
|
@@ -267,7 +267,7 @@ function parsePorcelainRecords(body) {
|
|
|
267
267
|
*
|
|
268
268
|
* @param before - Token captured before the run
|
|
269
269
|
* @param after - Token captured after the run
|
|
270
|
-
* @returns Human-readable lines describing the delta
|
|
270
|
+
* @returns Human-readable lines describing the delta. Empty when nothing
|
|
271
271
|
* could be attributed
|
|
272
272
|
*/
|
|
273
273
|
export function describeEngineGenerationDelta(before, after) {
|
|
@@ -296,25 +296,25 @@ export function describeEngineGenerationDelta(before, after) {
|
|
|
296
296
|
* Throws when the engine's generation token differs from `before`, i.e. the
|
|
297
297
|
* engine was mutated by another writer while a test run was in flight.
|
|
298
298
|
*
|
|
299
|
-
*
|
|
300
|
-
* always a git checkout
|
|
299
|
+
* An unmeasurable engine warns rather than throws. `engine/` is not
|
|
300
|
+
* always a git checkout (`fireforge download` extracts a source tarball),
|
|
301
301
|
* so a failed probe is a legitimate state and must not fail the run.
|
|
302
302
|
*
|
|
303
|
-
*
|
|
303
|
+
* It must also not pass silently. A failure token compared for
|
|
304
304
|
* equality like any other would let a git failure that reproduces across
|
|
305
305
|
* both probes (unreadable `.git`, a permissions problem, a corrupt index)
|
|
306
306
|
* take the `after === before` early return and bless a verdict the guard
|
|
307
|
-
* never verified. Two
|
|
307
|
+
* never verified. Two differing failure messages are worse still: they
|
|
308
308
|
* fall through to the mutation branch and report a spurious
|
|
309
309
|
* "engine/ changed". Hence the prefix comparison rather than a token
|
|
310
|
-
* comparison
|
|
310
|
+
* comparison: the token embeds the error message, and two genuine failures
|
|
311
311
|
* rarely phrase it identically.
|
|
312
312
|
*
|
|
313
|
-
* The tolerance is
|
|
313
|
+
* The tolerance is limited to a probe that failed both times:
|
|
314
314
|
* that is the steady state of a non-git `engine/`, and it warns. A one-sided
|
|
315
315
|
* transition is not that state. An `engine/` that was measurable and then
|
|
316
316
|
* was not means the second probe measured nothing about a checkout that
|
|
317
|
-
* demonstrably had something to measure
|
|
317
|
+
* demonstrably had something to measure. The reverse means there was never a
|
|
318
318
|
* baseline to compare against. Neither verdict can be trusted, so both throw.
|
|
319
319
|
*/
|
|
320
320
|
export async function assertEngineGenerationUnchanged(engineDir, before) {
|
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
* Detects the new-file-plus-moved-code slice shape and names the working
|
|
3
3
|
* sequence through it.
|
|
4
4
|
*
|
|
5
|
-
* A slice that
|
|
5
|
+
* A slice that adds new files and moves lines into them from an existing
|
|
6
6
|
* patch has no path through the two refusal flags:
|
|
7
7
|
*
|
|
8
8
|
* - `re-export --refuse-adjacent-unmanaged` refuses while the new files are
|
|
9
|
-
* still unmanaged
|
|
9
|
+
* still unmanaged, and
|
|
10
10
|
* - exporting the new files as their own patch fails cross-patch lint,
|
|
11
|
-
* because at the projected placement the
|
|
11
|
+
* because at the projected placement the old patch still contains the
|
|
12
12
|
* moved code.
|
|
13
13
|
*
|
|
14
14
|
* Each guard is individually correct. Together they dead-end, and the way out
|
|
15
|
-
* is non-obvious: adopt the new files into the
|
|
15
|
+
* is non-obvious: adopt the new files into the old patch first
|
|
16
16
|
* (`re-export --scan --scan-file`), then split them out into a patch of their
|
|
17
17
|
* own (`patch move-files --create --order N`).
|
|
18
18
|
*
|
|
19
|
-
* This module recognises the shape from evidence FireForge already has
|
|
19
|
+
* This module recognises the shape from evidence FireForge already has (the
|
|
20
20
|
* pending diff's new-file content versus the added lines the existing patches
|
|
21
|
-
* carry
|
|
21
|
+
* carry), so the refusal can name the sequence instead of leaving the
|
|
22
22
|
* operator to derive it.
|
|
23
23
|
*/
|
|
24
24
|
/** One existing patch that already carries lines the new files would add. */
|
|
@@ -37,7 +37,7 @@ export interface MovedCodeQueueEntry {
|
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Finds existing patches that still carry substantive lines the pending
|
|
40
|
-
* diff's
|
|
40
|
+
* diff's new files would add, the fingerprint of code moved out of an
|
|
41
41
|
* existing patch into a new file.
|
|
42
42
|
*
|
|
43
43
|
* Pure. Overlaps are returned strongest-first so the message names the
|
|
@@ -3,23 +3,23 @@
|
|
|
3
3
|
* Detects the new-file-plus-moved-code slice shape and names the working
|
|
4
4
|
* sequence through it.
|
|
5
5
|
*
|
|
6
|
-
* A slice that
|
|
6
|
+
* A slice that adds new files and moves lines into them from an existing
|
|
7
7
|
* patch has no path through the two refusal flags:
|
|
8
8
|
*
|
|
9
9
|
* - `re-export --refuse-adjacent-unmanaged` refuses while the new files are
|
|
10
|
-
* still unmanaged
|
|
10
|
+
* still unmanaged, and
|
|
11
11
|
* - exporting the new files as their own patch fails cross-patch lint,
|
|
12
|
-
* because at the projected placement the
|
|
12
|
+
* because at the projected placement the old patch still contains the
|
|
13
13
|
* moved code.
|
|
14
14
|
*
|
|
15
15
|
* Each guard is individually correct. Together they dead-end, and the way out
|
|
16
|
-
* is non-obvious: adopt the new files into the
|
|
16
|
+
* is non-obvious: adopt the new files into the old patch first
|
|
17
17
|
* (`re-export --scan --scan-file`), then split them out into a patch of their
|
|
18
18
|
* own (`patch move-files --create --order N`).
|
|
19
19
|
*
|
|
20
|
-
* This module recognises the shape from evidence FireForge already has
|
|
20
|
+
* This module recognises the shape from evidence FireForge already has (the
|
|
21
21
|
* pending diff's new-file content versus the added lines the existing patches
|
|
22
|
-
* carry
|
|
22
|
+
* carry), so the refusal can name the sequence instead of leaving the
|
|
23
23
|
* operator to derive it.
|
|
24
24
|
*/
|
|
25
25
|
import { extractAddedLinesPerFile } from './patch-lint-diff.js';
|
|
@@ -42,7 +42,7 @@ function isSubstantiveLine(line) {
|
|
|
42
42
|
const MOVED_CODE_LINE_THRESHOLD = 3;
|
|
43
43
|
/**
|
|
44
44
|
* Finds existing patches that still carry substantive lines the pending
|
|
45
|
-
* diff's
|
|
45
|
+
* diff's new files would add, the fingerprint of code moved out of an
|
|
46
46
|
* existing patch into a new file.
|
|
47
47
|
*
|
|
48
48
|
* Pure. Overlaps are returned strongest-first so the message names the
|
|
@@ -108,7 +108,7 @@ export function formatAdoptThenSplitRemedy(overlaps, newPatchName, insertionOrde
|
|
|
108
108
|
return [];
|
|
109
109
|
const fileArgs = strongest.files.map((file) => `--scan-file ${file}`).join(' ');
|
|
110
110
|
const moveArgs = strongest.files.map((file) => `--file ${file}`).join(' ');
|
|
111
|
-
// `patch move-files --create` takes the new patch's
|
|
111
|
+
// `patch move-files --create` takes the new patch's name, not a
|
|
112
112
|
// filename: strip the order prefix and the `.patch` suffix so the
|
|
113
113
|
// suggested command is copy-pasteable.
|
|
114
114
|
const suggestedName = newPatchName.replace(/^\d+-/, '').replace(/\.patch$/, '');
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Filename of a lock directory's owner record, relative to the lock dir.
|
|
3
3
|
*
|
|
4
4
|
* Re-exported by `file-lock.ts` so external readers (`tree-store.ts`) share
|
|
5
|
-
* the constant instead of re-spelling `'pid'
|
|
5
|
+
* the constant instead of re-spelling `'pid'`. The file format is
|
|
6
6
|
* documented on {@link readLockOwner}.
|
|
7
7
|
*/
|
|
8
8
|
export declare const LOCK_PID_FILE = "pid";
|
|
@@ -12,8 +12,8 @@ export declare const LOCK_PID_FILE = "pid";
|
|
|
12
12
|
* `token` is the per-acquisition UUID written on line 2 of the PID file,
|
|
13
13
|
* `acquiredAtMs` the wall-clock time the record was written (diagnostic),
|
|
14
14
|
* and `startTick` the writer's boot-relative start tick (liveness). Records
|
|
15
|
-
* from releases before a field was introduced parse with it `undefined
|
|
16
|
-
*
|
|
15
|
+
* from releases before a field was introduced parse with it `undefined`.
|
|
16
|
+
* Readers must treat that as "unknown", never as a mismatch.
|
|
17
17
|
*/
|
|
18
18
|
export type LockOwner = {
|
|
19
19
|
present: false;
|
|
@@ -34,7 +34,7 @@ export type LockOwner = {
|
|
|
34
34
|
* age-only staleness heuristic).
|
|
35
35
|
*
|
|
36
36
|
* File format note: external readers do `parseInt(content.trim(), 10)`,
|
|
37
|
-
* which parses the leading digits of a multi-line file
|
|
37
|
+
* which parses the leading digits of a multi-line file, so the token and
|
|
38
38
|
* mechanical lines stay compatible.
|
|
39
39
|
*
|
|
40
40
|
* @param lockPath - Lock directory whose owner record to read
|
|
@@ -46,8 +46,8 @@ export declare function readLockOwner(lockPath: string): Promise<LockOwner>;
|
|
|
46
46
|
* time, own start tick, diagnostic metadata) into a lock directory it has
|
|
47
47
|
* just created, and reads the record back to prove it landed.
|
|
48
48
|
*
|
|
49
|
-
* The write is
|
|
50
|
-
* recovery would fall back to the age heuristic
|
|
49
|
+
* The write is fatal. It used to be best-effort, on the theory that stale
|
|
50
|
+
* recovery would fall back to the age heuristic, but that heuristic reaps
|
|
51
51
|
* any owner-less lock after five minutes, and the build lock legitimately
|
|
52
52
|
* holds for hours. A holder whose record failed to write was therefore
|
|
53
53
|
* reaped mid-build and a second process entered the critical section. On
|
|
@@ -67,14 +67,14 @@ export declare function writeLockOwner(lockPath: string, token: string, ownerMet
|
|
|
67
67
|
* Linux only: field 22 of `/proc/<pid>/stat`, in USER_HZ since boot.
|
|
68
68
|
* Elsewhere (macOS, Windows) obtaining a start time means spawning
|
|
69
69
|
* `ps`/`wmic` per probe, which is not worth paying on every poll of a
|
|
70
|
-
* contended lock
|
|
70
|
+
* contended lock. Those platforms return `undefined` and liveness stays
|
|
71
71
|
* PID-only.
|
|
72
72
|
*
|
|
73
|
-
*
|
|
73
|
+
* Not converted to wall-clock time via `/proc/stat` `btime`, on purpose:
|
|
74
74
|
* on current kernels `btime` is derived from the realtime clock and moves
|
|
75
75
|
* with every clock step, so a wall-clock comparison against a recorded
|
|
76
76
|
* acquisition time misjudges a live holder as a reused PID after NTP steps
|
|
77
|
-
* the clock forward
|
|
77
|
+
* the clock forward, and reaps a lock that is in use.
|
|
78
78
|
*
|
|
79
79
|
* @param pid - Process to look up
|
|
80
80
|
* @param procRoot - procfs mount, overridable for tests
|
|
@@ -82,10 +82,10 @@ export declare function writeLockOwner(lockPath: string, token: string, ownerMet
|
|
|
82
82
|
*/
|
|
83
83
|
export declare function readProcessStartTick(pid: number, procRoot?: string): number | undefined;
|
|
84
84
|
/**
|
|
85
|
-
* Whether the process named by a lock's owner record is the
|
|
85
|
+
* Whether the process named by a lock's owner record is the same process
|
|
86
86
|
* that acquired the lock, not merely a live process wearing its PID.
|
|
87
87
|
*
|
|
88
|
-
* `isProcessAlive` answers "does this PID exist"
|
|
88
|
+
* `isProcessAlive` answers "does this PID exist". After a holder crashes,
|
|
89
89
|
* the kernel may hand its PID to a long-lived daemon, and a PID-only check
|
|
90
90
|
* then honours the dead lock until the waiter's timeout. Where the record
|
|
91
91
|
* carries the writer's start tick and the candidate's own tick is cheaply
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
/**
|
|
3
|
-
* Owner record of a `withFileLock` directory: the file that says
|
|
3
|
+
* Owner record of a `withFileLock` directory: the file that says which
|
|
4
4
|
* process holds the lock, so stale recovery can tell a dead holder from a
|
|
5
5
|
* slow one and release can refuse to remove a lock it no longer owns.
|
|
6
6
|
*
|
|
@@ -18,7 +18,7 @@ import { sleep } from '../utils/sleep.js';
|
|
|
18
18
|
* Filename of a lock directory's owner record, relative to the lock dir.
|
|
19
19
|
*
|
|
20
20
|
* Re-exported by `file-lock.ts` so external readers (`tree-store.ts`) share
|
|
21
|
-
* the constant instead of re-spelling `'pid'
|
|
21
|
+
* the constant instead of re-spelling `'pid'`. The file format is
|
|
22
22
|
* documented on {@link readLockOwner}.
|
|
23
23
|
*/
|
|
24
24
|
export const LOCK_PID_FILE = 'pid';
|
|
@@ -26,8 +26,8 @@ export const LOCK_PID_FILE = 'pid';
|
|
|
26
26
|
* Prefix of the mechanical owner-record line that carries the acquisition
|
|
27
27
|
* wall time. It lives among the metadata lines (line 3 onward) so older
|
|
28
28
|
* readers, which treat everything past line 2 as free-form diagnostics,
|
|
29
|
-
* still parse the record
|
|
30
|
-
* Diagnostic only
|
|
29
|
+
* still parse the record. The current reader lifts it out of `metadata`.
|
|
30
|
+
* Diagnostic only. See {@link START_TICK_PREFIX} for the liveness field.
|
|
31
31
|
*/
|
|
32
32
|
const ACQUIRED_AT_PREFIX = 'acquired-at-ms=';
|
|
33
33
|
/**
|
|
@@ -41,11 +41,11 @@ const ACQUIRED_AT_PREFIX = 'acquired-at-ms=';
|
|
|
41
41
|
*/
|
|
42
42
|
const START_TICK_PREFIX = 'start-tick=';
|
|
43
43
|
/**
|
|
44
|
-
* How many times the post-write read-back is retried when the
|
|
44
|
+
* How many times the post-write read-back is retried when the read itself
|
|
45
45
|
* errors (not when the record is absent or differs). An on-access scanner
|
|
46
46
|
* on Windows briefly holding the just-written file (`EBUSY`), or a FUSE
|
|
47
47
|
* mount's momentary `EIO`, must not be indistinguishable from "the record
|
|
48
|
-
* never landed"
|
|
48
|
+
* never landed": that verdict releases a lock this process has correctly
|
|
49
49
|
* acquired and aborts the run before it starts.
|
|
50
50
|
*/
|
|
51
51
|
const READ_BACK_ATTEMPTS = 5;
|
|
@@ -100,7 +100,7 @@ function parseLockOwnerRecord(pidContent) {
|
|
|
100
100
|
* age-only staleness heuristic).
|
|
101
101
|
*
|
|
102
102
|
* File format note: external readers do `parseInt(content.trim(), 10)`,
|
|
103
|
-
* which parses the leading digits of a multi-line file
|
|
103
|
+
* which parses the leading digits of a multi-line file, so the token and
|
|
104
104
|
* mechanical lines stay compatible.
|
|
105
105
|
*
|
|
106
106
|
* @param lockPath - Lock directory whose owner record to read
|
|
@@ -113,14 +113,14 @@ export async function readLockOwner(lockPath) {
|
|
|
113
113
|
return owner;
|
|
114
114
|
}
|
|
115
115
|
catch {
|
|
116
|
-
// PID file missing or unreadable
|
|
116
|
+
// PID file missing or unreadable. Treat as absent.
|
|
117
117
|
}
|
|
118
118
|
return { present: false };
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
|
-
* Reads the just-written record back, retrying a
|
|
121
|
+
* Reads the just-written record back, retrying a read error a few times
|
|
122
122
|
* before giving up. A missing or malformed record is returned as-is (the
|
|
123
|
-
* caller treats it as a failed write)
|
|
123
|
+
* caller treats it as a failed write). Only errno-level failures retry.
|
|
124
124
|
*/
|
|
125
125
|
async function readBackLockOwner(lockPath) {
|
|
126
126
|
let lastError;
|
|
@@ -141,8 +141,8 @@ async function readBackLockOwner(lockPath) {
|
|
|
141
141
|
* time, own start tick, diagnostic metadata) into a lock directory it has
|
|
142
142
|
* just created, and reads the record back to prove it landed.
|
|
143
143
|
*
|
|
144
|
-
* The write is
|
|
145
|
-
* recovery would fall back to the age heuristic
|
|
144
|
+
* The write is fatal. It used to be best-effort, on the theory that stale
|
|
145
|
+
* recovery would fall back to the age heuristic, but that heuristic reaps
|
|
146
146
|
* any owner-less lock after five minutes, and the build lock legitimately
|
|
147
147
|
* holds for hours. A holder whose record failed to write was therefore
|
|
148
148
|
* reaped mid-build and a second process entered the critical section. On
|
|
@@ -196,14 +196,14 @@ export async function writeLockOwner(lockPath, token, ownerMetadata) {
|
|
|
196
196
|
* Linux only: field 22 of `/proc/<pid>/stat`, in USER_HZ since boot.
|
|
197
197
|
* Elsewhere (macOS, Windows) obtaining a start time means spawning
|
|
198
198
|
* `ps`/`wmic` per probe, which is not worth paying on every poll of a
|
|
199
|
-
* contended lock
|
|
199
|
+
* contended lock. Those platforms return `undefined` and liveness stays
|
|
200
200
|
* PID-only.
|
|
201
201
|
*
|
|
202
|
-
*
|
|
202
|
+
* Not converted to wall-clock time via `/proc/stat` `btime`, on purpose:
|
|
203
203
|
* on current kernels `btime` is derived from the realtime clock and moves
|
|
204
204
|
* with every clock step, so a wall-clock comparison against a recorded
|
|
205
205
|
* acquisition time misjudges a live holder as a reused PID after NTP steps
|
|
206
|
-
* the clock forward
|
|
206
|
+
* the clock forward, and reaps a lock that is in use.
|
|
207
207
|
*
|
|
208
208
|
* @param pid - Process to look up
|
|
209
209
|
* @param procRoot - procfs mount, overridable for tests
|
|
@@ -213,7 +213,7 @@ export function readProcessStartTick(pid, procRoot = '/proc') {
|
|
|
213
213
|
try {
|
|
214
214
|
const stat = readFileSync(join(procRoot, String(pid), 'stat'), 'utf-8');
|
|
215
215
|
// `comm` (field 2) is parenthesised and may itself contain spaces or
|
|
216
|
-
// parentheses, so split only what follows the
|
|
216
|
+
// parentheses, so split only what follows the last closing paren:
|
|
217
217
|
// field 3 (state) is then index 0 and field 22 (starttime) index 19.
|
|
218
218
|
const startTick = Number.parseInt(stat
|
|
219
219
|
.slice(stat.lastIndexOf(')') + 1)
|
|
@@ -226,10 +226,10 @@ export function readProcessStartTick(pid, procRoot = '/proc') {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
/**
|
|
229
|
-
* Whether the process named by a lock's owner record is the
|
|
229
|
+
* Whether the process named by a lock's owner record is the same process
|
|
230
230
|
* that acquired the lock, not merely a live process wearing its PID.
|
|
231
231
|
*
|
|
232
|
-
* `isProcessAlive` answers "does this PID exist"
|
|
232
|
+
* `isProcessAlive` answers "does this PID exist". After a holder crashes,
|
|
233
233
|
* the kernel may hand its PID to a long-lived daemon, and a PID-only check
|
|
234
234
|
* then honours the dead lock until the waiter's timeout. Where the record
|
|
235
235
|
* carries the writer's start tick and the candidate's own tick is cheaply
|