software-engineer 0.1.22 → 0.1.24
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 +94 -2
- package/dist/claude.js +3 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +20 -1
- package/dist/index.js +40 -4
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +8 -1
- package/dist/pipeline.js +154 -45
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
A CLI tool that automates the software development workflow using Claude AI. It runs an 8-step pipeline to implement features, simplify code, review, ensure quality, test, commit, and update changelogs with real-time progress visualization.
|
|
4
4
|
|
|
5
|
+
By default, Claude is automatically granted permission to **Edit, Read, and Bash** tools, allowing seamless autonomous operation without constant permission prompts.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## The Brain
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
5
12
|
## Installation
|
|
6
13
|
|
|
7
14
|
```bash
|
|
@@ -32,6 +39,7 @@ For best results, follow this workflow:
|
|
|
32
39
|
This approach gives you the best of both worlds:
|
|
33
40
|
- **Interactive planning** with Claude to ensure the approach is correct
|
|
34
41
|
- **Automated execution** with comprehensive quality checks
|
|
42
|
+
- **Seamless operation** - Claude automatically has permission to edit files, read code, and run commands without prompts
|
|
35
43
|
|
|
36
44
|
## Usage
|
|
37
45
|
|
|
@@ -61,6 +69,79 @@ sf --skip-tests --skip-push "update README"
|
|
|
61
69
|
sf --log pipeline.log "implement caching layer"
|
|
62
70
|
```
|
|
63
71
|
|
|
72
|
+
## Permission Management
|
|
73
|
+
|
|
74
|
+
By default, `software-engineer` automatically grants Claude permission to use **Edit, Read, and Bash** tools without prompting. This streamlines the workflow while maintaining control over file operations.
|
|
75
|
+
|
|
76
|
+
### Default Behavior
|
|
77
|
+
|
|
78
|
+
When you run the tool, it automatically passes `--allowedTools "Edit,Read,Bash"` to Claude:
|
|
79
|
+
- **Edit**: Modify existing files
|
|
80
|
+
- **Read**: Read file contents
|
|
81
|
+
- **Bash**: Execute shell commands (git, npm, build tools, etc.)
|
|
82
|
+
|
|
83
|
+
This means Claude can work autonomously on your codebase without constant permission prompts, making the pipeline smooth and efficient.
|
|
84
|
+
|
|
85
|
+
### Customizing Allowed Tools
|
|
86
|
+
|
|
87
|
+
You can customize which tools are auto-approved:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Allow additional tools
|
|
91
|
+
sf --allowedTools "Edit,Read,Write,Bash,Grep" "add new feature"
|
|
92
|
+
|
|
93
|
+
# Via environment variable
|
|
94
|
+
SF_ALLOWED_TOOLS="Edit,Read,Write,Bash" sf "implement caching"
|
|
95
|
+
|
|
96
|
+
# Restrict to read-only operations
|
|
97
|
+
sf --allowedTools "Read,Grep,Glob" "analyze the codebase"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Skipping All Permissions (Use with Caution)
|
|
101
|
+
|
|
102
|
+
For fully autonomous operation in trusted environments (like CI/CD), you can skip all permission checks:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
sf --dangerously-skip-permissions "implement feature"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Warning**: This bypasses ALL permission prompts. Only use in isolated, secure environments.
|
|
109
|
+
|
|
110
|
+
**Note**: When `--dangerously-skip-permissions` is used, the `allowedTools` setting is ignored.
|
|
111
|
+
|
|
112
|
+
## Run Individual Stages
|
|
113
|
+
|
|
114
|
+
You can run specific pipeline stages directly without executing the full pipeline. This is useful for running a quick review or cleanup on code you've already written.
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Run only the code simplification step
|
|
118
|
+
sf --simplify
|
|
119
|
+
|
|
120
|
+
# Run only the code review step
|
|
121
|
+
sf --review
|
|
122
|
+
|
|
123
|
+
# Run only the SOLID & clean code check
|
|
124
|
+
sf --clean-code
|
|
125
|
+
|
|
126
|
+
# Run only the testing step
|
|
127
|
+
sf --test
|
|
128
|
+
|
|
129
|
+
# Run only the commit step
|
|
130
|
+
sf --commit
|
|
131
|
+
|
|
132
|
+
# Run only the implementation step (requires a requirement)
|
|
133
|
+
sf --implement "add error handling to the API"
|
|
134
|
+
|
|
135
|
+
# Combine multiple stages (executed in pipeline order)
|
|
136
|
+
sf --simplify --review --clean-code
|
|
137
|
+
|
|
138
|
+
# Works with other options
|
|
139
|
+
sf --review -r 3 # 3 review iterations
|
|
140
|
+
sf --review --dry-run # Preview without executing
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Note**: All stages except `--implement` work without a requirement — they operate on the current state of your code. You can combine multiple stage flags and they will run in pipeline order.
|
|
144
|
+
|
|
64
145
|
## Options
|
|
65
146
|
|
|
66
147
|
| Option | Description |
|
|
@@ -71,8 +152,17 @@ sf --log pipeline.log "implement caching layer"
|
|
|
71
152
|
| `--skip-tests` | Skip the testing step |
|
|
72
153
|
| `--skip-push` | Commit but don't push to remote |
|
|
73
154
|
| `--skip-branch-management` | Skip smart branch management |
|
|
155
|
+
| `--implementation-only` | Run only: Implement → Review → SOLID |
|
|
156
|
+
| `--implement` | Run only the implementation step |
|
|
157
|
+
| `--simplify` | Run only the code simplification step |
|
|
158
|
+
| `--review` | Run only the code review step |
|
|
159
|
+
| `--clean-code` | Run only the SOLID & clean code step |
|
|
160
|
+
| `--test` | Run only the testing step |
|
|
161
|
+
| `--commit` | Run only the commit step |
|
|
162
|
+
| `--changelog` | Run only the changelog step |
|
|
74
163
|
| `--log <file>` | Log output to file |
|
|
75
|
-
| `--
|
|
164
|
+
| `--allowedTools <tools>` | Comma-separated list of allowed tools (default: "Edit,Read,Bash") |
|
|
165
|
+
| `--dangerously-skip-permissions` | Skip Claude permission prompts (overrides allowedTools) |
|
|
76
166
|
| `-h, --help` | Display help |
|
|
77
167
|
| `-V, --version` | Display version |
|
|
78
168
|
|
|
@@ -89,7 +179,8 @@ All options can be set via environment variables:
|
|
|
89
179
|
| `SF_SKIP_TESTS` | `true`/`false` to skip tests |
|
|
90
180
|
| `SF_SKIP_PUSH` | `true`/`false` to skip push |
|
|
91
181
|
| `SF_SKIP_BRANCH_MANAGEMENT` | `true`/`false` to skip branch management |
|
|
92
|
-
| `
|
|
182
|
+
| `SF_ALLOWED_TOOLS` | Comma-separated list of allowed tools (default: "Edit,Read,Bash") |
|
|
183
|
+
| `SF_DANGEROUSLY_SKIP_PERMISSIONS` | `true`/`false` to skip Claude permissions (overrides allowedTools) |
|
|
93
184
|
|
|
94
185
|
Example:
|
|
95
186
|
```bash
|
|
@@ -98,6 +189,7 @@ SF_REVIEW_ITERATIONS=3 sf "add feature X"
|
|
|
98
189
|
|
|
99
190
|
## Features
|
|
100
191
|
|
|
192
|
+
- **Automatic Permission Management**: Claude is pre-authorized to Edit, Read, and execute Bash commands by default - no constant permission prompts
|
|
101
193
|
- **Real-time Progress Visualization**: See exactly what Claude is doing with colorized, emoji-enhanced output
|
|
102
194
|
- 📖 File reads in cyan
|
|
103
195
|
- ✍️ File writes in green
|
package/dist/claude.js
CHANGED
|
@@ -75,6 +75,9 @@ export async function runClaude(options, config) {
|
|
|
75
75
|
if (config.dangerouslySkipPermissions) {
|
|
76
76
|
args.push('--dangerously-skip-permissions');
|
|
77
77
|
}
|
|
78
|
+
else if (config.allowedTools) {
|
|
79
|
+
args.push('--allowedTools', config.allowedTools);
|
|
80
|
+
}
|
|
78
81
|
// Always pass -p for output and add streaming JSON output format
|
|
79
82
|
args.push('-p', '--output-format=stream-json', '--verbose');
|
|
80
83
|
if (options.continueConversation) {
|
package/dist/config.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export declare const VALID_STAGES: readonly ["implement", "simplify", "review", "clean-code", "test", "commit", "changelog"];
|
|
2
|
+
export type StageName = typeof VALID_STAGES[number];
|
|
1
3
|
export interface Config {
|
|
2
4
|
reviewIterations: number;
|
|
3
5
|
dryRun: boolean;
|
|
@@ -6,8 +8,11 @@ export interface Config {
|
|
|
6
8
|
skipPush: boolean;
|
|
7
9
|
skipBranchManagement: boolean;
|
|
8
10
|
dangerouslySkipPermissions: boolean;
|
|
11
|
+
allowedTools?: string;
|
|
9
12
|
requirement: string;
|
|
10
13
|
adaptiveExecution: boolean;
|
|
14
|
+
implementationOnly: boolean;
|
|
15
|
+
runStages?: StageName[];
|
|
11
16
|
}
|
|
12
17
|
export declare function loadConfigFromEnv(): Partial<Config>;
|
|
13
18
|
export declare function mergeConfig(envConfig: Partial<Config>, cliConfig: Partial<Config>): Config;
|
package/dist/config.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
const DEFAULT_REVIEW_ITERATIONS = 2;
|
|
2
|
+
export const VALID_STAGES = [
|
|
3
|
+
'implement',
|
|
4
|
+
'simplify',
|
|
5
|
+
'review',
|
|
6
|
+
'clean-code',
|
|
7
|
+
'test',
|
|
8
|
+
'commit',
|
|
9
|
+
'changelog',
|
|
10
|
+
];
|
|
2
11
|
function parseBoolEnv(value, defaultValue) {
|
|
3
12
|
if (value === undefined)
|
|
4
13
|
return defaultValue;
|
|
@@ -19,10 +28,17 @@ export function loadConfigFromEnv() {
|
|
|
19
28
|
skipPush: parseBoolEnv(process.env.SF_SKIP_PUSH, false),
|
|
20
29
|
skipBranchManagement: parseBoolEnv(process.env.SF_SKIP_BRANCH_MANAGEMENT, false),
|
|
21
30
|
dangerouslySkipPermissions: parseBoolEnv(process.env.SF_DANGEROUSLY_SKIP_PERMISSIONS, false),
|
|
31
|
+
allowedTools: process.env.SF_ALLOWED_TOOLS || undefined,
|
|
22
32
|
adaptiveExecution: parseBoolEnv(process.env.SF_ADAPTIVE_EXECUTION, false),
|
|
33
|
+
implementationOnly: parseBoolEnv(process.env.SF_IMPLEMENTATION_ONLY, false),
|
|
23
34
|
};
|
|
24
35
|
}
|
|
25
36
|
export function mergeConfig(envConfig, cliConfig) {
|
|
37
|
+
const dangerouslySkipPermissions = cliConfig.dangerouslySkipPermissions ?? envConfig.dangerouslySkipPermissions ?? false;
|
|
38
|
+
// Set default allowedTools to "Edit,Read,Bash" unless dangerouslySkipPermissions is true
|
|
39
|
+
const allowedTools = dangerouslySkipPermissions
|
|
40
|
+
? undefined
|
|
41
|
+
: (cliConfig.allowedTools ?? envConfig.allowedTools ?? 'Edit,Read,Bash');
|
|
26
42
|
return {
|
|
27
43
|
reviewIterations: cliConfig.reviewIterations ?? envConfig.reviewIterations ?? DEFAULT_REVIEW_ITERATIONS,
|
|
28
44
|
dryRun: cliConfig.dryRun ?? envConfig.dryRun ?? false,
|
|
@@ -30,8 +46,11 @@ export function mergeConfig(envConfig, cliConfig) {
|
|
|
30
46
|
skipTests: cliConfig.skipTests ?? envConfig.skipTests ?? false,
|
|
31
47
|
skipPush: cliConfig.skipPush ?? envConfig.skipPush ?? false,
|
|
32
48
|
skipBranchManagement: cliConfig.skipBranchManagement ?? envConfig.skipBranchManagement ?? false,
|
|
33
|
-
dangerouslySkipPermissions
|
|
49
|
+
dangerouslySkipPermissions,
|
|
50
|
+
allowedTools,
|
|
34
51
|
requirement: cliConfig.requirement ?? '',
|
|
35
52
|
adaptiveExecution: cliConfig.adaptiveExecution ?? envConfig.adaptiveExecution ?? false,
|
|
53
|
+
implementationOnly: cliConfig.implementationOnly ?? envConfig.implementationOnly ?? false,
|
|
54
|
+
runStages: cliConfig.runStages,
|
|
36
55
|
};
|
|
37
56
|
}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { readFileSync } from 'fs';
|
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
import { dirname, join } from 'path';
|
|
7
7
|
import { createInterface } from 'readline';
|
|
8
|
-
import { loadConfigFromEnv, mergeConfig } from './config.js';
|
|
8
|
+
import { loadConfigFromEnv, mergeConfig, VALID_STAGES } from './config.js';
|
|
9
9
|
import { runPipeline } from './pipeline.js';
|
|
10
10
|
import { checkForUpdates } from './utils/updateNotifier.js';
|
|
11
11
|
async function promptForRequirement() {
|
|
@@ -47,14 +47,29 @@ program
|
|
|
47
47
|
.option('--skip-tests', 'Skip the testing step')
|
|
48
48
|
.option('--skip-push', 'Commit but do not push')
|
|
49
49
|
.option('--skip-branch-management', 'Skip smart branch management')
|
|
50
|
+
.option('--implementation-only', 'Run only: Implement → Review → SOLID (skips branch, tests, commit)')
|
|
51
|
+
.option('--implement', 'Run only the implementation step')
|
|
52
|
+
.option('--simplify', 'Run only the code simplification step')
|
|
53
|
+
.option('--review', 'Run only the code review step')
|
|
54
|
+
.option('--clean-code', 'Run only the SOLID & clean code step')
|
|
55
|
+
.option('--test', 'Run only the testing step')
|
|
56
|
+
.option('--commit', 'Run only the commit step')
|
|
57
|
+
.option('--changelog', 'Run only the changelog step')
|
|
50
58
|
.option('--log <file>', 'Log output to file')
|
|
51
59
|
.option('--dangerously-skip-permissions', 'Pass flag to claude to skip permission prompts')
|
|
60
|
+
.option('--allowedTools <tools>', 'Comma-separated list of allowed tools (default: "Edit,Read,Bash")')
|
|
52
61
|
.action(async (requirement, options) => {
|
|
53
62
|
// Check for updates (non-blocking, fails silently)
|
|
54
63
|
await checkForUpdates(pkg.name, pkg.version).catch(() => { });
|
|
55
|
-
//
|
|
64
|
+
// Collect stage flags
|
|
65
|
+
const selectedStages = VALID_STAGES.filter((stage) => {
|
|
66
|
+
const camelCase = stage.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
67
|
+
return !!options[camelCase];
|
|
68
|
+
});
|
|
69
|
+
// Prompt for requirement if not provided (skip for stages that don't need one)
|
|
70
|
+
const stageNeedsRequirement = selectedStages.length === 0 || selectedStages.includes('implement');
|
|
56
71
|
let finalRequirement = requirement;
|
|
57
|
-
if (!finalRequirement) {
|
|
72
|
+
if (!finalRequirement && stageNeedsRequirement) {
|
|
58
73
|
finalRequirement = await promptForRequirement();
|
|
59
74
|
}
|
|
60
75
|
const envConfig = loadConfigFromEnv();
|
|
@@ -67,10 +82,31 @@ program
|
|
|
67
82
|
skipBranchManagement: options.skipBranchManagement ?? undefined,
|
|
68
83
|
logFile: options.log ?? undefined,
|
|
69
84
|
dangerouslySkipPermissions: options.dangerouslySkipPermissions ?? undefined,
|
|
85
|
+
allowedTools: options.allowedTools ?? undefined,
|
|
70
86
|
adaptiveExecution: options.adaptive ?? undefined,
|
|
87
|
+
implementationOnly: options.implementationOnly ?? undefined,
|
|
88
|
+
runStages: selectedStages.length > 0 ? selectedStages : undefined,
|
|
71
89
|
};
|
|
72
90
|
const config = mergeConfig(envConfig, cliConfig);
|
|
73
|
-
|
|
91
|
+
// Handle implementation-only mode
|
|
92
|
+
if (config.implementationOnly) {
|
|
93
|
+
if (config.runStages) {
|
|
94
|
+
console.error(chalk.red('Error:') + ' Cannot use --implementation-only with individual stage flags');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
// Implementation-only mode automatically skips branch management and tests
|
|
98
|
+
config.skipBranchManagement = true;
|
|
99
|
+
config.skipTests = true;
|
|
100
|
+
// Warn if adaptive execution was explicitly requested but will be overridden
|
|
101
|
+
const adaptiveWasRequested = options.adaptive || process.env.SF_ADAPTIVE_EXECUTION === 'true';
|
|
102
|
+
if (config.adaptiveExecution && adaptiveWasRequested) {
|
|
103
|
+
console.log(chalk.yellow('⚠ Implementation-only mode overrides --adaptive flag'));
|
|
104
|
+
}
|
|
105
|
+
config.adaptiveExecution = false;
|
|
106
|
+
}
|
|
107
|
+
// Require a requirement for full pipeline or implement stage; optional for other stages
|
|
108
|
+
const needsRequirement = !config.runStages || config.runStages.includes('implement');
|
|
109
|
+
if (!config.requirement && needsRequirement) {
|
|
74
110
|
console.error(chalk.red('Error:') + ' No requirement provided');
|
|
75
111
|
program.help();
|
|
76
112
|
return; // Ensure we don't continue if help() doesn't exit
|
package/dist/logger.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export declare function logHeader(config: {
|
|
|
6
6
|
reviewIterations: number;
|
|
7
7
|
dryRun: boolean;
|
|
8
8
|
dangerouslySkipPermissions: boolean;
|
|
9
|
+
allowedTools?: string;
|
|
10
|
+
implementationOnly: boolean;
|
|
9
11
|
}): void;
|
|
10
12
|
export declare function logSuccess(message: string): void;
|
|
11
13
|
export declare function logError(message: string): void;
|
package/dist/logger.js
CHANGED
|
@@ -52,12 +52,19 @@ export function logHeader(config) {
|
|
|
52
52
|
const authorLine = ' '.repeat(authorPadding) + author + ' '.repeat(BOX_WIDTH - authorPadding - author.length);
|
|
53
53
|
console.log(chalk.green('║') + chalk.dim(authorLine) + chalk.green('║'));
|
|
54
54
|
console.log(chalk.green(`╠${line}╣`));
|
|
55
|
-
|
|
55
|
+
let configLine = ` Reviews: ${config.reviewIterations} | Dry-run: ${config.dryRun}`;
|
|
56
|
+
if (config.implementationOnly) {
|
|
57
|
+
configLine += ' | Mode: implementation-only';
|
|
58
|
+
}
|
|
56
59
|
console.log(chalk.green('║') + configLine.padEnd(BOX_WIDTH) + chalk.green('║'));
|
|
57
60
|
if (config.dangerouslySkipPermissions) {
|
|
58
61
|
const permLine = ' ' + chalk.yellow('⚠ Skip permissions: enabled');
|
|
59
62
|
console.log(chalk.green('║') + permLine + ' '.repeat(BOX_WIDTH - stripAnsi(permLine).length) + chalk.green('║'));
|
|
60
63
|
}
|
|
64
|
+
else if (config.allowedTools) {
|
|
65
|
+
const toolsLine = ' ' + chalk.cyan(`🔓 Allowed tools: ${config.allowedTools}`);
|
|
66
|
+
console.log(chalk.green('║') + toolsLine + ' '.repeat(BOX_WIDTH - stripAnsi(toolsLine).length) + chalk.green('║'));
|
|
67
|
+
}
|
|
61
68
|
console.log(chalk.green(`╚${line}╝`));
|
|
62
69
|
console.log();
|
|
63
70
|
}
|
package/dist/pipeline.js
CHANGED
|
@@ -1,7 +1,107 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { log, logHeader, setLogFile, logInfo } from './logger.js';
|
|
3
3
|
import { stepBranchManagement, stepImplement, stepSimplify, stepReview, stepSolidCleanCode, stepTest, stepCommit, stepChangelog, } from './steps/index.js';
|
|
4
|
+
const EXIT_CODE_FAILURE = 1;
|
|
5
|
+
const EXIT_CODE_INTERRUPT = 130;
|
|
4
6
|
let signalHandlersRegistered = false;
|
|
7
|
+
function exitWithError(message) {
|
|
8
|
+
console.log(chalk.red(`\n${message}`));
|
|
9
|
+
process.exit(EXIT_CODE_FAILURE);
|
|
10
|
+
}
|
|
11
|
+
function getSkipReason(implementationOnly, primaryReason, fallbackReason) {
|
|
12
|
+
return implementationOnly ? 'implementation-only mode' : primaryReason;
|
|
13
|
+
}
|
|
14
|
+
function determineSkipTestsReason(config, rec) {
|
|
15
|
+
if (config.implementationOnly)
|
|
16
|
+
return 'implementation-only mode';
|
|
17
|
+
if (rec?.skipTests)
|
|
18
|
+
return 'adaptive execution';
|
|
19
|
+
if (config.skipTests)
|
|
20
|
+
return '--skip-tests';
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
function displayImplementationOnlyBanner() {
|
|
24
|
+
console.log(chalk.cyan('▶ Running in IMPLEMENTATION-ONLY mode'));
|
|
25
|
+
console.log(chalk.cyan('▶ Steps: Implement → Review → SOLID'));
|
|
26
|
+
console.log(chalk.dim('▶ Skipping: Branch Management, Simplify, Tests, Commit, Changelog\n'));
|
|
27
|
+
}
|
|
28
|
+
function displayCompletionMessage(implementationOnly) {
|
|
29
|
+
if (implementationOnly) {
|
|
30
|
+
console.log(chalk.green('\n✓ Implementation-only pipeline completed successfully'));
|
|
31
|
+
console.log(chalk.yellow('⚠ Changes are not committed - review and commit manually when ready\n'));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.log(chalk.green('\n✓ Pipeline completed successfully\n'));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const STAGE_LABELS = {
|
|
38
|
+
'implement': 'Implement',
|
|
39
|
+
'simplify': 'Simplify',
|
|
40
|
+
'review': 'Code Review',
|
|
41
|
+
'clean-code': 'SOLID & Clean Code',
|
|
42
|
+
'test': 'Testing',
|
|
43
|
+
'commit': 'Commit',
|
|
44
|
+
'changelog': 'Changelog',
|
|
45
|
+
};
|
|
46
|
+
async function runSelectedStages(config) {
|
|
47
|
+
const stages = config.runStages;
|
|
48
|
+
const stageLabels = stages.map((s) => STAGE_LABELS[s]).join(' → ');
|
|
49
|
+
console.log(chalk.cyan(`▶ Running selected stage(s): ${stageLabels}\n`));
|
|
50
|
+
for (const stage of stages) {
|
|
51
|
+
switch (stage) {
|
|
52
|
+
case 'implement': {
|
|
53
|
+
const success = await stepImplement(config);
|
|
54
|
+
if (!success)
|
|
55
|
+
exitWithError('Implementation step failed. Exiting.');
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case 'simplify': {
|
|
59
|
+
const success = await stepSimplify(config);
|
|
60
|
+
if (!success)
|
|
61
|
+
exitWithError('Simplification step failed. Exiting.');
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case 'review': {
|
|
65
|
+
const reviewIterations = config.reviewIterations;
|
|
66
|
+
for (let i = 1; i <= reviewIterations; i++) {
|
|
67
|
+
const reviewResult = await stepReview(i, config);
|
|
68
|
+
if (!reviewResult.success)
|
|
69
|
+
exitWithError('Review step failed. Exiting.');
|
|
70
|
+
if (reviewResult.noIssuesFound) {
|
|
71
|
+
console.log(chalk.green('\n✓ Code review passed - no issues found, skipping remaining reviews'));
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case 'clean-code': {
|
|
78
|
+
const success = await stepSolidCleanCode(config);
|
|
79
|
+
if (!success)
|
|
80
|
+
exitWithError('SOLID review step failed. Exiting.');
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
case 'test': {
|
|
84
|
+
const success = await stepTest(config);
|
|
85
|
+
if (!success)
|
|
86
|
+
exitWithError('Test step failed. Exiting.');
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case 'commit': {
|
|
90
|
+
const success = await stepCommit(config);
|
|
91
|
+
if (!success)
|
|
92
|
+
exitWithError('Commit step failed. Exiting.');
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case 'changelog': {
|
|
96
|
+
const success = await stepChangelog(config);
|
|
97
|
+
if (!success)
|
|
98
|
+
exitWithError('Changelog step failed. Exiting.');
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
console.log(chalk.green('\n✓ Selected stage(s) completed successfully\n'));
|
|
104
|
+
}
|
|
5
105
|
export async function runPipeline(config) {
|
|
6
106
|
// Setup logging
|
|
7
107
|
if (config.logFile) {
|
|
@@ -11,44 +111,58 @@ export async function runPipeline(config) {
|
|
|
11
111
|
if (!signalHandlersRegistered) {
|
|
12
112
|
process.on('SIGINT', () => {
|
|
13
113
|
console.log(chalk.red('\n\nPipeline interrupted'));
|
|
14
|
-
process.exit(
|
|
114
|
+
process.exit(EXIT_CODE_INTERRUPT);
|
|
15
115
|
});
|
|
16
116
|
process.on('SIGTERM', () => {
|
|
17
117
|
console.log(chalk.red('\n\nPipeline terminated'));
|
|
18
|
-
process.exit(
|
|
118
|
+
process.exit(EXIT_CODE_INTERRUPT);
|
|
19
119
|
});
|
|
20
120
|
signalHandlersRegistered = true;
|
|
21
121
|
}
|
|
22
122
|
// Display header
|
|
23
123
|
logHeader(config);
|
|
124
|
+
// Run specific stages if requested
|
|
125
|
+
if (config.runStages && config.runStages.length > 0) {
|
|
126
|
+
return runSelectedStages(config);
|
|
127
|
+
}
|
|
128
|
+
if (config.implementationOnly) {
|
|
129
|
+
displayImplementationOnlyBanner();
|
|
130
|
+
}
|
|
24
131
|
log(`Starting pipeline for: ${config.requirement}`);
|
|
25
|
-
// Step 1: Smart Branch Management
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
132
|
+
// Step 1: Smart Branch Management
|
|
133
|
+
let adaptive = null;
|
|
134
|
+
let rec = null;
|
|
135
|
+
const shouldSkipBranchManagement = config.implementationOnly || config.skipBranchManagement;
|
|
136
|
+
if (shouldSkipBranchManagement) {
|
|
137
|
+
const reason = getSkipReason(config.implementationOnly, '--skip-branch-management', '--skip-branch-management');
|
|
138
|
+
logInfo(`Branch management step skipped (${reason})`);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
const branchResult = await stepBranchManagement(config);
|
|
142
|
+
if (!branchResult.success) {
|
|
143
|
+
exitWithError('Branch management step failed. Exiting.');
|
|
144
|
+
}
|
|
145
|
+
adaptive = branchResult.adaptiveAnalysis;
|
|
146
|
+
rec = adaptive?.stepRecommendation;
|
|
147
|
+
}
|
|
34
148
|
// Step 2: Implement
|
|
35
149
|
const implSuccess = await stepImplement(config);
|
|
36
150
|
if (!implSuccess) {
|
|
37
|
-
|
|
38
|
-
process.exit(1);
|
|
151
|
+
exitWithError('Implementation step failed. Exiting.');
|
|
39
152
|
}
|
|
40
|
-
// Step
|
|
41
|
-
|
|
42
|
-
|
|
153
|
+
// Step 3: Simplify
|
|
154
|
+
const shouldSkipSimplify = config.implementationOnly || rec?.skipSimplify;
|
|
155
|
+
if (shouldSkipSimplify) {
|
|
156
|
+
const reason = getSkipReason(config.implementationOnly, 'adaptive execution', 'adaptive execution');
|
|
157
|
+
logInfo(`Simplify step skipped (${reason})`);
|
|
43
158
|
}
|
|
44
159
|
else {
|
|
45
160
|
const simplifySuccess = await stepSimplify(config);
|
|
46
161
|
if (!simplifySuccess) {
|
|
47
|
-
|
|
48
|
-
process.exit(1);
|
|
162
|
+
exitWithError('Simplification step failed. Exiting.');
|
|
49
163
|
}
|
|
50
164
|
}
|
|
51
|
-
// Step 5: Review loop
|
|
165
|
+
// Step 5: Review loop
|
|
52
166
|
if (rec?.skipReview) {
|
|
53
167
|
logInfo('Review step skipped (adaptive execution)');
|
|
54
168
|
}
|
|
@@ -57,61 +171,56 @@ export async function runPipeline(config) {
|
|
|
57
171
|
for (let i = 1; i <= reviewIterations; i++) {
|
|
58
172
|
const reviewResult = await stepReview(i, config, rec?.reviewDepth);
|
|
59
173
|
if (!reviewResult.success) {
|
|
60
|
-
|
|
61
|
-
process.exit(1);
|
|
174
|
+
exitWithError('Review step failed. Exiting.');
|
|
62
175
|
}
|
|
63
|
-
// Skip remaining reviews if no issues were found
|
|
64
176
|
if (reviewResult.noIssuesFound) {
|
|
65
177
|
console.log(chalk.green('\n✓ Code review passed - no issues found, skipping remaining reviews'));
|
|
66
178
|
break;
|
|
67
179
|
}
|
|
68
180
|
}
|
|
69
181
|
}
|
|
70
|
-
// Step 6: SOLID & Clean Code
|
|
182
|
+
// Step 6: SOLID & Clean Code
|
|
71
183
|
if (rec?.skipSolid) {
|
|
72
184
|
logInfo('SOLID review step skipped (adaptive execution)');
|
|
73
185
|
}
|
|
74
186
|
else {
|
|
75
187
|
const solidSuccess = await stepSolidCleanCode(config);
|
|
76
188
|
if (!solidSuccess) {
|
|
77
|
-
|
|
78
|
-
process.exit(1);
|
|
189
|
+
exitWithError('SOLID review step failed. Exiting.');
|
|
79
190
|
}
|
|
80
191
|
}
|
|
81
|
-
// Step 7: Test
|
|
82
|
-
|
|
83
|
-
if (rec?.skipTests) {
|
|
84
|
-
skipTestsReason = 'adaptive execution';
|
|
85
|
-
}
|
|
86
|
-
else if (config.skipTests) {
|
|
87
|
-
skipTestsReason = '--skip-tests';
|
|
88
|
-
}
|
|
192
|
+
// Step 7: Test
|
|
193
|
+
const skipTestsReason = determineSkipTestsReason(config, rec);
|
|
89
194
|
if (skipTestsReason) {
|
|
90
195
|
logInfo(`Test step skipped (${skipTestsReason})`);
|
|
91
196
|
}
|
|
92
197
|
else {
|
|
93
198
|
const testSuccess = await stepTest(config);
|
|
94
199
|
if (!testSuccess) {
|
|
95
|
-
|
|
96
|
-
process.exit(1);
|
|
200
|
+
exitWithError('Test step failed. Exiting.');
|
|
97
201
|
}
|
|
98
202
|
}
|
|
99
203
|
// Step 8: Commit
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
204
|
+
if (config.implementationOnly) {
|
|
205
|
+
logInfo('Commit step skipped (implementation-only mode)');
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
const commitSuccess = await stepCommit(config);
|
|
209
|
+
if (!commitSuccess) {
|
|
210
|
+
exitWithError('Commit step failed. Exiting.');
|
|
211
|
+
}
|
|
104
212
|
}
|
|
105
|
-
// Step 9: Changelog
|
|
106
|
-
|
|
107
|
-
|
|
213
|
+
// Step 9: Changelog
|
|
214
|
+
const shouldSkipChangelog = config.implementationOnly || rec?.skipChangelog;
|
|
215
|
+
if (shouldSkipChangelog) {
|
|
216
|
+
const reason = getSkipReason(config.implementationOnly, 'adaptive execution', 'adaptive execution');
|
|
217
|
+
logInfo(`Changelog step skipped (${reason})`);
|
|
108
218
|
}
|
|
109
219
|
else {
|
|
110
220
|
const changelogSuccess = await stepChangelog(config);
|
|
111
221
|
if (!changelogSuccess) {
|
|
112
|
-
|
|
113
|
-
process.exit(1);
|
|
222
|
+
exitWithError('Changelog step failed. Exiting.');
|
|
114
223
|
}
|
|
115
224
|
}
|
|
116
|
-
|
|
225
|
+
displayCompletionMessage(config.implementationOnly);
|
|
117
226
|
}
|
package/package.json
CHANGED