claude-yes 1.24.2 → 1.25.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/package.json CHANGED
@@ -1,9 +1,15 @@
1
1
  {
2
2
  "name": "claude-yes",
3
- "version": "1.24.2",
3
+ "version": "1.25.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",
7
+ "qwen",
8
+ "gemini",
9
+ "codex",
10
+ "copilot",
11
+ "cursor",
12
+ "grok",
7
13
  "ai",
8
14
  "automation",
9
15
  "cli",
@@ -32,11 +38,13 @@
32
38
  "types": "./ts/index.ts",
33
39
  "bin": {
34
40
  "claude-yes": "dist/claude-yes.js",
41
+ "cli-yes": "dist/cli.js",
35
42
  "codex-yes": "dist/codex-yes.js",
36
43
  "copilot-yes": "dist/copilot-yes.js",
37
44
  "cursor-yes": "dist/cursor-yes.js",
38
45
  "gemini-yes": "dist/gemini-yes.js",
39
- "grok-yes": "dist/grok-yes.js"
46
+ "grok-yes": "dist/grok-yes.js",
47
+ "qwen-yes": "dist/qwen-yes.js"
40
48
  },
41
49
  "directories": {
42
50
  "doc": "docs"
@@ -52,21 +60,47 @@
52
60
  "fmt": "bunx @biomejs/biome check --fix && bunx sort-package-json",
53
61
  "prepack": "bun run build",
54
62
  "prepare": "bunx husky",
55
- "test": "vitest"
63
+ "test": "vitest",
64
+ "test:bun": "bun test ts/*.bun.spec.ts",
65
+ "test:all": "npm run test && npm run test:bun"
56
66
  },
57
67
  "lint-staged": {
58
68
  "*.{ts,js,json,md}": [
59
69
  "bunx @biomejs/biome check --fix"
60
70
  ]
61
71
  },
72
+ "release": {
73
+ "branches": [
74
+ "main"
75
+ ],
76
+ "plugins": [
77
+ "@semantic-release/commit-analyzer",
78
+ "@semantic-release/release-notes-generator",
79
+ "@semantic-release/changelog",
80
+ "@semantic-release/npm",
81
+ [
82
+ "@semantic-release/exec",
83
+ {
84
+ "publishCmd": "npm pkg set name=claude-yes"
85
+ }
86
+ ],
87
+ "@semantic-release/npm",
88
+ "@semantic-release/git",
89
+ "@semantic-release/github"
90
+ ]
91
+ },
62
92
  "dependencies": {
63
93
  "bun-pty": "^0.3.2",
94
+ "cpu-wait": "^0.0.10",
64
95
  "p-map": "^7.0.3",
65
96
  "phpdie": "^1.7.0",
66
- "tsa-composer": "^3.0.0"
97
+ "tsa-composer": "^3.0.2"
67
98
  },
68
99
  "devDependencies": {
69
100
  "@biomejs/biome": "^2.2.5",
101
+ "@semantic-release/changelog": "^6.0.3",
102
+ "@semantic-release/exec": "^7.1.0",
103
+ "@semantic-release/git": "^10.0.1",
70
104
  "@types/bun": "^1.2.18",
71
105
  "@types/jest": "^30.0.0",
72
106
  "@types/node": "^24.0.10",
@@ -1,17 +1,20 @@
1
1
  import { exec } from 'child_process';
2
2
  import { fromStdio } from 'from-node-stream';
3
3
  import sflow from 'sflow';
4
+ import { describe, it } from 'vitest';
4
5
  import { sleepms } from './utils';
5
6
 
6
- // 2025-08-11 ok
7
- it.skip('CLI --exit-on-idle flag with custom timeout', async () => {
8
- const p = exec(
9
- `bunx tsx ./cli.ts --verbose --logFile=./cli-idle.log --exit-on-idle=3s "say hello and wait"`,
10
- );
11
- const tr = new TransformStream<string, string>();
12
- const output = await sflow(tr.readable).by(fromStdio(p)).log().text();
13
- console.log(output);
14
- expect(output).toContain('hello');
15
- await sleepms(1000); // wait for process exit
16
- expect(p.exitCode).toBe(0);
17
- }, 20e3);
7
+ describe('CLI idle tests', () => {
8
+ // 2025-08-11 ok
9
+ it.skip('CLI --exit-on-idle flag with custom timeout', async () => {
10
+ const p = exec(
11
+ `bunx tsx ./ts/cli.ts claude --verbose --logFile=./cli-idle.log --exit-on-idle=3s "say hello and wait"`,
12
+ );
13
+ const tr = new TransformStream<string, string>();
14
+ const output = await sflow(tr.readable).by(fromStdio(p)).log().text();
15
+ console.log(output);
16
+ expect(output).toContain('hello');
17
+ await sleepms(1000); // wait for process exit
18
+ expect(p.exitCode).toBe(0);
19
+ }, 20e3);
20
+ });
package/ts/cli.spec.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { vi } from 'vitest';
2
+
3
+ // Mock cliYes function
4
+ const mockCliYes = vi.fn(async ({ prompt }) => {
5
+ return { exitCode: 0, logs: 'mocked logs' };
6
+ });
7
+
8
+ test('CLI args parsing', () => {
9
+ const rawArgs = ['claude', '--verbose', '--idle=5m', '--', 'write tests'];
10
+ const optionalIndex = (e: number) => (0 <= e ? e : undefined);
11
+ const dashIndex = optionalIndex(rawArgs.indexOf('--'));
12
+ const dashPrompt = dashIndex
13
+ ? rawArgs.slice(dashIndex + 1).join(' ')
14
+ : undefined;
15
+
16
+ expect(dashPrompt).toBe('write tests');
17
+ expect(mockCliYes).toBeDefined();
18
+ });
package/ts/cli.ts CHANGED
@@ -1,47 +1,69 @@
1
1
  #!/usr/bin/env node
2
2
  import enhancedMs from 'enhanced-ms';
3
+ import path from 'path';
4
+ import DIE from 'phpdie';
3
5
  import yargs from 'yargs';
4
6
  import { hideBin } from 'yargs/helpers';
5
- import claudeYes from '.';
7
+ import cliYes, { CLIS_CONFIG, type CliYesConfig, SUPPORTED_CLIS } from '.';
6
8
 
7
9
  // cli entry point
10
+ const cliName = ((e?: string) => {
11
+ // Handle test environment where script is run as cli.ts
12
+ if (e === 'cli' || e === 'cli.ts') return undefined;
13
+ return e;
14
+ })(process.argv[1]?.split('/').pop()?.split('-')[0]);
15
+
8
16
  const argv = yargs(hideBin(process.argv))
9
- .usage('Usage: $0 [options] [agent-cli args] [--] [prompts...]')
17
+ .usage('Usage: $0 [cli] [cli-yes args] [agent-cli args] [--] [prompts...]')
10
18
  .example(
11
- '$0 --exit-on-idle=30s --continue-on-crash "help me solve all todos in my codebase"',
12
- 'Run Claude with a 30 seconds idle timeout and continue on crash',
19
+ '$0 claude --idle=30s -- solve all todos in my codebase, commit one by one',
20
+ 'Run Claude with a 30 seconds idle timeout, and the prompt is everything after `--`',
13
21
  )
14
- // .option('continue-on-crash', {
15
- // type: 'boolean',
16
- // default: true,
17
- // description:
18
- // 'spawn Claude with --continue if it crashes, only works for claude',
19
- // alias: 'c',
20
- // })
21
- .option('log-file', {
22
+ .option('robust', {
23
+ type: 'boolean',
24
+ default: true,
25
+ description:
26
+ 're-spawn Claude with --continue if it crashes, only works for claude yet',
27
+ alias: 'r',
28
+ })
29
+ .option('logFile', {
22
30
  type: 'string',
23
- description: 'Log file to write to',
31
+ description: 'Rendered log file to write to.',
24
32
  })
25
33
  .option('prompt', {
26
34
  type: 'string',
27
- description: 'Prompt to send to Claude',
35
+ description: 'Prompt to send to Claude (also can be passed after --)',
28
36
  alias: 'p',
29
37
  })
30
38
  .option('verbose', {
31
39
  type: 'boolean',
32
- description: 'Enable verbose logging',
40
+ description: 'Enable verbose logging, will emit ./agent-yes.log',
33
41
  default: false,
34
42
  })
35
43
  .option('exit-on-idle', {
36
44
  type: 'string',
37
45
  description: 'Exit after a period of inactivity, e.g., "5s" or "1m"',
46
+ deprecated: 'use --idle instead',
47
+ default: '60s',
38
48
  alias: 'e',
39
49
  })
40
- .option('disable-lock', {
50
+ .option('idle', {
51
+ type: 'string',
52
+ description: 'Exit after a period of inactivity, e.g., "5s" or "1m"',
53
+ alias: 'i',
54
+ })
55
+ .option('queue', {
41
56
  type: 'boolean',
42
57
  description:
43
- 'Disable the running lock feature that prevents concurrent agents in the same directory/repo',
44
- default: false,
58
+ 'Queue Agent when spawning multiple agents in the same directory/repo, can be disabled with --no-queue',
59
+ default: true,
60
+ })
61
+ .positional('cli', {
62
+ describe: 'The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini',
63
+ type: 'string',
64
+ choices: SUPPORTED_CLIS,
65
+ demandOption: false,
66
+ default: cliName,
45
67
  })
46
68
  .help()
47
69
  .version()
@@ -51,40 +73,52 @@ const argv = yargs(hideBin(process.argv))
51
73
  })
52
74
  .parseSync();
53
75
 
54
- console.log(argv);
55
-
56
76
  // detect cli name for cli, while package.json have multiple bin link: {"claude-yes": "cli.js", "codex-yes": "cli.js", "gemini-yes": "cli.js"}
57
- const cliName = process.argv[1]?.split('/').pop()?.split('-')[0];
58
-
77
+ const optionalIndex = (e: number) => (0 <= e ? e : undefined);
59
78
  const rawArgs = process.argv.slice(2);
60
- const cliArgIndex = rawArgs.indexOf(String(argv._[0]));
61
- const dashIndex = rawArgs.indexOf('--');
79
+ const cliArgIndex = optionalIndex(rawArgs.indexOf(String(argv._[0])));
80
+ const dashIndex = optionalIndex(rawArgs.indexOf('--'));
62
81
 
63
82
  // Support: everything after a literal `--` is a prompt string. Example:
64
83
  // claude-yes --exit-on-idle=30s -- "help me refactor this"
65
84
  // In that example the prompt will be `help me refactor this` and won't be
66
85
  // passed as args to the underlying CLI binary.
67
86
 
68
- const cliArgsForSpawn = rawArgs.slice(
69
- cliArgIndex === -1 ? 0 : cliArgIndex,
70
- dashIndex === -1 ? undefined : dashIndex,
71
- ); // default to all args
72
- const promptFromDash: string | undefined = rawArgs
73
- .slice(dashIndex + 1)
74
- .join(' ');
87
+ const cliArgsForSpawn = argv._[0]
88
+ ? rawArgs.slice(cliArgIndex ?? 0, dashIndex ?? undefined)
89
+ : []; // default to all args
90
+ const dashPrompt: string | undefined = dashIndex
91
+ ? rawArgs.slice(dashIndex + 1).join(' ')
92
+ : undefined;
75
93
 
76
- console.log({ rawArgs, cliArgsForSpawn, promptFromDash });
77
- console.clear();
78
- const { exitCode } = await claudeYes({
79
- cli: cliName,
80
- // prefer explicit --prompt / -p; otherwise use the text after `--` if present
81
- prompt: argv.prompt || promptFromDash,
82
- exitOnIdle: argv.exitOnIdle ? enhancedMs(argv.exitOnIdle) : undefined,
94
+ // console.clear();
95
+ if (argv.verbose) {
96
+ process.env.VERBOSE = 'true'; // enable verbose logging in yesLog.ts
97
+ console.log({ ...argv, cliArgsForSpawn, prompt: dashPrompt });
98
+ }
99
+
100
+ const { exitCode } = await cliYes({
101
+ // cli name, detect from argv[1] if not provided
102
+ cli: (cliName ||
103
+ argv.cli ||
104
+ argv._[0]?.toString()?.replace?.(/-yes$/, '') ||
105
+ DIE('missing cli def')) as SUPPORTED_CLIS,
83
106
  cliArgs: cliArgsForSpawn,
84
- // continueOnCrash: argv.continueOnCrash,
107
+
108
+ // prefer explicit --prompt / -p; otherwise use the text after `--` if present
109
+ prompt: [argv.prompt, dashPrompt].join(' ').trim() || undefined,
110
+
111
+ exitOnIdle: Number(
112
+ (argv.exitOnIdle || argv.idle)?.replace(/.*/, (e) =>
113
+ String(enhancedMs(e)),
114
+ ) || 0,
115
+ ),
116
+
117
+ // other options
118
+ queue: argv.queue,
119
+ robust: argv.robust,
85
120
  logFile: argv.logFile,
86
121
  verbose: argv.verbose,
87
- disableLock: argv.disableLock,
88
122
  });
89
123
 
90
124
  process.exit(exitCode ?? 1);
@@ -0,0 +1,12 @@
1
+ import type { AgentCliConfig, CliYesConfig } from '.';
2
+
3
+ type Awaitable<T> = T | Promise<T>;
4
+ export async function defineCliYesConfig<T extends CliYesConfig>(
5
+ cfg: Awaitable<T> | ((original: T) => Awaitable<T>),
6
+ ) {
7
+ if (typeof cfg === 'function') cfg = await cfg({ clis: {} } as T);
8
+
9
+ return cfg as unknown as {
10
+ clis: Record<string, AgentCliConfig>;
11
+ };
12
+ }