@lumenflow/cli 2.2.1 → 2.3.1
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/README.md +147 -57
- package/dist/__tests__/agent-log-issue.test.js +56 -0
- package/dist/__tests__/cli-entry-point.test.js +66 -17
- package/dist/__tests__/cli-subprocess.test.js +25 -0
- package/dist/__tests__/init.test.js +298 -0
- package/dist/__tests__/initiative-plan.test.js +340 -0
- package/dist/__tests__/mem-cleanup-execution.test.js +19 -0
- package/dist/__tests__/merge-block.test.js +220 -0
- package/dist/__tests__/release.test.js +28 -0
- package/dist/__tests__/safe-git.test.js +191 -0
- package/dist/__tests__/state-doctor.test.js +274 -0
- package/dist/__tests__/wu-done.test.js +36 -0
- package/dist/__tests__/wu-edit.test.js +119 -0
- package/dist/__tests__/wu-prep.test.js +108 -0
- package/dist/agent-issues-query.js +4 -3
- package/dist/agent-log-issue.js +25 -4
- package/dist/backlog-prune.js +5 -4
- package/dist/cli-entry-point.js +11 -1
- package/dist/doctor.js +368 -0
- package/dist/flow-bottlenecks.js +6 -5
- package/dist/flow-report.js +4 -3
- package/dist/gates.js +468 -116
- package/dist/guard-locked.js +4 -3
- package/dist/guard-worktree-commit.js +4 -3
- package/dist/init.js +508 -86
- package/dist/initiative-add-wu.js +4 -3
- package/dist/initiative-bulk-assign-wus.js +8 -5
- package/dist/initiative-create.js +73 -37
- package/dist/initiative-edit.js +37 -21
- package/dist/initiative-list.js +4 -3
- package/dist/initiative-plan.js +337 -0
- package/dist/initiative-status.js +4 -3
- package/dist/lane-health.js +377 -0
- package/dist/lane-suggest.js +382 -0
- package/dist/mem-checkpoint.js +2 -2
- package/dist/mem-cleanup.js +2 -2
- package/dist/mem-context.js +306 -0
- package/dist/mem-create.js +2 -2
- package/dist/mem-delete.js +293 -0
- package/dist/mem-inbox.js +2 -2
- package/dist/mem-index.js +211 -0
- package/dist/mem-init.js +1 -1
- package/dist/mem-profile.js +207 -0
- package/dist/mem-promote.js +254 -0
- package/dist/mem-ready.js +2 -2
- package/dist/mem-signal.js +2 -2
- package/dist/mem-start.js +2 -2
- package/dist/mem-summarize.js +2 -2
- package/dist/mem-triage.js +2 -2
- package/dist/merge-block.js +222 -0
- package/dist/metrics-cli.js +7 -4
- package/dist/metrics-snapshot.js +4 -3
- package/dist/orchestrate-initiative.js +10 -4
- package/dist/orchestrate-monitor.js +379 -31
- package/dist/signal-cleanup.js +296 -0
- package/dist/spawn-list.js +6 -5
- package/dist/state-bootstrap.js +5 -4
- package/dist/state-cleanup.js +360 -0
- package/dist/state-doctor-fix.js +196 -0
- package/dist/state-doctor.js +501 -0
- package/dist/validate-agent-skills.js +4 -3
- package/dist/validate-agent-sync.js +4 -3
- package/dist/validate-backlog-sync.js +7 -84
- package/dist/validate-skills-spec.js +4 -3
- package/dist/validate.js +7 -107
- package/dist/wu-block.js +3 -3
- package/dist/wu-claim.js +208 -98
- package/dist/wu-cleanup.js +5 -4
- package/dist/wu-create.js +71 -46
- package/dist/wu-delete.js +88 -60
- package/dist/wu-deps.js +6 -5
- package/dist/wu-done-check.js +34 -0
- package/dist/wu-done.js +60 -24
- package/dist/wu-edit.js +63 -28
- package/dist/wu-infer-lane.js +7 -6
- package/dist/wu-preflight.js +23 -81
- package/dist/wu-prep.js +125 -0
- package/dist/wu-prune.js +4 -3
- package/dist/wu-recover.js +88 -22
- package/dist/wu-repair.js +7 -6
- package/dist/wu-spawn.js +226 -270
- package/dist/wu-status.js +4 -3
- package/dist/wu-unblock.js +5 -5
- package/dist/wu-unlock-lane.js +4 -3
- package/dist/wu-validate.js +5 -4
- package/package.json +16 -7
- package/templates/core/.lumenflow/constraints.md.template +192 -0
- package/templates/core/.lumenflow/rules/git-safety.md.template +27 -0
- package/templates/core/.lumenflow/rules/wu-workflow.md.template +48 -0
- package/templates/core/AGENTS.md.template +60 -0
- package/templates/core/LUMENFLOW.md.template +255 -0
- package/templates/core/UPGRADING.md.template +121 -0
- package/templates/core/ai/onboarding/agent-safety-card.md.template +106 -0
- package/templates/core/ai/onboarding/first-wu-mistakes.md.template +198 -0
- package/templates/core/ai/onboarding/quick-ref-commands.md.template +186 -0
- package/templates/core/ai/onboarding/release-process.md.template +362 -0
- package/templates/core/ai/onboarding/troubleshooting-wu-done.md.template +159 -0
- package/templates/core/ai/onboarding/wu-create-checklist.md.template +117 -0
- package/templates/vendors/aider/.aider.conf.yml.template +27 -0
- package/templates/vendors/claude/.claude/CLAUDE.md.template +52 -0
- package/templates/vendors/claude/.claude/settings.json.template +49 -0
- package/templates/vendors/claude/.claude/skills/bug-classification/SKILL.md.template +192 -0
- package/templates/vendors/claude/.claude/skills/code-quality/SKILL.md.template +152 -0
- package/templates/vendors/claude/.claude/skills/context-management/SKILL.md.template +155 -0
- package/templates/vendors/claude/.claude/skills/execution-memory/SKILL.md.template +304 -0
- package/templates/vendors/claude/.claude/skills/frontend-design/SKILL.md.template +131 -0
- package/templates/vendors/claude/.claude/skills/initiative-management/SKILL.md.template +164 -0
- package/templates/vendors/claude/.claude/skills/library-first/SKILL.md.template +98 -0
- package/templates/vendors/claude/.claude/skills/lumenflow-gates/SKILL.md.template +87 -0
- package/templates/vendors/claude/.claude/skills/multi-agent-coordination/SKILL.md.template +84 -0
- package/templates/vendors/claude/.claude/skills/ops-maintenance/SKILL.md.template +254 -0
- package/templates/vendors/claude/.claude/skills/orchestration/SKILL.md.template +189 -0
- package/templates/vendors/claude/.claude/skills/tdd-workflow/SKILL.md.template +139 -0
- package/templates/vendors/claude/.claude/skills/worktree-discipline/SKILL.md.template +138 -0
- package/templates/vendors/claude/.claude/skills/wu-lifecycle/SKILL.md.template +106 -0
- package/templates/vendors/cline/.clinerules.template +53 -0
- package/templates/vendors/cursor/.cursor/rules/lumenflow.md.template +34 -0
- package/templates/vendors/cursor/.cursor/rules.md.template +28 -0
- package/templates/vendors/windsurf/.windsurf/rules/lumenflow.md.template +34 -0
package/dist/wu-done.js
CHANGED
|
@@ -31,10 +31,16 @@
|
|
|
31
31
|
* WU-2542: This script imports utilities from @lumenflow/core package.
|
|
32
32
|
* Full migration to thin shim pending @lumenflow/core CLI export implementation.
|
|
33
33
|
*/
|
|
34
|
+
// WU-1153: wu:done guard for uncommitted code_paths is implemented in core package
|
|
35
|
+
// The guard runs in executeWorktreeCompletion() before metadata transaction
|
|
36
|
+
// See: packages/@lumenflow/core/src/wu-done-validation.ts
|
|
34
37
|
import { execSync } from 'node:child_process';
|
|
35
38
|
import prettyMs from 'pretty-ms';
|
|
39
|
+
import { runGates } from './gates.js';
|
|
36
40
|
import { getGitForCwd } from '@lumenflow/core/dist/git-adapter.js';
|
|
37
41
|
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
42
|
+
// WU-1223: Location detection for worktree check
|
|
43
|
+
import { resolveLocation } from '@lumenflow/core/dist/context/location-resolver.js';
|
|
38
44
|
import { existsSync, readFileSync, mkdirSync, appendFileSync, unlinkSync, statSync } from 'node:fs';
|
|
39
45
|
import path from 'node:path';
|
|
40
46
|
// WU-1825: Import from unified code-path-validator (consolidates 3 validators)
|
|
@@ -53,7 +59,9 @@ validateAllPreCommitHooks,
|
|
|
53
59
|
validateTypeVsCodePathsPreflight, buildTypeVsCodePathsErrorMessage, } from '@lumenflow/core/dist/wu-done-validators.js';
|
|
54
60
|
// WU-1825: validateCodePathsExist moved to unified code-path-validator
|
|
55
61
|
import { validateCodePathsExist } from '@lumenflow/core/dist/code-path-validator.js';
|
|
56
|
-
import { BRANCHES, REMOTES, PATTERNS, DEFAULTS, LOG_PREFIX, EMOJI, GIT, SESSION, WU_STATUS, PKG_MANAGER, SCRIPTS, CLI_FLAGS, FILE_SYSTEM, EXIT_CODES, STRING_LITERALS, MICRO_WORKTREE_OPERATIONS, TELEMETRY_STEPS, SKIP_GATES_REASONS, CHECKPOINT_MESSAGES,
|
|
62
|
+
import { BRANCHES, REMOTES, PATTERNS, DEFAULTS, LOG_PREFIX, EMOJI, GIT, SESSION, WU_STATUS, PKG_MANAGER, SCRIPTS, CLI_FLAGS, FILE_SYSTEM, EXIT_CODES, STRING_LITERALS, MICRO_WORKTREE_OPERATIONS, TELEMETRY_STEPS, SKIP_GATES_REASONS, CHECKPOINT_MESSAGES,
|
|
63
|
+
// WU-1223: Location types for worktree detection
|
|
64
|
+
CONTEXT_VALIDATION, } from '@lumenflow/core/dist/wu-constants.js';
|
|
57
65
|
import { printGateFailureBox, printStatusPreview } from '@lumenflow/core/dist/wu-done-ui.js';
|
|
58
66
|
import { ensureOnMain } from '@lumenflow/core/dist/wu-helpers.js';
|
|
59
67
|
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
@@ -85,6 +93,7 @@ import { SpawnStatus } from '@lumenflow/core/dist/spawn-registry-schema.js';
|
|
|
85
93
|
// WU-1999: Exposure validation for UI pairing
|
|
86
94
|
// WU-2022: Feature accessibility validation (blocking)
|
|
87
95
|
import { validateExposure, validateFeatureAccessibility, } from '@lumenflow/core/dist/wu-validation.js';
|
|
96
|
+
import { ensureCleanWorktree } from './wu-done-check.js';
|
|
88
97
|
// WU-1588: Memory layer constants
|
|
89
98
|
const MEMORY_SIGNAL_TYPES = {
|
|
90
99
|
WU_COMPLETION: 'wu_completion',
|
|
@@ -147,7 +156,7 @@ async function validateClaimMetadataBeforeGates(id, worktreePath, yamlStatus) {
|
|
|
147
156
|
` pnpm wu:repair-claim --id ${id}\n\n` +
|
|
148
157
|
`After repair, retry:\n` +
|
|
149
158
|
` pnpm wu:done --id ${id}\n\n` +
|
|
150
|
-
`See:
|
|
159
|
+
`See: https://lumenflow.dev/reference/troubleshooting-wu-done/ for more recovery options.`);
|
|
151
160
|
}
|
|
152
161
|
export function printExposureWarnings(wu, options = {}) {
|
|
153
162
|
// Validate exposure
|
|
@@ -444,7 +453,7 @@ export async function isBranchAlreadyMerged(branch) {
|
|
|
444
453
|
return false;
|
|
445
454
|
}
|
|
446
455
|
}
|
|
447
|
-
// WU-1281: isDocsOnlyByPaths removed - use shouldSkipWebTests from path-classifiers.
|
|
456
|
+
// WU-1281: isDocsOnlyByPaths removed - use shouldSkipWebTests from path-classifiers.ts
|
|
448
457
|
// The validators already use shouldSkipWebTests via detectDocsOnlyByPaths wrapper.
|
|
449
458
|
// Keeping the export for backward compatibility but re-exporting the canonical function.
|
|
450
459
|
export { shouldSkipWebTests as isDocsOnlyByPaths } from '@lumenflow/core/dist/path-classifiers.js';
|
|
@@ -500,7 +509,7 @@ function getCommitHeaderLimit() {
|
|
|
500
509
|
return DEFAULTS.MAX_COMMIT_SUBJECT; // Fallback if config is malformed or missing
|
|
501
510
|
}
|
|
502
511
|
}
|
|
503
|
-
// ensureOnMain() moved to wu-helpers.
|
|
512
|
+
// ensureOnMain() moved to wu-helpers.ts (WU-1256)
|
|
504
513
|
/**
|
|
505
514
|
* Ensure working tree is clean before wu:done operations.
|
|
506
515
|
*
|
|
@@ -718,7 +727,7 @@ async function ensureMainUpToDate() {
|
|
|
718
727
|
* by calling /usr/bin/git directly or if PATH was not set up correctly.
|
|
719
728
|
*
|
|
720
729
|
* Context: WU-630 (detective layer, Layer 3 of 4)
|
|
721
|
-
* See:
|
|
730
|
+
* See: https://lumenflow.dev/reference/playbook/ §4.6
|
|
722
731
|
*/
|
|
723
732
|
function runTripwireCheck() {
|
|
724
733
|
const violations = scanLogForViolations();
|
|
@@ -763,7 +772,7 @@ function runTripwireCheck() {
|
|
|
763
772
|
console.error(' 3. Escalate to human if critical files were deleted\n');
|
|
764
773
|
}
|
|
765
774
|
console.error('📖 See detailed recovery steps:');
|
|
766
|
-
console.error('
|
|
775
|
+
console.error(' https://lumenflow.dev/reference/playbook/ §4.6\n');
|
|
767
776
|
console.error('🚫 DO NOT proceed with wu:done until violations are remediated.\n');
|
|
768
777
|
console.error('Fix violations first, then retry wu:done.\n');
|
|
769
778
|
// Also rotate log (cleanup old entries)
|
|
@@ -846,7 +855,7 @@ async function auditSkipCosGates(id, reason) {
|
|
|
846
855
|
appendFileSync(auditPath, `${line}\n`, { encoding: FILE_SYSTEM.UTF8 });
|
|
847
856
|
console.log(`${LOG_PREFIX.DONE} ${EMOJI.MEMO} Skip-COS-gates event logged to ${auditPath}`);
|
|
848
857
|
}
|
|
849
|
-
// WU-2308: validateAllPreCommitHooks moved to wu-done-validators.
|
|
858
|
+
// WU-2308: validateAllPreCommitHooks moved to wu-done-validators.ts
|
|
850
859
|
// Now accepts worktreePath parameter to run audit from worktree context
|
|
851
860
|
/**
|
|
852
861
|
* Check if node_modules in worktree may be stale
|
|
@@ -915,14 +924,13 @@ function checkNodeModulesStaleness(worktreePath) {
|
|
|
915
924
|
* @param {boolean} options.isDocsOnly - Auto-detected docs-only from code_paths
|
|
916
925
|
* @param {boolean} options.docsOnly - Explicit --docs-only flag from CLI
|
|
917
926
|
*/
|
|
918
|
-
function runGatesInWorktree(worktreePath, id, options = {}) {
|
|
927
|
+
async function runGatesInWorktree(worktreePath, id, options = {}) {
|
|
919
928
|
const { isDocsOnly = false, docsOnly = false } = options;
|
|
920
929
|
console.log(`\n${LOG_PREFIX.DONE} Running gates in worktree: ${worktreePath}`);
|
|
921
930
|
// Check for stale node_modules before running gates (prevents confusing failures)
|
|
922
931
|
checkNodeModulesStaleness(worktreePath);
|
|
923
932
|
// WU-1012: Use docs-only gates if explicit --docs-only flag OR auto-detected
|
|
924
933
|
const useDocsOnlyGates = docsOnly || isDocsOnly;
|
|
925
|
-
const gatesCmd = buildGatesCommand({ docsOnly, isDocsOnly });
|
|
926
934
|
if (useDocsOnlyGates) {
|
|
927
935
|
console.log(`${LOG_PREFIX.DONE} Using docs-only gates (skipping lint/typecheck/tests)`);
|
|
928
936
|
if (docsOnly) {
|
|
@@ -931,12 +939,14 @@ function runGatesInWorktree(worktreePath, id, options = {}) {
|
|
|
931
939
|
}
|
|
932
940
|
const startTime = Date.now();
|
|
933
941
|
try {
|
|
934
|
-
|
|
935
|
-
execSync(gatesCmd, {
|
|
942
|
+
const ok = Boolean(await runGates({
|
|
936
943
|
cwd: worktreePath,
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
});
|
|
944
|
+
docsOnly: useDocsOnlyGates,
|
|
945
|
+
coverageMode: undefined,
|
|
946
|
+
}));
|
|
947
|
+
if (!ok) {
|
|
948
|
+
throw new Error('Gates failed');
|
|
949
|
+
}
|
|
940
950
|
const duration = Date.now() - startTime;
|
|
941
951
|
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Gates passed in ${prettyMs(duration)}`);
|
|
942
952
|
emitTelemetry({ script: 'wu-done', wu_id: id, step: 'gates', ok: true, duration_ms: duration });
|
|
@@ -998,13 +1008,13 @@ async function validateStagedFiles(id, isDocsOnly = false) {
|
|
|
998
1008
|
}
|
|
999
1009
|
}
|
|
1000
1010
|
// Note: updateStatusRemoveInProgress, addToStatusCompleted, and moveWUToDoneBacklog
|
|
1001
|
-
// have been extracted to tools/lib/wu-status-updater.
|
|
1011
|
+
// have been extracted to tools/lib/wu-status-updater.ts and imported above (WU-1163)
|
|
1002
1012
|
//
|
|
1003
|
-
// Note: ensureStamp has been replaced with createStamp from tools/lib/stamp-utils.
|
|
1013
|
+
// Note: ensureStamp has been replaced with createStamp from tools/lib/stamp-utils.ts (WU-1163)
|
|
1004
1014
|
//
|
|
1005
1015
|
// Note: readWUPreferWorktree, detectCurrentWorktree, defaultWorktreeFrom, detectWorkspaceMode,
|
|
1006
1016
|
// defaultBranchFrom, branchExists, runCleanup have been extracted to
|
|
1007
|
-
// tools/lib/wu-done-validators.
|
|
1017
|
+
// tools/lib/wu-done-validators.ts and imported above (WU-1215)
|
|
1008
1018
|
/**
|
|
1009
1019
|
* Validate Branch-Only mode requirements before proceeding
|
|
1010
1020
|
* @param {string} laneBranch - Expected lane branch name
|
|
@@ -1774,8 +1784,7 @@ async function executeGates({ id, args, isBranchOnly, isDocsOnly, worktreePath,
|
|
|
1774
1784
|
// Branch-Only mode: run gates in-place (current directory on lane branch)
|
|
1775
1785
|
console.log(`\n${LOG_PREFIX.DONE} Running gates in Branch-Only mode (in-place on lane branch)`);
|
|
1776
1786
|
// WU-1012: Use docs-only gates if explicit --docs-only flag OR auto-detected
|
|
1777
|
-
const useDocsOnlyGates = args.docsOnly || isDocsOnly;
|
|
1778
|
-
const gatesCmd = buildGatesCommand({ docsOnly: Boolean(args.docsOnly), isDocsOnly });
|
|
1787
|
+
const useDocsOnlyGates = Boolean(args.docsOnly) || Boolean(isDocsOnly);
|
|
1779
1788
|
if (useDocsOnlyGates) {
|
|
1780
1789
|
console.log(`${LOG_PREFIX.DONE} Using docs-only gates (skipping lint/typecheck/tests)`);
|
|
1781
1790
|
if (args.docsOnly) {
|
|
@@ -1784,7 +1793,10 @@ async function executeGates({ id, args, isBranchOnly, isDocsOnly, worktreePath,
|
|
|
1784
1793
|
}
|
|
1785
1794
|
const startTime = Date.now();
|
|
1786
1795
|
try {
|
|
1787
|
-
|
|
1796
|
+
const ok = Boolean(await runGates({ docsOnly: useDocsOnlyGates }));
|
|
1797
|
+
if (!ok) {
|
|
1798
|
+
throw new Error('Gates failed');
|
|
1799
|
+
}
|
|
1788
1800
|
const duration = Date.now() - startTime;
|
|
1789
1801
|
console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Gates passed in ${prettyMs(duration)}`);
|
|
1790
1802
|
emitTelemetry({
|
|
@@ -1818,7 +1830,10 @@ async function executeGates({ id, args, isBranchOnly, isDocsOnly, worktreePath,
|
|
|
1818
1830
|
else if (worktreePath && existsSync(worktreePath)) {
|
|
1819
1831
|
// Worktree mode: run gates in the dedicated worktree
|
|
1820
1832
|
// WU-1012: Pass both auto-detected and explicit docs-only flags
|
|
1821
|
-
runGatesInWorktree(worktreePath, id, {
|
|
1833
|
+
await runGatesInWorktree(worktreePath, id, {
|
|
1834
|
+
isDocsOnly,
|
|
1835
|
+
docsOnly: Boolean(args.docsOnly),
|
|
1836
|
+
});
|
|
1822
1837
|
}
|
|
1823
1838
|
else {
|
|
1824
1839
|
die(`Worktree not found (${worktreePath || 'unknown'}). Gates must run in the lane worktree.\n` +
|
|
@@ -1855,7 +1870,7 @@ async function executeGates({ id, args, isBranchOnly, isDocsOnly, worktreePath,
|
|
|
1855
1870
|
console.error(`\n${LOG_PREFIX.DONE} ${EMOJI.FAILURE} COS governance gates failed`);
|
|
1856
1871
|
console.error('\nTo fix:');
|
|
1857
1872
|
console.error(' 1. Add required evidence to governance.evidence field in WU YAML');
|
|
1858
|
-
console.error(' 2. See:
|
|
1873
|
+
console.error(' 2. See: https://lumenflow.dev/reference/evidence-format/');
|
|
1859
1874
|
console.error('\nEmergency bypass (creates audit trail):');
|
|
1860
1875
|
console.error(` pnpm wu:done --id ${id} --skip-cos-gates --reason "explanation"`);
|
|
1861
1876
|
die('Abort: WU not completed. Fix governance evidence and retry pnpm wu:done.');
|
|
@@ -1908,8 +1923,22 @@ function printStateHUD({ id, docMain, isBranchOnly, isDocsOnly, derivedWorktree,
|
|
|
1908
1923
|
async function main() {
|
|
1909
1924
|
// Allow pre-push hook to recognize wu:done automation (WU-1030)
|
|
1910
1925
|
process.env.LUMENFLOW_WU_TOOL = 'wu-done';
|
|
1911
|
-
// Validate CLI arguments and WU ID format (extracted to wu-done-validators.
|
|
1926
|
+
// Validate CLI arguments and WU ID format (extracted to wu-done-validators.ts)
|
|
1912
1927
|
const { args, id } = validateInputs(process.argv);
|
|
1928
|
+
// WU-1223: Check if running from worktree - wu:done now requires main checkout
|
|
1929
|
+
// Agents should use wu:prep from worktree, then wu:done from main
|
|
1930
|
+
const { LOCATION_TYPES } = CONTEXT_VALIDATION;
|
|
1931
|
+
const currentLocation = await resolveLocation();
|
|
1932
|
+
if (currentLocation.type === LOCATION_TYPES.WORKTREE) {
|
|
1933
|
+
die(`${EMOJI.FAILURE} wu:done must be run from main checkout, not from a worktree.\n\n` +
|
|
1934
|
+
`Current location: ${currentLocation.cwd}\n\n` +
|
|
1935
|
+
`WU-1223 NEW WORKFLOW:\n` +
|
|
1936
|
+
` 1. From worktree, run: pnpm wu:prep --id ${id}\n` +
|
|
1937
|
+
` (This runs gates and prepares for completion)\n\n` +
|
|
1938
|
+
` 2. From main, run: cd ${currentLocation.mainCheckout} && pnpm wu:done --id ${id}\n` +
|
|
1939
|
+
` (This does merge + cleanup only)\n\n` +
|
|
1940
|
+
`Use wu:prep to run gates in the worktree, then wu:done from main for merge/cleanup.`);
|
|
1941
|
+
}
|
|
1913
1942
|
// Detect workspace mode and calculate paths (WU-1215: extracted to validators module)
|
|
1914
1943
|
const pathInfo = await detectModeAndPaths(id, args);
|
|
1915
1944
|
const { WU_PATH, STATUS_PATH, BACKLOG_PATH, STAMPS_DIR, docMain, isBranchOnly, derivedWorktree, docForValidation: initialDocForValidation, isDocsOnly, } = pathInfo;
|
|
@@ -1933,6 +1962,11 @@ async function main() {
|
|
|
1933
1962
|
}
|
|
1934
1963
|
const effectiveDerivedWorktree = effectiveBranchOnly ? null : derivedWorktree;
|
|
1935
1964
|
const effectiveWorktreePath = effectiveBranchOnly ? null : resolvedWorktreePath;
|
|
1965
|
+
// WU-1169: Ensure worktree is clean before proceeding
|
|
1966
|
+
// This prevents WU-1943 rollback loops if rebase fails due to dirty state
|
|
1967
|
+
if (effectiveWorktreePath && existsSync(effectiveWorktreePath)) {
|
|
1968
|
+
await ensureCleanWorktree(effectiveWorktreePath);
|
|
1969
|
+
}
|
|
1936
1970
|
// Pre-flight checks (WU-1215: extracted to executePreFlightChecks function)
|
|
1937
1971
|
const preFlightResult = await executePreFlightChecks({
|
|
1938
1972
|
id,
|
|
@@ -1977,7 +2011,9 @@ async function main() {
|
|
|
1977
2011
|
// WU-2308: Pass worktreePath to run audit from worktree (checks fixed deps, not stale main deps)
|
|
1978
2012
|
// WU-1145: Skip pre-flight when skipGates is true (pre-flight runs gates which was already skipped)
|
|
1979
2013
|
if (!args.skipGates) {
|
|
1980
|
-
const hookResult = validateAllPreCommitHooks(id, worktreePath
|
|
2014
|
+
const hookResult = await validateAllPreCommitHooks(id, worktreePath, {
|
|
2015
|
+
runGates: ({ cwd }) => runGates({ cwd, docsOnly: false }),
|
|
2016
|
+
});
|
|
1981
2017
|
if (!hookResult.valid) {
|
|
1982
2018
|
die('Pre-flight validation failed. Fix hook issues and try again.');
|
|
1983
2019
|
}
|
package/dist/wu-edit.js
CHANGED
|
@@ -24,9 +24,8 @@
|
|
|
24
24
|
* pnpm wu:edit --id WU-123 --acceptance "Criterion 1" --acceptance "Criterion 2"
|
|
25
25
|
*
|
|
26
26
|
* Part of WU-1274: Add wu:edit command for spec-only changes
|
|
27
|
-
* @see {@link
|
|
27
|
+
* @see {@link packages/@lumenflow/cli/src/lib/micro-worktree.ts} - Shared micro-worktree logic
|
|
28
28
|
*/
|
|
29
|
-
import { fileURLToPath } from 'node:url';
|
|
30
29
|
import { getGitForCwd, createGitForPath } from '@lumenflow/core/dist/git-adapter.js';
|
|
31
30
|
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
32
31
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
@@ -182,19 +181,30 @@ const EDIT_OPTIONS = {
|
|
|
182
181
|
codePaths: {
|
|
183
182
|
name: 'codePaths',
|
|
184
183
|
flags: '--code-paths <path>',
|
|
185
|
-
description: 'Code path (repeatable,
|
|
184
|
+
description: 'Code path (repeatable, appends to existing; use --replace-code-paths to overwrite)',
|
|
186
185
|
isRepeatable: true,
|
|
187
186
|
},
|
|
187
|
+
replaceCodePaths: {
|
|
188
|
+
name: 'replaceCodePaths',
|
|
189
|
+
flags: '--replace-code-paths',
|
|
190
|
+
description: 'Replace existing code_paths instead of appending',
|
|
191
|
+
},
|
|
188
192
|
risks: {
|
|
189
193
|
name: 'risks',
|
|
190
194
|
flags: '--risks <risk>',
|
|
191
|
-
description: 'Risk entry (repeatable,
|
|
195
|
+
description: 'Risk entry (repeatable, appends to existing; use --replace-risks to overwrite)',
|
|
192
196
|
isRepeatable: true,
|
|
193
197
|
},
|
|
198
|
+
replaceRisks: {
|
|
199
|
+
name: 'replaceRisks',
|
|
200
|
+
flags: '--replace-risks',
|
|
201
|
+
description: 'Replace existing risks instead of appending',
|
|
202
|
+
},
|
|
203
|
+
// WU-1225: Deprecated --append flag (kept for backwards compatibility)
|
|
194
204
|
append: {
|
|
195
205
|
name: 'append',
|
|
196
206
|
flags: '--append',
|
|
197
|
-
description: '
|
|
207
|
+
description: '[DEPRECATED] Arrays now append by default. Use --replace-* flags to replace.',
|
|
198
208
|
},
|
|
199
209
|
// WU-1456: Add lane reassignment support
|
|
200
210
|
lane: {
|
|
@@ -228,12 +238,22 @@ const EDIT_OPTIONS = {
|
|
|
228
238
|
blockedBy: {
|
|
229
239
|
name: 'blockedBy',
|
|
230
240
|
flags: '--blocked-by <wuIds>',
|
|
231
|
-
description: 'Comma-separated WU IDs that block this WU (
|
|
241
|
+
description: 'Comma-separated WU IDs that block this WU (appends to existing; use --replace-blocked-by to overwrite)',
|
|
242
|
+
},
|
|
243
|
+
replaceBlockedBy: {
|
|
244
|
+
name: 'replaceBlockedBy',
|
|
245
|
+
flags: '--replace-blocked-by',
|
|
246
|
+
description: 'Replace existing blocked_by instead of appending',
|
|
232
247
|
},
|
|
233
248
|
addDep: {
|
|
234
249
|
name: 'addDep',
|
|
235
250
|
flags: '--add-dep <wuIds>',
|
|
236
|
-
description: 'Comma-separated WU IDs to add to dependencies array (
|
|
251
|
+
description: 'Comma-separated WU IDs to add to dependencies array (appends to existing; use --replace-dependencies to overwrite)',
|
|
252
|
+
},
|
|
253
|
+
replaceDependencies: {
|
|
254
|
+
name: 'replaceDependencies',
|
|
255
|
+
flags: '--replace-dependencies',
|
|
256
|
+
description: 'Replace existing dependencies instead of appending',
|
|
237
257
|
},
|
|
238
258
|
};
|
|
239
259
|
/**
|
|
@@ -334,7 +354,9 @@ function parseArgs() {
|
|
|
334
354
|
EDIT_OPTIONS.replaceNotes,
|
|
335
355
|
EDIT_OPTIONS.replaceAcceptance,
|
|
336
356
|
EDIT_OPTIONS.codePaths,
|
|
357
|
+
EDIT_OPTIONS.replaceCodePaths,
|
|
337
358
|
EDIT_OPTIONS.risks,
|
|
359
|
+
EDIT_OPTIONS.replaceRisks,
|
|
338
360
|
EDIT_OPTIONS.append,
|
|
339
361
|
// WU-1390: Add test path flags
|
|
340
362
|
WU_OPTIONS.testPathsManual,
|
|
@@ -350,7 +372,9 @@ function parseArgs() {
|
|
|
350
372
|
EDIT_OPTIONS.phase,
|
|
351
373
|
// WU-2564: Add blocked_by and dependencies
|
|
352
374
|
EDIT_OPTIONS.blockedBy,
|
|
375
|
+
EDIT_OPTIONS.replaceBlockedBy,
|
|
353
376
|
EDIT_OPTIONS.addDep,
|
|
377
|
+
EDIT_OPTIONS.replaceDependencies,
|
|
354
378
|
// WU-1039: Add exposure for done WU metadata updates
|
|
355
379
|
WU_OPTIONS.exposure,
|
|
356
380
|
],
|
|
@@ -702,7 +726,7 @@ export function applyEdits(wu, opts) {
|
|
|
702
726
|
}
|
|
703
727
|
updated.phase = phaseNum;
|
|
704
728
|
}
|
|
705
|
-
// Handle repeatable --code-paths flags (WU-
|
|
729
|
+
// Handle repeatable --code-paths flags (WU-1225: append by default, replace with --replace-code-paths)
|
|
706
730
|
// WU-1816: Split comma-separated string into array (same pattern as test paths)
|
|
707
731
|
// WU-1870: Fix to split comma-separated values WITHIN array elements (Commander passes ['a,b'] not 'a,b')
|
|
708
732
|
if (opts.codePaths && opts.codePaths.length > 0) {
|
|
@@ -716,9 +740,12 @@ export function applyEdits(wu, opts) {
|
|
|
716
740
|
.split(',')
|
|
717
741
|
.map((p) => p.trim())
|
|
718
742
|
.filter(Boolean);
|
|
719
|
-
|
|
743
|
+
// WU-1225: Invert logic - append by default, replace with --replace-code-paths
|
|
744
|
+
// Also support legacy --append flag for backwards compatibility
|
|
745
|
+
const shouldAppend = !opts.replaceCodePaths || opts.append;
|
|
746
|
+
updated.code_paths = mergeArrayField(wu.code_paths, codePaths, shouldAppend);
|
|
720
747
|
}
|
|
721
|
-
// WU-
|
|
748
|
+
// WU-1225: Handle repeatable --risks flags (append by default, replace with --replace-risks)
|
|
722
749
|
// Split comma-separated values within each entry for consistency with other list fields
|
|
723
750
|
if (opts.risks && opts.risks.length > 0) {
|
|
724
751
|
const rawRisks = opts.risks;
|
|
@@ -731,9 +758,12 @@ export function applyEdits(wu, opts) {
|
|
|
731
758
|
.split(',')
|
|
732
759
|
.map((risk) => risk.trim())
|
|
733
760
|
.filter(Boolean);
|
|
734
|
-
|
|
761
|
+
// WU-1225: Invert logic - append by default
|
|
762
|
+
const shouldAppend = !opts.replaceRisks || opts.append;
|
|
763
|
+
updated.risks = mergeArrayField(wu.risks, risks, shouldAppend);
|
|
735
764
|
}
|
|
736
765
|
// WU-1390: Handle test path flags (DRY refactor)
|
|
766
|
+
// WU-1225: Test paths now append by default (consistent with --acceptance and --code-paths)
|
|
737
767
|
const testPathMappings = [
|
|
738
768
|
{ optKey: 'testPathsManual', field: 'manual' },
|
|
739
769
|
{ optKey: 'testPathsUnit', field: 'unit' },
|
|
@@ -754,28 +784,32 @@ export function applyEdits(wu, opts) {
|
|
|
754
784
|
.map((p) => p.trim())
|
|
755
785
|
.filter(Boolean);
|
|
756
786
|
updated.tests = updated.tests || {};
|
|
757
|
-
|
|
787
|
+
// WU-1225: Append by default (no individual replace flags for test paths yet)
|
|
788
|
+
const shouldAppend = true;
|
|
789
|
+
updated.tests[field] = mergeArrayField(wu.tests?.[field], paths, shouldAppend);
|
|
758
790
|
}
|
|
759
791
|
}
|
|
760
792
|
// WU-2564: Handle --blocked-by flag
|
|
761
|
-
//
|
|
793
|
+
// WU-1225: Append by default, replace with --replace-blocked-by
|
|
762
794
|
if (opts.blockedBy) {
|
|
763
795
|
const rawBlockedBy = opts.blockedBy;
|
|
764
796
|
const blockedByIds = rawBlockedBy
|
|
765
797
|
.split(',')
|
|
766
798
|
.map((id) => id.trim())
|
|
767
799
|
.filter(Boolean);
|
|
768
|
-
|
|
800
|
+
const shouldAppend = !opts.replaceBlockedBy || opts.append;
|
|
801
|
+
updated.blocked_by = mergeArrayField(wu.blocked_by, blockedByIds, shouldAppend);
|
|
769
802
|
}
|
|
770
803
|
// WU-2564: Handle --add-dep flag
|
|
771
|
-
//
|
|
804
|
+
// WU-1225: Append by default, replace with --replace-dependencies
|
|
772
805
|
if (opts.addDep) {
|
|
773
806
|
const rawAddDep = opts.addDep;
|
|
774
807
|
const depIds = rawAddDep
|
|
775
808
|
.split(',')
|
|
776
809
|
.map((id) => id.trim())
|
|
777
810
|
.filter(Boolean);
|
|
778
|
-
|
|
811
|
+
const shouldAppend = !opts.replaceDependencies || opts.append;
|
|
812
|
+
updated.dependencies = mergeArrayField(wu.dependencies, depIds, shouldAppend);
|
|
779
813
|
}
|
|
780
814
|
// WU-1039: Handle --exposure flag with validation
|
|
781
815
|
if (opts.exposure) {
|
|
@@ -845,21 +879,20 @@ async function main() {
|
|
|
845
879
|
' --description <text> Update description field\n' +
|
|
846
880
|
' --acceptance <text> Append acceptance criteria (repeatable; use --replace-acceptance to overwrite)\n' +
|
|
847
881
|
' --notes <text> Append to notes (use --replace-notes to overwrite)\n' +
|
|
848
|
-
' --
|
|
849
|
-
' --
|
|
850
|
-
' --code-paths <paths> Replace code paths (repeatable; use --append to add)\n' +
|
|
851
|
-
' --risks <risk> Replace risks (repeatable; use --append to add)\n' +
|
|
882
|
+
' --code-paths <paths> Append code paths (repeatable; use --replace-code-paths to overwrite)\n' +
|
|
883
|
+
' --risks <risk> Append risks (repeatable; use --replace-risks to overwrite)\n' +
|
|
852
884
|
' --lane <lane> Update lane assignment (e.g., "Operations: Tooling")\n' +
|
|
853
885
|
' --type <type> Update WU type (feature, bug, refactor, documentation)\n' +
|
|
854
886
|
' --priority <priority> Update priority (P0, P1, P2, P3)\n' +
|
|
855
887
|
' --initiative <initId> Update initiative (bidirectional update)\n' +
|
|
856
888
|
' --phase <number> Update phase within initiative\n' +
|
|
857
|
-
' --test-paths-manual <t>
|
|
858
|
-
' --test-paths-unit <path>
|
|
859
|
-
' --test-paths-e2e <path>
|
|
860
|
-
' --blocked-by <wuIds> WU IDs that block this WU (
|
|
861
|
-
' --add-dep <wuIds>
|
|
862
|
-
' --exposure <type> Update exposure level (ui, api, backend-only, documentation)'
|
|
889
|
+
' --test-paths-manual <t> Append manual test descriptions (repeatable)\n' +
|
|
890
|
+
' --test-paths-unit <path> Append unit test paths (repeatable)\n' +
|
|
891
|
+
' --test-paths-e2e <path> Append e2e test paths (repeatable)\n' +
|
|
892
|
+
' --blocked-by <wuIds> Append WU IDs that block this WU (use --replace-blocked-by to overwrite)\n' +
|
|
893
|
+
' --add-dep <wuIds> Append WU IDs to dependencies (use --replace-dependencies to overwrite)\n' +
|
|
894
|
+
' --exposure <type> Update exposure level (ui, api, backend-only, documentation)\n\n' +
|
|
895
|
+
'Note: All array fields now append by default (WU-1225). Use --replace-* flags to overwrite.');
|
|
863
896
|
}
|
|
864
897
|
// Apply edits to get updated WU
|
|
865
898
|
const updatedWU = applyEdits(originalWU, opts);
|
|
@@ -1001,8 +1034,10 @@ async function main() {
|
|
|
1001
1034
|
displayReadinessSummary(id);
|
|
1002
1035
|
}
|
|
1003
1036
|
}
|
|
1004
|
-
//
|
|
1005
|
-
|
|
1037
|
+
// WU-1181: Use import.meta.main instead of process.argv[1] comparison
|
|
1038
|
+
// The old pattern fails with pnpm symlinks because process.argv[1] is the symlink
|
|
1039
|
+
// path but import.meta.url resolves to the real path - they never match
|
|
1040
|
+
if (import.meta.main) {
|
|
1006
1041
|
main().catch((err) => {
|
|
1007
1042
|
console.error(`${PREFIX} ❌ ${err.message}`);
|
|
1008
1043
|
process.exit(EXIT_CODES.ERROR);
|
package/dist/wu-infer-lane.js
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* WU Lane Inference CLI (WU-908)
|
|
4
4
|
*
|
|
5
5
|
* Suggests sub-lane for a WU based on code paths and description.
|
|
6
|
-
* Wrapper around lib/lane-inference.
|
|
6
|
+
* Wrapper around lib/lane-inference.ts for standalone CLI usage.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* # Infer from existing WU
|
|
10
|
-
* node tools/wu-infer-lane.
|
|
10
|
+
* node tools/wu-infer-lane.ts --id WU-123
|
|
11
11
|
*
|
|
12
12
|
* # Infer from manual inputs
|
|
13
|
-
* node tools/wu-infer-lane.
|
|
13
|
+
* node tools/wu-infer-lane.ts --paths "tools/**" "docs/**" --desc "Tooling improvements"
|
|
14
14
|
*
|
|
15
15
|
* Returns suggested lane and confidence score (0-100).
|
|
16
16
|
*/
|
|
@@ -128,9 +128,10 @@ async function main() {
|
|
|
128
128
|
die(`Lane inference failed: ${err.message}`);
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
|
-
//
|
|
132
|
-
|
|
131
|
+
// WU-1181: Use import.meta.main instead of process.argv[1] comparison
|
|
132
|
+
// The old pattern fails with pnpm symlinks because process.argv[1] is the symlink
|
|
133
|
+
// path but import.meta.url resolves to the real path - they never match
|
|
133
134
|
import { runCLI } from './cli-entry-point.js';
|
|
134
|
-
if (
|
|
135
|
+
if (import.meta.main) {
|
|
135
136
|
runCLI(main);
|
|
136
137
|
}
|
package/dist/wu-preflight.js
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
* WU-1803: Fast validation of code_paths and test paths before gates run.
|
|
6
6
|
* Completes in under 5 seconds vs 2+ minutes for full gates.
|
|
7
7
|
*
|
|
8
|
+
* WU-1180: Migrated from deprecated parseWUArgs to createWUParser for
|
|
9
|
+
* proper Commander --help output and consistency with other WU commands.
|
|
10
|
+
*
|
|
8
11
|
* This catches YAML mismatches early, preventing wasted time running full
|
|
9
12
|
* gates only to fail on code_paths validation at the end of wu:done.
|
|
10
13
|
*
|
|
@@ -17,78 +20,14 @@
|
|
|
17
20
|
* - test file paths exist (unit, e2e, integration)
|
|
18
21
|
* - WU YAML schema is valid
|
|
19
22
|
*/
|
|
20
|
-
import { fileURLToPath } from 'node:url';
|
|
21
23
|
import { existsSync } from 'node:fs';
|
|
22
|
-
import {
|
|
24
|
+
import { createWUParser, WU_OPTIONS } from '@lumenflow/core/dist/arg-parser.js';
|
|
23
25
|
import { validatePreflight, formatPreflightResult, } from '@lumenflow/core/dist/wu-preflight-validators.js';
|
|
24
26
|
import { PATTERNS, EXIT_CODES, LOG_PREFIX, EMOJI } from '@lumenflow/core/dist/wu-constants.js';
|
|
25
27
|
import { defaultWorktreeFrom, WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
26
28
|
import { readWURaw } from '@lumenflow/core/dist/wu-yaml.js';
|
|
29
|
+
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
27
30
|
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
28
|
-
/**
|
|
29
|
-
* Parse command-line arguments
|
|
30
|
-
* @param {string[]} argv - Process arguments
|
|
31
|
-
* @returns {object} Parsed arguments
|
|
32
|
-
*/
|
|
33
|
-
function parseArgs(argv) {
|
|
34
|
-
const args = parseWUArgs(argv);
|
|
35
|
-
// Handle help
|
|
36
|
-
if (args.help) {
|
|
37
|
-
return { help: true };
|
|
38
|
-
}
|
|
39
|
-
// Validate WU ID
|
|
40
|
-
if (!args.id) {
|
|
41
|
-
return { error: 'Missing required argument: --id WU-XXX' };
|
|
42
|
-
}
|
|
43
|
-
const id = args.id.toUpperCase();
|
|
44
|
-
if (!PATTERNS.WU_ID.test(id)) {
|
|
45
|
-
return { error: `Invalid WU ID format: ${args.id}. Expected WU-NNN` };
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
id,
|
|
49
|
-
worktree: args.worktree || null,
|
|
50
|
-
help: false,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Display help message
|
|
55
|
-
*/
|
|
56
|
-
function showHelp() {
|
|
57
|
-
console.log(`
|
|
58
|
-
WU Preflight Validation - Fast code_paths and test paths check
|
|
59
|
-
|
|
60
|
-
Usage:
|
|
61
|
-
pnpm wu:preflight --id WU-XXX [OPTIONS]
|
|
62
|
-
|
|
63
|
-
Options:
|
|
64
|
-
--id <WU-ID> WU ID to validate (required)
|
|
65
|
-
--worktree <path> Worktree path to validate files in (auto-detected if not provided)
|
|
66
|
-
--help, -h Show this help
|
|
67
|
-
|
|
68
|
-
Description:
|
|
69
|
-
Validates code_paths and test file paths exist BEFORE running full gates.
|
|
70
|
-
Completes in under 5 seconds vs 2+ minutes for gates.
|
|
71
|
-
|
|
72
|
-
This prevents wasting time running full gates only to fail on
|
|
73
|
-
code_paths validation at the end of wu:done.
|
|
74
|
-
|
|
75
|
-
Checks performed:
|
|
76
|
-
${EMOJI.SUCCESS} code_paths files exist in worktree/main
|
|
77
|
-
${EMOJI.SUCCESS} Test file paths exist (unit, e2e, integration)
|
|
78
|
-
${EMOJI.SUCCESS} WU YAML schema is valid (required fields present)
|
|
79
|
-
${EMOJI.SUCCESS} Manual tests are skipped (descriptions, not files)
|
|
80
|
-
|
|
81
|
-
Recommended workflow:
|
|
82
|
-
1. Implement feature/fix
|
|
83
|
-
2. Run: pnpm wu:preflight --id WU-XXX (fast check)
|
|
84
|
-
3. Run: pnpm gates (full validation)
|
|
85
|
-
4. Run: pnpm wu:done --id WU-XXX (complete WU)
|
|
86
|
-
|
|
87
|
-
Example:
|
|
88
|
-
pnpm wu:preflight --id WU-1803
|
|
89
|
-
pnpm wu:preflight --id WU-1803 --worktree worktrees/operations-gates-wu-1803
|
|
90
|
-
`);
|
|
91
|
-
}
|
|
92
31
|
/**
|
|
93
32
|
* Detect worktree path from WU YAML or calculate from lane
|
|
94
33
|
* @param {string} id - WU ID
|
|
@@ -116,23 +55,23 @@ function detectWorktreePath(id) {
|
|
|
116
55
|
*/
|
|
117
56
|
async function main() {
|
|
118
57
|
const PREFIX = LOG_PREFIX.PREFLIGHT;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
58
|
+
// WU-1180: Use createWUParser for proper Commander help output
|
|
59
|
+
const args = createWUParser({
|
|
60
|
+
name: 'wu-preflight',
|
|
61
|
+
description: 'Fast validation of code_paths and test paths before gates run. ' +
|
|
62
|
+
'Completes in under 5 seconds vs 2+ minutes for full gates.',
|
|
63
|
+
options: [WU_OPTIONS.id, WU_OPTIONS.worktree],
|
|
64
|
+
required: ['id'],
|
|
65
|
+
allowPositionalId: true,
|
|
66
|
+
});
|
|
67
|
+
const id = args.id.toUpperCase();
|
|
68
|
+
if (!PATTERNS.WU_ID.test(id)) {
|
|
69
|
+
die(`Invalid WU ID format: ${args.id}. Expected WU-NNN`);
|
|
130
70
|
}
|
|
131
|
-
const { id, worktree } = args;
|
|
132
71
|
console.log(`${PREFIX} Preflight Validation for ${id}`);
|
|
133
72
|
console.log(`${PREFIX} ${'='.repeat(30)}\n`);
|
|
134
73
|
// Determine worktree path
|
|
135
|
-
let worktreePath = worktree;
|
|
74
|
+
let worktreePath = args.worktree || null;
|
|
136
75
|
if (!worktreePath) {
|
|
137
76
|
worktreePath = detectWorktreePath(id);
|
|
138
77
|
if (worktreePath) {
|
|
@@ -160,9 +99,12 @@ async function main() {
|
|
|
160
99
|
process.exit(EXIT_CODES.SUCCESS);
|
|
161
100
|
}
|
|
162
101
|
// Guard main() for testability
|
|
102
|
+
// WU-1071: Use import.meta.main instead of process.argv[1] comparison
|
|
103
|
+
// The old pattern fails with pnpm symlinks because process.argv[1] is the symlink
|
|
104
|
+
// path but import.meta.url resolves to the real path - they never match
|
|
163
105
|
import { runCLI } from './cli-entry-point.js';
|
|
164
|
-
if (
|
|
106
|
+
if (import.meta.main) {
|
|
165
107
|
runCLI(main);
|
|
166
108
|
}
|
|
167
109
|
// Export for testing
|
|
168
|
-
export {
|
|
110
|
+
export { detectWorktreePath };
|