@hominis/fireforge 0.44.4 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +120 -0
- package/dist/bin/fireforge.js +6 -0
- package/dist/build-info.json +4 -4
- package/dist/src/cli-usage-error.d.ts +46 -0
- package/dist/src/cli-usage-error.js +81 -0
- package/dist/src/cli.d.ts +5 -1
- package/dist/src/cli.js +20 -21
- package/dist/src/commands/bootstrap.js +1 -2
- package/dist/src/commands/build.js +15 -6
- package/dist/src/commands/destructive-decision.d.ts +19 -0
- package/dist/src/commands/destructive-decision.js +31 -0
- package/dist/src/commands/doctor-check-core.d.ts +0 -6
- package/dist/src/commands/doctor-check-core.js +0 -8
- package/dist/src/commands/doctor-orphaned-harness.d.ts +0 -6
- package/dist/src/commands/doctor-orphaned-harness.js +4 -12
- package/dist/src/commands/doctor-post-rebase-audit.js +1 -1
- package/dist/src/commands/doctor-source-pin.d.ts +29 -0
- package/dist/src/commands/doctor-source-pin.js +81 -0
- package/dist/src/commands/doctor.d.ts +2 -0
- package/dist/src/commands/doctor.js +9 -8
- package/dist/src/commands/download.js +35 -24
- package/dist/src/commands/export-all.js +21 -4
- package/dist/src/commands/export-flow.js +15 -60
- package/dist/src/commands/export-placement-conflicts.js +3 -3
- package/dist/src/commands/export-placement-gate.js +2 -8
- package/dist/src/commands/export-placement-policy.js +3 -5
- package/dist/src/commands/export-shared.d.ts +42 -23
- package/dist/src/commands/export-shared.js +4 -19
- package/dist/src/commands/export.js +10 -1
- package/dist/src/commands/furnace/authoring-config.d.ts +13 -0
- package/dist/src/commands/furnace/authoring-config.js +19 -0
- package/dist/src/commands/furnace/chrome-doc-remove.js +1 -1
- package/dist/src/commands/furnace/create-browser-test.js +3 -8
- package/dist/src/commands/furnace/create-dry-run.js +2 -5
- package/dist/src/commands/furnace/create-templates.d.ts +17 -1
- package/dist/src/commands/furnace/create-templates.js +2 -1
- package/dist/src/commands/furnace/create.js +25 -19
- package/dist/src/commands/furnace/deploy.js +11 -2
- package/dist/src/commands/furnace/init.js +2 -1
- package/dist/src/commands/furnace/override.js +28 -19
- package/dist/src/commands/furnace/refresh.js +9 -1
- package/dist/src/commands/furnace/remove-mutations.d.ts +6 -7
- package/dist/src/commands/furnace/remove-mutations.js +0 -1
- package/dist/src/commands/furnace/remove.js +2 -6
- package/dist/src/commands/furnace/rename-browser-test.js +1 -7
- package/dist/src/commands/furnace/rename.js +29 -29
- package/dist/src/commands/furnace/status.js +12 -9
- package/dist/src/commands/furnace/test-file-name.d.ts +28 -0
- package/dist/src/commands/furnace/test-file-name.js +39 -0
- package/dist/src/commands/furnace/validation-output.d.ts +21 -9
- package/dist/src/commands/furnace/validation-output.js +3 -8
- package/dist/src/commands/import.js +2 -9
- package/dist/src/commands/lint-per-patch.d.ts +2 -2
- package/dist/src/commands/lint-per-patch.js +19 -4
- package/dist/src/commands/lint-per-run-checkjs.d.ts +2 -2
- package/dist/src/commands/lint.d.ts +2 -1
- package/dist/src/commands/lint.js +1 -1
- package/dist/src/commands/manifest.js +1 -1
- package/dist/src/commands/package.js +2 -4
- package/dist/src/commands/patch/compact.js +14 -15
- package/dist/src/commands/patch/delete.js +15 -25
- package/dist/src/commands/patch/entry-projection.d.ts +13 -0
- package/dist/src/commands/patch/entry-projection.js +24 -0
- package/dist/src/commands/patch/lint-ignore.d.ts +0 -8
- package/dist/src/commands/patch/lint-ignore.js +19 -29
- package/dist/src/commands/patch/move-files-create.js +24 -10
- package/dist/src/commands/patch/move-files-into.js +38 -37
- package/dist/src/commands/patch/move-files.js +4 -13
- package/dist/src/commands/patch/rename.js +27 -41
- package/dist/src/commands/patch/reorder.js +25 -38
- package/dist/src/commands/patch/split-plan.d.ts +4 -5
- package/dist/src/commands/patch/split-plan.js +4 -11
- package/dist/src/commands/patch/split.js +45 -43
- package/dist/src/commands/patch/staged-dependency.js +16 -22
- package/dist/src/commands/patch/tier.js +15 -25
- package/dist/src/commands/patch-rename-map.d.ts +19 -0
- package/dist/src/commands/patch-rename-map.js +36 -0
- package/dist/src/commands/pending-resolution.d.ts +15 -0
- package/dist/src/commands/pending-resolution.js +25 -0
- package/dist/src/commands/re-export-adjacent.d.ts +32 -2
- package/dist/src/commands/re-export-adjacent.js +51 -10
- package/dist/src/commands/re-export-bulk-scan.js +6 -10
- package/dist/src/commands/re-export-drift.d.ts +8 -0
- package/dist/src/commands/re-export-drift.js +65 -4
- package/dist/src/commands/re-export-files.d.ts +2 -3
- package/dist/src/commands/re-export-files.js +38 -32
- package/dist/src/commands/re-export-lint.d.ts +3 -4
- package/dist/src/commands/re-export-lint.js +9 -2
- package/dist/src/commands/re-export-options.js +19 -5
- package/dist/src/commands/re-export-register.js +5 -1
- package/dist/src/commands/re-export-scan.js +8 -8
- package/dist/src/commands/re-export-single.d.ts +22 -3
- package/dist/src/commands/re-export-single.js +19 -11
- package/dist/src/commands/re-export.js +44 -27
- package/dist/src/commands/rebase/abort.js +3 -8
- package/dist/src/commands/rebase/continue.js +12 -12
- package/dist/src/commands/rebase/index.js +2 -2
- package/dist/src/commands/rebase/patch-loop.d.ts +2 -2
- package/dist/src/commands/rebase/patch-loop.js +2 -7
- package/dist/src/commands/resolve.js +18 -10
- package/dist/src/commands/run.d.ts +0 -13
- package/dist/src/commands/run.js +12 -25
- package/dist/src/commands/setup-support.d.ts +16 -4
- package/dist/src/commands/setup-support.js +16 -16
- package/dist/src/commands/setup.js +3 -9
- package/dist/src/commands/source.js +8 -1
- package/dist/src/commands/status-check.js +2 -2
- package/dist/src/commands/status-output.js +2 -2
- package/dist/src/commands/status.js +3 -4
- package/dist/src/commands/test-build-phase.d.ts +2 -2
- package/dist/src/commands/test-build-phase.js +33 -8
- package/dist/src/commands/test-diagnose.js +14 -5
- package/dist/src/commands/test-modes.d.ts +2 -2
- package/dist/src/commands/test-modes.js +0 -1
- package/dist/src/commands/test-register.js +6 -3
- package/dist/src/commands/test-run.js +29 -21
- package/dist/src/commands/test-stale-gate.js +8 -5
- package/dist/src/commands/test-verdict.d.ts +16 -2
- package/dist/src/commands/test-verdict.js +18 -3
- package/dist/src/commands/test.js +51 -7
- package/dist/src/commands/token-list.d.ts +26 -0
- package/dist/src/commands/token-list.js +153 -0
- package/dist/src/commands/token.js +17 -1
- package/dist/src/commands/tree.js +7 -2
- package/dist/src/commands/typecheck.js +9 -9
- package/dist/src/commands/wire.js +4 -3
- package/dist/src/core/branding.d.ts +0 -7
- package/dist/src/core/branding.js +3 -2
- package/dist/src/core/browser-wire.js +6 -3
- package/dist/src/core/build-audit-platform.d.ts +29 -0
- package/dist/src/core/build-audit-platform.js +140 -0
- package/dist/src/core/build-audit-registration.js +3 -2
- package/dist/src/core/build-audit-skip.d.ts +57 -0
- package/dist/src/core/build-audit-skip.js +112 -0
- package/dist/src/core/build-audit.d.ts +15 -2
- package/dist/src/core/build-audit.js +154 -12
- package/dist/src/core/build-baseline.d.ts +45 -28
- package/dist/src/core/build-baseline.js +6 -29
- package/dist/src/core/build-jar-escalation.d.ts +64 -0
- package/dist/src/core/build-jar-escalation.js +128 -0
- package/dist/src/core/build-overwrite-guard.js +1 -1
- package/dist/src/core/build-prepare.d.ts +5 -2
- package/dist/src/core/build-prepare.js +34 -6
- package/dist/src/core/config-paths.d.ts +2 -6
- package/dist/src/core/config-paths.js +4 -2
- package/dist/src/core/config-state.d.ts +0 -6
- package/dist/src/core/config-state.js +1 -19
- package/dist/src/core/config-validate-build-audit.d.ts +8 -0
- package/dist/src/core/config-validate-build-audit.js +80 -0
- package/dist/src/core/config-validate-file-size.d.ts +12 -0
- package/dist/src/core/config-validate-file-size.js +65 -0
- package/dist/src/core/config-validate-patch-policy.d.ts +2 -2
- package/dist/src/core/config-validate-patch-policy.js +3 -3
- package/dist/src/core/config-validate-test-toolchains.d.ts +2 -2
- package/dist/src/core/config-validate-test-toolchains.js +4 -5
- package/dist/src/core/config-validate.js +20 -3
- package/dist/src/core/config.d.ts +2 -2
- package/dist/src/core/config.js +11 -15
- package/dist/src/core/coverage-extend.js +4 -4
- package/dist/src/core/discard-baseline.js +7 -7
- package/dist/src/core/engine-precondition.d.ts +1 -9
- package/dist/src/core/engine-precondition.js +3 -8
- package/dist/src/core/engine-session-lock.js +13 -17
- package/dist/src/core/export-moved-code-shape.js +2 -2
- package/dist/src/core/file-lock-owner.d.ts +103 -0
- package/dist/src/core/file-lock-owner.js +259 -0
- package/dist/src/core/file-lock.d.ts +2 -7
- package/dist/src/core/file-lock.js +40 -91
- package/dist/src/core/firefox-cache.d.ts +13 -1
- package/dist/src/core/firefox-cache.js +59 -34
- package/dist/src/core/firefox-download.d.ts +15 -0
- package/dist/src/core/firefox-download.js +37 -21
- package/dist/src/core/firefox-extract.d.ts +6 -5
- package/dist/src/core/firefox-extract.js +36 -18
- package/dist/src/core/firefox.d.ts +30 -32
- package/dist/src/core/firefox.js +5 -36
- package/dist/src/core/furnace-apply-dry-run.d.ts +1 -6
- package/dist/src/core/furnace-apply-dry-run.js +1 -7
- package/dist/src/core/furnace-apply-helpers.d.ts +0 -11
- package/dist/src/core/furnace-apply-helpers.js +8 -19
- package/dist/src/core/furnace-apply-overwrite-warn.js +4 -2
- package/dist/src/core/furnace-apply.d.ts +1 -1
- package/dist/src/core/furnace-apply.js +30 -10
- package/dist/src/core/furnace-config.d.ts +1 -1
- package/dist/src/core/furnace-config.js +23 -36
- package/dist/src/core/furnace-constants.js +3 -2
- package/dist/src/core/furnace-dir-entry.d.ts +20 -0
- package/dist/src/core/furnace-dir-entry.js +21 -0
- package/dist/src/core/furnace-operation.d.ts +2 -0
- package/dist/src/core/furnace-operation.js +3 -1
- package/dist/src/core/furnace-refresh.d.ts +18 -6
- package/dist/src/core/furnace-refresh.js +3 -6
- package/dist/src/core/furnace-registration-ast.d.ts +0 -1
- package/dist/src/core/furnace-registration-ast.js +0 -3
- package/dist/src/core/furnace-registration.d.ts +2 -1
- package/dist/src/core/furnace-registration.js +22 -29
- package/dist/src/core/furnace-scanner.js +3 -6
- package/dist/src/core/furnace-state-persist.d.ts +2 -2
- package/dist/src/core/furnace-validate-registration.js +5 -7
- package/dist/src/core/git-base.d.ts +3 -1
- package/dist/src/core/git-base.js +25 -3
- package/dist/src/core/git-diff-new-file.d.ts +40 -0
- package/dist/src/core/git-diff-new-file.js +119 -0
- package/dist/src/core/git-diff.d.ts +9 -9
- package/dist/src/core/git-diff.js +88 -157
- package/dist/src/core/git-file-ops.d.ts +0 -7
- package/dist/src/core/git-file-ops.js +4 -28
- package/dist/src/core/git-readonly-index.d.ts +0 -2
- package/dist/src/core/git-readonly-index.js +0 -4
- package/dist/src/core/git-status.d.ts +7 -0
- package/dist/src/core/git-status.js +21 -9
- package/dist/src/core/git.d.ts +0 -6
- package/dist/src/core/git.js +14 -43
- package/dist/src/core/harness-orphans.d.ts +73 -0
- package/dist/src/core/harness-orphans.js +187 -0
- package/dist/src/core/history-log.d.ts +19 -0
- package/dist/src/core/history-log.js +29 -0
- package/dist/src/core/mach-error-hints.d.ts +0 -5
- package/dist/src/core/mach-error-hints.js +1 -1
- package/dist/src/core/mach-known-noise-filter.d.ts +25 -3
- package/dist/src/core/mach-known-noise-filter.js +31 -10
- package/dist/src/core/mach-mozconfig.js +2 -1
- package/dist/src/core/mach-python.d.ts +2 -0
- package/dist/src/core/mach-python.js +12 -7
- package/dist/src/core/mach-resource-shim.d.ts +13 -1
- package/dist/src/core/mach-resource-shim.js +112 -9
- package/dist/src/core/mach.d.ts +46 -53
- package/dist/src/core/mach.js +31 -83
- package/dist/src/core/marionette-port.d.ts +0 -17
- package/dist/src/core/marionette-port.js +12 -58
- package/dist/src/core/marionette-preflight.js +9 -27
- package/dist/src/core/mochitest-server-port.js +3 -3
- package/dist/src/core/moz-manifest-rules.js +37 -33
- package/dist/src/core/patch-apply-fuzz.js +4 -4
- package/dist/src/core/patch-apply.d.ts +4 -5
- package/dist/src/core/patch-apply.js +55 -32
- package/dist/src/core/patch-export-coverage.d.ts +0 -9
- package/dist/src/core/patch-export-coverage.js +1 -30
- package/dist/src/core/patch-export-update.d.ts +18 -1
- package/dist/src/core/patch-export-update.js +4 -3
- package/dist/src/core/patch-export.d.ts +11 -21
- package/dist/src/core/patch-export.js +44 -66
- package/dist/src/core/patch-files.d.ts +0 -4
- package/dist/src/core/patch-files.js +0 -11
- package/dist/src/core/patch-lint-binary.d.ts +6 -12
- package/dist/src/core/patch-lint-cache.d.ts +17 -1
- package/dist/src/core/patch-lint-cache.js +3 -6
- package/dist/src/core/patch-lint-checkjs.d.ts +33 -16
- package/dist/src/core/patch-lint-checkjs.js +43 -25
- package/dist/src/core/patch-lint-creators.d.ts +2 -6
- package/dist/src/core/patch-lint-cross.d.ts +16 -8
- package/dist/src/core/patch-lint-cross.js +49 -92
- package/dist/src/core/patch-lint-css.js +10 -6
- package/dist/src/core/patch-lint-file-size.d.ts +52 -0
- package/dist/src/core/patch-lint-file-size.js +53 -0
- package/dist/src/core/patch-lint-forward-registration.d.ts +58 -0
- package/dist/src/core/patch-lint-forward-registration.js +210 -0
- package/dist/src/core/patch-lint-jsdoc.js +36 -36
- package/dist/src/core/patch-lint-module-registration.d.ts +2 -8
- package/dist/src/core/patch-lint-prettier.d.ts +36 -0
- package/dist/src/core/patch-lint-prettier.js +126 -0
- package/dist/src/core/patch-lint-queue-types.d.ts +60 -0
- package/dist/src/core/patch-lint-queue-types.js +12 -0
- package/dist/src/core/patch-lint-staged-registration.d.ts +61 -0
- package/dist/src/core/patch-lint-staged-registration.js +90 -0
- package/dist/src/core/patch-lint-unmanaged-companion.d.ts +106 -0
- package/dist/src/core/patch-lint-unmanaged-companion.js +214 -0
- package/dist/src/core/patch-lint.d.ts +14 -9
- package/dist/src/core/patch-lint.js +27 -27
- package/dist/src/core/patch-lock.js +3 -3
- package/dist/src/core/patch-manifest-io.js +8 -7
- package/dist/src/core/patch-parse.d.ts +19 -8
- package/dist/src/core/patch-parse.js +25 -0
- package/dist/src/core/patch-policy.js +15 -27
- package/dist/src/core/patch-source-metadata.d.ts +1 -3
- package/dist/src/core/patch-source-metadata.js +0 -4
- package/dist/src/core/patch-transform.d.ts +21 -8
- package/dist/src/core/patch-transform.js +38 -10
- package/dist/src/core/process-cpu-time.js +1 -1
- package/dist/src/core/rebase-session.d.ts +2 -8
- package/dist/src/core/rebase-session.js +5 -17
- package/dist/src/core/register-browser-content.js +3 -2
- package/dist/src/core/register-browser-test.js +2 -1
- package/dist/src/core/register-module.js +2 -1
- package/dist/src/core/register-scaffold.js +5 -4
- package/dist/src/core/register-shared-css.js +2 -1
- package/dist/src/core/run-log-redact.d.ts +38 -0
- package/dist/src/core/run-log-redact.js +69 -0
- package/dist/src/core/run-log.d.ts +13 -2
- package/dist/src/core/run-log.js +67 -18
- package/dist/src/core/signal-critical.js +2 -4
- package/dist/src/core/smoke-patterns.d.ts +0 -1
- package/dist/src/core/smoke-patterns.js +18 -11
- package/dist/src/core/state-file.d.ts +12 -1
- package/dist/src/core/state-file.js +14 -1
- package/dist/src/core/status-classify.js +2 -1
- package/dist/src/core/test-changed-prefs.js +26 -11
- package/dist/src/core/test-harness-crash.js +61 -48
- package/dist/src/core/test-harness-verdict-notes.d.ts +55 -0
- package/dist/src/core/test-harness-verdict-notes.js +48 -0
- package/dist/src/core/test-stale-check.d.ts +23 -8
- package/dist/src/core/test-stale-check.js +77 -4
- package/dist/src/core/test-stall-triage.js +37 -19
- package/dist/src/core/test-xpcshell-retry.d.ts +26 -7
- package/dist/src/core/test-xpcshell-retry.js +14 -11
- package/dist/src/core/token-category.d.ts +33 -0
- package/dist/src/core/token-category.js +56 -48
- package/dist/src/core/token-dark-mode.js +2 -14
- package/dist/src/core/token-inventory.d.ts +56 -0
- package/dist/src/core/token-inventory.js +109 -0
- package/dist/src/core/token-manager.d.ts +1 -1
- package/dist/src/core/token-manager.js +1 -1
- package/dist/src/core/token-variant.js +21 -22
- package/dist/src/core/toolchain-preflight.js +1 -1
- package/dist/src/core/tree-cow.d.ts +0 -2
- package/dist/src/core/tree-cow.js +2 -2
- package/dist/src/core/tree-store.js +4 -5
- package/dist/src/core/typecheck.js +2 -2
- package/dist/src/core/wire-dom-fragment.js +6 -17
- package/dist/src/core/wire-utils.js +5 -17
- package/dist/src/core/xpcshell-appdir.js +2 -4
- package/dist/src/errors/base.d.ts +53 -1
- package/dist/src/errors/base.js +79 -11
- package/dist/src/errors/build.d.ts +28 -0
- package/dist/src/errors/build.js +51 -10
- package/dist/src/errors/config.d.ts +0 -14
- package/dist/src/errors/config.js +13 -34
- package/dist/src/errors/download.d.ts +13 -0
- package/dist/src/errors/download.js +53 -24
- package/dist/src/errors/furnace.js +8 -9
- package/dist/src/errors/git.d.ts +8 -8
- package/dist/src/errors/git.js +20 -30
- package/dist/src/errors/patch.js +8 -10
- package/dist/src/errors/rebase.js +7 -7
- package/dist/src/types/commands/options.d.ts +96 -123
- package/dist/src/types/commands/patches.d.ts +17 -6
- package/dist/src/types/config.d.ts +75 -2
- package/dist/src/types/index.d.ts +0 -1
- package/dist/src/utils/assert.d.ts +3 -15
- package/dist/src/utils/assert.js +1 -18
- package/dist/src/utils/build-info.d.ts +1 -1
- package/dist/src/utils/child-env.d.ts +2 -1
- package/dist/src/utils/elapsed.js +10 -1
- package/dist/src/utils/fs.d.ts +4 -2
- package/dist/src/utils/fs.js +11 -14
- package/dist/src/utils/hash.d.ts +12 -0
- package/dist/src/utils/hash.js +16 -0
- package/dist/src/utils/line-dispatch.d.ts +15 -0
- package/dist/src/utils/line-dispatch.js +48 -0
- package/dist/src/utils/options.d.ts +1 -7
- package/dist/src/utils/options.js +6 -7
- package/dist/src/utils/package-root.js +3 -12
- package/dist/src/utils/platform.d.ts +0 -4
- package/dist/src/utils/process-group.d.ts +2 -1
- package/dist/src/utils/process-group.js +20 -19
- package/dist/src/utils/process.d.ts +40 -26
- package/dist/src/utils/process.js +115 -166
- package/dist/src/utils/ps-duration.js +3 -3
- package/dist/src/utils/sleep.d.ts +26 -0
- package/dist/src/utils/sleep.js +31 -0
- package/dist/src/utils/validation.d.ts +2 -38
- package/dist/src/utils/validation.js +7 -16
- package/docs/configuration.md +136 -1
- package/docs/exit-codes.md +34 -20
- package/docs/lifecycle-invariants.md +18 -12
- package/docs/machine-output.md +31 -8
- package/docs/patch-workflow.md +2 -1
- package/docs/run-logs.md +44 -4
- package/docs/testing.md +70 -11
- package/package.json +8 -7
- package/dist/src/commands/rebase.d.ts +0 -4
- package/dist/src/commands/rebase.js +0 -5
- package/dist/src/core/patch-artifact-normalize.d.ts +0 -21
- package/dist/src/core/patch-artifact-normalize.js +0 -24
- package/dist/src/core/patch-lint-reexports.d.ts +0 -7
- package/dist/src/core/patch-lint-reexports.js +0 -8
- package/dist/src/core/wire-targets.d.ts +0 -7
- package/dist/src/core/wire-targets.js +0 -8
|
@@ -20,12 +20,13 @@
|
|
|
20
20
|
* runs `--add` and `--remove` back-to-back.
|
|
21
21
|
*/
|
|
22
22
|
import { Command } from 'commander';
|
|
23
|
-
import {
|
|
23
|
+
import { confirmDestructive } from '../../core/destructive.js';
|
|
24
|
+
import { appendHistoryBestEffort } from '../../core/history-log.js';
|
|
24
25
|
import { mutatePatchMetadata } from '../../core/patch-export.js';
|
|
25
26
|
import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
26
|
-
import { toError } from '../../utils/errors.js';
|
|
27
27
|
import { info, intro, outro, warn } from '../../utils/logger.js';
|
|
28
28
|
import { addWaitLockOption, resolveWaitLockSeconds, stringListOption, } from '../../utils/options.js';
|
|
29
|
+
import { proceedAfterDecision } from '../destructive-decision.js';
|
|
29
30
|
import { requirePatchQueue, requirePatchTarget } from './patch-context.js';
|
|
30
31
|
/**
|
|
31
32
|
* Printed whenever `--add` lands a new check id. The waiver this command
|
|
@@ -65,7 +66,7 @@ function applyMode(existing, mode, values) {
|
|
|
65
66
|
* `info()` / dry-run / history args. Exported for unit-testing the
|
|
66
67
|
* message format directly without mocking the logger transport.
|
|
67
68
|
*/
|
|
68
|
-
|
|
69
|
+
function describeChange(before, after, mode, values) {
|
|
69
70
|
const beforeSet = new Set(before);
|
|
70
71
|
const afterSet = new Set(after);
|
|
71
72
|
if (mode === 'clear') {
|
|
@@ -135,17 +136,11 @@ export async function patchLintIgnoreCommand(projectRoot, identifier, options =
|
|
|
135
136
|
yes: options.yes === true,
|
|
136
137
|
dryRun: isDryRun,
|
|
137
138
|
});
|
|
138
|
-
if (decision === 'dry-run') {
|
|
139
|
-
|
|
140
|
-
warn(LINT_IGNORE_REVIEW_WARNING);
|
|
141
|
-
}
|
|
142
|
-
outro('Dry run complete — no changes made');
|
|
143
|
-
return;
|
|
139
|
+
if (decision === 'dry-run' && addsNewIds) {
|
|
140
|
+
warn(LINT_IGNORE_REVIEW_WARNING);
|
|
144
141
|
}
|
|
145
|
-
if (decision
|
|
146
|
-
outro('Cancelled — no changes made');
|
|
142
|
+
if (!proceedAfterDecision(decision, 'Cancelled — no changes made'))
|
|
147
143
|
return;
|
|
148
|
-
}
|
|
149
144
|
const result = await mutatePatchMetadata(paths.patches, target.filename, (existing) => {
|
|
150
145
|
const next = applyMode(existing.lintIgnore ?? [], mode, values);
|
|
151
146
|
// Either set the new list when non-empty or unset the field
|
|
@@ -167,23 +162,18 @@ export async function patchLintIgnoreCommand(projectRoot, identifier, options =
|
|
|
167
162
|
if (mode === 'add' && projected.length > existing.length) {
|
|
168
163
|
warn(LINT_IGNORE_REVIEW_WARNING);
|
|
169
164
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
catch (historyError) {
|
|
185
|
-
warn(`History log append failed after patch lint-ignore committed (${target.filename}): ${toError(historyError).message}`);
|
|
186
|
-
}
|
|
165
|
+
await appendHistoryBestEffort(paths.patches, {
|
|
166
|
+
operation: 'patch-lint-ignore',
|
|
167
|
+
args: {
|
|
168
|
+
filename: target.filename,
|
|
169
|
+
mode,
|
|
170
|
+
values: [...values],
|
|
171
|
+
before: existing,
|
|
172
|
+
after: projected,
|
|
173
|
+
},
|
|
174
|
+
...(options.yes === true ? { yes: true } : {}),
|
|
175
|
+
result: 'ok',
|
|
176
|
+
}, `patch lint-ignore committed (${target.filename})`);
|
|
187
177
|
outro('Patch lint-ignore complete');
|
|
188
178
|
}
|
|
189
179
|
/**
|
|
@@ -15,10 +15,12 @@ import { assertConfirmationAvailable, confirmDestructive } from '../../core/dest
|
|
|
15
15
|
import { formatPatchNotFoundError } from '../../core/patch-identifier-suggest.js';
|
|
16
16
|
import { buildPatchQueueContext } from '../../core/patch-lint.js';
|
|
17
17
|
import { loadPatchesManifest, resolvePatchIdentifier } from '../../core/patch-manifest.js';
|
|
18
|
+
import { formatPatchOrder } from '../../core/patch-parse.js';
|
|
18
19
|
import { enforcePatchPolicy } from '../../core/patch-policy.js';
|
|
19
20
|
import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
20
21
|
import { info, intro, outro, success } from '../../utils/logger.js';
|
|
21
22
|
import { normalizePatchDisplayName } from '../../utils/validation.js';
|
|
23
|
+
import { proceedAfterDecision } from '../destructive-decision.js';
|
|
22
24
|
import { resolvePlacementPlan } from '../export-flow.js';
|
|
23
25
|
import { runPatchLint } from '../export-shared.js';
|
|
24
26
|
import { commitPatchSplit } from './split.js';
|
|
@@ -95,8 +97,26 @@ export async function patchMoveFilesCreateCommand(projectRoot, fromIdentifier, n
|
|
|
95
97
|
// projection lint is blind.
|
|
96
98
|
const patchQueueCtx = await buildPatchQueueContext(paths.patches, config);
|
|
97
99
|
const ignoreChecks = source.lintIgnore ? new Set(source.lintIgnore) : undefined;
|
|
98
|
-
await runPatchLint(
|
|
99
|
-
|
|
100
|
+
await runPatchLint({
|
|
101
|
+
engineDir: paths.engine,
|
|
102
|
+
filesAffected: remainingFiles,
|
|
103
|
+
diffContent: remainingDiff,
|
|
104
|
+
config,
|
|
105
|
+
skipLint: options.skipLint,
|
|
106
|
+
patchQueueCtx,
|
|
107
|
+
ignoreChecks,
|
|
108
|
+
patchTier: source.tier,
|
|
109
|
+
});
|
|
110
|
+
await runPatchLint({
|
|
111
|
+
engineDir: paths.engine,
|
|
112
|
+
filesAffected: movedFiles,
|
|
113
|
+
diffContent: movedDiff,
|
|
114
|
+
config,
|
|
115
|
+
skipLint: options.skipLint,
|
|
116
|
+
patchQueueCtx,
|
|
117
|
+
ignoreChecks,
|
|
118
|
+
patchTier: source.tier,
|
|
119
|
+
});
|
|
100
120
|
const { conflicts, stagedDependencyAdditions } = runProjectedSplitLint(plan, patchQueueCtx);
|
|
101
121
|
plan.stagedDependencyAdditions = stagedDependencyAdditions;
|
|
102
122
|
const newMetadata = buildNewPatchMetadata(plan, config);
|
|
@@ -118,16 +138,10 @@ export async function patchMoveFilesCreateCommand(projectRoot, fromIdentifier, n
|
|
|
118
138
|
unsafeOverride: options.forceUnsafe === true,
|
|
119
139
|
conflicts,
|
|
120
140
|
});
|
|
121
|
-
if (decision
|
|
122
|
-
outro('Dry run complete — no changes made');
|
|
141
|
+
if (!proceedAfterDecision(decision, 'Move cancelled'))
|
|
123
142
|
return;
|
|
124
|
-
}
|
|
125
|
-
if (decision === 'declined') {
|
|
126
|
-
outro('Move cancelled');
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
143
|
await commitPatchSplit(paths.patches, plan, newMetadata, options, config);
|
|
130
|
-
success(`Created ${placement.newFilename} (order ${
|
|
144
|
+
success(`Created ${placement.newFilename} (order ${formatPatchOrder(placement.insertionOrder)}) ` +
|
|
131
145
|
`and moved ${plan.movedFiles.length} file(s) out of ${source.filename}`);
|
|
132
146
|
if (plan.ownerRewrites.length > 0) {
|
|
133
147
|
info(`Re-pointed staged-dependency owners in: ${plan.ownerRewrites.join(', ')}`);
|
|
@@ -15,27 +15,21 @@
|
|
|
15
15
|
* the worktree.
|
|
16
16
|
*/
|
|
17
17
|
import { join } from 'node:path';
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
18
|
+
import { assertConfirmationAvailable, confirmDestructive, } from '../../core/destructive.js';
|
|
19
|
+
import { appendHistoryBestEffort } from '../../core/history-log.js';
|
|
20
|
+
import { buildPatchQueueContext, collectForwardImportEdges, formatPatchLintIssue, lintPatchQueue, } from '../../core/patch-lint.js';
|
|
21
21
|
import { computeProjectedLintRegressions } from '../../core/patch-lint-projection.js';
|
|
22
22
|
import { withPatchDirectoryLock } from '../../core/patch-lock.js';
|
|
23
23
|
import { loadPatchesManifest, savePatchesManifest, validatePatchesManifest, } from '../../core/patch-manifest.js';
|
|
24
|
-
import { extractNewFileContentFromDiff } from '../../core/patch-transform.js';
|
|
25
24
|
import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
26
25
|
import { toError } from '../../utils/errors.js';
|
|
27
26
|
import { readText, writeText } from '../../utils/fs.js';
|
|
28
27
|
import { info, outro, success, warn } from '../../utils/logger.js';
|
|
29
28
|
import { resolveWaitLockSeconds } from '../../utils/options.js';
|
|
29
|
+
import { proceedAfterDecision } from '../destructive-decision.js';
|
|
30
30
|
import { runPatchLint } from '../export-shared.js';
|
|
31
|
+
import { projectEntryBody } from './entry-projection.js';
|
|
31
32
|
import { buildSplitDiff, findOwnerRewriteHolders, mergeStagedForwardImports, rewriteSplitOwners, } from './split-plan.js';
|
|
32
|
-
function projectEntryBody(diff) {
|
|
33
|
-
const newFiles = new Map();
|
|
34
|
-
for (const path of detectNewFilesInDiff(diff)) {
|
|
35
|
-
newFiles.set(path, extractNewFileContentFromDiff(diff, path));
|
|
36
|
-
}
|
|
37
|
-
return { diff, newFiles, modifiedFileAdditions: buildModifiedFileAdditionsFromDiff(diff) };
|
|
38
|
-
}
|
|
39
33
|
/**
|
|
40
34
|
* Projects the post-move queue through cross-patch lint, auto-declaring the
|
|
41
35
|
* forward edges the move introduces into the target (an importer that used
|
|
@@ -124,9 +118,9 @@ async function commitMoveInto(patchesDir, plan, waitLockSeconds) {
|
|
|
124
118
|
let sourceWritten = false;
|
|
125
119
|
let targetWritten = false;
|
|
126
120
|
try {
|
|
127
|
-
await writeText(sourcePath,
|
|
121
|
+
await writeText(sourcePath, plan.sourceDiff);
|
|
128
122
|
sourceWritten = true;
|
|
129
|
-
await writeText(targetPath,
|
|
123
|
+
await writeText(targetPath, plan.targetDiff);
|
|
130
124
|
targetWritten = true;
|
|
131
125
|
const updatedPatches = manifest.patches.map((patch) => {
|
|
132
126
|
let updated = rewriteSplitOwners(patch, plan.source.filename, movedSet, plan.target.filename);
|
|
@@ -143,21 +137,16 @@ async function commitMoveInto(patchesDir, plan, waitLockSeconds) {
|
|
|
143
137
|
});
|
|
144
138
|
const updated = validatePatchesManifest({ ...manifest, patches: updatedPatches });
|
|
145
139
|
await savePatchesManifest(patchesDir, updated);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
catch (historyError) {
|
|
159
|
-
warn(`History log append failed after patch move-files committed: ${toError(historyError).message}`);
|
|
160
|
-
}
|
|
140
|
+
await appendHistoryBestEffort(patchesDir, {
|
|
141
|
+
operation: 'patch-move-files',
|
|
142
|
+
args: {
|
|
143
|
+
source: plan.source.filename,
|
|
144
|
+
target: plan.target.filename,
|
|
145
|
+
files: plan.movedFiles,
|
|
146
|
+
ownerRewrites: plan.ownerRewrites,
|
|
147
|
+
},
|
|
148
|
+
result: 'ok',
|
|
149
|
+
}, `patch move-files committed`);
|
|
161
150
|
}
|
|
162
151
|
catch (error) {
|
|
163
152
|
if (targetWritten) {
|
|
@@ -202,8 +191,26 @@ export async function runMoveFilesInto(args) {
|
|
|
202
191
|
// parity) resolves cross-patch imports and sibling head.js harness roots
|
|
203
192
|
// instead of linting each projected body blind.
|
|
204
193
|
const patchQueueCtx = await buildPatchQueueContext(patchesDir, args.config);
|
|
205
|
-
await runPatchLint(
|
|
206
|
-
|
|
194
|
+
await runPatchLint({
|
|
195
|
+
engineDir: enginePath,
|
|
196
|
+
filesAffected: sourceAfter,
|
|
197
|
+
diffContent: sourceDiff,
|
|
198
|
+
config: args.config,
|
|
199
|
+
skipLint: options.skipLint,
|
|
200
|
+
patchQueueCtx,
|
|
201
|
+
ignoreChecks: source.lintIgnore ? new Set(source.lintIgnore) : undefined,
|
|
202
|
+
patchTier: source.tier,
|
|
203
|
+
});
|
|
204
|
+
await runPatchLint({
|
|
205
|
+
engineDir: enginePath,
|
|
206
|
+
filesAffected: targetAfter,
|
|
207
|
+
diffContent: targetDiff,
|
|
208
|
+
config: args.config,
|
|
209
|
+
skipLint: options.skipLint,
|
|
210
|
+
patchQueueCtx,
|
|
211
|
+
ignoreChecks: target.lintIgnore ? new Set(target.lintIgnore) : undefined,
|
|
212
|
+
patchTier: target.tier,
|
|
213
|
+
});
|
|
207
214
|
const manifest = await loadPatchesManifest(patchesDir);
|
|
208
215
|
const plan = {
|
|
209
216
|
source,
|
|
@@ -234,14 +241,8 @@ export async function runMoveFilesInto(args) {
|
|
|
234
241
|
unsafeOverride: options.forceUnsafe === true,
|
|
235
242
|
conflicts,
|
|
236
243
|
});
|
|
237
|
-
if (decision
|
|
238
|
-
outro('Dry run complete — no changes made');
|
|
244
|
+
if (!proceedAfterDecision(decision, 'Move cancelled'))
|
|
239
245
|
return;
|
|
240
|
-
}
|
|
241
|
-
if (decision === 'declined') {
|
|
242
|
-
outro('Move cancelled');
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
246
|
await commitMoveInto(patchesDir, plan, resolveWaitLockSeconds(options.waitLock));
|
|
246
247
|
success(`Moved ${files.length} file(s) from ${source.filename} to ${target.filename}`);
|
|
247
248
|
if (plan.ownerRewrites.length > 0) {
|
|
@@ -13,13 +13,10 @@ import { loadPatchesManifest, resolvePatchIdentifier } from '../../core/patch-ma
|
|
|
13
13
|
import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
14
14
|
import { pathExists } from '../../utils/fs.js';
|
|
15
15
|
import { info, intro, note, warn } from '../../utils/logger.js';
|
|
16
|
-
import { addWaitLockOption, commanderArgParser, pickDefined } from '../../utils/options.js';
|
|
16
|
+
import { addWaitLockOption, commanderArgParser, pickDefined, stringListOption, } from '../../utils/options.js';
|
|
17
|
+
import { parsePositiveIntegerFlag } from '../../utils/validation.js';
|
|
17
18
|
import { patchMoveFilesCreateCommand } from './move-files-create.js';
|
|
18
19
|
import { runMoveFilesInto } from './move-files-into.js';
|
|
19
|
-
function collectOption(value, previous) {
|
|
20
|
-
previous.push(value);
|
|
21
|
-
return previous;
|
|
22
|
-
}
|
|
23
20
|
function normalizeFileList(files) {
|
|
24
21
|
const cleaned = (files ?? []).map((file) => file.trim()).filter((file) => file.length > 0);
|
|
25
22
|
return [...new Set(cleaned)].sort((left, right) => left.localeCompare(right));
|
|
@@ -165,15 +162,9 @@ export function registerPatchMoveFiles(parent, context) {
|
|
|
165
162
|
.command('move-files <from> <to>')
|
|
166
163
|
.description('Preview the re-export commands needed to move file ownership between patches, ' +
|
|
167
164
|
'or create the target patch and move the files in one transaction with --create --order <n>.')
|
|
168
|
-
.option('--file <path>', 'File path relative to engine/ to move (repeatable)',
|
|
165
|
+
.option('--file <path>', 'File path relative to engine/ to move (repeatable)', ...stringListOption())
|
|
169
166
|
.option('--create', 'Create <to> as a new patch and move the files into it (requires --order)')
|
|
170
|
-
.option('--order <n>', 'Exact sparse order for the created patch (only valid with --create)', commanderArgParser((raw) =>
|
|
171
|
-
const n = Number.parseInt(raw, 10);
|
|
172
|
-
if (!Number.isInteger(n) || n <= 0) {
|
|
173
|
-
throw new InvalidArgumentError(`--order must be a positive integer, got "${raw}".`, '--order');
|
|
174
|
-
}
|
|
175
|
-
return n;
|
|
176
|
-
}))
|
|
167
|
+
.option('--order <n>', 'Exact sparse order for the created patch (only valid with --create)', commanderArgParser((raw) => parsePositiveIntegerFlag('--order', raw)))
|
|
177
168
|
.option('--category <category>', "Category for the created patch (default: the source patch's)")
|
|
178
169
|
.option('-d, --description <desc>', 'Description for the created patch')
|
|
179
170
|
.option('--dry-run', 'Show what would happen without writing')
|
|
@@ -19,7 +19,8 @@ import { rename as fsRename } from 'node:fs/promises';
|
|
|
19
19
|
import { join } from 'node:path';
|
|
20
20
|
import { Command } from 'commander';
|
|
21
21
|
import { loadConfig } from '../../core/config.js';
|
|
22
|
-
import {
|
|
22
|
+
import { confirmDestructive } from '../../core/destructive.js';
|
|
23
|
+
import { appendHistoryBestEffort } from '../../core/history-log.js';
|
|
23
24
|
import { patchNameSlug } from '../../core/patch-export.js';
|
|
24
25
|
import { buildPatchQueueContext, formatPatchLintIssue, lintPatchQueue, } from '../../core/patch-lint.js';
|
|
25
26
|
import { withPatchDirectoryLock } from '../../core/patch-lock.js';
|
|
@@ -30,6 +31,8 @@ import { toError } from '../../utils/errors.js';
|
|
|
30
31
|
import { pathExists } from '../../utils/fs.js';
|
|
31
32
|
import { info, intro, outro, warn } from '../../utils/logger.js';
|
|
32
33
|
import { addWaitLockOption, commanderArgParser, pickDefined, resolveWaitLockSeconds, } from '../../utils/options.js';
|
|
34
|
+
import { parsePositiveIntegerFlag } from '../../utils/validation.js';
|
|
35
|
+
import { proceedAfterDecision } from '../destructive-decision.js';
|
|
33
36
|
import { requirePatchQueue, requirePatchTarget } from './patch-context.js';
|
|
34
37
|
import { projectReorder } from './reorder.js';
|
|
35
38
|
/**
|
|
@@ -76,7 +79,7 @@ async function commitRenameUnderLock(input) {
|
|
|
76
79
|
if (orderChanging && input.newOrder !== undefined) {
|
|
77
80
|
const orderHolder = fresh.patches.find((p) => p.order === input.newOrder && p.filename !== target.filename);
|
|
78
81
|
if (orderHolder) {
|
|
79
|
-
throw new InvalidArgumentError(`Order ${
|
|
82
|
+
throw new InvalidArgumentError(`Order ${input.newOrder} was claimed by ${orderHolder.filename} concurrently. Pick an unused order, or use "fireforge patch reorder" to renumber siblings.`, '--order');
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
85
|
let oldPath;
|
|
@@ -136,28 +139,23 @@ async function commitRenameUnderLock(input) {
|
|
|
136
139
|
else {
|
|
137
140
|
await savePatchesManifest(patchesDir, fresh);
|
|
138
141
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
catch (historyError) {
|
|
159
|
-
warn(`History log append failed after patch rename committed (${newFilename}): ${toError(historyError).message}`);
|
|
160
|
-
}
|
|
142
|
+
await appendHistoryBestEffort(patchesDir, {
|
|
143
|
+
operation: 'patch-rename',
|
|
144
|
+
args: {
|
|
145
|
+
oldFilename: target.filename,
|
|
146
|
+
newFilename,
|
|
147
|
+
oldName: target.name,
|
|
148
|
+
newName,
|
|
149
|
+
...(descriptionChanging ? { oldDescription: target.description, newDescription } : {}),
|
|
150
|
+
...(orderChanging ? { oldOrder: target.order, newOrder: input.newOrder } : {}),
|
|
151
|
+
...(categoryChanging
|
|
152
|
+
? { oldCategory: target.category, newCategory: input.newCategory }
|
|
153
|
+
: {}),
|
|
154
|
+
},
|
|
155
|
+
...(input.yes === true ? { yes: true } : {}),
|
|
156
|
+
...(input.forceUnsafe === true ? { unsafeOverride: true } : {}),
|
|
157
|
+
result: 'ok',
|
|
158
|
+
}, `patch rename committed (${newFilename})`);
|
|
161
159
|
}, { waitLockSeconds: input.waitLockSeconds, command: 'patch rename' });
|
|
162
160
|
}
|
|
163
161
|
/** Validates the flags and resolves the new filename/identity fields. */
|
|
@@ -215,14 +213,14 @@ async function assertRenamePreconditions(patchesDir, manifest, target, plan, opt
|
|
|
215
213
|
if (plan.orderChanging && options.order !== undefined) {
|
|
216
214
|
const holder = manifest.patches.find((p) => p.order === options.order && p.filename !== target.filename);
|
|
217
215
|
if (holder) {
|
|
218
|
-
throw new InvalidArgumentError(`Order ${
|
|
216
|
+
throw new InvalidArgumentError(`Order ${options.order} is already used by ${holder.filename}. Pick an unused order, or use "fireforge patch reorder ${target.filename} --to ${options.order}" to renumber siblings.`, '--order');
|
|
219
217
|
}
|
|
220
218
|
if (options.forceUnsafe !== true) {
|
|
221
219
|
const baseCtx = await buildPatchQueueContext(patchesDir, config);
|
|
222
220
|
const projected = projectReorder(baseCtx, new Map([[target.filename, { newFilename: plan.newFilename, newOrder: options.order }]]));
|
|
223
221
|
const projectedErrors = lintPatchQueue(projected).filter((i) => i.severity === 'error');
|
|
224
222
|
if (projectedErrors.length > 0) {
|
|
225
|
-
throw new InvalidArgumentError(`Refusing to run patch rename: the order change would introduce ${
|
|
223
|
+
throw new InvalidArgumentError(`Refusing to run patch rename: the order change would introduce ${projectedErrors.length} cross-patch lint error(s):\n ${projectedErrors
|
|
226
224
|
.map(formatPatchLintIssue)
|
|
227
225
|
.join('\n ')}\nPass --force-unsafe to override.`, '--force-unsafe');
|
|
228
226
|
}
|
|
@@ -248,7 +246,7 @@ function buildRenameSummary(target, plan, options) {
|
|
|
248
246
|
summary.push(`description: "${target.description || '(none)'}" → "${options.description ?? '(none)'}"`);
|
|
249
247
|
}
|
|
250
248
|
if (plan.orderChanging && options.order !== undefined) {
|
|
251
|
-
summary.push(`order: ${
|
|
249
|
+
summary.push(`order: ${target.order} → ${options.order}`);
|
|
252
250
|
}
|
|
253
251
|
if (plan.categoryChanging) {
|
|
254
252
|
summary.push(`category: ${target.category} → ${plan.newCategory}`);
|
|
@@ -309,14 +307,8 @@ export async function patchRenameCommand(projectRoot, identifier, options = {})
|
|
|
309
307
|
dryRun: isDryRun,
|
|
310
308
|
conflicts: null,
|
|
311
309
|
});
|
|
312
|
-
if (decision
|
|
313
|
-
outro('Dry run complete — no changes made');
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
if (decision === 'declined') {
|
|
317
|
-
outro('Rename cancelled');
|
|
310
|
+
if (!proceedAfterDecision(decision, 'Rename cancelled'))
|
|
318
311
|
return;
|
|
319
|
-
}
|
|
320
312
|
await commitRenameUnderLock({
|
|
321
313
|
patchesDir: paths.patches,
|
|
322
314
|
target,
|
|
@@ -356,13 +348,7 @@ export function registerPatchRename(parent, context) {
|
|
|
356
348
|
.description('Rename a patch: filename, manifest name, category, order, and/or description update in one transaction without rewriting the .patch body.')
|
|
357
349
|
.option('--to <new-name>', 'New human-readable name, category-prefixed slug, or full filename stem (normalised into the filename slug)')
|
|
358
350
|
.option('--category <category>', 'New category for the patch (validated against configured categories); rewrites the filename prefix and manifest row in one transaction')
|
|
359
|
-
.option('--order <n>', 'Move the patch to this exact unused order; refuses on collision — use "patch reorder" to renumber siblings', commanderArgParser((raw) =>
|
|
360
|
-
const n = Number.parseInt(raw, 10);
|
|
361
|
-
if (!Number.isInteger(n) || n <= 0) {
|
|
362
|
-
throw new InvalidArgumentError(`--order must be a positive integer, got "${raw}".`, '--order');
|
|
363
|
-
}
|
|
364
|
-
return n;
|
|
365
|
-
}))
|
|
351
|
+
.option('--order <n>', 'Move the patch to this exact unused order; refuses on collision — use "patch reorder" to renumber siblings', commanderArgParser((raw) => parsePositiveIntegerFlag('--order', raw)))
|
|
366
352
|
.option('-d, --description <text>', 'Replacement description (omit to leave description unchanged)')
|
|
367
353
|
.option('--dry-run', 'Show what would change without writing')
|
|
368
354
|
.option('-y, --yes', 'Skip confirmation prompt (required for non-TTY)')
|
|
@@ -10,16 +10,18 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { Command, Option } from 'commander';
|
|
12
12
|
import { loadConfig } from '../../core/config.js';
|
|
13
|
-
import {
|
|
13
|
+
import { confirmDestructive, } from '../../core/destructive.js';
|
|
14
|
+
import { appendHistoryBestEffort } from '../../core/history-log.js';
|
|
14
15
|
import { buildPatchQueueContext, formatPatchLintIssue, lintPatchQueue, } from '../../core/patch-lint.js';
|
|
15
16
|
import { withPatchDirectoryLock } from '../../core/patch-lock.js';
|
|
16
17
|
import { loadPatchesManifest, renumberPatchesInManifest, resolvePatchIdentifier, rewriteStagedDependencyOwners, } from '../../core/patch-manifest.js';
|
|
17
18
|
import { applyRenameMapToManifest, enforcePatchPolicy } from '../../core/patch-policy.js';
|
|
18
19
|
import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
19
|
-
import {
|
|
20
|
-
import { info, intro, outro, warn } from '../../utils/logger.js';
|
|
20
|
+
import { info, intro, outro } from '../../utils/logger.js';
|
|
21
21
|
import { addWaitLockOption, commanderArgParser, pickDefined, resolveWaitLockSeconds, } from '../../utils/options.js';
|
|
22
22
|
import { parsePositiveIntegerFlag } from '../../utils/validation.js';
|
|
23
|
+
import { proceedAfterDecision } from '../destructive-decision.js';
|
|
24
|
+
import { getSortedRenameEntries, renameMapsEqual } from '../patch-rename-map.js';
|
|
23
25
|
import { requirePatchQueue, requirePatchTarget } from './patch-context.js';
|
|
24
26
|
/** Zero-pads an ordinal number to the given width. */
|
|
25
27
|
function padOrder(value, width) {
|
|
@@ -98,25 +100,6 @@ function computeRenameMap(manifestPatches, target, destinationOrder) {
|
|
|
98
100
|
});
|
|
99
101
|
return renames;
|
|
100
102
|
}
|
|
101
|
-
function getSortedRenameEntries(renameMap) {
|
|
102
|
-
return Array.from(renameMap.entries()).sort((a, b) => a[1].newOrder - b[1].newOrder);
|
|
103
|
-
}
|
|
104
|
-
function renameMapsEqual(left, right) {
|
|
105
|
-
const leftEntries = getSortedRenameEntries(left);
|
|
106
|
-
const rightEntries = getSortedRenameEntries(right);
|
|
107
|
-
if (leftEntries.length !== rightEntries.length) {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
return leftEntries.every(([leftFilename, leftEntry], index) => {
|
|
111
|
-
const rightTuple = rightEntries[index];
|
|
112
|
-
if (!rightTuple)
|
|
113
|
-
return false;
|
|
114
|
-
const [rightFilename, rightEntry] = rightTuple;
|
|
115
|
-
return (leftFilename === rightFilename &&
|
|
116
|
-
leftEntry.newFilename === rightEntry.newFilename &&
|
|
117
|
-
leftEntry.newOrder === rightEntry.newOrder);
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
103
|
/**
|
|
121
104
|
* Applies a rename map to a {@link PatchQueueContext} so cross-patch lint
|
|
122
105
|
* can run against the projected state without touching disk. Exported for
|
|
@@ -159,7 +142,7 @@ function resolveDestination(target, manifestPatches, options) {
|
|
|
159
142
|
// integers, but the function is reachable from tests that may pass
|
|
160
143
|
// `{ to: NaN }` directly.
|
|
161
144
|
if (!Number.isInteger(options.to) || options.to <= 0) {
|
|
162
|
-
throw new InvalidArgumentError(`--to must be a positive integer, got ${
|
|
145
|
+
throw new InvalidArgumentError(`--to must be a positive integer, got ${options.to}.`, '--to');
|
|
163
146
|
}
|
|
164
147
|
return { destinationOrder: options.to, anchorFilename: undefined };
|
|
165
148
|
}
|
|
@@ -195,7 +178,14 @@ function resolveDestination(target, manifestPatches, options) {
|
|
|
195
178
|
}
|
|
196
179
|
return { destinationOrder: anchor.order + 1, anchorFilename: anchor.filename };
|
|
197
180
|
}
|
|
198
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Re-validates the reorder against the freshly-loaded manifest and commits
|
|
183
|
+
* it, all under the patch directory lock.
|
|
184
|
+
*
|
|
185
|
+
* @param commitOptions - See {@link CommitReorderPlanOptions}
|
|
186
|
+
*/
|
|
187
|
+
async function commitReorderPlan(commitOptions) {
|
|
188
|
+
const { patchesDir, target, renameMap, anchorFilename, options, config, buildHistoryEntry } = commitOptions;
|
|
199
189
|
await withPatchDirectoryLock(patchesDir, async () => {
|
|
200
190
|
const currentManifest = await loadPatchesManifest(patchesDir);
|
|
201
191
|
if (!currentManifest || currentManifest.patches.length === 0) {
|
|
@@ -248,12 +238,7 @@ async function commitReorderPlan(patchesDir, target, renameMap, anchorFilename,
|
|
|
248
238
|
// permissions) is warned but not re-thrown: the mutation has already
|
|
249
239
|
// succeeded and is not reversible, so surfacing it as a command
|
|
250
240
|
// failure would mislead.
|
|
251
|
-
|
|
252
|
-
await appendHistory(patchesDir, buildHistoryEntry(currentRenameMap));
|
|
253
|
-
}
|
|
254
|
-
catch (historyError) {
|
|
255
|
-
warn(`History log append failed after patch reorder committed: ${toError(historyError).message}`);
|
|
256
|
-
}
|
|
241
|
+
await appendHistoryBestEffort(patchesDir, buildHistoryEntry(currentRenameMap), `patch reorder committed`);
|
|
257
242
|
}, { waitLockSeconds: resolveWaitLockSeconds(options.waitLock), command: 'patch reorder' });
|
|
258
243
|
}
|
|
259
244
|
/**
|
|
@@ -329,14 +314,8 @@ export async function patchReorderCommand(projectRoot, identifier, options = {})
|
|
|
329
314
|
unsafeOverride: options.forceUnsafe === true,
|
|
330
315
|
conflicts,
|
|
331
316
|
});
|
|
332
|
-
if (decision
|
|
333
|
-
outro('Dry run complete — no changes made');
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
if (decision === 'declined') {
|
|
337
|
-
outro('Reorder cancelled');
|
|
317
|
+
if (!proceedAfterDecision(decision, 'Reorder cancelled'))
|
|
338
318
|
return;
|
|
339
|
-
}
|
|
340
319
|
// The history entry is built inside commitReorderPlan (still under the
|
|
341
320
|
// lock) from the *final* rename map, not the pre-confirmation one, so
|
|
342
321
|
// the destinationOrder and renames mirror what actually landed on disk.
|
|
@@ -359,7 +338,15 @@ export async function patchReorderCommand(projectRoot, identifier, options = {})
|
|
|
359
338
|
result: 'ok',
|
|
360
339
|
};
|
|
361
340
|
};
|
|
362
|
-
await commitReorderPlan(
|
|
341
|
+
await commitReorderPlan({
|
|
342
|
+
patchesDir: paths.patches,
|
|
343
|
+
target,
|
|
344
|
+
renameMap,
|
|
345
|
+
anchorFilename,
|
|
346
|
+
options,
|
|
347
|
+
config,
|
|
348
|
+
buildHistoryEntry,
|
|
349
|
+
});
|
|
363
350
|
info(`Reordered ${renameMap.size} patch(es).`);
|
|
364
351
|
outro('Reorder complete');
|
|
365
352
|
}
|
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
* budget; consumed only by the split command.
|
|
7
7
|
*/
|
|
8
8
|
import { type ConflictReport } from '../../core/destructive.js';
|
|
9
|
-
import {
|
|
10
|
-
import { buildProjectedManifest } from '../../core/patch-policy.js';
|
|
9
|
+
import type { PatchQueueContext } from '../../core/patch-lint-cross.js';
|
|
11
10
|
import type { PatchStagedForwardImport } from '../../types/commands/index.js';
|
|
12
|
-
import type { PatchCategory, PatchMetadata } from '../../types/commands/index.js';
|
|
11
|
+
import type { PatchCategory, PatchesManifest, PatchMetadata } from '../../types/commands/index.js';
|
|
13
12
|
import type { FireForgeConfig } from '../../types/config.js';
|
|
14
13
|
import { type PlacementPlan } from '../export-flow.js';
|
|
15
14
|
/** Everything the commit step needs, computed and confirmed up front. */
|
|
@@ -68,7 +67,7 @@ export declare function mergeStagedForwardImports(patch: PatchMetadata, decls: r
|
|
|
68
67
|
* patch are auto-declared (and the declarations returned) so the projection
|
|
69
68
|
* matches the real per-patch gate the split leaves behind.
|
|
70
69
|
*/
|
|
71
|
-
export declare function runProjectedSplitLint(plan: SplitPlan, baseCtx:
|
|
70
|
+
export declare function runProjectedSplitLint(plan: SplitPlan, baseCtx: PatchQueueContext): {
|
|
72
71
|
conflicts: ConflictReport | null;
|
|
73
72
|
stagedDependencyAdditions: Map<string, PatchStagedForwardImport[]>;
|
|
74
73
|
};
|
|
@@ -76,7 +75,7 @@ export declare function runProjectedSplitLint(plan: SplitPlan, baseCtx: Awaited<
|
|
|
76
75
|
export declare function projectSplitManifest(manifest: {
|
|
77
76
|
version: 1;
|
|
78
77
|
patches: PatchMetadata[];
|
|
79
|
-
}, plan: SplitPlan, newMetadata: PatchMetadata):
|
|
78
|
+
}, plan: SplitPlan, newMetadata: PatchMetadata): PatchesManifest;
|
|
80
79
|
/**
|
|
81
80
|
* Builds the manifest row for the patch created by a split, carrying the
|
|
82
81
|
* source's provenance (product, version, category) onto the new patch.
|
|
@@ -10,16 +10,16 @@ import { join } from 'node:path';
|
|
|
10
10
|
import {} from '../../core/destructive.js';
|
|
11
11
|
import { getDiffForFilesAgainstHead } from '../../core/git-diff.js';
|
|
12
12
|
import { extractAffectedFiles } from '../../core/patch-apply.js';
|
|
13
|
-
import {
|
|
13
|
+
import { collectForwardImportEdges, formatPatchLintIssue, lintPatchQueue, } from '../../core/patch-lint.js';
|
|
14
14
|
import { computeProjectedLintRegressions } from '../../core/patch-lint-projection.js';
|
|
15
15
|
import { rewriteStagedDependencyOwners } from '../../core/patch-manifest.js';
|
|
16
16
|
import { applyRenameMapToManifest, buildProjectedManifest } from '../../core/patch-policy.js';
|
|
17
17
|
import { buildPatchSourceMetadata } from '../../core/patch-source-metadata.js';
|
|
18
|
-
import { extractNewFileContentFromDiff } from '../../core/patch-transform.js';
|
|
19
18
|
import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
20
19
|
import { pathExists } from '../../utils/fs.js';
|
|
21
20
|
import { warn } from '../../utils/logger.js';
|
|
22
21
|
import {} from '../export-flow.js';
|
|
22
|
+
import { projectEntryBody } from './entry-projection.js';
|
|
23
23
|
/**
|
|
24
24
|
* Refuses the split unless the source patch currently owns every requested
|
|
25
25
|
* file. Splitting out a file the source does not own would produce a new patch
|
|
@@ -81,13 +81,6 @@ export function rewriteSplitOwners(patch, sourceFilename, movedSet, newFilename)
|
|
|
81
81
|
},
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
-
function buildEntryProjection(diff) {
|
|
85
|
-
const newFiles = new Map();
|
|
86
|
-
for (const path of detectNewFilesInDiff(diff)) {
|
|
87
|
-
newFiles.set(path, extractNewFileContentFromDiff(diff, path));
|
|
88
|
-
}
|
|
89
|
-
return { diff, newFiles, modifiedFileAdditions: buildModifiedFileAdditionsFromDiff(diff) };
|
|
90
|
-
}
|
|
91
84
|
/** Builds the projected post-split queue entries (renumber + shrunken source + new patch). */
|
|
92
85
|
function buildProjectedSplitEntries(baseCtx, plan) {
|
|
93
86
|
const movedSet = new Set(plan.movedFiles);
|
|
@@ -104,13 +97,13 @@ function buildProjectedSplitEntries(baseCtx, plan) {
|
|
|
104
97
|
: { ...entry, metadata };
|
|
105
98
|
if (entry.filename !== plan.source.filename)
|
|
106
99
|
return base;
|
|
107
|
-
return { ...base, ...
|
|
100
|
+
return { ...base, ...projectEntryBody(plan.remainingDiff) };
|
|
108
101
|
});
|
|
109
102
|
entries.push({
|
|
110
103
|
filename: plan.placement.newFilename,
|
|
111
104
|
order: plan.placement.insertionOrder,
|
|
112
105
|
metadata: null,
|
|
113
|
-
...
|
|
106
|
+
...projectEntryBody(plan.movedDiff),
|
|
114
107
|
});
|
|
115
108
|
entries.sort((a, b) => a.order - b.order || a.filename.localeCompare(b.filename));
|
|
116
109
|
return entries;
|