claude-yes 1.32.3 → 1.33.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/cli.js CHANGED
@@ -20633,16 +20633,20 @@ import { fromReadable } from "from-node-stream";
20633
20633
  import { createReadStream as createReadStream2, mkdirSync } from "fs";
20634
20634
  import { unlink } from "fs/promises";
20635
20635
  import { dirname } from "path";
20636
- function createFifoStream(cli) {
20636
+ function createFifoStream(cli, customPath) {
20637
20637
  if (process.platform !== "linux") {
20638
20638
  return null;
20639
20639
  }
20640
20640
  let fifoPath = null;
20641
20641
  let fifoStream = null;
20642
20642
  try {
20643
- const timestamp = new Date().toISOString().replace(/\D/g, "").slice(0, 17);
20644
- const randomSuffix = Math.random().toString(36).substring(2, 5);
20645
- fifoPath = `/tmp/agent-yes-${timestamp}${randomSuffix}.stdin`;
20643
+ if (customPath) {
20644
+ fifoPath = customPath;
20645
+ } else {
20646
+ const timestamp = new Date().toISOString().replace(/\D/g, "").slice(0, 17);
20647
+ const randomSuffix = Math.random().toString(36).substring(2, 5);
20648
+ fifoPath = `/tmp/agent-yes-${timestamp}${randomSuffix}.stdin`;
20649
+ }
20646
20650
  mkdirSync(dirname(fifoPath), { recursive: true });
20647
20651
  const mkfifoResult = execaCommandSync(`mkfifo ${fifoPath}`, {
20648
20652
  reject: false
@@ -20727,6 +20731,107 @@ var init_fifo = __esm(() => {
20727
20731
  init_logger();
20728
20732
  });
20729
20733
 
20734
+ // ts/pidStore.ts
20735
+ import Datastore from "@seald-io/nedb";
20736
+ import { mkdir as mkdir3 } from "fs/promises";
20737
+ import path9 from "path";
20738
+
20739
+ class PidStore {
20740
+ db;
20741
+ baseDir;
20742
+ constructor(workingDir) {
20743
+ this.baseDir = path9.resolve(workingDir, ".agent-yes");
20744
+ }
20745
+ async init() {
20746
+ await mkdir3(path9.join(this.baseDir, "logs"), { recursive: true });
20747
+ await mkdir3(path9.join(this.baseDir, "fifo"), { recursive: true });
20748
+ this.db = new Datastore({
20749
+ filename: path9.join(this.baseDir, "pid.jsonl"),
20750
+ autoload: true
20751
+ });
20752
+ await this.db.loadDatabaseAsync();
20753
+ await this.cleanStaleRecords();
20754
+ }
20755
+ async registerProcess({
20756
+ pid,
20757
+ cli,
20758
+ args,
20759
+ prompt
20760
+ }) {
20761
+ const now = Date.now();
20762
+ const record = {
20763
+ pid,
20764
+ cli,
20765
+ args,
20766
+ prompt,
20767
+ logFile: this.getLogPath(pid),
20768
+ fifoFile: this.getFifoPath(pid),
20769
+ status: "active",
20770
+ exitReason: "",
20771
+ startedAt: now,
20772
+ updatedAt: now
20773
+ };
20774
+ await this.db.insertAsync(record);
20775
+ logger.debug(`[pidStore] Registered process ${pid}`);
20776
+ return record;
20777
+ }
20778
+ async updateStatus(pid, status, extra) {
20779
+ const update2 = {
20780
+ status,
20781
+ updatedAt: Date.now(),
20782
+ ...extra
20783
+ };
20784
+ await this.db.updateAsync({ pid }, { $set: update2 }, {});
20785
+ logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
20786
+ }
20787
+ getLogPath(pid) {
20788
+ return path9.resolve(this.baseDir, "logs", `${pid}.log`);
20789
+ }
20790
+ getFifoPath(pid) {
20791
+ return path9.resolve(this.baseDir, "fifo", `${pid}.stdin`);
20792
+ }
20793
+ async cleanStaleRecords() {
20794
+ const activeRecords = await this.db.findAsync({
20795
+ status: { $ne: "exited" }
20796
+ });
20797
+ for (const record of activeRecords) {
20798
+ if (!this.isProcessAlive(record.pid)) {
20799
+ await this.db.updateAsync({ pid: record.pid }, {
20800
+ $set: {
20801
+ status: "exited",
20802
+ exitReason: "stale-cleanup",
20803
+ updatedAt: Date.now()
20804
+ }
20805
+ }, {});
20806
+ logger.debug(`[pidStore] Cleaned stale record for PID ${record.pid}`);
20807
+ }
20808
+ }
20809
+ }
20810
+ async close() {
20811
+ await this.db.compactDatafileAsync();
20812
+ logger.debug("[pidStore] Database compacted and closed");
20813
+ }
20814
+ isProcessAlive(pid) {
20815
+ try {
20816
+ process.kill(pid, 0);
20817
+ return true;
20818
+ } catch {
20819
+ return false;
20820
+ }
20821
+ }
20822
+ static async findActiveFifo(workingDir) {
20823
+ const store = new PidStore(workingDir);
20824
+ await store.init();
20825
+ const records = await store.db.findAsync({ status: { $ne: "exited" } });
20826
+ await store.close();
20827
+ const sorted = records.sort((a2, b) => b.startedAt - a2.startedAt);
20828
+ return sorted[0]?.fifoFile ?? null;
20829
+ }
20830
+ }
20831
+ var init_pidStore = __esm(() => {
20832
+ init_logger();
20833
+ });
20834
+
20730
20835
  // ts/defineConfig.ts
20731
20836
  async function defineCliYesConfig(cfg) {
20732
20837
  if (typeof cfg === "function")
@@ -20757,13 +20862,13 @@ var exports_agent_yes_config = {};
20757
20862
  __export(exports_agent_yes_config, {
20758
20863
  default: () => agent_yes_config_default
20759
20864
  });
20760
- import { mkdir as mkdir3 } from "node:fs/promises";
20865
+ import { mkdir as mkdir4 } from "node:fs/promises";
20761
20866
  import os from "node:os";
20762
- import path9 from "node:path";
20867
+ import path10 from "node:path";
20763
20868
  function getDefaultConfig() {
20764
20869
  return defineCliYesConfig({
20765
20870
  configDir,
20766
- logsDir: configDir && path9.resolve(configDir, "logs"),
20871
+ logsDir: configDir && path10.resolve(configDir, "logs"),
20767
20872
  clis: {
20768
20873
  qwen: {
20769
20874
  install: "npm install -g @qwen-code/qwen-code@latest",
@@ -20860,21 +20965,21 @@ var init_agent_yes_config = __esm(async () => {
20860
20965
  init_logger();
20861
20966
  logger.debug("loading cli-yes.config.ts from " + import.meta.url);
20862
20967
  configDir = await (async () => {
20863
- const homeConfigDir = path9.resolve(os.homedir(), ".agent-yes");
20864
- const isHomeWritable = await mkdir3(homeConfigDir, { recursive: true }).then(() => true).catch(() => false);
20968
+ const homeConfigDir = path10.resolve(os.homedir(), ".agent-yes");
20969
+ const isHomeWritable = await mkdir4(homeConfigDir, { recursive: true }).then(() => true).catch(() => false);
20865
20970
  if (isHomeWritable) {
20866
20971
  logger.debug("[config] Using home directory:", homeConfigDir);
20867
20972
  return homeConfigDir;
20868
20973
  }
20869
- const tmpConfigDir = path9.resolve("/tmp/.agent-yes");
20870
- const isWritable = await mkdir3(tmpConfigDir, { recursive: true });
20974
+ const tmpConfigDir = path10.resolve("/tmp/.agent-yes");
20975
+ const isWritable = await mkdir4(tmpConfigDir, { recursive: true });
20871
20976
  if (isWritable) {
20872
20977
  logger.debug("[config] Using workspace directory:", tmpConfigDir);
20873
20978
  return tmpConfigDir;
20874
20979
  }
20875
20980
  return;
20876
20981
  })();
20877
- agent_yes_config_default = deepMixin(await getDefaultConfig(), await import(path9.resolve(os.homedir(), ".agent-yes/config.ts")).catch(() => ({ default: {} })).then((mod) => mod.default), await import(path9.resolve(process.cwd(), "node_modules/.agent-yes/config.ts")).catch(() => ({ default: {} })).then((mod) => mod.default), await import(path9.resolve(process.cwd(), ".agent-yes/config.ts")).catch(() => ({ default: {} })).then((mod) => mod.default));
20982
+ agent_yes_config_default = deepMixin(await getDefaultConfig(), await import(path10.resolve(os.homedir(), ".agent-yes/config.ts")).catch(() => ({ default: {} })).then((mod) => mod.default), await import(path10.resolve(process.cwd(), "node_modules/.agent-yes/config.ts")).catch(() => ({ default: {} })).then((mod) => mod.default), await import(path10.resolve(process.cwd(), ".agent-yes/config.ts")).catch(() => ({ default: {} })).then((mod) => mod.default));
20878
20983
  });
20879
20984
 
20880
20985
  // ts/pty-fix.ts
@@ -21041,8 +21146,8 @@ __export(exports_ts, {
21041
21146
  CLIS_CONFIG: () => CLIS_CONFIG2
21042
21147
  });
21043
21148
  import { fromReadable as fromReadable3, fromWritable as fromWritable2 } from "from-node-stream";
21044
- import { mkdir as mkdir6, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
21045
- import path12 from "path";
21149
+ import { mkdir as mkdir7, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
21150
+ import path13 from "path";
21046
21151
  async function agentYes2({
21047
21152
  cli,
21048
21153
  cliArgs = [],
@@ -21086,6 +21191,8 @@ async function agentYes2({
21086
21191
  process.exit(code);
21087
21192
  });
21088
21193
  }
21194
+ const pidStore = new PidStore(workingDir);
21195
+ await pidStore.init();
21089
21196
  process.stdin.setRawMode?.(true);
21090
21197
  let isFatal = false;
21091
21198
  let shouldRestartWithoutContinue = false;
@@ -21101,16 +21208,10 @@ async function agentYes2({
21101
21208
  const shellOutputStream = new TransformStream;
21102
21209
  const outputWriter = shellOutputStream.writable.getWriter();
21103
21210
  logger.debug(`Using ${ptyPackage} for pseudo terminal management.`);
21104
- const datetime = new Date().toISOString().replace(/\D/g, "").slice(0, 17);
21105
- const logPath = config2.logsDir && path12.resolve(config2.logsDir, `${cli}-yes-${datetime}.log`);
21106
- const rawLogPath = config2.logsDir && path12.resolve(config2.logsDir, `${cli}-yes-${datetime}.raw.log`);
21107
- const rawLinesLogPath = config2.logsDir && path12.resolve(config2.logsDir, `${cli}-yes-${datetime}.lines.log`);
21108
- const debuggingLogsPath = config2.logsDir && path12.resolve(config2.logsDir, `${cli}-yes-${datetime}.debug.log`);
21109
- if (debuggingLogsPath)
21110
- logger.add(new import_winston4.default.transports.File({
21111
- filename: debuggingLogsPath,
21112
- level: "debug"
21113
- }));
21211
+ let logPath = false;
21212
+ let rawLogPath = false;
21213
+ let rawLinesLogPath = false;
21214
+ let debuggingLogsPath = false;
21114
21215
  const isSubAgent = !!process.env.CLAUDE_PPID;
21115
21216
  if (isSubAgent)
21116
21217
  logger.info(`[${cli}-yes] Running as sub-agent (CLAUDE_PPID=${process.env.CLAUDE_PPID})`);
@@ -21140,9 +21241,9 @@ async function agentYes2({
21140
21241
  } catch {}
21141
21242
  const skillHeaders = [];
21142
21243
  let currentDir = workingDir2;
21143
- const searchLimit = gitRoot || path12.parse(currentDir).root;
21244
+ const searchLimit = gitRoot || path13.parse(currentDir).root;
21144
21245
  while (true) {
21145
- const skillPath = path12.resolve(currentDir, "SKILL.md");
21246
+ const skillPath = path13.resolve(currentDir, "SKILL.md");
21146
21247
  const md = await readFile4(skillPath, "utf8").catch(() => null);
21147
21248
  if (md) {
21148
21249
  const headerMatch = md.match(/^[\s\S]*?(?=\n##\s)/);
@@ -21155,7 +21256,7 @@ async function agentYes2({
21155
21256
  }
21156
21257
  if (currentDir === searchLimit)
21157
21258
  break;
21158
- const parentDir = path12.dirname(currentDir);
21259
+ const parentDir = path13.dirname(currentDir);
21159
21260
  if (parentDir === currentDir)
21160
21261
  break;
21161
21262
  currentDir = parentDir;
@@ -21255,6 +21356,16 @@ ${prompt}` : prefix;
21255
21356
  return false;
21256
21357
  }
21257
21358
  }, spawn2)();
21359
+ await pidStore.registerProcess({ pid: shell.pid, cli, args: cliArgs, prompt });
21360
+ logPath = pidStore.getLogPath(shell.pid);
21361
+ rawLogPath = path13.resolve(path13.dirname(logPath), `${shell.pid}.raw.log`);
21362
+ rawLinesLogPath = path13.resolve(path13.dirname(logPath), `${shell.pid}.lines.log`);
21363
+ debuggingLogsPath = path13.resolve(path13.dirname(logPath), `${shell.pid}.debug.log`);
21364
+ if (debuggingLogsPath)
21365
+ logger.add(new import_winston4.default.transports.File({
21366
+ filename: debuggingLogsPath,
21367
+ level: "debug"
21368
+ }));
21258
21369
  const pendingExitCode = Promise.withResolvers();
21259
21370
  async function onData(data) {
21260
21371
  await outputWriter.write(data);
@@ -21264,6 +21375,7 @@ ${prompt}` : prefix;
21264
21375
  stdinReady.unready();
21265
21376
  const agentCrashed = exitCode2 !== 0;
21266
21377
  if (shouldRestartWithoutContinue) {
21378
+ await pidStore.updateStatus(shell.pid, "exited", { exitReason: "restarted", exitCode: exitCode2 ?? undefined });
21267
21379
  shouldRestartWithoutContinue = false;
21268
21380
  isFatal = false;
21269
21381
  const cliCommand = cliConf?.binary || cli;
@@ -21273,6 +21385,7 @@ ${prompt}` : prefix;
21273
21385
  ];
21274
21386
  logger.info(`Restarting ${cli} ${JSON.stringify([bin, ...args])}`);
21275
21387
  shell = pty_default.spawn(bin, args, getPtyOptions());
21388
+ await pidStore.registerProcess({ pid: shell.pid, cli, args, prompt });
21276
21389
  shell.onData(onData);
21277
21390
  shell.onExit(onExit);
21278
21391
  return;
@@ -21282,8 +21395,11 @@ ${prompt}` : prefix;
21282
21395
  logger.warn(`robust is only supported for ${Object.entries(CLIS_CONFIG2).filter(([_, v]) => v.restoreArgs).map(([k]) => k).join(", ")} currently, not ${cli}`);
21283
21396
  return;
21284
21397
  }
21285
- if (isFatal)
21398
+ if (isFatal) {
21399
+ await pidStore.updateStatus(shell.pid, "exited", { exitReason: "fatal", exitCode: exitCode2 ?? undefined });
21286
21400
  return pendingExitCode.resolve(exitCode2);
21401
+ }
21402
+ await pidStore.updateStatus(shell.pid, "exited", { exitReason: "restarted", exitCode: exitCode2 ?? undefined });
21287
21403
  logger.info(`${cli} crashed, restarting...`);
21288
21404
  let restoreArgs = conf.restoreArgs;
21289
21405
  if (cli === "codex") {
@@ -21296,10 +21412,13 @@ ${prompt}` : prefix;
21296
21412
  }
21297
21413
  }
21298
21414
  shell = pty_default.spawn(cli, restoreArgs, getPtyOptions());
21415
+ await pidStore.registerProcess({ pid: shell.pid, cli, args: restoreArgs, prompt });
21299
21416
  shell.onData(onData);
21300
21417
  shell.onExit(onExit);
21301
21418
  return;
21302
21419
  }
21420
+ const exitReason = agentCrashed ? "crash" : "normal";
21421
+ await pidStore.updateStatus(shell.pid, "exited", { exitReason, exitCode: exitCode2 ?? undefined });
21303
21422
  return pendingExitCode.resolve(exitCode2);
21304
21423
  });
21305
21424
  process.stdout.on("resize", () => {
@@ -21311,6 +21430,7 @@ ${prompt}` : prefix;
21311
21430
  const idleWaiter = new IdleWaiter;
21312
21431
  if (exitOnIdle)
21313
21432
  idleWaiter.wait(exitOnIdle).then(async () => {
21433
+ await pidStore.updateStatus(shell.pid, "idle").catch(() => null);
21314
21434
  if (isStillWorkingQ()) {
21315
21435
  logger.warn("[${cli}-yes] ${cli} is idle, but seems still working, not exiting yet");
21316
21436
  return;
@@ -21336,10 +21456,14 @@ ${prompt}` : prefix;
21336
21456
  }).by((s) => {
21337
21457
  if (!useFifo)
21338
21458
  return s;
21339
- const fifoResult = createFifoStream(cli);
21459
+ const fifoResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
21340
21460
  if (!fifoResult)
21341
21461
  return s;
21342
21462
  pendingExitCode.promise.finally(() => fifoResult.cleanup());
21463
+ process.stderr.write(`
21464
+ Append prompts: ${cli}-yes --append-prompt '...'
21465
+
21466
+ `);
21343
21467
  return s.merge(fifoResult.stream);
21344
21468
  }).onStart(async function promptOnStart() {
21345
21469
  logger.debug("Sending prompt message: " + JSON.stringify(prompt));
@@ -21353,10 +21477,13 @@ ${prompt}` : prefix;
21353
21477
  }
21354
21478
  }),
21355
21479
  readable: shellOutputStream.readable
21356
- }).forEach(() => idleWaiter.ping()).forEach(() => nextStdout.ready()).forkTo(async function rawLogger(f) {
21480
+ }).forEach(() => {
21481
+ idleWaiter.ping();
21482
+ pidStore.updateStatus(shell.pid, "active").catch(() => null);
21483
+ }).forEach(() => nextStdout.ready()).forkTo(async function rawLogger(f) {
21357
21484
  if (!rawLogPath)
21358
21485
  return f.run();
21359
- return await mkdir6(path12.dirname(rawLogPath), { recursive: true }).then(() => {
21486
+ return await mkdir7(path13.dirname(rawLogPath), { recursive: true }).then(() => {
21360
21487
  logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
21361
21488
  return f.forEach(async (chars) => {
21362
21489
  await writeFile5(rawLogPath, chars, { flag: "a" }).catch(() => null);
@@ -21430,18 +21557,19 @@ ${prompt}` : prefix;
21430
21557
  flush: (ctrl) => ctrl.terminate()
21431
21558
  })).to(fromWritable2(process.stdout));
21432
21559
  if (logPath) {
21433
- await mkdir6(path12.dirname(logPath), { recursive: true }).catch(() => null);
21560
+ await mkdir7(path13.dirname(logPath), { recursive: true }).catch(() => null);
21434
21561
  await writeFile5(logPath, terminalRender.render()).catch(() => null);
21435
21562
  logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
21436
21563
  }
21437
21564
  const exitCode = await pendingExitCode.promise;
21438
21565
  logger.info(`[${cli}-yes] ${cli} exited with code ${exitCode}`);
21566
+ await pidStore.close();
21439
21567
  await outputWriter.close();
21440
21568
  if (logFile) {
21441
21569
  if (verbose)
21442
21570
  logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
21443
- const logFilePath = path12.resolve(logFile);
21444
- await mkdir6(path12.dirname(logFilePath), { recursive: true }).catch(() => null);
21571
+ const logFilePath = path13.resolve(logFile);
21572
+ await mkdir7(path13.dirname(logFilePath), { recursive: true }).catch(() => null);
21445
21573
  await writeFile5(logFilePath, terminalRender.render());
21446
21574
  }
21447
21575
  return { exitCode, logs: terminalRender.render() };
@@ -21512,6 +21640,7 @@ var init_ts = __esm(async () => {
21512
21640
  init_runningLock();
21513
21641
  init_logger();
21514
21642
  init_fifo();
21643
+ init_pidStore();
21515
21644
  await init_pty();
21516
21645
  import_winston4 = __toESM(require_winston(), 1);
21517
21646
  config2 = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
@@ -21527,11 +21656,12 @@ init_codexSessionManager();
21527
21656
  init_runningLock();
21528
21657
  init_logger();
21529
21658
  init_fifo();
21659
+ init_pidStore();
21530
21660
  await init_pty();
21531
21661
  var import_winston2 = __toESM(require_winston(), 1);
21532
21662
  import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
21533
- import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
21534
- import path10 from "path";
21663
+ import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
21664
+ import path11 from "path";
21535
21665
  var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
21536
21666
  var CLIS_CONFIG = config.clis;
21537
21667
  async function agentYes({
@@ -21577,6 +21707,8 @@ async function agentYes({
21577
21707
  process.exit(code);
21578
21708
  });
21579
21709
  }
21710
+ const pidStore = new PidStore(workingDir);
21711
+ await pidStore.init();
21580
21712
  process.stdin.setRawMode?.(true);
21581
21713
  let isFatal = false;
21582
21714
  let shouldRestartWithoutContinue = false;
@@ -21592,16 +21724,10 @@ async function agentYes({
21592
21724
  const shellOutputStream = new TransformStream;
21593
21725
  const outputWriter = shellOutputStream.writable.getWriter();
21594
21726
  logger.debug(`Using ${ptyPackage} for pseudo terminal management.`);
21595
- const datetime = new Date().toISOString().replace(/\D/g, "").slice(0, 17);
21596
- const logPath = config.logsDir && path10.resolve(config.logsDir, `${cli}-yes-${datetime}.log`);
21597
- const rawLogPath = config.logsDir && path10.resolve(config.logsDir, `${cli}-yes-${datetime}.raw.log`);
21598
- const rawLinesLogPath = config.logsDir && path10.resolve(config.logsDir, `${cli}-yes-${datetime}.lines.log`);
21599
- const debuggingLogsPath = config.logsDir && path10.resolve(config.logsDir, `${cli}-yes-${datetime}.debug.log`);
21600
- if (debuggingLogsPath)
21601
- logger.add(new import_winston2.default.transports.File({
21602
- filename: debuggingLogsPath,
21603
- level: "debug"
21604
- }));
21727
+ let logPath = false;
21728
+ let rawLogPath = false;
21729
+ let rawLinesLogPath = false;
21730
+ let debuggingLogsPath = false;
21605
21731
  const isSubAgent = !!process.env.CLAUDE_PPID;
21606
21732
  if (isSubAgent)
21607
21733
  logger.info(`[${cli}-yes] Running as sub-agent (CLAUDE_PPID=${process.env.CLAUDE_PPID})`);
@@ -21631,9 +21757,9 @@ async function agentYes({
21631
21757
  } catch {}
21632
21758
  const skillHeaders = [];
21633
21759
  let currentDir = workingDir2;
21634
- const searchLimit = gitRoot || path10.parse(currentDir).root;
21760
+ const searchLimit = gitRoot || path11.parse(currentDir).root;
21635
21761
  while (true) {
21636
- const skillPath = path10.resolve(currentDir, "SKILL.md");
21762
+ const skillPath = path11.resolve(currentDir, "SKILL.md");
21637
21763
  const md = await readFile3(skillPath, "utf8").catch(() => null);
21638
21764
  if (md) {
21639
21765
  const headerMatch = md.match(/^[\s\S]*?(?=\n##\s)/);
@@ -21646,7 +21772,7 @@ async function agentYes({
21646
21772
  }
21647
21773
  if (currentDir === searchLimit)
21648
21774
  break;
21649
- const parentDir = path10.dirname(currentDir);
21775
+ const parentDir = path11.dirname(currentDir);
21650
21776
  if (parentDir === currentDir)
21651
21777
  break;
21652
21778
  currentDir = parentDir;
@@ -21746,6 +21872,16 @@ ${prompt}` : prefix;
21746
21872
  return false;
21747
21873
  }
21748
21874
  }, spawn2)();
21875
+ await pidStore.registerProcess({ pid: shell.pid, cli, args: cliArgs, prompt });
21876
+ logPath = pidStore.getLogPath(shell.pid);
21877
+ rawLogPath = path11.resolve(path11.dirname(logPath), `${shell.pid}.raw.log`);
21878
+ rawLinesLogPath = path11.resolve(path11.dirname(logPath), `${shell.pid}.lines.log`);
21879
+ debuggingLogsPath = path11.resolve(path11.dirname(logPath), `${shell.pid}.debug.log`);
21880
+ if (debuggingLogsPath)
21881
+ logger.add(new import_winston2.default.transports.File({
21882
+ filename: debuggingLogsPath,
21883
+ level: "debug"
21884
+ }));
21749
21885
  const pendingExitCode = Promise.withResolvers();
21750
21886
  async function onData(data) {
21751
21887
  await outputWriter.write(data);
@@ -21755,6 +21891,7 @@ ${prompt}` : prefix;
21755
21891
  stdinReady.unready();
21756
21892
  const agentCrashed = exitCode2 !== 0;
21757
21893
  if (shouldRestartWithoutContinue) {
21894
+ await pidStore.updateStatus(shell.pid, "exited", { exitReason: "restarted", exitCode: exitCode2 ?? undefined });
21758
21895
  shouldRestartWithoutContinue = false;
21759
21896
  isFatal = false;
21760
21897
  const cliCommand = cliConf?.binary || cli;
@@ -21764,6 +21901,7 @@ ${prompt}` : prefix;
21764
21901
  ];
21765
21902
  logger.info(`Restarting ${cli} ${JSON.stringify([bin, ...args])}`);
21766
21903
  shell = pty_default.spawn(bin, args, getPtyOptions());
21904
+ await pidStore.registerProcess({ pid: shell.pid, cli, args, prompt });
21767
21905
  shell.onData(onData);
21768
21906
  shell.onExit(onExit);
21769
21907
  return;
@@ -21773,8 +21911,11 @@ ${prompt}` : prefix;
21773
21911
  logger.warn(`robust is only supported for ${Object.entries(CLIS_CONFIG).filter(([_, v]) => v.restoreArgs).map(([k]) => k).join(", ")} currently, not ${cli}`);
21774
21912
  return;
21775
21913
  }
21776
- if (isFatal)
21914
+ if (isFatal) {
21915
+ await pidStore.updateStatus(shell.pid, "exited", { exitReason: "fatal", exitCode: exitCode2 ?? undefined });
21777
21916
  return pendingExitCode.resolve(exitCode2);
21917
+ }
21918
+ await pidStore.updateStatus(shell.pid, "exited", { exitReason: "restarted", exitCode: exitCode2 ?? undefined });
21778
21919
  logger.info(`${cli} crashed, restarting...`);
21779
21920
  let restoreArgs = conf.restoreArgs;
21780
21921
  if (cli === "codex") {
@@ -21787,10 +21928,13 @@ ${prompt}` : prefix;
21787
21928
  }
21788
21929
  }
21789
21930
  shell = pty_default.spawn(cli, restoreArgs, getPtyOptions());
21931
+ await pidStore.registerProcess({ pid: shell.pid, cli, args: restoreArgs, prompt });
21790
21932
  shell.onData(onData);
21791
21933
  shell.onExit(onExit);
21792
21934
  return;
21793
21935
  }
21936
+ const exitReason = agentCrashed ? "crash" : "normal";
21937
+ await pidStore.updateStatus(shell.pid, "exited", { exitReason, exitCode: exitCode2 ?? undefined });
21794
21938
  return pendingExitCode.resolve(exitCode2);
21795
21939
  });
21796
21940
  process.stdout.on("resize", () => {
@@ -21802,6 +21946,7 @@ ${prompt}` : prefix;
21802
21946
  const idleWaiter = new IdleWaiter;
21803
21947
  if (exitOnIdle)
21804
21948
  idleWaiter.wait(exitOnIdle).then(async () => {
21949
+ await pidStore.updateStatus(shell.pid, "idle").catch(() => null);
21805
21950
  if (isStillWorkingQ()) {
21806
21951
  logger.warn("[${cli}-yes] ${cli} is idle, but seems still working, not exiting yet");
21807
21952
  return;
@@ -21827,10 +21972,14 @@ ${prompt}` : prefix;
21827
21972
  }).by((s) => {
21828
21973
  if (!useFifo)
21829
21974
  return s;
21830
- const fifoResult = createFifoStream(cli);
21975
+ const fifoResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
21831
21976
  if (!fifoResult)
21832
21977
  return s;
21833
21978
  pendingExitCode.promise.finally(() => fifoResult.cleanup());
21979
+ process.stderr.write(`
21980
+ Append prompts: ${cli}-yes --append-prompt '...'
21981
+
21982
+ `);
21834
21983
  return s.merge(fifoResult.stream);
21835
21984
  }).onStart(async function promptOnStart() {
21836
21985
  logger.debug("Sending prompt message: " + JSON.stringify(prompt));
@@ -21844,10 +21993,13 @@ ${prompt}` : prefix;
21844
21993
  }
21845
21994
  }),
21846
21995
  readable: shellOutputStream.readable
21847
- }).forEach(() => idleWaiter.ping()).forEach(() => nextStdout.ready()).forkTo(async function rawLogger(f) {
21996
+ }).forEach(() => {
21997
+ idleWaiter.ping();
21998
+ pidStore.updateStatus(shell.pid, "active").catch(() => null);
21999
+ }).forEach(() => nextStdout.ready()).forkTo(async function rawLogger(f) {
21848
22000
  if (!rawLogPath)
21849
22001
  return f.run();
21850
- return await mkdir4(path10.dirname(rawLogPath), { recursive: true }).then(() => {
22002
+ return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
21851
22003
  logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
21852
22004
  return f.forEach(async (chars) => {
21853
22005
  await writeFile3(rawLogPath, chars, { flag: "a" }).catch(() => null);
@@ -21921,18 +22073,19 @@ ${prompt}` : prefix;
21921
22073
  flush: (ctrl) => ctrl.terminate()
21922
22074
  })).to(fromWritable(process.stdout));
21923
22075
  if (logPath) {
21924
- await mkdir4(path10.dirname(logPath), { recursive: true }).catch(() => null);
22076
+ await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
21925
22077
  await writeFile3(logPath, terminalRender.render()).catch(() => null);
21926
22078
  logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
21927
22079
  }
21928
22080
  const exitCode = await pendingExitCode.promise;
21929
22081
  logger.info(`[${cli}-yes] ${cli} exited with code ${exitCode}`);
22082
+ await pidStore.close();
21930
22083
  await outputWriter.close();
21931
22084
  if (logFile) {
21932
22085
  if (verbose)
21933
22086
  logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
21934
- const logFilePath = path10.resolve(logFile);
21935
- await mkdir4(path10.dirname(logFilePath), { recursive: true }).catch(() => null);
22087
+ const logFilePath = path11.resolve(logFile);
22088
+ await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
21936
22089
  await writeFile3(logFilePath, terminalRender.render());
21937
22090
  }
21938
22091
  return { exitCode, logs: terminalRender.render() };
@@ -21997,124 +22150,6 @@ function sleep2(ms) {
21997
22150
  // ts/cli.ts
21998
22151
  import { argv } from "process";
21999
22152
 
22000
- // agent-yes.config.ts
22001
- init_logger();
22002
- import { mkdir as mkdir5 } from "node:fs/promises";
22003
- import os2 from "node:os";
22004
- import path11 from "node:path";
22005
- logger.debug("loading cli-yes.config.ts from " + import.meta.url);
22006
- var configDir2 = await (async () => {
22007
- const homeConfigDir = path11.resolve(os2.homedir(), ".agent-yes");
22008
- const isHomeWritable = await mkdir5(homeConfigDir, { recursive: true }).then(() => true).catch(() => false);
22009
- if (isHomeWritable) {
22010
- logger.debug("[config] Using home directory:", homeConfigDir);
22011
- return homeConfigDir;
22012
- }
22013
- const tmpConfigDir = path11.resolve("/tmp/.agent-yes");
22014
- const isWritable = await mkdir5(tmpConfigDir, { recursive: true });
22015
- if (isWritable) {
22016
- logger.debug("[config] Using workspace directory:", tmpConfigDir);
22017
- return tmpConfigDir;
22018
- }
22019
- return;
22020
- })();
22021
- var agent_yes_config_default2 = deepMixin(await getDefaultConfig2(), await import(path11.resolve(os2.homedir(), ".agent-yes/config.ts")).catch(() => ({ default: {} })).then((mod) => mod.default), await import(path11.resolve(process.cwd(), "node_modules/.agent-yes/config.ts")).catch(() => ({ default: {} })).then((mod) => mod.default), await import(path11.resolve(process.cwd(), ".agent-yes/config.ts")).catch(() => ({ default: {} })).then((mod) => mod.default));
22022
- function getDefaultConfig2() {
22023
- return defineCliYesConfig({
22024
- configDir: configDir2,
22025
- logsDir: configDir2 && path11.resolve(configDir2, "logs"),
22026
- clis: {
22027
- qwen: {
22028
- install: "npm install -g @qwen-code/qwen-code@latest",
22029
- version: "qwen --version"
22030
- },
22031
- grok: {
22032
- install: "npm install -g @vibe-kit/grok-cli@latest",
22033
- ready: [/^ │ ❯ +/],
22034
- enter: [/^ 1. Yes/]
22035
- },
22036
- claude: {
22037
- promptArg: "last-arg",
22038
- install: "npm install -g @anthropic-ai/claude-code@latest",
22039
- ready: [/\? for shortcuts/],
22040
- typingRespond: {
22041
- "1\n": [/│ Do you want to use this API key\?/]
22042
- },
22043
- enter: [
22044
- /^.{0,4} 1\. Yes/m,
22045
- /^.{0,4} 1\. Yes, continue/m,
22046
- /^.{0,4} 1\. Dark mode ?✔/m,
22047
- /❯ 1\. Yes/m,
22048
- /❯ 1\. Yes, continue/m,
22049
- /❯ 1\. Dark mode ?✔/m,
22050
- /Press Enter to continue…/m
22051
- ],
22052
- fatal: [/⎿ Claude usage limit reached\./, /^error: unknown option/],
22053
- restoreArgs: ["--continue"],
22054
- restartWithoutContinueArg: [/No conversation found to continue/],
22055
- exitCommand: ["/exit"],
22056
- bunx: true,
22057
- defaultArgs: ["--model=sonnet"]
22058
- },
22059
- gemini: {
22060
- install: "npm install -g @google/gemini-cli@latest",
22061
- ready: [/Type your message/],
22062
- enter: [/│ ● 1. Yes, allow once/, /│ ● 1. Allow once/],
22063
- fatal: [/Error resuming session/, /No previous sessions found for this project./],
22064
- restoreArgs: ["--resume"],
22065
- restartWithoutContinueArg: [
22066
- /No previous sessions found for this project\./,
22067
- /Error resuming session/
22068
- ],
22069
- exitCommand: ["/chat save ${PWD}", "/quit"]
22070
- },
22071
- codex: {
22072
- promptArg: "first-arg",
22073
- install: "npm install -g @openai/codex@latest",
22074
- updateAvailable: [/^✨⬆️ Update available!/],
22075
- ready: [
22076
- /⏎ send/,
22077
- /\? for shortcuts/
22078
- ],
22079
- enter: [
22080
- /> 1. Yes,/,
22081
- /> 1. Yes, allow Codex to work in this folder/,
22082
- /> 1. Approve and run now/
22083
- ],
22084
- fatal: [/Error: The cursor position could not be read within/],
22085
- defaultArgs: ["--search"],
22086
- noEOL: true
22087
- },
22088
- copilot: {
22089
- install: "npm install -g @github/copilot",
22090
- ready: [/^ +> /, /Ctrl\+c Exit/],
22091
- enter: [/ │ ❯ +1. Yes, proceed/, /❯ +1. Yes/],
22092
- fatal: []
22093
- },
22094
- cursor: {
22095
- install: "open https://cursor.com/ja/docs/cli/installation",
22096
- binary: "cursor-agent",
22097
- bunx: true,
22098
- ready: [/\/ commands/],
22099
- enter: [/→ Run \(once\) \(y\) \(enter\)/, /▶ \[a\] Trust this workspace/],
22100
- fatal: [/^ Error: You've hit your usage limit/]
22101
- },
22102
- auggie: {
22103
- help: "https://docs.augmentcode.com/cli/overview",
22104
- install: "npm install -g @augmentcode/auggie",
22105
- promptArg: "first-arg",
22106
- ready: [/ > /, /\? to show shortcuts/],
22107
- enter: [],
22108
- fatal: []
22109
- },
22110
- amp: {
22111
- help: "",
22112
- install: "npm i -g @sourcegraph/amp"
22113
- }
22114
- }
22115
- });
22116
- }
22117
-
22118
22153
  // ts/parseCliArgs.ts
22119
22154
  var import_ms = __toESM(require_ms(), 1);
22120
22155
 
@@ -27542,6 +27577,7 @@ var package_default = {
27542
27577
  url: "git+https://github.com/snomiao/agent-yes.git"
27543
27578
  },
27544
27579
  bin: {
27580
+ ay: "./dist/agent-yes.js",
27545
27581
  "agent-yes": "./dist/agent-yes.js",
27546
27582
  "amp-yes": "./dist/amp-yes.js",
27547
27583
  "auggie-yes": "./dist/auggie-yes.js",
@@ -27574,7 +27610,7 @@ var package_default = {
27574
27610
  registry: "https://registry.npmjs.org/"
27575
27611
  },
27576
27612
  scripts: {
27577
- build: "bun build ./ts/cli.ts ./ts/index.ts --outdir=dist --target=node --sourcemap --external=@snomiao/bun-pty --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
27613
+ build: "bun build ./ts/cli.ts ./ts/index.ts --outdir=dist --target=node --sourcemap --external=@seald-io/nedb --external=@snomiao/bun-pty --external=bun-pty --external=node-pty --external=from-node-stream --external=bun",
27578
27614
  postbuild: "bun ./ts/postbuild.ts",
27579
27615
  demo: "bun run build && bun link && claude-yes -- demo",
27580
27616
  dev: "bun ts/index.ts",
@@ -27586,6 +27622,7 @@ var package_default = {
27586
27622
  test: "bun test --coverage"
27587
27623
  },
27588
27624
  dependencies: {
27625
+ "@seald-io/nedb": "^4.0.4",
27589
27626
  "@snomiao/bun-pty": "^0.3.4",
27590
27627
  "bun-pty": "^0.4.8",
27591
27628
  "from-node-stream": "^0.1.2"
@@ -27707,6 +27744,13 @@ function parseCliArgs(argv) {
27707
27744
  description: "Resume previous session in current cwd if any, note: will exit if no previous session found",
27708
27745
  default: false,
27709
27746
  alias: "c"
27747
+ }).option("append-prompt", {
27748
+ type: "string",
27749
+ description: "Send a prompt to the active agent's FIFO stdin in current directory"
27750
+ }).option("fifo", {
27751
+ type: "boolean",
27752
+ description: "Enable FIFO input stream for additional stdin input (Linux only)",
27753
+ default: false
27710
27754
  }).positional("cli", {
27711
27755
  describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
27712
27756
  type: "string",
@@ -27777,7 +27821,9 @@ function parseCliArgs(argv) {
27777
27821
  logFile: parsedArgv.logFile,
27778
27822
  verbose: parsedArgv.verbose,
27779
27823
  resume: parsedArgv.continue,
27780
- useSkills: parsedArgv.useSkills
27824
+ useSkills: parsedArgv.useSkills,
27825
+ appendPrompt: parsedArgv.appendPrompt,
27826
+ useFifo: parsedArgv.fifo
27781
27827
  };
27782
27828
  }
27783
27829
 
@@ -27798,12 +27844,123 @@ var logger2 = import_winston3.default.createLogger({
27798
27844
  silent: false
27799
27845
  });
27800
27846
 
27847
+ // ts/pidStore.ts
27848
+ init_logger();
27849
+ import Datastore2 from "@seald-io/nedb";
27850
+ import { mkdir as mkdir6 } from "fs/promises";
27851
+ import path12 from "path";
27852
+
27853
+ class PidStore2 {
27854
+ db;
27855
+ baseDir;
27856
+ constructor(workingDir) {
27857
+ this.baseDir = path12.resolve(workingDir, ".agent-yes");
27858
+ }
27859
+ async init() {
27860
+ await mkdir6(path12.join(this.baseDir, "logs"), { recursive: true });
27861
+ await mkdir6(path12.join(this.baseDir, "fifo"), { recursive: true });
27862
+ this.db = new Datastore2({
27863
+ filename: path12.join(this.baseDir, "pid.jsonl"),
27864
+ autoload: true
27865
+ });
27866
+ await this.db.loadDatabaseAsync();
27867
+ await this.cleanStaleRecords();
27868
+ }
27869
+ async registerProcess({
27870
+ pid,
27871
+ cli,
27872
+ args,
27873
+ prompt
27874
+ }) {
27875
+ const now = Date.now();
27876
+ const record = {
27877
+ pid,
27878
+ cli,
27879
+ args,
27880
+ prompt,
27881
+ logFile: this.getLogPath(pid),
27882
+ fifoFile: this.getFifoPath(pid),
27883
+ status: "active",
27884
+ exitReason: "",
27885
+ startedAt: now,
27886
+ updatedAt: now
27887
+ };
27888
+ await this.db.insertAsync(record);
27889
+ logger.debug(`[pidStore] Registered process ${pid}`);
27890
+ return record;
27891
+ }
27892
+ async updateStatus(pid, status, extra) {
27893
+ const update2 = {
27894
+ status,
27895
+ updatedAt: Date.now(),
27896
+ ...extra
27897
+ };
27898
+ await this.db.updateAsync({ pid }, { $set: update2 }, {});
27899
+ logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
27900
+ }
27901
+ getLogPath(pid) {
27902
+ return path12.resolve(this.baseDir, "logs", `${pid}.log`);
27903
+ }
27904
+ getFifoPath(pid) {
27905
+ return path12.resolve(this.baseDir, "fifo", `${pid}.stdin`);
27906
+ }
27907
+ async cleanStaleRecords() {
27908
+ const activeRecords = await this.db.findAsync({
27909
+ status: { $ne: "exited" }
27910
+ });
27911
+ for (const record of activeRecords) {
27912
+ if (!this.isProcessAlive(record.pid)) {
27913
+ await this.db.updateAsync({ pid: record.pid }, {
27914
+ $set: {
27915
+ status: "exited",
27916
+ exitReason: "stale-cleanup",
27917
+ updatedAt: Date.now()
27918
+ }
27919
+ }, {});
27920
+ logger.debug(`[pidStore] Cleaned stale record for PID ${record.pid}`);
27921
+ }
27922
+ }
27923
+ }
27924
+ async close() {
27925
+ await this.db.compactDatafileAsync();
27926
+ logger.debug("[pidStore] Database compacted and closed");
27927
+ }
27928
+ isProcessAlive(pid) {
27929
+ try {
27930
+ process.kill(pid, 0);
27931
+ return true;
27932
+ } catch {
27933
+ return false;
27934
+ }
27935
+ }
27936
+ static async findActiveFifo(workingDir) {
27937
+ const store = new PidStore2(workingDir);
27938
+ await store.init();
27939
+ const records = await store.db.findAsync({ status: { $ne: "exited" } });
27940
+ await store.close();
27941
+ const sorted = records.sort((a2, b) => b.startedAt - a2.startedAt);
27942
+ return sorted[0]?.fifoFile ?? null;
27943
+ }
27944
+ }
27945
+
27801
27946
  // ts/cli.ts
27802
27947
  var config3 = parseCliArgs(process.argv);
27948
+ if (config3.appendPrompt) {
27949
+ const fifoPath = await PidStore2.findActiveFifo(process.cwd());
27950
+ if (!fifoPath) {
27951
+ console.error("No active agent with FIFO found in current directory.");
27952
+ process.exit(1);
27953
+ }
27954
+ const { writeFileSync: writeFileSync2, openSync, closeSync } = await import("fs");
27955
+ const fd = openSync(fifoPath, "w");
27956
+ writeFileSync2(fd, config3.appendPrompt + "\r");
27957
+ closeSync(fd);
27958
+ console.log(`Sent prompt to ${fifoPath}`);
27959
+ process.exit(0);
27960
+ }
27803
27961
  if (!config3.cli) {
27804
- logger2.error(process.argv);
27805
- logger2.error("Error: No CLI name provided.");
27806
- throw new Error(`missing cli def, available clis: ${Object.keys((await agent_yes_config_default2).clis).join(", ")}`);
27962
+ config3.cli = "claude";
27963
+ logger2.warn("Warning: No CLI name provided. Using default 'claude'.");
27807
27964
  }
27808
27965
  if (config3.verbose) {
27809
27966
  process.env.VERBOSE = "true";
@@ -27815,5 +27972,5 @@ var { exitCode } = await cliYes(config3);
27815
27972
  console.log("exiting process");
27816
27973
  process.exit(exitCode ?? 1);
27817
27974
 
27818
- //# debugId=88F92B41CE5B430064756E2164756E21
27975
+ //# debugId=DBF8D77A7DEE11C764756E2164756E21
27819
27976
  //# sourceMappingURL=cli.js.map