@lumenflow/cli 1.4.0 → 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
 
@@ -105,6 +110,23 @@ npx wu-claim --id WU-123 --lane operations
105
110
  npx gates
106
111
  ```
107
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
+
108
130
  ## Integration
109
131
 
110
132
  The CLI integrates with other LumenFlow packages:
@@ -116,7 +138,7 @@ The CLI integrates with other LumenFlow packages:
116
138
 
117
139
  ## Documentation
118
140
 
119
- For complete documentation, see the [LumenFlow documentation](https://github.com/hellmai/os).
141
+ For complete documentation, see [lumenflow.dev](https://lumenflow.dev/reference/cli).
120
142
 
121
143
  ## License
122
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
  }
package/dist/docs-sync.js CHANGED
@@ -1,9 +1,38 @@
1
1
  /**
2
2
  * @file docs-sync.ts
3
3
  * LumenFlow docs:sync command for syncing agent docs to existing projects (WU-1083)
4
+ * WU-1085: Added createWUParser for proper --help support
4
5
  */
5
6
  import * as fs from 'node:fs';
6
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
+ }
7
36
  /**
8
37
  * Get current date in YYYY-MM-DD format
9
38
  */
@@ -407,32 +436,18 @@ export async function syncSkills(targetDir, options) {
407
436
  await createFile(path.join(gatesDir, 'SKILL.md'), processTemplate(LUMENFLOW_GATES_SKILL_TEMPLATE, tokens), options.force, result, targetDir);
408
437
  return result;
409
438
  }
410
- /**
411
- * Parse vendor flag from arguments
412
- */
413
- function parseVendorArg(args) {
414
- const vendorIndex = args.findIndex((arg) => arg === '--vendor');
415
- if (vendorIndex !== -1 && args[vendorIndex + 1]) {
416
- const vendor = args[vendorIndex + 1].toLowerCase();
417
- if (['claude', 'cursor', 'aider', 'all', 'none'].includes(vendor)) {
418
- return vendor;
419
- }
420
- }
421
- return undefined;
422
- }
423
439
  /**
424
440
  * CLI entry point for docs:sync command
441
+ * WU-1085: Updated to use parseDocsSyncOptions for proper --help support
425
442
  */
426
443
  export async function main() {
427
- const args = process.argv.slice(2);
428
- const force = args.includes('--force') || args.includes('-f');
429
- const vendor = parseVendorArg(args) ?? 'claude'; // Default to claude
444
+ const opts = parseDocsSyncOptions();
430
445
  const targetDir = process.cwd();
431
446
  console.log('[lumenflow docs:sync] Syncing agent documentation...');
432
- console.log(` Vendor: ${vendor}`);
433
- console.log(` Force: ${force}`);
434
- const docsResult = await syncAgentDocs(targetDir, { force });
435
- const skillsResult = await syncSkills(targetDir, { force, vendor });
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 });
436
451
  const created = [...docsResult.created, ...skillsResult.created];
437
452
  const skipped = [...docsResult.skipped, ...skillsResult.skipped];
438
453
  if (created.length > 0) {
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';
package/dist/init.js CHANGED
@@ -3,13 +3,58 @@
3
3
  * LumenFlow project scaffolding command (WU-1045)
4
4
  * WU-1006: Library-First - use core defaults for config generation
5
5
  * WU-1028: Vendor-agnostic core + vendor overlays
6
+ * WU-1085: Added createWUParser for proper --help support
6
7
  */
7
8
  import * as fs from 'node:fs';
8
9
  import * as path from 'node:path';
9
10
  import * as yaml from 'yaml';
10
- import { getDefaultConfig } from '@lumenflow/core';
11
+ import { getDefaultConfig, createWUParser, WU_OPTIONS } from '@lumenflow/core';
11
12
  // WU-1067: Import GATE_PRESETS for --preset support
12
13
  import { GATE_PRESETS } from '@lumenflow/core/dist/gates-config.js';
14
+ /**
15
+ * WU-1085: CLI option definitions for init command
16
+ */
17
+ const INIT_OPTIONS = {
18
+ full: {
19
+ name: 'full',
20
+ flags: '--full',
21
+ description: 'Add docs + agent onboarding + task scaffolding',
22
+ },
23
+ framework: {
24
+ name: 'framework',
25
+ flags: '--framework <name>',
26
+ description: 'Add framework hint + overlay docs',
27
+ },
28
+ vendor: {
29
+ name: 'vendor',
30
+ flags: '--vendor <type>',
31
+ description: 'Vendor type (claude, cursor, aider, all, none)',
32
+ },
33
+ preset: {
34
+ name: 'preset',
35
+ flags: '--preset <preset>',
36
+ description: 'Gate preset for config (node, python, go, rust, dotnet)',
37
+ },
38
+ force: WU_OPTIONS.force,
39
+ };
40
+ /**
41
+ * WU-1085: Parse init command options using createWUParser
42
+ * Provides proper --help, --version, and option parsing
43
+ */
44
+ export function parseInitOptions() {
45
+ const opts = createWUParser({
46
+ name: 'lumenflow-init',
47
+ description: 'Initialize LumenFlow in a project',
48
+ options: Object.values(INIT_OPTIONS),
49
+ });
50
+ return {
51
+ force: opts.force ?? false,
52
+ full: opts.full ?? false,
53
+ framework: opts.framework,
54
+ vendor: opts.vendor,
55
+ preset: opts.preset,
56
+ };
57
+ }
13
58
  const CONFIG_FILE_NAME = '.lumenflow.config.yaml';
14
59
  const FRAMEWORK_HINT_FILE = '.lumenflow.framework.yaml';
15
60
  const LUMENFLOW_DIR = '.lumenflow';
@@ -1100,26 +1145,22 @@ async function createFile(filePath, content, force, result, targetDir) {
1100
1145
  }
1101
1146
  /**
1102
1147
  * CLI entry point
1148
+ * WU-1085: Updated to use parseInitOptions for proper --help support
1103
1149
  */
1104
1150
  export async function main() {
1105
- const args = process.argv.slice(2);
1106
- const force = args.includes('--force') || args.includes('-f');
1107
- const full = args.includes('--full');
1108
- const vendor = parseVendorArg(args);
1109
- const framework = parseFrameworkArg(args);
1110
- const gatePreset = parsePresetArg(args); // WU-1067
1151
+ const opts = parseInitOptions();
1111
1152
  const targetDir = process.cwd();
1112
1153
  console.log('[lumenflow init] Scaffolding LumenFlow project...');
1113
- console.log(` Mode: ${full ? 'full' : 'minimal'}`);
1114
- console.log(` Framework: ${framework ?? 'none'}`);
1115
- console.log(` Vendor overlays: ${vendor ?? 'auto'}`);
1116
- console.log(` Gate preset: ${gatePreset ?? 'none (manual config)'}`);
1154
+ console.log(` Mode: ${opts.full ? 'full' : 'minimal'}`);
1155
+ console.log(` Framework: ${opts.framework ?? 'none'}`);
1156
+ console.log(` Vendor overlays: ${opts.vendor ?? 'auto'}`);
1157
+ console.log(` Gate preset: ${opts.preset ?? 'none (manual config)'}`);
1117
1158
  const result = await scaffoldProject(targetDir, {
1118
- force,
1119
- full,
1120
- vendor,
1121
- framework,
1122
- gatePreset,
1159
+ force: opts.force,
1160
+ full: opts.full,
1161
+ vendor: opts.vendor,
1162
+ framework: opts.framework,
1163
+ gatePreset: opts.preset,
1123
1164
  });
1124
1165
  if (result.created.length > 0) {
1125
1166
  console.log('\nCreated:');
package/dist/release.js CHANGED
@@ -13,9 +13,12 @@
13
13
  * - Creates git tag vX.Y.Z
14
14
  *
15
15
  * Usage:
16
- * pnpm release --version 1.3.0
17
- * pnpm release --version 1.3.0 --dry-run # Preview without making changes
18
- * pnpm release --version 1.3.0 --skip-publish # Bump and tag only (no npm publish)
16
+ * pnpm release --release-version 1.3.0
17
+ * pnpm release --release-version 1.3.0 --dry-run # Preview without making changes
18
+ * pnpm release --release-version 1.3.0 --skip-publish # Bump and tag only (no npm publish)
19
+ *
20
+ * WU-1085: The --release-version flag was renamed from --version to avoid conflict
21
+ * with the standard CLI --version flag that shows the CLI version.
19
22
  *
20
23
  * WU-1074: Add release command for npm publishing
21
24
  */
@@ -262,19 +265,22 @@ export async function pushTagWithForce(git, tagName, reason = 'release: tag push
262
265
  }
263
266
  /**
264
267
  * Main release function
268
+ * WU-1085: Renamed --version to --release-version to avoid conflict with CLI --version flag
265
269
  */
266
270
  async function main() {
267
271
  const program = new Command()
268
- .name('release')
272
+ .name('lumenflow-release')
269
273
  .description('Release @lumenflow/* packages to npm with version bump, tag, and publish')
270
- .requiredOption('-v, --version <version>', 'Semver version to release (e.g., 1.3.0)')
274
+ .version('1.0.0', '-V, --version', 'Output the CLI version')
275
+ .requiredOption('-v, --release-version <version>', 'Semver version to release (e.g., 1.3.0)')
271
276
  .option('--dry-run', 'Preview changes without making them', false)
272
277
  .option('--skip-publish', 'Skip npm publish (only bump and tag)', false)
273
278
  .option('--skip-build', 'Skip build step (use existing dist)', false)
274
279
  .helpOption('-h, --help', 'Display help for command');
275
280
  program.parse();
276
281
  const opts = program.opts();
277
- const { version, dryRun, skipPublish, skipBuild } = opts;
282
+ // WU-1085: Use releaseVersion instead of version (renamed to avoid CLI --version conflict)
283
+ const { releaseVersion: version, dryRun, skipPublish, skipBuild } = opts;
278
284
  console.log(`${LOG_PREFIX} Starting release process for v${version}`);
279
285
  if (dryRun) {
280
286
  console.log(`${LOG_PREFIX} DRY RUN MODE - no changes will be made`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/cli",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Command-line interface for LumenFlow workflow framework",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -21,6 +21,18 @@
21
21
  "url": "https://hellm.ai"
22
22
  },
23
23
  "type": "module",
24
+ "main": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ },
31
+ "./cli-entry-point": {
32
+ "types": "./dist/cli-entry-point.d.ts",
33
+ "import": "./dist/cli-entry-point.js"
34
+ }
35
+ },
24
36
  "bin": {
25
37
  "wu-claim": "./dist/wu-claim.js",
26
38
  "wu-done": "./dist/wu-done.js",
@@ -88,11 +100,11 @@
88
100
  "pretty-ms": "^9.2.0",
89
101
  "simple-git": "^3.30.0",
90
102
  "yaml": "^2.8.2",
91
- "@lumenflow/core": "1.4.0",
92
- "@lumenflow/metrics": "1.4.0",
93
- "@lumenflow/memory": "1.4.0",
94
- "@lumenflow/initiatives": "1.4.0",
95
- "@lumenflow/agent": "1.4.0"
103
+ "@lumenflow/core": "1.5.0",
104
+ "@lumenflow/initiatives": "1.5.0",
105
+ "@lumenflow/memory": "1.5.0",
106
+ "@lumenflow/agent": "1.5.0",
107
+ "@lumenflow/metrics": "1.5.0"
96
108
  },
97
109
  "devDependencies": {
98
110
  "@vitest/coverage-v8": "^4.0.17",