claude-yes 1.21.1 → 1.23.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.
- package/dist/claude-yes.js +30 -14
- package/dist/cli.js +30 -14
- package/dist/cli.js.map +3 -3
- package/dist/codex-yes.js +30 -14
- package/dist/copilot-yes.js +30 -14
- package/dist/cursor-yes.js +30 -14
- package/dist/gemini-yes.js +30 -14
- package/dist/grok-yes.js +30 -14
- package/dist/index.js +30 -14
- package/dist/index.js.map +3 -3
- package/index.ts +44 -39
- package/package.json +3 -2
package/index.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { fromReadable, fromWritable } from 'from-node-stream';
|
|
2
|
-
import { mkdir, writeFile } from 'fs/promises';
|
|
2
|
+
import { appendFile, mkdir, rm, writeFile } from 'fs/promises';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import DIE from 'phpdie';
|
|
5
5
|
import sflow from 'sflow';
|
|
6
6
|
import { TerminalTextRender } from 'terminal-render';
|
|
7
|
+
import tsaComposer from 'tsa-composer';
|
|
7
8
|
import { IdleWaiter } from './idleWaiter';
|
|
8
9
|
import { ReadyManager } from './ReadyManager';
|
|
9
10
|
import { removeControlCharacters } from './removeControlCharacters';
|
|
@@ -26,7 +27,8 @@ export const CLI_CONFIGURES: Record<
|
|
|
26
27
|
},
|
|
27
28
|
claude: {
|
|
28
29
|
install: 'npm install -g @anthropic-ai/claude-code',
|
|
29
|
-
ready: [/^> /], // regex matcher for stdin ready
|
|
30
|
+
// ready: [/^> /], // regex matcher for stdin ready
|
|
31
|
+
ready: [/\? for shortcuts/], // regex matcher for stdin ready
|
|
30
32
|
enter: [/❯ 1. Yes/, /❯ 1. Dark mode✔/, /Press Enter to continue…/],
|
|
31
33
|
fatal: [
|
|
32
34
|
/No conversation found to continue/,
|
|
@@ -43,7 +45,10 @@ export const CLI_CONFIGURES: Record<
|
|
|
43
45
|
codex: {
|
|
44
46
|
install: 'npm install -g @openai/codex-cli',
|
|
45
47
|
ready: [/⏎ send/],
|
|
46
|
-
enter: [
|
|
48
|
+
enter: [
|
|
49
|
+
/> 1. Yes, allow Codex to work in this folder/,
|
|
50
|
+
/▌ > 1. Approve and run now/,
|
|
51
|
+
],
|
|
47
52
|
fatal: [/Error: The cursor position could not be read within/],
|
|
48
53
|
// add to codex --search by default when not provided by the user
|
|
49
54
|
ensureArgs: (args: string[]) => {
|
|
@@ -67,15 +72,15 @@ export const CLI_CONFIGURES: Record<
|
|
|
67
72
|
},
|
|
68
73
|
};
|
|
69
74
|
/**
|
|
70
|
-
* Main function to run
|
|
75
|
+
* Main function to run agent-cli with automatic yes/no responses
|
|
71
76
|
* @param options Configuration options
|
|
72
|
-
* @param options.continueOnCrash - If true, automatically restart
|
|
73
|
-
* 1. Shows message '
|
|
74
|
-
* 2. Spawns a new '
|
|
77
|
+
* @param options.continueOnCrash - If true, automatically restart agent-cli when it crashes:
|
|
78
|
+
* 1. Shows message 'agent-cli crashed, restarting..'
|
|
79
|
+
* 2. Spawns a new 'agent-cli --continue' process
|
|
75
80
|
* 3. Re-attaches the new process to the shell stdio (pipes new process stdin/stdout)
|
|
76
81
|
* 4. If it crashes with "No conversation found to continue", exits the process
|
|
77
|
-
* @param options.exitOnIdle - Exit when
|
|
78
|
-
* @param options.
|
|
82
|
+
* @param options.exitOnIdle - Exit when agent-cli is idle. Boolean or timeout in milliseconds, recommended 5000 - 60000, default is false
|
|
83
|
+
* @param options.cliArgs - Additional arguments to pass to the agent-cli CLI
|
|
79
84
|
* @param options.removeControlCharactersFromStdout - Remove ANSI control characters from stdout. Defaults to !process.stdout.isTTY
|
|
80
85
|
*
|
|
81
86
|
* @example
|
|
@@ -116,31 +121,16 @@ export default async function claudeYes({
|
|
|
116
121
|
removeControlCharactersFromStdout?: boolean;
|
|
117
122
|
verbose?: boolean;
|
|
118
123
|
} = {}) {
|
|
124
|
+
await rm('agent-yes.log').catch(() => null); // ignore error if file doesn't exist
|
|
125
|
+
const yesLog = tsaComposer()(async function yesLog(msg: string) {
|
|
126
|
+
await appendFile('agent-yes.log', `${msg}\n`).catch(() => null);
|
|
127
|
+
});
|
|
119
128
|
const continueArgs = {
|
|
120
129
|
codex: 'resume --last'.split(' '),
|
|
121
130
|
claude: '--continue'.split(' '),
|
|
122
131
|
gemini: [], // not possible yet
|
|
123
132
|
};
|
|
124
133
|
|
|
125
|
-
// if (verbose) {
|
|
126
|
-
// console.log('calling claudeYes: ', {
|
|
127
|
-
// cli,
|
|
128
|
-
// continueOnCrash,
|
|
129
|
-
// exitOnIdle,
|
|
130
|
-
// cliArgs,
|
|
131
|
-
// cwd,
|
|
132
|
-
// removeControlCharactersFromStdout,
|
|
133
|
-
// logFile,
|
|
134
|
-
// verbose,
|
|
135
|
-
// });
|
|
136
|
-
// }
|
|
137
|
-
// console.log(
|
|
138
|
-
// `⭐ Starting ${cli}, automatically responding to yes/no prompts...`
|
|
139
|
-
// );
|
|
140
|
-
// console.log(
|
|
141
|
-
// '⚠️ 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.'
|
|
142
|
-
// );
|
|
143
|
-
|
|
144
134
|
process.stdin.setRawMode?.(true); // must be called any stdout/stdin usage
|
|
145
135
|
let isFatal = false; // when true, do not restart on crash, and exit agent
|
|
146
136
|
const stdinReady = new ReadyManager();
|
|
@@ -243,7 +233,11 @@ export default async function claudeYes({
|
|
|
243
233
|
await exitAgent();
|
|
244
234
|
});
|
|
245
235
|
|
|
236
|
+
// console.log(
|
|
237
|
+
// `[${cli}-yes] Started ${cli} with args: ${[cliCommand, ...cliArgs].join(" ")}`
|
|
238
|
+
// );
|
|
246
239
|
// Message streaming
|
|
240
|
+
|
|
247
241
|
sflow(fromReadable<Buffer>(process.stdin))
|
|
248
242
|
.map((buffer) => buffer.toString())
|
|
249
243
|
// .map((e) => e.replaceAll('\x1a', '')) // remove ctrl+z from user's input (seems bug)
|
|
@@ -264,16 +258,19 @@ export default async function claudeYes({
|
|
|
264
258
|
terminalRender.write(text);
|
|
265
259
|
// todo: .onStatus((msg)=> shell.write(msg))
|
|
266
260
|
if (process.stdin.isTTY) return; // only handle it when stdin is not tty
|
|
267
|
-
if (text.includes('\u001b[6n')) return; // only asked
|
|
268
|
-
|
|
261
|
+
if (!text.includes('\u001b[6n')) return; // only asked for cursor position
|
|
269
262
|
// todo: use terminalRender API to get cursor position when new version is available
|
|
270
263
|
// xterm replies CSI row; column R if asked cursor position
|
|
271
264
|
// https://en.wikipedia.org/wiki/ANSI_escape_code#:~:text=citation%20needed%5D-,xterm%20replies,-CSI%20row%C2%A0%3B
|
|
272
265
|
// when agent asking position, respond with row; col
|
|
273
|
-
const rendered = terminalRender.render();
|
|
274
|
-
const row =
|
|
275
|
-
|
|
276
|
-
|
|
266
|
+
// const rendered = terminalRender.render();
|
|
267
|
+
const { col, row } = terminalRender.getCursorPosition();
|
|
268
|
+
console.log(
|
|
269
|
+
`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`,
|
|
270
|
+
);
|
|
271
|
+
shell.write(`\u001b[${row};${col}R`); // reply cli when getting cursor position
|
|
272
|
+
// const row = rendered.split('\n').length + 1;
|
|
273
|
+
// const col = (rendered.split('\n').slice(-1)[0]?.length || 0) + 1;
|
|
277
274
|
})
|
|
278
275
|
|
|
279
276
|
// auto-response
|
|
@@ -282,6 +279,7 @@ export default async function claudeYes({
|
|
|
282
279
|
.map((e) => removeControlCharacters(e))
|
|
283
280
|
.map((e) => e.replaceAll('\r', '')) // remove carriage return
|
|
284
281
|
.lines({ EOL: 'NONE' })
|
|
282
|
+
.forEach((e) => yesLog`output|${e}`) // for debugging
|
|
285
283
|
// Generic auto-response handler driven by CLI_CONFIGURES
|
|
286
284
|
.forEach(async (e, i) => {
|
|
287
285
|
const conf =
|
|
@@ -290,21 +288,25 @@ export default async function claudeYes({
|
|
|
290
288
|
|
|
291
289
|
// ready matcher: if matched, mark stdin ready
|
|
292
290
|
if (conf.ready?.some((rx: RegExp) => e.match(rx))) {
|
|
291
|
+
await yesLog`ready |${e}`;
|
|
293
292
|
if (cli === 'gemini' && i <= 80) return; // gemini initial noise, only after many lines
|
|
294
293
|
stdinReady.ready();
|
|
295
294
|
}
|
|
296
295
|
|
|
297
296
|
// enter matchers: send Enter when any enter regex matches
|
|
298
|
-
if (conf.enter?.some((rx: RegExp) => e.match(rx)))
|
|
297
|
+
if (conf.enter?.some((rx: RegExp) => e.match(rx))) {
|
|
298
|
+
await yesLog`enter |${e}`;
|
|
299
299
|
await sendEnter(300); // send Enter after 300ms idle wait
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
300
302
|
|
|
301
303
|
// fatal matchers: set isFatal flag when matched
|
|
302
304
|
if (conf.fatal?.some((rx: RegExp) => e.match(rx))) {
|
|
305
|
+
await yesLog`fatal |${e}`;
|
|
303
306
|
isFatal = true;
|
|
304
307
|
await exitAgent();
|
|
305
308
|
}
|
|
306
309
|
})
|
|
307
|
-
// .forEach(e => appendFile('.cache/io.log', "output|" + JSON.stringify(e) + '\n')) // for debugging
|
|
308
310
|
.run(),
|
|
309
311
|
)
|
|
310
312
|
.map((e) =>
|
|
@@ -314,6 +316,7 @@ export default async function claudeYes({
|
|
|
314
316
|
.then(() => null); // run it immediately without await
|
|
315
317
|
|
|
316
318
|
// wait for cli ready and send prompt if provided
|
|
319
|
+
if (cli === 'codex') shell.write(`\u001b[1;1R`); // send cursor position response when stdin is not tty
|
|
317
320
|
if (prompt) await sendMessage(prompt);
|
|
318
321
|
|
|
319
322
|
const exitCode = await pendingExitCode.promise; // wait for the shell to exit
|
|
@@ -333,10 +336,10 @@ export default async function claudeYes({
|
|
|
333
336
|
async function sendEnter(waitms = 1000) {
|
|
334
337
|
// wait for idle for a bit to let agent cli finish rendering
|
|
335
338
|
const st = Date.now();
|
|
336
|
-
|
|
337
339
|
await idleWaiter.wait(waitms);
|
|
338
340
|
const et = Date.now();
|
|
339
|
-
process.stdout.write(`\ridleWaiter.wait(${waitms}) took ${et - st}ms\r`);
|
|
341
|
+
// process.stdout.write(`\ridleWaiter.wait(${waitms}) took ${et - st}ms\r`);
|
|
342
|
+
await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
|
|
340
343
|
|
|
341
344
|
shell.write('\r');
|
|
342
345
|
}
|
|
@@ -344,6 +347,7 @@ export default async function claudeYes({
|
|
|
344
347
|
async function sendMessage(message: string) {
|
|
345
348
|
await stdinReady.wait();
|
|
346
349
|
// show in-place message: write msg and move cursor back start
|
|
350
|
+
await yesLog`send |${message}`;
|
|
347
351
|
shell.write(message);
|
|
348
352
|
idleWaiter.ping(); // just sent a message, wait for echo
|
|
349
353
|
await sendEnter();
|
|
@@ -371,10 +375,11 @@ export default async function claudeYes({
|
|
|
371
375
|
}
|
|
372
376
|
|
|
373
377
|
function getTerminalDimensions() {
|
|
378
|
+
if (!process.stdout.isTTY) return { cols: 80, rows: 30 }; // default size when not tty
|
|
374
379
|
return {
|
|
375
380
|
// TODO: enforce minimum cols/rows to avoid layout issues
|
|
376
381
|
// cols: Math.max(process.stdout.columns, 80),
|
|
377
|
-
cols: process.stdout.columns,
|
|
382
|
+
cols: Math.min(Math.max(20, process.stdout.columns), 80),
|
|
378
383
|
rows: process.stdout.rows,
|
|
379
384
|
};
|
|
380
385
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-yes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.0",
|
|
4
4
|
"description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -62,7 +62,8 @@
|
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"bun-pty": "^0.3.2",
|
|
64
64
|
"p-map": "^7.0.3",
|
|
65
|
-
"phpdie": "^1.7.0"
|
|
65
|
+
"phpdie": "^1.7.0",
|
|
66
|
+
"tsa-composer": "^3.0.0"
|
|
66
67
|
},
|
|
67
68
|
"devDependencies": {
|
|
68
69
|
"@biomejs/biome": "^2.2.5",
|