@lumenflow/cli 2.2.2 → 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__/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 +356 -101
- 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 +4 -3
- package/dist/validate-skills-spec.js +4 -3
- package/dist/validate.js +4 -3
- 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 +39 -12
- 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-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 };
|
package/dist/wu-prep.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* WU Prep Helper (WU-1223)
|
|
4
|
+
*
|
|
5
|
+
* Prepares a WU for completion by running gates and generating docs in the worktree.
|
|
6
|
+
* After successful prep, prints copy-paste instruction to run wu:done from main.
|
|
7
|
+
*
|
|
8
|
+
* Workflow:
|
|
9
|
+
* 1. Verify we're in a worktree (error if in main checkout)
|
|
10
|
+
* 2. Run gates in the worktree
|
|
11
|
+
* 3. Generate docs (if applicable)
|
|
12
|
+
* 4. Print copy-paste instruction for wu:done from main
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* pnpm wu:prep --id WU-XXX [--docs-only]
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
import { createWUParser, WU_OPTIONS } from '@lumenflow/core/dist/arg-parser.js';
|
|
20
|
+
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
21
|
+
import { resolveLocation } from '@lumenflow/core/dist/context/location-resolver.js';
|
|
22
|
+
import { readWU } from '@lumenflow/core/dist/wu-yaml.js';
|
|
23
|
+
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
24
|
+
import { CONTEXT_VALIDATION, PATTERNS, EXIT_CODES, WU_STATUS, EMOJI, } from '@lumenflow/core/dist/wu-constants.js';
|
|
25
|
+
import { runGates } from './gates.js';
|
|
26
|
+
const { LOCATION_TYPES } = CONTEXT_VALIDATION;
|
|
27
|
+
/**
|
|
28
|
+
* Log prefix for wu:prep command output.
|
|
29
|
+
*/
|
|
30
|
+
const PREP_PREFIX = '[wu-prep]';
|
|
31
|
+
/**
|
|
32
|
+
* GATES_OPTIONS for wu:prep command.
|
|
33
|
+
* Subset of gates options relevant for prep.
|
|
34
|
+
*/
|
|
35
|
+
const PREP_OPTIONS = {
|
|
36
|
+
docsOnly: {
|
|
37
|
+
name: 'docsOnly',
|
|
38
|
+
flags: '--docs-only',
|
|
39
|
+
description: 'Run docs-only gates (format, spec-linter)',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Print success message with copy-paste instruction.
|
|
44
|
+
*/
|
|
45
|
+
function printSuccessMessage(wuId, mainCheckout) {
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log(`${PREP_PREFIX} ${EMOJI.SUCCESS} ${wuId}: Prep completed successfully!`);
|
|
48
|
+
console.log('');
|
|
49
|
+
console.log(`${PREP_PREFIX} Gates passed in worktree.`);
|
|
50
|
+
console.log('');
|
|
51
|
+
console.log(`${PREP_PREFIX} Next step - copy and paste this command:`);
|
|
52
|
+
console.log('');
|
|
53
|
+
console.log(` cd ${mainCheckout} && pnpm wu:done --id ${wuId}`);
|
|
54
|
+
console.log('');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Main entry point.
|
|
58
|
+
*/
|
|
59
|
+
async function main() {
|
|
60
|
+
// Parse arguments
|
|
61
|
+
const args = createWUParser({
|
|
62
|
+
name: 'wu-prep',
|
|
63
|
+
description: 'Prepare WU for completion (run gates in worktree)',
|
|
64
|
+
options: [WU_OPTIONS.id, PREP_OPTIONS.docsOnly],
|
|
65
|
+
required: ['id'],
|
|
66
|
+
allowPositionalId: true,
|
|
67
|
+
});
|
|
68
|
+
const id = args.id.toUpperCase();
|
|
69
|
+
if (!PATTERNS.WU_ID.test(id)) {
|
|
70
|
+
die(`Invalid WU id '${args.id}'. Expected format WU-123`);
|
|
71
|
+
}
|
|
72
|
+
// Detect location
|
|
73
|
+
const location = await resolveLocation();
|
|
74
|
+
// WU-1223: wu:prep MUST be run from worktree, not main
|
|
75
|
+
if (location.type !== LOCATION_TYPES.WORKTREE) {
|
|
76
|
+
die(`${EMOJI.FAILURE} wu:prep must be run from a worktree, not ${location.type}.\n\n` +
|
|
77
|
+
`Current location: ${location.cwd}\n\n` +
|
|
78
|
+
`If you have a worktree for ${id}, navigate to it first:\n` +
|
|
79
|
+
` cd worktrees/<lane>-${id.toLowerCase()}\n\n` +
|
|
80
|
+
`If you don't have a worktree yet, claim the WU first:\n` +
|
|
81
|
+
` pnpm wu:claim --id ${id} --lane "<lane>"`);
|
|
82
|
+
}
|
|
83
|
+
// Verify the worktree is for the correct WU
|
|
84
|
+
if (location.worktreeWuId && location.worktreeWuId !== id) {
|
|
85
|
+
console.warn(`${PREP_PREFIX} ${EMOJI.WARNING} Worktree is for ${location.worktreeWuId}, but you specified ${id}.`);
|
|
86
|
+
console.warn(`${PREP_PREFIX} Proceeding with ${id} as specified.`);
|
|
87
|
+
}
|
|
88
|
+
// Read WU YAML to validate it exists and check status
|
|
89
|
+
const wuPath = WU_PATHS.WU(id);
|
|
90
|
+
let doc;
|
|
91
|
+
try {
|
|
92
|
+
doc = readWU(wuPath, id);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
die(`Failed to read WU ${id}: ${error.message}\n\n` +
|
|
96
|
+
`Options:\n` +
|
|
97
|
+
` 1. Check if WU file exists: ls -la ${wuPath}\n` +
|
|
98
|
+
` 2. Validate YAML syntax: pnpm wu:validate --id ${id}`);
|
|
99
|
+
}
|
|
100
|
+
// Validate WU status is in_progress
|
|
101
|
+
if (doc.status !== WU_STATUS.IN_PROGRESS) {
|
|
102
|
+
die(`${EMOJI.FAILURE} WU ${id} status is '${doc.status}', expected '${WU_STATUS.IN_PROGRESS}'.\n\n` +
|
|
103
|
+
`wu:prep can only be run on WUs that are in progress.`);
|
|
104
|
+
}
|
|
105
|
+
console.log(`${PREP_PREFIX} Preparing ${id} for completion...`);
|
|
106
|
+
console.log(`${PREP_PREFIX} Location: ${location.cwd}`);
|
|
107
|
+
console.log(`${PREP_PREFIX} Main checkout: ${location.mainCheckout}`);
|
|
108
|
+
console.log('');
|
|
109
|
+
// Run gates in the worktree
|
|
110
|
+
console.log(`${PREP_PREFIX} Running gates in worktree...`);
|
|
111
|
+
const gatesResult = await runGates({
|
|
112
|
+
cwd: location.cwd,
|
|
113
|
+
docsOnly: args.docsOnly,
|
|
114
|
+
});
|
|
115
|
+
if (!gatesResult) {
|
|
116
|
+
die(`${EMOJI.FAILURE} Gates failed in worktree.\n\n` +
|
|
117
|
+
`Fix the gate failures and run wu:prep again.`);
|
|
118
|
+
}
|
|
119
|
+
// Success - print copy-paste instruction
|
|
120
|
+
printSuccessMessage(id, location.mainCheckout);
|
|
121
|
+
}
|
|
122
|
+
main().catch((e) => {
|
|
123
|
+
console.error(e.message);
|
|
124
|
+
process.exit(EXIT_CODES.ERROR);
|
|
125
|
+
});
|
package/dist/wu-prune.js
CHANGED
|
@@ -260,9 +260,10 @@ This tool:
|
|
|
260
260
|
}
|
|
261
261
|
process.exit(totalErrors > 0 ? EXIT_CODES.ERROR : EXIT_CODES.SUCCESS);
|
|
262
262
|
}
|
|
263
|
-
//
|
|
264
|
-
|
|
263
|
+
// WU-1181: Use import.meta.main instead of process.argv[1] comparison
|
|
264
|
+
// The old pattern fails with pnpm symlinks because process.argv[1] is the symlink
|
|
265
|
+
// path but import.meta.url resolves to the real path - they never match
|
|
265
266
|
import { runCLI } from './cli-entry-point.js';
|
|
266
|
-
if (
|
|
267
|
+
if (import.meta.main) {
|
|
267
268
|
runCLI(main);
|
|
268
269
|
}
|