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/README.md
CHANGED
|
@@ -8,7 +8,8 @@ A wrapper tool that automates interactions with the Claude CLI by automatically
|
|
|
8
8
|
|
|
9
9
|
- Same as `claude` command
|
|
10
10
|
- Automatically responds to common prompts like "Yes, proceed" and "Yes"
|
|
11
|
-
- So, this will Let claude run until your task done, and wait for your next prompt.
|
|
11
|
+
- So, this will Let claude keep run until your task done, and wait for your next prompt.
|
|
12
|
+
- You can still Queue More Prompts or Cancel executing task by `ESC` or `Ctrl+C`
|
|
12
13
|
|
|
13
14
|
## Prerequirements
|
|
14
15
|
|
|
@@ -40,6 +41,9 @@ bunx claude-yes "Solve TODO.md"
|
|
|
40
41
|
|
|
41
42
|
# Auto-exit when Claude becomes idle (useful for automation scripts)
|
|
42
43
|
claude-yes --exit-on-idle=60s "run all tests and commit current changes"
|
|
44
|
+
|
|
45
|
+
# Alternative: use with claude-code-execute
|
|
46
|
+
claude-code-execute claude-yes "your task here"
|
|
43
47
|
```
|
|
44
48
|
|
|
45
49
|
The tool will:
|
package/ReadyManager.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export class ReadyManager {
|
|
2
|
+
private isReady = false;
|
|
3
|
+
private readyQueue: (() => void)[] = [];
|
|
4
|
+
wait() {
|
|
5
|
+
return new Promise<void>((resolve) => {
|
|
6
|
+
if (this.isReady) return resolve();
|
|
7
|
+
this.readyQueue.push(resolve);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
unready() {
|
|
11
|
+
this.isReady = false;
|
|
12
|
+
}
|
|
13
|
+
ready() {
|
|
14
|
+
this.isReady = true;
|
|
15
|
+
if (!this.readyQueue.length) return; // check len for performance
|
|
16
|
+
this.readyQueue.splice(0).map((resolve) => resolve());
|
|
17
|
+
}
|
|
18
|
+
}
|
package/cli.ts
CHANGED
|
@@ -14,7 +14,8 @@ const argv = yargs(hideBin(process.argv))
|
|
|
14
14
|
.option('exit-on-idle', {
|
|
15
15
|
type: 'string',
|
|
16
16
|
default: '60s',
|
|
17
|
-
description:
|
|
17
|
+
description:
|
|
18
|
+
'Exit after being idle for specified duration, default 1min, set to 0 to disable this behaviour',
|
|
18
19
|
})
|
|
19
20
|
.option('continue-on-crash', {
|
|
20
21
|
type: 'boolean',
|
package/dist/cli.js
CHANGED
|
@@ -141,7 +141,7 @@ class PolyfillTextEncoderStream {
|
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
// node_modules/rambda/dist/rambda.js
|
|
144
|
+
// node_modules/sflow/node_modules/rambda/dist/rambda.js
|
|
145
145
|
var cloneList = (list) => Array.prototype.slice.call(list);
|
|
146
146
|
function curry(fn, args = []) {
|
|
147
147
|
return (..._args) => ((rest) => rest.length >= fn.length ? fn(...rest) : curry(fn, rest))([...args, ..._args]);
|
|
@@ -5119,12 +5119,36 @@ class TerminalTextRender {
|
|
|
5119
5119
|
import { writeFile } from "fs/promises";
|
|
5120
5120
|
import path2 from "path";
|
|
5121
5121
|
import { mkdir } from "fs/promises";
|
|
5122
|
+
|
|
5123
|
+
// ReadyManager.ts
|
|
5124
|
+
class ReadyManager {
|
|
5125
|
+
isReady = false;
|
|
5126
|
+
readyQueue = [];
|
|
5127
|
+
wait() {
|
|
5128
|
+
return new Promise((resolve) => {
|
|
5129
|
+
if (this.isReady)
|
|
5130
|
+
return resolve();
|
|
5131
|
+
this.readyQueue.push(resolve);
|
|
5132
|
+
});
|
|
5133
|
+
}
|
|
5134
|
+
unready() {
|
|
5135
|
+
this.isReady = false;
|
|
5136
|
+
}
|
|
5137
|
+
ready() {
|
|
5138
|
+
this.isReady = true;
|
|
5139
|
+
if (!this.readyQueue.length)
|
|
5140
|
+
return;
|
|
5141
|
+
this.readyQueue.splice(0).map((resolve) => resolve());
|
|
5142
|
+
}
|
|
5143
|
+
}
|
|
5144
|
+
|
|
5145
|
+
// index.ts
|
|
5122
5146
|
async function claudeYes({
|
|
5123
5147
|
claudeArgs = [],
|
|
5124
5148
|
continueOnCrash,
|
|
5125
|
-
cwd
|
|
5126
|
-
env
|
|
5127
|
-
exitOnIdle,
|
|
5149
|
+
cwd,
|
|
5150
|
+
env,
|
|
5151
|
+
exitOnIdle = 60000,
|
|
5128
5152
|
logFile,
|
|
5129
5153
|
removeControlCharactersFromStdout = false,
|
|
5130
5154
|
verbose = false
|
|
@@ -5146,52 +5170,51 @@ async function claudeYes({
|
|
|
5146
5170
|
const prefix = "";
|
|
5147
5171
|
const PREFIXLENGTH = prefix.length;
|
|
5148
5172
|
let errorNoConversation = false;
|
|
5173
|
+
const shellReady = new ReadyManager;
|
|
5149
5174
|
const shellOutputStream = new TransformStream;
|
|
5150
5175
|
const outputWriter = shellOutputStream.writable.getWriter();
|
|
5151
|
-
const pty = process.versions.bun ? await import("bun-pty")
|
|
5152
|
-
|
|
5176
|
+
const pty = process.versions.bun ? await import("bun-pty").catch(() => {
|
|
5177
|
+
throw new Error("Please install bun-pty");
|
|
5178
|
+
}) : await import("node-pty").catch(() => {
|
|
5179
|
+
throw new Error("Please install node-pty");
|
|
5180
|
+
});
|
|
5181
|
+
const getPtyOptions = () => ({
|
|
5153
5182
|
name: "xterm-color",
|
|
5154
5183
|
cols: process.stdout.columns - PREFIXLENGTH,
|
|
5155
5184
|
rows: process.stdout.rows,
|
|
5156
|
-
cwd,
|
|
5157
|
-
env
|
|
5185
|
+
cwd: cwd ?? process.cwd(),
|
|
5186
|
+
env: env ?? process.env
|
|
5158
5187
|
});
|
|
5188
|
+
let shell = pty.spawn("claude", claudeArgs, getPtyOptions());
|
|
5159
5189
|
let pendingExitCode = Promise.withResolvers();
|
|
5190
|
+
let pendingExitCodeValue = null;
|
|
5160
5191
|
async function onData(data) {
|
|
5161
5192
|
await outputWriter.write(data);
|
|
5193
|
+
shellReady.ready();
|
|
5162
5194
|
}
|
|
5163
5195
|
shell.onData(onData);
|
|
5164
5196
|
shell.onExit(function onExit({ exitCode: exitCode2 }) {
|
|
5165
|
-
|
|
5197
|
+
shellReady.unready();
|
|
5198
|
+
const claudeCrashed = exitCode2 !== 0;
|
|
5199
|
+
if (claudeCrashed && continueOnCrash) {
|
|
5166
5200
|
if (errorNoConversation) {
|
|
5167
5201
|
console.log('Claude crashed with "No conversation found to continue", exiting...');
|
|
5168
|
-
return pendingExitCode.resolve(exitCode2);
|
|
5202
|
+
return pendingExitCode.resolve(pendingExitCodeValue = exitCode2);
|
|
5169
5203
|
}
|
|
5170
5204
|
console.log("Claude crashed, restarting...");
|
|
5171
|
-
shell = pty.spawn("claude", ["--continue", "continue"],
|
|
5172
|
-
name: "xterm-color",
|
|
5173
|
-
cols: process.stdout.columns - PREFIXLENGTH,
|
|
5174
|
-
rows: process.stdout.rows,
|
|
5175
|
-
cwd,
|
|
5176
|
-
env
|
|
5177
|
-
});
|
|
5205
|
+
shell = pty.spawn("claude", ["--continue", "continue"], getPtyOptions());
|
|
5178
5206
|
shell.onData(onData);
|
|
5179
5207
|
shell.onExit(onExit);
|
|
5180
5208
|
return;
|
|
5181
5209
|
}
|
|
5182
|
-
return pendingExitCode.resolve(exitCode2);
|
|
5210
|
+
return pendingExitCode.resolve(pendingExitCodeValue = exitCode2);
|
|
5183
5211
|
});
|
|
5184
5212
|
const exitClaudeCode = async () => {
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
shell.write(e);
|
|
5188
|
-
}).run();
|
|
5213
|
+
continueOnCrash = false;
|
|
5214
|
+
await src_default(["\r", "/exit", "\r"]).forEach(async () => await sleepms(200)).forEach(async (e) => shell.write(e)).run();
|
|
5189
5215
|
let exited = false;
|
|
5190
5216
|
await Promise.race([
|
|
5191
|
-
|
|
5192
|
-
resolve();
|
|
5193
|
-
exited = true;
|
|
5194
|
-
})),
|
|
5217
|
+
pendingExitCode.promise.then(() => exited = true),
|
|
5195
5218
|
new Promise((resolve) => setTimeout(() => {
|
|
5196
5219
|
if (exited)
|
|
5197
5220
|
return;
|
|
@@ -5204,16 +5227,9 @@ async function claudeYes({
|
|
|
5204
5227
|
const { columns, rows } = process.stdout;
|
|
5205
5228
|
shell.resize(columns - PREFIXLENGTH, rows);
|
|
5206
5229
|
});
|
|
5207
|
-
const
|
|
5208
|
-
writable: new WritableStream({
|
|
5209
|
-
write: (data) => shell.write(data),
|
|
5210
|
-
close: () => {}
|
|
5211
|
-
}),
|
|
5212
|
-
readable: shellOutputStream.readable
|
|
5213
|
-
};
|
|
5214
|
-
const ttr = new TerminalTextRender;
|
|
5230
|
+
const render = new TerminalTextRender;
|
|
5215
5231
|
const idleWatcher = !exitOnIdle ? null : createIdleWatcher(async () => {
|
|
5216
|
-
if (
|
|
5232
|
+
if (render.render().replace(/\s+/g, " ").match(/esc to interrupt|to run in background/)) {
|
|
5217
5233
|
console.log("[claude-yes] Claude is idle, but seems still working, not exiting yet");
|
|
5218
5234
|
} else {
|
|
5219
5235
|
console.log("[claude-yes] Claude is idle, exiting...");
|
|
@@ -5224,7 +5240,15 @@ async function claudeYes({
|
|
|
5224
5240
|
await sleepms(200);
|
|
5225
5241
|
shell.write("\r");
|
|
5226
5242
|
};
|
|
5227
|
-
src_default(fromReadable(process.stdin)).map((buffer2) => buffer2.toString()).by(
|
|
5243
|
+
src_default(fromReadable(process.stdin)).map((buffer2) => buffer2.toString()).by({
|
|
5244
|
+
writable: new WritableStream({
|
|
5245
|
+
write: async (data) => {
|
|
5246
|
+
await shellReady.wait();
|
|
5247
|
+
shell.write(data);
|
|
5248
|
+
}
|
|
5249
|
+
}),
|
|
5250
|
+
readable: shellOutputStream.readable
|
|
5251
|
+
}).forEach((text) => render.write(text)).forEach(() => idleWatcher?.ping()).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).forEach(async (e2) => {
|
|
5228
5252
|
if (e2.match(/❯ 1. Yes/))
|
|
5229
5253
|
return await confirm();
|
|
5230
5254
|
if (e2.match(/❯ 1. Dark mode✔|Press Enter to continue…/))
|
|
@@ -5235,14 +5259,14 @@ async function claudeYes({
|
|
|
5235
5259
|
}
|
|
5236
5260
|
}).run()).replaceAll(/.*(?:\r\n?|\r?\n)/g, (line) => prefix + line).map((e) => removeControlCharactersFromStdout ? removeControlCharacters(e) : e).to(fromWritable(process.stdout));
|
|
5237
5261
|
const exitCode = await pendingExitCode.promise;
|
|
5238
|
-
|
|
5262
|
+
console.log(`[claude-yes] claude exited with code ${exitCode}`);
|
|
5239
5263
|
if (logFile) {
|
|
5240
5264
|
verbose && console.log(`[claude-yes] Writing rendered logs to ${logFile}`);
|
|
5241
5265
|
const logFilePath = path2.resolve(logFile);
|
|
5242
5266
|
await mkdir(path2.dirname(logFilePath), { recursive: true }).catch(() => null);
|
|
5243
|
-
await writeFile(logFilePath,
|
|
5267
|
+
await writeFile(logFilePath, render.render());
|
|
5244
5268
|
}
|
|
5245
|
-
return { exitCode, logs:
|
|
5269
|
+
return { exitCode, logs: render.render() };
|
|
5246
5270
|
}
|
|
5247
5271
|
// node_modules/enhanced-ms/dist/index.js
|
|
5248
5272
|
var units = {
|
|
@@ -11395,7 +11419,7 @@ var yargs_default = Yargs;
|
|
|
11395
11419
|
var argv = yargs_default(hideBin(process.argv)).usage("Usage: $0 [options] [--] [claude args]").example('$0 --exit-on-idle=30s --continue-on-crash "help me solve all todos in my codebase"', "Run Claude with a 30 seconds idle timeout and continue on crash").option("exit-on-idle", {
|
|
11396
11420
|
type: "string",
|
|
11397
11421
|
default: "60s",
|
|
11398
|
-
description: "Exit after being idle for specified duration"
|
|
11422
|
+
description: "Exit after being idle for specified duration, default 1min, set to 0 to disable this behaviour"
|
|
11399
11423
|
}).option("continue-on-crash", {
|
|
11400
11424
|
type: "boolean",
|
|
11401
11425
|
default: true,
|
|
@@ -11420,5 +11444,5 @@ var { exitCode, logs: logs2 } = await claudeYes({
|
|
|
11420
11444
|
});
|
|
11421
11445
|
process.exit(exitCode ?? 1);
|
|
11422
11446
|
|
|
11423
|
-
//# debugId=
|
|
11447
|
+
//# debugId=1D1D428D01E003D264756E2164756E21
|
|
11424
11448
|
//# sourceMappingURL=cli.js.map
|