claude-yes 1.14.2 → 1.15.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/cli-idle.spec.ts +17 -0
- package/cli.test.ts +50 -67
- package/cli.ts +41 -41
- package/createIdleWatcher.ts +18 -16
- package/dist/cli.js +5380 -264
- package/dist/index.js +41 -21
- package/index.ts +60 -38
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -4832,14 +4832,13 @@ function createIdleWatcher(onIdle, idleTimeout) {
|
|
|
4832
4832
|
let idleTimeoutId = null;
|
|
4833
4833
|
return {
|
|
4834
4834
|
ping: () => {
|
|
4835
|
-
if (idleTimeoutId)
|
|
4835
|
+
if (idleTimeoutId)
|
|
4836
4836
|
clearTimeout(idleTimeoutId);
|
|
4837
|
-
|
|
4837
|
+
lastActiveTime = new Date;
|
|
4838
4838
|
idleTimeoutId = setTimeout(() => {
|
|
4839
4839
|
clearTimeout(idleTimeoutId);
|
|
4840
4840
|
onIdle();
|
|
4841
4841
|
}, idleTimeout);
|
|
4842
|
-
lastActiveTime = new Date;
|
|
4843
4842
|
},
|
|
4844
4843
|
getLastActiveTime: () => lastActiveTime
|
|
4845
4844
|
};
|
|
@@ -5088,15 +5087,29 @@ class TerminalTextRender {
|
|
|
5088
5087
|
}
|
|
5089
5088
|
|
|
5090
5089
|
// index.ts
|
|
5090
|
+
import { writeFile } from "fs/promises";
|
|
5091
|
+
import path2 from "path";
|
|
5092
|
+
import { mkdir } from "fs/promises";
|
|
5091
5093
|
async function claudeYes({
|
|
5092
5094
|
continueOnCrash,
|
|
5093
5095
|
exitOnIdle,
|
|
5094
5096
|
claudeArgs = [],
|
|
5095
5097
|
cwd = process.cwd(),
|
|
5096
|
-
removeControlCharactersFromStdout = false
|
|
5098
|
+
removeControlCharactersFromStdout = false,
|
|
5099
|
+
logFile,
|
|
5100
|
+
verbose = false
|
|
5097
5101
|
} = {}) {
|
|
5098
|
-
|
|
5099
|
-
|
|
5102
|
+
if (verbose) {
|
|
5103
|
+
console.log("calling claudeYes: ", {
|
|
5104
|
+
continueOnCrash,
|
|
5105
|
+
exitOnIdle,
|
|
5106
|
+
claudeArgs,
|
|
5107
|
+
cwd,
|
|
5108
|
+
removeControlCharactersFromStdout,
|
|
5109
|
+
logFile,
|
|
5110
|
+
verbose
|
|
5111
|
+
});
|
|
5112
|
+
}
|
|
5100
5113
|
console.log("⭐ Starting claude, automatically responding to yes/no prompts...");
|
|
5101
5114
|
console.log("⚠️ Important Security Warning: Only run this on trusted repositories. This tool automatically responds to prompts and can execute commands without user confirmation. Be aware of potential prompt injection attacks where malicious code or instructions could be embedded in files or user inputs to manipulate the automated responses.");
|
|
5102
5115
|
process.stdin.setRawMode?.(true);
|
|
@@ -5113,15 +5126,16 @@ async function claudeYes({
|
|
|
5113
5126
|
cwd,
|
|
5114
5127
|
env: process.env
|
|
5115
5128
|
});
|
|
5129
|
+
let pendingExitCode = Promise.withResolvers();
|
|
5116
5130
|
async function onData(data) {
|
|
5117
5131
|
await outputWriter.write(data);
|
|
5118
5132
|
}
|
|
5119
5133
|
shell.onData(onData);
|
|
5120
|
-
shell.onExit(function onExit({ exitCode }) {
|
|
5121
|
-
if (continueOnCrash &&
|
|
5134
|
+
shell.onExit(function onExit({ exitCode: exitCode2 }) {
|
|
5135
|
+
if (continueOnCrash && exitCode2 !== 0) {
|
|
5122
5136
|
if (errorNoConversation) {
|
|
5123
5137
|
console.log('Claude crashed with "No conversation found to continue", exiting...');
|
|
5124
|
-
|
|
5138
|
+
return pendingExitCode.resolve(exitCode2);
|
|
5125
5139
|
}
|
|
5126
5140
|
console.log("Claude crashed, restarting...");
|
|
5127
5141
|
shell = pty.spawn("claude", ["continue", "--continue"], {
|
|
@@ -5135,7 +5149,7 @@ async function claudeYes({
|
|
|
5135
5149
|
shell.onExit(onExit);
|
|
5136
5150
|
return;
|
|
5137
5151
|
}
|
|
5138
|
-
|
|
5152
|
+
return pendingExitCode.resolve(exitCode2);
|
|
5139
5153
|
});
|
|
5140
5154
|
const exitClaudeCode = async () => {
|
|
5141
5155
|
await src_default(["\r", "/exit", "\r"]).forEach(async (e) => {
|
|
@@ -5168,21 +5182,19 @@ async function claudeYes({
|
|
|
5168
5182
|
readable: shellOutputStream.readable
|
|
5169
5183
|
};
|
|
5170
5184
|
const ttr = new TerminalTextRender;
|
|
5171
|
-
const idleWatcher = createIdleWatcher(async () => {
|
|
5172
|
-
if (
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
await exitClaudeCode();
|
|
5178
|
-
}
|
|
5185
|
+
const idleWatcher = !exitOnIdle ? null : createIdleWatcher(async () => {
|
|
5186
|
+
if (ttr.render().replace(/\s+/g, " ").match(/esc to interrupt|to run in background/)) {
|
|
5187
|
+
console.log("[claude-yes] Claude is idle, but seems still working, not exiting yet");
|
|
5188
|
+
} else {
|
|
5189
|
+
console.log("[claude-yes] Claude is idle, exiting...");
|
|
5190
|
+
await exitClaudeCode();
|
|
5179
5191
|
}
|
|
5180
|
-
},
|
|
5192
|
+
}, exitOnIdle);
|
|
5181
5193
|
const confirm = async () => {
|
|
5182
5194
|
await sleepms(200);
|
|
5183
5195
|
shell.write("\r");
|
|
5184
5196
|
};
|
|
5185
|
-
|
|
5197
|
+
src_default(fromReadable(process.stdin)).map((buffer2) => buffer2.toString()).by(shellStdio).forEach((text) => ttr.write(text)).forEach(() => idleWatcher?.ping()).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).forEach(async (e2) => {
|
|
5186
5198
|
if (e2.match(/❯ 1. Yes/))
|
|
5187
5199
|
return await confirm();
|
|
5188
5200
|
if (e2.match(/❯ 1. Dark mode✔|Press Enter to continue…/))
|
|
@@ -5192,7 +5204,15 @@ async function claudeYes({
|
|
|
5192
5204
|
return;
|
|
5193
5205
|
}
|
|
5194
5206
|
}).run()).replaceAll(/.*(?:\r\n?|\r?\n)/g, (line) => prefix + line).map((e) => removeControlCharactersFromStdout ? removeControlCharacters(e) : e).to(fromWritable(process.stdout));
|
|
5195
|
-
|
|
5207
|
+
const exitCode = await pendingExitCode.promise;
|
|
5208
|
+
verbose && console.log(`[claude-yes] claude exited with code ${exitCode}`);
|
|
5209
|
+
if (logFile) {
|
|
5210
|
+
verbose && console.log(`[claude-yes] Writing rendered logs to ${logFile}`);
|
|
5211
|
+
const logFilePath = path2.resolve(logFile);
|
|
5212
|
+
await mkdir(path2.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
5213
|
+
await writeFile(logFilePath, ttr.render());
|
|
5214
|
+
}
|
|
5215
|
+
return { exitCode, logs: ttr.render() };
|
|
5196
5216
|
}
|
|
5197
5217
|
export {
|
|
5198
5218
|
removeControlCharacters,
|
package/index.ts
CHANGED
|
@@ -4,15 +4,9 @@ import { createIdleWatcher } from './createIdleWatcher';
|
|
|
4
4
|
import { removeControlCharacters } from './removeControlCharacters';
|
|
5
5
|
import { sleepms } from './utils';
|
|
6
6
|
import { TerminalTextRender } from 'terminal-render';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// await claudeYes({
|
|
11
|
-
// continueOnCrash: true,
|
|
12
|
-
// exitOnIdle: 10000,
|
|
13
|
-
// claudeArgs: ["say hello and exit"]
|
|
14
|
-
// })
|
|
15
|
-
// }
|
|
7
|
+
import { writeFile } from 'fs/promises';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import { mkdir } from 'fs/promises';
|
|
16
10
|
|
|
17
11
|
/**
|
|
18
12
|
* Main function to run Claude with automatic yes/no respojnses
|
|
@@ -33,17 +27,28 @@ export default async function claudeYes({
|
|
|
33
27
|
cwd = process.cwd(),
|
|
34
28
|
// removeControlCharactersFromStdout = !process.stdout.isTTY,
|
|
35
29
|
removeControlCharactersFromStdout = false,
|
|
30
|
+
logFile,
|
|
31
|
+
verbose = false,
|
|
36
32
|
}: {
|
|
37
33
|
continueOnCrash?: boolean;
|
|
38
|
-
exitOnIdle?:
|
|
34
|
+
exitOnIdle?: number;
|
|
39
35
|
claudeArgs?: string[];
|
|
40
36
|
cwd?: string;
|
|
41
37
|
removeControlCharactersFromStdout?: boolean;
|
|
38
|
+
logFile?: string;
|
|
39
|
+
verbose?: boolean;
|
|
42
40
|
} = {}) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
if (verbose) {
|
|
42
|
+
console.log('calling claudeYes: ', {
|
|
43
|
+
continueOnCrash,
|
|
44
|
+
exitOnIdle,
|
|
45
|
+
claudeArgs,
|
|
46
|
+
cwd,
|
|
47
|
+
removeControlCharactersFromStdout,
|
|
48
|
+
logFile,
|
|
49
|
+
verbose,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
47
52
|
console.log(
|
|
48
53
|
'⭐ Starting claude, automatically responding to yes/no prompts...'
|
|
49
54
|
);
|
|
@@ -68,6 +73,7 @@ export default async function claudeYes({
|
|
|
68
73
|
cwd,
|
|
69
74
|
env: process.env as Record<string, string>,
|
|
70
75
|
});
|
|
76
|
+
let pendingExitCode = Promise.withResolvers<number | null>();
|
|
71
77
|
// TODO handle error if claude is not installed, show msg:
|
|
72
78
|
// npm install -g @anthropic-ai/claude-code
|
|
73
79
|
|
|
@@ -83,7 +89,7 @@ export default async function claudeYes({
|
|
|
83
89
|
console.log(
|
|
84
90
|
'Claude crashed with "No conversation found to continue", exiting...'
|
|
85
91
|
);
|
|
86
|
-
|
|
92
|
+
return pendingExitCode.resolve(exitCode);
|
|
87
93
|
}
|
|
88
94
|
console.log('Claude crashed, restarting...');
|
|
89
95
|
shell = pty.spawn('claude', ['continue', '--continue'], {
|
|
@@ -97,7 +103,7 @@ export default async function claudeYes({
|
|
|
97
103
|
shell.onExit(onExit);
|
|
98
104
|
return;
|
|
99
105
|
}
|
|
100
|
-
|
|
106
|
+
return pendingExitCode.resolve(exitCode);
|
|
101
107
|
});
|
|
102
108
|
|
|
103
109
|
const exitClaudeCode = async () => {
|
|
@@ -144,33 +150,38 @@ export default async function claudeYes({
|
|
|
144
150
|
};
|
|
145
151
|
|
|
146
152
|
const ttr = new TerminalTextRender();
|
|
147
|
-
const idleWatcher =
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
153
|
+
const idleWatcher = !exitOnIdle
|
|
154
|
+
? null
|
|
155
|
+
: createIdleWatcher(async () => {
|
|
156
|
+
if (
|
|
157
|
+
ttr
|
|
158
|
+
.render()
|
|
159
|
+
.replace(/\s+/g, ' ')
|
|
160
|
+
.match(/esc to interrupt|to run in background/)
|
|
161
|
+
) {
|
|
162
|
+
console.log(
|
|
163
|
+
'[claude-yes] Claude is idle, but seems still working, not exiting yet'
|
|
164
|
+
);
|
|
165
|
+
} else {
|
|
166
|
+
console.log('[claude-yes] Claude is idle, exiting...');
|
|
167
|
+
await exitClaudeCode();
|
|
168
|
+
}
|
|
169
|
+
}, exitOnIdle);
|
|
164
170
|
const confirm = async () => {
|
|
165
171
|
await sleepms(200);
|
|
166
172
|
shell.write('\r');
|
|
167
173
|
};
|
|
168
|
-
|
|
169
|
-
|
|
174
|
+
|
|
175
|
+
sflow(fromReadable<Buffer>(process.stdin))
|
|
170
176
|
.map((buffer) => buffer.toString())
|
|
171
|
-
.forEach((text) => ttr.write(text))
|
|
172
177
|
// .forEach(e => appendFile('.cache/io.log', "input |" + JSON.stringify(e) + '\n')) // for debugging
|
|
173
178
|
.by(shellStdio)
|
|
179
|
+
// handle ttr render
|
|
180
|
+
.forEach((text) => ttr.write(text))
|
|
181
|
+
|
|
182
|
+
// handle idle
|
|
183
|
+
.forEach(() => idleWatcher?.ping()) // ping the idle watcher on output for last active time to keep track of claude status
|
|
184
|
+
// auto-response
|
|
174
185
|
.forkTo((e) =>
|
|
175
186
|
e
|
|
176
187
|
.map((e) => removeControlCharacters(e as string))
|
|
@@ -184,7 +195,6 @@ export default async function claudeYes({
|
|
|
184
195
|
return;
|
|
185
196
|
}
|
|
186
197
|
})
|
|
187
|
-
|
|
188
198
|
// .forEach(e => appendFile('.cache/io.log', "output|" + JSON.stringify(e) + '\n')) // for debugging
|
|
189
199
|
.run()
|
|
190
200
|
)
|
|
@@ -194,7 +204,19 @@ export default async function claudeYes({
|
|
|
194
204
|
)
|
|
195
205
|
.to(fromWritable(process.stdout));
|
|
196
206
|
|
|
197
|
-
|
|
207
|
+
const exitCode = await pendingExitCode.promise; // wait for the shell to exit
|
|
208
|
+
verbose && console.log(`[claude-yes] claude exited with code ${exitCode}`);
|
|
209
|
+
|
|
210
|
+
if (logFile) {
|
|
211
|
+
verbose && console.log(`[claude-yes] Writing rendered logs to ${logFile}`);
|
|
212
|
+
const logFilePath = path.resolve(logFile);
|
|
213
|
+
await mkdir(path.dirname(logFilePath), { recursive: true }).catch(
|
|
214
|
+
() => null
|
|
215
|
+
);
|
|
216
|
+
await writeFile(logFilePath, ttr.render());
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return { exitCode, logs: ttr.render() };
|
|
198
220
|
}
|
|
199
221
|
|
|
200
222
|
export { removeControlCharacters };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-yes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.1",
|
|
4
4
|
"homepage": "https://github.com/snomiao/claude-yes#readme",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "snomiao <snomiao@gmail.com>",
|
|
@@ -35,14 +35,13 @@
|
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/bun": "^1.2.18",
|
|
37
37
|
"@types/jest": "^30.0.0",
|
|
38
|
-
"@types/minimist": "^1.2.5",
|
|
39
38
|
"@types/node": "^24.0.10",
|
|
39
|
+
"@types/yargs": "^17.0.33",
|
|
40
40
|
"enhanced-ms": "^4.1.0",
|
|
41
41
|
"execa": "^9.6.0",
|
|
42
42
|
"from-node-stream": "^0.0.11",
|
|
43
43
|
"husky": "^9.1.7",
|
|
44
44
|
"lint-staged": "^16.1.4",
|
|
45
|
-
"minimist": "^1.2.8",
|
|
46
45
|
"prettier": "^3.6.2",
|
|
47
46
|
"semantic-release": "^24.2.6",
|
|
48
47
|
"sflow": "^1.20.2",
|
|
@@ -63,7 +62,8 @@
|
|
|
63
62
|
"dependencies": {
|
|
64
63
|
"bun-pty": "^0.3.2",
|
|
65
64
|
"node-pty": "^1.0.0",
|
|
66
|
-
"terminal-render": "^1.1.0"
|
|
65
|
+
"terminal-render": "^1.1.0",
|
|
66
|
+
"yargs": "^18.0.0"
|
|
67
67
|
},
|
|
68
68
|
"lint-staged": {
|
|
69
69
|
"*.{ts,js,json,md}": [
|