@hominis/fireforge 0.44.4 → 0.46.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 +120 -0
- package/dist/bin/fireforge.js +6 -0
- package/dist/build-info.json +4 -4
- package/dist/src/cli-usage-error.d.ts +46 -0
- package/dist/src/cli-usage-error.js +81 -0
- package/dist/src/cli.d.ts +5 -1
- package/dist/src/cli.js +20 -21
- package/dist/src/commands/bootstrap.js +1 -2
- package/dist/src/commands/build.js +15 -6
- package/dist/src/commands/destructive-decision.d.ts +19 -0
- package/dist/src/commands/destructive-decision.js +31 -0
- package/dist/src/commands/doctor-check-core.d.ts +0 -6
- package/dist/src/commands/doctor-check-core.js +0 -8
- package/dist/src/commands/doctor-orphaned-harness.d.ts +0 -6
- package/dist/src/commands/doctor-orphaned-harness.js +4 -12
- package/dist/src/commands/doctor-post-rebase-audit.js +1 -1
- package/dist/src/commands/doctor-source-pin.d.ts +29 -0
- package/dist/src/commands/doctor-source-pin.js +81 -0
- package/dist/src/commands/doctor.d.ts +2 -0
- package/dist/src/commands/doctor.js +9 -8
- package/dist/src/commands/download.js +35 -24
- package/dist/src/commands/export-all.js +21 -4
- package/dist/src/commands/export-flow.js +15 -60
- package/dist/src/commands/export-placement-conflicts.js +3 -3
- package/dist/src/commands/export-placement-gate.js +2 -8
- package/dist/src/commands/export-placement-policy.js +3 -5
- package/dist/src/commands/export-shared.d.ts +42 -23
- package/dist/src/commands/export-shared.js +4 -19
- package/dist/src/commands/export.js +10 -1
- package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
- package/dist/src/commands/furnace/authoring-config.js +19 -0
- package/dist/src/commands/furnace/chrome-doc-remove.js +1 -1
- package/dist/src/commands/furnace/create-browser-test.js +3 -8
- package/dist/src/commands/furnace/create-dry-run.js +2 -5
- package/dist/src/commands/furnace/create-templates.d.ts +17 -1
- package/dist/src/commands/furnace/create-templates.js +2 -1
- package/dist/src/commands/furnace/create.js +25 -19
- package/dist/src/commands/furnace/deploy.js +11 -2
- package/dist/src/commands/furnace/init.js +2 -1
- package/dist/src/commands/furnace/override.js +28 -19
- package/dist/src/commands/furnace/refresh.js +9 -1
- package/dist/src/commands/furnace/remove-mutations.d.ts +6 -7
- package/dist/src/commands/furnace/remove-mutations.js +0 -1
- package/dist/src/commands/furnace/remove.js +2 -6
- package/dist/src/commands/furnace/rename-browser-test.js +1 -7
- package/dist/src/commands/furnace/rename.js +29 -29
- package/dist/src/commands/furnace/status.js +12 -9
- package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
- package/dist/src/commands/furnace/test-file-name.js +39 -0
- package/dist/src/commands/furnace/validation-output.d.ts +21 -9
- package/dist/src/commands/furnace/validation-output.js +3 -8
- package/dist/src/commands/import.js +2 -9
- package/dist/src/commands/lint-per-patch.d.ts +2 -2
- package/dist/src/commands/lint-per-patch.js +19 -4
- package/dist/src/commands/lint-per-run-checkjs.d.ts +2 -2
- package/dist/src/commands/lint.d.ts +2 -1
- package/dist/src/commands/lint.js +1 -1
- package/dist/src/commands/manifest.js +1 -1
- package/dist/src/commands/package.js +2 -4
- package/dist/src/commands/patch/compact.js +14 -15
- package/dist/src/commands/patch/delete.js +15 -25
- package/dist/src/commands/patch/entry-projection.d.ts +13 -0
- package/dist/src/commands/patch/entry-projection.js +24 -0
- package/dist/src/commands/patch/lint-ignore.d.ts +0 -8
- package/dist/src/commands/patch/lint-ignore.js +19 -29
- package/dist/src/commands/patch/move-files-create.js +24 -10
- package/dist/src/commands/patch/move-files-into.js +38 -37
- package/dist/src/commands/patch/move-files.js +4 -13
- package/dist/src/commands/patch/rename.js +27 -41
- package/dist/src/commands/patch/reorder.js +25 -38
- package/dist/src/commands/patch/split-plan.d.ts +4 -5
- package/dist/src/commands/patch/split-plan.js +4 -11
- package/dist/src/commands/patch/split.js +45 -43
- package/dist/src/commands/patch/staged-dependency.js +16 -22
- package/dist/src/commands/patch/tier.js +15 -25
- package/dist/src/commands/patch-rename-map.d.ts +19 -0
- package/dist/src/commands/patch-rename-map.js +36 -0
- package/dist/src/commands/pending-resolution.d.ts +15 -0
- package/dist/src/commands/pending-resolution.js +25 -0
- package/dist/src/commands/re-export-adjacent.d.ts +32 -2
- package/dist/src/commands/re-export-adjacent.js +51 -10
- package/dist/src/commands/re-export-bulk-scan.js +6 -10
- package/dist/src/commands/re-export-drift.d.ts +8 -0
- package/dist/src/commands/re-export-drift.js +65 -4
- package/dist/src/commands/re-export-files.d.ts +2 -3
- package/dist/src/commands/re-export-files.js +38 -32
- package/dist/src/commands/re-export-lint.d.ts +3 -4
- package/dist/src/commands/re-export-lint.js +9 -2
- package/dist/src/commands/re-export-options.js +19 -5
- package/dist/src/commands/re-export-register.js +5 -1
- package/dist/src/commands/re-export-scan.js +8 -8
- package/dist/src/commands/re-export-single.d.ts +22 -3
- package/dist/src/commands/re-export-single.js +19 -11
- package/dist/src/commands/re-export.js +44 -27
- package/dist/src/commands/rebase/abort.js +3 -8
- package/dist/src/commands/rebase/continue.js +12 -12
- package/dist/src/commands/rebase/index.js +2 -2
- package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
- package/dist/src/commands/rebase/patch-loop.js +2 -7
- package/dist/src/commands/resolve.js +18 -10
- package/dist/src/commands/run.d.ts +0 -13
- package/dist/src/commands/run.js +12 -25
- package/dist/src/commands/setup-support.d.ts +16 -4
- package/dist/src/commands/setup-support.js +16 -16
- package/dist/src/commands/setup.js +3 -9
- package/dist/src/commands/source.js +8 -1
- package/dist/src/commands/status-check.js +2 -2
- package/dist/src/commands/status-output.js +2 -2
- package/dist/src/commands/status.js +3 -4
- package/dist/src/commands/test-build-phase.d.ts +2 -2
- package/dist/src/commands/test-build-phase.js +33 -8
- package/dist/src/commands/test-diagnose.js +14 -5
- package/dist/src/commands/test-modes.d.ts +2 -2
- package/dist/src/commands/test-modes.js +0 -1
- package/dist/src/commands/test-register.js +6 -3
- package/dist/src/commands/test-run.js +29 -21
- package/dist/src/commands/test-stale-gate.js +8 -5
- package/dist/src/commands/test-verdict.d.ts +16 -2
- package/dist/src/commands/test-verdict.js +18 -3
- package/dist/src/commands/test.js +51 -7
- package/dist/src/commands/token-list.d.ts +26 -0
- package/dist/src/commands/token-list.js +153 -0
- package/dist/src/commands/token.js +17 -1
- package/dist/src/commands/tree.js +7 -2
- package/dist/src/commands/typecheck.js +9 -9
- package/dist/src/commands/wire.js +4 -3
- package/dist/src/core/branding.d.ts +0 -7
- package/dist/src/core/branding.js +3 -2
- package/dist/src/core/browser-wire.js +6 -3
- package/dist/src/core/build-audit-platform.d.ts +29 -0
- package/dist/src/core/build-audit-platform.js +140 -0
- package/dist/src/core/build-audit-registration.js +3 -2
- package/dist/src/core/build-audit-skip.d.ts +57 -0
- package/dist/src/core/build-audit-skip.js +112 -0
- package/dist/src/core/build-audit.d.ts +15 -2
- package/dist/src/core/build-audit.js +154 -12
- package/dist/src/core/build-baseline.d.ts +45 -28
- package/dist/src/core/build-baseline.js +6 -29
- package/dist/src/core/build-jar-escalation.d.ts +64 -0
- package/dist/src/core/build-jar-escalation.js +128 -0
- package/dist/src/core/build-overwrite-guard.js +1 -1
- package/dist/src/core/build-prepare.d.ts +5 -2
- package/dist/src/core/build-prepare.js +34 -6
- package/dist/src/core/config-paths.d.ts +2 -6
- package/dist/src/core/config-paths.js +4 -2
- package/dist/src/core/config-state.d.ts +0 -6
- package/dist/src/core/config-state.js +1 -19
- package/dist/src/core/config-validate-build-audit.d.ts +8 -0
- package/dist/src/core/config-validate-build-audit.js +80 -0
- package/dist/src/core/config-validate-file-size.d.ts +12 -0
- package/dist/src/core/config-validate-file-size.js +65 -0
- package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
- package/dist/src/core/config-validate-patch-policy.js +3 -3
- package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
- package/dist/src/core/config-validate-test-toolchains.js +4 -5
- package/dist/src/core/config-validate.js +20 -3
- package/dist/src/core/config.d.ts +2 -2
- package/dist/src/core/config.js +11 -15
- package/dist/src/core/coverage-extend.js +4 -4
- package/dist/src/core/discard-baseline.js +7 -7
- package/dist/src/core/engine-precondition.d.ts +1 -9
- package/dist/src/core/engine-precondition.js +3 -8
- package/dist/src/core/engine-session-lock.js +13 -17
- package/dist/src/core/export-moved-code-shape.js +2 -2
- package/dist/src/core/file-lock-owner.d.ts +103 -0
- package/dist/src/core/file-lock-owner.js +259 -0
- package/dist/src/core/file-lock.d.ts +2 -7
- package/dist/src/core/file-lock.js +40 -91
- package/dist/src/core/firefox-cache.d.ts +13 -1
- package/dist/src/core/firefox-cache.js +59 -34
- package/dist/src/core/firefox-download.d.ts +15 -0
- package/dist/src/core/firefox-download.js +37 -21
- package/dist/src/core/firefox-extract.d.ts +6 -5
- package/dist/src/core/firefox-extract.js +36 -18
- package/dist/src/core/firefox.d.ts +30 -32
- package/dist/src/core/firefox.js +5 -36
- package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
- package/dist/src/core/furnace-apply-dry-run.js +1 -7
- package/dist/src/core/furnace-apply-helpers.d.ts +0 -11
- package/dist/src/core/furnace-apply-helpers.js +8 -19
- package/dist/src/core/furnace-apply-overwrite-warn.js +4 -2
- package/dist/src/core/furnace-apply.d.ts +1 -1
- package/dist/src/core/furnace-apply.js +30 -10
- package/dist/src/core/furnace-config.d.ts +1 -1
- package/dist/src/core/furnace-config.js +23 -36
- package/dist/src/core/furnace-constants.js +3 -2
- package/dist/src/core/furnace-dir-entry.d.ts +20 -0
- package/dist/src/core/furnace-dir-entry.js +21 -0
- package/dist/src/core/furnace-operation.d.ts +2 -0
- package/dist/src/core/furnace-operation.js +3 -1
- package/dist/src/core/furnace-refresh.d.ts +18 -6
- package/dist/src/core/furnace-refresh.js +3 -6
- package/dist/src/core/furnace-registration-ast.d.ts +0 -1
- package/dist/src/core/furnace-registration-ast.js +0 -3
- package/dist/src/core/furnace-registration.d.ts +2 -1
- package/dist/src/core/furnace-registration.js +22 -29
- package/dist/src/core/furnace-scanner.js +3 -6
- package/dist/src/core/furnace-state-persist.d.ts +2 -2
- package/dist/src/core/furnace-validate-registration.js +5 -7
- package/dist/src/core/git-base.d.ts +3 -1
- package/dist/src/core/git-base.js +25 -3
- package/dist/src/core/git-diff-new-file.d.ts +40 -0
- package/dist/src/core/git-diff-new-file.js +119 -0
- package/dist/src/core/git-diff.d.ts +9 -9
- package/dist/src/core/git-diff.js +88 -157
- package/dist/src/core/git-file-ops.d.ts +0 -7
- package/dist/src/core/git-file-ops.js +4 -28
- package/dist/src/core/git-readonly-index.d.ts +0 -2
- package/dist/src/core/git-readonly-index.js +0 -4
- package/dist/src/core/git-status.d.ts +7 -0
- package/dist/src/core/git-status.js +21 -9
- package/dist/src/core/git.d.ts +0 -6
- package/dist/src/core/git.js +14 -43
- package/dist/src/core/harness-orphans.d.ts +73 -0
- package/dist/src/core/harness-orphans.js +187 -0
- package/dist/src/core/history-log.d.ts +19 -0
- package/dist/src/core/history-log.js +29 -0
- package/dist/src/core/mach-error-hints.d.ts +0 -5
- package/dist/src/core/mach-error-hints.js +1 -1
- package/dist/src/core/mach-known-noise-filter.d.ts +25 -3
- package/dist/src/core/mach-known-noise-filter.js +31 -10
- package/dist/src/core/mach-mozconfig.js +2 -1
- package/dist/src/core/mach-python.d.ts +2 -0
- package/dist/src/core/mach-python.js +12 -7
- package/dist/src/core/mach-resource-shim.d.ts +13 -1
- package/dist/src/core/mach-resource-shim.js +112 -9
- package/dist/src/core/mach.d.ts +46 -53
- package/dist/src/core/mach.js +31 -83
- package/dist/src/core/marionette-port.d.ts +0 -17
- package/dist/src/core/marionette-port.js +12 -58
- package/dist/src/core/marionette-preflight.js +9 -27
- package/dist/src/core/mochitest-server-port.js +3 -3
- package/dist/src/core/moz-manifest-rules.js +37 -33
- package/dist/src/core/patch-apply-fuzz.js +4 -4
- package/dist/src/core/patch-apply.d.ts +4 -5
- package/dist/src/core/patch-apply.js +55 -32
- package/dist/src/core/patch-export-coverage.d.ts +0 -9
- package/dist/src/core/patch-export-coverage.js +1 -30
- package/dist/src/core/patch-export-update.d.ts +18 -1
- package/dist/src/core/patch-export-update.js +4 -3
- package/dist/src/core/patch-export.d.ts +11 -21
- package/dist/src/core/patch-export.js +44 -66
- package/dist/src/core/patch-files.d.ts +0 -4
- package/dist/src/core/patch-files.js +0 -11
- package/dist/src/core/patch-lint-binary.d.ts +6 -12
- package/dist/src/core/patch-lint-cache.d.ts +17 -1
- package/dist/src/core/patch-lint-cache.js +3 -6
- package/dist/src/core/patch-lint-checkjs.d.ts +33 -16
- package/dist/src/core/patch-lint-checkjs.js +43 -25
- package/dist/src/core/patch-lint-creators.d.ts +2 -6
- package/dist/src/core/patch-lint-cross.d.ts +16 -8
- package/dist/src/core/patch-lint-cross.js +49 -92
- package/dist/src/core/patch-lint-css.js +10 -6
- package/dist/src/core/patch-lint-file-size.d.ts +52 -0
- package/dist/src/core/patch-lint-file-size.js +53 -0
- package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
- package/dist/src/core/patch-lint-forward-registration.js +210 -0
- package/dist/src/core/patch-lint-jsdoc.js +36 -36
- package/dist/src/core/patch-lint-module-registration.d.ts +2 -8
- package/dist/src/core/patch-lint-prettier.d.ts +36 -0
- package/dist/src/core/patch-lint-prettier.js +126 -0
- package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
- package/dist/src/core/patch-lint-queue-types.js +12 -0
- package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
- package/dist/src/core/patch-lint-staged-registration.js +90 -0
- package/dist/src/core/patch-lint-unmanaged-companion.d.ts +106 -0
- package/dist/src/core/patch-lint-unmanaged-companion.js +214 -0
- package/dist/src/core/patch-lint.d.ts +14 -9
- package/dist/src/core/patch-lint.js +27 -27
- package/dist/src/core/patch-lock.js +3 -3
- package/dist/src/core/patch-manifest-io.js +8 -7
- package/dist/src/core/patch-parse.d.ts +19 -8
- package/dist/src/core/patch-parse.js +25 -0
- package/dist/src/core/patch-policy.js +15 -27
- package/dist/src/core/patch-source-metadata.d.ts +1 -3
- package/dist/src/core/patch-source-metadata.js +0 -4
- package/dist/src/core/patch-transform.d.ts +21 -8
- package/dist/src/core/patch-transform.js +38 -10
- package/dist/src/core/process-cpu-time.js +1 -1
- package/dist/src/core/rebase-session.d.ts +2 -8
- package/dist/src/core/rebase-session.js +5 -17
- package/dist/src/core/register-browser-content.js +3 -2
- package/dist/src/core/register-browser-test.js +2 -1
- package/dist/src/core/register-module.js +2 -1
- package/dist/src/core/register-scaffold.js +5 -4
- package/dist/src/core/register-shared-css.js +2 -1
- package/dist/src/core/run-log-redact.d.ts +38 -0
- package/dist/src/core/run-log-redact.js +69 -0
- package/dist/src/core/run-log.d.ts +13 -2
- package/dist/src/core/run-log.js +67 -18
- package/dist/src/core/signal-critical.js +2 -4
- package/dist/src/core/smoke-patterns.d.ts +0 -1
- package/dist/src/core/smoke-patterns.js +18 -11
- package/dist/src/core/state-file.d.ts +12 -1
- package/dist/src/core/state-file.js +14 -1
- package/dist/src/core/status-classify.js +2 -1
- package/dist/src/core/test-changed-prefs.js +26 -11
- package/dist/src/core/test-harness-crash.js +61 -48
- package/dist/src/core/test-harness-verdict-notes.d.ts +55 -0
- package/dist/src/core/test-harness-verdict-notes.js +48 -0
- package/dist/src/core/test-stale-check.d.ts +23 -8
- package/dist/src/core/test-stale-check.js +77 -4
- package/dist/src/core/test-stall-triage.js +37 -19
- package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
- package/dist/src/core/test-xpcshell-retry.js +14 -11
- package/dist/src/core/token-category.d.ts +33 -0
- package/dist/src/core/token-category.js +56 -48
- package/dist/src/core/token-dark-mode.js +2 -14
- package/dist/src/core/token-inventory.d.ts +56 -0
- package/dist/src/core/token-inventory.js +109 -0
- package/dist/src/core/token-manager.d.ts +1 -1
- package/dist/src/core/token-manager.js +1 -1
- package/dist/src/core/token-variant.js +21 -22
- package/dist/src/core/toolchain-preflight.js +1 -1
- package/dist/src/core/tree-cow.d.ts +0 -2
- package/dist/src/core/tree-cow.js +2 -2
- package/dist/src/core/tree-store.js +4 -5
- package/dist/src/core/typecheck.js +2 -2
- package/dist/src/core/wire-dom-fragment.js +6 -17
- package/dist/src/core/wire-utils.js +5 -17
- package/dist/src/core/xpcshell-appdir.js +2 -4
- package/dist/src/errors/base.d.ts +53 -1
- package/dist/src/errors/base.js +79 -11
- package/dist/src/errors/build.d.ts +28 -0
- package/dist/src/errors/build.js +51 -10
- package/dist/src/errors/config.d.ts +0 -14
- package/dist/src/errors/config.js +13 -34
- package/dist/src/errors/download.d.ts +13 -0
- package/dist/src/errors/download.js +53 -24
- package/dist/src/errors/furnace.js +8 -9
- package/dist/src/errors/git.d.ts +8 -8
- package/dist/src/errors/git.js +20 -30
- package/dist/src/errors/patch.js +8 -10
- package/dist/src/errors/rebase.js +7 -7
- package/dist/src/types/commands/options.d.ts +96 -123
- package/dist/src/types/commands/patches.d.ts +17 -6
- package/dist/src/types/config.d.ts +75 -2
- package/dist/src/types/index.d.ts +0 -1
- package/dist/src/utils/assert.d.ts +3 -15
- package/dist/src/utils/assert.js +1 -18
- package/dist/src/utils/build-info.d.ts +1 -1
- package/dist/src/utils/child-env.d.ts +2 -1
- package/dist/src/utils/elapsed.js +10 -1
- package/dist/src/utils/fs.d.ts +4 -2
- package/dist/src/utils/fs.js +11 -14
- package/dist/src/utils/hash.d.ts +12 -0
- package/dist/src/utils/hash.js +16 -0
- package/dist/src/utils/line-dispatch.d.ts +15 -0
- package/dist/src/utils/line-dispatch.js +48 -0
- package/dist/src/utils/options.d.ts +1 -7
- package/dist/src/utils/options.js +6 -7
- package/dist/src/utils/package-root.js +3 -12
- package/dist/src/utils/platform.d.ts +0 -4
- package/dist/src/utils/process-group.d.ts +2 -1
- package/dist/src/utils/process-group.js +20 -19
- package/dist/src/utils/process.d.ts +40 -26
- package/dist/src/utils/process.js +115 -166
- package/dist/src/utils/ps-duration.js +3 -3
- package/dist/src/utils/sleep.d.ts +26 -0
- package/dist/src/utils/sleep.js +31 -0
- package/dist/src/utils/validation.d.ts +2 -38
- package/dist/src/utils/validation.js +7 -16
- package/docs/configuration.md +136 -1
- package/docs/exit-codes.md +34 -20
- package/docs/lifecycle-invariants.md +18 -12
- package/docs/machine-output.md +31 -8
- package/docs/patch-workflow.md +2 -1
- package/docs/run-logs.md +44 -4
- package/docs/testing.md +70 -11
- package/package.json +8 -7
- package/dist/src/commands/rebase.d.ts +0 -4
- package/dist/src/commands/rebase.js +0 -5
- package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
- package/dist/src/core/patch-artifact-normalize.js +0 -24
- package/dist/src/core/patch-lint-reexports.d.ts +0 -7
- package/dist/src/core/patch-lint-reexports.js +0 -8
- package/dist/src/core/wire-targets.d.ts +0 -7
- package/dist/src/core/wire-targets.js +0 -8
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* file sits on a 500-line budget; the logic belongs to the exec layer.
|
|
6
6
|
*/
|
|
7
7
|
/** The `env` / `envUnset` slice of exec options this module needs. */
|
|
8
|
-
|
|
8
|
+
interface ChildEnvOptions {
|
|
9
9
|
/** Variables to add or overwrite on top of `process.env`. */
|
|
10
10
|
env?: Record<string, string> | undefined;
|
|
11
11
|
/** Variables to remove after the merge. */
|
|
@@ -28,3 +28,4 @@ export interface ChildEnvOptions {
|
|
|
28
28
|
* @returns The environment to hand `spawn`
|
|
29
29
|
*/
|
|
30
30
|
export declare function buildChildEnv(options: ChildEnvOptions): NodeJS.ProcessEnv;
|
|
31
|
+
export {};
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Formats a duration in milliseconds as `Xm Ys`, or `Ys` under a minute.
|
|
4
|
+
*
|
|
5
|
+
* The single spelling of FireForge's elapsed-time wording: `build` and
|
|
6
|
+
* `package` each hand-rolled the same minute/second split, so a change to
|
|
7
|
+
* the format silently applied to some progress lines and not others.
|
|
8
|
+
*
|
|
9
|
+
* @param ms - Duration in milliseconds; negative input is clamped to zero.
|
|
10
|
+
* @returns The duration as `Xm Ys`, or `Ys` when under one minute.
|
|
11
|
+
*/
|
|
3
12
|
function formatElapsed(ms) {
|
|
4
13
|
const totalSeconds = Math.max(0, Math.round(ms / 1000));
|
|
5
14
|
const minutes = Math.floor(totalSeconds / 60);
|
package/dist/src/utils/fs.d.ts
CHANGED
|
@@ -76,9 +76,11 @@ export declare function writeTextIfChanged(path: string, content: string): Promi
|
|
|
76
76
|
* Writes content atomically using a temp-file-and-rename strategy.
|
|
77
77
|
* Temp files are created in the destination directory so rename stays atomic.
|
|
78
78
|
* @param path - Destination file path
|
|
79
|
-
* @param content - Content to write
|
|
79
|
+
* @param content - Content to write. `Uint8Array` rather than `Buffer` so
|
|
80
|
+
* published types never name a Node global (every `Buffer` still assigns
|
|
81
|
+
* to it, and `fs.writeFile` accepts both).
|
|
80
82
|
*/
|
|
81
|
-
export declare function writeFileAtomic(path: string, content: string |
|
|
83
|
+
export declare function writeFileAtomic(path: string, content: string | Uint8Array): Promise<void>;
|
|
82
84
|
/**
|
|
83
85
|
* Copies a directory recursively.
|
|
84
86
|
* @param src - Source directory path
|
package/dist/src/utils/fs.js
CHANGED
|
@@ -3,13 +3,9 @@ import { randomUUID } from 'node:crypto';
|
|
|
3
3
|
import { access, chmod, copyFile as fsCopyFile, lstat, mkdir, open, readdir, readFile, rename, rm, stat, statfs, } from 'node:fs/promises';
|
|
4
4
|
import { basename, dirname, join } from 'node:path';
|
|
5
5
|
import { getNodeErrorCode } from './errors.js';
|
|
6
|
+
import { sleep } from './sleep.js';
|
|
6
7
|
const RETRIABLE_REMOVE_ERRORS = new Set(['ENOTEMPTY', 'EBUSY', 'EPERM']);
|
|
7
8
|
const RETRIABLE_RENAME_ERRORS = new Set(['EPERM', 'EACCES', 'EBUSY']);
|
|
8
|
-
function sleep(ms) {
|
|
9
|
-
return new Promise((resolve) => {
|
|
10
|
-
setTimeout(resolve, ms);
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
9
|
/**
|
|
14
10
|
* Checks if a path exists.
|
|
15
11
|
* @param path - Path to check
|
|
@@ -19,8 +15,7 @@ export async function pathExists(path) {
|
|
|
19
15
|
await access(path);
|
|
20
16
|
return true;
|
|
21
17
|
}
|
|
22
|
-
catch
|
|
23
|
-
void error;
|
|
18
|
+
catch {
|
|
24
19
|
return false;
|
|
25
20
|
}
|
|
26
21
|
}
|
|
@@ -92,8 +87,7 @@ export async function isSymlink(path) {
|
|
|
92
87
|
try {
|
|
93
88
|
return (await lstat(path)).isSymbolicLink();
|
|
94
89
|
}
|
|
95
|
-
catch
|
|
96
|
-
void error;
|
|
90
|
+
catch {
|
|
97
91
|
return false;
|
|
98
92
|
}
|
|
99
93
|
}
|
|
@@ -165,7 +159,9 @@ export async function writeTextIfChanged(path, content) {
|
|
|
165
159
|
* Writes content atomically using a temp-file-and-rename strategy.
|
|
166
160
|
* Temp files are created in the destination directory so rename stays atomic.
|
|
167
161
|
* @param path - Destination file path
|
|
168
|
-
* @param content - Content to write
|
|
162
|
+
* @param content - Content to write. `Uint8Array` rather than `Buffer` so
|
|
163
|
+
* published types never name a Node global (every `Buffer` still assigns
|
|
164
|
+
* to it, and `fs.writeFile` accepts both).
|
|
169
165
|
*/
|
|
170
166
|
export async function writeFileAtomic(path, content) {
|
|
171
167
|
await ensureParentDir(path);
|
|
@@ -232,15 +228,16 @@ async function syncParentDir(path) {
|
|
|
232
228
|
directoryHandle = await open(dirname(path), 'r');
|
|
233
229
|
await directoryHandle.sync();
|
|
234
230
|
}
|
|
235
|
-
catch
|
|
236
|
-
|
|
231
|
+
catch {
|
|
232
|
+
// Best-effort durability: a directory that cannot be opened or fsynced
|
|
233
|
+
// (network mounts, Windows) must not fail the write it was protecting.
|
|
237
234
|
}
|
|
238
235
|
finally {
|
|
239
236
|
try {
|
|
240
237
|
await directoryHandle?.close();
|
|
241
238
|
}
|
|
242
|
-
catch
|
|
243
|
-
|
|
239
|
+
catch {
|
|
240
|
+
// Nothing left to do — the handle is being discarded either way.
|
|
244
241
|
}
|
|
245
242
|
}
|
|
246
243
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes the hexadecimal SHA-256 digest of a string or buffer.
|
|
3
|
+
*
|
|
4
|
+
* Eleven sites across `src/core/` inlined the same
|
|
5
|
+
* `createHash('sha256').update(input).digest('hex')` chain for cache keys,
|
|
6
|
+
* fingerprints and content addresses. They all share this helper instead, so
|
|
7
|
+
* the digest algorithm and encoding are decided in exactly one place.
|
|
8
|
+
*
|
|
9
|
+
* @param input - Data to digest, as a UTF-8 string or a raw buffer.
|
|
10
|
+
* @returns The 64-character lowercase hexadecimal digest.
|
|
11
|
+
*/
|
|
12
|
+
export declare function sha256Hex(input: string | Buffer): string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
/**
|
|
4
|
+
* Computes the hexadecimal SHA-256 digest of a string or buffer.
|
|
5
|
+
*
|
|
6
|
+
* Eleven sites across `src/core/` inlined the same
|
|
7
|
+
* `createHash('sha256').update(input).digest('hex')` chain for cache keys,
|
|
8
|
+
* fingerprints and content addresses. They all share this helper instead, so
|
|
9
|
+
* the digest algorithm and encoding are decided in exactly one place.
|
|
10
|
+
*
|
|
11
|
+
* @param input - Data to digest, as a UTF-8 string or a raw buffer.
|
|
12
|
+
* @returns The 64-character lowercase hexadecimal digest.
|
|
13
|
+
*/
|
|
14
|
+
export function sha256Hex(input) {
|
|
15
|
+
return createHash('sha256').update(input).digest('hex');
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line splitting for the smoke-run stream dispatch in `process.ts`. Kept as
|
|
3
|
+
* a sibling so the exec module stays within its size budget; the contract
|
|
4
|
+
* (terminators, partial-line cap) is documented on the function.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Drains complete lines from `buffer`, dispatching each to `cb`. Treats
|
|
8
|
+
* `\n`, `\r\n`, and lone `\r` as line terminators — the lone-`\r` case
|
|
9
|
+
* matters for progress-bar style output (mach, cargo) that repaints a line
|
|
10
|
+
* with carriage returns and never sends a newline, which otherwise
|
|
11
|
+
* accumulates indefinitely. A single trailing `\r` is held back since it may
|
|
12
|
+
* be the first half of a `\r\n` pair split across chunks. Returns the
|
|
13
|
+
* remaining partial line — callers keep accumulating into it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function dispatchCompleteLines(buffer: string, cb: ((line: string) => void) | undefined): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Line splitting for the smoke-run stream dispatch in `process.ts`. Kept as
|
|
4
|
+
* a sibling so the exec module stays within its size budget; the contract
|
|
5
|
+
* (terminators, partial-line cap) is documented on the function.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Cap on the partial-line tail kept between chunks. A child emitting one
|
|
9
|
+
* enormous line with no terminator (minified JS dumped to stderr, a raw
|
|
10
|
+
* binary blob) would otherwise grow the buffer without bound — the 50 MB cap
|
|
11
|
+
* guards the collector, not these line buffers. When the tail exceeds the
|
|
12
|
+
* cap it is dispatched as a synthetic (oversized) line so the matchers still
|
|
13
|
+
* see its content, then the buffer resets.
|
|
14
|
+
*/
|
|
15
|
+
const MAX_PARTIAL_LINE_SIZE = 1024 * 1024;
|
|
16
|
+
/**
|
|
17
|
+
* Drains complete lines from `buffer`, dispatching each to `cb`. Treats
|
|
18
|
+
* `\n`, `\r\n`, and lone `\r` as line terminators — the lone-`\r` case
|
|
19
|
+
* matters for progress-bar style output (mach, cargo) that repaints a line
|
|
20
|
+
* with carriage returns and never sends a newline, which otherwise
|
|
21
|
+
* accumulates indefinitely. A single trailing `\r` is held back since it may
|
|
22
|
+
* be the first half of a `\r\n` pair split across chunks. Returns the
|
|
23
|
+
* remaining partial line — callers keep accumulating into it.
|
|
24
|
+
*/
|
|
25
|
+
export function dispatchCompleteLines(buffer, cb) {
|
|
26
|
+
let searchFrom = 0;
|
|
27
|
+
for (;;) {
|
|
28
|
+
const nl = buffer.indexOf('\n', searchFrom);
|
|
29
|
+
const cr = buffer.indexOf('\r', searchFrom);
|
|
30
|
+
const idx = nl === -1 ? cr : cr === -1 ? nl : Math.min(nl, cr);
|
|
31
|
+
if (idx === -1)
|
|
32
|
+
break;
|
|
33
|
+
if (buffer[idx] === '\r' && idx === buffer.length - 1) {
|
|
34
|
+
// Possible first half of a chunk-split \r\n — wait for the next chunk.
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
const line = buffer.slice(0, idx);
|
|
38
|
+
const terminatorLength = buffer[idx] === '\r' && buffer[idx + 1] === '\n' ? 2 : 1;
|
|
39
|
+
buffer = buffer.slice(idx + terminatorLength);
|
|
40
|
+
searchFrom = 0;
|
|
41
|
+
cb?.(line);
|
|
42
|
+
}
|
|
43
|
+
if (buffer.length > MAX_PARTIAL_LINE_SIZE) {
|
|
44
|
+
cb?.(buffer);
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
return buffer;
|
|
48
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
1
2
|
/**
|
|
2
3
|
* Filters an object to only include keys whose values are not undefined.
|
|
3
4
|
* Designed for use with exactOptionalPropertyTypes — the result can be
|
|
@@ -15,7 +16,6 @@
|
|
|
15
16
|
export declare function pickDefined<T extends object>(obj: T): {
|
|
16
17
|
[K in keyof T]+?: Exclude<T[K], undefined>;
|
|
17
18
|
};
|
|
18
|
-
import type { Command } from 'commander';
|
|
19
19
|
/**
|
|
20
20
|
* Wraps an option-argument parser so its failures surface through
|
|
21
21
|
* commander's own invalid-argument channel.
|
|
@@ -88,12 +88,6 @@ export declare function resolveWaitLockSeconds(value: string | number | boolean
|
|
|
88
88
|
* @returns The session budget in milliseconds, or undefined
|
|
89
89
|
*/
|
|
90
90
|
export declare function sessionWaitLockMs(): number | undefined;
|
|
91
|
-
/**
|
|
92
|
-
* True when `command` already declares `--wait-lock` itself. Used by the
|
|
93
|
-
* CLI wiring to add the accept-and-ignore variant only where the honoring
|
|
94
|
-
* one is absent.
|
|
95
|
-
*/
|
|
96
|
-
export declare function hasWaitLockOption(command: Command): boolean;
|
|
97
91
|
/**
|
|
98
92
|
* Recursively gives every command in the tree a `--wait-lock` flag: the
|
|
99
93
|
* honoring registration where one already exists, the accept-and-ignore
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { InvalidArgumentError as CommanderInvalidArgumentError } from 'commander';
|
|
2
|
+
import { GeneralError, InvalidArgumentError } from '../errors/base.js';
|
|
3
|
+
import { toError } from './errors.js';
|
|
2
4
|
/**
|
|
3
5
|
* Filters an object to only include keys whose values are not undefined.
|
|
4
6
|
* Designed for use with exactOptionalPropertyTypes — the result can be
|
|
@@ -22,9 +24,6 @@ export function pickDefined(obj) {
|
|
|
22
24
|
}
|
|
23
25
|
return result;
|
|
24
26
|
}
|
|
25
|
-
import { InvalidArgumentError as CommanderInvalidArgumentError } from 'commander';
|
|
26
|
-
import { GeneralError, InvalidArgumentError } from '../errors/base.js';
|
|
27
|
-
import { toError } from './errors.js';
|
|
28
27
|
/**
|
|
29
28
|
* Wraps an option-argument parser so its failures surface through
|
|
30
29
|
* commander's own invalid-argument channel.
|
|
@@ -106,7 +105,7 @@ function waitLockSecondsFromEnv() {
|
|
|
106
105
|
}
|
|
107
106
|
const parsed = parseWaitLockSeconds(raw);
|
|
108
107
|
if (parsed === undefined) {
|
|
109
|
-
throw new InvalidArgumentError(`${WAIT_LOCK_ENV_VAR} must be an integer in ${
|
|
108
|
+
throw new InvalidArgumentError(`${WAIT_LOCK_ENV_VAR} must be an integer in ${MIN_WAIT_LOCK_SECONDS}..${MAX_WAIT_LOCK_SECONDS} (got "${raw}")`, WAIT_LOCK_ENV_VAR);
|
|
110
109
|
}
|
|
111
110
|
return parsed;
|
|
112
111
|
}
|
|
@@ -140,7 +139,7 @@ export function resolveWaitLockSeconds(value) {
|
|
|
140
139
|
}
|
|
141
140
|
const parsed = parseWaitLockSeconds(value);
|
|
142
141
|
if (parsed === undefined) {
|
|
143
|
-
throw new GeneralError(`--wait-lock must be an integer in ${
|
|
142
|
+
throw new GeneralError(`--wait-lock must be an integer in ${MIN_WAIT_LOCK_SECONDS}..${MAX_WAIT_LOCK_SECONDS} (got "${value}")`);
|
|
144
143
|
}
|
|
145
144
|
return parsed;
|
|
146
145
|
}
|
|
@@ -191,7 +190,7 @@ function addAcceptedWaitLockOption(command) {
|
|
|
191
190
|
* CLI wiring to add the accept-and-ignore variant only where the honoring
|
|
192
191
|
* one is absent.
|
|
193
192
|
*/
|
|
194
|
-
|
|
193
|
+
function hasWaitLockOption(command) {
|
|
195
194
|
return command.options.some((option) => option.long === '--wait-lock');
|
|
196
195
|
}
|
|
197
196
|
/**
|
|
@@ -3,21 +3,12 @@ import { readFileSync } from 'node:fs';
|
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { getNodeErrorCode, toError } from './errors.js';
|
|
6
|
+
import { parseObject } from './parse.js';
|
|
6
7
|
import { isObject } from './validation.js';
|
|
7
|
-
function validatePackageMetadata(data, filePath) {
|
|
8
|
-
if (typeof data !== 'object' || data === null) {
|
|
9
|
-
throw new Error(`Invalid package metadata in ${filePath}: expected an object`);
|
|
10
|
-
}
|
|
11
|
-
const name = 'name' in data ? data.name : undefined;
|
|
12
|
-
const version = 'version' in data ? data.version : undefined;
|
|
13
|
-
if (typeof name !== 'string' || typeof version !== 'string') {
|
|
14
|
-
throw new Error(`Invalid package metadata in ${filePath}: expected string "name" and "version" fields`);
|
|
15
|
-
}
|
|
16
|
-
return { name, version, bin: 'bin' in data ? data.bin : undefined };
|
|
17
|
-
}
|
|
18
8
|
function readPackageMetadata(filePath) {
|
|
19
9
|
const raw = readFileSync(filePath, 'utf-8');
|
|
20
|
-
|
|
10
|
+
const parsed = parseObject(JSON.parse(raw), 'package.json');
|
|
11
|
+
return { name: parsed.string('name'), version: parsed.string('version'), bin: parsed.raw('bin') };
|
|
21
12
|
}
|
|
22
13
|
let cachedPackageRoot;
|
|
23
14
|
/**
|
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
* Supported operating system platforms.
|
|
3
3
|
*/
|
|
4
4
|
export type Platform = 'darwin' | 'linux' | 'win32';
|
|
5
|
-
/**
|
|
6
|
-
* Supported CPU architectures.
|
|
7
|
-
*/
|
|
8
|
-
export type Arch = 'x64' | 'arm64';
|
|
9
5
|
/**
|
|
10
6
|
* Gets the current operating system platform.
|
|
11
7
|
* @throws Error if running on an unsupported platform
|
|
@@ -19,7 +19,7 @@ import { type ChildProcess } from 'node:child_process';
|
|
|
19
19
|
*/
|
|
20
20
|
export declare function killProcessTree(child: ChildProcess, signal: NodeJS.Signals, usesProcessGroup: boolean): void;
|
|
21
21
|
/** One process still alive in a swept group. */
|
|
22
|
-
|
|
22
|
+
interface ProcessGroupSurvivor {
|
|
23
23
|
/** PID, or -1 when pgrep was unavailable and only a liveness probe ran. */
|
|
24
24
|
pid: number;
|
|
25
25
|
/** Command line (pgrep -lf output), best-effort. */
|
|
@@ -36,3 +36,4 @@ export interface ProcessGroupSurvivor {
|
|
|
36
36
|
export declare function sweepProcessGroup(pgid: number, graceMs?: number): Promise<{
|
|
37
37
|
survivors: ProcessGroupSurvivor[];
|
|
38
38
|
}>;
|
|
39
|
+
export {};
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { spawn } from 'node:child_process';
|
|
9
9
|
import { getNodeErrorCode } from './errors.js';
|
|
10
10
|
import { verbose, warn } from './logger.js';
|
|
11
|
+
import { sleep } from './sleep.js';
|
|
11
12
|
/**
|
|
12
13
|
* Sends `signal` to the child's whole tree: the process GROUP on POSIX
|
|
13
14
|
* (negative-PID kill — reaches mach → python → firefox → content-process
|
|
@@ -61,18 +62,6 @@ export function killProcessTree(child, signal, usesProcessGroup) {
|
|
|
61
62
|
}
|
|
62
63
|
const SWEEP_GRACE_MS = 2000;
|
|
63
64
|
const MULTIPROCESSING_WORKER_PATTERN = /multiprocessing\.(?:spawn|forkserver)|resource_tracker/;
|
|
64
|
-
function sweepDelay(ms) {
|
|
65
|
-
// Deliberately ref'd (no unref()): this promise is AWAITED between the
|
|
66
|
-
// group SIGTERM and the post-grace re-list/SIGKILL escalation, from a
|
|
67
|
-
// child 'close' handler after the signal forwarder is disposed — with an
|
|
68
|
-
// unref'd timer nothing kept the event loop alive, so Node could exit
|
|
69
|
-
// mid-grace and skip the escalation entirely. Healthy runs never reach
|
|
70
|
-
// this function (sweepProcessGroup early-returns on zero survivors), so
|
|
71
|
-
// the ref never holds a clean exit open.
|
|
72
|
-
return new Promise((resolve) => {
|
|
73
|
-
setTimeout(resolve, ms);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
65
|
/**
|
|
77
66
|
* Minimal spawn-based pgrep runner. exitCode -1 means pgrep itself was
|
|
78
67
|
* unavailable or errored (distinct from exit 1 = "no matches").
|
|
@@ -130,7 +119,7 @@ function describeSurvivors(list) {
|
|
|
130
119
|
const tag = MULTIPROCESSING_WORKER_PATTERN.test(s.command)
|
|
131
120
|
? ' [multiprocessing worker — the known busy-spin orphan shape]'
|
|
132
121
|
: '';
|
|
133
|
-
return `PID ${
|
|
122
|
+
return `PID ${s.pid}: ${s.command}${tag}`;
|
|
134
123
|
})
|
|
135
124
|
.join('; ');
|
|
136
125
|
}
|
|
@@ -148,7 +137,7 @@ export async function sweepProcessGroup(pgid, graceMs = SWEEP_GRACE_MS) {
|
|
|
148
137
|
const survivors = await listGroupSurvivors(pgid);
|
|
149
138
|
if (survivors.length === 0)
|
|
150
139
|
return { survivors };
|
|
151
|
-
warn(`Harness process group ${
|
|
140
|
+
warn(`Harness process group ${pgid} left ${survivors.length} surviving ` +
|
|
152
141
|
`process(es) after exit — reaping the group. ${describeSurvivors(survivors)}`);
|
|
153
142
|
try {
|
|
154
143
|
process.kill(-pgid, 'SIGTERM');
|
|
@@ -158,7 +147,13 @@ export async function sweepProcessGroup(pgid, graceMs = SWEEP_GRACE_MS) {
|
|
|
158
147
|
// escalate against, so report the survivors collected so far.
|
|
159
148
|
return { survivors };
|
|
160
149
|
}
|
|
161
|
-
|
|
150
|
+
// Deliberately ref'd (sleep's default): this wait sits between the group
|
|
151
|
+
// SIGTERM and the post-grace re-list/SIGKILL escalation, awaited from a
|
|
152
|
+
// child 'close' handler after the signal forwarder is disposed. With an
|
|
153
|
+
// unref'd timer nothing keeps the event loop alive, so Node could exit
|
|
154
|
+
// mid-grace and skip the escalation entirely. Healthy runs never reach
|
|
155
|
+
// here (sweepProcessGroup early-returns on zero survivors).
|
|
156
|
+
await sleep(graceMs);
|
|
162
157
|
let remaining = await listGroupSurvivors(pgid);
|
|
163
158
|
if (remaining.length > 0) {
|
|
164
159
|
try {
|
|
@@ -169,18 +164,24 @@ export async function sweepProcessGroup(pgid, graceMs = SWEEP_GRACE_MS) {
|
|
|
169
164
|
// nothing to signal.
|
|
170
165
|
return { survivors };
|
|
171
166
|
}
|
|
172
|
-
|
|
167
|
+
// Deliberately ref'd (sleep's default): this wait sits between the group
|
|
168
|
+
// SIGTERM and the post-grace re-list/SIGKILL escalation, awaited from a
|
|
169
|
+
// child 'close' handler after the signal forwarder is disposed. With an
|
|
170
|
+
// unref'd timer nothing keeps the event loop alive, so Node could exit
|
|
171
|
+
// mid-grace and skip the escalation entirely. Healthy runs never reach
|
|
172
|
+
// here (sweepProcessGroup early-returns on zero survivors).
|
|
173
|
+
await sleep(Math.min(200, graceMs));
|
|
173
174
|
remaining = await listGroupSurvivors(pgid);
|
|
174
175
|
if (remaining.length > 0) {
|
|
175
|
-
warn(`Process group ${
|
|
176
|
+
warn(`Process group ${pgid} still has survivors after SIGKILL: ${describeSurvivors(remaining)}. ` +
|
|
176
177
|
'Inspect manually (ps -axo pid,ppid,time,command) and kill by PID.');
|
|
177
178
|
}
|
|
178
179
|
else {
|
|
179
|
-
verbose(`Process group ${
|
|
180
|
+
verbose(`Process group ${pgid} reaped after SIGKILL escalation.`);
|
|
180
181
|
}
|
|
181
182
|
}
|
|
182
183
|
else {
|
|
183
|
-
verbose(`Process group ${
|
|
184
|
+
verbose(`Process group ${pgid} reaped cleanly with SIGTERM.`);
|
|
184
185
|
}
|
|
185
186
|
return { survivors };
|
|
186
187
|
}
|
|
@@ -21,7 +21,12 @@ export interface ExecResult {
|
|
|
21
21
|
stderrTruncated?: boolean;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
|
-
* Options for
|
|
24
|
+
* Options for plain `exec()` — the pipe-capturing, non-grouped, non-mirrored
|
|
25
|
+
* path. The other wrappers extend this with the fields they actually read:
|
|
26
|
+
* `processGroup` lives in {@link ProcessGroupOptions}, `mirror` in
|
|
27
|
+
* {@link MirrorOptions}. Neither belongs here because `exec()` reads
|
|
28
|
+
* neither — a field the type accepts but the function ignores is a trap
|
|
29
|
+
* (the caller believes it got a process group, and never did).
|
|
25
30
|
*/
|
|
26
31
|
export interface ExecOptions {
|
|
27
32
|
/** Working directory for the command */
|
|
@@ -40,18 +45,32 @@ export interface ExecOptions {
|
|
|
40
45
|
* that must not have any.
|
|
41
46
|
*/
|
|
42
47
|
envUnset?: readonly string[];
|
|
48
|
+
/** Timeout in milliseconds */
|
|
49
|
+
timeout?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Output mirroring for the wrappers that capture through a collector
|
|
53
|
+
* ({@link execInheritCapture}, {@link execSmokeRun}).
|
|
54
|
+
*/
|
|
55
|
+
export interface MirrorOptions {
|
|
43
56
|
/**
|
|
44
57
|
* Streams to mirror the child's output into, replacing the default
|
|
45
58
|
* `process.stdout` / `process.stderr` on the stdio-inheriting capture
|
|
59
|
+
* path, or an operator-supplied `--capture-console` file on the smoke
|
|
46
60
|
* path. Lets a caller tee the live output somewhere else (a run log)
|
|
47
|
-
* without a second per-chunk hook.
|
|
61
|
+
* without a second per-chunk hook. Writes happen inline with capture and
|
|
62
|
+
* the stream is NOT closed here — the caller owns its lifecycle.
|
|
48
63
|
*/
|
|
49
64
|
mirror?: {
|
|
50
65
|
stdout?: NodeJS.WritableStream;
|
|
51
66
|
stderr?: NodeJS.WritableStream;
|
|
52
67
|
};
|
|
53
|
-
|
|
54
|
-
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Process-group reaping for the long-lived wrappers ({@link execStream},
|
|
71
|
+
* {@link execInherit}, {@link execInheritCapture}).
|
|
72
|
+
*/
|
|
73
|
+
export interface ProcessGroupOptions {
|
|
55
74
|
/**
|
|
56
75
|
* POSIX: spawn the child as a process-group leader and route every kill
|
|
57
76
|
* (parent-signal forwarding, abort, escalation) to the whole GROUP, then
|
|
@@ -78,11 +97,11 @@ export declare function exec(command: string, args: string[], options?: ExecOpti
|
|
|
78
97
|
/**
|
|
79
98
|
* Callback for streaming output.
|
|
80
99
|
*/
|
|
81
|
-
|
|
100
|
+
type StreamCallback = (data: string) => void;
|
|
82
101
|
/**
|
|
83
102
|
* Options for streaming command execution.
|
|
84
103
|
*/
|
|
85
|
-
|
|
104
|
+
interface StreamOptions extends ExecOptions, ProcessGroupOptions {
|
|
86
105
|
/** Callback for stdout data */
|
|
87
106
|
onStdout?: StreamCallback;
|
|
88
107
|
/** Callback for stderr data */
|
|
@@ -124,6 +143,14 @@ export declare function trackChildClosure(): {
|
|
|
124
143
|
* Resolves immediately when no children are active.
|
|
125
144
|
*/
|
|
126
145
|
export declare function waitForActiveChildShutdown(timeoutMs: number): Promise<void>;
|
|
146
|
+
/** Options for {@link execInherit}. */
|
|
147
|
+
export interface InheritOptions extends ExecOptions, ProcessGroupOptions {
|
|
148
|
+
/** Grace period between the forwarded SIGTERM and the SIGKILL escalation (default 1500 ms). */
|
|
149
|
+
shutdownGraceMs?: number;
|
|
150
|
+
}
|
|
151
|
+
/** Options for {@link execInheritCapture}: the inherit path plus output mirroring. */
|
|
152
|
+
export interface InheritCaptureOptions extends InheritOptions, MirrorOptions {
|
|
153
|
+
}
|
|
127
154
|
/**
|
|
128
155
|
* Executes a command and inherits stdio (shows output directly).
|
|
129
156
|
*
|
|
@@ -140,9 +167,7 @@ export declare function waitForActiveChildShutdown(timeoutMs: number): Promise<v
|
|
|
140
167
|
* @param options - Execution options
|
|
141
168
|
* @returns Exit code of the process
|
|
142
169
|
*/
|
|
143
|
-
export declare function execInherit(command: string, args: string[], options?:
|
|
144
|
-
shutdownGraceMs?: number;
|
|
145
|
-
}): Promise<number>;
|
|
170
|
+
export declare function execInherit(command: string, args: string[], options?: InheritOptions): Promise<number>;
|
|
146
171
|
/**
|
|
147
172
|
* Wires parent-process SIGINT/SIGTERM to a child: first signal → child.kill
|
|
148
173
|
* (SIGTERM) + grace timer; second matching signal → immediate SIGKILL; grace
|
|
@@ -162,9 +187,7 @@ export declare function installGracefulShutdownForwarder(child: ReturnType<typeo
|
|
|
162
187
|
* @param options - Execution options
|
|
163
188
|
* @returns Execution result with stdout, stderr, and exit code
|
|
164
189
|
*/
|
|
165
|
-
export declare function execInheritCapture(command: string, args: string[], options?:
|
|
166
|
-
shutdownGraceMs?: number;
|
|
167
|
-
}): Promise<ExecResult>;
|
|
190
|
+
export declare function execInheritCapture(command: string, args: string[], options?: InheritCaptureOptions): Promise<ExecResult>;
|
|
168
191
|
/** Per-line callback for smoke-run stream dispatch. */
|
|
169
192
|
export type SmokeLineCallback = (line: string) => void;
|
|
170
193
|
/**
|
|
@@ -175,11 +198,11 @@ export type SmokeLineCallback = (line: string) => void;
|
|
|
175
198
|
* group. Inheriting `timeout` is a leaky trap — accepted by the type but
|
|
176
199
|
* silently ignored, so a caller setting it gets no deadline at all.
|
|
177
200
|
*
|
|
178
|
-
*
|
|
179
|
-
* detached on POSIX (`usesProcessGroup` is derived from
|
|
180
|
-
* alone), so the field would be accepted and never read.
|
|
201
|
+
* {@link ProcessGroupOptions} is not mixed in for the same reason: a smoke
|
|
202
|
+
* run is ALWAYS detached on POSIX (`usesProcessGroup` is derived from
|
|
203
|
+
* `process.platform` alone), so the field would be accepted and never read.
|
|
181
204
|
*/
|
|
182
|
-
|
|
205
|
+
interface SmokeRunOptions extends Omit<ExecOptions, 'timeout'>, MirrorOptions {
|
|
183
206
|
/**
|
|
184
207
|
* Hard deadline in milliseconds. When it elapses the child process
|
|
185
208
|
* group is sent SIGTERM and, after `killGraceMs`, SIGKILL. The returned
|
|
@@ -199,16 +222,6 @@ export interface SmokeRunOptions extends Omit<ExecOptions, 'processGroup' | 'tim
|
|
|
199
222
|
onStdoutLine?: SmokeLineCallback;
|
|
200
223
|
/** Invoked once per complete line of stderr. Final partial line is flushed on close. */
|
|
201
224
|
onStderrLine?: SmokeLineCallback;
|
|
202
|
-
/**
|
|
203
|
-
* Optional writable stream to mirror captured output to (e.g. an
|
|
204
|
-
* operator-supplied `--capture-console` file). Writes happen inline
|
|
205
|
-
* with line dispatch and the stream is NOT closed here — the caller
|
|
206
|
-
* owns its lifecycle.
|
|
207
|
-
*/
|
|
208
|
-
mirror?: {
|
|
209
|
-
stdout?: NodeJS.WritableStream;
|
|
210
|
-
stderr?: NodeJS.WritableStream;
|
|
211
|
-
};
|
|
212
225
|
}
|
|
213
226
|
/** Result of {@link execSmokeRun}. */
|
|
214
227
|
export interface SmokeRunResult extends ExecResult {
|
|
@@ -255,3 +268,4 @@ export declare function findExecutable(name: string): Promise<string | undefined
|
|
|
255
268
|
* @returns True if the executable exists
|
|
256
269
|
*/
|
|
257
270
|
export declare function executableExists(name: string): Promise<boolean>;
|
|
271
|
+
export {};
|