@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.
Files changed (118) hide show
  1. package/README.md +147 -57
  2. package/dist/__tests__/agent-log-issue.test.js +56 -0
  3. package/dist/__tests__/cli-entry-point.test.js +66 -17
  4. package/dist/__tests__/cli-subprocess.test.js +25 -0
  5. package/dist/__tests__/init.test.js +298 -0
  6. package/dist/__tests__/initiative-plan.test.js +340 -0
  7. package/dist/__tests__/mem-cleanup-execution.test.js +19 -0
  8. package/dist/__tests__/merge-block.test.js +220 -0
  9. package/dist/__tests__/safe-git.test.js +191 -0
  10. package/dist/__tests__/state-doctor.test.js +274 -0
  11. package/dist/__tests__/wu-done.test.js +36 -0
  12. package/dist/__tests__/wu-edit.test.js +119 -0
  13. package/dist/__tests__/wu-prep.test.js +108 -0
  14. package/dist/agent-issues-query.js +4 -3
  15. package/dist/agent-log-issue.js +25 -4
  16. package/dist/backlog-prune.js +5 -4
  17. package/dist/cli-entry-point.js +11 -1
  18. package/dist/doctor.js +368 -0
  19. package/dist/flow-bottlenecks.js +6 -5
  20. package/dist/flow-report.js +4 -3
  21. package/dist/gates.js +356 -101
  22. package/dist/guard-locked.js +4 -3
  23. package/dist/guard-worktree-commit.js +4 -3
  24. package/dist/init.js +508 -86
  25. package/dist/initiative-add-wu.js +4 -3
  26. package/dist/initiative-bulk-assign-wus.js +8 -5
  27. package/dist/initiative-create.js +73 -37
  28. package/dist/initiative-edit.js +37 -21
  29. package/dist/initiative-list.js +4 -3
  30. package/dist/initiative-plan.js +337 -0
  31. package/dist/initiative-status.js +4 -3
  32. package/dist/lane-health.js +377 -0
  33. package/dist/lane-suggest.js +382 -0
  34. package/dist/mem-checkpoint.js +2 -2
  35. package/dist/mem-cleanup.js +2 -2
  36. package/dist/mem-context.js +306 -0
  37. package/dist/mem-create.js +2 -2
  38. package/dist/mem-delete.js +293 -0
  39. package/dist/mem-inbox.js +2 -2
  40. package/dist/mem-index.js +211 -0
  41. package/dist/mem-init.js +1 -1
  42. package/dist/mem-profile.js +207 -0
  43. package/dist/mem-promote.js +254 -0
  44. package/dist/mem-ready.js +2 -2
  45. package/dist/mem-signal.js +2 -2
  46. package/dist/mem-start.js +2 -2
  47. package/dist/mem-summarize.js +2 -2
  48. package/dist/mem-triage.js +2 -2
  49. package/dist/merge-block.js +222 -0
  50. package/dist/metrics-cli.js +7 -4
  51. package/dist/metrics-snapshot.js +4 -3
  52. package/dist/orchestrate-initiative.js +10 -4
  53. package/dist/orchestrate-monitor.js +379 -31
  54. package/dist/signal-cleanup.js +296 -0
  55. package/dist/spawn-list.js +6 -5
  56. package/dist/state-bootstrap.js +5 -4
  57. package/dist/state-cleanup.js +360 -0
  58. package/dist/state-doctor-fix.js +196 -0
  59. package/dist/state-doctor.js +501 -0
  60. package/dist/validate-agent-skills.js +4 -3
  61. package/dist/validate-agent-sync.js +4 -3
  62. package/dist/validate-backlog-sync.js +4 -3
  63. package/dist/validate-skills-spec.js +4 -3
  64. package/dist/validate.js +4 -3
  65. package/dist/wu-block.js +3 -3
  66. package/dist/wu-claim.js +208 -98
  67. package/dist/wu-cleanup.js +5 -4
  68. package/dist/wu-create.js +71 -46
  69. package/dist/wu-delete.js +88 -60
  70. package/dist/wu-deps.js +6 -5
  71. package/dist/wu-done-check.js +34 -0
  72. package/dist/wu-done.js +39 -12
  73. package/dist/wu-edit.js +63 -28
  74. package/dist/wu-infer-lane.js +7 -6
  75. package/dist/wu-preflight.js +23 -81
  76. package/dist/wu-prep.js +125 -0
  77. package/dist/wu-prune.js +4 -3
  78. package/dist/wu-recover.js +88 -22
  79. package/dist/wu-repair.js +7 -6
  80. package/dist/wu-spawn.js +226 -270
  81. package/dist/wu-status.js +4 -3
  82. package/dist/wu-unblock.js +5 -5
  83. package/dist/wu-unlock-lane.js +4 -3
  84. package/dist/wu-validate.js +5 -4
  85. package/package.json +16 -7
  86. package/templates/core/.lumenflow/constraints.md.template +192 -0
  87. package/templates/core/.lumenflow/rules/git-safety.md.template +27 -0
  88. package/templates/core/.lumenflow/rules/wu-workflow.md.template +48 -0
  89. package/templates/core/AGENTS.md.template +60 -0
  90. package/templates/core/LUMENFLOW.md.template +255 -0
  91. package/templates/core/UPGRADING.md.template +121 -0
  92. package/templates/core/ai/onboarding/agent-safety-card.md.template +106 -0
  93. package/templates/core/ai/onboarding/first-wu-mistakes.md.template +198 -0
  94. package/templates/core/ai/onboarding/quick-ref-commands.md.template +186 -0
  95. package/templates/core/ai/onboarding/release-process.md.template +362 -0
  96. package/templates/core/ai/onboarding/troubleshooting-wu-done.md.template +159 -0
  97. package/templates/core/ai/onboarding/wu-create-checklist.md.template +117 -0
  98. package/templates/vendors/aider/.aider.conf.yml.template +27 -0
  99. package/templates/vendors/claude/.claude/CLAUDE.md.template +52 -0
  100. package/templates/vendors/claude/.claude/settings.json.template +49 -0
  101. package/templates/vendors/claude/.claude/skills/bug-classification/SKILL.md.template +192 -0
  102. package/templates/vendors/claude/.claude/skills/code-quality/SKILL.md.template +152 -0
  103. package/templates/vendors/claude/.claude/skills/context-management/SKILL.md.template +155 -0
  104. package/templates/vendors/claude/.claude/skills/execution-memory/SKILL.md.template +304 -0
  105. package/templates/vendors/claude/.claude/skills/frontend-design/SKILL.md.template +131 -0
  106. package/templates/vendors/claude/.claude/skills/initiative-management/SKILL.md.template +164 -0
  107. package/templates/vendors/claude/.claude/skills/library-first/SKILL.md.template +98 -0
  108. package/templates/vendors/claude/.claude/skills/lumenflow-gates/SKILL.md.template +87 -0
  109. package/templates/vendors/claude/.claude/skills/multi-agent-coordination/SKILL.md.template +84 -0
  110. package/templates/vendors/claude/.claude/skills/ops-maintenance/SKILL.md.template +254 -0
  111. package/templates/vendors/claude/.claude/skills/orchestration/SKILL.md.template +189 -0
  112. package/templates/vendors/claude/.claude/skills/tdd-workflow/SKILL.md.template +139 -0
  113. package/templates/vendors/claude/.claude/skills/worktree-discipline/SKILL.md.template +138 -0
  114. package/templates/vendors/claude/.claude/skills/wu-lifecycle/SKILL.md.template +106 -0
  115. package/templates/vendors/cline/.clinerules.template +53 -0
  116. package/templates/vendors/cursor/.cursor/rules/lumenflow.md.template +34 -0
  117. package/templates/vendors/cursor/.cursor/rules.md.template +28 -0
  118. package/templates/vendors/windsurf/.windsurf/rules/lumenflow.md.template +34 -0
package/README.md CHANGED
@@ -13,6 +13,25 @@
13
13
  npm install @lumenflow/cli
14
14
  ```
15
15
 
16
+ ## Quick Start
17
+
18
+ ```bash
19
+ # Initialize LumenFlow (works with any AI)
20
+ npx lumenflow-init
21
+
22
+ # Or specify your AI tool for enhanced integration
23
+ npx lumenflow-init --client claude # Claude Code
24
+ npx lumenflow-init --client cursor # Cursor
25
+ npx lumenflow-init --client windsurf # Windsurf
26
+ npx lumenflow-init --client cline # Cline
27
+ npx lumenflow-init --client aider # Aider
28
+ npx lumenflow-init --client all # All integrations
29
+ ```
30
+
31
+ The default `lumenflow-init` creates `AGENTS.md` and `LUMENFLOW.md` which work with **any AI coding assistant**. The `--client` flag adds vendor-specific configuration files for deeper integration.
32
+
33
+ See [AI Integrations](https://lumenflow.dev/guides/ai-integrations) for details on each tool.
34
+
16
35
  ## Overview
17
36
 
18
37
  This package provides CLI commands for the LumenFlow workflow framework, including:
@@ -24,63 +43,134 @@ This package provides CLI commands for the LumenFlow workflow framework, includi
24
43
 
25
44
  ## Commands
26
45
 
27
- ### Work Unit Commands
28
-
29
- | Command | Description |
30
- | --------------- | ---------------------------------------------------- |
31
- | `wu-claim` | Claim a WU and create a worktree |
32
- | `wu-done` | Complete a WU (runs gates, merges, creates stamp) |
33
- | `wu-block` | Mark a WU as blocked with reason |
34
- | `wu-unblock` | Remove blocked status from a WU |
35
- | `wu-create` | Create a new WU specification |
36
- | `wu-edit` | Edit an existing WU specification |
37
- | `wu-spawn` | Generate spawn prompt for delegating WU to sub-agent |
38
- | `wu-validate` | Validate WU YAML against schema |
39
- | `wu-preflight` | Pre-claim validation checks |
40
- | `wu-repair` | Repair corrupted WU state |
41
- | `wu-prune` | Clean up stale worktrees |
42
- | `wu-cleanup` | Post-merge cleanup for a WU |
43
- | `wu-deps` | Display WU dependency graph |
44
- | `wu-infer-lane` | Infer lane from WU content |
45
-
46
- ### Memory Commands
47
-
48
- | Command | Description |
49
- | ---------------- | ---------------------------------------- |
50
- | `mem-init` | Initialize memory directory structure |
51
- | `mem-start` | Start a new memory session |
52
- | `mem-checkpoint` | Create a progress checkpoint |
53
- | `mem-ready` | Query pending nodes for a WU |
54
- | `mem-signal` | Send coordination signal to other agents |
55
- | `mem-inbox` | Check incoming coordination signals |
56
- | `mem-create` | Create a memory node |
57
- | `mem-summarize` | Roll up nodes for context compaction |
58
- | `mem-triage` | Triage discovered bugs |
59
- | `mem-cleanup` | Clean up expired memory nodes |
60
-
61
- ### Initiative Commands
62
-
63
- | Command | Description |
64
- | ------------------- | ----------------------------------- |
65
- | `initiative-create` | Create a new initiative |
66
- | `initiative-edit` | Edit an existing initiative |
67
- | `initiative-list` | List all initiatives |
68
- | `initiative-status` | Show initiative status and progress |
69
- | `initiative-add-wu` | Link a WU to an initiative |
70
-
71
- ### Setup Commands
72
-
73
- | Command | Description |
74
- | ----------- | --------------------------------------------------- |
75
- | `init` | Scaffold LumenFlow into a project |
76
- | `docs-sync` | Sync agent onboarding docs (for upgrading projects) |
77
-
78
- ### Other Commands
79
-
80
- | Command | Description |
81
- | ------------ | -------------------------------------------------- |
82
- | `gates` | Run quality gates (format, lint, typecheck, tests) |
83
- | `spawn-list` | List active spawned agents |
46
+ ### Work Unit Management
47
+
48
+ | Command | Description |
49
+ | ---------------- | ----------------------------------------------------------------------------------------------------------- |
50
+ | `wu-block` | Block a work unit and move it from in-progress to blocked status |
51
+ | `wu-claim` | Claim a work unit by creating a worktree/branch and updating status |
52
+ | `wu-cleanup` | Clean up worktree and branch after PR merge (PR-based completion workflow) |
53
+ | `wu-create` | Create a new Work Unit with micro-worktree isolation (race-safe). Auto-generates ID if `--id` not provided. |
54
+ | `wu-delete` | Safely delete WU YAML files with micro-worktree isolation |
55
+ | `wu-deps` | Visualize WU dependency graph |
56
+ | `wu-done` | Complete a WU (runs gates, merges, creates stamp) |
57
+ | `wu-edit` | Edit WU spec files with micro-worktree isolation |
58
+ | `wu-infer-lane` | Suggest sub-lane for a WU based on content |
59
+ | `wu-preflight` | Fast validation of code paths and test paths before gates |
60
+ | `wu-prune` | Maintain worktree hygiene (prune stale worktrees, detect orphans) |
61
+ | `wu-recover` | Analyze and fix WU state inconsistencies |
62
+ | `wu-release` | Release an orphaned WU from in_progress back to ready state |
63
+ | `wu-repair` | Unified WU repair tool - detect and fix WU state issues |
64
+ | `wu-spawn` | Generate Task tool invocation for sub-agent WU execution |
65
+ | `wu-status` | Show WU status, location, and valid commands |
66
+ | `wu-unblock` | Unblock a work unit and move it from blocked to in-progress status |
67
+ | `wu-unlock-lane` | Safely unlock a lane lock with audit logging |
68
+ | `wu-validate` | Validate WU YAML files against schema |
69
+
70
+ ### Memory & Session
71
+
72
+ | Command | Description |
73
+ | --------------------- | ----------------------------------------------------------- |
74
+ | `agent-issues-query` | Show summary of logged issues |
75
+ | `agent-log-issue` | Log a workflow issue or incident |
76
+ | `agent-session` | Start an agent session |
77
+ | `agent-session-end` | End the current agent session |
78
+ | `mem-checkpoint` | Create a checkpoint node for context snapshots |
79
+ | `mem-cleanup` | Prune closed memory nodes based on lifecycle policy and TTL |
80
+ | `mem-create` | Create a memory node with optional provenance tracking |
81
+ | `mem-export` | Export memory nodes as markdown or JSON |
82
+ | `mem-inbox` | Read coordination signals from other agents |
83
+ | `mem-init` | Initialize memory layer in repository |
84
+ | `mem-ready` | Query ready nodes for a WU (deterministic ordering) |
85
+ | `mem-signal` | Send a coordination signal to other agents |
86
+ | `mem-start` | Create a session node linked to a WU |
87
+ | `mem-summarize` | Rollup older memory nodes into summary nodes for compaction |
88
+ | `mem-triage` | Review discovery nodes and promote to WUs or archive |
89
+ | `session-coordinator` | Manage agent sessions for WU work coordination |
90
+ | `signal-cleanup` | Prune old signals based on TTL policy to prevent growth |
91
+
92
+ ### Initiative Orchestration
93
+
94
+ | Command | Description |
95
+ | ---------------------------- | ------------------------------------------------------------- |
96
+ | `init-plan` | Link a plan file to an initiative |
97
+ | `initiative-add-wu` | Link a WU to an initiative bidirectionally |
98
+ | `initiative-bulk-assign-wus` | Bulk-assign orphaned WUs to initiatives based on lane rules |
99
+ | `initiative-create` | Create a new Initiative with micro-worktree isolation |
100
+ | `initiative-edit` | Edit Initiative YAML files with micro-worktree isolation |
101
+ | `initiative-list` | List all initiatives with progress percentages |
102
+ | `initiative-status` | Show detailed initiative view with phases and WUs |
103
+ | `orchestrate-init-status` | Show initiative progress status |
104
+ | `orchestrate-initiative` | Orchestrate initiative execution with parallel agent spawning |
105
+ | `orchestrate-monitor` | Monitor spawned agent progress |
106
+ | `rotate-progress` | Move completed WUs from status.md to Completed section |
107
+ | `spawn-list` | Display spawn trees for WUs or initiatives |
108
+
109
+ ### Metrics & Analytics
110
+
111
+ | Command | Description |
112
+ | ------------------- | -------------------------------------------------------------- |
113
+ | `flow-bottlenecks` | Analyze WU dependency graph for bottlenecks and critical paths |
114
+ | `flow-report` | Generate DORA/SPACE flow report from telemetry and WU data |
115
+ | `lumenflow-metrics` | LumenFlow metrics CLI (lanes, dora, flow) |
116
+ | `metrics` | Alias for `lumenflow-metrics` |
117
+ | `metrics-snapshot` | Capture DORA metrics, lane health, and flow state snapshot |
118
+ | `trace-gen` | Generate traceability reports linking WUs to code changes |
119
+
120
+ ### Lane Tooling
121
+
122
+ | Command | Description |
123
+ | -------------- | --------------------------------------------------------------------- |
124
+ | `lane-health` | Check lane configuration health (overlaps, coverage gaps) |
125
+ | `lane-suggest` | LLM-driven lane suggestions based on codebase context and git history |
126
+
127
+ ### Verification & Gates
128
+
129
+ | Command | Description |
130
+ | ----------------------- | --------------------------------------------------------- |
131
+ | `gates` | Run quality gates (format, lint, typecheck, tests) |
132
+ | `guard-locked` | Check if a WU is locked (exits 1 if locked) |
133
+ | `guard-main-branch` | Check if current branch is protected and block operations |
134
+ | `guard-worktree-commit` | Check if a WU commit should be blocked from main checkout |
135
+ | `lumenflow-gates` | Alias for `gates` |
136
+ | `lumenflow-validate` | Validate WU YAML files for schema and quality |
137
+ | `validate` | Alias for `lumenflow-validate` |
138
+ | `validate-agent-skills` | Validate agent skill definitions |
139
+ | `validate-agent-sync` | Validate agent configuration and sync state |
140
+ | `validate-backlog-sync` | Validate that backlog.md is in sync with WU YAML files |
141
+ | `validate-skills-spec` | Validate skill specification format |
142
+
143
+ ### System & Setup
144
+
145
+ | Command | Description |
146
+ | -------------------------- | --------------------------------------------------------- |
147
+ | `backlog-prune` | Maintain backlog hygiene (archive old WUs) |
148
+ | `deps-add` | Add dependencies with worktree discipline enforcement |
149
+ | `deps-remove` | Remove dependencies with worktree discipline enforcement |
150
+ | `lumenflow` | CLI entry point (scaffold/init) |
151
+ | `lumenflow-docs-sync` | Sync agent onboarding docs to existing projects |
152
+ | `lumenflow-init` | Initialize LumenFlow in a project |
153
+ | `lumenflow-release` | Release @lumenflow/\* packages to npm |
154
+ | `lumenflow-sync-templates` | Sync internal docs to CLI templates |
155
+ | `lumenflow-upgrade` | Upgrade all @lumenflow/\* packages to a specified version |
156
+ | `state-bootstrap` | One-time migration utility for state sourcing |
157
+ | `state-cleanup` | Unified cleanup: signals, memory, and event archival |
158
+ | `state-doctor` | Check state integrity and detect inconsistencies |
159
+ | `lumenflow-doctor` | Alias for `state-doctor` |
160
+ | `sync-templates` | Alias for `lumenflow-sync-templates` |
161
+
162
+ ### File & Git Operations
163
+
164
+ | Command | Description |
165
+ | ------------- | -------------------------------------------------------------- |
166
+ | `file-delete` | Delete a file or directory with audit logging |
167
+ | `file-edit` | Edit file by replacing exact string matches with audit logging |
168
+ | `file-read` | Read file content with audit logging |
169
+ | `file-write` | Write content to a file with audit logging |
170
+ | `git-branch` | List, create, or delete branches |
171
+ | `git-diff` | Show changes between commits, commit and working tree |
172
+ | `git-log` | Show commit logs |
173
+ | `git-status` | Show the working tree status |
84
174
 
85
175
  ## Usage
86
176
 
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Tests for agent-log-issue CLI
3
+ *
4
+ * WU-1182: Validates that agent-log-issue.ts uses Commander.js repeatable
5
+ * options pattern instead of comma-separated splits for --tags and --files.
6
+ *
7
+ * Per Commander.js best practices:
8
+ * - Repeatable: --tag a --tag b → ['a', 'b'] (explicit, no ambiguity)
9
+ * - Comma-split: --tags "a,b" → splits on comma (ambiguous if values contain commas)
10
+ *
11
+ * The repeatable pattern is preferred for multi-value options.
12
+ */
13
+ import { describe, it, expect } from 'vitest';
14
+ import { readFileSync } from 'node:fs';
15
+ import path from 'node:path';
16
+ describe('WU-1182: agent-log-issue CLI patterns', () => {
17
+ const srcDir = path.resolve(__dirname, '..');
18
+ const filePath = path.join(srcDir, 'agent-log-issue.ts');
19
+ const content = readFileSync(filePath, 'utf-8');
20
+ describe('--tags option', () => {
21
+ it('should use repeatable pattern instead of comma-separated', () => {
22
+ // Should NOT have comma-split pattern for tags
23
+ const hasCommaSplit = /opts\.tags\s*\?\s*opts\.tags\.split\s*\(\s*['"],['"]/.test(content);
24
+ expect(hasCommaSplit, 'should not use comma-split for --tags').toBe(false);
25
+ });
26
+ it('should define --tag as repeatable option (not --tags with comma)', () => {
27
+ // Should have repeatable option pattern with collect function
28
+ // Either using Commander's variadic syntax (...) or custom collect function
29
+ const hasRepeatableTag = /\.option\s*\(\s*['"]--tag\s+</.test(content) ||
30
+ /\.option\s*\(\s*['"]--tags?\s+<[^>]+>\.\.\./.test(content) ||
31
+ /collect(?:Repeatable)?/.test(content);
32
+ expect(hasRepeatableTag, 'should use repeatable --tag option or collect function').toBe(true);
33
+ });
34
+ });
35
+ describe('--files option', () => {
36
+ it('should use repeatable pattern instead of comma-separated', () => {
37
+ // Should NOT have comma-split pattern for files
38
+ const hasCommaSplit = /opts\.files\s*\?\s*opts\.files\.split\s*\(\s*['"],['"]/.test(content);
39
+ expect(hasCommaSplit, 'should not use comma-split for --files').toBe(false);
40
+ });
41
+ it('should define --file as repeatable option (not --files with comma)', () => {
42
+ // Should have repeatable option pattern
43
+ const hasRepeatableFile = /\.option\s*\(\s*['"]--file\s+</.test(content) ||
44
+ /\.option\s*\(\s*['"]--files?\s+<[^>]+>\.\.\./.test(content) ||
45
+ /collect(?:Repeatable)?/.test(content);
46
+ expect(hasRepeatableFile, 'should use repeatable --file option or collect function').toBe(true);
47
+ });
48
+ });
49
+ describe('Commander.js best practices', () => {
50
+ it('should not import comma-split utility functions', () => {
51
+ // Should not have custom comma-split helper
52
+ const hasCommaSplitHelper = /commaSeparatedList|splitComma/.test(content);
53
+ expect(hasCommaSplitHelper, 'should not use comma-split helpers').toBe(false);
54
+ });
55
+ });
56
+ });
@@ -10,7 +10,7 @@
10
10
  * instead of the broken process.argv[1] === fileURLToPath(import.meta.url) pattern.
11
11
  */
12
12
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
13
- import { readFileSync } from 'node:fs';
13
+ import { readFileSync, readdirSync } from 'node:fs';
14
14
  import path from 'node:path';
15
15
  import { runCLI } from '../cli-entry-point.js';
16
16
  import { EXIT_CODES } from '@lumenflow/core/dist/wu-constants.js';
@@ -54,7 +54,7 @@ describe('runCLI', () => {
54
54
  });
55
55
  });
56
56
  /**
57
- * WU-1071: Verify CLI entry points use import.meta.main pattern
57
+ * WU-1071/WU-1181: Verify CLI entry points use import.meta.main pattern
58
58
  *
59
59
  * The old pattern `process.argv[1] === fileURLToPath(import.meta.url)` fails with
60
60
  * pnpm symlinks because process.argv[1] is the symlink path but import.meta.url
@@ -62,34 +62,80 @@ describe('runCLI', () => {
62
62
  *
63
63
  * The fix is to use `import.meta.main` (Node.js 22.16.0+ built-in) which correctly
64
64
  * handles symlinks.
65
+ *
66
+ * WU-1181: Extended to validate ALL CLI files with entry guards, not just a subset.
65
67
  */
66
- describe('WU-1071: CLI entry point patterns', () => {
67
- // CLI files that should have the main() entry guard
68
- const CLI_FILES_WITH_ENTRY_GUARD = [
69
- 'gates.ts',
70
- 'wu-spawn.ts',
71
- 'wu-create.ts',
72
- 'wu-claim.ts',
73
- 'wu-done.ts',
74
- ];
68
+ describe('WU-1071/WU-1181: CLI entry point patterns', () => {
69
+ // Files that should NOT be checked for entry guards
70
+ // (helper modules, index files, tests, or files without CLI entry points)
71
+ const EXCLUDED_FILES = new Set([
72
+ 'cli-entry-point.ts', // Helper module, not a CLI entry point itself
73
+ 'index.ts', // Re-exports only
74
+ 'merge-block.ts', // Not a CLI entry point (no main guard needed)
75
+ 'wu-done-check.ts', // Not a CLI entry point (no main guard needed)
76
+ 'wu-spawn-completion.ts', // Not a CLI entry point (helper module)
77
+ 'agent-session.ts', // Not a CLI entry point (helper module)
78
+ 'agent-session-end.ts', // Not a CLI entry point (helper module)
79
+ 'agent-log-issue.ts', // Not a CLI entry point (helper module)
80
+ 'orchestrate-init-status.ts', // Not a CLI entry point (helper module)
81
+ 'orchestrate-initiative.ts', // Not a CLI entry point (helper module)
82
+ 'orchestrate-monitor.ts', // Not a CLI entry point (helper module)
83
+ 'initiative-edit.ts', // Not a CLI entry point (no main guard)
84
+ 'wu-block.ts', // Not a CLI entry point (no main guard)
85
+ 'wu-unblock.ts', // Not a CLI entry point (no main guard)
86
+ 'wu-release.ts', // Not a CLI entry point (no main guard)
87
+ 'wu-delete.ts', // Not a CLI entry point (no main guard)
88
+ 'init.ts', // Not a CLI entry point (no main guard)
89
+ ]);
75
90
  // Old broken pattern that fails with pnpm symlinks
76
91
  const OLD_BROKEN_PATTERN = /if\s*\(\s*process\.argv\[1\]\s*===\s*fileURLToPath\(import\.meta\.url\)\s*\)/;
77
92
  // New working pattern using import.meta.main
78
93
  const NEW_WORKING_PATTERN = /if\s*\(\s*import\.meta\.main\s*\)/;
79
- it('should use import.meta.main instead of process.argv[1] comparison', () => {
94
+ /**
95
+ * Discovers all CLI files with entry guards by scanning the src directory.
96
+ * A file is considered to have an entry guard if it contains either:
97
+ * - The old broken pattern: if (process.argv[1] === fileURLToPath(import.meta.url))
98
+ * - The new working pattern: if (import.meta.main)
99
+ */
100
+ function discoverCLIFilesWithEntryGuards() {
101
+ const srcDir = path.resolve(__dirname, '..');
102
+ const files = readdirSync(srcDir).filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && !EXCLUDED_FILES.has(f));
103
+ return files.filter((file) => {
104
+ const content = readFileSync(path.join(srcDir, file), 'utf-8');
105
+ return OLD_BROKEN_PATTERN.test(content) || NEW_WORKING_PATTERN.test(content);
106
+ });
107
+ }
108
+ it('should discover all CLI files with entry guards', () => {
109
+ const cliFiles = discoverCLIFilesWithEntryGuards();
110
+ // WU-1181: There should be a significant number of CLI files with entry guards
111
+ // This test ensures we're actually discovering files, not returning an empty list
112
+ expect(cliFiles.length).toBeGreaterThan(40);
113
+ });
114
+ it('should use import.meta.main instead of process.argv[1] comparison in ALL CLI files', () => {
80
115
  const srcDir = path.resolve(__dirname, '..');
81
- for (const file of CLI_FILES_WITH_ENTRY_GUARD) {
116
+ const cliFiles = discoverCLIFilesWithEntryGuards();
117
+ const errors = [];
118
+ for (const file of cliFiles) {
82
119
  const filePath = path.join(srcDir, file);
83
120
  const content = readFileSync(filePath, 'utf-8');
84
121
  // Should NOT have old broken pattern
85
- expect(OLD_BROKEN_PATTERN.test(content), `${file} should not use the old broken pattern (process.argv[1] === fileURLToPath)`).toBe(false);
122
+ if (OLD_BROKEN_PATTERN.test(content)) {
123
+ errors.push(`${file} uses the old broken pattern (process.argv[1] === fileURLToPath)`);
124
+ }
86
125
  // Should have new working pattern
87
- expect(NEW_WORKING_PATTERN.test(content), `${file} should use import.meta.main pattern`).toBe(true);
126
+ if (!NEW_WORKING_PATTERN.test(content)) {
127
+ errors.push(`${file} does not use import.meta.main pattern`);
128
+ }
129
+ }
130
+ if (errors.length > 0) {
131
+ expect.fail(`Entry point pattern violations:\n${errors.join('\n')}`);
88
132
  }
89
133
  });
90
134
  it('should not have unused fileURLToPath imports in CLI files with entry guards', () => {
91
135
  const srcDir = path.resolve(__dirname, '..');
92
- for (const file of CLI_FILES_WITH_ENTRY_GUARD) {
136
+ const cliFiles = discoverCLIFilesWithEntryGuards();
137
+ const errors = [];
138
+ for (const file of cliFiles) {
93
139
  const filePath = path.join(srcDir, file);
94
140
  const content = readFileSync(filePath, 'utf-8');
95
141
  // If the file imports fileURLToPath, it should actually use it somewhere
@@ -97,9 +143,12 @@ describe('WU-1071: CLI entry point patterns', () => {
97
143
  const hasFileURLToPathImport = /import\s*{[^}]*fileURLToPath[^}]*}\s*from\s*['"]node:url['"]/.test(content);
98
144
  const usesFileURLToPath = /fileURLToPath\(/.test(content);
99
145
  if (hasFileURLToPathImport && !usesFileURLToPath) {
100
- expect.fail(`${file} imports fileURLToPath but does not use it - remove unused import`);
146
+ errors.push(`${file} imports fileURLToPath but does not use it - remove unused import`);
101
147
  }
102
148
  }
149
+ if (errors.length > 0) {
150
+ expect.fail(`Unused fileURLToPath imports:\n${errors.join('\n')}`);
151
+ }
103
152
  });
104
153
  it('cli-entry-point.ts JSDoc should document import.meta.main pattern', () => {
105
154
  const srcDir = path.resolve(__dirname, '..');
@@ -61,4 +61,29 @@ describe('CLI subprocess error handling', () => {
61
61
  expect(result.stderr.length + result.stdout.length).toBeGreaterThan(0);
62
62
  });
63
63
  });
64
+ describe('wu-preflight (WU-1180)', () => {
65
+ it('should show proper Commander help when --help is passed', () => {
66
+ const result = runCLI('wu-preflight', ['--help']);
67
+ // Help should work
68
+ expect(result.code).toBe(0);
69
+ expect(result.stdout).toContain('Usage');
70
+ expect(result.stdout).toContain('Options');
71
+ // Should have the standard Commander format with -h, --help
72
+ expect(result.stdout).toMatch(/-h,\s*--help/);
73
+ });
74
+ it('should show proper Commander help format with option descriptions', () => {
75
+ const result = runCLI('wu-preflight', ['--help']);
76
+ expect(result.code).toBe(0);
77
+ // Should include option descriptions in Commander format
78
+ expect(result.stdout).toContain('--id');
79
+ expect(result.stdout).toContain('--worktree');
80
+ });
81
+ it('should exit with non-zero code when required --id option is missing', () => {
82
+ const result = runCLI('wu-preflight', []);
83
+ // Should NOT exit 0 (silent failure)
84
+ expect(result.code).not.toBe(0);
85
+ // Should have some error output
86
+ expect(result.stderr.length + result.stdout.length).toBeGreaterThan(0);
87
+ });
88
+ });
64
89
  });