@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,5 +1,5 @@
|
|
|
1
1
|
import { GeneralError, InvalidArgumentError } from '../errors/base.js';
|
|
2
|
-
const
|
|
2
|
+
const ALL_CHECK_CLASSES = [
|
|
3
3
|
'patch-backed',
|
|
4
4
|
'patch-owned-drift',
|
|
5
5
|
'unmanaged',
|
|
@@ -7,12 +7,15 @@ const ALL_CLASSIFICATIONS = [
|
|
|
7
7
|
'furnace',
|
|
8
8
|
'conflict',
|
|
9
9
|
'binary-unsupported',
|
|
10
|
+
'ownership-conflict',
|
|
10
11
|
];
|
|
11
12
|
/**
|
|
12
13
|
* Default `--check` policy: everything outside {patch-backed, branding,
|
|
13
14
|
* furnace, binary-unsupported} fails. `binary-unsupported` is excluded so
|
|
14
15
|
* an honest "cannot compare" does not keep the gate permanently red.
|
|
15
16
|
* Strict CI can opt in via `--fail-on binary-unsupported`.
|
|
17
|
+
* `ownership-conflict` is opt-in too: the human `--ownership` mode already
|
|
18
|
+
* fails on it, and adding it here would change the default gate.
|
|
16
19
|
*/
|
|
17
20
|
const DEFAULT_FAIL_CLASSIFICATIONS = [
|
|
18
21
|
'unmanaged',
|
|
@@ -20,13 +23,19 @@ const DEFAULT_FAIL_CLASSIFICATIONS = [
|
|
|
20
23
|
'conflict',
|
|
21
24
|
];
|
|
22
25
|
/**
|
|
23
|
-
* Resolves the enforcement policy from the raw flags
|
|
24
|
-
* `--
|
|
25
|
-
*
|
|
26
|
+
* Resolves the enforcement policy from the raw flags. `--fail-on`,
|
|
27
|
+
* `--allow` and `--fail-on-unknown` each imply `--check`. `--fail-on`
|
|
28
|
+
* replaces the default set and `--allow` subtracts from it (naming one
|
|
29
|
+
* class in both is refused). `--fail-on-unknown` needs `--allow`: without
|
|
30
|
+
* an allow list every class the caller did not name, `patch-backed`
|
|
31
|
+
* included, would fail. All of them are refused alongside the modes that
|
|
32
|
+
* skip (or elide) classification.
|
|
26
33
|
*/
|
|
27
34
|
export function resolveStatusCheckPolicy(options) {
|
|
28
|
-
const failOnList =
|
|
29
|
-
const
|
|
35
|
+
const failOnList = parseCheckClassList(options.failOn, '--fail-on');
|
|
36
|
+
const allowList = parseCheckClassList(options.allow, '--allow');
|
|
37
|
+
const failOnUnknown = options.failOnUnknown === true;
|
|
38
|
+
const checkEnabled = options.check === true || failOnList !== undefined || allowList !== undefined || failOnUnknown;
|
|
30
39
|
if (checkEnabled &&
|
|
31
40
|
(options.raw === true ||
|
|
32
41
|
options.unmanaged === true ||
|
|
@@ -34,17 +43,32 @@ export function resolveStatusCheckPolicy(options) {
|
|
|
34
43
|
options.testCoverage === true)) {
|
|
35
44
|
throw new InvalidArgumentError('--check cannot be combined with --raw, --unmanaged, --ownership, or --test-coverage. Use the default view or --json.', '--check');
|
|
36
45
|
}
|
|
37
|
-
|
|
46
|
+
if (failOnUnknown && allowList === undefined) {
|
|
47
|
+
throw new InvalidArgumentError('--fail-on-unknown requires --allow naming the classes that may pass. Without it every class you did not name, patch-backed included, would fail.', '--fail-on-unknown');
|
|
48
|
+
}
|
|
49
|
+
const overlap = (failOnList ?? []).filter((entry) => allowList?.includes(entry) === true);
|
|
50
|
+
if (overlap.length > 0) {
|
|
51
|
+
throw new InvalidArgumentError(`--fail-on and --allow both name ${overlap.join(', ')}. A class either fails or is allowed.`, '--allow');
|
|
52
|
+
}
|
|
53
|
+
const base = failOnList ?? DEFAULT_FAIL_CLASSIFICATIONS;
|
|
54
|
+
const policy = {
|
|
55
|
+
checkEnabled,
|
|
56
|
+
failOn: allowList ? base.filter((entry) => !allowList.includes(entry)) : base,
|
|
57
|
+
};
|
|
58
|
+
if (allowList !== undefined)
|
|
59
|
+
policy.allow = allowList;
|
|
60
|
+
if (failOnUnknown)
|
|
61
|
+
policy.failOnUnknown = true;
|
|
62
|
+
return policy;
|
|
38
63
|
}
|
|
39
|
-
function
|
|
40
|
-
return
|
|
64
|
+
function isCheckClass(value) {
|
|
65
|
+
return ALL_CHECK_CLASSES.includes(value);
|
|
41
66
|
}
|
|
42
67
|
/**
|
|
43
|
-
* Parses a comma-separated `--fail-on` value into a
|
|
44
|
-
* Returns undefined when the flag was not given
|
|
45
|
-
* the default policy only under `--check`).
|
|
68
|
+
* Parses a comma-separated `--fail-on`/`--allow` value into a class list.
|
|
69
|
+
* Returns undefined when the flag was not given.
|
|
46
70
|
*/
|
|
47
|
-
function
|
|
71
|
+
function parseCheckClassList(raw, flag) {
|
|
48
72
|
if (raw === undefined)
|
|
49
73
|
return undefined;
|
|
50
74
|
const parts = raw
|
|
@@ -52,52 +76,83 @@ function parseFailOnClassifications(raw) {
|
|
|
52
76
|
.map((part) => part.trim())
|
|
53
77
|
.filter((part) => part.length > 0);
|
|
54
78
|
if (parts.length === 0) {
|
|
55
|
-
throw new InvalidArgumentError(
|
|
79
|
+
throw new InvalidArgumentError(`${flag} requires at least one classification. Valid: ${ALL_CHECK_CLASSES.join(', ')}.`, flag);
|
|
56
80
|
}
|
|
57
|
-
const
|
|
81
|
+
const classes = [];
|
|
58
82
|
for (const part of parts) {
|
|
59
|
-
if (!
|
|
60
|
-
throw new InvalidArgumentError(`Unknown
|
|
83
|
+
if (!isCheckClass(part)) {
|
|
84
|
+
throw new InvalidArgumentError(`Unknown ${flag} classification "${part}". Valid: ${ALL_CHECK_CLASSES.join(', ')}.`, flag);
|
|
61
85
|
}
|
|
62
|
-
if (!
|
|
63
|
-
|
|
86
|
+
if (!classes.includes(part))
|
|
87
|
+
classes.push(part);
|
|
64
88
|
}
|
|
65
|
-
return
|
|
89
|
+
return classes;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* True when the policy can fail on `ownership-conflict`, so the caller has
|
|
93
|
+
* to build the ownership rows even without `--include-ownership`.
|
|
94
|
+
*/
|
|
95
|
+
export function policyNeedsOwnership(policy) {
|
|
96
|
+
if (!policy.checkEnabled)
|
|
97
|
+
return false;
|
|
98
|
+
if (policy.failOn.includes('ownership-conflict'))
|
|
99
|
+
return true;
|
|
100
|
+
return policy.failOnUnknown === true && policy.allow?.includes('ownership-conflict') !== true;
|
|
66
101
|
}
|
|
67
102
|
const CHECK_FILE_PREVIEW_MAX = 3;
|
|
68
103
|
/**
|
|
69
|
-
* Collects the
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
104
|
+
* Collects the failing classes that have offending files, with full file
|
|
105
|
+
* lists: the fail set in policy order, then (under `--fail-on-unknown`)
|
|
106
|
+
* every other present class neither list names, in first-seen order.
|
|
107
|
+
* Shared by the human `--check` verdict and the JSON `check` block so the
|
|
108
|
+
* two views can never disagree about what failed.
|
|
109
|
+
*
|
|
110
|
+
* @param classified - Classified worktree entries
|
|
111
|
+
* @param policy - Resolved policy
|
|
112
|
+
* @param ownershipConflicts - Paths claimed by more than one patch. Only
|
|
113
|
+
* read for the `ownership-conflict` class
|
|
73
114
|
*/
|
|
74
|
-
export function collectStatusCheckOffenders(classified, policy) {
|
|
115
|
+
export function collectStatusCheckOffenders(classified, policy, ownershipConflicts = []) {
|
|
116
|
+
const filesOf = (checkClass) => checkClass === 'ownership-conflict'
|
|
117
|
+
? [...ownershipConflicts]
|
|
118
|
+
: classified.filter((entry) => entry.classification === checkClass).map((e) => e.file);
|
|
75
119
|
const offenders = [];
|
|
76
|
-
for (const
|
|
77
|
-
const files =
|
|
78
|
-
.filter((entry) => entry.classification === classification)
|
|
79
|
-
.map((entry) => entry.file);
|
|
120
|
+
for (const checkClass of policy.failOn) {
|
|
121
|
+
const files = filesOf(checkClass);
|
|
80
122
|
if (files.length === 0)
|
|
81
123
|
continue;
|
|
82
|
-
offenders.push({ classification, count: files.length, files });
|
|
124
|
+
offenders.push({ classification: checkClass, count: files.length, files });
|
|
125
|
+
}
|
|
126
|
+
if (policy.failOnUnknown !== true)
|
|
127
|
+
return offenders;
|
|
128
|
+
const named = new Set([...policy.failOn, ...(policy.allow ?? [])]);
|
|
129
|
+
const present = [...new Set(classified.map((e) => e.classification))];
|
|
130
|
+
if (ownershipConflicts.length > 0)
|
|
131
|
+
present.push('ownership-conflict');
|
|
132
|
+
for (const checkClass of present) {
|
|
133
|
+
if (named.has(checkClass))
|
|
134
|
+
continue;
|
|
135
|
+
const files = filesOf(checkClass);
|
|
136
|
+
offenders.push({ classification: checkClass, count: files.length, files, unnamed: true });
|
|
83
137
|
}
|
|
84
138
|
return offenders;
|
|
85
139
|
}
|
|
86
140
|
/**
|
|
87
|
-
* Throws a GeneralError (exit 1) when the policy is enabled and any
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
141
|
+
* Throws a GeneralError (exit 1) when the policy is enabled and any
|
|
142
|
+
* failing class is non-empty, naming each offending class with its first
|
|
143
|
+
* few files. A disabled policy or a fully tool-covered tree passes
|
|
144
|
+
* silently.
|
|
91
145
|
*/
|
|
92
|
-
export function runStatusCheck(classified, policy) {
|
|
146
|
+
export function runStatusCheck(classified, policy, ownershipConflicts = []) {
|
|
93
147
|
if (!policy.checkEnabled)
|
|
94
148
|
return;
|
|
95
|
-
const offending = collectStatusCheckOffenders(classified, policy).map((offender) => {
|
|
149
|
+
const offending = collectStatusCheckOffenders(classified, policy, ownershipConflicts).map((offender) => {
|
|
96
150
|
const preview = offender.files.slice(0, CHECK_FILE_PREVIEW_MAX).join(', ');
|
|
97
151
|
const more = offender.count > CHECK_FILE_PREVIEW_MAX
|
|
98
152
|
? `, +${offender.count - CHECK_FILE_PREVIEW_MAX} more`
|
|
99
153
|
: '';
|
|
100
|
-
|
|
154
|
+
const unnamed = offender.unnamed === true ? ' [named by neither --fail-on nor --allow]' : '';
|
|
155
|
+
return `${offender.count} ${offender.classification}${unnamed} (${preview}${more})`;
|
|
101
156
|
});
|
|
102
157
|
if (offending.length === 0)
|
|
103
158
|
return;
|
|
@@ -9,24 +9,37 @@
|
|
|
9
9
|
* `files[]` entirely, because engine-clean gates need the verdict,
|
|
10
10
|
* per-class counts, and offender names, not a payload that grows with
|
|
11
11
|
* the queue (175 KB+ on a large one).
|
|
12
|
+
*
|
|
13
|
+
* Both carry the `check` block when the `--check` policy is active, and the
|
|
14
|
+
* `scope` block under `--patches`.
|
|
12
15
|
*/
|
|
13
16
|
import type { ClassifiedFile } from '../core/status-classify.js';
|
|
14
17
|
import { type StatusCheckPolicy } from './status-check.js';
|
|
15
18
|
import type { OwnershipJsonBlock } from './status-ownership.js';
|
|
19
|
+
import type { StatusScope } from './status-scope.js';
|
|
20
|
+
/** What a JSON payload adds beside the classification counts. */
|
|
21
|
+
export interface StatusJsonContext {
|
|
22
|
+
policy: StatusCheckPolicy;
|
|
23
|
+
/** Paths claimed by more than one patch, for the `ownership-conflict` class. */
|
|
24
|
+
ownershipConflicts: readonly string[];
|
|
25
|
+
/** The `--include-ownership` block, when asked for. */
|
|
26
|
+
ownership?: OwnershipJsonBlock | undefined;
|
|
27
|
+
/** The `--patches` scope, when given. */
|
|
28
|
+
scope?: StatusScope | undefined;
|
|
29
|
+
}
|
|
16
30
|
/**
|
|
17
|
-
* Full `--json` payload: summary plus the per-file `files[]` list, and
|
|
18
|
-
*
|
|
19
|
-
* Additive within schemaVersion 1: a consumer that does not ask for
|
|
31
|
+
* Full `--json` payload: summary plus the per-file `files[]` list, and the
|
|
32
|
+
* additive `check`, `scope` and `ownership` blocks when their flags are
|
|
33
|
+
* set. Additive within schemaVersion 1: a consumer that does not ask for a
|
|
20
34
|
* block never sees the key.
|
|
21
35
|
*/
|
|
22
|
-
export declare function renderJsonStatus(classified: readonly ClassifiedFile[],
|
|
36
|
+
export declare function renderJsonStatus(classified: readonly ClassifiedFile[], context: StatusJsonContext): void;
|
|
23
37
|
/**
|
|
24
38
|
* Summary-only `--json --summary` payload. Counts are always present. When
|
|
25
39
|
* the `--check`/`--fail-on` policy is active, the payload adds a `check`
|
|
26
40
|
* block with the active fail set, the verdict, and the offending files per
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* the flag.
|
|
41
|
+
* failing class (sourced from the same collector as the human `--check`
|
|
42
|
+
* message, so the two views can never disagree). The absent `files[]` is
|
|
43
|
+
* the mode signal within schemaVersion 1. Consumers opt in via the flag.
|
|
31
44
|
*/
|
|
32
|
-
export declare function renderJsonSummaryStatus(classified: readonly ClassifiedFile[],
|
|
45
|
+
export declare function renderJsonSummaryStatus(classified: readonly ClassifiedFile[], context: StatusJsonContext): void;
|
|
@@ -16,12 +16,45 @@ function countByClassification(classified) {
|
|
|
16
16
|
return byClassification;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* Builds the `check` block, or undefined when no policy is active.
|
|
20
|
+
* `allow` and `failOnUnknown` appear only when the caller set them, so a
|
|
21
|
+
* consumer that never passes those flags sees the block it always did.
|
|
22
|
+
*/
|
|
23
|
+
function buildCheckBlock(classified, context) {
|
|
24
|
+
const { policy } = context;
|
|
25
|
+
if (!policy.checkEnabled)
|
|
26
|
+
return undefined;
|
|
27
|
+
const offenders = collectStatusCheckOffenders(classified, policy, context.ownershipConflicts);
|
|
28
|
+
return {
|
|
29
|
+
enabled: true,
|
|
30
|
+
failOn: policy.failOn,
|
|
31
|
+
...(policy.allow !== undefined ? { allow: policy.allow } : {}),
|
|
32
|
+
...(policy.failOnUnknown === true ? { failOnUnknown: true } : {}),
|
|
33
|
+
failed: offenders.length > 0,
|
|
34
|
+
offenders,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** The additive tail both payloads share: check, scope, ownership. */
|
|
38
|
+
function buildTrailingBlocks(classified, context) {
|
|
39
|
+
const check = buildCheckBlock(classified, context);
|
|
40
|
+
return {
|
|
41
|
+
...(check !== undefined ? { check } : {}),
|
|
42
|
+
...(context.scope !== undefined ? { scope: context.scope } : {}),
|
|
43
|
+
...(context.ownership !== undefined ? { ownership: context.ownership } : {}),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function writePayload(output) {
|
|
47
|
+
process.stdout.write(JSON.stringify(output, null, 2) + '\n');
|
|
48
|
+
// Payload written: stdout is now spoken for. See docs/machine-output.md.
|
|
49
|
+
setStdoutSealed(true);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Full `--json` payload: summary plus the per-file `files[]` list, and the
|
|
53
|
+
* additive `check`, `scope` and `ownership` blocks when their flags are
|
|
54
|
+
* set. Additive within schemaVersion 1: a consumer that does not ask for a
|
|
22
55
|
* block never sees the key.
|
|
23
56
|
*/
|
|
24
|
-
export function renderJsonStatus(classified,
|
|
57
|
+
export function renderJsonStatus(classified, context) {
|
|
25
58
|
const outputFiles = classified.map((f) => {
|
|
26
59
|
const entry = {
|
|
27
60
|
file: f.file,
|
|
@@ -34,49 +67,31 @@ export function renderJsonStatus(classified, ownership) {
|
|
|
34
67
|
}
|
|
35
68
|
return entry;
|
|
36
69
|
});
|
|
37
|
-
|
|
70
|
+
writePayload({
|
|
38
71
|
schemaVersion: 1,
|
|
39
72
|
summary: {
|
|
40
73
|
total: outputFiles.length,
|
|
41
74
|
byClassification: countByClassification(classified),
|
|
42
75
|
},
|
|
43
76
|
files: outputFiles,
|
|
44
|
-
...(
|
|
45
|
-
};
|
|
46
|
-
process.stdout.write(JSON.stringify(output, null, 2) + '\n');
|
|
47
|
-
// Payload written: stdout is now spoken for. See docs/machine-output.md.
|
|
48
|
-
setStdoutSealed(true);
|
|
77
|
+
...buildTrailingBlocks(classified, context),
|
|
78
|
+
});
|
|
49
79
|
}
|
|
50
80
|
/**
|
|
51
81
|
* Summary-only `--json --summary` payload. Counts are always present. When
|
|
52
82
|
* the `--check`/`--fail-on` policy is active, the payload adds a `check`
|
|
53
83
|
* block with the active fail set, the verdict, and the offending files per
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* the flag.
|
|
84
|
+
* failing class (sourced from the same collector as the human `--check`
|
|
85
|
+
* message, so the two views can never disagree). The absent `files[]` is
|
|
86
|
+
* the mode signal within schemaVersion 1. Consumers opt in via the flag.
|
|
58
87
|
*/
|
|
59
|
-
export function renderJsonSummaryStatus(classified,
|
|
60
|
-
|
|
88
|
+
export function renderJsonSummaryStatus(classified, context) {
|
|
89
|
+
writePayload({
|
|
61
90
|
schemaVersion: 1,
|
|
62
91
|
summary: {
|
|
63
92
|
total: classified.length,
|
|
64
93
|
byClassification: countByClassification(classified),
|
|
65
94
|
},
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const offenders = collectStatusCheckOffenders(classified, policy);
|
|
69
|
-
output.check = {
|
|
70
|
-
enabled: true,
|
|
71
|
-
failOn: policy.failOn,
|
|
72
|
-
failed: offenders.length > 0,
|
|
73
|
-
offenders,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
if (ownership !== undefined) {
|
|
77
|
-
output.ownership = ownership;
|
|
78
|
-
}
|
|
79
|
-
process.stdout.write(JSON.stringify(output, null, 2) + '\n');
|
|
80
|
-
// Payload written: stdout is now spoken for. See docs/machine-output.md.
|
|
81
|
-
setStdoutSealed(true);
|
|
95
|
+
...buildTrailingBlocks(classified, context),
|
|
96
|
+
});
|
|
82
97
|
}
|
|
@@ -220,6 +220,8 @@ export function renderTestCoverageStatus(baseline) {
|
|
|
220
220
|
}
|
|
221
221
|
const list = coverage.map((path) => ` - ${path}`).join('\n');
|
|
222
222
|
info(`Test packaging coverage: scoped to ${coverage.length} path(s):\n${list}\n` +
|
|
223
|
-
|
|
223
|
+
(baseline.fullCoverageAnchor === undefined
|
|
224
|
+
? 'A "fireforge test" over paths outside this list will be refused as uncovered.'
|
|
225
|
+
: 'A "fireforge test" over paths outside this list stays covered by the earlier full build while their own staging inputs are unchanged, and is refused otherwise.'));
|
|
224
226
|
outro(`Coverage: scoped (${coverage.length} paths)`);
|
|
225
227
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `status --patches <list>`: judges only the named patches' files. Split
|
|
3
|
+
* out of status.ts, which sits at the max-lines budget.
|
|
4
|
+
*
|
|
5
|
+
* On a shared engine a peer's unexported work keeps a tree-wide gate red
|
|
6
|
+
* for everyone. The scope keeps a file when the patch that owns it (or,
|
|
7
|
+
* for a conflict, any patch that claims it) is named, and an ownership
|
|
8
|
+
* row when any of its owners is named. An unmanaged file has no owning
|
|
9
|
+
* patch, so no scope covers it: scoped runs never judge unexported files.
|
|
10
|
+
* That is the point of the scope, and also its limit, which the docs say.
|
|
11
|
+
*/
|
|
12
|
+
import type { OwnershipRow } from '../core/ownership-table.js';
|
|
13
|
+
import type { ClassifiedFile, StatusFile } from '../core/status-classify.js';
|
|
14
|
+
/** The resolved `--patches` scope: manifest filenames, in request order. */
|
|
15
|
+
export interface StatusScope {
|
|
16
|
+
patches: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolves raw `--patches` values against the manifest. Returns undefined
|
|
20
|
+
* when the flag was not given, and refuses a name that matches no patch
|
|
21
|
+
* (so a typo fails loud instead of judging nothing).
|
|
22
|
+
*
|
|
23
|
+
* @param patchesDir - Absolute path to the patches directory
|
|
24
|
+
* @param requested - Raw `--patches` values (each may be a comma list)
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveStatusScope(patchesDir: string, requested: readonly string[] | undefined): Promise<StatusScope | undefined>;
|
|
27
|
+
/** Keeps only the classified entries the scope covers. No scope keeps all. */
|
|
28
|
+
export declare function scopeClassified(classified: ClassifiedFile[], scope: StatusScope | undefined): ClassifiedFile[];
|
|
29
|
+
/** Keeps only the ownership rows with an owner in scope. No scope keeps all. */
|
|
30
|
+
export declare function scopeOwnershipRows(rows: OwnershipRow[], scope: StatusScope | undefined): OwnershipRow[];
|
|
31
|
+
/**
|
|
32
|
+
* Builds the ownership rows from the full scan (classification needs every
|
|
33
|
+
* file to find claims), then narrows them to the scope.
|
|
34
|
+
*/
|
|
35
|
+
export declare function collectScopedOwnershipRows(patchesDir: string, files: StatusFile[], classified: readonly ClassifiedFile[], scope: StatusScope | undefined): Promise<OwnershipRow[]>;
|
|
36
|
+
/** The paths the `ownership-conflict` check class judges. */
|
|
37
|
+
export declare function ownershipConflictPaths(rows: readonly OwnershipRow[]): string[];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { loadPatchesManifest } from '../core/patch-manifest.js';
|
|
2
|
+
import { selectPatchSubset } from '../core/patch-subset.js';
|
|
3
|
+
import { GeneralError } from '../errors/base.js';
|
|
4
|
+
import { collectOwnershipRows } from './status-ownership.js';
|
|
5
|
+
/**
|
|
6
|
+
* Resolves raw `--patches` values against the manifest. Returns undefined
|
|
7
|
+
* when the flag was not given, and refuses a name that matches no patch
|
|
8
|
+
* (so a typo fails loud instead of judging nothing).
|
|
9
|
+
*
|
|
10
|
+
* @param patchesDir - Absolute path to the patches directory
|
|
11
|
+
* @param requested - Raw `--patches` values (each may be a comma list)
|
|
12
|
+
*/
|
|
13
|
+
export async function resolveStatusScope(patchesDir, requested) {
|
|
14
|
+
if (requested === undefined || requested.length === 0)
|
|
15
|
+
return undefined;
|
|
16
|
+
const manifest = await loadPatchesManifest(patchesDir);
|
|
17
|
+
if (!manifest || manifest.patches.length === 0) {
|
|
18
|
+
throw new GeneralError('--patches needs a patch queue, but patches.json lists no patches.');
|
|
19
|
+
}
|
|
20
|
+
const subset = selectPatchSubset(manifest, requested, '--patches selects patches (filename, stem, order number, manifest name, or slug), not engine files.');
|
|
21
|
+
return { patches: subset.map((patch) => patch.filename) };
|
|
22
|
+
}
|
|
23
|
+
/** True when the entry's owner, or any patch claiming it, is in scope. */
|
|
24
|
+
function isInScope(entry, names) {
|
|
25
|
+
if (entry.owner !== undefined && names.has(entry.owner))
|
|
26
|
+
return true;
|
|
27
|
+
return entry.claimedBy?.some((patch) => names.has(patch)) === true;
|
|
28
|
+
}
|
|
29
|
+
/** Keeps only the classified entries the scope covers. No scope keeps all. */
|
|
30
|
+
export function scopeClassified(classified, scope) {
|
|
31
|
+
if (scope === undefined)
|
|
32
|
+
return classified;
|
|
33
|
+
const names = new Set(scope.patches);
|
|
34
|
+
return classified.filter((entry) => isInScope(entry, names));
|
|
35
|
+
}
|
|
36
|
+
/** Keeps only the ownership rows with an owner in scope. No scope keeps all. */
|
|
37
|
+
export function scopeOwnershipRows(rows, scope) {
|
|
38
|
+
if (scope === undefined)
|
|
39
|
+
return rows;
|
|
40
|
+
const names = new Set(scope.patches);
|
|
41
|
+
return rows.filter((row) => row.owners.some((owner) => names.has(owner)));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Builds the ownership rows from the full scan (classification needs every
|
|
45
|
+
* file to find claims), then narrows them to the scope.
|
|
46
|
+
*/
|
|
47
|
+
export async function collectScopedOwnershipRows(patchesDir, files, classified, scope) {
|
|
48
|
+
const rows = await collectOwnershipRows(patchesDir, (await loadPatchesManifest(patchesDir))?.patches ?? [], files, classified);
|
|
49
|
+
return scopeOwnershipRows(rows, scope);
|
|
50
|
+
}
|
|
51
|
+
/** The paths the `ownership-conflict` check class judges. */
|
|
52
|
+
export function ownershipConflictPaths(rows) {
|
|
53
|
+
return rows.filter((row) => row.conflict).map((row) => row.path);
|
|
54
|
+
}
|
|
@@ -8,17 +8,17 @@ import { collectFurnaceManagedPrefixes } from '../core/furnace-config.js';
|
|
|
8
8
|
import { getHead, getStatusWithCodes, isGitRepository, isMissingHeadError } from '../core/git.js';
|
|
9
9
|
import { listUntrackedFilesInDirs, resolveMaxUntrackedFilesPerDir } from '../core/git-status.js';
|
|
10
10
|
import { renderOwnershipTable } from '../core/ownership-table.js';
|
|
11
|
-
import { loadPatchesManifest } from '../core/patch-manifest.js';
|
|
12
11
|
import { readProcessCpuSeconds } from '../core/process-cpu-time.js';
|
|
13
12
|
import { classifyFiles } from '../core/status-classify.js';
|
|
14
13
|
import { GeneralError, InvalidArgumentError } from '../errors/base.js';
|
|
15
14
|
import { FIREFORGE_TMP_PATH_PATTERN, pathExists } from '../utils/fs.js';
|
|
16
15
|
import { info, intro, isMachineOutputMode, outro, setMachineOutputMode, warn, } from '../utils/logger.js';
|
|
17
16
|
import { emitMachineError } from '../utils/machine-output.js';
|
|
18
|
-
import { resolveStatusCheckPolicy, runStatusCheck, } from './status-check.js';
|
|
17
|
+
import { policyNeedsOwnership, resolveStatusCheckPolicy, runStatusCheck, } from './status-check.js';
|
|
19
18
|
import { renderJsonStatus, renderJsonSummaryStatus } from './status-json.js';
|
|
20
19
|
import { renderDefaultStatus, renderTestCoverageStatus, renderUnmanagedOnly, } from './status-output.js';
|
|
21
|
-
import { buildOwnershipJsonBlock,
|
|
20
|
+
import { buildOwnershipJsonBlock, summarizeOwnership } from './status-ownership.js';
|
|
21
|
+
import { collectScopedOwnershipRows, ownershipConflictPaths, resolveStatusScope, scopeClassified, } from './status-scope.js';
|
|
22
22
|
/**
|
|
23
23
|
* Renders raw worktree status as machine-parseable porcelain-style output.
|
|
24
24
|
* Each line is: STATUS<tab>FILE
|
|
@@ -121,26 +121,47 @@ async function scanEngineStatusFiles(engineDir, requireGitRepository) {
|
|
|
121
121
|
* policy, which stays the only exit driver on this path.
|
|
122
122
|
*
|
|
123
123
|
* `--include-ownership` is a modifier rather than a mode: it appends an
|
|
124
|
-
* ownership block without touching exit semantics
|
|
125
|
-
*
|
|
124
|
+
* ownership block without touching exit semantics. Ownership conflicts
|
|
125
|
+
* fail this path only when the policy names `ownership-conflict` (or
|
|
126
|
+
* leaves it unnamed under `--fail-on-unknown`).
|
|
126
127
|
*
|
|
127
|
-
* @param classified - Classified worktree entries
|
|
128
|
+
* @param classified - Classified worktree entries, unscoped
|
|
128
129
|
* @param files - The same entries pre-classification, for ownership rows
|
|
129
130
|
* @param paths - Resolved project paths
|
|
130
131
|
* @param options - Status display options
|
|
131
132
|
* @param checkPolicy - Resolved `--check`/`--fail-on` policy
|
|
133
|
+
* @param scope - The `--patches` scope, when given
|
|
132
134
|
*/
|
|
133
|
-
async function renderJsonMode(classified, files, paths, options, checkPolicy) {
|
|
134
|
-
const
|
|
135
|
-
?
|
|
136
|
-
:
|
|
135
|
+
async function renderJsonMode(classified, files, paths, options, checkPolicy, scope) {
|
|
136
|
+
const rows = options.includeOwnership === true || policyNeedsOwnership(checkPolicy)
|
|
137
|
+
? await collectScopedOwnershipRows(paths.patches, files, classified, scope)
|
|
138
|
+
: [];
|
|
139
|
+
const context = {
|
|
140
|
+
policy: checkPolicy,
|
|
141
|
+
ownershipConflicts: ownershipConflictPaths(rows),
|
|
142
|
+
ownership: options.includeOwnership === true ? buildOwnershipJsonBlock(rows) : undefined,
|
|
143
|
+
scope,
|
|
144
|
+
};
|
|
145
|
+
const scoped = scopeClassified(classified, scope);
|
|
137
146
|
if (options.summary === true) {
|
|
138
|
-
renderJsonSummaryStatus(
|
|
147
|
+
renderJsonSummaryStatus(scoped, context);
|
|
139
148
|
}
|
|
140
149
|
else {
|
|
141
|
-
renderJsonStatus(
|
|
150
|
+
renderJsonStatus(scoped, context);
|
|
142
151
|
}
|
|
143
|
-
runStatusCheck(
|
|
152
|
+
runStatusCheck(scoped, checkPolicy, context.ownershipConflicts);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Applies the `--check` policy to the human default view. Builds the
|
|
156
|
+
* ownership rows only when the policy can fail on `ownership-conflict`,
|
|
157
|
+
* which it can on a clean tree too (two patches claiming one path need no
|
|
158
|
+
* worktree change).
|
|
159
|
+
*/
|
|
160
|
+
async function runHumanStatusCheck(classified, files, paths, checkPolicy, scope) {
|
|
161
|
+
const conflicts = policyNeedsOwnership(checkPolicy)
|
|
162
|
+
? ownershipConflictPaths(await collectScopedOwnershipRows(paths.patches, files, classified, scope))
|
|
163
|
+
: [];
|
|
164
|
+
runStatusCheck(scopeClassified(classified, scope), checkPolicy, conflicts);
|
|
144
165
|
}
|
|
145
166
|
/**
|
|
146
167
|
* Detects the "unborn HEAD" aftermath of an interrupted `fireforge download`:
|
|
@@ -200,8 +221,12 @@ export async function statusCommand(projectRoot, options = {}) {
|
|
|
200
221
|
setMachineOutputMode(previousMachineOutputMode);
|
|
201
222
|
}
|
|
202
223
|
}
|
|
203
|
-
/**
|
|
204
|
-
|
|
224
|
+
/**
|
|
225
|
+
* Refuses flag combinations no view can honour, before any output: one
|
|
226
|
+
* mode at most, and the JSON-only and scope modifiers only where they mean
|
|
227
|
+
* something.
|
|
228
|
+
*/
|
|
229
|
+
function assertStatusFlagCombination(options) {
|
|
205
230
|
const modeCount = [
|
|
206
231
|
options.raw,
|
|
207
232
|
options.unmanaged,
|
|
@@ -224,6 +249,18 @@ async function runStatusCommandBody(projectRoot, options) {
|
|
|
224
249
|
if (options.includeOwnership === true && options.json !== true) {
|
|
225
250
|
throw new InvalidArgumentError('--include-ownership requires --json. Use --ownership for the human table.', '--include-ownership');
|
|
226
251
|
}
|
|
252
|
+
// --patches scopes the classifying views and the ownership table only.
|
|
253
|
+
if (options.patches !== undefined &&
|
|
254
|
+
(options.raw === true ||
|
|
255
|
+
options.unmanaged === true ||
|
|
256
|
+
options.testCoverage === true ||
|
|
257
|
+
options.lock === true)) {
|
|
258
|
+
throw new InvalidArgumentError('--patches cannot be combined with --raw, --unmanaged, --test-coverage, or --lock.', '--patches');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/** The status body proper. The machine-mode lifecycle lives in {@link statusCommand}. */
|
|
262
|
+
async function runStatusCommandBody(projectRoot, options) {
|
|
263
|
+
assertStatusFlagCombination(options);
|
|
227
264
|
// --check / --fail-on enforcement policy. Applies only
|
|
228
265
|
// where classification runs (the default view and --json).
|
|
229
266
|
const checkPolicy = resolveStatusCheckPolicy(options);
|
|
@@ -253,6 +290,7 @@ async function runStatusCommandBody(projectRoot, options) {
|
|
|
253
290
|
}
|
|
254
291
|
const paths = getProjectPaths(projectRoot);
|
|
255
292
|
const config = await loadConfig(projectRoot);
|
|
293
|
+
const scope = await resolveStatusScope(paths.patches, options.patches);
|
|
256
294
|
// Shared envelope: see src/utils/machine-output.ts and
|
|
257
295
|
// docs/machine-output.md. `status` was the only command that had one.
|
|
258
296
|
// Ownership mode is a flat file→patch table. Sources are the manifest's
|
|
@@ -265,13 +303,12 @@ async function runStatusCommandBody(projectRoot, options) {
|
|
|
265
303
|
// Rung 1 only. See the note below on why this branch does not take the
|
|
266
304
|
// full assertEngineGitReady ladder.
|
|
267
305
|
await assertEngineExists(paths.engine);
|
|
268
|
-
const manifest = await loadPatchesManifest(paths.patches);
|
|
269
306
|
// The same scan and the same classification pass as every other mode.
|
|
270
307
|
// This branch keeps its historical guard shape on purpose:
|
|
271
308
|
// no baseline-commit assertion, and a non-git engine degrades to an
|
|
272
309
|
// empty table rather than the recovery banner.
|
|
273
310
|
const rawFilesOwnership = await scanEngineStatusFiles(paths.engine, false);
|
|
274
|
-
const rows = await
|
|
311
|
+
const rows = await collectScopedOwnershipRows(paths.patches, rawFilesOwnership, await classifyStatusFiles(rawFilesOwnership, paths, projectRoot, config.binaryName), scope);
|
|
275
312
|
renderOwnershipTable(rows);
|
|
276
313
|
const { managed, unmanaged, conflicts } = summarizeOwnership(rows);
|
|
277
314
|
const parts = [`${managed} managed`];
|
|
@@ -313,7 +350,7 @@ async function runStatusCommandBody(projectRoot, options) {
|
|
|
313
350
|
// `[]` here and return before the human fallback.
|
|
314
351
|
if (options.json) {
|
|
315
352
|
const classified = await classifyStatusFiles(files, paths, projectRoot, config.binaryName);
|
|
316
|
-
await renderJsonMode(classified, files, paths, options, checkPolicy);
|
|
353
|
+
await renderJsonMode(classified, files, paths, options, checkPolicy, scope);
|
|
317
354
|
return;
|
|
318
355
|
}
|
|
319
356
|
// `--raw` consumers parse the native `git status --porcelain` output
|
|
@@ -326,6 +363,7 @@ async function runStatusCommandBody(projectRoot, options) {
|
|
|
326
363
|
if (files.length === 0) {
|
|
327
364
|
info('No modified files');
|
|
328
365
|
outro('Working tree clean');
|
|
366
|
+
await runHumanStatusCheck([], files, paths, checkPolicy, scope);
|
|
329
367
|
return;
|
|
330
368
|
}
|
|
331
369
|
// Raw mode: existing behavior
|
|
@@ -333,8 +371,10 @@ async function runStatusCommandBody(projectRoot, options) {
|
|
|
333
371
|
renderRawStatus(files);
|
|
334
372
|
return;
|
|
335
373
|
}
|
|
336
|
-
// Patch-aware classification
|
|
337
|
-
|
|
374
|
+
// Patch-aware classification. The full scan is classified (claims need
|
|
375
|
+
// every file) and the buckets show only what the scope covers.
|
|
376
|
+
const allClassified = await classifyStatusFiles(files, paths, projectRoot, config.binaryName);
|
|
377
|
+
const classified = scopeClassified(allClassified, scope);
|
|
338
378
|
const buckets = {
|
|
339
379
|
conflict: classified.filter((f) => f.classification === 'conflict'),
|
|
340
380
|
unmanaged: classified.filter((f) => f.classification === 'unmanaged'),
|
|
@@ -349,8 +389,8 @@ async function runStatusCommandBody(projectRoot, options) {
|
|
|
349
389
|
await renderUnmanagedOnly(buckets.unmanaged, files.length, projectRoot, config.binaryName);
|
|
350
390
|
return;
|
|
351
391
|
}
|
|
352
|
-
await renderDefaultStatus(files.length, buckets, projectRoot, config.binaryName);
|
|
353
|
-
|
|
392
|
+
await renderDefaultStatus(scope ? classified.length : files.length, buckets, projectRoot, config.binaryName);
|
|
393
|
+
await runHumanStatusCheck(allClassified, files, paths, checkPolicy, scope);
|
|
354
394
|
}
|
|
355
395
|
/** Registers the status command on the CLI program. */
|
|
356
396
|
export function registerStatus(program, { getProjectRoot, withErrorHandling }) {
|
|
@@ -366,7 +406,10 @@ export function registerStatus(program, { getProjectRoot, withErrorHandling }) {
|
|
|
366
406
|
.option('--summary', 'With --json: emit only summary counts (plus offending files when --check/--fail-on is active), omitting the per-file files[] payload')
|
|
367
407
|
.option('--include-ownership', 'With --json (composes with --summary): append an ownership block (path->owning-patch rows plus managed/unmanaged/conflict counts) to the payload, so one scan serves the classification, ownership, and check views. Does not change exit semantics.')
|
|
368
408
|
.option('--check', 'Exit non-zero when any unmanaged, patch-owned-drift, or conflict file exists (composes with --json; combine with --fail-on for finer policy)')
|
|
369
|
-
.option('--fail-on <classifications>', 'Comma-separated classification list that fails --check, replacing the default set (implies --check). Valid: patch-backed, patch-owned-drift, unmanaged, branding, furnace, conflict, binary-unsupported')
|
|
409
|
+
.option('--fail-on <classifications>', 'Comma-separated classification list that fails --check, replacing the default set (implies --check). Valid: patch-backed, patch-owned-drift, unmanaged, branding, furnace, conflict, binary-unsupported, ownership-conflict (a path claimed by more than one patch)')
|
|
410
|
+
.option('--allow <classifications>', 'Comma-separated classification list that never fails --check, removed from the fail set (implies --check; same values as --fail-on)')
|
|
411
|
+
.option('--fail-on-unknown', 'With --allow: also fail on every present classification that neither --fail-on nor --allow names, so a classification added in a later FireForge fails closed (implies --check)')
|
|
412
|
+
.option('--patches <names...>', 'Judge only the named patches: keeps the files each owns or claims and the ownership rows naming it (filename, stem, order number, manifest name, or slug; repeat or comma-separate). Unmanaged files belong to no patch and drop out. Default view, --json and --ownership only')
|
|
370
413
|
.action(withErrorHandling(async (options) => {
|
|
371
414
|
await statusCommand(getProjectRoot(), options);
|
|
372
415
|
}));
|