@hominis/fireforge 0.49.2 → 0.51.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 +87 -1
- package/README.md +1 -1
- package/dist/bin/fireforge.js +6 -0
- package/dist/build-info.json +4 -4
- package/dist/src/commands/build-prelock.d.ts +20 -0
- package/dist/src/commands/build-prelock.js +50 -0
- package/dist/src/commands/build.d.ts +3 -1
- package/dist/src/commands/build.js +13 -6
- package/dist/src/commands/check-report.d.ts +41 -0
- package/dist/src/commands/check-report.js +91 -0
- package/dist/src/commands/check-run.d.ts +33 -0
- package/dist/src/commands/check-run.js +112 -0
- package/dist/src/commands/check-steps.d.ts +75 -0
- package/dist/src/commands/check-steps.js +200 -0
- package/dist/src/commands/check.d.ts +32 -0
- package/dist/src/commands/check.js +160 -0
- package/dist/src/commands/config.js +5 -6
- package/dist/src/commands/declarations-report.d.ts +43 -0
- package/dist/src/commands/declarations-report.js +76 -0
- package/dist/src/commands/doctor-engine-eslint.js +6 -1
- package/dist/src/commands/doctor-source-pin.js +4 -1
- package/dist/src/commands/export-adopt-check.d.ts +38 -0
- package/dist/src/commands/export-adopt-check.js +98 -0
- package/dist/src/commands/export-flow.js +29 -14
- package/dist/src/commands/export-placement-gate.d.ts +6 -2
- package/dist/src/commands/export-placement-gate.js +8 -0
- package/dist/src/commands/export-shared.d.ts +2 -1
- package/dist/src/commands/export-staged-registration.d.ts +46 -0
- package/dist/src/commands/export-staged-registration.js +91 -0
- package/dist/src/commands/forward-import-remedy.d.ts +32 -0
- package/dist/src/commands/forward-import-remedy.js +63 -0
- package/dist/src/commands/furnace/apply.js +3 -3
- package/dist/src/commands/furnace/chrome-doc-remove.d.ts +2 -1
- package/dist/src/commands/furnace/chrome-doc-remove.js +2 -2
- package/dist/src/commands/furnace/chrome-doc.d.ts +2 -1
- package/dist/src/commands/furnace/chrome-doc.js +2 -2
- package/dist/src/commands/furnace/create.js +2 -2
- package/dist/src/commands/furnace/deploy-named.d.ts +48 -0
- package/dist/src/commands/furnace/deploy-named.js +107 -0
- package/dist/src/commands/furnace/deploy.d.ts +3 -2
- package/dist/src/commands/furnace/deploy.js +50 -86
- package/dist/src/commands/furnace/diff.js +26 -3
- package/dist/src/commands/furnace/index.js +66 -41
- package/dist/src/commands/furnace/init.js +13 -6
- package/dist/src/commands/furnace/override.js +4 -2
- package/dist/src/commands/furnace/preview.js +4 -3
- package/dist/src/commands/furnace/refresh.js +2 -2
- package/dist/src/commands/furnace/remove.js +4 -3
- package/dist/src/commands/furnace/rename-dry-run.d.ts +29 -0
- package/dist/src/commands/furnace/rename-dry-run.js +127 -0
- package/dist/src/commands/furnace/rename-helpers.d.ts +7 -0
- package/dist/src/commands/furnace/rename-helpers.js +15 -1
- package/dist/src/commands/furnace/rename-registrations.d.ts +41 -0
- package/dist/src/commands/furnace/rename-registrations.js +98 -0
- package/dist/src/commands/furnace/rename.d.ts +2 -1
- package/dist/src/commands/furnace/rename.js +28 -66
- package/dist/src/commands/furnace/scan.d.ts +9 -4
- package/dist/src/commands/furnace/scan.js +11 -9
- package/dist/src/commands/furnace/sync.js +3 -2
- package/dist/src/commands/furnace/validate-report.d.ts +45 -0
- package/dist/src/commands/furnace/validate-report.js +91 -0
- package/dist/src/commands/furnace/validate.d.ts +1 -1
- package/dist/src/commands/furnace/validate.js +151 -113
- package/dist/src/commands/furnace/validation-output.js +14 -3
- package/dist/src/commands/lint-per-patch.js +36 -61
- package/dist/src/commands/lint-per-run-checkjs.js +2 -2
- package/dist/src/commands/lint-report.d.ts +8 -4
- package/dist/src/commands/lint-report.js +20 -5
- package/dist/src/commands/lint.js +15 -34
- package/dist/src/commands/manifest.js +4 -0
- package/dist/src/commands/park.d.ts +22 -0
- package/dist/src/commands/park.js +232 -0
- package/dist/src/commands/patch/delete-gap-notice.js +3 -1
- package/dist/src/commands/patch/delete.d.ts +1 -1
- package/dist/src/commands/patch/delete.js +24 -104
- package/dist/src/commands/patch/index.d.ts +3 -3
- package/dist/src/commands/patch/index.js +10 -4
- package/dist/src/commands/patch/lint-ignore-from.d.ts +44 -0
- package/dist/src/commands/patch/lint-ignore-from.js +142 -0
- package/dist/src/commands/patch/lint-ignore.d.ts +5 -1
- package/dist/src/commands/patch/lint-ignore.js +78 -31
- package/dist/src/commands/patch/move-files-create.js +34 -18
- package/dist/src/commands/patch/move-files-into.js +15 -7
- package/dist/src/commands/patch/move-files.js +6 -2
- package/dist/src/commands/patch/removal-created-files.d.ts +48 -0
- package/dist/src/commands/patch/removal-created-files.js +83 -0
- package/dist/src/commands/patch/removal-dependents.d.ts +63 -0
- package/dist/src/commands/patch/removal-dependents.js +133 -0
- package/dist/src/commands/patch/rename.js +20 -1
- package/dist/src/commands/patch/reserve.d.ts +33 -0
- package/dist/src/commands/patch/reserve.js +152 -0
- package/dist/src/commands/patch/retire.d.ts +34 -0
- package/dist/src/commands/patch/retire.js +133 -0
- package/dist/src/commands/patch/split-plan.d.ts +17 -8
- package/dist/src/commands/patch/split-plan.js +60 -28
- package/dist/src/commands/patch/split-staged.d.ts +108 -0
- package/dist/src/commands/patch/split-staged.js +202 -0
- package/dist/src/commands/patch/split.d.ts +5 -0
- package/dist/src/commands/patch/split.js +62 -17
- package/dist/src/commands/patch/stage.d.ts +34 -0
- package/dist/src/commands/patch/stage.js +153 -0
- package/dist/src/commands/patch/staged-dependency-batch.d.ts +48 -0
- package/dist/src/commands/patch/staged-dependency-batch.js +176 -0
- package/dist/src/commands/patch/staged-dependency-entries.d.ts +36 -0
- package/dist/src/commands/patch/staged-dependency-entries.js +52 -0
- package/dist/src/commands/patch/staged-dependency-from.d.ts +14 -0
- package/dist/src/commands/patch/staged-dependency-from.js +108 -0
- package/dist/src/commands/patch/staged-dependency-remove.d.ts +31 -0
- package/dist/src/commands/patch/staged-dependency-remove.js +80 -0
- package/dist/src/commands/patch/staged-dependency.js +54 -139
- package/dist/src/commands/re-export-adjacent-registrations.d.ts +20 -0
- package/dist/src/commands/re-export-adjacent-registrations.js +75 -0
- package/dist/src/commands/re-export-adjacent.d.ts +50 -2
- package/dist/src/commands/re-export-adjacent.js +160 -40
- package/dist/src/commands/re-export-bulk-scan.d.ts +2 -1
- package/dist/src/commands/re-export-bulk-scan.js +22 -7
- package/dist/src/commands/re-export-drift.d.ts +36 -8
- package/dist/src/commands/re-export-drift.js +73 -49
- package/dist/src/commands/re-export-files.js +11 -8
- package/dist/src/commands/re-export-hunks.d.ts +35 -0
- package/dist/src/commands/re-export-hunks.js +220 -0
- package/dist/src/commands/re-export-lint.d.ts +2 -1
- package/dist/src/commands/re-export-lint.js +23 -10
- package/dist/src/commands/re-export-options.js +74 -6
- package/dist/src/commands/re-export-preflight.d.ts +23 -0
- package/dist/src/commands/re-export-preflight.js +160 -0
- package/dist/src/commands/re-export-purity-scope.d.ts +18 -0
- package/dist/src/commands/re-export-purity-scope.js +131 -0
- package/dist/src/commands/re-export-register.js +56 -17
- package/dist/src/commands/re-export-removed.d.ts +13 -2
- package/dist/src/commands/re-export-removed.js +57 -12
- package/dist/src/commands/re-export-scan-owner.d.ts +44 -0
- package/dist/src/commands/re-export-scan-owner.js +116 -0
- package/dist/src/commands/re-export-scan.d.ts +19 -9
- package/dist/src/commands/re-export-scan.js +60 -24
- package/dist/src/commands/re-export-single.js +122 -46
- package/dist/src/commands/re-export-stale-registrations.d.ts +18 -0
- package/dist/src/commands/re-export-stale-registrations.js +62 -0
- package/dist/src/commands/re-export-summary.d.ts +28 -0
- package/dist/src/commands/re-export-summary.js +36 -0
- package/dist/src/commands/re-export.js +71 -57
- package/dist/src/commands/rebase/index.js +17 -17
- package/dist/src/commands/run.js +16 -2
- package/dist/src/commands/status-check.d.ts +55 -16
- package/dist/src/commands/status-check.js +92 -37
- package/dist/src/commands/status-json.d.ts +22 -9
- package/dist/src/commands/status-json.js +47 -32
- package/dist/src/commands/status-output.js +3 -1
- package/dist/src/commands/status-scope.d.ts +37 -0
- package/dist/src/commands/status-scope.js +54 -0
- package/dist/src/commands/status.js +66 -23
- package/dist/src/commands/test-browser-preflight.js +19 -3
- package/dist/src/commands/test-build-furnace.d.ts +22 -0
- package/dist/src/commands/test-build-furnace.js +54 -0
- package/dist/src/commands/test-build-phase.js +64 -41
- package/dist/src/commands/test-checkjs.js +10 -2
- package/dist/src/commands/test-diagnose.js +7 -0
- package/dist/src/commands/test-dispatch.d.ts +39 -0
- package/dist/src/commands/test-dispatch.js +211 -0
- package/dist/src/commands/test-furnace-reach.d.ts +37 -0
- package/dist/src/commands/test-furnace-reach.js +132 -0
- package/dist/src/commands/test-modes.d.ts +16 -1
- package/dist/src/commands/test-modes.js +24 -1
- package/dist/src/commands/test-multi-verdict.d.ts +61 -0
- package/dist/src/commands/test-multi-verdict.js +111 -0
- package/dist/src/commands/test-orchestrate.d.ts +52 -0
- package/dist/src/commands/test-orchestrate.js +240 -0
- package/dist/src/commands/test-perf-scope.d.ts +50 -0
- package/dist/src/commands/test-perf-scope.js +138 -0
- package/dist/src/commands/test-prelock.d.ts +51 -0
- package/dist/src/commands/test-prelock.js +273 -0
- package/dist/src/commands/test-register.js +69 -10
- package/dist/src/commands/test-results.d.ts +62 -0
- package/dist/src/commands/test-results.js +62 -0
- package/dist/src/commands/test-run.d.ts +13 -55
- package/dist/src/commands/test-run.js +74 -99
- package/dist/src/commands/test-shards.d.ts +110 -0
- package/dist/src/commands/test-shards.js +255 -0
- package/dist/src/commands/test-stale-gate.d.ts +5 -1
- package/dist/src/commands/test-stale-gate.js +60 -28
- package/dist/src/commands/test-verdict.d.ts +11 -1
- package/dist/src/commands/test-verdict.js +28 -1
- package/dist/src/commands/test.d.ts +6 -1
- package/dist/src/commands/test.js +120 -124
- package/dist/src/commands/token-lint.d.ts +14 -0
- package/dist/src/commands/token-lint.js +151 -0
- package/dist/src/commands/token.js +10 -0
- package/dist/src/commands/verify-scope.d.ts +28 -0
- package/dist/src/commands/verify-scope.js +67 -0
- package/dist/src/commands/verify.d.ts +10 -2
- package/dist/src/commands/verify.js +67 -36
- package/dist/src/core/build-baseline-types.d.ts +46 -0
- package/dist/src/core/build-baseline-validate.js +19 -0
- package/dist/src/core/build-baseline.d.ts +5 -1
- package/dist/src/core/build-baseline.js +3 -1
- package/dist/src/core/build-overwrite-guard.d.ts +50 -0
- package/dist/src/core/build-overwrite-guard.js +84 -4
- package/dist/src/core/build-prepare.d.ts +13 -0
- package/dist/src/core/build-prepare.js +42 -10
- package/dist/src/core/build-run-record.d.ts +74 -0
- package/dist/src/core/build-run-record.js +136 -0
- package/dist/src/core/checkjs-support-heads.d.ts +41 -0
- package/dist/src/core/checkjs-support-heads.js +104 -0
- package/dist/src/core/config-paths.d.ts +2 -2
- package/dist/src/core/config-paths.js +10 -0
- package/dist/src/core/config-validate-check.d.ts +8 -0
- package/dist/src/core/config-validate-check.js +219 -0
- package/dist/src/core/config-validate-file-size.d.ts +9 -6
- package/dist/src/core/config-validate-file-size.js +91 -2
- package/dist/src/core/config-validate-history.d.ts +11 -0
- package/dist/src/core/config-validate-history.js +38 -0
- package/dist/src/core/config-validate-patch-policy.js +100 -0
- package/dist/src/core/config-validate-test-toolchains.js +21 -0
- package/dist/src/core/config-validate-token-scales.d.ts +9 -0
- package/dist/src/core/config-validate-token-scales.js +92 -0
- package/dist/src/core/config-validate.js +20 -5
- package/dist/src/core/config.d.ts +5 -0
- package/dist/src/core/config.js +16 -0
- package/dist/src/core/coverage-dispatch.d.ts +24 -0
- package/dist/src/core/coverage-dispatch.js +44 -0
- package/dist/src/core/coverage-extend.d.ts +70 -45
- package/dist/src/core/coverage-extend.js +199 -144
- package/dist/src/core/coverage-records.d.ts +108 -0
- package/dist/src/core/coverage-records.js +384 -0
- package/dist/src/core/destructive.d.ts +7 -4
- package/dist/src/core/destructive.js +10 -10
- package/dist/src/core/engine-session-lock.d.ts +16 -1
- package/dist/src/core/engine-session-lock.js +38 -10
- package/dist/src/core/export-moved-code-shape.d.ts +49 -11
- package/dist/src/core/export-moved-code-shape.js +135 -44
- package/dist/src/core/file-lock-queue.d.ts +67 -0
- package/dist/src/core/file-lock-queue.js +221 -0
- package/dist/src/core/file-lock-shared.d.ts +57 -0
- package/dist/src/core/file-lock-shared.js +117 -0
- package/dist/src/core/file-lock.d.ts +13 -25
- package/dist/src/core/file-lock.js +163 -140
- package/dist/src/core/furnace-apply-output.d.ts +10 -0
- package/dist/src/core/furnace-apply-output.js +31 -1
- package/dist/src/core/furnace-apply.js +22 -12
- package/dist/src/core/furnace-composed-source.d.ts +76 -0
- package/dist/src/core/furnace-composed-source.js +167 -0
- package/dist/src/core/furnace-config-validate-exceptions.d.ts +16 -0
- package/dist/src/core/furnace-config-validate-exceptions.js +102 -0
- package/dist/src/core/furnace-config-validate.js +14 -0
- package/dist/src/core/furnace-css-fragments.d.ts +10 -0
- package/dist/src/core/furnace-css-fragments.js +26 -0
- package/dist/src/core/furnace-operation.d.ts +3 -3
- package/dist/src/core/furnace-registration-jar-inplace.d.ts +12 -0
- package/dist/src/core/furnace-registration-jar-inplace.js +80 -0
- package/dist/src/core/furnace-registration-remove.d.ts +22 -1
- package/dist/src/core/furnace-registration-remove.js +53 -17
- package/dist/src/core/furnace-registration-rename.d.ts +26 -0
- package/dist/src/core/furnace-registration-rename.js +77 -0
- package/dist/src/core/furnace-registration.d.ts +14 -4
- package/dist/src/core/furnace-registration.js +44 -10
- package/dist/src/core/furnace-staleness.d.ts +7 -0
- package/dist/src/core/furnace-staleness.js +34 -24
- package/dist/src/core/furnace-validate-accessibility.d.ts +8 -4
- package/dist/src/core/furnace-validate-accessibility.js +71 -28
- package/dist/src/core/furnace-validate-exceptions.d.ts +48 -0
- package/dist/src/core/furnace-validate-exceptions.js +80 -0
- package/dist/src/core/furnace-validate-icon-button.d.ts +7 -0
- package/dist/src/core/furnace-validate-icon-button.js +78 -0
- package/dist/src/core/furnace-validate.js +1 -1
- package/dist/src/core/harness-port-fallback.d.ts +60 -0
- package/dist/src/core/harness-port-fallback.js +96 -0
- package/dist/src/core/history-log-file.d.ts +61 -0
- package/dist/src/core/history-log-file.js +164 -0
- package/dist/src/core/history-log.d.ts +2 -1
- package/dist/src/core/history-log.js +2 -1
- package/dist/src/core/json-preserving-edit.d.ts +22 -0
- package/dist/src/core/json-preserving-edit.js +199 -0
- package/dist/src/core/line-prefixer.d.ts +18 -0
- package/dist/src/core/line-prefixer.js +34 -0
- package/dist/src/core/mach.d.ts +7 -0
- package/dist/src/core/mach.js +32 -10
- package/dist/src/core/module-resolution-preflight.d.ts +19 -3
- package/dist/src/core/module-resolution-preflight.js +24 -6
- package/dist/src/core/negative-control-compiled.d.ts +27 -0
- package/dist/src/core/negative-control-compiled.js +73 -0
- package/dist/src/core/negative-control-diff.d.ts +51 -0
- package/dist/src/core/negative-control-diff.js +179 -0
- package/dist/src/core/negative-control.d.ts +150 -0
- package/dist/src/core/negative-control.js +399 -0
- package/dist/src/core/objdir-install-manifests.d.ts +73 -0
- package/dist/src/core/objdir-install-manifests.js +226 -0
- package/dist/src/core/park-store.d.ts +63 -0
- package/dist/src/core/park-store.js +216 -0
- package/dist/src/core/patch-export-update.d.ts +6 -0
- package/dist/src/core/patch-export-update.js +13 -3
- package/dist/src/core/patch-export.d.ts +3 -2
- package/dist/src/core/patch-export.js +22 -16
- package/dist/src/core/patch-files.js +26 -8
- package/dist/src/core/patch-lint-checkjs-any-import.d.ts +39 -0
- package/dist/src/core/patch-lint-checkjs-any-import.js +63 -0
- package/dist/src/core/patch-lint-checkjs-diagnostics.d.ts +17 -0
- package/dist/src/core/patch-lint-checkjs-diagnostics.js +32 -0
- package/dist/src/core/patch-lint-checkjs.d.ts +10 -1
- package/dist/src/core/patch-lint-checkjs.js +20 -13
- package/dist/src/core/patch-lint-code-lines.d.ts +59 -0
- package/dist/src/core/patch-lint-code-lines.js +105 -0
- package/dist/src/core/patch-lint-cross.d.ts +3 -1
- package/dist/src/core/patch-lint-cross.js +17 -4
- package/dist/src/core/patch-lint-css.d.ts +8 -2
- package/dist/src/core/patch-lint-css.js +24 -14
- package/dist/src/core/patch-lint-file-size.d.ts +12 -5
- package/dist/src/core/patch-lint-file-size.js +22 -11
- package/dist/src/core/patch-lint-forward-registration-extended.d.ts +23 -0
- package/dist/src/core/patch-lint-forward-registration-extended.js +36 -11
- package/dist/src/core/patch-lint-forward-registration.js +10 -0
- package/dist/src/core/patch-lint-ignore.d.ts +196 -0
- package/dist/src/core/patch-lint-ignore.js +429 -0
- package/dist/src/core/patch-lint-ownership.d.ts +10 -0
- package/dist/src/core/patch-lint-ownership.js +26 -0
- package/dist/src/core/patch-lint-size-thresholds.d.ts +52 -0
- package/dist/src/core/patch-lint-size-thresholds.js +110 -0
- package/dist/src/core/patch-lint-size.d.ts +117 -0
- package/dist/src/core/patch-lint-size.js +331 -0
- package/dist/src/core/patch-lint-staged-registration.d.ts +18 -1
- package/dist/src/core/patch-lint-staged-registration.js +20 -0
- package/dist/src/core/patch-lint-token-scale.d.ts +57 -0
- package/dist/src/core/patch-lint-token-scale.js +286 -0
- package/dist/src/core/patch-lint.d.ts +11 -83
- package/dist/src/core/patch-lint.js +66 -288
- package/dist/src/core/patch-lock.js +7 -6
- package/dist/src/core/patch-manifest-consistency.js +7 -6
- package/dist/src/core/patch-manifest-io.d.ts +6 -3
- package/dist/src/core/patch-manifest-io.js +27 -9
- package/dist/src/core/patch-manifest-key-order.d.ts +24 -0
- package/dist/src/core/patch-manifest-key-order.js +61 -0
- package/dist/src/core/patch-manifest-stage.d.ts +46 -0
- package/dist/src/core/patch-manifest-stage.js +96 -0
- package/dist/src/core/patch-manifest-validate.js +61 -3
- package/dist/src/core/patch-order-legal.d.ts +26 -0
- package/dist/src/core/patch-order-legal.js +88 -0
- package/dist/src/core/patch-policy-content.d.ts +40 -0
- package/dist/src/core/patch-policy-content.js +216 -0
- package/dist/src/core/patch-policy.d.ts +22 -5
- package/dist/src/core/patch-policy.js +26 -12
- package/dist/src/core/patch-retired.d.ts +57 -0
- package/dist/src/core/patch-retired.js +92 -0
- package/dist/src/core/patch-subset.d.ts +16 -0
- package/dist/src/core/patch-subset.js +66 -0
- package/dist/src/core/preflight-wait.d.ts +20 -0
- package/dist/src/core/preflight-wait.js +38 -0
- package/dist/src/core/rebase-from-version.d.ts +46 -0
- package/dist/src/core/rebase-from-version.js +71 -0
- package/dist/src/core/run-log.d.ts +26 -0
- package/dist/src/core/run-log.js +106 -4
- package/dist/src/core/run-profile.d.ts +7 -0
- package/dist/src/core/run-profile.js +7 -1
- package/dist/src/core/smoke-patterns.d.ts +5 -0
- package/dist/src/core/smoke-patterns.js +13 -0
- package/dist/src/core/test-harness-crash.d.ts +19 -1
- package/dist/src/core/test-harness-crash.js +8 -9
- package/dist/src/core/test-harness-signature.d.ts +33 -0
- package/dist/src/core/test-harness-signature.js +23 -1
- package/dist/src/core/test-raw-log.d.ts +66 -0
- package/dist/src/core/test-raw-log.js +122 -0
- package/dist/src/core/test-run-completeness.d.ts +90 -0
- package/dist/src/core/test-run-completeness.js +184 -0
- package/dist/src/core/test-stale-check.d.ts +27 -1
- package/dist/src/core/test-stale-check.js +39 -49
- package/dist/src/core/test-stale-exempt.d.ts +40 -0
- package/dist/src/core/test-stale-exempt.js +70 -0
- package/dist/src/core/test-xpcshell-retry.d.ts +2 -0
- package/dist/src/core/test-xpcshell-retry.js +2 -1
- package/dist/src/core/token-lint.d.ts +53 -0
- package/dist/src/core/token-lint.js +131 -0
- package/dist/src/core/token-sibling-sheets.d.ts +46 -0
- package/dist/src/core/token-sibling-sheets.js +119 -0
- package/dist/src/core/tree-guard.js +5 -0
- package/dist/src/core/typecheck-shim.d.ts +6 -2
- package/dist/src/core/typecheck-shim.js +205 -4
- package/dist/src/core/typecheck.js +3 -1
- package/dist/src/index.d.ts +14 -3
- package/dist/src/index.js +6 -1
- package/dist/src/types/commands/index.d.ts +2 -2
- package/dist/src/types/commands/options.d.ts +212 -24
- package/dist/src/types/commands/patches.d.ts +118 -1
- package/dist/src/types/config.d.ts +264 -0
- package/dist/src/types/config.js +9 -0
- package/dist/src/types/furnace.d.ts +63 -1
- package/dist/src/types/furnace.js +7 -0
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/utils/options.d.ts +36 -7
- package/dist/src/utils/options.js +94 -8
- package/dist/src/utils/path-glob.d.ts +15 -0
- package/dist/src/utils/path-glob.js +47 -0
- package/dist/src/utils/regex.d.ts +15 -3
- package/dist/src/utils/regex.js +37 -16
- package/docs/configuration.md +369 -11
- package/docs/exit-codes.md +18 -1
- package/docs/furnace.md +139 -3
- package/docs/lifecycle-invariants.md +65 -30
- package/docs/machine-output.md +120 -12
- package/docs/patch-workflow.md +458 -22
- package/docs/run-logs.md +20 -1
- package/docs/testing.md +346 -21
- package/package.json +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PatchesManifest, PatchMetadata } from '../types/commands/index.js';
|
|
1
|
+
import type { PatchesManifest, PatchMetadata, ReExportOptions } from '../types/commands/index.js';
|
|
2
2
|
import type { ProjectPaths } from '../types/config.js';
|
|
3
3
|
/**
|
|
4
4
|
* Shared per-run context for the adjacency advisory: the classification
|
|
@@ -18,6 +18,23 @@ export interface AdjacentUnmanagedContext {
|
|
|
18
18
|
approvedUnmanaged: ReadonlySet<string>;
|
|
19
19
|
/** Approved paths actually met this run, so unused ones can be surfaced. */
|
|
20
20
|
approvedSeen: Set<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Engine-relative paths named by `--expect-new`: files this session
|
|
23
|
+
* created and will adopt with its next export (or `--scan-file`). They
|
|
24
|
+
* pass the belt and are reported, while every other adjacent file still
|
|
25
|
+
* refuses, so a peer's neighbour is not admitted with them.
|
|
26
|
+
*/
|
|
27
|
+
expectedNew: ReadonlySet<string>;
|
|
28
|
+
/** `--expect-new` paths actually met this run. */
|
|
29
|
+
expectedNewSeen: Set<string>;
|
|
30
|
+
/**
|
|
31
|
+
* Reviewed `--adjacent-ignore` entries: an engine-relative path, or a
|
|
32
|
+
* glob whose `*` stays within one path segment. Matches are reported in
|
|
33
|
+
* one line and never refuse.
|
|
34
|
+
*/
|
|
35
|
+
adjacentIgnore: readonly string[];
|
|
36
|
+
/** `--adjacent-ignore` entries that matched a file this run. */
|
|
37
|
+
adjacentIgnoreSeen: Set<string>;
|
|
21
38
|
/**
|
|
22
39
|
* Offenders collected across the loop. `files` stays the bare paths that
|
|
23
40
|
* downstream consumers already read. `anchored` carries the same entries
|
|
@@ -30,6 +47,16 @@ export interface AdjacentUnmanagedContext {
|
|
|
30
47
|
anchored: string[];
|
|
31
48
|
}[];
|
|
32
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Builds the run's adjacency context. The path flags are normalized once
|
|
52
|
+
* here, so the per-file comparison matches git's engine-relative output.
|
|
53
|
+
*/
|
|
54
|
+
export declare function buildAdjacentUnmanagedContext(options: ReExportOptions, binaryName: string, furnacePrefixes: ReadonlySet<string>): AdjacentUnmanagedContext;
|
|
55
|
+
/**
|
|
56
|
+
* The one definition of "adjacent", shared by the per-patch notice and the
|
|
57
|
+
* run-level refusal so the two cannot drift apart.
|
|
58
|
+
*/
|
|
59
|
+
export declare const ADJACENT_MEANS: string;
|
|
33
60
|
/** Returns the subset of `files` that no longer exist under `engineDir`. */
|
|
34
61
|
export declare function findMissingFiles(engineDir: string, files: readonly string[]): Promise<string[]>;
|
|
35
62
|
/**
|
|
@@ -44,8 +71,13 @@ export declare function findMissingFiles(engineDir: string, files: readonly stri
|
|
|
44
71
|
export interface AdjacentUnmanagedFile {
|
|
45
72
|
/** Engine-relative path of the unmanaged file. */
|
|
46
73
|
file: string;
|
|
47
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Directory holding at least one file this patch owns, or for a
|
|
76
|
+
* registration-named file, the directory of the carrier naming it.
|
|
77
|
+
*/
|
|
48
78
|
anchorDir: string;
|
|
79
|
+
/** The owned carrier whose added registration line names the file. */
|
|
80
|
+
registeredBy?: string;
|
|
49
81
|
}
|
|
50
82
|
/**
|
|
51
83
|
* Emits the scan-less advisory for one patch: missing manifest files and
|
|
@@ -61,4 +93,20 @@ export declare function reportAdjacentUnmanagedFiles(args: {
|
|
|
61
93
|
manifest: PatchesManifest;
|
|
62
94
|
currentFilesAffected: readonly string[];
|
|
63
95
|
ctx: AdjacentUnmanagedContext;
|
|
96
|
+
/**
|
|
97
|
+
* Set beside `--scan`: the scan has already reconciled missing files and
|
|
98
|
+
* adopted what it was asked to, so only the neighbours it left are judged.
|
|
99
|
+
*/
|
|
100
|
+
afterScan?: boolean;
|
|
64
101
|
}): Promise<boolean>;
|
|
102
|
+
/**
|
|
103
|
+
* End-of-run accounting for `--expect-new` and `--adjacent-ignore`.
|
|
104
|
+
*
|
|
105
|
+
* An `--expect-new` path is a promise that the next export adopts it, so a
|
|
106
|
+
* met one is repeated as the export still owed, and an unmet one is a
|
|
107
|
+
* warning: a typo there leaves the refusal armed for the file it meant to
|
|
108
|
+
* admit. An unmatched `--adjacent-ignore` entry is only noted, because a
|
|
109
|
+
* reviewed ignore list is reused across runs and patches, and "not met"
|
|
110
|
+
* is its normal case.
|
|
111
|
+
*/
|
|
112
|
+
export declare function reportAdjacentCarveOutUsage(ctx: AdjacentUnmanagedContext): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Re-export adjacency advisory.
|
|
4
4
|
*
|
|
5
5
|
* A plain `re-export` keeps the manifest's filesAffected unchanged, so a
|
|
6
6
|
* brand-new file an author just created beside a patch's owned files is
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* files, filters out tool-managed paths (branding, furnace) so the notice
|
|
9
9
|
* names only genuinely unmanaged candidates, and, under
|
|
10
10
|
* `--refuse-adjacent-unmanaged`, lets the caller turn the notice into a
|
|
11
|
-
* non-zero refusal.
|
|
11
|
+
* non-zero refusal. Beside `--scan` it judges the files the scan did not
|
|
12
|
+
* adopt, so a targeted `--scan-file` adoption keeps the belt.
|
|
12
13
|
*
|
|
13
14
|
* Split out of re-export.ts to keep that file inside the max-lines budget.
|
|
14
15
|
* Exports helpers consumed by re-export.ts, no registrar.
|
|
@@ -21,6 +22,34 @@ import { isGeneratedBrandingPath } from '../core/status-classify.js';
|
|
|
21
22
|
import { mapWithConcurrency } from '../utils/concurrency.js';
|
|
22
23
|
import { pathExists } from '../utils/fs.js';
|
|
23
24
|
import { info, warn } from '../utils/logger.js';
|
|
25
|
+
import { escapeRegex } from '../utils/regex.js';
|
|
26
|
+
import { findRegisteredChangedFiles } from './re-export-adjacent-registrations.js';
|
|
27
|
+
import { normalizeEngineRelativeInput } from './re-export-scan.js';
|
|
28
|
+
/**
|
|
29
|
+
* Builds the run's adjacency context. The path flags are normalized once
|
|
30
|
+
* here, so the per-file comparison matches git's engine-relative output.
|
|
31
|
+
*/
|
|
32
|
+
export function buildAdjacentUnmanagedContext(options, binaryName, furnacePrefixes) {
|
|
33
|
+
const normalized = (flag, values) => (values ?? []).map((value) => normalizeEngineRelativeInput(value, flag));
|
|
34
|
+
return {
|
|
35
|
+
binaryName,
|
|
36
|
+
furnacePrefixes,
|
|
37
|
+
refuseAdjacentUnmanaged: options.refuseAdjacentUnmanaged === true,
|
|
38
|
+
approvedUnmanaged: new Set(normalized('--expect-unmanaged', options.expectUnmanaged)),
|
|
39
|
+
approvedSeen: new Set(),
|
|
40
|
+
expectedNew: new Set(normalized('--expect-new', options.expectNew)),
|
|
41
|
+
expectedNewSeen: new Set(),
|
|
42
|
+
adjacentIgnore: normalized('--adjacent-ignore', options.adjacentIgnore),
|
|
43
|
+
adjacentIgnoreSeen: new Set(),
|
|
44
|
+
refusals: [],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The one definition of "adjacent", shared by the per-patch notice and the
|
|
49
|
+
* run-level refusal so the two cannot drift apart.
|
|
50
|
+
*/
|
|
51
|
+
export const ADJACENT_MEANS = 'Adjacent means the file sits in the same directory as a file this patch owns, ' +
|
|
52
|
+
'or a registration line this patch adds (jar.mn, moz.build, test manifest) names it.';
|
|
24
53
|
/** Concurrency bound for existence probes (matches the classify/lint pools). */
|
|
25
54
|
const PATH_PROBE_CONCURRENCY = 8;
|
|
26
55
|
/** Returns the subset of `files` that no longer exist under `engineDir`. */
|
|
@@ -42,14 +71,41 @@ function isToolManagedPath(file, isNewFile, ctx) {
|
|
|
42
71
|
}
|
|
43
72
|
return false;
|
|
44
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Matches an `--adjacent-ignore` entry. A `*` stays inside one path
|
|
76
|
+
* segment, the same narrowness as `buildAudit.unpackaged`: a carve-out that
|
|
77
|
+
* silently spans subtrees is how a reviewed exception becomes a blanket one.
|
|
78
|
+
*/
|
|
79
|
+
function matchesIgnoreEntry(entry, file) {
|
|
80
|
+
if (!entry.includes('*'))
|
|
81
|
+
return entry === file;
|
|
82
|
+
const pattern = entry
|
|
83
|
+
.split('*')
|
|
84
|
+
.map((part) => escapeRegex(part))
|
|
85
|
+
.join('[^/]*');
|
|
86
|
+
return new RegExp(`^${pattern}$`).test(file);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Lists the unmanaged files a re-export of this patch would plausibly have
|
|
90
|
+
* to capture: changed files directly in a directory the patch owns a file
|
|
91
|
+
* in, and changed files a registration line the patch adds names. A file in
|
|
92
|
+
* a sibling or nested directory is not adjacent. The directory listing
|
|
93
|
+
* recurses (pathspecs do), so it is filtered back to the exact directories,
|
|
94
|
+
* the same footprint the broad `--scan` adopts from.
|
|
95
|
+
*/
|
|
45
96
|
async function findAdjacentUnmanagedFiles(args) {
|
|
46
97
|
const { currentFilesAffected, engineDir, manifest, patchFilename, ctx } = args;
|
|
47
98
|
const parentDirs = [...new Set(currentFilesAffected.map((file) => dirname(file)))];
|
|
99
|
+
const parentDirSet = new Set(parentDirs);
|
|
48
100
|
const currentSet = new Set(currentFilesAffected);
|
|
49
101
|
const claimedByOthers = getClaimedFiles(manifest, patchFilename);
|
|
50
|
-
// First anchor wins:
|
|
51
|
-
//
|
|
102
|
+
// First anchor wins: a file lives in exactly one directory, and a
|
|
103
|
+
// directory anchor is the stronger statement than a registration one.
|
|
52
104
|
const candidates = new Map();
|
|
105
|
+
const isCandidate = (file, isNewFile) => !currentSet.has(file) &&
|
|
106
|
+
!claimedByOthers.has(file) &&
|
|
107
|
+
!candidates.has(file) &&
|
|
108
|
+
!isToolManagedPath(file, isNewFile, ctx);
|
|
53
109
|
for (const dir of parentDirs) {
|
|
54
110
|
const [modifiedFiles, untrackedFiles] = await Promise.all([
|
|
55
111
|
getModifiedFilesInDir(engineDir, dir),
|
|
@@ -57,41 +113,80 @@ async function findAdjacentUnmanagedFiles(args) {
|
|
|
57
113
|
]);
|
|
58
114
|
const untrackedSet = new Set(untrackedFiles);
|
|
59
115
|
for (const file of [...modifiedFiles, ...untrackedFiles]) {
|
|
60
|
-
if (
|
|
116
|
+
if (!parentDirSet.has(dirname(file)))
|
|
61
117
|
continue;
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
118
|
+
if (isCandidate(file, untrackedSet.has(file))) {
|
|
119
|
+
candidates.set(file, { file, anchorDir: dirname(file) });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const registered = await findRegisteredChangedFiles(engineDir, currentFilesAffected);
|
|
124
|
+
for (const { file, carrier } of registered) {
|
|
125
|
+
// A registered path is a patch candidate whatever its tracking state,
|
|
126
|
+
// so it is classified as new: only a generated path is tool-managed.
|
|
127
|
+
if (isCandidate(file, true)) {
|
|
128
|
+
candidates.set(file, { file, anchorDir: dirname(carrier), registeredBy: carrier });
|
|
66
129
|
}
|
|
67
130
|
}
|
|
68
|
-
return [...candidates.
|
|
69
|
-
|
|
70
|
-
|
|
131
|
+
return [...candidates.values()].sort((a, b) => a.file.localeCompare(b.file));
|
|
132
|
+
}
|
|
133
|
+
function dispositionOf(file, ctx) {
|
|
134
|
+
if (ctx.approvedUnmanaged.has(file)) {
|
|
135
|
+
ctx.approvedSeen.add(file);
|
|
136
|
+
return 'approved';
|
|
137
|
+
}
|
|
138
|
+
if (ctx.expectedNew.has(file)) {
|
|
139
|
+
ctx.expectedNewSeen.add(file);
|
|
140
|
+
return 'expected-new';
|
|
141
|
+
}
|
|
142
|
+
const ignore = ctx.adjacentIgnore.find((entry) => matchesIgnoreEntry(entry, file));
|
|
143
|
+
if (ignore !== undefined) {
|
|
144
|
+
ctx.adjacentIgnoreSeen.add(ignore);
|
|
145
|
+
return 'ignored';
|
|
146
|
+
}
|
|
147
|
+
return 'refusing';
|
|
71
148
|
}
|
|
72
149
|
/**
|
|
73
|
-
* Splits the candidates into the ones that refuse and the ones a
|
|
74
|
-
* `--expect-unmanaged
|
|
75
|
-
* so an unused
|
|
76
|
-
* dropped, so the exception stays visible
|
|
150
|
+
* Splits the candidates into the ones that refuse and the ones a carve-out
|
|
151
|
+
* (`--expect-unmanaged`, `--expect-new`, `--adjacent-ignore`) admits. Met
|
|
152
|
+
* carve-outs are recorded so an unused one can be reported, and admitted
|
|
153
|
+
* files are returned rather than dropped, so the exception stays visible
|
|
154
|
+
* instead of quietly widening.
|
|
77
155
|
*/
|
|
78
156
|
function partitionApproved(files, ctx) {
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return { refusing, approved };
|
|
157
|
+
const groups = {
|
|
158
|
+
refusing: [],
|
|
159
|
+
approved: [],
|
|
160
|
+
'expected-new': [],
|
|
161
|
+
ignored: [],
|
|
162
|
+
};
|
|
163
|
+
for (const entry of files)
|
|
164
|
+
groups[dispositionOf(entry.file, ctx)].push(entry);
|
|
165
|
+
return groups;
|
|
91
166
|
}
|
|
92
|
-
/**
|
|
167
|
+
/** How a notice names one file's anchor. */
|
|
168
|
+
function describeAnchor(entry) {
|
|
169
|
+
return entry.registeredBy !== undefined
|
|
170
|
+
? `registered by engine/${entry.registeredBy}`
|
|
171
|
+
: `beside engine/${entry.anchorDir}`;
|
|
172
|
+
}
|
|
173
|
+
/** Renders `<file> (beside engine/<dir>)` or `<file> (registered by engine/<carrier>)`. */
|
|
93
174
|
function describeAnchored(entry) {
|
|
94
|
-
return `${entry.file} (
|
|
175
|
+
return `${entry.file} (${describeAnchor(entry)})`;
|
|
176
|
+
}
|
|
177
|
+
/** The admitted-file notice lines, one per carve-out that admitted anything. */
|
|
178
|
+
function reportAdmitted(patchFilename, groups) {
|
|
179
|
+
const notices = [
|
|
180
|
+
[groups.approved, 'admitted by --expect-unmanaged'],
|
|
181
|
+
[groups['expected-new'], 'expected by --expect-new'],
|
|
182
|
+
[groups.ignored, 'ignored by --adjacent-ignore'],
|
|
183
|
+
];
|
|
184
|
+
for (const [entries, how] of notices) {
|
|
185
|
+
if (entries.length === 0)
|
|
186
|
+
continue;
|
|
187
|
+
info(`${patchFilename}: ${entries.length} adjacent unmanaged file(s) ${how} ` +
|
|
188
|
+
`(${entries.map(describeAnchored).join(', ')}) — reported, not refused.`);
|
|
189
|
+
}
|
|
95
190
|
}
|
|
96
191
|
/**
|
|
97
192
|
* Emits the scan-less advisory for one patch: missing manifest files and
|
|
@@ -103,7 +198,7 @@ function describeAnchored(entry) {
|
|
|
103
198
|
*/
|
|
104
199
|
export async function reportAdjacentUnmanagedFiles(args) {
|
|
105
200
|
const { patch, paths, manifest, currentFilesAffected, ctx } = args;
|
|
106
|
-
const missingFiles = await findMissingFiles(paths.engine, currentFilesAffected);
|
|
201
|
+
const missingFiles = args.afterScan === true ? [] : await findMissingFiles(paths.engine, currentFilesAffected);
|
|
107
202
|
if (missingFiles.length > 0) {
|
|
108
203
|
warn(`${patch.filename}: some files in patches.json no longer exist on disk ` +
|
|
109
204
|
`(${missingFiles.join(', ')}). Without --scan, re-export keeps the manifest's ` +
|
|
@@ -119,20 +214,19 @@ export async function reportAdjacentUnmanagedFiles(args) {
|
|
|
119
214
|
patchFilename: patch.filename,
|
|
120
215
|
ctx,
|
|
121
216
|
});
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
`--expect-unmanaged (${approved.map(describeAnchored).join(', ')}) — reported, not refused.`);
|
|
126
|
-
}
|
|
217
|
+
const groups = partitionApproved(allUnmanaged, ctx);
|
|
218
|
+
reportAdmitted(patch.filename, groups);
|
|
219
|
+
const unmanagedFiles = groups.refusing;
|
|
127
220
|
if (unmanagedFiles.length === 0)
|
|
128
221
|
return false;
|
|
129
222
|
const firstFew = unmanagedFiles.slice(0, 3).map(describeAnchored).join(', ');
|
|
130
223
|
const more = unmanagedFiles.length > 3 ? `, +${unmanagedFiles.length - 3} more` : '';
|
|
131
|
-
warn(`${patch.filename}: found ${unmanagedFiles.length} unmanaged file(s) adjacent to this patch's ownership (${firstFew}${more})
|
|
132
|
-
|
|
133
|
-
`Plain re-export keeps filesAffected unchanged — use --scan-file to include reviewed files
|
|
224
|
+
warn(`${patch.filename}: found ${unmanagedFiles.length} unmanaged file(s) adjacent to this patch's ownership (${firstFew}${more}). ` +
|
|
225
|
+
`${ADJACENT_MEANS} ` +
|
|
226
|
+
`Plain re-export keeps filesAffected unchanged — use --scan-file to include reviewed files, ` +
|
|
227
|
+
`or --expect-new for a file your next export adopts.`);
|
|
134
228
|
for (const entry of unmanagedFiles) {
|
|
135
|
-
info(` ${entry.file} —
|
|
229
|
+
info(` ${entry.file} — ${describeAnchor(entry)} — ` +
|
|
136
230
|
`fireforge re-export ${patch.filename} --scan --scan-file ${entry.file}`);
|
|
137
231
|
}
|
|
138
232
|
if (ctx.refuseAdjacentUnmanaged) {
|
|
@@ -145,3 +239,29 @@ export async function reportAdjacentUnmanagedFiles(args) {
|
|
|
145
239
|
}
|
|
146
240
|
return false;
|
|
147
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* End-of-run accounting for `--expect-new` and `--adjacent-ignore`.
|
|
244
|
+
*
|
|
245
|
+
* An `--expect-new` path is a promise that the next export adopts it, so a
|
|
246
|
+
* met one is repeated as the export still owed, and an unmet one is a
|
|
247
|
+
* warning: a typo there leaves the refusal armed for the file it meant to
|
|
248
|
+
* admit. An unmatched `--adjacent-ignore` entry is only noted, because a
|
|
249
|
+
* reviewed ignore list is reused across runs and patches, and "not met"
|
|
250
|
+
* is its normal case.
|
|
251
|
+
*/
|
|
252
|
+
export function reportAdjacentCarveOutUsage(ctx) {
|
|
253
|
+
const unseenNew = [...ctx.expectedNew].filter((file) => !ctx.expectedNewSeen.has(file));
|
|
254
|
+
if (unseenNew.length > 0) {
|
|
255
|
+
warn(`--expect-new path(s) were not met as adjacent unmanaged files this run: ` +
|
|
256
|
+
`${unseenNew.join(', ')}. Check the path for a typo, and that a selected patch owns a ` +
|
|
257
|
+
'file in its directory or registers it. The refusal stayed armed for everything else.');
|
|
258
|
+
}
|
|
259
|
+
if (ctx.expectedNewSeen.size > 0) {
|
|
260
|
+
info(`--expect-new admitted ${[...ctx.expectedNewSeen].sort().join(', ')}, which no patch owns ` +
|
|
261
|
+
'yet. Export them next so the queue does not register files it does not ship.');
|
|
262
|
+
}
|
|
263
|
+
const unseenIgnore = ctx.adjacentIgnore.filter((entry) => !ctx.adjacentIgnoreSeen.has(entry));
|
|
264
|
+
if (unseenIgnore.length > 0) {
|
|
265
|
+
info(`--adjacent-ignore entries matched no adjacent file this run: ${unseenIgnore.join(', ')}.`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { PatchesManifest } from '../types/commands/index.js';
|
|
2
|
+
import { type DryRunPurityScope } from './re-export-purity-scope.js';
|
|
2
3
|
/** Loads and validates a `re-export --scan-files` assignment manifest. */
|
|
3
4
|
export declare function loadScanFilesAssignments(manifestPath: string, manifest: PatchesManifest): Promise<Map<string, string[]>>;
|
|
4
5
|
/**
|
|
@@ -13,6 +14,6 @@ export declare function loadScanFilesAssignments(manifestPath: string, manifest:
|
|
|
13
14
|
* violation surfaces the violation with the original error as `cause`.
|
|
14
15
|
* No-op outside dry-run.
|
|
15
16
|
*/
|
|
16
|
-
export declare function withDryRunPurityGuard<T>(engineDir: string, patchesDir: string, isDryRun: boolean, operation: () => Promise<T
|
|
17
|
+
export declare function withDryRunPurityGuard<T>(engineDir: string, patchesDir: string, isDryRun: boolean, operation: () => Promise<T>, scope?: DryRunPurityScope): Promise<T>;
|
|
17
18
|
/** Serializes dry-run re-export git inspection against the same project tree. */
|
|
18
19
|
export declare function withDryRunReExportLock<T>(fireforgeDir: string, isDryRun: boolean, operation: () => Promise<T>): Promise<T>;
|
|
@@ -11,6 +11,7 @@ import { getNodeErrorCode, toError } from '../utils/errors.js';
|
|
|
11
11
|
import { readText } from '../utils/fs.js';
|
|
12
12
|
import { sha256Hex } from '../utils/hash.js';
|
|
13
13
|
import { isObject } from '../utils/validation.js';
|
|
14
|
+
import { describeForeignWriters, fingerprintScopedDryRunState, } from './re-export-purity-scope.js';
|
|
14
15
|
import { normalizeEngineRelativeInput } from './re-export-scan.js';
|
|
15
16
|
/** Concurrency bound for patch-body hashing (matches the classify/lint pools). */
|
|
16
17
|
const PATCH_HASH_CONCURRENCY = 8;
|
|
@@ -161,10 +162,14 @@ async function fingerprintDryRunState(engineDir, patchesDir) {
|
|
|
161
162
|
* violation surfaces the violation with the original error as `cause`.
|
|
162
163
|
* No-op outside dry-run.
|
|
163
164
|
*/
|
|
164
|
-
export async function withDryRunPurityGuard(engineDir, patchesDir, isDryRun, operation) {
|
|
165
|
+
export async function withDryRunPurityGuard(engineDir, patchesDir, isDryRun, operation, scope) {
|
|
165
166
|
if (!isDryRun)
|
|
166
167
|
return operation();
|
|
167
|
-
const
|
|
168
|
+
const fingerprint = () => scope === undefined
|
|
169
|
+
? fingerprintDryRunState(engineDir, patchesDir)
|
|
170
|
+
: fingerprintScopedDryRunState(engineDir, patchesDir, scope);
|
|
171
|
+
const startedAt = Date.now();
|
|
172
|
+
const before = await fingerprint();
|
|
168
173
|
let result;
|
|
169
174
|
let operationError;
|
|
170
175
|
let failed = false;
|
|
@@ -177,7 +182,7 @@ export async function withDryRunPurityGuard(engineDir, patchesDir, isDryRun, ope
|
|
|
177
182
|
}
|
|
178
183
|
let after;
|
|
179
184
|
try {
|
|
180
|
-
after = await
|
|
185
|
+
after = await fingerprint();
|
|
181
186
|
}
|
|
182
187
|
catch (fingerprintError) {
|
|
183
188
|
// The post-run fingerprint failing must not swallow the dry run's own
|
|
@@ -195,10 +200,20 @@ export async function withDryRunPurityGuard(engineDir, patchesDir, isDryRun, ope
|
|
|
195
200
|
.sort()
|
|
196
201
|
.filter((key) => before.get(key) !== after.get(key));
|
|
197
202
|
if (touched.length > 0) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
203
|
+
const also = failed ? ` The dry run also failed: ${toError(operationError).message}` : '';
|
|
204
|
+
const writers = await describeForeignWriters(patchesDir, startedAt);
|
|
205
|
+
if (writers.length > 0) {
|
|
206
|
+
throw new GeneralError(`[dry-run] ${touched.join(', ')} changed during this dry run, written by another ` +
|
|
207
|
+
`writer: ${writers.join('; ')}. The preview raced that write; rerun it once the ` +
|
|
208
|
+
`writer is done.${also}`, operationError);
|
|
209
|
+
}
|
|
210
|
+
throw new GeneralError(`[dry-run] invariant violated: ${touched.join(', ')} changed during this dry run. No ` +
|
|
211
|
+
'other FireForge command recorded a write in that window, so either another writer ' +
|
|
212
|
+
'(an editor, an agent or a git command in engine/) changed it, or this is a FireForge ' +
|
|
213
|
+
'bug. Rerun the dry run; if it repeats on a quiet tree, please report it, and inspect ' +
|
|
214
|
+
'the listed state (e.g. `git status` in engine/ and your patches/ diff) before ' +
|
|
215
|
+
'trusting it.' +
|
|
216
|
+
also, operationError);
|
|
202
217
|
}
|
|
203
218
|
if (failed)
|
|
204
219
|
throw operationError;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* (`re-export-adjacent.ts`) warns about unmanaged neighbour files but is
|
|
9
9
|
* structurally blind to drift inside owned files. This module compares
|
|
10
10
|
* the old body against the refreshed body per file and reports the
|
|
11
|
-
* payload lines that are about to enter the body. Under
|
|
11
|
+
* payload lines that are about to enter or leave the body. Under
|
|
12
12
|
* `--refuse-foreign-drift` the patch is skipped and the run exits
|
|
13
13
|
* non-zero, mirroring `--refuse-adjacent-unmanaged`.
|
|
14
14
|
*
|
|
@@ -41,23 +41,39 @@ export interface ForeignDriftContext {
|
|
|
41
41
|
reason: ForeignDriftRefusalReason;
|
|
42
42
|
}[];
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* One owned file's foreign drift between the old and refreshed body,
|
|
46
|
+
* counted as edits to the engine file rather than as body payload, so a
|
|
47
|
+
* deletion-only change is drift like any other.
|
|
48
|
+
*/
|
|
45
49
|
export interface FileForeignDrift {
|
|
46
50
|
file: string;
|
|
47
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Lines the engine file gained since the old body: `+` payload the new
|
|
53
|
+
* body carries that the old did not, plus `-` payload the old body carried
|
|
54
|
+
* that the new one dropped (an upstream line restored).
|
|
55
|
+
*/
|
|
48
56
|
addedLines: number;
|
|
49
|
-
/**
|
|
57
|
+
/**
|
|
58
|
+
* Lines the engine file lost since the old body: `-` payload the new body
|
|
59
|
+
* carries that the old did not, plus `+` payload the old body carried that
|
|
60
|
+
* the new one dropped (a line the patch added, now deleted).
|
|
61
|
+
*/
|
|
50
62
|
removedLines: number;
|
|
51
|
-
/** `@@` headers of
|
|
63
|
+
/** `@@` headers of the hunks carrying those lines (capped). */
|
|
52
64
|
hunkSummaries: string[];
|
|
53
65
|
/** True when a binary section's recorded new-side blob hash changed. */
|
|
54
66
|
binaryChanged: boolean;
|
|
55
67
|
}
|
|
56
68
|
/**
|
|
57
69
|
* Pure comparison: per owned file, which `+`/`-` payload lines the
|
|
58
|
-
* refreshed body carries that the old body did not
|
|
59
|
-
*
|
|
60
|
-
*
|
|
70
|
+
* refreshed body carries that the old body did not, and which the old body
|
|
71
|
+
* carried that the refreshed one dropped. Both directions are drift: a
|
|
72
|
+
* concurrent session deleting a line the patch added changes the patch as
|
|
73
|
+
* surely as one adding a line, and a belt that only saw absorbed lines let
|
|
74
|
+
* such a deletion through silently. Files not in `previousFilesAffected`
|
|
75
|
+
* are skipped, since those are intentional adoptions (`--scan`) or
|
|
76
|
+
* retirements (`--expect-removed`) rather than drift.
|
|
61
77
|
*/
|
|
62
78
|
export declare function computeForeignDrift(oldBody: string, newBody: string, previousFilesAffected: readonly string[]): FileForeignDrift[];
|
|
63
79
|
/**
|
|
@@ -71,6 +87,18 @@ export declare function reportForeignDrift(args: {
|
|
|
71
87
|
engineDir: string;
|
|
72
88
|
newDiffContent: string;
|
|
73
89
|
ctx: ForeignDriftContext;
|
|
90
|
+
/**
|
|
91
|
+
* The patch's files that the comparison covers. Defaults to its
|
|
92
|
+
* `filesAffected`; the caller narrows it by the `--expect-removed`
|
|
93
|
+
* retirements, which leave the body on purpose.
|
|
94
|
+
*/
|
|
95
|
+
ownedFiles?: readonly string[];
|
|
96
|
+
/**
|
|
97
|
+
* Files a `--scan`/`--scan-file` adoption brings in this run. They sit
|
|
98
|
+
* outside the comparison (nothing to compare against) and count as
|
|
99
|
+
* expected, so naming one in `--expect` is not reported as unseen.
|
|
100
|
+
*/
|
|
101
|
+
adoptedFiles?: readonly string[];
|
|
74
102
|
}): Promise<boolean>;
|
|
75
103
|
/**
|
|
76
104
|
* Names `--expect` paths that never drifted this run. A typo'd
|