software-engineer 0.1.21 → 0.1.23

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,8 @@
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
+
5
7
  ## Installation
6
8
 
7
9
  ```bash
@@ -13,6 +15,27 @@ npm install -g software-engineer
13
15
  - Node.js >= 18.0.0
14
16
  - [Claude CLI](https://github.com/anthropics/claude-code) installed and configured
15
17
 
18
+ ## Recommended Workflow
19
+
20
+ For best results, follow this workflow:
21
+
22
+ 1. **Plan with Claude**: Start a Claude session and use plan mode to design what needs to be done
23
+ - Discuss requirements with Claude
24
+ - Iterate and refine the plan until it's complete
25
+ - Claude will generate a plan file (usually a `.md` file)
26
+
27
+ 2. **Execute with software-engineer**: Once your plan is finalized, close Claude and run:
28
+ ```bash
29
+ sf "implement the plan mentioned in /path/to/plan.md"
30
+ ```
31
+
32
+ 3. **Wait for completion**: The tool will automatically execute the entire pipeline and implement your plan
33
+
34
+ This approach gives you the best of both worlds:
35
+ - **Interactive planning** with Claude to ensure the approach is correct
36
+ - **Automated execution** with comprehensive quality checks
37
+ - **Seamless operation** - Claude automatically has permission to edit files, read code, and run commands without prompts
38
+
16
39
  ## Usage
17
40
 
18
41
  ```bash
@@ -22,7 +45,10 @@ sf "<requirement>"
22
45
  ### Examples
23
46
 
24
47
  ```bash
25
- # Basic usage
48
+ # Recommended: Use with a plan file from Claude
49
+ sf "implement the plan mentioned in ./docs/feature-plan.md"
50
+
51
+ # Basic usage with direct requirement
26
52
  sf "add user authentication with JWT"
27
53
 
28
54
  # Custom review iterations
@@ -38,6 +64,46 @@ sf --skip-tests --skip-push "update README"
38
64
  sf --log pipeline.log "implement caching layer"
39
65
  ```
40
66
 
67
+ ## Permission Management
68
+
69
+ 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.
70
+
71
+ ### Default Behavior
72
+
73
+ When you run the tool, it automatically passes `--allowedTools "Edit,Read,Bash"` to Claude:
74
+ - **Edit**: Modify existing files
75
+ - **Read**: Read file contents
76
+ - **Bash**: Execute shell commands (git, npm, build tools, etc.)
77
+
78
+ This means Claude can work autonomously on your codebase without constant permission prompts, making the pipeline smooth and efficient.
79
+
80
+ ### Customizing Allowed Tools
81
+
82
+ You can customize which tools are auto-approved:
83
+
84
+ ```bash
85
+ # Allow additional tools
86
+ sf --allowedTools "Edit,Read,Write,Bash,Grep" "add new feature"
87
+
88
+ # Via environment variable
89
+ SF_ALLOWED_TOOLS="Edit,Read,Write,Bash" sf "implement caching"
90
+
91
+ # Restrict to read-only operations
92
+ sf --allowedTools "Read,Grep,Glob" "analyze the codebase"
93
+ ```
94
+
95
+ ### Skipping All Permissions (Use with Caution)
96
+
97
+ For fully autonomous operation in trusted environments (like CI/CD), you can skip all permission checks:
98
+
99
+ ```bash
100
+ sf --dangerously-skip-permissions "implement feature"
101
+ ```
102
+
103
+ **Warning**: This bypasses ALL permission prompts. Only use in isolated, secure environments.
104
+
105
+ **Note**: When `--dangerously-skip-permissions` is used, the `allowedTools` setting is ignored.
106
+
41
107
  ## Options
42
108
 
43
109
  | Option | Description |
@@ -49,7 +115,8 @@ sf --log pipeline.log "implement caching layer"
49
115
  | `--skip-push` | Commit but don't push to remote |
50
116
  | `--skip-branch-management` | Skip smart branch management |
51
117
  | `--log <file>` | Log output to file |
52
- | `--dangerously-skip-permissions` | Skip Claude permission prompts |
118
+ | `--allowedTools <tools>` | Comma-separated list of allowed tools (default: "Edit,Read,Bash") |
119
+ | `--dangerously-skip-permissions` | Skip Claude permission prompts (overrides allowedTools) |
53
120
  | `-h, --help` | Display help |
54
121
  | `-V, --version` | Display version |
55
122
 
@@ -66,7 +133,8 @@ All options can be set via environment variables:
66
133
  | `SF_SKIP_TESTS` | `true`/`false` to skip tests |
67
134
  | `SF_SKIP_PUSH` | `true`/`false` to skip push |
68
135
  | `SF_SKIP_BRANCH_MANAGEMENT` | `true`/`false` to skip branch management |
69
- | `SF_DANGEROUSLY_SKIP_PERMISSIONS` | `true`/`false` to skip Claude permissions |
136
+ | `SF_ALLOWED_TOOLS` | Comma-separated list of allowed tools (default: "Edit,Read,Bash") |
137
+ | `SF_DANGEROUSLY_SKIP_PERMISSIONS` | `true`/`false` to skip Claude permissions (overrides allowedTools) |
70
138
 
71
139
  Example:
72
140
  ```bash
@@ -75,6 +143,7 @@ SF_REVIEW_ITERATIONS=3 sf "add feature X"
75
143
 
76
144
  ## Features
77
145
 
146
+ - **Automatic Permission Management**: Claude is pre-authorized to Edit, Read, and execute Bash commands by default - no constant permission prompts
78
147
  - **Real-time Progress Visualization**: See exactly what Claude is doing with colorized, emoji-enhanced output
79
148
  - šŸ“– File reads in cyan
80
149
  - āœļø 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
@@ -6,8 +6,10 @@ export interface Config {
6
6
  skipPush: boolean;
7
7
  skipBranchManagement: boolean;
8
8
  dangerouslySkipPermissions: boolean;
9
+ allowedTools?: string;
9
10
  requirement: string;
10
11
  adaptiveExecution: boolean;
12
+ implementationOnly: boolean;
11
13
  }
12
14
  export declare function loadConfigFromEnv(): Partial<Config>;
13
15
  export declare function mergeConfig(envConfig: Partial<Config>, cliConfig: Partial<Config>): Config;
package/dist/config.js CHANGED
@@ -19,10 +19,17 @@ export function loadConfigFromEnv() {
19
19
  skipPush: parseBoolEnv(process.env.SF_SKIP_PUSH, false),
20
20
  skipBranchManagement: parseBoolEnv(process.env.SF_SKIP_BRANCH_MANAGEMENT, false),
21
21
  dangerouslySkipPermissions: parseBoolEnv(process.env.SF_DANGEROUSLY_SKIP_PERMISSIONS, false),
22
+ allowedTools: process.env.SF_ALLOWED_TOOLS || undefined,
22
23
  adaptiveExecution: parseBoolEnv(process.env.SF_ADAPTIVE_EXECUTION, false),
24
+ implementationOnly: parseBoolEnv(process.env.SF_IMPLEMENTATION_ONLY, false),
23
25
  };
24
26
  }
25
27
  export function mergeConfig(envConfig, cliConfig) {
28
+ const dangerouslySkipPermissions = cliConfig.dangerouslySkipPermissions ?? envConfig.dangerouslySkipPermissions ?? false;
29
+ // Set default allowedTools to "Edit,Read,Bash" unless dangerouslySkipPermissions is true
30
+ const allowedTools = dangerouslySkipPermissions
31
+ ? undefined
32
+ : (cliConfig.allowedTools ?? envConfig.allowedTools ?? 'Edit,Read,Bash');
26
33
  return {
27
34
  reviewIterations: cliConfig.reviewIterations ?? envConfig.reviewIterations ?? DEFAULT_REVIEW_ITERATIONS,
28
35
  dryRun: cliConfig.dryRun ?? envConfig.dryRun ?? false,
@@ -30,8 +37,10 @@ export function mergeConfig(envConfig, cliConfig) {
30
37
  skipTests: cliConfig.skipTests ?? envConfig.skipTests ?? false,
31
38
  skipPush: cliConfig.skipPush ?? envConfig.skipPush ?? false,
32
39
  skipBranchManagement: cliConfig.skipBranchManagement ?? envConfig.skipBranchManagement ?? false,
33
- dangerouslySkipPermissions: cliConfig.dangerouslySkipPermissions ?? envConfig.dangerouslySkipPermissions ?? false,
40
+ dangerouslySkipPermissions,
41
+ allowedTools,
34
42
  requirement: cliConfig.requirement ?? '',
35
43
  adaptiveExecution: cliConfig.adaptiveExecution ?? envConfig.adaptiveExecution ?? false,
44
+ implementationOnly: cliConfig.implementationOnly ?? envConfig.implementationOnly ?? false,
36
45
  };
37
46
  }
package/dist/index.js CHANGED
@@ -47,8 +47,10 @@ 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)')
50
51
  .option('--log <file>', 'Log output to file')
51
52
  .option('--dangerously-skip-permissions', 'Pass flag to claude to skip permission prompts')
53
+ .option('--allowedTools <tools>', 'Comma-separated list of allowed tools (default: "Edit,Read,Bash")')
52
54
  .action(async (requirement, options) => {
53
55
  // Check for updates (non-blocking, fails silently)
54
56
  await checkForUpdates(pkg.name, pkg.version).catch(() => { });
@@ -67,9 +69,23 @@ program
67
69
  skipBranchManagement: options.skipBranchManagement ?? undefined,
68
70
  logFile: options.log ?? undefined,
69
71
  dangerouslySkipPermissions: options.dangerouslySkipPermissions ?? undefined,
72
+ allowedTools: options.allowedTools ?? undefined,
70
73
  adaptiveExecution: options.adaptive ?? undefined,
74
+ implementationOnly: options.implementationOnly ?? undefined,
71
75
  };
72
76
  const config = mergeConfig(envConfig, cliConfig);
77
+ // Handle implementation-only mode
78
+ if (config.implementationOnly) {
79
+ // Implementation-only mode automatically skips branch management and tests
80
+ config.skipBranchManagement = true;
81
+ config.skipTests = true;
82
+ // Warn if adaptive execution was explicitly requested but will be overridden
83
+ const adaptiveWasRequested = options.adaptive || process.env.SF_ADAPTIVE_EXECUTION === 'true';
84
+ if (config.adaptiveExecution && adaptiveWasRequested) {
85
+ console.log(chalk.yellow('⚠ Implementation-only mode overrides --adaptive flag'));
86
+ }
87
+ config.adaptiveExecution = false;
88
+ }
73
89
  if (!config.requirement) {
74
90
  console.error(chalk.red('Error:') + ' No requirement provided');
75
91
  program.help();
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,39 @@
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
+ }
5
37
  export async function runPipeline(config) {
6
38
  // Setup logging
7
39
  if (config.logFile) {
@@ -11,44 +43,54 @@ export async function runPipeline(config) {
11
43
  if (!signalHandlersRegistered) {
12
44
  process.on('SIGINT', () => {
13
45
  console.log(chalk.red('\n\nPipeline interrupted'));
14
- process.exit(130);
46
+ process.exit(EXIT_CODE_INTERRUPT);
15
47
  });
16
48
  process.on('SIGTERM', () => {
17
49
  console.log(chalk.red('\n\nPipeline terminated'));
18
- process.exit(130);
50
+ process.exit(EXIT_CODE_INTERRUPT);
19
51
  });
20
52
  signalHandlersRegistered = true;
21
53
  }
22
54
  // Display header
23
55
  logHeader(config);
56
+ if (config.implementationOnly) {
57
+ displayImplementationOnlyBanner();
58
+ }
24
59
  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;
60
+ // Step 1: Smart Branch Management
61
+ let adaptive = null;
62
+ let rec = null;
63
+ const shouldSkipBranchManagement = config.implementationOnly || config.skipBranchManagement;
64
+ if (shouldSkipBranchManagement) {
65
+ const reason = getSkipReason(config.implementationOnly, '--skip-branch-management', '--skip-branch-management');
66
+ logInfo(`Branch management step skipped (${reason})`);
67
+ }
68
+ else {
69
+ const branchResult = await stepBranchManagement(config);
70
+ if (!branchResult.success) {
71
+ exitWithError('Branch management step failed. Exiting.');
72
+ }
73
+ adaptive = branchResult.adaptiveAnalysis;
74
+ rec = adaptive?.stepRecommendation;
75
+ }
34
76
  // Step 2: Implement
35
77
  const implSuccess = await stepImplement(config);
36
78
  if (!implSuccess) {
37
- console.log(chalk.red('\nImplementation step failed. Exiting.'));
38
- process.exit(1);
79
+ exitWithError('Implementation step failed. Exiting.');
39
80
  }
40
- // Step 4: Simplify (can be skipped by adaptive execution)
41
- if (rec?.skipSimplify) {
42
- logInfo('Simplify step skipped (adaptive execution)');
81
+ // Step 3: Simplify
82
+ const shouldSkipSimplify = config.implementationOnly || rec?.skipSimplify;
83
+ if (shouldSkipSimplify) {
84
+ const reason = getSkipReason(config.implementationOnly, 'adaptive execution', 'adaptive execution');
85
+ logInfo(`Simplify step skipped (${reason})`);
43
86
  }
44
87
  else {
45
88
  const simplifySuccess = await stepSimplify(config);
46
89
  if (!simplifySuccess) {
47
- console.log(chalk.red('\nSimplification step failed. Exiting.'));
48
- process.exit(1);
90
+ exitWithError('Simplification step failed. Exiting.');
49
91
  }
50
92
  }
51
- // Step 5: Review loop (can be skipped or adjusted by adaptive execution)
93
+ // Step 5: Review loop
52
94
  if (rec?.skipReview) {
53
95
  logInfo('Review step skipped (adaptive execution)');
54
96
  }
@@ -57,61 +99,56 @@ export async function runPipeline(config) {
57
99
  for (let i = 1; i <= reviewIterations; i++) {
58
100
  const reviewResult = await stepReview(i, config, rec?.reviewDepth);
59
101
  if (!reviewResult.success) {
60
- console.log(chalk.red('\nReview step failed. Exiting.'));
61
- process.exit(1);
102
+ exitWithError('Review step failed. Exiting.');
62
103
  }
63
- // Skip remaining reviews if no issues were found
64
104
  if (reviewResult.noIssuesFound) {
65
105
  console.log(chalk.green('\nāœ“ Code review passed - no issues found, skipping remaining reviews'));
66
106
  break;
67
107
  }
68
108
  }
69
109
  }
70
- // Step 6: SOLID & Clean Code (can be skipped by adaptive execution)
110
+ // Step 6: SOLID & Clean Code
71
111
  if (rec?.skipSolid) {
72
112
  logInfo('SOLID review step skipped (adaptive execution)');
73
113
  }
74
114
  else {
75
115
  const solidSuccess = await stepSolidCleanCode(config);
76
116
  if (!solidSuccess) {
77
- console.log(chalk.red('\nSOLID review step failed. Exiting.'));
78
- process.exit(1);
117
+ exitWithError('SOLID review step failed. Exiting.');
79
118
  }
80
119
  }
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
- }
120
+ // Step 7: Test
121
+ const skipTestsReason = determineSkipTestsReason(config, rec);
89
122
  if (skipTestsReason) {
90
123
  logInfo(`Test step skipped (${skipTestsReason})`);
91
124
  }
92
125
  else {
93
126
  const testSuccess = await stepTest(config);
94
127
  if (!testSuccess) {
95
- console.log(chalk.red('\nTest step failed. Exiting.'));
96
- process.exit(1);
128
+ exitWithError('Test step failed. Exiting.');
97
129
  }
98
130
  }
99
131
  // 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);
132
+ if (config.implementationOnly) {
133
+ logInfo('Commit step skipped (implementation-only mode)');
134
+ }
135
+ else {
136
+ const commitSuccess = await stepCommit(config);
137
+ if (!commitSuccess) {
138
+ exitWithError('Commit step failed. Exiting.');
139
+ }
104
140
  }
105
- // Step 9: Changelog (can be skipped by adaptive execution)
106
- if (rec?.skipChangelog) {
107
- logInfo('Changelog step skipped (adaptive execution)');
141
+ // Step 9: Changelog
142
+ const shouldSkipChangelog = config.implementationOnly || rec?.skipChangelog;
143
+ if (shouldSkipChangelog) {
144
+ const reason = getSkipReason(config.implementationOnly, 'adaptive execution', 'adaptive execution');
145
+ logInfo(`Changelog step skipped (${reason})`);
108
146
  }
109
147
  else {
110
148
  const changelogSuccess = await stepChangelog(config);
111
149
  if (!changelogSuccess) {
112
- console.log(chalk.red('\nChangelog step failed. Exiting.'));
113
- process.exit(1);
150
+ exitWithError('Changelog step failed. Exiting.');
114
151
  }
115
152
  }
116
- console.log(chalk.green('\nāœ“ Pipeline completed successfully\n'));
153
+ displayCompletionMessage(config.implementationOnly);
117
154
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "software-engineer",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
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",