@lumenflow/cli 1.3.6 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # @lumenflow/cli
2
2
 
3
- Command-line interface for LumenFlow workflow management.
3
+ [![npm version](https://img.shields.io/npm/v/@lumenflow/cli.svg)](https://www.npmjs.com/package/@lumenflow/cli)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@lumenflow/cli.svg)](https://www.npmjs.com/package/@lumenflow/cli)
5
+ [![license](https://img.shields.io/npm/l/@lumenflow/cli.svg)](https://github.com/hellmai/os/blob/main/LICENSE)
6
+ [![node](https://img.shields.io/node/v/@lumenflow/cli.svg)](https://nodejs.org)
7
+
8
+ > Command-line interface for LumenFlow workflow framework
4
9
 
5
10
  ## Installation
6
11
 
@@ -63,6 +68,13 @@ This package provides CLI commands for the LumenFlow workflow framework, includi
63
68
  | `initiative-status` | Show initiative status and progress |
64
69
  | `initiative-add-wu` | Link a WU to an initiative |
65
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
+
66
78
  ### Other Commands
67
79
 
68
80
  | Command | Description |
@@ -98,6 +110,23 @@ npx wu-claim --id WU-123 --lane operations
98
110
  npx gates
99
111
  ```
100
112
 
113
+ ## Global Flags
114
+
115
+ All commands support these flags:
116
+
117
+ | Flag | Description |
118
+ | ----------------- | ------------------------- |
119
+ | `--help`, `-h` | Show help for the command |
120
+ | `--version`, `-V` | Show version number |
121
+ | `--no-color` | Disable colored output |
122
+
123
+ ## Environment Variables
124
+
125
+ | Variable | Description |
126
+ | ------------- | -------------------------------------------------------------------------------------- |
127
+ | `NO_COLOR` | Disable colored output when set (any value, per [no-color.org](https://no-color.org/)) |
128
+ | `FORCE_COLOR` | Override color level: `0` (disabled), `1` (basic), `2` (256 colors), `3` (16m colors) |
129
+
101
130
  ## Integration
102
131
 
103
132
  The CLI integrates with other LumenFlow packages:
@@ -109,7 +138,7 @@ The CLI integrates with other LumenFlow packages:
109
138
 
110
139
  ## Documentation
111
140
 
112
- For complete documentation, see the [LumenFlow documentation](https://github.com/hellmai/os).
141
+ For complete documentation, see [lumenflow.dev](https://lumenflow.dev/reference/cli).
113
142
 
114
143
  ## License
115
144
 
@@ -10,6 +10,8 @@
10
10
  * path but import.meta.url resolves to the real path - they never match
11
11
  * so main() is never called.
12
12
  *
13
+ * WU-1085: Initializes color support respecting NO_COLOR/FORCE_COLOR/--no-color
14
+ *
13
15
  * @example
14
16
  * ```typescript
15
17
  * // At the bottom of each CLI file:
@@ -21,13 +23,17 @@
21
23
  * ```
22
24
  */
23
25
  import { EXIT_CODES } from '@lumenflow/core/dist/wu-constants.js';
26
+ import { initColorSupport } from '@lumenflow/core';
24
27
  /**
25
28
  * Wraps an async main function with proper error handling.
29
+ * WU-1085: Also initializes color support based on NO_COLOR/FORCE_COLOR/--no-color
26
30
  *
27
31
  * @param main - The async main function to execute
28
32
  * @returns Promise that resolves when main completes (or after error handling)
29
33
  */
30
34
  export async function runCLI(main) {
35
+ // WU-1085: Initialize color support before running command
36
+ initColorSupport();
31
37
  try {
32
38
  await main();
33
39
  }
@@ -0,0 +1,467 @@
1
+ /**
2
+ * @file docs-sync.ts
3
+ * LumenFlow docs:sync command for syncing agent docs to existing projects (WU-1083)
4
+ * WU-1085: Added createWUParser for proper --help support
5
+ */
6
+ import * as fs from 'node:fs';
7
+ import * as path from 'node:path';
8
+ import { createWUParser, WU_OPTIONS } from '@lumenflow/core';
9
+ /**
10
+ * WU-1085: CLI option definitions for docs-sync command
11
+ */
12
+ const DOCS_SYNC_OPTIONS = {
13
+ vendor: {
14
+ name: 'vendor',
15
+ flags: '--vendor <type>',
16
+ description: 'Vendor type (claude, cursor, aider, all, none)',
17
+ default: 'claude',
18
+ },
19
+ force: WU_OPTIONS.force,
20
+ };
21
+ /**
22
+ * WU-1085: Parse docs-sync command options using createWUParser
23
+ * Provides proper --help, --version, and option parsing
24
+ */
25
+ export function parseDocsSyncOptions() {
26
+ const opts = createWUParser({
27
+ name: 'lumenflow-docs-sync',
28
+ description: 'Sync agent onboarding docs to existing projects (skips existing files by default)',
29
+ options: Object.values(DOCS_SYNC_OPTIONS),
30
+ });
31
+ return {
32
+ force: opts.force ?? false,
33
+ vendor: opts.vendor ?? 'claude',
34
+ };
35
+ }
36
+ /**
37
+ * Get current date in YYYY-MM-DD format
38
+ */
39
+ function getCurrentDate() {
40
+ return new Date().toISOString().split('T')[0];
41
+ }
42
+ /**
43
+ * Process template content by replacing placeholders
44
+ */
45
+ function processTemplate(content, tokens) {
46
+ let output = content;
47
+ for (const [key, value] of Object.entries(tokens)) {
48
+ output = output.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value);
49
+ }
50
+ return output;
51
+ }
52
+ function getRelativePath(targetDir, filePath) {
53
+ return path.relative(targetDir, filePath).split(path.sep).join('/');
54
+ }
55
+ /**
56
+ * Create a directory if missing
57
+ */
58
+ async function createDirectory(dirPath, result, targetDir) {
59
+ if (!fs.existsSync(dirPath)) {
60
+ fs.mkdirSync(dirPath, { recursive: true });
61
+ result.created.push(getRelativePath(targetDir, dirPath));
62
+ }
63
+ }
64
+ /**
65
+ * Create a file, respecting force option
66
+ */
67
+ async function createFile(filePath, content, force, result, targetDir) {
68
+ const relativePath = getRelativePath(targetDir, filePath);
69
+ if (fs.existsSync(filePath) && !force) {
70
+ result.skipped.push(relativePath);
71
+ return;
72
+ }
73
+ const parentDir = path.dirname(filePath);
74
+ if (!fs.existsSync(parentDir)) {
75
+ fs.mkdirSync(parentDir, { recursive: true });
76
+ }
77
+ fs.writeFileSync(filePath, content);
78
+ result.created.push(relativePath);
79
+ }
80
+ // Agent onboarding docs templates (duplicated from init.ts for modularity)
81
+ const QUICK_REF_COMMANDS_TEMPLATE = `# Quick Reference: LumenFlow Commands
82
+
83
+ **Last updated:** {{DATE}}
84
+
85
+ ---
86
+
87
+ ## Project Setup
88
+
89
+ | Command | Description |
90
+ | --------------------------------------------- | --------------------------------------- |
91
+ | \`pnpm exec lumenflow init\` | Scaffold minimal LumenFlow core |
92
+ | \`pnpm exec lumenflow init --full\` | Add docs/04-operations task scaffolding |
93
+ | \`pnpm exec lumenflow init --framework <name>\` | Add framework hint + overlay docs |
94
+ | \`pnpm exec lumenflow init --force\` | Overwrite existing files |
95
+
96
+ ---
97
+
98
+ ## WU Management
99
+
100
+ | Command | Description |
101
+ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
102
+ | \`pnpm wu:create --id WU-XXX --lane <Lane> --title "Title" --description "..." --acceptance "..." --code-paths "path" --test-paths-unit "path" --exposure backend-only --spec-refs "~/.lumenflow/plans/WU-XXX.md"\` | Create new WU |
103
+ | \`pnpm wu:claim --id WU-XXX --lane <Lane>\` | Claim WU (creates worktree) |
104
+ | \`pnpm wu:done --id WU-XXX\` | Complete WU (merge, stamp, cleanup) |
105
+ | \`pnpm wu:block --id WU-XXX --reason "Reason"\` | Block a WU |
106
+ | \`pnpm wu:unblock --id WU-XXX\` | Unblock a WU |
107
+
108
+ ---
109
+
110
+ ## Gates
111
+
112
+ | Command | Description |
113
+ | ------------------------ | -------------------------- |
114
+ | \`pnpm gates\` | Run all quality gates |
115
+ | \`pnpm gates --docs-only\` | Run gates for docs changes |
116
+ | \`pnpm format\` | Format all files |
117
+ | \`pnpm lint\` | Run linter |
118
+ | \`pnpm typecheck\` | Run TypeScript check |
119
+
120
+ ---
121
+
122
+ ## File Paths
123
+
124
+ | Path | Description |
125
+ | ----------------------------------------- | -------------------- |
126
+ | \`docs/04-operations/tasks/wu/WU-XXX.yaml\` | WU specification |
127
+ | \`docs/04-operations/tasks/status.md\` | Current status board |
128
+ | \`.lumenflow/stamps/WU-XXX.done\` | Completion stamp |
129
+ | \`worktrees/<lane>-wu-xxx/\` | Worktree directory |
130
+ `;
131
+ const FIRST_WU_MISTAKES_TEMPLATE = `# First WU Mistakes
132
+
133
+ **Last updated:** {{DATE}}
134
+
135
+ Common mistakes agents make on their first WU, and how to avoid them.
136
+
137
+ ---
138
+
139
+ ## Mistake 1: Not Using Worktrees
140
+
141
+ ### Wrong
142
+
143
+ \`\`\`bash
144
+ # Working directly in main
145
+ vim src/feature.ts
146
+ git commit -m "feat: add feature"
147
+ git push origin main
148
+ \`\`\`
149
+
150
+ ### Right
151
+
152
+ \`\`\`bash
153
+ # Claim first, then work in worktree
154
+ pnpm wu:claim --id WU-123 --lane Core
155
+ cd worktrees/core-wu-123
156
+ vim src/feature.ts
157
+ git commit -m "feat: add feature"
158
+ git push origin lane/core/wu-123
159
+ cd /path/to/main
160
+ pnpm wu:done --id WU-123
161
+ \`\`\`
162
+
163
+ ---
164
+
165
+ ## Mistake 2: Forgetting to Run wu:done
166
+
167
+ **TL;DR:** After gates pass, ALWAYS run \`pnpm wu:done --id WU-XXX\`.
168
+
169
+ ---
170
+
171
+ ## Mistake 3: Working Outside code_paths
172
+
173
+ Only edit files within the specified \`code_paths\`.
174
+
175
+ ---
176
+
177
+ ## Quick Checklist
178
+
179
+ - [ ] Claim the WU with \`pnpm wu:claim\`
180
+ - [ ] cd to the worktree IMMEDIATELY
181
+ - [ ] Work only in the worktree
182
+ - [ ] Run gates before wu:done
183
+ - [ ] ALWAYS run wu:done
184
+ `;
185
+ const TROUBLESHOOTING_WU_DONE_TEMPLATE = `# Troubleshooting: wu:done Not Run
186
+
187
+ **Last updated:** {{DATE}}
188
+
189
+ This is the most common mistake agents make.
190
+
191
+ ---
192
+
193
+ ## The Fix
194
+
195
+ ### Rule: ALWAYS Run wu:done
196
+
197
+ After gates pass, you MUST run:
198
+
199
+ \`\`\`bash
200
+ cd /path/to/main
201
+ pnpm wu:done --id WU-XXX
202
+ \`\`\`
203
+
204
+ Do NOT:
205
+
206
+ - Ask "Should I run wu:done?"
207
+ - Write "To Complete: pnpm wu:done"
208
+ - Wait for permission
209
+
210
+ ---
211
+
212
+ ## What wu:done Does
213
+
214
+ 1. Validates the worktree exists and has commits
215
+ 2. Runs gates in the worktree (not main)
216
+ 3. Fast-forward merges to main
217
+ 4. Creates the done stamp
218
+ 5. Updates status and backlog docs
219
+ 6. Removes the worktree
220
+ 7. Pushes to origin
221
+ `;
222
+ const AGENT_SAFETY_CARD_TEMPLATE = `# Agent Safety Card
223
+
224
+ **Last updated:** {{DATE}}
225
+
226
+ Quick reference for AI agents working in LumenFlow projects.
227
+
228
+ ---
229
+
230
+ ## Stop and Ask When
231
+
232
+ - Same error repeats 3 times
233
+ - Auth or permissions changes needed
234
+ - PII/PHI/secrets involved
235
+ - Cloud spend decisions
236
+
237
+ ---
238
+
239
+ ## Never Do
240
+
241
+ | Action | Why |
242
+ | ------------------------ | ---------------- |
243
+ | \`git reset --hard\` | Data loss |
244
+ | \`git push --force\` | History rewrite |
245
+ | \`--no-verify\` | Bypasses safety |
246
+ | Work in main after claim | Breaks isolation |
247
+ | Skip wu:done | Incomplete WU |
248
+
249
+ ---
250
+
251
+ ## Always Do
252
+
253
+ | Action | Why |
254
+ | -------------------------- | ---------------- |
255
+ | Read WU spec first | Understand scope |
256
+ | cd to worktree after claim | Isolation |
257
+ | Write tests before code | TDD |
258
+ | Run gates before wu:done | Quality |
259
+ | Run wu:done | Complete WU |
260
+ `;
261
+ const WU_CREATE_CHECKLIST_TEMPLATE = `# WU Creation Checklist
262
+
263
+ **Last updated:** {{DATE}}
264
+
265
+ Before running \`pnpm wu:create\`, verify these items.
266
+
267
+ ---
268
+
269
+ ## Step 1: Check Valid Lanes
270
+
271
+ \`\`\`bash
272
+ grep -A 30 "lanes:" .lumenflow.config.yaml
273
+ \`\`\`
274
+
275
+ **Format:** \`"Parent: Sublane"\` (colon + single space)
276
+
277
+ ---
278
+
279
+ ## Step 2: Required Fields
280
+
281
+ | Field | Required For | Example |
282
+ |-------|--------------|---------|
283
+ | \`--id\` | All | \`WU-1234\` |
284
+ | \`--lane\` | All | \`"Experience: Chat"\` |
285
+ | \`--title\` | All | \`"Add feature"\` |
286
+ | \`--description\` | All | \`"Context: ... Problem: ... Solution: ..."\` |
287
+ | \`--acceptance\` | All | \`--acceptance "Works"\` (repeatable) |
288
+ | \`--exposure\` | All | \`ui\`, \`api\`, \`backend-only\`, \`documentation\` |
289
+ | \`--code-paths\` | Code WUs | \`"src/a.ts,src/b.ts"\` |
290
+ | \`--test-paths-unit\` | Code WUs | \`"src/__tests__/a.test.ts"\` |
291
+ | \`--spec-refs\` | Feature WUs | \`"~/.lumenflow/plans/WU-XXX.md"\` |
292
+
293
+ ---
294
+
295
+ ## Step 3: Plan Storage
296
+
297
+ Plans go in \`~/.lumenflow/plans/\` (NOT in project):
298
+
299
+ \`\`\`bash
300
+ mkdir -p ~/.lumenflow/plans
301
+ vim ~/.lumenflow/plans/WU-XXX-plan.md
302
+ \`\`\`
303
+
304
+ Reference in wu:create:
305
+ \`\`\`bash
306
+ --spec-refs "~/.lumenflow/plans/WU-XXX-plan.md"
307
+ \`\`\`
308
+
309
+ ---
310
+
311
+ ## Step 4: Validate First
312
+
313
+ \`\`\`bash
314
+ pnpm wu:create --id WU-XXX ... --validate
315
+ \`\`\`
316
+
317
+ Fix errors, then remove \`--validate\` to create.
318
+ `;
319
+ // Claude skills templates
320
+ const WU_LIFECYCLE_SKILL_TEMPLATE = `---
321
+ name: wu-lifecycle
322
+ description: Work Unit claim/block/done workflow automation.
323
+ version: 1.0.0
324
+ ---
325
+
326
+ # WU Lifecycle Skill
327
+
328
+ ## State Machine
329
+
330
+ \`\`\`
331
+ ready -> in_progress -> waiting/blocked -> done
332
+ \`\`\`
333
+
334
+ ## Core Commands
335
+
336
+ \`\`\`bash
337
+ # Claim WU
338
+ pnpm wu:claim --id WU-XXX --lane <lane>
339
+ cd worktrees/<lane>-wu-xxx # IMMEDIATELY
340
+
341
+ # Complete WU (from main)
342
+ cd ../..
343
+ pnpm wu:done --id WU-XXX
344
+ \`\`\`
345
+ `;
346
+ const WORKTREE_DISCIPLINE_SKILL_TEMPLATE = `---
347
+ name: worktree-discipline
348
+ description: Prevents the "absolute path trap" in Write/Edit/Read tools.
349
+ version: 1.0.0
350
+ ---
351
+
352
+ # Worktree Discipline: Absolute Path Trap Prevention
353
+
354
+ **Purpose**: Prevent AI agents from bypassing worktree isolation via absolute file paths.
355
+
356
+ ## The Absolute Path Trap
357
+
358
+ **Problem**: AI agents using Write/Edit/Read tools can bypass worktree isolation by passing absolute paths.
359
+
360
+ ## Golden Rules
361
+
362
+ 1. **Always verify pwd** before file operations
363
+ 2. **Never use absolute paths** in Write/Edit/Read tools
364
+ 3. **When in doubt, use relative paths**
365
+ `;
366
+ const LUMENFLOW_GATES_SKILL_TEMPLATE = `---
367
+ name: lumenflow-gates
368
+ description: Quality gates troubleshooting (format, lint, typecheck, tests).
369
+ version: 1.0.0
370
+ ---
371
+
372
+ # LumenFlow Gates Skill
373
+
374
+ ## Gate Sequence
375
+
376
+ \`\`\`
377
+ pnpm gates = format:check -> lint -> typecheck -> spec:linter -> tests
378
+ \`\`\`
379
+
380
+ ## Fix Patterns
381
+
382
+ | Gate | Auto-fix | Manual |
383
+ | --------- | --------------- | ----------------------------------- |
384
+ | Format | \`pnpm format\` | - |
385
+ | Lint | \`pnpm lint:fix\` | Fix reported issues |
386
+ | Typecheck | - | Fix type errors (first error first) |
387
+ | Tests | - | Debug, fix mocks, update snapshots |
388
+ `;
389
+ /**
390
+ * Sync agent onboarding docs to an existing project
391
+ */
392
+ export async function syncAgentDocs(targetDir, options) {
393
+ const result = {
394
+ created: [],
395
+ skipped: [],
396
+ };
397
+ const tokens = {
398
+ DATE: getCurrentDate(),
399
+ };
400
+ const onboardingDir = path.join(targetDir, 'docs', '04-operations', '_frameworks', 'lumenflow', 'agent', 'onboarding');
401
+ await createDirectory(onboardingDir, result, targetDir);
402
+ await createFile(path.join(onboardingDir, 'quick-ref-commands.md'), processTemplate(QUICK_REF_COMMANDS_TEMPLATE, tokens), options.force, result, targetDir);
403
+ await createFile(path.join(onboardingDir, 'first-wu-mistakes.md'), processTemplate(FIRST_WU_MISTAKES_TEMPLATE, tokens), options.force, result, targetDir);
404
+ await createFile(path.join(onboardingDir, 'troubleshooting-wu-done.md'), processTemplate(TROUBLESHOOTING_WU_DONE_TEMPLATE, tokens), options.force, result, targetDir);
405
+ await createFile(path.join(onboardingDir, 'agent-safety-card.md'), processTemplate(AGENT_SAFETY_CARD_TEMPLATE, tokens), options.force, result, targetDir);
406
+ await createFile(path.join(onboardingDir, 'wu-create-checklist.md'), processTemplate(WU_CREATE_CHECKLIST_TEMPLATE, tokens), options.force, result, targetDir);
407
+ return result;
408
+ }
409
+ /**
410
+ * Sync Claude skills to an existing project
411
+ */
412
+ export async function syncSkills(targetDir, options) {
413
+ const result = {
414
+ created: [],
415
+ skipped: [],
416
+ };
417
+ const vendor = options.vendor ?? 'none';
418
+ if (vendor !== 'claude' && vendor !== 'all') {
419
+ return result;
420
+ }
421
+ const tokens = {
422
+ DATE: getCurrentDate(),
423
+ };
424
+ const skillsDir = path.join(targetDir, '.claude', 'skills');
425
+ // wu-lifecycle skill
426
+ const wuLifecycleDir = path.join(skillsDir, 'wu-lifecycle');
427
+ await createDirectory(wuLifecycleDir, result, targetDir);
428
+ await createFile(path.join(wuLifecycleDir, 'SKILL.md'), processTemplate(WU_LIFECYCLE_SKILL_TEMPLATE, tokens), options.force, result, targetDir);
429
+ // worktree-discipline skill
430
+ const worktreeDir = path.join(skillsDir, 'worktree-discipline');
431
+ await createDirectory(worktreeDir, result, targetDir);
432
+ await createFile(path.join(worktreeDir, 'SKILL.md'), processTemplate(WORKTREE_DISCIPLINE_SKILL_TEMPLATE, tokens), options.force, result, targetDir);
433
+ // lumenflow-gates skill
434
+ const gatesDir = path.join(skillsDir, 'lumenflow-gates');
435
+ await createDirectory(gatesDir, result, targetDir);
436
+ await createFile(path.join(gatesDir, 'SKILL.md'), processTemplate(LUMENFLOW_GATES_SKILL_TEMPLATE, tokens), options.force, result, targetDir);
437
+ return result;
438
+ }
439
+ /**
440
+ * CLI entry point for docs:sync command
441
+ * WU-1085: Updated to use parseDocsSyncOptions for proper --help support
442
+ */
443
+ export async function main() {
444
+ const opts = parseDocsSyncOptions();
445
+ const targetDir = process.cwd();
446
+ console.log('[lumenflow docs:sync] Syncing agent documentation...');
447
+ console.log(` Vendor: ${opts.vendor}`);
448
+ console.log(` Force: ${opts.force}`);
449
+ const docsResult = await syncAgentDocs(targetDir, { force: opts.force });
450
+ const skillsResult = await syncSkills(targetDir, { force: opts.force, vendor: opts.vendor });
451
+ const created = [...docsResult.created, ...skillsResult.created];
452
+ const skipped = [...docsResult.skipped, ...skillsResult.skipped];
453
+ if (created.length > 0) {
454
+ console.log('\nCreated:');
455
+ created.forEach((f) => console.log(` + ${f}`));
456
+ }
457
+ if (skipped.length > 0) {
458
+ console.log('\nSkipped (already exists, use --force to overwrite):');
459
+ skipped.forEach((f) => console.log(` - ${f}`));
460
+ }
461
+ console.log('\n[lumenflow docs:sync] Done!');
462
+ }
463
+ // CLI entry point (WU-1071 pattern: import.meta.main)
464
+ import { runCLI } from './cli-entry-point.js';
465
+ if (import.meta.main) {
466
+ runCLI(main);
467
+ }
package/dist/gates.js CHANGED
@@ -54,35 +54,92 @@ import { buildGatesLogPath, shouldUseGatesAgentMode, updateGatesLatestSymlink, }
54
54
  import { detectRiskTier, RISK_TIERS, } from '@lumenflow/core/dist/risk-detector.js';
55
55
  // WU-2252: Import invariants runner for first-check validation
56
56
  import { runInvariants } from '@lumenflow/core/dist/invariants-runner.js';
57
- import { Command } from 'commander';
57
+ import { createWUParser } from '@lumenflow/core/dist/arg-parser.js';
58
58
  import { BRANCHES, PACKAGES, PKG_MANAGER, PKG_FLAGS, ESLINT_FLAGS, ESLINT_COMMANDS, ESLINT_DEFAULTS, SCRIPTS, CACHE_STRATEGIES, DIRECTORIES, GATE_NAMES, GATE_COMMANDS, TOOL_PATHS, CLI_MODES, EXIT_CODES, FILE_SYSTEM, PRETTIER_ARGS, PRETTIER_FLAGS, } from '@lumenflow/core/dist/wu-constants.js';
59
- // WU-2457: Add Commander.js for --help support
60
- function parseGatesArgs(argv = process.argv) {
59
+ /**
60
+ * WU-1087: Gates-specific option definitions for createWUParser.
61
+ * Exported for testing and consistency with other CLI commands.
62
+ */
63
+ export const GATES_OPTIONS = {
64
+ docsOnly: {
65
+ name: 'docsOnly',
66
+ flags: '--docs-only',
67
+ description: 'Run docs-only gates (format, spec-linter, prompts-lint, backlog-sync)',
68
+ },
69
+ fullLint: {
70
+ name: 'fullLint',
71
+ flags: '--full-lint',
72
+ description: 'Run full lint instead of incremental',
73
+ },
74
+ fullTests: {
75
+ name: 'fullTests',
76
+ flags: '--full-tests',
77
+ description: 'Run full test suite instead of incremental',
78
+ },
79
+ fullCoverage: {
80
+ name: 'fullCoverage',
81
+ flags: '--full-coverage',
82
+ description: 'Force full test suite and coverage gate (implies --full-tests)',
83
+ },
84
+ coverageMode: {
85
+ name: 'coverageMode',
86
+ flags: '--coverage-mode <mode>',
87
+ description: 'Coverage gate mode: "warn" logs warnings, "block" fails gate',
88
+ default: 'block',
89
+ },
90
+ verbose: {
91
+ name: 'verbose',
92
+ flags: '--verbose',
93
+ description: 'Stream output in agent mode instead of logging to file',
94
+ },
95
+ };
96
+ /**
97
+ * WU-1087: Parse gates options using createWUParser for consistency.
98
+ * Handles pnpm's `--` separator and provides automatic --help support.
99
+ *
100
+ * @returns Parsed options object
101
+ */
102
+ export function parseGatesOptions() {
61
103
  // WU-2465: Pre-filter argv to handle pnpm's `--` separator
62
104
  // When invoked via `pnpm gates -- --docs-only`, pnpm passes ["--", "--docs-only"]
63
- // Commander treats `--` as "everything after is positional", causing errors.
64
- // Solution: Remove standalone `--` from argv before parsing.
65
- const filteredArgv = argv.filter((arg, index, arr) => {
66
- // Keep `--` only if it's followed by a non-option (actual positional arg)
67
- // Remove it if it's followed by an option (starts with -)
105
+ // createWUParser's default filtering removes all `--`, but we need smarter handling:
106
+ // Remove `--` only if it's followed by an option (starts with -)
107
+ const originalArgv = process.argv;
108
+ const filteredArgv = originalArgv.filter((arg, index, arr) => {
68
109
  if (arg === '--') {
69
110
  const nextArg = arr[index + 1];
70
111
  return nextArg && !nextArg.startsWith('-');
71
112
  }
72
113
  return true;
73
114
  });
74
- const program = new Command()
75
- .name('gates')
76
- .description('Run quality gates with support for docs-only mode, incremental linting, and tiered testing')
77
- .option('--docs-only', 'Run docs-only gates (format, spec-linter, prompts-lint, backlog-sync)')
78
- .option('--full-lint', 'Run full lint instead of incremental')
79
- .option('--full-tests', 'Run full test suite instead of incremental')
80
- .option('--full-coverage', 'Force full test suite and coverage gate (implies --full-tests)')
81
- .option('--coverage-mode <mode>', 'Coverage gate mode: "warn" logs warnings, "block" fails gate (default)', 'block')
82
- .option('--verbose', 'Stream output in agent mode instead of logging to file')
83
- .helpOption('-h, --help', 'Display help for command');
84
- program.parse(filteredArgv);
85
- return program.opts();
115
+ // Temporarily replace process.argv for createWUParser
116
+ process.argv = filteredArgv;
117
+ try {
118
+ const opts = createWUParser({
119
+ name: 'gates',
120
+ description: 'Run quality gates with support for docs-only mode, incremental linting, and tiered testing',
121
+ options: Object.values(GATES_OPTIONS),
122
+ });
123
+ return {
124
+ docsOnly: opts.docsOnly,
125
+ fullLint: opts.fullLint,
126
+ fullTests: opts.fullTests,
127
+ fullCoverage: opts.fullCoverage,
128
+ coverageMode: opts.coverageMode ?? 'block',
129
+ verbose: opts.verbose,
130
+ };
131
+ }
132
+ finally {
133
+ // Restore original process.argv
134
+ process.argv = originalArgv;
135
+ }
136
+ }
137
+ /**
138
+ * @deprecated Use parseGatesOptions() instead (WU-1087)
139
+ * Kept for backward compatibility during migration.
140
+ */
141
+ function parseGatesArgs(argv = process.argv) {
142
+ return parseGatesOptions();
86
143
  }
87
144
  /**
88
145
  * Build a pnpm command string
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @lumenflow/cli - Command-line interface for LumenFlow workflow framework
3
+ *
4
+ * This package provides CLI commands for the LumenFlow workflow framework.
5
+ * Most functionality is exposed via bin commands, but the cli-entry-point
6
+ * helper is exported for use in custom CLI wrappers.
7
+ *
8
+ * @see https://lumenflow.dev/reference/cli
9
+ */
10
+ export { runCLI } from './cli-entry-point.js';