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 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:
@@ -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: 'Exit after being idle for specified duration',
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 = process.cwd(),
5126
- env = process.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") : await import("node-pty");
5152
- let shell = pty.spawn("claude", claudeArgs, {
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
- if (continueOnCrash && exitCode2 !== 0) {
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
- await src_default(["\r", "/exit", "\r"]).forEach(async (e) => {
5186
- await sleepms(200);
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
- new Promise((resolve) => shell.onExit(() => {
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 shellStdio = {
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 (ttr.render().replace(/\s+/g, " ").match(/esc to interrupt|to run in background/)) {
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(shellStdio).forEach((text) => ttr.write(text)).forEach(() => idleWatcher?.ping()).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).forEach(async (e2) => {
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
- verbose && console.log(`[claude-yes] claude exited with code ${exitCode}`);
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, ttr.render());
5267
+ await writeFile(logFilePath, render.render());
5244
5268
  }
5245
- return { exitCode, logs: ttr.render() };
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=60C91F29E6CD011A64756E2164756E21
11447
+ //# debugId=1D1D428D01E003D264756E2164756E21
11424
11448
  //# sourceMappingURL=cli.js.map