claude-yes 1.24.1 → 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/dist/index.js CHANGED
@@ -4826,7 +4826,7 @@ function fromWritable(i) {
4826
4826
  });
4827
4827
  }
4828
4828
 
4829
- // index.ts
4829
+ // ts/index.ts
4830
4830
  import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
4831
4831
  import path3 from "path";
4832
4832
 
@@ -5234,7 +5234,75 @@ class TerminalTextRender {
5234
5234
  }
5235
5235
  }
5236
5236
 
5237
- // idleWaiter.ts
5237
+ // ts/defineConfig.ts
5238
+ async function defineCliYesConfig(cfg) {
5239
+ if (typeof cfg === "function")
5240
+ cfg = await cfg({ clis: {} });
5241
+ return cfg;
5242
+ }
5243
+
5244
+ // cli-yes.config.ts
5245
+ process.env.VERBOSE && console.log("loading cli-yes.config.ts from " + import.meta.url);
5246
+ var cli_yes_config_default = defineCliYesConfig({
5247
+ clis: {
5248
+ qwen: {
5249
+ install: "npm install -g @qwen-code/qwen-code@latest",
5250
+ version: "qwen --version"
5251
+ },
5252
+ grok: {
5253
+ install: "npm install -g @vibe-kit/grok-cli",
5254
+ ready: [/^ │ ❯ /],
5255
+ enter: [/^ 1. Yes/]
5256
+ },
5257
+ claude: {
5258
+ promptArg: "first-arg",
5259
+ install: "npm install -g @anthropic-ai/claude-code",
5260
+ restoreArgs: ["--continue"],
5261
+ ready: [/\? for shortcuts/],
5262
+ enter: [/❯ 1. Yes/, /❯ 1. Dark mode✔/, /Press Enter to continue…/],
5263
+ fatal: [
5264
+ /No conversation found to continue/,
5265
+ /⎿ Claude usage limit reached\./,
5266
+ /^error: unknown option/
5267
+ ],
5268
+ defaultArgs: ["--model=sonnet"]
5269
+ },
5270
+ gemini: {
5271
+ install: "npm install -g @google/gemini-cli",
5272
+ ready: [/Type your message/],
5273
+ enter: [/│ ● 1. Yes, allow once/],
5274
+ fatal: []
5275
+ },
5276
+ codex: {
5277
+ promptArg: "first-arg",
5278
+ install: "npm install -g @openai/codex-cli",
5279
+ ready: [/⏎ send/],
5280
+ enter: [
5281
+ /> 1. Yes, allow Codex to work in this folder/,
5282
+ /> 1. Approve and run now/
5283
+ ],
5284
+ fatal: [/Error: The cursor position could not be read within/],
5285
+ defaultArgs: ["--search"],
5286
+ noEOL: true
5287
+ },
5288
+ copilot: {
5289
+ promptArg: "--prompt",
5290
+ install: "npm install -g @github/copilot",
5291
+ ready: [/^ +> /, /Ctrl\+c Exit/],
5292
+ enter: [/ │ ❯ 1. Yes, proceed/, /❯ 1. Yes/],
5293
+ fatal: []
5294
+ },
5295
+ cursor: {
5296
+ install: "open https://cursor.com/ja/docs/cli/installation",
5297
+ binary: "cursor-agent",
5298
+ ready: [/\/ commands/],
5299
+ enter: [/→ Run \(once\) \(y\) \(enter\)/, /▶ \[a\] Trust this workspace/],
5300
+ fatal: [/^ Error: You've hit your usage limit/]
5301
+ }
5302
+ }
5303
+ });
5304
+
5305
+ // ts/idleWaiter.ts
5238
5306
  class IdleWaiter {
5239
5307
  lastActivityTime = Date.now();
5240
5308
  checkInterval = 100;
@@ -5251,7 +5319,7 @@ class IdleWaiter {
5251
5319
  }
5252
5320
  }
5253
5321
 
5254
- // ReadyManager.ts
5322
+ // ts/ReadyManager.ts
5255
5323
  class ReadyManager {
5256
5324
  isReady = false;
5257
5325
  readyQueue = [];
@@ -5271,12 +5339,12 @@ class ReadyManager {
5271
5339
  }
5272
5340
  }
5273
5341
 
5274
- // removeControlCharacters.ts
5342
+ // ts/removeControlCharacters.ts
5275
5343
  function removeControlCharacters(str) {
5276
5344
  return str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
5277
5345
  }
5278
5346
 
5279
- // runningLock.ts
5347
+ // ts/runningLock.ts
5280
5348
  import { execSync } from "child_process";
5281
5349
  import { existsSync } from "fs";
5282
5350
  import { mkdir, readFile, rename, writeFile } from "fs/promises";
@@ -5400,10 +5468,47 @@ async function removeTask(pid) {
5400
5468
  }
5401
5469
  async function waitForUnlock(blockingTasks, currentTask) {
5402
5470
  const blockingTask = blockingTasks[0];
5471
+ if (!blockingTask)
5472
+ return;
5403
5473
  console.log(`⏳ Queueing for unlock of: ${blockingTask.task}`);
5474
+ console.log(` Press 'b' to bypass queue, 'k' to kill previous instance`);
5404
5475
  await addTask({ ...currentTask, status: "queued" });
5476
+ const stdin = process.stdin;
5477
+ const wasRaw = stdin.isRaw;
5478
+ stdin.setRawMode?.(true);
5479
+ stdin.resume();
5480
+ let bypassed = false;
5481
+ let killed = false;
5482
+ const keyHandler = (key) => {
5483
+ const char = key.toString();
5484
+ if (char === "b" || char === "B") {
5485
+ console.log(`
5486
+ ⚡ Bypassing queue...`);
5487
+ bypassed = true;
5488
+ } else if (char === "k" || char === "K") {
5489
+ console.log(`
5490
+ \uD83D\uDD2A Killing previous instance...`);
5491
+ killed = true;
5492
+ }
5493
+ };
5494
+ stdin.on("data", keyHandler);
5405
5495
  let dots = 0;
5406
5496
  while (true) {
5497
+ if (bypassed) {
5498
+ await updateTaskStatus(currentTask.pid, "running");
5499
+ console.log("✓ Queue bypassed, starting task...");
5500
+ break;
5501
+ }
5502
+ if (killed && blockingTask) {
5503
+ try {
5504
+ process.kill(blockingTask.pid, "SIGTERM");
5505
+ console.log(`✓ Killed process ${blockingTask.pid}`);
5506
+ await sleep2(1000);
5507
+ } catch (err) {
5508
+ console.log(`⚠️ Could not kill process ${blockingTask.pid}: ${err}`);
5509
+ }
5510
+ killed = false;
5511
+ }
5407
5512
  await sleep2(POLL_INTERVAL);
5408
5513
  const lockCheck = await checkLock(currentTask.cwd, currentTask.task);
5409
5514
  if (!lockCheck.isLocked) {
@@ -5415,6 +5520,10 @@ async function waitForUnlock(blockingTasks, currentTask) {
5415
5520
  dots = (dots + 1) % 4;
5416
5521
  process.stdout.write(`\r⏳ Queueing${".".repeat(dots)}${" ".repeat(3 - dots)}`);
5417
5522
  }
5523
+ stdin.off("data", keyHandler);
5524
+ stdin.setRawMode?.(wasRaw);
5525
+ if (!wasRaw)
5526
+ stdin.pause();
5418
5527
  }
5419
5528
  async function acquireLock(cwd, prompt = "no prompt provided") {
5420
5529
  const resolvedCwd = resolveRealPath(cwd);
@@ -5446,96 +5555,106 @@ function shouldUseLock(cwd) {
5446
5555
  return true;
5447
5556
  }
5448
5557
 
5449
- // index.ts
5450
- var CLI_CONFIGURES = {
5451
- grok: {
5452
- install: "npm install -g @vibe-kit/grok-cli",
5453
- ready: [/^ /],
5454
- enter: [/^ 1. Yes/]
5455
- },
5456
- claude: {
5457
- install: "npm install -g @anthropic-ai/claude-code",
5458
- ready: [/\? for shortcuts/],
5459
- enter: [/❯ 1. Yes/, /❯ 1. Dark mode✔/, /Press Enter to continue…/],
5460
- fatal: [
5461
- /No conversation found to continue/,
5462
- /⎿ Claude usage limit reached\./
5463
- ]
5464
- },
5465
- gemini: {
5466
- install: "npm install -g @google/gemini-cli",
5467
- ready: [/Type your message/],
5468
- enter: [/│ ● 1. Yes, allow once/],
5469
- fatal: []
5470
- },
5471
- codex: {
5472
- install: "npm install -g @openai/codex-cli",
5473
- ready: [/⏎ send/],
5474
- enter: [
5475
- /> 1. Yes, allow Codex to work in this folder/,
5476
- /> 1. Approve and run now/
5477
- ],
5478
- fatal: [/Error: The cursor position could not be read within/],
5479
- ensureArgs: (args) => {
5480
- if (!args.includes("--search"))
5481
- return ["--search", ...args];
5482
- return args;
5558
+ // ts/tryCatch.ts
5559
+ function catcher(catchFn, fn) {
5560
+ if (!fn)
5561
+ return (fn2) => catcher(catchFn, fn2);
5562
+ return (...args) => {
5563
+ try {
5564
+ return fn(...args);
5565
+ } catch (error) {
5566
+ return catchFn(error);
5483
5567
  }
5484
- },
5485
- copilot: {
5486
- install: "npm install -g @github/copilot",
5487
- ready: [/^ +> /, /Ctrl\+c Exit/],
5488
- enter: [/ │ ❯ 1. Yes, proceed/, /❯ 1. Yes/],
5489
- fatal: []
5490
- },
5491
- cursor: {
5492
- install: "open https://cursor.com/ja/docs/cli/installation",
5493
- binary: "cursor-agent",
5494
- ready: [/\/ commands/],
5495
- enter: [/→ Run \(once\) \(y\) \(enter\)/, /▶ \[a\] Trust this workspace/],
5496
- fatal: [/^ Error: You've hit your usage limit/]
5497
- }
5498
- };
5499
- async function claudeYes({
5500
- cli = "claude",
5568
+ };
5569
+ }
5570
+
5571
+ // ts/yesLog.ts
5572
+ import { appendFileSync, rmSync } from "node:fs";
5573
+
5574
+ // node_modules/tsa-composer/dist/index.js
5575
+ function tsaStringJoiner(tsa, ...slots) {
5576
+ return [tsa.reduce((acc, s, i) => acc + s + (slots[i] ?? ""), "")];
5577
+ }
5578
+ function tsaComposer(parse, fn) {
5579
+ if (!parse)
5580
+ return tsaComposer(tsaStringJoiner);
5581
+ if (!fn)
5582
+ return (fn2) => tsaComposer(parse, fn2);
5583
+ const composedFn = function(...args) {
5584
+ const [tsa, ...slots] = args;
5585
+ if (!isTSA(tsa))
5586
+ return fn(...args);
5587
+ return fn(...parse(tsa, ...slots));
5588
+ };
5589
+ Object.setPrototypeOf(composedFn, fn);
5590
+ Object.getOwnPropertyNames(fn).forEach((prop2) => {
5591
+ if (prop2 !== "length" && prop2 !== "name" && prop2 !== "prototype") {
5592
+ Object.defineProperty(composedFn, prop2, Object.getOwnPropertyDescriptor(fn, prop2));
5593
+ }
5594
+ });
5595
+ return composedFn;
5596
+ }
5597
+ function isTSA(tsa) {
5598
+ return Array.isArray(tsa) && "raw" in tsa && Array.isArray(tsa.raw);
5599
+ }
5600
+
5601
+ // ts/yesLog.ts
5602
+ var initial = true;
5603
+ var yesLog = tsaComposer()(catcher((error) => {
5604
+ console.error("yesLog error:", error);
5605
+ }, function yesLog2(msg) {
5606
+ if (!process.env.VERBOSE)
5607
+ return;
5608
+ if (initial)
5609
+ rmSync("./agent-yes.log");
5610
+ initial = false;
5611
+ appendFileSync("./agent-yes.log", `${msg}
5612
+ `);
5613
+ }));
5614
+
5615
+ // ts/index.ts
5616
+ var config = await cli_yes_config_default;
5617
+ var CLIS_CONFIG = config.clis;
5618
+ var SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
5619
+ async function cliYes({
5620
+ cli,
5501
5621
  cliArgs = [],
5502
5622
  prompt,
5503
- continueOnCrash,
5623
+ robust = true,
5504
5624
  cwd,
5505
5625
  env,
5506
5626
  exitOnIdle,
5507
5627
  logFile,
5508
5628
  removeControlCharactersFromStdout = false,
5509
5629
  verbose = false,
5510
- disableLock = false
5511
- } = {}) {
5512
- const continueArgs = {
5513
- codex: "resume --last".split(" "),
5514
- claude: "--continue".split(" "),
5515
- gemini: []
5516
- };
5630
+ queue = true
5631
+ }) {
5632
+ if (!cli)
5633
+ throw new Error(`cli is required`);
5634
+ const conf = CLIS_CONFIG[cli] || phpdie_default2(`Unsupported cli tool: ${cli}`);
5517
5635
  const workingDir = cwd ?? process.cwd();
5518
- if (!disableLock && shouldUseLock(workingDir)) {
5519
- await acquireLock(workingDir, prompt ?? "Interactive session");
5520
- }
5521
- const cleanupLock = async () => {
5522
- if (!disableLock && shouldUseLock(workingDir)) {
5523
- await releaseLock().catch(() => null);
5636
+ if (queue) {
5637
+ if (queue && shouldUseLock(workingDir)) {
5638
+ await acquireLock(workingDir, prompt ?? "Interactive session");
5524
5639
  }
5525
- };
5526
- process.on("exit", () => {
5527
- if (!disableLock) {
5528
- releaseLock().catch(() => null);
5529
- }
5530
- });
5531
- process.on("SIGINT", async () => {
5532
- await cleanupLock();
5533
- process.exit(130);
5534
- });
5535
- process.on("SIGTERM", async () => {
5536
- await cleanupLock();
5537
- process.exit(143);
5538
- });
5640
+ const cleanupLock = async () => {
5641
+ if (queue && shouldUseLock(workingDir)) {
5642
+ await releaseLock().catch(() => null);
5643
+ }
5644
+ };
5645
+ process.on("exit", () => {
5646
+ if (queue)
5647
+ releaseLock().catch(() => null);
5648
+ });
5649
+ process.on("SIGINT", async (code) => {
5650
+ await cleanupLock();
5651
+ process.exit(code);
5652
+ });
5653
+ process.on("SIGTERM", async (code) => {
5654
+ await cleanupLock();
5655
+ process.exit(code);
5656
+ });
5657
+ }
5539
5658
  process.stdin.setRawMode?.(true);
5540
5659
  let isFatal = false;
5541
5660
  const stdinReady = new ReadyManager;
@@ -5549,36 +5668,53 @@ async function claudeYes({
5549
5668
  cwd: cwd ?? process.cwd(),
5550
5669
  env: env ?? process.env
5551
5670
  });
5552
- const cliConf = CLI_CONFIGURES[cli] || {};
5553
- cliArgs = cliConf.ensureArgs?.(cliArgs) ?? cliArgs;
5671
+ const cliConf = CLIS_CONFIG[cli] || {};
5672
+ cliArgs = cliConf.defaultArgs ? [...cliConf.defaultArgs, ...cliArgs] : cliArgs;
5673
+ if (prompt && cliConf.promptArg) {
5674
+ if (cliConf.promptArg === "first-arg") {
5675
+ cliArgs = [prompt, ...cliArgs];
5676
+ prompt = undefined;
5677
+ } else if (cliConf.promptArg === "last-arg") {
5678
+ cliArgs = [...cliArgs, prompt];
5679
+ prompt = undefined;
5680
+ } else if (cliConf.promptArg.startsWith("--")) {
5681
+ cliArgs = [cliConf.promptArg, prompt, ...cliArgs];
5682
+ prompt = undefined;
5683
+ } else {
5684
+ console.warn(`Unknown promptArg format: ${cliConf.promptArg}`);
5685
+ }
5686
+ }
5554
5687
  const cliCommand = cliConf?.binary || cli;
5555
- let shell = tryCatch(() => pty.spawn(cliCommand, cliArgs, getPtyOptions()), (error) => {
5688
+ let shell = catcher((error) => {
5556
5689
  console.error(`Fatal: Failed to start ${cliCommand}.`);
5557
- if (cliConf?.install)
5690
+ if (cliConf?.install && isCommandNotFoundError(error))
5558
5691
  console.error(`If you did not installed it yet, Please install it first: ${cliConf.install}`);
5559
5692
  throw error;
5560
- });
5693
+ function isCommandNotFoundError(e) {
5694
+ if (e instanceof Error) {
5695
+ return e.message.includes("command not found") || e.message.includes("ENOENT") || e.message.includes("spawn");
5696
+ }
5697
+ return false;
5698
+ }
5699
+ }, () => pty.spawn(cliCommand, cliArgs, getPtyOptions()))();
5561
5700
  const pendingExitCode = Promise.withResolvers();
5562
5701
  let pendingExitCodeValue = null;
5563
5702
  async function onData(data) {
5564
- nextStdout.ready();
5565
5703
  await outputWriter.write(data);
5566
5704
  }
5567
5705
  shell.onData(onData);
5568
5706
  shell.onExit(function onExit({ exitCode: exitCode2 }) {
5569
- nextStdout.ready();
5570
5707
  stdinReady.unready();
5571
5708
  const agentCrashed = exitCode2 !== 0;
5572
- const continueArg = continueArgs[cli];
5573
- if (agentCrashed && continueOnCrash && continueArg) {
5574
- if (!continueArg) {
5575
- return console.warn(`continueOnCrash is only supported for ${Object.keys(continueArgs).join(", ")} currently, not ${cli}`);
5709
+ if (agentCrashed && robust && conf?.restoreArgs) {
5710
+ if (!conf.restoreArgs) {
5711
+ return console.warn(`robust is only supported for ${Object.entries(CLIS_CONFIG).filter(([_, v]) => v.restoreArgs).map(([k]) => k).join(", ")} currently, not ${cli}`);
5576
5712
  }
5577
5713
  if (isFatal) {
5578
5714
  return pendingExitCode.resolve(pendingExitCodeValue = exitCode2);
5579
5715
  }
5580
5716
  console.log(`${cli} crashed, restarting...`);
5581
- shell = pty.spawn(cli, continueArg, getPtyOptions());
5717
+ shell = pty.spawn(cli, conf.restoreArgs, getPtyOptions());
5582
5718
  shell.onData(onData);
5583
5719
  shell.onExit(onExit);
5584
5720
  return;
@@ -5609,7 +5745,7 @@ async function claudeYes({
5609
5745
  }
5610
5746
  }),
5611
5747
  readable: shellOutputStream.readable
5612
- }).forEach(() => idleWaiter.ping()).forEach((text) => {
5748
+ }).forEach(() => idleWaiter.ping()).forEach(() => nextStdout.ready()).forEach(async (text) => {
5613
5749
  terminalRender.write(text);
5614
5750
  if (process.stdin.isTTY)
5615
5751
  return;
@@ -5617,24 +5753,25 @@ async function claudeYes({
5617
5753
  return;
5618
5754
  const { col, row } = terminalRender.getCursorPosition();
5619
5755
  shell.write(`\x1B[${row};${col}R`);
5756
+ await yesLog`cursor|respond position: row=${String(row)}, col=${String(col)}`;
5620
5757
  }).forkTo((e) => e.map((e2) => removeControlCharacters(e2)).map((e2) => e2.replaceAll("\r", "")).by((s) => {
5621
- if (cli === "codex")
5758
+ if (conf.noEOL)
5622
5759
  return s;
5623
5760
  return s.lines({ EOL: "NONE" });
5624
- }).forEach(async (e2, i) => {
5625
- const conf = CLI_CONFIGURES[cli] || null;
5626
- if (!conf)
5627
- return;
5761
+ }).forEach((e2) => yesLog`output|${e2}`).forEach(async (e2, i) => {
5628
5762
  if (conf.ready?.some((rx) => e2.match(rx))) {
5763
+ await yesLog`ready |${e2}`;
5629
5764
  if (cli === "gemini" && i <= 80)
5630
5765
  return;
5631
5766
  stdinReady.ready();
5632
5767
  }
5633
5768
  if (conf.enter?.some((rx) => e2.match(rx))) {
5769
+ await yesLog`enter |${e2}`;
5634
5770
  await sendEnter(300);
5635
5771
  return;
5636
5772
  }
5637
5773
  if (conf.fatal?.some((rx) => e2.match(rx))) {
5774
+ await yesLog`fatal |${e2}`;
5638
5775
  isFatal = true;
5639
5776
  await exitAgent();
5640
5777
  }
@@ -5645,7 +5782,7 @@ async function claudeYes({
5645
5782
  await sendMessage(prompt);
5646
5783
  const exitCode = await pendingExitCode.promise;
5647
5784
  console.log(`[${cli}-yes] ${cli} exited with code ${exitCode}`);
5648
- if (!disableLock && shouldUseLock(workingDir)) {
5785
+ if (queue && shouldUseLock(workingDir)) {
5649
5786
  await updateCurrentTaskStatus(exitCode === 0 ? "completed" : "failed").catch(() => null);
5650
5787
  await releaseLock().catch(() => null);
5651
5788
  }
@@ -5660,18 +5797,33 @@ async function claudeYes({
5660
5797
  const st = Date.now();
5661
5798
  await idleWaiter.wait(waitms);
5662
5799
  const et = Date.now();
5800
+ await yesLog`sendEn| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`;
5801
+ nextStdout.unready();
5663
5802
  shell.write("\r");
5803
+ await Promise.race([
5804
+ nextStdout.wait(),
5805
+ new Promise((resolve) => setTimeout(() => {
5806
+ if (!nextStdout.ready) {
5807
+ shell.write("\r");
5808
+ }
5809
+ resolve();
5810
+ }, 1000))
5811
+ ]);
5664
5812
  }
5665
5813
  async function sendMessage(message) {
5666
5814
  await stdinReady.wait();
5667
- shell.write(message);
5815
+ yesLog`send |${message}`;
5668
5816
  nextStdout.unready();
5817
+ shell.write(message);
5669
5818
  idleWaiter.ping();
5819
+ yesLog`waiting next stdout|${message}`;
5670
5820
  await nextStdout.wait();
5671
- await sendEnter();
5821
+ yesLog`sending enter`;
5822
+ await sendEnter(1000);
5823
+ yesLog`sent enter`;
5672
5824
  }
5673
5825
  async function exitAgent() {
5674
- continueOnCrash = false;
5826
+ robust = false;
5675
5827
  await sendMessage("/exit");
5676
5828
  let exited = false;
5677
5829
  await Promise.race([
@@ -5693,18 +5845,13 @@ async function claudeYes({
5693
5845
  };
5694
5846
  }
5695
5847
  }
5696
- function tryCatch(fn, catchFn) {
5697
- try {
5698
- return fn();
5699
- } catch (error) {
5700
- return catchFn(error);
5701
- }
5702
- }
5703
5848
  export {
5704
5849
  removeControlCharacters,
5705
- claudeYes as default,
5706
- CLI_CONFIGURES
5850
+ cliYes as default,
5851
+ config,
5852
+ SUPPORTED_CLIS,
5853
+ CLIS_CONFIG
5707
5854
  };
5708
5855
 
5709
- //# debugId=C257F9AC903EC67664756E2164756E21
5856
+ //# debugId=266F6AAC46785FCA64756E2164756E21
5710
5857
  //# sourceMappingURL=index.js.map