claude-yes 1.16.1 → 1.17.1
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 +5 -1
- package/ReadyManager.ts +18 -0
- package/cli.ts +2 -1
- package/dist/cli.js +65 -41
- package/dist/cli.js.map +6 -5
- package/dist/index.js +64 -40
- package/dist/index.js.map +5 -4
- package/index.ts +48 -45
- package/package.json +12 -11
package/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { TerminalTextRender } from 'terminal-render';
|
|
|
7
7
|
import { writeFile } from 'fs/promises';
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import { mkdir } from 'fs/promises';
|
|
10
|
+
import { ReadyManager } from './ReadyManager';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Main function to run Claude with automatic yes/no respojnses
|
|
@@ -23,9 +24,9 @@ import { mkdir } from 'fs/promises';
|
|
|
23
24
|
export default async function claudeYes({
|
|
24
25
|
claudeArgs = [],
|
|
25
26
|
continueOnCrash,
|
|
26
|
-
cwd
|
|
27
|
-
env
|
|
28
|
-
exitOnIdle,
|
|
27
|
+
cwd,
|
|
28
|
+
env,
|
|
29
|
+
exitOnIdle = 60e3,
|
|
29
30
|
logFile,
|
|
30
31
|
removeControlCharactersFromStdout = false, // = !process.stdout.isTTY,
|
|
31
32
|
verbose = false,
|
|
@@ -61,6 +62,7 @@ export default async function claudeYes({
|
|
|
61
62
|
const prefix = ''; // "YESC|"
|
|
62
63
|
const PREFIXLENGTH = prefix.length;
|
|
63
64
|
let errorNoConversation = false; // match 'No conversation found to continue'
|
|
65
|
+
const shellReady = new ReadyManager();
|
|
64
66
|
|
|
65
67
|
const shellOutputStream = new TransformStream<string, string>();
|
|
66
68
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
@@ -68,66 +70,66 @@ export default async function claudeYes({
|
|
|
68
70
|
|
|
69
71
|
// recommened to use bun pty in windows
|
|
70
72
|
const pty = process.versions.bun
|
|
71
|
-
? await import('bun-pty')
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
? await import('bun-pty').catch(() => {
|
|
74
|
+
throw new Error('Please install bun-pty');
|
|
75
|
+
})
|
|
76
|
+
: await import('node-pty').catch(() => {
|
|
77
|
+
throw new Error('Please install node-pty');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const getPtyOptions = () => ({
|
|
74
81
|
name: 'xterm-color',
|
|
75
82
|
cols: process.stdout.columns - PREFIXLENGTH,
|
|
76
83
|
rows: process.stdout.rows,
|
|
77
|
-
cwd,
|
|
78
|
-
env,
|
|
84
|
+
cwd: cwd ?? process.cwd(),
|
|
85
|
+
env: env ?? (process.env as Record<string, string>),
|
|
79
86
|
});
|
|
87
|
+
let shell = pty.spawn('claude', claudeArgs, getPtyOptions());
|
|
80
88
|
let pendingExitCode = Promise.withResolvers<number | null>();
|
|
89
|
+
let pendingExitCodeValue = null;
|
|
90
|
+
|
|
81
91
|
// TODO handle error if claude is not installed, show msg:
|
|
82
92
|
// npm install -g @anthropic-ai/claude-code
|
|
83
93
|
|
|
84
94
|
async function onData(data: string) {
|
|
85
95
|
// append data to the buffer, so we can process it later
|
|
86
96
|
await outputWriter.write(data);
|
|
97
|
+
shellReady.ready(); // shell has output, also means ready for stdin
|
|
87
98
|
}
|
|
99
|
+
|
|
88
100
|
shell.onData(onData);
|
|
89
|
-
// when claude process exits, exit the main process with the same exit code
|
|
90
101
|
shell.onExit(function onExit({ exitCode }) {
|
|
91
|
-
|
|
102
|
+
shellReady.unready(); // start buffer stdin
|
|
103
|
+
const claudeCrashed = exitCode !== 0;
|
|
104
|
+
if (claudeCrashed && continueOnCrash) {
|
|
92
105
|
if (errorNoConversation) {
|
|
93
106
|
console.log(
|
|
94
107
|
'Claude crashed with "No conversation found to continue", exiting...'
|
|
95
108
|
);
|
|
96
|
-
return pendingExitCode.resolve(exitCode);
|
|
109
|
+
return pendingExitCode.resolve((pendingExitCodeValue = exitCode));
|
|
97
110
|
}
|
|
98
111
|
console.log('Claude crashed, restarting...');
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
cols: process.stdout.columns - PREFIXLENGTH,
|
|
102
|
-
rows: process.stdout.rows,
|
|
103
|
-
cwd,
|
|
104
|
-
env,
|
|
105
|
-
});
|
|
112
|
+
|
|
113
|
+
shell = pty.spawn('claude', ['--continue', 'continue'], getPtyOptions());
|
|
106
114
|
shell.onData(onData);
|
|
107
115
|
shell.onExit(onExit);
|
|
108
116
|
return;
|
|
109
117
|
}
|
|
110
|
-
return pendingExitCode.resolve(exitCode);
|
|
118
|
+
return pendingExitCode.resolve((pendingExitCodeValue = exitCode));
|
|
111
119
|
});
|
|
112
120
|
|
|
113
121
|
const exitClaudeCode = async () => {
|
|
122
|
+
continueOnCrash = false;
|
|
114
123
|
// send exit command to the shell, must sleep a bit to avoid claude treat it as pasted input
|
|
115
124
|
await sflow(['\r', '/exit', '\r'])
|
|
116
|
-
.forEach(async (
|
|
117
|
-
|
|
118
|
-
shell.write(e);
|
|
119
|
-
})
|
|
125
|
+
.forEach(async () => await sleepms(200))
|
|
126
|
+
.forEach(async (e) => shell.write(e))
|
|
120
127
|
.run();
|
|
121
128
|
|
|
122
129
|
// wait for shell to exit or kill it with a timeout
|
|
123
130
|
let exited = false;
|
|
124
131
|
await Promise.race([
|
|
125
|
-
|
|
126
|
-
shell.onExit(() => {
|
|
127
|
-
resolve();
|
|
128
|
-
exited = true;
|
|
129
|
-
})
|
|
130
|
-
), // resolve when shell exits
|
|
132
|
+
pendingExitCode.promise.then(() => (exited = true)), // resolve when shell exits
|
|
131
133
|
// if shell doesn't exit in 5 seconds, kill it
|
|
132
134
|
new Promise<void>((resolve) =>
|
|
133
135
|
setTimeout(() => {
|
|
@@ -145,20 +147,12 @@ export default async function claudeYes({
|
|
|
145
147
|
shell.resize(columns - PREFIXLENGTH, rows);
|
|
146
148
|
});
|
|
147
149
|
|
|
148
|
-
const
|
|
149
|
-
writable: new WritableStream<string>({
|
|
150
|
-
write: (data) => shell.write(data),
|
|
151
|
-
close: () => {},
|
|
152
|
-
}),
|
|
153
|
-
readable: shellOutputStream.readable,
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const ttr = new TerminalTextRender();
|
|
150
|
+
const render = new TerminalTextRender();
|
|
157
151
|
const idleWatcher = !exitOnIdle
|
|
158
152
|
? null
|
|
159
153
|
: createIdleWatcher(async () => {
|
|
160
154
|
if (
|
|
161
|
-
|
|
155
|
+
render
|
|
162
156
|
.render()
|
|
163
157
|
.replace(/\s+/g, ' ')
|
|
164
158
|
.match(/esc to interrupt|to run in background/)
|
|
@@ -179,9 +173,18 @@ export default async function claudeYes({
|
|
|
179
173
|
sflow(fromReadable<Buffer>(process.stdin))
|
|
180
174
|
.map((buffer) => buffer.toString())
|
|
181
175
|
// .forEach(e => appendFile('.cache/io.log', "input |" + JSON.stringify(e) + '\n')) // for debugging
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
176
|
+
// pipe
|
|
177
|
+
.by({
|
|
178
|
+
writable: new WritableStream<string>({
|
|
179
|
+
write: async (data) => {
|
|
180
|
+
await shellReady.wait();
|
|
181
|
+
shell.write(data);
|
|
182
|
+
},
|
|
183
|
+
}),
|
|
184
|
+
readable: shellOutputStream.readable,
|
|
185
|
+
})
|
|
186
|
+
// handle terminal render
|
|
187
|
+
.forEach((text) => render.write(text))
|
|
185
188
|
|
|
186
189
|
// handle idle
|
|
187
190
|
.forEach(() => idleWatcher?.ping()) // ping the idle watcher on output for last active time to keep track of claude status
|
|
@@ -209,7 +212,7 @@ export default async function claudeYes({
|
|
|
209
212
|
.to(fromWritable(process.stdout));
|
|
210
213
|
|
|
211
214
|
const exitCode = await pendingExitCode.promise; // wait for the shell to exit
|
|
212
|
-
|
|
215
|
+
console.log(`[claude-yes] claude exited with code ${exitCode}`);
|
|
213
216
|
|
|
214
217
|
if (logFile) {
|
|
215
218
|
verbose && console.log(`[claude-yes] Writing rendered logs to ${logFile}`);
|
|
@@ -217,10 +220,10 @@ export default async function claudeYes({
|
|
|
217
220
|
await mkdir(path.dirname(logFilePath), { recursive: true }).catch(
|
|
218
221
|
() => null
|
|
219
222
|
);
|
|
220
|
-
await writeFile(logFilePath,
|
|
223
|
+
await writeFile(logFilePath, render.render());
|
|
221
224
|
}
|
|
222
225
|
|
|
223
|
-
return { exitCode, logs:
|
|
226
|
+
return { exitCode, logs: render.render() };
|
|
224
227
|
}
|
|
225
228
|
|
|
226
229
|
export { removeControlCharacters };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-yes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.1",
|
|
4
4
|
"description": "A wrapper tool that automates interactions with the Claude CLI by automatically handling common prompts and responses.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"import": "./dist/index.js",
|
|
28
28
|
"types": "./index.ts"
|
|
29
29
|
},
|
|
30
|
-
"main": "index.js",
|
|
30
|
+
"main": "dist/index.js",
|
|
31
31
|
"module": "index.ts",
|
|
32
32
|
"types": "./index.ts",
|
|
33
33
|
"bin": {
|
|
@@ -52,30 +52,31 @@
|
|
|
52
52
|
"prettier --write"
|
|
53
53
|
]
|
|
54
54
|
},
|
|
55
|
-
"dependencies": {
|
|
56
|
-
"bun-pty": "^0.3.2",
|
|
57
|
-
"node-pty": "^1.0.0"
|
|
58
|
-
},
|
|
59
55
|
"devDependencies": {
|
|
60
|
-
"terminal-render": "^1.1.0",
|
|
61
|
-
"yargs": "^18.0.0",
|
|
62
56
|
"@types/bun": "^1.2.18",
|
|
63
57
|
"@types/jest": "^30.0.0",
|
|
64
58
|
"@types/node": "^24.0.10",
|
|
65
59
|
"@types/yargs": "^17.0.33",
|
|
66
|
-
"sflow": "^1.20.2",
|
|
67
60
|
"enhanced-ms": "^4.1.0",
|
|
68
61
|
"execa": "^9.6.0",
|
|
69
62
|
"from-node-stream": "^0.0.11",
|
|
70
63
|
"husky": "^9.1.7",
|
|
71
64
|
"lint-staged": "^16.1.4",
|
|
72
65
|
"prettier": "^3.6.2",
|
|
66
|
+
"rambda": "^10.3.2",
|
|
73
67
|
"semantic-release": "^24.2.6",
|
|
68
|
+
"sflow": "^1.20.2",
|
|
74
69
|
"strip-ansi-control-characters": "^2.0.0",
|
|
70
|
+
"terminal-render": "^1.1.0",
|
|
75
71
|
"tsx": "^4.20.3",
|
|
76
|
-
"vitest": "^3.2.4"
|
|
72
|
+
"vitest": "^3.2.4",
|
|
73
|
+
"yargs": "^18.0.0"
|
|
77
74
|
},
|
|
78
75
|
"peerDependencies": {
|
|
79
|
-
"typescript": "^5.8.3"
|
|
76
|
+
"typescript": "^5.8.3",
|
|
77
|
+
"node-pty": "^1.0.0"
|
|
78
|
+
},
|
|
79
|
+
"dependencies": {
|
|
80
|
+
"bun-pty": "^0.3.2"
|
|
80
81
|
}
|
|
81
82
|
}
|