@rcrsr/claude-code-runner 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/dist/cli/args.d.ts +20 -0
  4. package/dist/cli/args.d.ts.map +1 -0
  5. package/dist/cli/args.js +144 -0
  6. package/dist/cli/args.js.map +1 -0
  7. package/dist/cli/index.d.ts +2 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +2 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/core/index.d.ts +2 -0
  12. package/dist/core/index.d.ts.map +1 -0
  13. package/dist/core/index.js +2 -0
  14. package/dist/core/index.js.map +1 -0
  15. package/dist/core/runner.d.ts +18 -0
  16. package/dist/core/runner.d.ts.map +1 -0
  17. package/dist/core/runner.js +107 -0
  18. package/dist/core/runner.js.map +1 -0
  19. package/dist/index.d.ts +7 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +125 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/output/colors.d.ts +33 -0
  24. package/dist/output/colors.d.ts.map +1 -0
  25. package/dist/output/colors.js +63 -0
  26. package/dist/output/colors.js.map +1 -0
  27. package/dist/output/formatter.d.ts +28 -0
  28. package/dist/output/formatter.d.ts.map +1 -0
  29. package/dist/output/formatter.js +275 -0
  30. package/dist/output/formatter.js.map +1 -0
  31. package/dist/output/index.d.ts +4 -0
  32. package/dist/output/index.d.ts.map +1 -0
  33. package/dist/output/index.js +4 -0
  34. package/dist/output/index.js.map +1 -0
  35. package/dist/output/logger.d.ts +13 -0
  36. package/dist/output/logger.d.ts.map +1 -0
  37. package/dist/output/logger.js +38 -0
  38. package/dist/output/logger.js.map +1 -0
  39. package/dist/parsers/index.d.ts +3 -0
  40. package/dist/parsers/index.d.ts.map +1 -0
  41. package/dist/parsers/index.js +3 -0
  42. package/dist/parsers/index.js.map +1 -0
  43. package/dist/parsers/signals.d.ts +10 -0
  44. package/dist/parsers/signals.d.ts.map +1 -0
  45. package/dist/parsers/signals.js +24 -0
  46. package/dist/parsers/signals.js.map +1 -0
  47. package/dist/parsers/stream.d.ts +16 -0
  48. package/dist/parsers/stream.d.ts.map +1 -0
  49. package/dist/parsers/stream.js +45 -0
  50. package/dist/parsers/stream.js.map +1 -0
  51. package/dist/process/index.d.ts +2 -0
  52. package/dist/process/index.d.ts.map +1 -0
  53. package/dist/process/index.js +2 -0
  54. package/dist/process/index.js.map +1 -0
  55. package/dist/process/pty.d.ts +19 -0
  56. package/dist/process/pty.d.ts.map +1 -0
  57. package/dist/process/pty.js +47 -0
  58. package/dist/process/pty.js.map +1 -0
  59. package/dist/templates/command.d.ts +17 -0
  60. package/dist/templates/command.d.ts.map +1 -0
  61. package/dist/templates/command.js +48 -0
  62. package/dist/templates/command.js.map +1 -0
  63. package/dist/templates/index.d.ts +2 -0
  64. package/dist/templates/index.d.ts.map +1 -0
  65. package/dist/templates/index.js +2 -0
  66. package/dist/templates/index.js.map +1 -0
  67. package/dist/types/claude.d.ts +66 -0
  68. package/dist/types/claude.d.ts.map +1 -0
  69. package/dist/types/claude.js +28 -0
  70. package/dist/types/claude.js.map +1 -0
  71. package/dist/types/index.d.ts +3 -0
  72. package/dist/types/index.d.ts.map +1 -0
  73. package/dist/types/index.js +3 -0
  74. package/dist/types/index.js.map +1 -0
  75. package/dist/types/runner.d.ts +74 -0
  76. package/dist/types/runner.d.ts.map +1 -0
  77. package/dist/types/runner.js +31 -0
  78. package/dist/types/runner.js.map +1 -0
  79. package/package.json +66 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Andre Bremer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # Claude Code Runner
2
+
3
+ Deterministic, scripted, unattended Claude Code execution.
4
+
5
+ ## Why Use This?
6
+
7
+ - **Run unattended** — Execute Claude commands in CI/CD pipelines and automation scripts
8
+ - **Script multiple commands** — Chain prompts together in a single run
9
+ - **Iterative runs with fresh context per phase** — Each command starts with a clean slate, ideal for phase-based implementation plans
10
+ - **Self-correcting loops** — Users can configure prompts with [runner signals](#runner-signals) to control execution, like retry, complete, or escalation to a human
11
+ - **Full visibility** — Watch tool calls stream in real-time
12
+ - **Complete logs** — Every session captured for debugging and review
13
+
14
+ ## Prerequisites
15
+
16
+ - Node.js 18 or later
17
+ - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install -g @rcrsr/claude-code-runner
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### prompt — Run a single prompt
28
+
29
+ ```bash
30
+ claude-code-runner prompt "Refactor the auth module to use async/await"
31
+ ```
32
+
33
+ The `prompt` keyword is optional — bare strings work the same way:
34
+
35
+ ```bash
36
+ claude-code-runner "Fix the failing tests in src/utils"
37
+ ```
38
+
39
+ ### command — Run a slash command file
40
+
41
+ Store prompts as markdown files in `.claude/commands/` and invoke them by name:
42
+
43
+ ```bash
44
+ claude-code-runner command review-code src/auth.ts
45
+ ```
46
+
47
+ This loads `.claude/commands/review-code.md` and substitutes `$1` with `src/auth.ts`.
48
+
49
+ **Example template** (`.claude/commands/review-code.md`):
50
+
51
+ ```markdown
52
+ Review the code in $1 for:
53
+
54
+ - Security vulnerabilities
55
+ - Performance issues
56
+ - Code style violations
57
+
58
+ Output findings as a numbered list.
59
+ ```
60
+
61
+ Templates support multiple arguments (`$1`, `$2`, `$3`, etc.) and YAML frontmatter is automatically stripped.
62
+
63
+ ### script — Run multiple commands in sequence
64
+
65
+ Create a script file with one command per line:
66
+
67
+ ```bash
68
+ claude-code-runner script deploy-tasks.txt
69
+ ```
70
+
71
+ **Example script** (`deploy-tasks.txt`):
72
+
73
+ ```text
74
+ # Comments start with #
75
+ prompt Run the test suite and fix any failures
76
+ command review-code src/api/handlers.ts
77
+ prompt Update the changelog for version 2.1.0
78
+ ```
79
+
80
+ Scripts stop on `BLOCKED` or `ERROR` signals, letting you catch issues before continuing.
81
+
82
+ ### Options
83
+
84
+ | Option | Description |
85
+ | ----------- | ---------------------------- |
86
+ | `--quiet` | Minimal output (errors only) |
87
+ | `--normal` | Default output level |
88
+ | `--verbose` | Full output with details |
89
+ | `--no-log` | Disable file logging |
90
+
91
+ ## Runner Signals
92
+
93
+ Signals give Claude a way to control execution flow. Instruct Claude to output these signals in your prompts or templates, and the runner will respond accordingly.
94
+
95
+ | Signal | Effect |
96
+ | ------------------------ | -------------------------------- |
97
+ | `:::RUNNER::DONE:::` | Exit successfully |
98
+ | `:::RUNNER::CONTINUE:::` | Continue to next iteration |
99
+ | `:::RUNNER::BLOCKED:::` | Exit with error (awaiting human) |
100
+ | `:::RUNNER::ERROR:::` | Exit with error |
101
+
102
+ **Example prompt using signals:**
103
+
104
+ ```bash
105
+ claude-code-runner "Fix all lint errors in src/. Output :::RUNNER::DONE::: when complete, or :::RUNNER::BLOCKED::: if you need human input."
106
+ ```
107
+
108
+ **Example template with signals** (`.claude/commands/fix-tests.md`):
109
+
110
+ ```markdown
111
+ Run the test suite for $1.
112
+
113
+ - If all tests pass, output :::RUNNER::DONE:::
114
+ - If tests fail and you can fix them, fix them and output :::RUNNER::CONTINUE::: to re-run
115
+ - If tests fail and you need help, output :::RUNNER::BLOCKED::: with an explanation
116
+ ```
117
+
118
+ This pattern enables self-correcting loops: Claude attempts a fix, signals `CONTINUE` to retry, and only exits when done or stuck.
119
+
120
+ **Defaults:**
121
+
122
+ - Max 10 iterations per command (prevents runaway loops)
123
+ - If no signal is detected, the runner uses the CLI exit code (0 = success, non-0 = error)
124
+
125
+ ## Exit Codes
126
+
127
+ For CI/CD integration:
128
+
129
+ | Code | Meaning |
130
+ | ---- | -------------------------------------------- |
131
+ | 0 | Success (`DONE` signal or clean exit) |
132
+ | 1 | Error (`ERROR`, `BLOCKED`, or non-zero exit) |
133
+
134
+ ## Logs
135
+
136
+ Sessions are logged to `./logs/` with timestamped filenames. Disable with `--no-log`.
137
+
138
+ ## Development
139
+
140
+ ```bash
141
+ npm run check # Run all checks (typecheck, lint, format, test)
142
+ npm run build # Build the project
143
+ npm test # Run tests
144
+ ```
145
+
146
+ ## License
147
+
148
+ MIT
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CLI argument parsing
3
+ */
4
+ import type { ParsedArgs } from '../types/index.js';
5
+ /**
6
+ * Parse a command line into a prompt
7
+ * Used for script mode line parsing
8
+ */
9
+ export declare function parseCommandLine(line: string): {
10
+ prompt: string;
11
+ };
12
+ /**
13
+ * Parse CLI arguments
14
+ */
15
+ export declare function parseArgs(args: string[]): ParsedArgs;
16
+ /**
17
+ * Print usage information
18
+ */
19
+ export declare function printUsage(): void;
20
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,mBAAmB,CAAC;AAsC3B;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAkBjE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAwDpD;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CA0BjC"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * CLI argument parsing
3
+ */
4
+ import * as fs from 'fs';
5
+ import { loadCommandTemplate } from '../templates/command.js';
6
+ /**
7
+ * Extract options from raw args, returning positional args and config
8
+ */
9
+ function extractOptions(args) {
10
+ let verbosity = 'normal';
11
+ let enableLog = true;
12
+ const positionalArgs = [];
13
+ for (const arg of args) {
14
+ switch (arg) {
15
+ case '--quiet':
16
+ verbosity = 'quiet';
17
+ break;
18
+ case '--normal':
19
+ verbosity = 'normal';
20
+ break;
21
+ case '--verbose':
22
+ verbosity = 'verbose';
23
+ break;
24
+ case '--no-log':
25
+ enableLog = false;
26
+ break;
27
+ default:
28
+ positionalArgs.push(arg);
29
+ }
30
+ }
31
+ return { positionalArgs, verbosity, enableLog };
32
+ }
33
+ /**
34
+ * Parse a command line into a prompt
35
+ * Used for script mode line parsing
36
+ */
37
+ export function parseCommandLine(line) {
38
+ const parts = line.trim().split(/\s+/);
39
+ const cmd = parts[0];
40
+ if (cmd === 'prompt') {
41
+ return { prompt: parts.slice(1).join(' ') };
42
+ }
43
+ else if (cmd === 'command') {
44
+ const cmdName = parts[1];
45
+ if (!cmdName) {
46
+ throw new Error('command requires a name');
47
+ }
48
+ return { prompt: loadCommandTemplate(cmdName, parts.slice(2)) };
49
+ }
50
+ else if (cmd === 'script') {
51
+ throw new Error('script cannot be nested');
52
+ }
53
+ else {
54
+ // Treat as raw prompt
55
+ return { prompt: line.trim() };
56
+ }
57
+ }
58
+ /**
59
+ * Parse CLI arguments
60
+ */
61
+ export function parseArgs(args) {
62
+ const { positionalArgs, verbosity, enableLog } = extractOptions(args);
63
+ const subcommand = (positionalArgs[0] ?? 'prompt');
64
+ let prompt = '';
65
+ let scriptMode = false;
66
+ let scriptLines = [];
67
+ switch (subcommand) {
68
+ case 'command': {
69
+ const commandName = positionalArgs[1];
70
+ if (!commandName) {
71
+ console.error('Error: command name required');
72
+ console.error('Usage: claude-code-runner command <name> [args...]');
73
+ process.exit(1);
74
+ }
75
+ prompt = loadCommandTemplate(commandName, positionalArgs.slice(2));
76
+ break;
77
+ }
78
+ case 'script': {
79
+ const scriptFile = positionalArgs[1];
80
+ if (!scriptFile) {
81
+ console.error('Error: script file required');
82
+ console.error('Usage: claude-code-runner script <file>');
83
+ process.exit(1);
84
+ }
85
+ if (!fs.existsSync(scriptFile)) {
86
+ console.error(`Error: script file not found: ${scriptFile}`);
87
+ process.exit(1);
88
+ }
89
+ scriptLines = fs
90
+ .readFileSync(scriptFile, 'utf-8')
91
+ .split('\n')
92
+ .map((l) => l.trim())
93
+ .filter((l) => l && !l.startsWith('#')); // Skip empty lines and comments
94
+ scriptMode = true;
95
+ break;
96
+ }
97
+ case 'prompt':
98
+ prompt =
99
+ positionalArgs.slice(1).join(' ') || 'Tell me about this project';
100
+ break;
101
+ }
102
+ const config = {
103
+ verbosity,
104
+ enableLog,
105
+ };
106
+ return {
107
+ subcommand: scriptMode ? 'script' : subcommand,
108
+ prompt,
109
+ scriptLines,
110
+ scriptMode,
111
+ config,
112
+ };
113
+ }
114
+ /**
115
+ * Print usage information
116
+ */
117
+ export function printUsage() {
118
+ console.log(`
119
+ Claude Code Runner - executes claude CLI with proper TTY handling
120
+
121
+ Usage:
122
+ claude-code-runner [options] prompt <prompt>
123
+ claude-code-runner [options] command <name> [args...]
124
+ claude-code-runner [options] script <file>
125
+
126
+ Subcommands:
127
+ prompt <text> Run with the given prompt (supports RUNNER signals)
128
+ command <name> [args] Load .claude/commands/<name>.md (supports RUNNER signals)
129
+ script <file> Run commands from file, stop on ERROR/BLOCKED
130
+
131
+ Iteration Status Signals (output by Claude to control loop):
132
+ :::RUNNER::DONE::: Exit successfully
133
+ :::RUNNER::CONTINUE::: Continue to next iteration
134
+ :::RUNNER::BLOCKED::: Exit with error (awaiting human intervention)
135
+ :::RUNNER::ERROR::: Exit with error (something went wrong)
136
+
137
+ Options:
138
+ --quiet Minimal output (errors only)
139
+ --normal Default output level
140
+ --verbose Full output with all details
141
+ --no-log Disable logging to file (enabled by default)
142
+ `);
143
+ }
144
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './args.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './args.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './runner.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './runner.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Core runner with iteration control and signal detection
3
+ */
4
+ import type { FormatterState } from '../output/formatter.js';
5
+ import type { Logger } from '../output/logger.js';
6
+ import type { RunnerConfig, SignalResult } from '../types/runner.js';
7
+ export interface RunnerContext {
8
+ config: RunnerConfig;
9
+ logger: Logger;
10
+ formatterState: FormatterState;
11
+ cwd: string;
12
+ }
13
+ /**
14
+ * Run a command with RUNNER signal support
15
+ * Handles iteration loop and signal detection
16
+ */
17
+ export declare function runWithSignals(promptText: string, startTime: number, context: RunnerContext): Promise<SignalResult>;
18
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAGlD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAErE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,cAAc,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CAoGvB"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Core runner with iteration control and signal detection
3
+ */
4
+ import { colors, formatDuration } from '../output/colors.js';
5
+ import { detectRunnerSignal } from '../parsers/signals.js';
6
+ import { spawnClaude } from '../process/pty.js';
7
+ /**
8
+ * Run a command with RUNNER signal support
9
+ * Handles iteration loop and signal detection
10
+ */
11
+ export async function runWithSignals(promptText, startTime, context) {
12
+ const { config, logger, formatterState, cwd } = context;
13
+ const { verbosity, maxIterations, parallelThresholdMs, iterationPauseMs } = config;
14
+ let iteration = 0;
15
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional infinite loop with internal exits
16
+ while (true) {
17
+ iteration++;
18
+ // Check max iterations
19
+ if (iteration > maxIterations) {
20
+ const totalDuration = Math.round((Date.now() - startTime) / 1000);
21
+ console.log('');
22
+ printSeparator();
23
+ console.log(`${colors.red}MAX ITERATIONS (${maxIterations})${colors.reset} | Total: ${formatDuration(totalDuration * 1000)}`);
24
+ printSeparator();
25
+ logger.log(`\nMAX ITERATIONS reached after ${maxIterations}`);
26
+ return 'error';
27
+ }
28
+ // Print iteration header for subsequent iterations
29
+ if (iteration > 1) {
30
+ console.log('');
31
+ printIterationHeader(iteration);
32
+ logger.log(`\n--- Iteration ${iteration} ---\n`);
33
+ }
34
+ // Run Claude
35
+ const { exitCode, duration, claudeText } = await spawnClaude({
36
+ prompt: promptText,
37
+ cwd,
38
+ verbosity,
39
+ logger,
40
+ formatterState,
41
+ parallelThresholdMs,
42
+ });
43
+ const status = detectRunnerSignal(claudeText);
44
+ const totalDuration = Math.round((Date.now() - startTime) / 1000);
45
+ console.log('');
46
+ printSeparator();
47
+ if (status === 'done') {
48
+ console.log(`${colors.green}COMPLETE${colors.reset} | Iterations: ${iteration} | Total: ${formatDuration(totalDuration * 1000)}`);
49
+ printSeparator();
50
+ logger.log(`\nCOMPLETE after ${iteration} iterations, ${totalDuration}s total`);
51
+ return 'ok';
52
+ }
53
+ else if (status === 'blocked') {
54
+ console.log(`${colors.red}BLOCKED${colors.reset} | Iterations: ${iteration} | Total: ${formatDuration(totalDuration * 1000)}`);
55
+ printSeparator();
56
+ logger.log(`\nBLOCKED after ${iteration} iterations, ${totalDuration}s total`);
57
+ return 'blocked';
58
+ }
59
+ else if (status === 'error') {
60
+ console.log(`${colors.red}ERROR${colors.reset} | Iterations: ${iteration} | Total: ${formatDuration(totalDuration * 1000)}`);
61
+ printSeparator();
62
+ logger.log(`\nERROR after ${iteration} iterations, ${totalDuration}s total`);
63
+ return 'error';
64
+ }
65
+ else if (status === 'continue') {
66
+ console.log(`${colors.yellow}CONTINUE${colors.reset} | Iteration ${iteration} done (${duration}s), continuing...`);
67
+ printSeparator();
68
+ logger.log(`Iteration ${iteration} complete, continuing...`);
69
+ await sleep(iterationPauseMs);
70
+ }
71
+ else {
72
+ // No status signal - treat as successful single run
73
+ const exitStatus = exitCode === 0 ? 'ok' : 'error';
74
+ if (iteration === 1) {
75
+ console.log(`Exit: ${exitCode === 0 ? colors.green : colors.red}${exitCode}${colors.reset} | Duration: ${duration}s`);
76
+ }
77
+ else {
78
+ console.log(`${exitCode === 0 ? colors.green + 'COMPLETE' : colors.red + 'FAILED'}${colors.reset} | Iterations: ${iteration} | Total: ${formatDuration(totalDuration * 1000)}`);
79
+ }
80
+ printSeparator();
81
+ logger.log(`\nCompleted after ${iteration} iteration(s), exit=${exitCode}`);
82
+ return exitStatus;
83
+ }
84
+ }
85
+ }
86
+ /**
87
+ * Print a separator line
88
+ */
89
+ function printSeparator() {
90
+ console.log(`${colors.bold}════════════════════════════════════════════════════════════${colors.reset}`);
91
+ }
92
+ /**
93
+ * Print iteration header
94
+ */
95
+ function printIterationHeader(iteration) {
96
+ console.log(`${colors.blue}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
97
+ console.log(`${colors.blue}Iteration ${iteration}${colors.reset}`);
98
+ console.log(`${colors.blue}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
99
+ console.log('');
100
+ }
101
+ /**
102
+ * Sleep for a given number of milliseconds
103
+ */
104
+ function sleep(ms) {
105
+ return new Promise((resolve) => setTimeout(resolve, ms));
106
+ }
107
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Claude Code Runner - executes claude CLI with proper TTY handling
4
+ * Shows intermediate tool calls and responses in real-time
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG"}
package/dist/index.js ADDED
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Claude Code Runner - executes claude CLI with proper TTY handling
4
+ * Shows intermediate tool calls and responses in real-time
5
+ */
6
+ import { parseArgs, parseCommandLine } from './cli/args.js';
7
+ import { runWithSignals } from './core/runner.js';
8
+ import { colors, formatDuration, truncate } from './output/colors.js';
9
+ import { createFormatterState } from './output/formatter.js';
10
+ import { createLogger } from './output/logger.js';
11
+ import { DEFAULT_CONFIG } from './types/runner.js';
12
+ async function main() {
13
+ const totalStart = Date.now();
14
+ const args = process.argv.slice(2);
15
+ const parsed = parseArgs(args);
16
+ // Merge config with defaults
17
+ const config = {
18
+ ...DEFAULT_CONFIG,
19
+ ...parsed.config,
20
+ };
21
+ // Create logger
22
+ const commandName = parsed.scriptMode
23
+ ? 'script'
24
+ : parsed.subcommand === 'command'
25
+ ? (args[1] ?? 'prompt')
26
+ : 'prompt';
27
+ const logger = createLogger(config.enableLog, config.logDir, commandName);
28
+ // Create formatter state
29
+ const formatterState = createFormatterState();
30
+ // Create runner context
31
+ const context = {
32
+ config,
33
+ logger,
34
+ formatterState,
35
+ cwd: process.cwd(),
36
+ };
37
+ // Print header
38
+ printHeader(parsed.subcommand, config.verbosity, logger.filePath);
39
+ logger.log(`Started: ${new Date().toISOString()}`);
40
+ if (parsed.scriptMode) {
41
+ // Script mode: run each line
42
+ await runScriptMode(parsed.scriptLines, context, totalStart);
43
+ }
44
+ else {
45
+ // Single command mode
46
+ await runSingleMode(parsed.prompt, context, totalStart);
47
+ }
48
+ }
49
+ /**
50
+ * Print runner header
51
+ */
52
+ function printHeader(mode, verbosity, logFile) {
53
+ console.log(`${colors.bold}════════════════════════════════════════════════════════════${colors.reset}`);
54
+ console.log(`${colors.bold}Claude Code Runner${colors.reset} ${colors.dim}(${verbosity}, ${mode})${colors.reset}`);
55
+ console.log(`${colors.bold}════════════════════════════════════════════════════════════${colors.reset}`);
56
+ if (logFile) {
57
+ console.log(`${colors.dim}Log:${colors.reset} ${logFile}`);
58
+ }
59
+ }
60
+ /**
61
+ * Run in single command mode (prompt or command)
62
+ */
63
+ async function runSingleMode(prompt, context, startTime) {
64
+ console.log(`${colors.dim}Prompt:${colors.reset} ${truncate(prompt, 80)}`);
65
+ console.log('');
66
+ context.logger.log(`Prompt: ${prompt}\n`);
67
+ const result = await runWithSignals(prompt, startTime, context);
68
+ context.logger.close();
69
+ process.exit(result === 'ok' ? 0 : 1);
70
+ }
71
+ /**
72
+ * Run in script mode
73
+ */
74
+ async function runScriptMode(scriptLines, context, startTime) {
75
+ console.log(`${colors.dim}Script:${colors.reset} ${scriptLines.length} commands`);
76
+ console.log('');
77
+ context.logger.log(`Script: ${scriptLines.length} commands\n`);
78
+ for (const [i, line] of scriptLines.entries()) {
79
+ printScriptStep(i + 1, scriptLines.length, line);
80
+ context.logger.log(`\n=== [${i + 1}/${scriptLines.length}] ${line} ===\n`);
81
+ let result;
82
+ try {
83
+ const parsed = parseCommandLine(line);
84
+ result = await runWithSignals(parsed.prompt, startTime, context);
85
+ }
86
+ catch (err) {
87
+ console.log(`${colors.red}PARSE ERROR:${colors.reset} ${err.message}`);
88
+ result = 'error';
89
+ }
90
+ if (result === 'blocked' || result === 'error') {
91
+ const totalDuration = Math.round((Date.now() - startTime) / 1000);
92
+ console.log('');
93
+ console.log(`${colors.bold}════════════════════════════════════════════════════════════${colors.reset}`);
94
+ console.log(`${colors.red}SCRIPT STOPPED${colors.reset} at step ${i + 1}/${scriptLines.length} | Total: ${formatDuration(totalDuration * 1000)}`);
95
+ console.log(`${colors.bold}════════════════════════════════════════════════════════════${colors.reset}`);
96
+ context.logger.log(`\nSCRIPT STOPPED at step ${i + 1}, ${totalDuration}s total`);
97
+ context.logger.close();
98
+ process.exit(1);
99
+ }
100
+ }
101
+ // All commands completed
102
+ const totalDuration = Math.round((Date.now() - startTime) / 1000);
103
+ console.log('');
104
+ console.log(`${colors.bold}════════════════════════════════════════════════════════════${colors.reset}`);
105
+ console.log(`${colors.green}SCRIPT COMPLETE${colors.reset} | ${scriptLines.length} commands | Total: ${formatDuration(totalDuration * 1000)}`);
106
+ console.log(`${colors.bold}════════════════════════════════════════════════════════════${colors.reset}`);
107
+ context.logger.log(`\nSCRIPT COMPLETE, ${scriptLines.length} commands, ${totalDuration}s total`);
108
+ context.logger.close();
109
+ process.exit(0);
110
+ }
111
+ /**
112
+ * Print script step header
113
+ */
114
+ function printScriptStep(current, total, line) {
115
+ console.log(`${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
116
+ console.log(`${colors.cyan}[${current}/${total}]${colors.reset} ${truncate(line, 60)}`);
117
+ console.log(`${colors.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
118
+ console.log('');
119
+ }
120
+ // Run main
121
+ main().catch((err) => {
122
+ console.error('Fatal error:', err);
123
+ process.exit(1);
124
+ });
125
+ //# sourceMappingURL=index.js.map