@hominis/fireforge 0.40.0 → 0.42.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 +85 -0
- package/README.md +16 -10
- package/dist/bin/fireforge.js +25 -4
- package/dist/build-info.json +9 -0
- package/dist/src/cli.js +20 -3
- package/dist/src/commands/bootstrap.js +5 -1
- package/dist/src/commands/discard.js +2 -22
- package/dist/src/commands/doctor/post-rebase-audit.js +27 -4
- package/dist/src/commands/doctor-check-core.d.ts +20 -0
- package/dist/src/commands/doctor-check-core.js +28 -0
- package/dist/src/commands/doctor-external-toolchains.js +2 -0
- package/dist/src/commands/doctor-furnace-manifest-sync.js +144 -46
- package/dist/src/commands/doctor-furnace.js +13 -11
- package/dist/src/commands/doctor-orphaned-harness.js +2 -1
- package/dist/src/commands/doctor.js +2 -2
- package/dist/src/commands/export-all.js +9 -1
- package/dist/src/commands/export-flow.js +13 -3
- package/dist/src/commands/export-placement-conflicts.d.ts +17 -0
- package/dist/src/commands/export-placement-conflicts.js +74 -0
- package/dist/src/commands/export-placement-gate.js +1 -1
- package/dist/src/commands/export-shared.d.ts +8 -1
- package/dist/src/commands/export-shared.js +16 -7
- package/dist/src/commands/export.js +2 -2
- package/dist/src/commands/furnace/apply.js +4 -3
- package/dist/src/commands/furnace/chrome-doc-remove.js +13 -2
- package/dist/src/commands/furnace/chrome-doc.js +13 -2
- package/dist/src/commands/furnace/create-browser-test.d.ts +5 -0
- package/dist/src/commands/furnace/create-browser-test.js +5 -0
- package/dist/src/commands/furnace/create.js +2 -2
- package/dist/src/commands/furnace/diff.js +2 -1
- package/dist/src/commands/furnace/init.js +4 -6
- package/dist/src/commands/furnace/override.js +2 -2
- package/dist/src/commands/furnace/remove-mutations.d.ts +40 -0
- package/dist/src/commands/furnace/remove-mutations.js +171 -0
- package/dist/src/commands/furnace/remove.js +21 -128
- package/dist/src/commands/furnace/rename-browser-test.js +54 -5
- package/dist/src/commands/furnace/scan.js +27 -36
- package/dist/src/commands/furnace/status.js +30 -28
- package/dist/src/commands/furnace/validate.js +25 -18
- package/dist/src/commands/import.js +6 -20
- package/dist/src/commands/lint-per-patch.js +12 -59
- package/dist/src/commands/lint-per-run-checkjs.d.ts +64 -0
- package/dist/src/commands/lint-per-run-checkjs.js +102 -0
- package/dist/src/commands/lint.js +4 -4
- package/dist/src/commands/manifest.js +1 -1
- package/dist/src/commands/package.js +9 -16
- package/dist/src/commands/patch/compact.js +5 -5
- package/dist/src/commands/patch/delete.js +5 -5
- package/dist/src/commands/patch/lint-ignore.js +3 -2
- package/dist/src/commands/patch/move-files-create.js +22 -4
- package/dist/src/commands/patch/move-files-into.js +14 -10
- package/dist/src/commands/patch/move-files.js +6 -5
- package/dist/src/commands/patch/rename.d.ts +2 -2
- package/dist/src/commands/patch/rename.js +151 -50
- package/dist/src/commands/patch/reorder.d.ts +9 -0
- package/dist/src/commands/patch/reorder.js +14 -10
- package/dist/src/commands/patch/split-plan.d.ts +13 -6
- package/dist/src/commands/patch/split-plan.js +22 -12
- package/dist/src/commands/patch/split.d.ts +1 -1
- package/dist/src/commands/patch/split.js +23 -9
- package/dist/src/commands/patch/staged-dependency-validate.d.ts +15 -0
- package/dist/src/commands/patch/staged-dependency-validate.js +49 -0
- package/dist/src/commands/patch/staged-dependency.js +10 -0
- package/dist/src/commands/re-export-adjacent.js +5 -6
- package/dist/src/commands/re-export-bulk-scan.d.ts +13 -0
- package/dist/src/commands/re-export-bulk-scan.js +142 -2
- package/dist/src/commands/re-export-drift.d.ts +74 -0
- package/dist/src/commands/re-export-drift.js +234 -0
- package/dist/src/commands/re-export-files.js +5 -3
- package/dist/src/commands/re-export-lint.d.ts +97 -0
- package/dist/src/commands/re-export-lint.js +210 -0
- package/dist/src/commands/re-export-options.js +8 -0
- package/dist/src/commands/re-export-register.d.ts +18 -0
- package/dist/src/commands/re-export-register.js +61 -0
- package/dist/src/commands/re-export-scan.js +13 -7
- package/dist/src/commands/re-export-single.d.ts +20 -0
- package/dist/src/commands/re-export-single.js +261 -0
- package/dist/src/commands/re-export.d.ts +0 -4
- package/dist/src/commands/re-export.js +113 -268
- package/dist/src/commands/rebase/abort.js +13 -4
- package/dist/src/commands/rebase/continue.js +11 -4
- package/dist/src/commands/rebase/index.js +19 -29
- package/dist/src/commands/rebase/patch-loop.js +12 -0
- package/dist/src/commands/reset.js +4 -23
- package/dist/src/commands/resolve.js +2 -9
- package/dist/src/commands/run.js +11 -21
- package/dist/src/commands/source.js +3 -9
- package/dist/src/commands/status-check.d.ts +13 -0
- package/dist/src/commands/status-check.js +31 -13
- package/dist/src/commands/status-json.d.ts +31 -0
- package/dist/src/commands/status-json.js +76 -0
- package/dist/src/commands/status-output.d.ts +1 -0
- package/dist/src/commands/status-output.js +10 -1
- package/dist/src/commands/status-ownership.d.ts +52 -0
- package/dist/src/commands/status-ownership.js +57 -0
- package/dist/src/commands/status.js +184 -175
- package/dist/src/commands/test-build-phase.d.ts +19 -0
- package/dist/src/commands/test-build-phase.js +168 -0
- package/dist/src/commands/test-diagnose.js +30 -2
- package/dist/src/commands/test-modes.d.ts +9 -1
- package/dist/src/commands/test-modes.js +46 -13
- package/dist/src/commands/test-register.js +59 -27
- package/dist/src/commands/test-run.d.ts +29 -3
- package/dist/src/commands/test-run.js +41 -4
- package/dist/src/commands/test-verdict.d.ts +32 -0
- package/dist/src/commands/test-verdict.js +48 -0
- package/dist/src/commands/test.d.ts +9 -0
- package/dist/src/commands/test.js +100 -123
- package/dist/src/commands/token-coverage.js +4 -9
- package/dist/src/commands/tree.d.ts +3 -0
- package/dist/src/commands/tree.js +171 -25
- package/dist/src/commands/verify.js +2 -2
- package/dist/src/commands/watch.js +22 -21
- package/dist/src/commands/wire.js +1 -1
- package/dist/src/core/ast-utils.d.ts +11 -0
- package/dist/src/core/ast-utils.js +11 -0
- package/dist/src/core/branding.d.ts +16 -0
- package/dist/src/core/branding.js +18 -2
- package/dist/src/core/build-audit-platform.js +6 -1
- package/dist/src/core/build-audit-registration.js +2 -0
- package/dist/src/core/build-audit-resolve.d.ts +13 -0
- package/dist/src/core/build-audit-resolve.js +34 -13
- package/dist/src/core/build-audit.js +4 -20
- package/dist/src/core/build-baseline-types.d.ts +29 -8
- package/dist/src/core/build-baseline-types.js +2 -1
- package/dist/src/core/build-baseline.d.ts +10 -2
- package/dist/src/core/build-baseline.js +39 -8
- package/dist/src/core/build-prepare.d.ts +4 -0
- package/dist/src/core/build-prepare.js +7 -1
- package/dist/src/core/config-paths.d.ts +1 -1
- package/dist/src/core/config-paths.js +2 -0
- package/dist/src/core/config-validate-test-toolchains.js +3 -2
- package/dist/src/core/config-validate.js +34 -36
- package/dist/src/core/config.js +16 -3
- package/dist/src/core/coverage-extend.d.ts +89 -0
- package/dist/src/core/coverage-extend.js +188 -0
- package/dist/src/core/destructive.js +3 -1
- package/dist/src/core/discard-baseline.js +18 -4
- package/dist/src/core/engine-precondition.d.ts +35 -0
- package/dist/src/core/engine-precondition.js +50 -0
- package/dist/src/core/engine-session-lock.d.ts +38 -1
- package/dist/src/core/engine-session-lock.js +78 -4
- package/dist/src/core/file-lock.d.ts +7 -0
- package/dist/src/core/file-lock.js +20 -30
- package/dist/src/core/firefox.js +5 -2
- package/dist/src/core/furnace-apply-helpers.d.ts +12 -1
- package/dist/src/core/furnace-apply-helpers.js +12 -3
- package/dist/src/core/furnace-apply-output.js +9 -0
- package/dist/src/core/furnace-apply-overwrite-warn.d.ts +63 -0
- package/dist/src/core/furnace-apply-overwrite-warn.js +123 -0
- package/dist/src/core/furnace-apply-undeploy-actions.d.ts +11 -0
- package/dist/src/core/furnace-apply-undeploy-actions.js +49 -0
- package/dist/src/core/furnace-apply.d.ts +16 -4
- package/dist/src/core/furnace-apply.js +39 -43
- package/dist/src/core/furnace-config.js +2 -0
- package/dist/src/core/furnace-css-fragments.js +2 -0
- package/dist/src/core/furnace-jsconfig.js +14 -7
- package/dist/src/core/furnace-registration-ast.js +8 -8
- package/dist/src/core/furnace-registration-remove.js +6 -3
- package/dist/src/core/furnace-registration.js +9 -12
- package/dist/src/core/furnace-rollback.js +1 -1
- package/dist/src/core/furnace-scanner.js +2 -1
- package/dist/src/core/furnace-stale-export.js +2 -1
- package/dist/src/core/furnace-state-persist.d.ts +4 -6
- package/dist/src/core/furnace-validate-compatibility.js +4 -7
- package/dist/src/core/furnace-validate-helpers.js +33 -1
- package/dist/src/core/furnace-validate-registration.js +16 -0
- package/dist/src/core/furnace-validate.js +4 -2
- package/dist/src/core/git-diff.js +37 -2
- package/dist/src/core/lint-cache.d.ts +1 -1
- package/dist/src/core/lint-cache.js +33 -10
- package/dist/src/core/mach-build-artifacts.d.ts +63 -1
- package/dist/src/core/mach-build-artifacts.js +108 -2
- package/dist/src/core/mach-mozconfig.js +9 -1
- package/dist/src/core/mach-resource-shim.js +1 -0
- package/dist/src/core/marionette-port.d.ts +16 -0
- package/dist/src/core/marionette-port.js +93 -8
- package/dist/src/core/marionette-preflight.js +6 -5
- package/dist/src/core/patch-apply.d.ts +20 -13
- package/dist/src/core/patch-apply.js +32 -33
- package/dist/src/core/patch-export.js +3 -5
- package/dist/src/core/patch-lint-checkjs.d.ts +25 -3
- package/dist/src/core/patch-lint-checkjs.js +78 -7
- package/dist/src/core/patch-lint-chrome-jsdoc.js +9 -0
- package/dist/src/core/patch-lint-creators.d.ts +30 -0
- package/dist/src/core/patch-lint-creators.js +45 -0
- package/dist/src/core/patch-lint-cross.d.ts +1 -17
- package/dist/src/core/patch-lint-cross.js +16 -32
- package/dist/src/core/patch-lint-jsdoc.d.ts +3 -1
- package/dist/src/core/patch-lint-jsdoc.js +15 -5
- package/dist/src/core/patch-lint-module-registration.d.ts +15 -0
- package/dist/src/core/patch-lint-module-registration.js +88 -0
- package/dist/src/core/patch-lint-mozbuild.js +99 -11
- package/dist/src/core/patch-lint-reexports.d.ts +1 -0
- package/dist/src/core/patch-lint-reexports.js +1 -0
- package/dist/src/core/patch-lint.d.ts +8 -0
- package/dist/src/core/patch-lint.js +84 -6
- package/dist/src/core/patch-lock.d.ts +12 -1
- package/dist/src/core/patch-lock.js +40 -4
- package/dist/src/core/patch-manifest-consistency.js +15 -3
- package/dist/src/core/patch-parse.d.ts +8 -0
- package/dist/src/core/patch-parse.js +10 -0
- package/dist/src/core/patch-policy.d.ts +7 -0
- package/dist/src/core/patch-policy.js +4 -1
- package/dist/src/core/patch-transform.d.ts +10 -0
- package/dist/src/core/patch-transform.js +13 -2
- package/dist/src/core/rebase-session.d.ts +44 -2
- package/dist/src/core/rebase-session.js +114 -17
- package/dist/src/core/register-browser-content.js +2 -1
- package/dist/src/core/register-shared-css.js +2 -1
- package/dist/src/core/smoke-patterns.d.ts +0 -8
- package/dist/src/core/smoke-patterns.js +3 -2
- package/dist/src/core/status-binary.d.ts +55 -0
- package/dist/src/core/status-binary.js +124 -0
- package/dist/src/core/status-classify.d.ts +6 -1
- package/dist/src/core/status-classify.js +101 -73
- package/dist/src/core/test-harness-crash.d.ts +32 -1
- package/dist/src/core/test-harness-crash.js +59 -4
- package/dist/src/core/test-path-scope.js +2 -0
- package/dist/src/core/test-stale-check.js +1 -20
- package/dist/src/core/toolchain-preflight.js +24 -26
- package/dist/src/core/tree-guard.d.ts +1 -1
- package/dist/src/core/tree-guard.js +67 -12
- package/dist/src/core/tree-store.d.ts +86 -10
- package/dist/src/core/tree-store.js +310 -72
- package/dist/src/core/typecheck.js +2 -1
- package/dist/src/core/wire-destroy.js +14 -3
- package/dist/src/core/wire-init.js +37 -40
- package/dist/src/core/wire-subscript.js +11 -3
- package/dist/src/core/wire-utils.js +4 -4
- package/dist/src/core/xpcshell-appdir.js +3 -0
- package/dist/src/errors/base.d.ts +13 -0
- package/dist/src/errors/base.js +13 -0
- package/dist/src/errors/rebase.d.ts +13 -0
- package/dist/src/errors/rebase.js +17 -0
- package/dist/src/types/commands/options.d.ts +86 -1
- package/dist/src/types/commands/patches.d.ts +8 -0
- package/dist/src/types/furnace.d.ts +7 -0
- package/dist/src/utils/build-info.d.ts +31 -0
- package/dist/src/utils/build-info.js +98 -0
- package/dist/src/utils/concurrency.d.ts +8 -0
- package/dist/src/utils/concurrency.js +21 -0
- package/dist/src/utils/errors.d.ts +39 -0
- package/dist/src/utils/errors.js +55 -0
- package/dist/src/utils/fs.js +5 -12
- package/dist/src/utils/logger.d.ts +14 -2
- package/dist/src/utils/logger.js +43 -13
- package/dist/src/utils/options.d.ts +21 -4
- package/dist/src/utils/options.js +26 -6
- package/dist/src/utils/package-root.js +7 -4
- package/dist/src/utils/process-group.js +13 -2
- package/dist/src/utils/stdio-drain.d.ts +28 -0
- package/dist/src/utils/stdio-drain.js +54 -0
- package/dist/src/utils/validation.d.ts +23 -2
- package/dist/src/utils/validation.js +29 -3
- package/package.json +9 -9
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/**
|
|
3
|
+
* Per-run checkJs program controller, shared by `lint --per-patch` and
|
|
4
|
+
* `re-export` (FORGE J1).
|
|
5
|
+
*
|
|
6
|
+
* The dominant fixed cost of patch lint is one `ts.createProgram` over the
|
|
7
|
+
* queue's patch-owned `.sys.mjs` files (~37 s on a 290-patch consumer
|
|
8
|
+
* queue). This controller builds that program at most ONCE per command
|
|
9
|
+
* invocation (lazily, promise-memoised) and lets callers slice per-patch
|
|
10
|
+
* findings out of the grouped result. Three levers keep the cost paid only
|
|
11
|
+
* when it buys something:
|
|
12
|
+
*
|
|
13
|
+
* - **Lazy build**: nothing is built until the first cache miss asks.
|
|
14
|
+
* - **Root scoping** (`rootScopePatches`): with `--patches <subset>` the
|
|
15
|
+
* program's roots are only the subset's owned files; the full queue
|
|
16
|
+
* stays resolvable, so cross-patch imports type-check identically while
|
|
17
|
+
* unrelated files are never parsed (FORGE J1c).
|
|
18
|
+
* - **Warm-run probe**: run-level ("global") checkJs findings come only
|
|
19
|
+
* from a missing `typescript` package or an unreadable shim — never
|
|
20
|
+
* from the built program — so an all-cache-hit run satisfies "warm
|
|
21
|
+
* never reports less than cold" (FORGE F5) via
|
|
22
|
+
* `probeCheckJsGlobalIssues` instead of building anything.
|
|
23
|
+
*/
|
|
24
|
+
import { invokePatchLintCheckJsGrouped, probeCheckJsGlobalIssues, runCheckJsTestFilesGrouped, } from '../core/patch-lint-checkjs.js';
|
|
25
|
+
import { isTestScriptFile, resolvePatchOwnedSysMjs, resolvePatchOwnedTestScripts, } from '../core/patch-lint-ownership.js';
|
|
26
|
+
/**
|
|
27
|
+
* Builds the per-run checkJs program controller when `patchLint.checkJs` is
|
|
28
|
+
* enabled, or returns undefined. With `rootScopePatches` set (the
|
|
29
|
+
* `--patches` subset, by patch filename), the program roots at only the
|
|
30
|
+
* subset's owned files and the test-file pass runs only the subset's own
|
|
31
|
+
* scripts (head.js discovery still spans the queue).
|
|
32
|
+
*/
|
|
33
|
+
export function buildPerRunCheckJs(projectRoot, paths, config, ctx, rootScopePatches) {
|
|
34
|
+
const patchLint = config.patchLint;
|
|
35
|
+
if (!patchLint?.checkJs)
|
|
36
|
+
return undefined;
|
|
37
|
+
const testFilesEnabled = patchLint.checkJsTestFiles === true;
|
|
38
|
+
const ownedByPatch = new Map();
|
|
39
|
+
for (const entry of ctx.entries) {
|
|
40
|
+
const owned = new Set();
|
|
41
|
+
for (const f of entry.newFiles.keys()) {
|
|
42
|
+
if (f.endsWith('.sys.mjs'))
|
|
43
|
+
owned.add(f);
|
|
44
|
+
else if (testFilesEnabled && isTestScriptFile(f))
|
|
45
|
+
owned.add(f);
|
|
46
|
+
}
|
|
47
|
+
if (owned.size > 0)
|
|
48
|
+
ownedByPatch.set(entry.filename, owned);
|
|
49
|
+
}
|
|
50
|
+
const resolutionSet = new Set();
|
|
51
|
+
for (const files of ownedByPatch.values()) {
|
|
52
|
+
for (const f of files)
|
|
53
|
+
resolutionSet.add(f);
|
|
54
|
+
}
|
|
55
|
+
// The subset's owned files, split by program kind; undefined = full queue.
|
|
56
|
+
let scopedRoots;
|
|
57
|
+
if (rootScopePatches !== undefined) {
|
|
58
|
+
scopedRoots = new Set();
|
|
59
|
+
for (const [patchFilename, files] of ownedByPatch) {
|
|
60
|
+
if (!rootScopePatches.has(patchFilename))
|
|
61
|
+
continue;
|
|
62
|
+
for (const f of files)
|
|
63
|
+
scopedRoots.add(f);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// One build for the whole run: the queue-wide `.sys.mjs` program plus —
|
|
67
|
+
// when `patchLint.checkJsTestFiles` is on (FORGE G5) — one small
|
|
68
|
+
// script-scope program per patch-owned test file, merged by file.
|
|
69
|
+
const buildAll = async () => {
|
|
70
|
+
const sys = await invokePatchLintCheckJsGrouped(paths.engine, resolvePatchOwnedSysMjs(new Set(), ctx), patchLint, projectRoot, scopedRoots);
|
|
71
|
+
if (!testFilesEnabled)
|
|
72
|
+
return sys;
|
|
73
|
+
const tests = await runCheckJsTestFilesGrouped(paths.engine, resolvePatchOwnedTestScripts(new Set(), ctx), patchLint, projectRoot, scopedRoots);
|
|
74
|
+
const byFile = new Map(sys.byFile);
|
|
75
|
+
for (const [rel, list] of tests.byFile) {
|
|
76
|
+
byFile.set(rel, [...(byFile.get(rel) ?? []), ...list]);
|
|
77
|
+
}
|
|
78
|
+
return { byFile, global: [...sys.global, ...tests.global] };
|
|
79
|
+
};
|
|
80
|
+
// Memoise the *promise*, not the resolved value: under the bounded pool
|
|
81
|
+
// several patches can reach `getGrouped` before the first build resolves, and
|
|
82
|
+
// `??=` on the promise (a synchronous expression) guarantees a single build.
|
|
83
|
+
let groupedPromise;
|
|
84
|
+
const getGrouped = () => (groupedPromise ??= buildAll());
|
|
85
|
+
return {
|
|
86
|
+
ownedByPatch,
|
|
87
|
+
resolutionSet,
|
|
88
|
+
getGrouped,
|
|
89
|
+
getGlobal: async () => groupedPromise !== undefined
|
|
90
|
+
? (await groupedPromise).global
|
|
91
|
+
: probeCheckJsGlobalIssues(patchLint, projectRoot),
|
|
92
|
+
sliceFor: async (files) => {
|
|
93
|
+
const grouped = await getGrouped();
|
|
94
|
+
const issues = [];
|
|
95
|
+
for (const rel of files) {
|
|
96
|
+
issues.push(...(grouped.byFile.get(rel) ?? []));
|
|
97
|
+
}
|
|
98
|
+
return issues;
|
|
99
|
+
},
|
|
100
|
+
isRelevant: (file) => file.endsWith('.sys.mjs') || (testFilesEnabled && isTestScriptFile(file)),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -10,7 +10,7 @@ import { getAllDiff, getDiffForFilesAgainstHead } from '../core/git-diff.js';
|
|
|
10
10
|
import { expandUntrackedDirectoryEntries, getModifiedFilesInDir, getUntrackedFiles, getUntrackedFilesInDir, getWorkingTreeStatus, } from '../core/git-status.js';
|
|
11
11
|
import { clearPerPatchLintCache } from '../core/lint-cache.js';
|
|
12
12
|
import { extractAffectedFiles } from '../core/patch-apply.js';
|
|
13
|
-
import { buildPatchQueueContext, countNonBinaryDiffLines, lintExportedPatch, lintPatchQueue, lintPatchSize, } from '../core/patch-lint.js';
|
|
13
|
+
import { buildPatchQueueContext, countNonBinaryDiffLines, formatPatchLintIssue, lintExportedPatch, lintPatchQueue, lintPatchSize, } from '../core/patch-lint.js';
|
|
14
14
|
import { collectDiffFilePaths, tagLintIssues } from '../core/patch-lint-diff-tag.js';
|
|
15
15
|
import { GeneralError } from '../errors/base.js';
|
|
16
16
|
import { pathExists } from '../utils/fs.js';
|
|
@@ -361,13 +361,13 @@ async function reportLintOutcome(engineDir, issues, options) {
|
|
|
361
361
|
const notices = issues.filter((i) => i.severity === 'notice');
|
|
362
362
|
const tagPrefix = (issue) => sinceActive && issue.tag ? `[${issue.tag}] ` : '';
|
|
363
363
|
for (const issue of notices) {
|
|
364
|
-
info(`${tagPrefix(issue)}NOTICE
|
|
364
|
+
info(`${tagPrefix(issue)}NOTICE ${formatPatchLintIssue(issue)}`);
|
|
365
365
|
}
|
|
366
366
|
for (const issue of warnings) {
|
|
367
|
-
warn(`${tagPrefix(issue)}
|
|
367
|
+
warn(`${tagPrefix(issue)}${formatPatchLintIssue(issue)}`);
|
|
368
368
|
}
|
|
369
369
|
for (const issue of errors) {
|
|
370
|
-
warn(`${tagPrefix(issue)}ERROR
|
|
370
|
+
warn(`${tagPrefix(issue)}ERROR ${formatPatchLintIssue(issue)}`);
|
|
371
371
|
}
|
|
372
372
|
if (sinceActive) {
|
|
373
373
|
const introducedErrors = errors.filter((i) => i.tag === 'introduced').length;
|
|
@@ -11,7 +11,7 @@ import { registerImport } from './import.js';
|
|
|
11
11
|
import { registerLint } from './lint.js';
|
|
12
12
|
import { registerPackage } from './package.js';
|
|
13
13
|
import { registerPatch } from './patch/index.js';
|
|
14
|
-
import { registerReExport } from './re-export.js';
|
|
14
|
+
import { registerReExport } from './re-export-register.js';
|
|
15
15
|
import { registerRebase } from './rebase.js';
|
|
16
16
|
import { registerRegister } from './register.js';
|
|
17
17
|
import { registerReset } from './reset.js';
|
|
@@ -3,10 +3,11 @@ import { Command } from 'commander';
|
|
|
3
3
|
import { validateBrandOverride } from '../core/brand-validation.js';
|
|
4
4
|
import { prepareBuildEnvironment } from '../core/build-prepare.js';
|
|
5
5
|
import { getProjectPaths, loadConfig } from '../core/config.js';
|
|
6
|
-
import {
|
|
6
|
+
import { hasBuildArtifacts, machPackageCapture } from '../core/mach.js';
|
|
7
|
+
import { assertBuildArtifacts } from '../core/mach-build-artifacts.js';
|
|
7
8
|
import { explainMachError } from '../core/mach-error-hints.js';
|
|
8
9
|
import { GeneralError } from '../errors/base.js';
|
|
9
|
-
import {
|
|
10
|
+
import { BuildError } from '../errors/build.js';
|
|
10
11
|
import { pathExists } from '../utils/fs.js';
|
|
11
12
|
import { error, info, intro, outro, verbose } from '../utils/logger.js';
|
|
12
13
|
import { pickDefined } from '../utils/options.js';
|
|
@@ -27,20 +28,12 @@ export async function packageCommand(projectRoot, options) {
|
|
|
27
28
|
throw new GeneralError('Firefox source not found. Run "fireforge download" first.');
|
|
28
29
|
}
|
|
29
30
|
const buildCheck = await hasBuildArtifacts(paths.engine);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
if (!buildCheck.exists) {
|
|
38
|
-
const detail = buildCheck.objDir
|
|
39
|
-
? `Build artifacts incomplete in ${buildCheck.objDir}/`
|
|
40
|
-
: 'No build artifacts found (obj-*/ directory missing)';
|
|
41
|
-
throw new GeneralError(`Packaging requires a completed build. ${detail}\n\n` +
|
|
42
|
-
"Run 'fireforge build' first, then rerun 'fireforge package'.");
|
|
43
|
-
}
|
|
31
|
+
assertBuildArtifacts(paths.engine, buildCheck, {
|
|
32
|
+
label: 'Package',
|
|
33
|
+
requirement: 'Packaging requires a completed build.',
|
|
34
|
+
remediation: "Run 'fireforge build' first, then rerun 'fireforge package'.",
|
|
35
|
+
requireExisting: true,
|
|
36
|
+
});
|
|
44
37
|
// Log brand info if specified
|
|
45
38
|
if (options.brand) {
|
|
46
39
|
verbose(`Packaging with brand: ${options.brand}`);
|
|
@@ -18,7 +18,7 @@ import { applyRenameMapToManifest, enforcePatchPolicy } from '../../core/patch-p
|
|
|
18
18
|
import { GeneralError } from '../../errors/base.js';
|
|
19
19
|
import { toError } from '../../utils/errors.js';
|
|
20
20
|
import { info, intro, outro, warn } from '../../utils/logger.js';
|
|
21
|
-
import { pickDefined } from '../../utils/options.js';
|
|
21
|
+
import { addWaitLockOption, pickDefined, resolveWaitLockSeconds } from '../../utils/options.js';
|
|
22
22
|
import { requirePatchQueue } from './patch-context.js';
|
|
23
23
|
import { rebuildFilenameForOrder } from './reorder.js';
|
|
24
24
|
/** True when `order` falls inside a configured reserved range. */
|
|
@@ -185,7 +185,7 @@ export async function patchCompactCommand(projectRoot, options = {}) {
|
|
|
185
185
|
catch (historyError) {
|
|
186
186
|
warn(`History log append failed after patch compact committed: ${toError(historyError).message}`);
|
|
187
187
|
}
|
|
188
|
-
});
|
|
188
|
+
}, { waitLockSeconds: resolveWaitLockSeconds(options.waitLock), command: 'patch compact' });
|
|
189
189
|
info(`Compacted ${renameMap.size} patch(es).`);
|
|
190
190
|
outro('Compact complete');
|
|
191
191
|
}
|
|
@@ -197,13 +197,13 @@ export async function patchCompactCommand(projectRoot, options = {}) {
|
|
|
197
197
|
*/
|
|
198
198
|
export function registerPatchCompact(parent, context) {
|
|
199
199
|
const { getProjectRoot, withErrorHandling } = context;
|
|
200
|
-
parent
|
|
200
|
+
const command = parent
|
|
201
201
|
.command('compact')
|
|
202
202
|
.description('Close ordinal gaps in the patch queue (range-aware when patchPolicy.ranges is configured)')
|
|
203
203
|
.option('--dry-run', 'Show what would happen without writing')
|
|
204
204
|
.option('-y, --yes', 'Skip confirmation prompt (required for non-TTY)')
|
|
205
|
-
.option('--force-unsafe', 'Bypass force-mode patchPolicy refusals')
|
|
206
|
-
|
|
205
|
+
.option('--force-unsafe', 'Bypass force-mode patchPolicy refusals');
|
|
206
|
+
addWaitLockOption(command).action(withErrorHandling(async (options) => {
|
|
207
207
|
await patchCompactCommand(getProjectRoot(), pickDefined(options));
|
|
208
208
|
}));
|
|
209
209
|
}
|
|
@@ -15,7 +15,7 @@ import { withPatchDirectoryLock } from '../../core/patch-lock.js';
|
|
|
15
15
|
import { removePatchFileAndManifest } from '../../core/patch-manifest.js';
|
|
16
16
|
import { toError } from '../../utils/errors.js';
|
|
17
17
|
import { info, intro, outro, warn } from '../../utils/logger.js';
|
|
18
|
-
import { pickDefined } from '../../utils/options.js';
|
|
18
|
+
import { addWaitLockOption, pickDefined, resolveWaitLockSeconds } from '../../utils/options.js';
|
|
19
19
|
import { requirePatchQueue, requirePatchTarget } from './patch-context.js';
|
|
20
20
|
/**
|
|
21
21
|
* Runs the `patch delete` command: removes a patch file and its manifest
|
|
@@ -181,7 +181,7 @@ export async function patchDeleteCommand(projectRoot, identifier, options = {})
|
|
|
181
181
|
catch (historyError) {
|
|
182
182
|
warn(`History log append failed after patch delete committed (${target.filename}): ${toError(historyError).message}`);
|
|
183
183
|
}
|
|
184
|
-
});
|
|
184
|
+
}, { waitLockSeconds: resolveWaitLockSeconds(options.waitLock), command: 'patch delete' });
|
|
185
185
|
info(`Deleted ${target.filename}.`);
|
|
186
186
|
outro('Delete complete');
|
|
187
187
|
}
|
|
@@ -193,13 +193,13 @@ export async function patchDeleteCommand(projectRoot, identifier, options = {})
|
|
|
193
193
|
*/
|
|
194
194
|
export function registerPatchDelete(parent, context) {
|
|
195
195
|
const { getProjectRoot, withErrorHandling } = context;
|
|
196
|
-
parent
|
|
196
|
+
const command = parent
|
|
197
197
|
.command('delete <name>')
|
|
198
198
|
.description('Delete a patch from the queue (destructive)')
|
|
199
199
|
.option('--dry-run', 'Show what would happen without writing')
|
|
200
200
|
.option('-y, --yes', 'Skip confirmation prompt (required for non-TTY)')
|
|
201
|
-
.option('--force-unsafe', 'Bypass the refusal when a later patch depends on this patch (last resort)')
|
|
202
|
-
|
|
201
|
+
.option('--force-unsafe', 'Bypass the refusal when a later patch depends on this patch (last resort)');
|
|
202
|
+
addWaitLockOption(command).action(withErrorHandling(async (name, options) => {
|
|
203
203
|
await patchDeleteCommand(getProjectRoot(), name, pickDefined(options));
|
|
204
204
|
}));
|
|
205
205
|
}
|
|
@@ -25,6 +25,7 @@ import { mutatePatchMetadata } from '../../core/patch-export.js';
|
|
|
25
25
|
import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
26
26
|
import { toError } from '../../utils/errors.js';
|
|
27
27
|
import { info, intro, outro, warn } from '../../utils/logger.js';
|
|
28
|
+
import { stringListOption } from '../../utils/options.js';
|
|
28
29
|
import { requirePatchQueue, requirePatchTarget } from './patch-context.js';
|
|
29
30
|
/**
|
|
30
31
|
* Printed whenever `--add` lands a new check id. The waiver this command
|
|
@@ -197,8 +198,8 @@ export function registerPatchLintIgnore(parent, context) {
|
|
|
197
198
|
parent
|
|
198
199
|
.command('lint-ignore <name>')
|
|
199
200
|
.description('Edit PatchMetadata.lintIgnore on a single patch (no .patch body rewrite). One mode per invocation.')
|
|
200
|
-
.option('--add <check-id>', 'Lint check ID to add to the patch lintIgnore list (repeatable)', (
|
|
201
|
-
.option('--remove <check-id>', 'Lint check ID to remove from the patch lintIgnore list (repeatable)', (
|
|
201
|
+
.option('--add <check-id>', 'Lint check ID to add to the patch lintIgnore list (repeatable)', ...stringListOption())
|
|
202
|
+
.option('--remove <check-id>', 'Lint check ID to remove from the patch lintIgnore list (repeatable)', ...stringListOption())
|
|
202
203
|
.option('--clear', 'Drop the lintIgnore field entirely')
|
|
203
204
|
.option('--dry-run', 'Show what would change without writing')
|
|
204
205
|
.option('-y, --yes', 'Skip confirmation prompt (required for non-TTY)')
|
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
import { getProjectPaths, loadConfig } from '../../core/config.js';
|
|
14
14
|
import { confirmDestructive } from '../../core/destructive.js';
|
|
15
15
|
import { formatPatchNotFoundError } from '../../core/patch-identifier-suggest.js';
|
|
16
|
+
import { buildPatchQueueContext } from '../../core/patch-lint.js';
|
|
16
17
|
import { loadPatchesManifest, resolvePatchIdentifier } from '../../core/patch-manifest.js';
|
|
17
18
|
import { enforcePatchPolicy } from '../../core/patch-policy.js';
|
|
18
19
|
import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
19
20
|
import { info, intro, outro, success } from '../../utils/logger.js';
|
|
21
|
+
import { normalizePatchDisplayName } from '../../utils/validation.js';
|
|
20
22
|
import { resolvePlacementPlan } from '../export-flow.js';
|
|
21
23
|
import { runPatchLint } from '../export-shared.js';
|
|
22
24
|
import { commitPatchSplit } from './split.js';
|
|
@@ -60,6 +62,13 @@ export async function patchMoveFilesCreateCommand(projectRoot, fromIdentifier, n
|
|
|
60
62
|
const category = options.category ?? source.category;
|
|
61
63
|
const placementOptions = { order: options.order };
|
|
62
64
|
const placement = await resolvePlacementPlan(paths.patches, placementOptions, category, newPatchName, config);
|
|
65
|
+
// The filename slug pipeline (resolvePlacementPlan above) strips redundant
|
|
66
|
+
// category prefixes; the manifest display name must agree with the bare-slug
|
|
67
|
+
// naming policy, exactly as `export --name` already does (FORGE G13/H4).
|
|
68
|
+
const displayName = normalizePatchDisplayName(newPatchName, category);
|
|
69
|
+
if (displayName !== newPatchName) {
|
|
70
|
+
info(`Patch name normalized: "${newPatchName}" → "${displayName}" (the filename carries the order and category prefix).`);
|
|
71
|
+
}
|
|
63
72
|
const plan = {
|
|
64
73
|
source,
|
|
65
74
|
movedFiles,
|
|
@@ -69,7 +78,7 @@ export async function patchMoveFilesCreateCommand(projectRoot, fromIdentifier, n
|
|
|
69
78
|
placement,
|
|
70
79
|
placementOptions,
|
|
71
80
|
category,
|
|
72
|
-
name:
|
|
81
|
+
name: displayName,
|
|
73
82
|
description: options.description ?? '',
|
|
74
83
|
ownerRewrites: findOwnerRewriteHolders(manifest.patches, source.filename, movedSet),
|
|
75
84
|
// Populated by runProjectedSplitLint below (forward edges into the new patch).
|
|
@@ -77,10 +86,16 @@ export async function patchMoveFilesCreateCommand(projectRoot, fromIdentifier, n
|
|
|
77
86
|
};
|
|
78
87
|
// Per-patch lint both projected bodies, threading the source patch's
|
|
79
88
|
// tier/lintIgnore so an intentional-advisory patch can still move files.
|
|
89
|
+
// The whole-queue context (built once, with the config so it carries the
|
|
90
|
+
// same patch-policy shape as the committed `lint --per-patch` gate) makes
|
|
91
|
+
// cross-patch `resource:///` imports and sibling head.js harness roots
|
|
92
|
+
// resolve exactly as they will after the move lands — without it the
|
|
93
|
+
// projection lint was blind (FORGE I3).
|
|
94
|
+
const patchQueueCtx = await buildPatchQueueContext(paths.patches, config);
|
|
80
95
|
const ignoreChecks = source.lintIgnore ? new Set(source.lintIgnore) : undefined;
|
|
81
|
-
await runPatchLint(paths.engine, remainingFiles, remainingDiff, config, options.skipLint,
|
|
82
|
-
await runPatchLint(paths.engine, movedFiles, movedDiff, config, options.skipLint,
|
|
83
|
-
const { conflicts, stagedDependencyAdditions } =
|
|
96
|
+
await runPatchLint(paths.engine, remainingFiles, remainingDiff, config, options.skipLint, patchQueueCtx, ignoreChecks, source.tier);
|
|
97
|
+
await runPatchLint(paths.engine, movedFiles, movedDiff, config, options.skipLint, patchQueueCtx, ignoreChecks, source.tier);
|
|
98
|
+
const { conflicts, stagedDependencyAdditions } = runProjectedSplitLint(plan, patchQueueCtx);
|
|
84
99
|
plan.stagedDependencyAdditions = stagedDependencyAdditions;
|
|
85
100
|
const newMetadata = buildNewPatchMetadata(plan, config);
|
|
86
101
|
enforcePatchPolicy({
|
|
@@ -88,6 +103,9 @@ export async function patchMoveFilesCreateCommand(projectRoot, fromIdentifier, n
|
|
|
88
103
|
manifest: projectSplitManifest(manifest, plan, newMetadata),
|
|
89
104
|
command: 'patch move-files --create',
|
|
90
105
|
forceUnsafe: options.forceUnsafe === true,
|
|
106
|
+
hints: {
|
|
107
|
+
'description-required': 'Pass --description "<text>" (or -d) on this command to set the created patch\'s description.',
|
|
108
|
+
},
|
|
91
109
|
});
|
|
92
110
|
const decision = await confirmDestructive({
|
|
93
111
|
operation: 'patch-move-files-create',
|
|
@@ -18,7 +18,7 @@ import { join } from 'node:path';
|
|
|
18
18
|
import { appendHistory, confirmDestructive } from '../../core/destructive.js';
|
|
19
19
|
import { computeProjectedLintRegressions } from '../../core/lint-projection.js';
|
|
20
20
|
import { normalizePatchArtifact } from '../../core/patch-artifact-normalize.js';
|
|
21
|
-
import { buildModifiedFileAdditionsFromDiff, buildPatchQueueContext, collectForwardImportEdges, detectNewFilesInDiff, lintPatchQueue, } from '../../core/patch-lint.js';
|
|
21
|
+
import { buildModifiedFileAdditionsFromDiff, buildPatchQueueContext, collectForwardImportEdges, detectNewFilesInDiff, formatPatchLintIssue, lintPatchQueue, } from '../../core/patch-lint.js';
|
|
22
22
|
import { withPatchDirectoryLock } from '../../core/patch-lock.js';
|
|
23
23
|
import { loadPatchesManifest, savePatchesManifest, validatePatchesManifest, } from '../../core/patch-manifest.js';
|
|
24
24
|
import { extractNewFileContentFromDiff } from '../../core/patch-transform.js';
|
|
@@ -26,6 +26,7 @@ import { GeneralError, InvalidArgumentError } from '../../errors/base.js';
|
|
|
26
26
|
import { toError } from '../../utils/errors.js';
|
|
27
27
|
import { readText, writeText } from '../../utils/fs.js';
|
|
28
28
|
import { info, outro, success, warn } from '../../utils/logger.js';
|
|
29
|
+
import { resolveWaitLockSeconds } from '../../utils/options.js';
|
|
29
30
|
import { runPatchLint } from '../export-shared.js';
|
|
30
31
|
import { buildSplitDiff, findOwnerRewriteHolders, mergeStagedForwardImports, rewriteSplitOwners, } from './split-plan.js';
|
|
31
32
|
function projectEntryBody(diff) {
|
|
@@ -41,9 +42,8 @@ function projectEntryBody(diff) {
|
|
|
41
42
|
* to live in the same patch as the moved file gains a forward edge when the
|
|
42
43
|
* target is later-ordered). Reports only regressions the move itself adds.
|
|
43
44
|
*/
|
|
44
|
-
|
|
45
|
+
function runProjectedMoveLint(plan, baseCtx) {
|
|
45
46
|
const movedSet = new Set(plan.movedFiles);
|
|
46
|
-
const baseCtx = await buildPatchQueueContext(patchesDir);
|
|
47
47
|
const entries = baseCtx.entries.map((entry) => {
|
|
48
48
|
let metadata = entry.metadata;
|
|
49
49
|
if (metadata) {
|
|
@@ -93,7 +93,7 @@ async function runProjectedMoveLint(patchesDir, plan) {
|
|
|
93
93
|
? null
|
|
94
94
|
: {
|
|
95
95
|
reason: `move would introduce ${regressions.length} cross-patch lint error(s)`,
|
|
96
|
-
details: regressions.map(
|
|
96
|
+
details: regressions.map(formatPatchLintIssue),
|
|
97
97
|
};
|
|
98
98
|
return { conflicts, stagedDependencyAdditions };
|
|
99
99
|
}
|
|
@@ -103,7 +103,7 @@ async function runProjectedMoveLint(patchesDir, plan) {
|
|
|
103
103
|
* owner rewrites + auto-declared forward imports). Rolled back in reverse
|
|
104
104
|
* order on any failure.
|
|
105
105
|
*/
|
|
106
|
-
async function commitMoveInto(patchesDir, plan) {
|
|
106
|
+
async function commitMoveInto(patchesDir, plan, waitLockSeconds) {
|
|
107
107
|
await withPatchDirectoryLock(patchesDir, async () => {
|
|
108
108
|
const manifest = await loadPatchesManifest(patchesDir);
|
|
109
109
|
if (!manifest)
|
|
@@ -184,7 +184,7 @@ async function commitMoveInto(patchesDir, plan) {
|
|
|
184
184
|
}
|
|
185
185
|
throw error;
|
|
186
186
|
}
|
|
187
|
-
});
|
|
187
|
+
}, { waitLockSeconds, command: 'patch move-files' });
|
|
188
188
|
}
|
|
189
189
|
/**
|
|
190
190
|
* Plans, lints, confirms, and commits a file-ownership move into an
|
|
@@ -196,8 +196,12 @@ export async function runMoveFilesInto(args) {
|
|
|
196
196
|
const sourceDiff = await buildSplitDiff(enginePath, sourceAfter, 'remaining', source.filename);
|
|
197
197
|
const targetDiff = await buildSplitDiff(enginePath, targetAfter, 'moved', target.filename);
|
|
198
198
|
// Per-patch lint both projected bodies with each patch's own waivers.
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
// The whole-queue context (built once, with the config for committed-gate
|
|
200
|
+
// parity) resolves cross-patch imports and sibling head.js harness roots
|
|
201
|
+
// instead of linting each projected body blind (FORGE I3).
|
|
202
|
+
const patchQueueCtx = await buildPatchQueueContext(patchesDir, args.config);
|
|
203
|
+
await runPatchLint(enginePath, sourceAfter, sourceDiff, args.config, options.skipLint, patchQueueCtx, source.lintIgnore ? new Set(source.lintIgnore) : undefined, source.tier);
|
|
204
|
+
await runPatchLint(enginePath, targetAfter, targetDiff, args.config, options.skipLint, patchQueueCtx, target.lintIgnore ? new Set(target.lintIgnore) : undefined, target.tier);
|
|
201
205
|
const manifest = await loadPatchesManifest(patchesDir);
|
|
202
206
|
const plan = {
|
|
203
207
|
source,
|
|
@@ -210,7 +214,7 @@ export async function runMoveFilesInto(args) {
|
|
|
210
214
|
ownerRewrites: findOwnerRewriteHolders(manifest?.patches ?? [], source.filename, new Set(files)),
|
|
211
215
|
stagedDependencyAdditions: new Map(),
|
|
212
216
|
};
|
|
213
|
-
const { conflicts, stagedDependencyAdditions } =
|
|
217
|
+
const { conflicts, stagedDependencyAdditions } = runProjectedMoveLint(plan, patchQueueCtx);
|
|
214
218
|
plan.stagedDependencyAdditions = stagedDependencyAdditions;
|
|
215
219
|
const decision = await confirmDestructive({
|
|
216
220
|
operation: 'patch-move-files',
|
|
@@ -236,7 +240,7 @@ export async function runMoveFilesInto(args) {
|
|
|
236
240
|
outro('Move cancelled');
|
|
237
241
|
return;
|
|
238
242
|
}
|
|
239
|
-
await commitMoveInto(patchesDir, plan);
|
|
243
|
+
await commitMoveInto(patchesDir, plan, resolveWaitLockSeconds(options.waitLock));
|
|
240
244
|
success(`Moved ${files.length} file(s) from ${source.filename} to ${target.filename}`);
|
|
241
245
|
if (plan.ownerRewrites.length > 0) {
|
|
242
246
|
info(`Re-pointed staged-dependency owners in: ${plan.ownerRewrites.join(', ')}`);
|
|
@@ -13,7 +13,7 @@ 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 { commanderArgParser, pickDefined } from '../../utils/options.js';
|
|
16
|
+
import { addWaitLockOption, commanderArgParser, pickDefined } from '../../utils/options.js';
|
|
17
17
|
import { patchMoveFilesCreateCommand } from './move-files-create.js';
|
|
18
18
|
import { runMoveFilesInto } from './move-files-into.js';
|
|
19
19
|
function collectOption(value, previous) {
|
|
@@ -161,7 +161,7 @@ export async function patchMoveFilesCommand(projectRoot, fromIdentifier, toIdent
|
|
|
161
161
|
*/
|
|
162
162
|
export function registerPatchMoveFiles(parent, context) {
|
|
163
163
|
const { getProjectRoot, withErrorHandling } = context;
|
|
164
|
-
parent
|
|
164
|
+
const command = parent
|
|
165
165
|
.command('move-files <from> <to>')
|
|
166
166
|
.description('Preview the re-export commands needed to move file ownership between patches, ' +
|
|
167
167
|
'or create the target patch and move the files in one transaction with --create --order <n>.')
|
|
@@ -175,12 +175,12 @@ export function registerPatchMoveFiles(parent, context) {
|
|
|
175
175
|
return n;
|
|
176
176
|
}))
|
|
177
177
|
.option('--category <category>', "Category for the created patch (default: the source patch's)")
|
|
178
|
-
.option('--description <desc>', 'Description for the created patch')
|
|
178
|
+
.option('-d, --description <desc>', 'Description for the created patch')
|
|
179
179
|
.option('--dry-run', 'Show what would happen without writing')
|
|
180
180
|
.option('-y, --yes', 'Skip confirmation prompt (required for non-TTY)')
|
|
181
181
|
.option('--force-unsafe', 'Bypass projected-lint refusals')
|
|
182
|
-
.option('--skip-lint', 'Skip per-patch lint of the projected bodies')
|
|
183
|
-
|
|
182
|
+
.option('--skip-lint', 'Skip per-patch lint of the projected bodies');
|
|
183
|
+
addWaitLockOption(command).action(withErrorHandling(async (from, to, options) => {
|
|
184
184
|
await patchMoveFilesCommand(getProjectRoot(), from, to, {
|
|
185
185
|
...pickDefined({
|
|
186
186
|
file: options.file,
|
|
@@ -192,6 +192,7 @@ export function registerPatchMoveFiles(parent, context) {
|
|
|
192
192
|
yes: options.yes,
|
|
193
193
|
forceUnsafe: options.forceUnsafe,
|
|
194
194
|
skipLint: options.skipLint,
|
|
195
|
+
waitLock: options.waitLock,
|
|
195
196
|
}),
|
|
196
197
|
});
|
|
197
198
|
}));
|
|
@@ -20,11 +20,11 @@ import type { CommandContext } from '../../types/cli.js';
|
|
|
20
20
|
import type { PatchRenameOptions } from '../../types/commands/index.js';
|
|
21
21
|
/**
|
|
22
22
|
* Runs the `patch rename` command: relabels filename + manifest entry
|
|
23
|
-
* for a single patch atomically.
|
|
23
|
+
* (name, category, order, description) for a single patch atomically.
|
|
24
24
|
*
|
|
25
25
|
* @param projectRoot - Project root directory
|
|
26
26
|
* @param identifier - Patch filename, ordinal, or manifest `name`
|
|
27
|
-
* @param options - Command options (
|
|
27
|
+
* @param options - Command options (at least one change flag required)
|
|
28
28
|
*/
|
|
29
29
|
export declare function patchRenameCommand(projectRoot: string, identifier: string, options?: PatchRenameOptions): Promise<void>;
|
|
30
30
|
/**
|