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 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
+ ![](docs/architecture-diagram.png)
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
- | `--dangerously-skip-permissions` | Skip Claude permission prompts |
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
- | `SF_DANGEROUSLY_SKIP_PERMISSIONS` | `true`/`false` to skip Claude permissions |
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: cliConfig.dangerouslySkipPermissions ?? envConfig.dangerouslySkipPermissions ?? false,
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
- // Prompt for requirement if not provided
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
- if (!config.requirement) {
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
- const configLine = ` Reviews: ${config.reviewIterations} | Dry-run: ${config.dryRun}`;
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(130);
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(130);
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 (also performs adaptive analysis if enabled)
26
- const branchResult = await stepBranchManagement(config);
27
- if (!branchResult.success) {
28
- console.log(chalk.red('\nBranch management step failed. Exiting.'));
29
- process.exit(1);
30
- }
31
- // Extract adaptive analysis for step decisions
32
- const adaptive = branchResult.adaptiveAnalysis;
33
- const rec = adaptive?.stepRecommendation;
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
- console.log(chalk.red('\nImplementation step failed. Exiting.'));
38
- process.exit(1);
151
+ exitWithError('Implementation step failed. Exiting.');
39
152
  }
40
- // Step 4: Simplify (can be skipped by adaptive execution)
41
- if (rec?.skipSimplify) {
42
- logInfo('Simplify step skipped (adaptive execution)');
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
- console.log(chalk.red('\nSimplification step failed. Exiting.'));
48
- process.exit(1);
162
+ exitWithError('Simplification step failed. Exiting.');
49
163
  }
50
164
  }
51
- // Step 5: Review loop (can be skipped or adjusted by adaptive execution)
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
- console.log(chalk.red('\nReview step failed. Exiting.'));
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 (can be skipped by adaptive execution)
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
- console.log(chalk.red('\nSOLID review step failed. Exiting.'));
78
- process.exit(1);
189
+ exitWithError('SOLID review step failed. Exiting.');
79
190
  }
80
191
  }
81
- // Step 7: Test (can be skipped by adaptive execution or CLI flag)
82
- let skipTestsReason = null;
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
- console.log(chalk.red('\nTest step failed. Exiting.'));
96
- process.exit(1);
200
+ exitWithError('Test step failed. Exiting.');
97
201
  }
98
202
  }
99
203
  // Step 8: Commit
100
- const commitSuccess = await stepCommit(config);
101
- if (!commitSuccess) {
102
- console.log(chalk.red('\nCommit step failed. Exiting.'));
103
- process.exit(1);
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 (can be skipped by adaptive execution)
106
- if (rec?.skipChangelog) {
107
- logInfo('Changelog step skipped (adaptive execution)');
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
- console.log(chalk.red('\nChangelog step failed. Exiting.'));
113
- process.exit(1);
222
+ exitWithError('Changelog step failed. Exiting.');
114
223
  }
115
224
  }
116
- console.log(chalk.green('\n✓ Pipeline completed successfully\n'));
225
+ displayCompletionMessage(config.implementationOnly);
117
226
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "software-engineer",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "description": "CLI that automates the full dev workflow with Claude AI - implement, review, test, and commit code with a single command",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",