claude-yes 1.23.2 → 1.24.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.
@@ -25,11 +25,16 @@ import { hideBin } from "yargs/helpers";
25
25
 
26
26
  // dist/index.js
27
27
  import { fromReadable, fromWritable } from "from-node-stream";
28
- import { mkdir, writeFile } from "fs/promises";
29
- import path from "path";
28
+ import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
29
+ import path2 from "path";
30
30
  import DIE from "phpdie";
31
31
  import sflow from "sflow";
32
32
  import { TerminalTextRender } from "terminal-render";
33
+ import { execSync } from "child_process";
34
+ import { existsSync } from "fs";
35
+ import { mkdir, readFile, rename, writeFile } from "fs/promises";
36
+ import { homedir } from "os";
37
+ import path from "path";
33
38
  class IdleWaiter {
34
39
  lastActivityTime = Date.now();
35
40
  checkInterval = 100;
@@ -67,6 +72,169 @@ class ReadyManager {
67
72
  function removeControlCharacters(str) {
68
73
  return str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
69
74
  }
75
+ var LOCK_DIR = path.join(homedir(), ".claude-yes");
76
+ var LOCK_FILE = path.join(LOCK_DIR, "running.lock.json");
77
+ var MAX_RETRIES = 5;
78
+ var RETRY_DELAYS = [50, 100, 200, 400, 800];
79
+ var POLL_INTERVAL = 2000;
80
+ function isProcessRunning(pid) {
81
+ try {
82
+ process.kill(pid, 0);
83
+ return true;
84
+ } catch {
85
+ return false;
86
+ }
87
+ }
88
+ function getGitRoot(cwd) {
89
+ try {
90
+ const result = execSync("git rev-parse --show-toplevel", {
91
+ cwd,
92
+ encoding: "utf8",
93
+ stdio: ["pipe", "pipe", "ignore"]
94
+ });
95
+ return result.trim();
96
+ } catch {
97
+ return null;
98
+ }
99
+ }
100
+ function isGitRepo(cwd) {
101
+ try {
102
+ const gitRoot = getGitRoot(cwd);
103
+ return gitRoot !== null;
104
+ } catch {
105
+ return false;
106
+ }
107
+ }
108
+ function resolveRealPath(p) {
109
+ try {
110
+ return path.resolve(p);
111
+ } catch {
112
+ return p;
113
+ }
114
+ }
115
+ function sleep(ms) {
116
+ return new Promise((resolve) => setTimeout(resolve, ms));
117
+ }
118
+ async function readLockFile() {
119
+ try {
120
+ await mkdir(LOCK_DIR, { recursive: true });
121
+ if (!existsSync(LOCK_FILE)) {
122
+ return { tasks: [] };
123
+ }
124
+ const content = await readFile(LOCK_FILE, "utf8");
125
+ const lockFile = JSON.parse(content);
126
+ lockFile.tasks = lockFile.tasks.filter((task) => {
127
+ if (isProcessRunning(task.pid))
128
+ return true;
129
+ return false;
130
+ });
131
+ return lockFile;
132
+ } catch (error) {
133
+ return { tasks: [] };
134
+ }
135
+ }
136
+ async function writeLockFile(lockFile, retryCount = 0) {
137
+ try {
138
+ await mkdir(LOCK_DIR, { recursive: true });
139
+ const tempFile = `${LOCK_FILE}.tmp.${process.pid}`;
140
+ await writeFile(tempFile, JSON.stringify(lockFile, null, 2), "utf8");
141
+ await rename(tempFile, LOCK_FILE);
142
+ } catch (error) {
143
+ if (retryCount < MAX_RETRIES) {
144
+ await sleep(RETRY_DELAYS[retryCount] || 800);
145
+ return writeLockFile(lockFile, retryCount + 1);
146
+ }
147
+ throw error;
148
+ }
149
+ }
150
+ async function checkLock(cwd, prompt) {
151
+ const resolvedCwd = resolveRealPath(cwd);
152
+ const gitRoot = isGitRepo(resolvedCwd) ? getGitRoot(resolvedCwd) : null;
153
+ const lockKey = gitRoot || resolvedCwd;
154
+ const lockFile = await readLockFile();
155
+ const blockingTasks = lockFile.tasks.filter((task) => {
156
+ if (!isProcessRunning(task.pid))
157
+ return false;
158
+ if (task.status !== "running")
159
+ return false;
160
+ if (gitRoot && task.gitRoot) {
161
+ return task.gitRoot === gitRoot;
162
+ } else {
163
+ return task.cwd === lockKey;
164
+ }
165
+ });
166
+ return {
167
+ isLocked: blockingTasks.length > 0,
168
+ blockingTasks,
169
+ lockKey
170
+ };
171
+ }
172
+ async function addTask(task) {
173
+ const lockFile = await readLockFile();
174
+ lockFile.tasks = lockFile.tasks.filter((t) => t.pid !== task.pid);
175
+ lockFile.tasks.push(task);
176
+ await writeLockFile(lockFile);
177
+ }
178
+ async function updateTaskStatus(pid, status) {
179
+ const lockFile = await readLockFile();
180
+ const task = lockFile.tasks.find((t) => t.pid === pid);
181
+ if (task) {
182
+ task.status = status;
183
+ await writeLockFile(lockFile);
184
+ }
185
+ }
186
+ async function removeTask(pid) {
187
+ const lockFile = await readLockFile();
188
+ lockFile.tasks = lockFile.tasks.filter((t) => t.pid !== pid);
189
+ await writeLockFile(lockFile);
190
+ }
191
+ async function waitForUnlock(blockingTasks, currentTask) {
192
+ const blockingTask = blockingTasks[0];
193
+ console.log(`⏳ Queueing for unlock of: ${blockingTask.task}`);
194
+ await addTask({ ...currentTask, status: "queued" });
195
+ let dots = 0;
196
+ while (true) {
197
+ await sleep(POLL_INTERVAL);
198
+ const lockCheck = await checkLock(currentTask.cwd, currentTask.task);
199
+ if (!lockCheck.isLocked) {
200
+ await updateTaskStatus(currentTask.pid, "running");
201
+ console.log(`
202
+ ✓ Lock released, starting task...`);
203
+ break;
204
+ }
205
+ dots = (dots + 1) % 4;
206
+ process.stdout.write(`\r⏳ Queueing${".".repeat(dots)}${" ".repeat(3 - dots)}`);
207
+ }
208
+ }
209
+ async function acquireLock(cwd, prompt = "no prompt provided") {
210
+ const resolvedCwd = resolveRealPath(cwd);
211
+ const gitRoot = isGitRepo(resolvedCwd) ? getGitRoot(resolvedCwd) : null;
212
+ const task = {
213
+ cwd: resolvedCwd,
214
+ gitRoot: gitRoot || undefined,
215
+ task: prompt.substring(0, 100),
216
+ pid: process.pid,
217
+ status: "running",
218
+ startedAt: Date.now(),
219
+ lockedAt: Date.now()
220
+ };
221
+ const lockCheck = await checkLock(resolvedCwd, prompt);
222
+ if (lockCheck.isLocked) {
223
+ await waitForUnlock(lockCheck.blockingTasks, task);
224
+ } else {
225
+ await addTask(task);
226
+ }
227
+ }
228
+ async function releaseLock(pid = process.pid) {
229
+ await removeTask(pid);
230
+ }
231
+ async function updateCurrentTaskStatus(status, pid = process.pid) {
232
+ await updateTaskStatus(pid, status);
233
+ }
234
+ function shouldUseLock(cwd) {
235
+ const resolvedCwd = resolveRealPath(cwd);
236
+ return true;
237
+ }
70
238
  var CLI_CONFIGURES = {
71
239
  grok: {
72
240
  install: "npm install -g @vibe-kit/grok-cli",
@@ -104,7 +272,7 @@ var CLI_CONFIGURES = {
104
272
  },
105
273
  copilot: {
106
274
  install: "npm install -g @github/copilot",
107
- ready: [/^ > /],
275
+ ready: [/^ +> /, /Ctrl\+c Exit/],
108
276
  enter: [/ │ ❯ 1. Yes, proceed/, /❯ 1. Yes/],
109
277
  fatal: []
110
278
  },
@@ -126,13 +294,36 @@ async function claudeYes({
126
294
  exitOnIdle,
127
295
  logFile,
128
296
  removeControlCharactersFromStdout = false,
129
- verbose = false
297
+ verbose = false,
298
+ disableLock = false
130
299
  } = {}) {
131
300
  const continueArgs = {
132
301
  codex: "resume --last".split(" "),
133
302
  claude: "--continue".split(" "),
134
303
  gemini: []
135
304
  };
305
+ const workingDir = cwd ?? process.cwd();
306
+ if (!disableLock && shouldUseLock(workingDir)) {
307
+ await acquireLock(workingDir, prompt ?? "Interactive session");
308
+ }
309
+ const cleanupLock = async () => {
310
+ if (!disableLock && shouldUseLock(workingDir)) {
311
+ await releaseLock().catch(() => null);
312
+ }
313
+ };
314
+ process.on("exit", () => {
315
+ if (!disableLock) {
316
+ releaseLock().catch(() => null);
317
+ }
318
+ });
319
+ process.on("SIGINT", async () => {
320
+ await cleanupLock();
321
+ process.exit(130);
322
+ });
323
+ process.on("SIGTERM", async () => {
324
+ await cleanupLock();
325
+ process.exit(143);
326
+ });
136
327
  process.stdin.setRawMode?.(true);
137
328
  let isFatal = false;
138
329
  const stdinReady = new ReadyManager;
@@ -213,7 +404,6 @@ async function claudeYes({
213
404
  if (!text.includes("\x1B[6n"))
214
405
  return;
215
406
  const { col, row } = terminalRender.getCursorPosition();
216
- console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);
217
407
  shell.write(`\x1B[${row};${col}R`);
218
408
  }).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
219
409
  if (cli === "codex")
@@ -243,11 +433,15 @@ async function claudeYes({
243
433
  await sendMessage(prompt);
244
434
  const exitCode = await pendingExitCode.promise;
245
435
  console.log(`[${cli}-yes] ${cli} exited with code ${exitCode}`);
436
+ if (!disableLock && shouldUseLock(workingDir)) {
437
+ await updateCurrentTaskStatus(exitCode === 0 ? "completed" : "failed").catch(() => null);
438
+ await releaseLock().catch(() => null);
439
+ }
246
440
  if (logFile) {
247
441
  verbose && console.log(`[${cli}-yes] Writing rendered logs to ${logFile}`);
248
- const logFilePath = path.resolve(logFile);
249
- await mkdir(path.dirname(logFilePath), { recursive: true }).catch(() => null);
250
- await writeFile(logFilePath, terminalRender.render());
442
+ const logFilePath = path2.resolve(logFile);
443
+ await mkdir2(path2.dirname(logFilePath), { recursive: true }).catch(() => null);
444
+ await writeFile2(logFilePath, terminalRender.render());
251
445
  }
252
446
  return { exitCode, logs: terminalRender.render() };
253
447
  async function sendEnter(waitms = 1000) {
@@ -299,13 +493,14 @@ function tryCatch(fn, catchFn) {
299
493
  var argv = yargs(hideBin(process.argv)).usage("Usage: $0 [options] [claude args] [--] [prompts...]").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("continue-on-crash", {
300
494
  type: "boolean",
301
495
  default: true,
302
- description: "spawn Claude with --continue if it crashes, only works for claude"
496
+ description: "spawn Claude with --continue if it crashes, only works for claude",
497
+ alias: "c"
303
498
  }).option("log-file", {
304
499
  type: "string",
305
500
  description: "Log file to write to"
306
501
  }).option("cli", {
307
502
  type: "string",
308
- description: 'Claude CLI command, e.g. "claude,gemini,codex,cursor,copilot", default is "claude"'
503
+ description: 'CLI command to run. Supports: claude, gemini, codex, copilot, cursor, grok. Defaults to the CLI inferred from the executable name or "claude".'
309
504
  }).option("prompt", {
310
505
  type: "string",
311
506
  description: "Prompt to send to Claude",
@@ -316,8 +511,13 @@ var argv = yargs(hideBin(process.argv)).usage("Usage: $0 [options] [claude args]
316
511
  default: false
317
512
  }).option("exit-on-idle", {
318
513
  type: "string",
319
- description: 'Exit after a period of inactivity, e.g., "5s" or "1m"'
320
- }).parserConfiguration({
514
+ description: 'Exit after a period of inactivity, e.g., "5s" or "1m"',
515
+ alias: "e"
516
+ }).option("disable-lock", {
517
+ type: "boolean",
518
+ description: "Disable the running lock feature that prevents concurrent agents in the same directory/repo",
519
+ default: false
520
+ }).help().version().parserConfiguration({
321
521
  "unknown-options-as-args": true,
322
522
  "halt-at-non-option": true
323
523
  }).parseSync();
@@ -344,9 +544,10 @@ var { exitCode, logs } = await claudeYes({
344
544
  cliArgs: cliArgsForSpawn,
345
545
  continueOnCrash: argv.continueOnCrash,
346
546
  logFile: argv.logFile,
347
- verbose: argv.verbose
547
+ verbose: argv.verbose,
548
+ disableLock: argv.disableLock
348
549
  });
349
550
  process.exit(exitCode ?? 1);
350
551
 
351
- //# debugId=C28320E15F2B1F0F64756E2164756E21
552
+ //# debugId=4BC661A586B1849964756E2164756E21
352
553
  //# sourceMappingURL=cli.js.map
@@ -25,11 +25,16 @@ import { hideBin } from "yargs/helpers";
25
25
 
26
26
  // dist/index.js
27
27
  import { fromReadable, fromWritable } from "from-node-stream";
28
- import { mkdir, writeFile } from "fs/promises";
29
- import path from "path";
28
+ import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
29
+ import path2 from "path";
30
30
  import DIE from "phpdie";
31
31
  import sflow from "sflow";
32
32
  import { TerminalTextRender } from "terminal-render";
33
+ import { execSync } from "child_process";
34
+ import { existsSync } from "fs";
35
+ import { mkdir, readFile, rename, writeFile } from "fs/promises";
36
+ import { homedir } from "os";
37
+ import path from "path";
33
38
  class IdleWaiter {
34
39
  lastActivityTime = Date.now();
35
40
  checkInterval = 100;
@@ -67,6 +72,169 @@ class ReadyManager {
67
72
  function removeControlCharacters(str) {
68
73
  return str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
69
74
  }
75
+ var LOCK_DIR = path.join(homedir(), ".claude-yes");
76
+ var LOCK_FILE = path.join(LOCK_DIR, "running.lock.json");
77
+ var MAX_RETRIES = 5;
78
+ var RETRY_DELAYS = [50, 100, 200, 400, 800];
79
+ var POLL_INTERVAL = 2000;
80
+ function isProcessRunning(pid) {
81
+ try {
82
+ process.kill(pid, 0);
83
+ return true;
84
+ } catch {
85
+ return false;
86
+ }
87
+ }
88
+ function getGitRoot(cwd) {
89
+ try {
90
+ const result = execSync("git rev-parse --show-toplevel", {
91
+ cwd,
92
+ encoding: "utf8",
93
+ stdio: ["pipe", "pipe", "ignore"]
94
+ });
95
+ return result.trim();
96
+ } catch {
97
+ return null;
98
+ }
99
+ }
100
+ function isGitRepo(cwd) {
101
+ try {
102
+ const gitRoot = getGitRoot(cwd);
103
+ return gitRoot !== null;
104
+ } catch {
105
+ return false;
106
+ }
107
+ }
108
+ function resolveRealPath(p) {
109
+ try {
110
+ return path.resolve(p);
111
+ } catch {
112
+ return p;
113
+ }
114
+ }
115
+ function sleep(ms) {
116
+ return new Promise((resolve) => setTimeout(resolve, ms));
117
+ }
118
+ async function readLockFile() {
119
+ try {
120
+ await mkdir(LOCK_DIR, { recursive: true });
121
+ if (!existsSync(LOCK_FILE)) {
122
+ return { tasks: [] };
123
+ }
124
+ const content = await readFile(LOCK_FILE, "utf8");
125
+ const lockFile = JSON.parse(content);
126
+ lockFile.tasks = lockFile.tasks.filter((task) => {
127
+ if (isProcessRunning(task.pid))
128
+ return true;
129
+ return false;
130
+ });
131
+ return lockFile;
132
+ } catch (error) {
133
+ return { tasks: [] };
134
+ }
135
+ }
136
+ async function writeLockFile(lockFile, retryCount = 0) {
137
+ try {
138
+ await mkdir(LOCK_DIR, { recursive: true });
139
+ const tempFile = `${LOCK_FILE}.tmp.${process.pid}`;
140
+ await writeFile(tempFile, JSON.stringify(lockFile, null, 2), "utf8");
141
+ await rename(tempFile, LOCK_FILE);
142
+ } catch (error) {
143
+ if (retryCount < MAX_RETRIES) {
144
+ await sleep(RETRY_DELAYS[retryCount] || 800);
145
+ return writeLockFile(lockFile, retryCount + 1);
146
+ }
147
+ throw error;
148
+ }
149
+ }
150
+ async function checkLock(cwd, prompt) {
151
+ const resolvedCwd = resolveRealPath(cwd);
152
+ const gitRoot = isGitRepo(resolvedCwd) ? getGitRoot(resolvedCwd) : null;
153
+ const lockKey = gitRoot || resolvedCwd;
154
+ const lockFile = await readLockFile();
155
+ const blockingTasks = lockFile.tasks.filter((task) => {
156
+ if (!isProcessRunning(task.pid))
157
+ return false;
158
+ if (task.status !== "running")
159
+ return false;
160
+ if (gitRoot && task.gitRoot) {
161
+ return task.gitRoot === gitRoot;
162
+ } else {
163
+ return task.cwd === lockKey;
164
+ }
165
+ });
166
+ return {
167
+ isLocked: blockingTasks.length > 0,
168
+ blockingTasks,
169
+ lockKey
170
+ };
171
+ }
172
+ async function addTask(task) {
173
+ const lockFile = await readLockFile();
174
+ lockFile.tasks = lockFile.tasks.filter((t) => t.pid !== task.pid);
175
+ lockFile.tasks.push(task);
176
+ await writeLockFile(lockFile);
177
+ }
178
+ async function updateTaskStatus(pid, status) {
179
+ const lockFile = await readLockFile();
180
+ const task = lockFile.tasks.find((t) => t.pid === pid);
181
+ if (task) {
182
+ task.status = status;
183
+ await writeLockFile(lockFile);
184
+ }
185
+ }
186
+ async function removeTask(pid) {
187
+ const lockFile = await readLockFile();
188
+ lockFile.tasks = lockFile.tasks.filter((t) => t.pid !== pid);
189
+ await writeLockFile(lockFile);
190
+ }
191
+ async function waitForUnlock(blockingTasks, currentTask) {
192
+ const blockingTask = blockingTasks[0];
193
+ console.log(`⏳ Queueing for unlock of: ${blockingTask.task}`);
194
+ await addTask({ ...currentTask, status: "queued" });
195
+ let dots = 0;
196
+ while (true) {
197
+ await sleep(POLL_INTERVAL);
198
+ const lockCheck = await checkLock(currentTask.cwd, currentTask.task);
199
+ if (!lockCheck.isLocked) {
200
+ await updateTaskStatus(currentTask.pid, "running");
201
+ console.log(`
202
+ ✓ Lock released, starting task...`);
203
+ break;
204
+ }
205
+ dots = (dots + 1) % 4;
206
+ process.stdout.write(`\r⏳ Queueing${".".repeat(dots)}${" ".repeat(3 - dots)}`);
207
+ }
208
+ }
209
+ async function acquireLock(cwd, prompt = "no prompt provided") {
210
+ const resolvedCwd = resolveRealPath(cwd);
211
+ const gitRoot = isGitRepo(resolvedCwd) ? getGitRoot(resolvedCwd) : null;
212
+ const task = {
213
+ cwd: resolvedCwd,
214
+ gitRoot: gitRoot || undefined,
215
+ task: prompt.substring(0, 100),
216
+ pid: process.pid,
217
+ status: "running",
218
+ startedAt: Date.now(),
219
+ lockedAt: Date.now()
220
+ };
221
+ const lockCheck = await checkLock(resolvedCwd, prompt);
222
+ if (lockCheck.isLocked) {
223
+ await waitForUnlock(lockCheck.blockingTasks, task);
224
+ } else {
225
+ await addTask(task);
226
+ }
227
+ }
228
+ async function releaseLock(pid = process.pid) {
229
+ await removeTask(pid);
230
+ }
231
+ async function updateCurrentTaskStatus(status, pid = process.pid) {
232
+ await updateTaskStatus(pid, status);
233
+ }
234
+ function shouldUseLock(cwd) {
235
+ const resolvedCwd = resolveRealPath(cwd);
236
+ return true;
237
+ }
70
238
  var CLI_CONFIGURES = {
71
239
  grok: {
72
240
  install: "npm install -g @vibe-kit/grok-cli",
@@ -104,7 +272,7 @@ var CLI_CONFIGURES = {
104
272
  },
105
273
  copilot: {
106
274
  install: "npm install -g @github/copilot",
107
- ready: [/^ > /],
275
+ ready: [/^ +> /, /Ctrl\+c Exit/],
108
276
  enter: [/ │ ❯ 1. Yes, proceed/, /❯ 1. Yes/],
109
277
  fatal: []
110
278
  },
@@ -126,13 +294,36 @@ async function claudeYes({
126
294
  exitOnIdle,
127
295
  logFile,
128
296
  removeControlCharactersFromStdout = false,
129
- verbose = false
297
+ verbose = false,
298
+ disableLock = false
130
299
  } = {}) {
131
300
  const continueArgs = {
132
301
  codex: "resume --last".split(" "),
133
302
  claude: "--continue".split(" "),
134
303
  gemini: []
135
304
  };
305
+ const workingDir = cwd ?? process.cwd();
306
+ if (!disableLock && shouldUseLock(workingDir)) {
307
+ await acquireLock(workingDir, prompt ?? "Interactive session");
308
+ }
309
+ const cleanupLock = async () => {
310
+ if (!disableLock && shouldUseLock(workingDir)) {
311
+ await releaseLock().catch(() => null);
312
+ }
313
+ };
314
+ process.on("exit", () => {
315
+ if (!disableLock) {
316
+ releaseLock().catch(() => null);
317
+ }
318
+ });
319
+ process.on("SIGINT", async () => {
320
+ await cleanupLock();
321
+ process.exit(130);
322
+ });
323
+ process.on("SIGTERM", async () => {
324
+ await cleanupLock();
325
+ process.exit(143);
326
+ });
136
327
  process.stdin.setRawMode?.(true);
137
328
  let isFatal = false;
138
329
  const stdinReady = new ReadyManager;
@@ -213,7 +404,6 @@ async function claudeYes({
213
404
  if (!text.includes("\x1B[6n"))
214
405
  return;
215
406
  const { col, row } = terminalRender.getCursorPosition();
216
- console.log(`[${cli}-yes] Responding cursor position: row=${row}, col=${col}`);
217
407
  shell.write(`\x1B[${row};${col}R`);
218
408
  }).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
219
409
  if (cli === "codex")
@@ -243,11 +433,15 @@ async function claudeYes({
243
433
  await sendMessage(prompt);
244
434
  const exitCode = await pendingExitCode.promise;
245
435
  console.log(`[${cli}-yes] ${cli} exited with code ${exitCode}`);
436
+ if (!disableLock && shouldUseLock(workingDir)) {
437
+ await updateCurrentTaskStatus(exitCode === 0 ? "completed" : "failed").catch(() => null);
438
+ await releaseLock().catch(() => null);
439
+ }
246
440
  if (logFile) {
247
441
  verbose && console.log(`[${cli}-yes] Writing rendered logs to ${logFile}`);
248
- const logFilePath = path.resolve(logFile);
249
- await mkdir(path.dirname(logFilePath), { recursive: true }).catch(() => null);
250
- await writeFile(logFilePath, terminalRender.render());
442
+ const logFilePath = path2.resolve(logFile);
443
+ await mkdir2(path2.dirname(logFilePath), { recursive: true }).catch(() => null);
444
+ await writeFile2(logFilePath, terminalRender.render());
251
445
  }
252
446
  return { exitCode, logs: terminalRender.render() };
253
447
  async function sendEnter(waitms = 1000) {
@@ -299,13 +493,14 @@ function tryCatch(fn, catchFn) {
299
493
  var argv = yargs(hideBin(process.argv)).usage("Usage: $0 [options] [claude args] [--] [prompts...]").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("continue-on-crash", {
300
494
  type: "boolean",
301
495
  default: true,
302
- description: "spawn Claude with --continue if it crashes, only works for claude"
496
+ description: "spawn Claude with --continue if it crashes, only works for claude",
497
+ alias: "c"
303
498
  }).option("log-file", {
304
499
  type: "string",
305
500
  description: "Log file to write to"
306
501
  }).option("cli", {
307
502
  type: "string",
308
- description: 'Claude CLI command, e.g. "claude,gemini,codex,cursor,copilot", default is "claude"'
503
+ description: 'CLI command to run. Supports: claude, gemini, codex, copilot, cursor, grok. Defaults to the CLI inferred from the executable name or "claude".'
309
504
  }).option("prompt", {
310
505
  type: "string",
311
506
  description: "Prompt to send to Claude",
@@ -316,8 +511,13 @@ var argv = yargs(hideBin(process.argv)).usage("Usage: $0 [options] [claude args]
316
511
  default: false
317
512
  }).option("exit-on-idle", {
318
513
  type: "string",
319
- description: 'Exit after a period of inactivity, e.g., "5s" or "1m"'
320
- }).parserConfiguration({
514
+ description: 'Exit after a period of inactivity, e.g., "5s" or "1m"',
515
+ alias: "e"
516
+ }).option("disable-lock", {
517
+ type: "boolean",
518
+ description: "Disable the running lock feature that prevents concurrent agents in the same directory/repo",
519
+ default: false
520
+ }).help().version().parserConfiguration({
321
521
  "unknown-options-as-args": true,
322
522
  "halt-at-non-option": true
323
523
  }).parseSync();
@@ -344,9 +544,10 @@ var { exitCode, logs } = await claudeYes({
344
544
  cliArgs: cliArgsForSpawn,
345
545
  continueOnCrash: argv.continueOnCrash,
346
546
  logFile: argv.logFile,
347
- verbose: argv.verbose
547
+ verbose: argv.verbose,
548
+ disableLock: argv.disableLock
348
549
  });
349
550
  process.exit(exitCode ?? 1);
350
551
 
351
- //# debugId=C28320E15F2B1F0F64756E2164756E21
552
+ //# debugId=4BC661A586B1849964756E2164756E21
352
553
  //# sourceMappingURL=cli.js.map