@lumenflow/cli 1.1.0 โ 1.3.2
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/dist/__tests__/cli-entry-point.test.js +50 -0
- package/dist/__tests__/cli-subprocess.test.js +64 -0
- package/dist/cli-entry-point.js +46 -0
- package/dist/gates.js +102 -39
- package/dist/init.js +241 -195
- package/dist/initiative-add-wu.js +2 -1
- package/dist/initiative-create.js +5 -8
- package/dist/initiative-edit.js +3 -3
- package/dist/initiative-list.js +2 -1
- package/dist/initiative-status.js +2 -1
- package/dist/wu-claim.js +297 -110
- package/dist/wu-cleanup.js +129 -57
- package/dist/wu-create.js +197 -122
- package/dist/wu-deps.js +2 -1
- package/dist/wu-done.js +46 -14
- package/dist/wu-edit.js +152 -61
- package/dist/wu-infer-lane.js +5 -4
- package/dist/wu-preflight.js +2 -1
- package/dist/wu-prune.js +12 -3
- package/dist/wu-repair.js +2 -1
- package/dist/wu-spawn.js +79 -159
- package/dist/wu-unlock-lane.js +6 -1
- package/dist/wu-validate.js +2 -1
- package/package.json +14 -14
- package/dist/gates.d.ts +0 -41
- package/dist/gates.d.ts.map +0 -1
- package/dist/gates.js.map +0 -1
- package/dist/initiative-add-wu.d.ts +0 -22
- package/dist/initiative-add-wu.d.ts.map +0 -1
- package/dist/initiative-add-wu.js.map +0 -1
- package/dist/initiative-create.d.ts +0 -28
- package/dist/initiative-create.d.ts.map +0 -1
- package/dist/initiative-create.js.map +0 -1
- package/dist/initiative-edit.d.ts +0 -34
- package/dist/initiative-edit.d.ts.map +0 -1
- package/dist/initiative-edit.js.map +0 -1
- package/dist/initiative-list.d.ts +0 -12
- package/dist/initiative-list.d.ts.map +0 -1
- package/dist/initiative-list.js.map +0 -1
- package/dist/initiative-status.d.ts +0 -11
- package/dist/initiative-status.d.ts.map +0 -1
- package/dist/initiative-status.js.map +0 -1
- package/dist/mem-checkpoint.d.ts +0 -16
- package/dist/mem-checkpoint.d.ts.map +0 -1
- package/dist/mem-checkpoint.js.map +0 -1
- package/dist/mem-cleanup.d.ts +0 -29
- package/dist/mem-cleanup.d.ts.map +0 -1
- package/dist/mem-cleanup.js.map +0 -1
- package/dist/mem-create.d.ts +0 -17
- package/dist/mem-create.d.ts.map +0 -1
- package/dist/mem-create.js.map +0 -1
- package/dist/mem-inbox.d.ts +0 -35
- package/dist/mem-inbox.d.ts.map +0 -1
- package/dist/mem-inbox.js.map +0 -1
- package/dist/mem-init.d.ts +0 -15
- package/dist/mem-init.d.ts.map +0 -1
- package/dist/mem-init.js.map +0 -1
- package/dist/mem-ready.d.ts +0 -16
- package/dist/mem-ready.d.ts.map +0 -1
- package/dist/mem-ready.js.map +0 -1
- package/dist/mem-signal.d.ts +0 -16
- package/dist/mem-signal.d.ts.map +0 -1
- package/dist/mem-signal.js.map +0 -1
- package/dist/mem-start.d.ts +0 -16
- package/dist/mem-start.d.ts.map +0 -1
- package/dist/mem-start.js.map +0 -1
- package/dist/mem-summarize.d.ts +0 -22
- package/dist/mem-summarize.d.ts.map +0 -1
- package/dist/mem-summarize.js.map +0 -1
- package/dist/mem-triage.d.ts +0 -22
- package/dist/mem-triage.d.ts.map +0 -1
- package/dist/mem-triage.js.map +0 -1
- package/dist/spawn-list.d.ts +0 -16
- package/dist/spawn-list.d.ts.map +0 -1
- package/dist/spawn-list.js.map +0 -1
- package/dist/wu-block.d.ts +0 -16
- package/dist/wu-block.d.ts.map +0 -1
- package/dist/wu-block.js.map +0 -1
- package/dist/wu-claim.d.ts +0 -32
- package/dist/wu-claim.d.ts.map +0 -1
- package/dist/wu-claim.js.map +0 -1
- package/dist/wu-cleanup.d.ts +0 -17
- package/dist/wu-cleanup.d.ts.map +0 -1
- package/dist/wu-cleanup.js.map +0 -1
- package/dist/wu-create.d.ts +0 -38
- package/dist/wu-create.d.ts.map +0 -1
- package/dist/wu-create.js.map +0 -1
- package/dist/wu-deps.d.ts +0 -13
- package/dist/wu-deps.d.ts.map +0 -1
- package/dist/wu-deps.js.map +0 -1
- package/dist/wu-done.d.ts +0 -153
- package/dist/wu-done.d.ts.map +0 -1
- package/dist/wu-done.js.map +0 -1
- package/dist/wu-edit.d.ts +0 -29
- package/dist/wu-edit.d.ts.map +0 -1
- package/dist/wu-edit.js.map +0 -1
- package/dist/wu-infer-lane.d.ts +0 -17
- package/dist/wu-infer-lane.d.ts.map +0 -1
- package/dist/wu-infer-lane.js.map +0 -1
- package/dist/wu-preflight.d.ts +0 -47
- package/dist/wu-preflight.d.ts.map +0 -1
- package/dist/wu-preflight.js.map +0 -1
- package/dist/wu-prune.d.ts +0 -16
- package/dist/wu-prune.d.ts.map +0 -1
- package/dist/wu-prune.js.map +0 -1
- package/dist/wu-repair.d.ts +0 -60
- package/dist/wu-repair.d.ts.map +0 -1
- package/dist/wu-repair.js.map +0 -1
- package/dist/wu-spawn-completion.d.ts +0 -10
- package/dist/wu-spawn.d.ts +0 -168
- package/dist/wu-spawn.d.ts.map +0 -1
- package/dist/wu-spawn.js.map +0 -1
- package/dist/wu-unblock.d.ts +0 -16
- package/dist/wu-unblock.d.ts.map +0 -1
- package/dist/wu-unblock.js.map +0 -1
- package/dist/wu-validate.d.ts +0 -16
- package/dist/wu-validate.d.ts.map +0 -1
- package/dist/wu-validate.js.map +0 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for CLI entry point error handling
|
|
3
|
+
*
|
|
4
|
+
* Verifies that runCLI wrapper properly:
|
|
5
|
+
* - Catches async errors from main()
|
|
6
|
+
* - Logs error messages to stderr
|
|
7
|
+
* - Exits with EXIT_CODES.ERROR on failure
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
10
|
+
import { runCLI } from '../cli-entry-point.js';
|
|
11
|
+
import { EXIT_CODES } from '@lumenflow/core/dist/wu-constants.js';
|
|
12
|
+
describe('runCLI', () => {
|
|
13
|
+
let mockExit;
|
|
14
|
+
let mockConsoleError;
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined);
|
|
17
|
+
mockConsoleError = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
18
|
+
});
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
mockExit.mockRestore();
|
|
21
|
+
mockConsoleError.mockRestore();
|
|
22
|
+
});
|
|
23
|
+
it('should call main() and do nothing on success', async () => {
|
|
24
|
+
const main = vi.fn().mockResolvedValue(undefined);
|
|
25
|
+
await runCLI(main);
|
|
26
|
+
expect(main).toHaveBeenCalledOnce();
|
|
27
|
+
expect(mockExit).not.toHaveBeenCalled();
|
|
28
|
+
expect(mockConsoleError).not.toHaveBeenCalled();
|
|
29
|
+
});
|
|
30
|
+
it('should catch errors and exit with ERROR code', async () => {
|
|
31
|
+
const error = new Error('Test error message');
|
|
32
|
+
const main = vi.fn().mockRejectedValue(error);
|
|
33
|
+
await runCLI(main);
|
|
34
|
+
expect(main).toHaveBeenCalledOnce();
|
|
35
|
+
expect(mockConsoleError).toHaveBeenCalledWith('Test error message');
|
|
36
|
+
expect(mockExit).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
37
|
+
});
|
|
38
|
+
it('should handle errors without message property', async () => {
|
|
39
|
+
const main = vi.fn().mockRejectedValue('string error');
|
|
40
|
+
await runCLI(main);
|
|
41
|
+
expect(mockConsoleError).toHaveBeenCalledWith('string error');
|
|
42
|
+
expect(mockExit).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
43
|
+
});
|
|
44
|
+
it('should handle null/undefined errors', async () => {
|
|
45
|
+
const main = vi.fn().mockRejectedValue(null);
|
|
46
|
+
await runCLI(main);
|
|
47
|
+
expect(mockConsoleError).toHaveBeenCalledWith('Unknown error');
|
|
48
|
+
expect(mockExit).toHaveBeenCalledWith(EXIT_CODES.ERROR);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for CLI subprocess execution
|
|
3
|
+
*
|
|
4
|
+
* Tests that CLI commands properly:
|
|
5
|
+
* - Exit with non-zero code on errors
|
|
6
|
+
* - Output error messages to stderr
|
|
7
|
+
* - Don't silently fail
|
|
8
|
+
*
|
|
9
|
+
* These tests run CLI commands as subprocesses to verify
|
|
10
|
+
* the entry point error handling works end-to-end.
|
|
11
|
+
*/
|
|
12
|
+
import { describe, it, expect } from 'vitest';
|
|
13
|
+
import { spawnSync } from 'node:child_process';
|
|
14
|
+
import { resolve } from 'node:path';
|
|
15
|
+
const CLI_DIR = resolve(__dirname, '../../dist');
|
|
16
|
+
/**
|
|
17
|
+
* Helper to run a CLI command as subprocess
|
|
18
|
+
*/
|
|
19
|
+
function runCLI(command, args = []) {
|
|
20
|
+
const result = spawnSync('node', [resolve(CLI_DIR, `${command}.js`), ...args], {
|
|
21
|
+
encoding: 'utf-8',
|
|
22
|
+
timeout: 10000,
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
code: result.status ?? -1,
|
|
26
|
+
stdout: result.stdout ?? '',
|
|
27
|
+
stderr: result.stderr ?? '',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
describe('CLI subprocess error handling', () => {
|
|
31
|
+
describe('wu-claim', () => {
|
|
32
|
+
it('should exit with non-zero code when required options are missing', () => {
|
|
33
|
+
const result = runCLI('wu-claim', ['--id', 'WU-TEST']);
|
|
34
|
+
// Should NOT exit 0 (silent failure)
|
|
35
|
+
expect(result.code).not.toBe(0);
|
|
36
|
+
// Should have some error output
|
|
37
|
+
expect(result.stderr.length + result.stdout.length).toBeGreaterThan(0);
|
|
38
|
+
});
|
|
39
|
+
it('should output help when --help is passed', () => {
|
|
40
|
+
const result = runCLI('wu-claim', ['--help']);
|
|
41
|
+
// Help should work
|
|
42
|
+
expect(result.code).toBe(0);
|
|
43
|
+
expect(result.stdout).toContain('Usage');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe('wu-done', () => {
|
|
47
|
+
it('should exit with non-zero code for non-existent WU', () => {
|
|
48
|
+
const result = runCLI('wu-done', ['--id', 'WU-NONEXISTENT-99999']);
|
|
49
|
+
// Should NOT exit 0 (silent failure)
|
|
50
|
+
expect(result.code).not.toBe(0);
|
|
51
|
+
// Should have some error output
|
|
52
|
+
expect(result.stderr.length + result.stdout.length).toBeGreaterThan(0);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('wu-create', () => {
|
|
56
|
+
it('should exit with non-zero code when validation fails', () => {
|
|
57
|
+
const result = runCLI('wu-create', ['--id', 'WU-TEST', '--lane', 'Invalid Lane']);
|
|
58
|
+
// Should NOT exit 0 (silent failure)
|
|
59
|
+
expect(result.code).not.toBe(0);
|
|
60
|
+
// Should have some error output
|
|
61
|
+
expect(result.stderr.length + result.stdout.length).toBeGreaterThan(0);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared CLI entry point wrapper
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent error handling for all CLI commands.
|
|
5
|
+
* Catches async errors, logs them, and exits with proper code.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // At the bottom of each CLI file:
|
|
10
|
+
* import { runCLI } from './cli-entry-point.js';
|
|
11
|
+
* import { fileURLToPath } from 'node:url';
|
|
12
|
+
*
|
|
13
|
+
* if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
14
|
+
* runCLI(main);
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import { EXIT_CODES } from '@lumenflow/core/dist/wu-constants.js';
|
|
19
|
+
/**
|
|
20
|
+
* Wraps an async main function with proper error handling.
|
|
21
|
+
*
|
|
22
|
+
* @param main - The async main function to execute
|
|
23
|
+
* @returns Promise that resolves when main completes (or after error handling)
|
|
24
|
+
*/
|
|
25
|
+
export async function runCLI(main) {
|
|
26
|
+
try {
|
|
27
|
+
await main();
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
const message = getErrorMessage(err);
|
|
31
|
+
console.error(message);
|
|
32
|
+
process.exit(EXIT_CODES.ERROR);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Extracts error message from unknown error type.
|
|
37
|
+
*/
|
|
38
|
+
function getErrorMessage(err) {
|
|
39
|
+
if (err === null || err === undefined) {
|
|
40
|
+
return 'Unknown error';
|
|
41
|
+
}
|
|
42
|
+
if (err instanceof Error) {
|
|
43
|
+
return err.message;
|
|
44
|
+
}
|
|
45
|
+
return String(err);
|
|
46
|
+
}
|
package/dist/gates.js
CHANGED
|
@@ -42,6 +42,7 @@ import { execSync, spawnSync } from 'node:child_process';
|
|
|
42
42
|
import { closeSync, mkdirSync, openSync, readSync, statSync, writeSync } from 'node:fs';
|
|
43
43
|
import { access } from 'node:fs/promises';
|
|
44
44
|
import path from 'node:path';
|
|
45
|
+
import { fileURLToPath } from 'node:url';
|
|
45
46
|
import { emitGateEvent, getCurrentWU, getCurrentLane } from '@lumenflow/core/dist/telemetry.js';
|
|
46
47
|
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
47
48
|
import { getChangedLintableFiles, convertToPackageRelativePaths, } from '@lumenflow/core/dist/incremental-lint.js';
|
|
@@ -55,42 +56,35 @@ import { detectRiskTier, RISK_TIERS, } from '@lumenflow/core/dist/risk-detector.
|
|
|
55
56
|
// WU-2252: Import invariants runner for first-check validation
|
|
56
57
|
import { runInvariants } from '@lumenflow/core/dist/invariants-runner.js';
|
|
57
58
|
import { Command } from 'commander';
|
|
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, } from '@lumenflow/core/dist/wu-constants.js';
|
|
59
|
+
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
60
|
// WU-2457: Add Commander.js for --help support
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const isFullLint = opts.fullLint || false;
|
|
88
|
-
const isFullTests = opts.fullTests || false;
|
|
89
|
-
// WU-2244: Full coverage flag forces full test suite and coverage gate (deterministic)
|
|
90
|
-
const isFullCoverage = opts.fullCoverage || false;
|
|
91
|
-
// WU-1433: Coverage gate mode (warn or block)
|
|
92
|
-
// WU-2334: Default changed from WARN to BLOCK for TDD enforcement
|
|
93
|
-
const coverageMode = opts.coverageMode || COVERAGE_GATE_MODES.BLOCK;
|
|
61
|
+
function parseGatesArgs(argv = process.argv) {
|
|
62
|
+
// WU-2465: Pre-filter argv to handle pnpm's `--` separator
|
|
63
|
+
// When invoked via `pnpm gates -- --docs-only`, pnpm passes ["--", "--docs-only"]
|
|
64
|
+
// Commander treats `--` as "everything after is positional", causing errors.
|
|
65
|
+
// Solution: Remove standalone `--` from argv before parsing.
|
|
66
|
+
const filteredArgv = argv.filter((arg, index, arr) => {
|
|
67
|
+
// Keep `--` only if it's followed by a non-option (actual positional arg)
|
|
68
|
+
// Remove it if it's followed by an option (starts with -)
|
|
69
|
+
if (arg === '--') {
|
|
70
|
+
const nextArg = arr[index + 1];
|
|
71
|
+
return nextArg && !nextArg.startsWith('-');
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
});
|
|
75
|
+
const program = new Command()
|
|
76
|
+
.name('gates')
|
|
77
|
+
.description('Run quality gates with support for docs-only mode, incremental linting, and tiered testing')
|
|
78
|
+
.option('--docs-only', 'Run docs-only gates (format, spec-linter, prompts-lint, backlog-sync)')
|
|
79
|
+
.option('--full-lint', 'Run full lint instead of incremental')
|
|
80
|
+
.option('--full-tests', 'Run full test suite instead of incremental')
|
|
81
|
+
.option('--full-coverage', 'Force full test suite and coverage gate (implies --full-tests)')
|
|
82
|
+
.option('--coverage-mode <mode>', 'Coverage gate mode: "warn" logs warnings, "block" fails gate (default)', 'block')
|
|
83
|
+
.option('--verbose', 'Stream output in agent mode instead of logging to file')
|
|
84
|
+
.helpOption('-h, --help', 'Display help for command');
|
|
85
|
+
program.parse(filteredArgv);
|
|
86
|
+
return program.opts();
|
|
87
|
+
}
|
|
94
88
|
/**
|
|
95
89
|
* Build a pnpm command string
|
|
96
90
|
*/
|
|
@@ -104,6 +98,60 @@ function pnpmRun(script, ...args) {
|
|
|
104
98
|
const argsStr = args.length > 0 ? ` ${args.join(' ')}` : '';
|
|
105
99
|
return `${PKG_MANAGER} ${SCRIPTS.RUN} ${script}${argsStr}`;
|
|
106
100
|
}
|
|
101
|
+
export function parsePrettierListOutput(output) {
|
|
102
|
+
if (!output)
|
|
103
|
+
return [];
|
|
104
|
+
return output
|
|
105
|
+
.split(/\r?\n/)
|
|
106
|
+
.map((line) => line.trim())
|
|
107
|
+
.filter(Boolean)
|
|
108
|
+
.map((line) => line.replace(/^\[error\]\s*/i, '').trim())
|
|
109
|
+
.filter((line) => !line.toLowerCase().includes('code style issues found') &&
|
|
110
|
+
!line.toLowerCase().includes('all matched files use prettier') &&
|
|
111
|
+
!line.toLowerCase().includes('checking formatting'));
|
|
112
|
+
}
|
|
113
|
+
export function buildPrettierWriteCommand(files) {
|
|
114
|
+
const quotedFiles = files.map((file) => `"${file}"`).join(' ');
|
|
115
|
+
const base = pnpmCmd(SCRIPTS.PRETTIER, PRETTIER_FLAGS.WRITE);
|
|
116
|
+
return quotedFiles ? `${base} ${quotedFiles}` : base;
|
|
117
|
+
}
|
|
118
|
+
export function formatFormatCheckGuidance(files) {
|
|
119
|
+
if (!files.length)
|
|
120
|
+
return [];
|
|
121
|
+
const command = buildPrettierWriteCommand(files);
|
|
122
|
+
return [
|
|
123
|
+
'',
|
|
124
|
+
'โ format:check failed',
|
|
125
|
+
'Fix with:',
|
|
126
|
+
` ${command}`,
|
|
127
|
+
'',
|
|
128
|
+
'Affected files:',
|
|
129
|
+
...files.map((file) => ` - ${file}`),
|
|
130
|
+
'',
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
function collectPrettierListDifferent(cwd) {
|
|
134
|
+
const cmd = pnpmCmd(SCRIPTS.PRETTIER, PRETTIER_ARGS.LIST_DIFFERENT, '.');
|
|
135
|
+
const result = spawnSync(cmd, [], {
|
|
136
|
+
shell: true,
|
|
137
|
+
cwd,
|
|
138
|
+
encoding: FILE_SYSTEM.ENCODING,
|
|
139
|
+
});
|
|
140
|
+
const output = `${result.stdout || ''}\n${result.stderr || ''}`;
|
|
141
|
+
return parsePrettierListOutput(output);
|
|
142
|
+
}
|
|
143
|
+
function emitFormatCheckGuidance({ agentLog, useAgentMode, }) {
|
|
144
|
+
const files = collectPrettierListDifferent(process.cwd());
|
|
145
|
+
if (!files.length)
|
|
146
|
+
return;
|
|
147
|
+
const lines = formatFormatCheckGuidance(files);
|
|
148
|
+
const logLine = useAgentMode && agentLog
|
|
149
|
+
? (line) => writeSync(agentLog.logFd, `${line}\n`)
|
|
150
|
+
: (line) => console.log(line);
|
|
151
|
+
for (const line of lines) {
|
|
152
|
+
logLine(line);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
107
155
|
/**
|
|
108
156
|
* Build a pnpm --filter command string
|
|
109
157
|
*/
|
|
@@ -480,6 +528,16 @@ const agentLog = useAgentMode ? createAgentLogContext({ wuId: wu_id, lane }) : n
|
|
|
480
528
|
// Main execution
|
|
481
529
|
// eslint-disable-next-line sonarjs/cognitive-complexity -- Pre-existing: main() orchestrates multi-step gate workflow
|
|
482
530
|
async function main() {
|
|
531
|
+
const opts = parseGatesArgs();
|
|
532
|
+
// Parse command line arguments (now via Commander)
|
|
533
|
+
const isDocsOnly = opts.docsOnly || false;
|
|
534
|
+
const isFullLint = opts.fullLint || false;
|
|
535
|
+
const isFullTests = opts.fullTests || false;
|
|
536
|
+
// WU-2244: Full coverage flag forces full test suite and coverage gate (deterministic)
|
|
537
|
+
const isFullCoverage = opts.fullCoverage || false;
|
|
538
|
+
// WU-1433: Coverage gate mode (warn or block)
|
|
539
|
+
// WU-2334: Default changed from WARN to BLOCK for TDD enforcement
|
|
540
|
+
const coverageMode = opts.coverageMode || COVERAGE_GATE_MODES.BLOCK;
|
|
483
541
|
if (useAgentMode) {
|
|
484
542
|
console.log(`๐งพ gates (agent mode): output -> ${agentLog.logPath} (use --verbose for streaming)\n`);
|
|
485
543
|
}
|
|
@@ -670,6 +728,9 @@ async function main() {
|
|
|
670
728
|
}
|
|
671
729
|
continue;
|
|
672
730
|
}
|
|
731
|
+
if (gate.name === GATE_NAMES.FORMAT_CHECK) {
|
|
732
|
+
emitFormatCheckGuidance({ agentLog, useAgentMode });
|
|
733
|
+
}
|
|
673
734
|
if (useAgentMode) {
|
|
674
735
|
const tail = readLogTail(agentLog.logPath);
|
|
675
736
|
console.error(`\nโ ${gate.name} failed (agent mode). Log: ${agentLog.logPath}\n`);
|
|
@@ -692,7 +753,9 @@ async function main() {
|
|
|
692
753
|
}
|
|
693
754
|
process.exit(EXIT_CODES.SUCCESS);
|
|
694
755
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
756
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
757
|
+
main().catch((error) => {
|
|
758
|
+
console.error('Gates failed:', error);
|
|
759
|
+
process.exit(EXIT_CODES.ERROR);
|
|
760
|
+
});
|
|
761
|
+
}
|