claude-yes 1.35.1 → 1.36.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,10 +20633,91 @@ 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
+ import { createServer } from "net";
20636
20637
  function createFifoStream(cli, customPath) {
20637
- if (process.platform !== "linux") {
20638
+ if (process.platform === "win32") {
20639
+ return createWindowsNamedPipe(cli, customPath);
20640
+ } else if (process.platform === "linux") {
20641
+ return createLinuxFifo(cli, customPath);
20642
+ } else {
20643
+ logger.warn(`[${cli}-yes] IPC not supported on platform: ${process.platform}`);
20644
+ return null;
20645
+ }
20646
+ }
20647
+ function createWindowsNamedPipe(cli, customPath) {
20648
+ try {
20649
+ let pipePath;
20650
+ if (customPath) {
20651
+ pipePath = customPath;
20652
+ } else {
20653
+ const timestamp = new Date().toISOString().replace(/\D/g, "").slice(0, 17);
20654
+ const randomSuffix = Math.random().toString(36).substring(2, 5);
20655
+ pipePath = `\\\\.\\pipe\\agent-yes-${timestamp}${randomSuffix}`;
20656
+ }
20657
+ logger.info(`[${cli}-yes] Creating Windows named pipe at ${pipePath}`);
20658
+ const server = createServer();
20659
+ let connection = null;
20660
+ let isClosing = false;
20661
+ const stream = new ReadableStream({
20662
+ start(controller) {
20663
+ server.on("connection", (socket) => {
20664
+ connection = socket;
20665
+ logger.info(`[${cli}-yes] Client connected to named pipe`);
20666
+ socket.on("data", (chunk) => {
20667
+ const data = chunk.toString();
20668
+ logger.debug(`[${cli}-yes] Received data via named pipe: ${data}`);
20669
+ controller.enqueue(data);
20670
+ });
20671
+ socket.on("end", () => {
20672
+ logger.debug(`[${cli}-yes] Client disconnected from named pipe`);
20673
+ connection = null;
20674
+ });
20675
+ socket.on("error", (error) => {
20676
+ logger.warn(`[${cli}-yes] Named pipe socket error:`, error);
20677
+ if (!isClosing) {
20678
+ controller.error(error);
20679
+ }
20680
+ });
20681
+ });
20682
+ server.on("error", (error) => {
20683
+ logger.warn(`[${cli}-yes] Named pipe server error:`, error);
20684
+ if (!isClosing) {
20685
+ controller.error(error);
20686
+ }
20687
+ });
20688
+ server.listen(pipePath, () => {
20689
+ logger.info(`[${cli}-yes] Named pipe server listening at ${pipePath}`);
20690
+ });
20691
+ },
20692
+ cancel() {
20693
+ isClosing = true;
20694
+ if (connection) {
20695
+ connection.end();
20696
+ }
20697
+ server.close();
20698
+ }
20699
+ });
20700
+ const cleanup = async () => {
20701
+ isClosing = true;
20702
+ if (connection) {
20703
+ connection.end();
20704
+ }
20705
+ server.close();
20706
+ logger.info(`[${cli}-yes] Cleaned up Windows named pipe at ${pipePath}`);
20707
+ };
20708
+ process.on("exit", () => cleanup().catch(() => null));
20709
+ process.on("SIGINT", () => cleanup().catch(() => null));
20710
+ process.on("SIGTERM", () => cleanup().catch(() => null));
20711
+ return {
20712
+ stream,
20713
+ cleanup
20714
+ };
20715
+ } catch (error) {
20716
+ logger.warn(`[${cli}-yes] Failed to create Windows named pipe:`, error);
20638
20717
  return null;
20639
20718
  }
20719
+ }
20720
+ function createLinuxFifo(cli, customPath) {
20640
20721
  let fifoPath = null;
20641
20722
  let fifoStream = null;
20642
20723
  try {
@@ -20732,7 +20813,7 @@ var init_fifo = __esm(() => {
20732
20813
  });
20733
20814
 
20734
20815
  // ts/pidStore.ts
20735
- import { mkdir as mkdir3 } from "fs/promises";
20816
+ import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
20736
20817
  import path9 from "path";
20737
20818
 
20738
20819
  class SqliteAdapter {
@@ -20776,15 +20857,16 @@ class SqliteAdapter {
20776
20857
 
20777
20858
  class PidStore {
20778
20859
  db;
20779
- baseDir;
20860
+ storeDir;
20780
20861
  dbPath;
20781
20862
  constructor(workingDir) {
20782
- this.baseDir = path9.resolve(workingDir, ".agent-yes");
20783
- this.dbPath = path9.join(this.baseDir, "pid.sqlite");
20863
+ this.storeDir = path9.resolve(workingDir, ".agent-yes");
20864
+ this.dbPath = path9.join(this.storeDir, "pid.sqlite");
20784
20865
  }
20785
20866
  async init() {
20786
- await mkdir3(path9.join(this.baseDir, "logs"), { recursive: true });
20787
- await mkdir3(path9.join(this.baseDir, "fifo"), { recursive: true });
20867
+ await mkdir3(path9.join(this.storeDir, "logs"), { recursive: true });
20868
+ await mkdir3(path9.join(this.storeDir, "fifo"), { recursive: true });
20869
+ await this.ensureGitignore();
20788
20870
  this.db = new SqliteAdapter;
20789
20871
  await this.db.init(this.dbPath);
20790
20872
  this.db.run("PRAGMA journal_mode=WAL");
@@ -20856,10 +20938,14 @@ class PidStore {
20856
20938
  logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
20857
20939
  }
20858
20940
  getLogPath(pid) {
20859
- return path9.resolve(this.baseDir, "logs", `${pid}.log`);
20941
+ return path9.resolve(this.storeDir, "logs", `${pid}.log`);
20860
20942
  }
20861
20943
  getFifoPath(pid) {
20862
- return path9.resolve(this.baseDir, "fifo", `${pid}.stdin`);
20944
+ if (process.platform === "win32") {
20945
+ return `\\\\.\\pipe\\agent-yes-${pid}`;
20946
+ } else {
20947
+ return path9.resolve(this.storeDir, "fifo", `${pid}.stdin`);
20948
+ }
20863
20949
  }
20864
20950
  async cleanStaleRecords() {
20865
20951
  const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
@@ -20888,6 +20974,28 @@ class PidStore {
20888
20974
  return false;
20889
20975
  }
20890
20976
  }
20977
+ async ensureGitignore() {
20978
+ const gitignorePath = path9.join(this.storeDir, ".gitignore");
20979
+ const gitignoreContent = `# Auto-generated .gitignore for agent-yes
20980
+ # Ignore all log files and runtime data
20981
+ logs/
20982
+ fifo/
20983
+ *.sqlite
20984
+ *.sqlite-*
20985
+ *.log
20986
+ *.raw.log
20987
+ *.lines.log
20988
+ *.debug.log
20989
+ `;
20990
+ try {
20991
+ await writeFile3(gitignorePath, gitignoreContent, { flag: "wx" });
20992
+ logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
20993
+ } catch (error) {
20994
+ if (error.code !== "EEXIST") {
20995
+ logger.warn(`[pidStore] Failed to create .gitignore:`, error);
20996
+ }
20997
+ }
20998
+ }
20891
20999
  static async findActiveFifo(workingDir) {
20892
21000
  const store = new PidStore(workingDir);
20893
21001
  await store.init();
@@ -21026,8 +21134,11 @@ function getDefaultConfig() {
21026
21134
  fatal: []
21027
21135
  },
21028
21136
  amp: {
21029
- help: "",
21030
- install: "npm i -g @sourcegraph/amp",
21137
+ help: "https://ampcode.com/",
21138
+ install: {
21139
+ bash: "curl -fsSL https://ampcode.com/install.sh | bash",
21140
+ npm: "npm i -g @sourcegraph/amp"
21141
+ },
21031
21142
  enter: [
21032
21143
  /^.{0,4} Approve /
21033
21144
  ]
@@ -21221,7 +21332,7 @@ __export(exports_ts, {
21221
21332
  CLIS_CONFIG: () => CLIS_CONFIG2
21222
21333
  });
21223
21334
  import { fromReadable as fromReadable3, fromWritable as fromWritable2 } from "from-node-stream";
21224
- import { mkdir as mkdir7, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
21335
+ import { mkdir as mkdir7, readFile as readFile4, writeFile as writeFile7 } from "fs/promises";
21225
21336
  import path13 from "path";
21226
21337
  async function agentYes2({
21227
21338
  cli,
@@ -21568,15 +21679,15 @@ ${prompt}` : prefix;
21568
21679
  }).by((s) => {
21569
21680
  if (!useFifo)
21570
21681
  return s;
21571
- const fifoResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
21572
- if (!fifoResult)
21682
+ const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
21683
+ if (!ipcResult)
21573
21684
  return s;
21574
- pendingExitCode.promise.finally(() => fifoResult.cleanup());
21685
+ pendingExitCode.promise.finally(() => ipcResult.cleanup());
21575
21686
  process.stderr.write(`
21576
21687
  Append prompts: ${cli}-yes --append-prompt '...'
21577
21688
 
21578
21689
  `);
21579
- return s.merge(fifoResult.stream);
21690
+ return s.merge(ipcResult.stream);
21580
21691
  }).onStart(async function promptOnStart() {
21581
21692
  logger.debug("Sending prompt message: " + JSON.stringify(prompt));
21582
21693
  if (prompt)
@@ -21598,7 +21709,7 @@ ${prompt}` : prefix;
21598
21709
  return await mkdir7(path13.dirname(rawLogPath), { recursive: true }).then(() => {
21599
21710
  logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
21600
21711
  return f.forEach(async (chars) => {
21601
- await writeFile5(rawLogPath, chars, { flag: "a" }).catch(() => null);
21712
+ await writeFile7(rawLogPath, chars, { flag: "a" }).catch(() => null);
21602
21713
  }).run();
21603
21714
  }).catch(() => f.run());
21604
21715
  }).by(function consoleResponder(e) {
@@ -21670,7 +21781,7 @@ ${prompt}` : prefix;
21670
21781
  })).to(fromWritable2(process.stdout));
21671
21782
  if (logPath) {
21672
21783
  await mkdir7(path13.dirname(logPath), { recursive: true }).catch(() => null);
21673
- await writeFile5(logPath, terminalRender.render()).catch(() => null);
21784
+ await writeFile7(logPath, terminalRender.render()).catch(() => null);
21674
21785
  logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
21675
21786
  }
21676
21787
  const exitCode = await pendingExitCode.promise;
@@ -21682,7 +21793,7 @@ ${prompt}` : prefix;
21682
21793
  logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
21683
21794
  const logFilePath = path13.resolve(logFile);
21684
21795
  await mkdir7(path13.dirname(logFilePath), { recursive: true }).catch(() => null);
21685
- await writeFile5(logFilePath, terminalRender.render());
21796
+ await writeFile7(logFilePath, terminalRender.render());
21686
21797
  }
21687
21798
  return { exitCode, logs: terminalRender.render() };
21688
21799
  async function sendEnter(waitms = 1000) {
@@ -21701,6 +21812,15 @@ ${prompt}` : prefix;
21701
21812
  resolve5();
21702
21813
  }, 1000))
21703
21814
  ]);
21815
+ await Promise.race([
21816
+ nextStdout.wait(),
21817
+ new Promise((resolve5) => setTimeout(() => {
21818
+ if (!nextStdout.ready) {
21819
+ shell.write("\r");
21820
+ }
21821
+ resolve5();
21822
+ }, 3000))
21823
+ ]);
21704
21824
  }
21705
21825
  async function sendMessage3(message, { waitForReady = true } = {}) {
21706
21826
  if (waitForReady)
@@ -21772,7 +21892,7 @@ init_pidStore();
21772
21892
  await init_pty();
21773
21893
  var import_winston2 = __toESM(require_winston(), 1);
21774
21894
  import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
21775
- import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
21895
+ import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
21776
21896
  import path11 from "path";
21777
21897
  var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
21778
21898
  var CLIS_CONFIG = config.clis;
@@ -22121,15 +22241,15 @@ ${prompt}` : prefix;
22121
22241
  }).by((s) => {
22122
22242
  if (!useFifo)
22123
22243
  return s;
22124
- const fifoResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
22125
- if (!fifoResult)
22244
+ const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
22245
+ if (!ipcResult)
22126
22246
  return s;
22127
- pendingExitCode.promise.finally(() => fifoResult.cleanup());
22247
+ pendingExitCode.promise.finally(() => ipcResult.cleanup());
22128
22248
  process.stderr.write(`
22129
22249
  Append prompts: ${cli}-yes --append-prompt '...'
22130
22250
 
22131
22251
  `);
22132
- return s.merge(fifoResult.stream);
22252
+ return s.merge(ipcResult.stream);
22133
22253
  }).onStart(async function promptOnStart() {
22134
22254
  logger.debug("Sending prompt message: " + JSON.stringify(prompt));
22135
22255
  if (prompt)
@@ -22151,7 +22271,7 @@ ${prompt}` : prefix;
22151
22271
  return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
22152
22272
  logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
22153
22273
  return f.forEach(async (chars) => {
22154
- await writeFile3(rawLogPath, chars, { flag: "a" }).catch(() => null);
22274
+ await writeFile4(rawLogPath, chars, { flag: "a" }).catch(() => null);
22155
22275
  }).run();
22156
22276
  }).catch(() => f.run());
22157
22277
  }).by(function consoleResponder(e) {
@@ -22223,7 +22343,7 @@ ${prompt}` : prefix;
22223
22343
  })).to(fromWritable(process.stdout));
22224
22344
  if (logPath) {
22225
22345
  await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
22226
- await writeFile3(logPath, terminalRender.render()).catch(() => null);
22346
+ await writeFile4(logPath, terminalRender.render()).catch(() => null);
22227
22347
  logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
22228
22348
  }
22229
22349
  const exitCode = await pendingExitCode.promise;
@@ -22235,7 +22355,7 @@ ${prompt}` : prefix;
22235
22355
  logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
22236
22356
  const logFilePath = path11.resolve(logFile);
22237
22357
  await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
22238
- await writeFile3(logFilePath, terminalRender.render());
22358
+ await writeFile4(logFilePath, terminalRender.render());
22239
22359
  }
22240
22360
  return { exitCode, logs: terminalRender.render() };
22241
22361
  async function sendEnter(waitms = 1000) {
@@ -22254,6 +22374,15 @@ ${prompt}` : prefix;
22254
22374
  resolve();
22255
22375
  }, 1000))
22256
22376
  ]);
22377
+ await Promise.race([
22378
+ nextStdout.wait(),
22379
+ new Promise((resolve) => setTimeout(() => {
22380
+ if (!nextStdout.ready) {
22381
+ shell.write("\r");
22382
+ }
22383
+ resolve();
22384
+ }, 3000))
22385
+ ]);
22257
22386
  }
22258
22387
  async function sendMessage3(message, { waitForReady = true } = {}) {
22259
22388
  if (waitForReady)
@@ -24132,13 +24261,13 @@ function stringWidth3(string, options = {}) {
24132
24261
  }
24133
24262
 
24134
24263
  // node_modules/y18n/build/lib/platform-shims/node.js
24135
- import { readFileSync as readFileSync4, statSync as statSync3, writeFile as writeFile4 } from "fs";
24264
+ import { readFileSync as readFileSync4, statSync as statSync3, writeFile as writeFile5 } from "fs";
24136
24265
  import { format as format3 } from "util";
24137
24266
  import { resolve as resolve3 } from "path";
24138
24267
  var node_default = {
24139
24268
  fs: {
24140
24269
  readFileSync: readFileSync4,
24141
- writeFile: writeFile4
24270
+ writeFile: writeFile5
24142
24271
  },
24143
24272
  format: format3,
24144
24273
  resolve: resolve3,
@@ -27848,7 +27977,7 @@ var package_default = {
27848
27977
  // ts/parseCliArgs.ts
27849
27978
  function parseCliArgs(argv) {
27850
27979
  const cliName = argv[1]?.split(/[/\\]/).at(-1)?.replace(/(\.[jt]s)?$/, "").replace(/^(cli|agent)(-yes$)?/, "").replace(/^ay$/, "").replace(/-yes$/, "") || undefined;
27851
- const parsedArgv = yargs_default(hideBin(argv)).usage("Usage: $0 [cli] [agent-yes args] [agent-cli args] [--] [prompts...]").example("$0 claude --idle=30s -- solve all todos in my codebase, commit one by one", "Run Claude with a 30 seconds idle timeout, and the prompt is everything after `--`").option("robust", {
27980
+ const parsedArgv = yargs_default(hideBin(argv)).usage("Usage: $0 [cli] [agent-yes args] [agent-cli args] [--] [prompts...]").example("$0 claude --idle=30s -- solve all todos in my codebase, commit one by one", "Run Claude with a 30 seconds idle timeout, and the prompt is everything after `--`").example("$0 claude --stdpush", "Run Claude with external stdin input enabled via --append-prompt").option("robust", {
27852
27981
  type: "boolean",
27853
27982
  default: true,
27854
27983
  description: "re-spawn Claude with --continue if it crashes, only works for claude yet",
@@ -27896,11 +28025,12 @@ function parseCliArgs(argv) {
27896
28025
  alias: "c"
27897
28026
  }).option("append-prompt", {
27898
28027
  type: "string",
27899
- description: "Send a prompt to the active agent's FIFO stdin in current directory"
27900
- }).option("fifo", {
28028
+ description: "Send a prompt to the active agent's stdin in current directory"
28029
+ }).option("stdpush", {
27901
28030
  type: "boolean",
27902
- description: "Enable FIFO input stream for additional stdin input (Linux only)",
27903
- default: false
28031
+ description: "Enable external input stream to push additional data to stdin",
28032
+ default: false,
28033
+ alias: ["ipc", "fifo"]
27904
28034
  }).positional("cli", {
27905
28035
  describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
27906
28036
  type: "string",
@@ -27973,7 +28103,7 @@ function parseCliArgs(argv) {
27973
28103
  resume: parsedArgv.continue,
27974
28104
  useSkills: parsedArgv.useSkills,
27975
28105
  appendPrompt: parsedArgv.appendPrompt,
27976
- useFifo: parsedArgv.fifo
28106
+ useFifo: parsedArgv.stdpush || parsedArgv.ipc || parsedArgv.fifo
27977
28107
  };
27978
28108
  }
27979
28109
 
@@ -27996,7 +28126,7 @@ var logger2 = import_winston3.default.createLogger({
27996
28126
 
27997
28127
  // ts/pidStore.ts
27998
28128
  init_logger();
27999
- import { mkdir as mkdir6 } from "fs/promises";
28129
+ import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
28000
28130
  import path12 from "path";
28001
28131
 
28002
28132
  class SqliteAdapter2 {
@@ -28040,15 +28170,16 @@ class SqliteAdapter2 {
28040
28170
 
28041
28171
  class PidStore2 {
28042
28172
  db;
28043
- baseDir;
28173
+ storeDir;
28044
28174
  dbPath;
28045
28175
  constructor(workingDir) {
28046
- this.baseDir = path12.resolve(workingDir, ".agent-yes");
28047
- this.dbPath = path12.join(this.baseDir, "pid.sqlite");
28176
+ this.storeDir = path12.resolve(workingDir, ".agent-yes");
28177
+ this.dbPath = path12.join(this.storeDir, "pid.sqlite");
28048
28178
  }
28049
28179
  async init() {
28050
- await mkdir6(path12.join(this.baseDir, "logs"), { recursive: true });
28051
- await mkdir6(path12.join(this.baseDir, "fifo"), { recursive: true });
28180
+ await mkdir6(path12.join(this.storeDir, "logs"), { recursive: true });
28181
+ await mkdir6(path12.join(this.storeDir, "fifo"), { recursive: true });
28182
+ await this.ensureGitignore();
28052
28183
  this.db = new SqliteAdapter2;
28053
28184
  await this.db.init(this.dbPath);
28054
28185
  this.db.run("PRAGMA journal_mode=WAL");
@@ -28120,10 +28251,14 @@ class PidStore2 {
28120
28251
  logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
28121
28252
  }
28122
28253
  getLogPath(pid) {
28123
- return path12.resolve(this.baseDir, "logs", `${pid}.log`);
28254
+ return path12.resolve(this.storeDir, "logs", `${pid}.log`);
28124
28255
  }
28125
28256
  getFifoPath(pid) {
28126
- return path12.resolve(this.baseDir, "fifo", `${pid}.stdin`);
28257
+ if (process.platform === "win32") {
28258
+ return `\\\\.\\pipe\\agent-yes-${pid}`;
28259
+ } else {
28260
+ return path12.resolve(this.storeDir, "fifo", `${pid}.stdin`);
28261
+ }
28127
28262
  }
28128
28263
  async cleanStaleRecords() {
28129
28264
  const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
@@ -28152,6 +28287,28 @@ class PidStore2 {
28152
28287
  return false;
28153
28288
  }
28154
28289
  }
28290
+ async ensureGitignore() {
28291
+ const gitignorePath = path12.join(this.storeDir, ".gitignore");
28292
+ const gitignoreContent = `# Auto-generated .gitignore for agent-yes
28293
+ # Ignore all log files and runtime data
28294
+ logs/
28295
+ fifo/
28296
+ *.sqlite
28297
+ *.sqlite-*
28298
+ *.log
28299
+ *.raw.log
28300
+ *.lines.log
28301
+ *.debug.log
28302
+ `;
28303
+ try {
28304
+ await writeFile6(gitignorePath, gitignoreContent, { flag: "wx" });
28305
+ logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
28306
+ } catch (error) {
28307
+ if (error.code !== "EEXIST") {
28308
+ logger.warn(`[pidStore] Failed to create .gitignore:`, error);
28309
+ }
28310
+ }
28311
+ }
28155
28312
  static async findActiveFifo(workingDir) {
28156
28313
  const store = new PidStore2(workingDir);
28157
28314
  await store.init();
@@ -28164,16 +28321,42 @@ class PidStore2 {
28164
28321
  // ts/cli.ts
28165
28322
  var config3 = parseCliArgs(process.argv);
28166
28323
  if (config3.appendPrompt) {
28167
- const fifoPath = await PidStore2.findActiveFifo(process.cwd());
28168
- if (!fifoPath) {
28169
- console.error("No active agent with FIFO found in current directory.");
28324
+ const ipcPath = await PidStore2.findActiveFifo(process.cwd());
28325
+ if (!ipcPath) {
28326
+ console.error("No active agent with IPC found in current directory.");
28327
+ process.exit(1);
28328
+ }
28329
+ try {
28330
+ if (process.platform === "win32") {
28331
+ const { connect } = await import("net");
28332
+ await new Promise((resolve5, reject) => {
28333
+ const client = connect(ipcPath);
28334
+ client.on("connect", () => {
28335
+ client.write(config3.appendPrompt + "\r");
28336
+ client.end();
28337
+ console.log(`Sent prompt to Windows named pipe: ${ipcPath}`);
28338
+ resolve5();
28339
+ });
28340
+ client.on("error", (error) => {
28341
+ console.error(`Failed to connect to named pipe: ${error}`);
28342
+ reject(error);
28343
+ });
28344
+ setTimeout(() => {
28345
+ client.destroy();
28346
+ reject(new Error("Connection timeout"));
28347
+ }, 5000);
28348
+ });
28349
+ } else {
28350
+ const { writeFileSync: writeFileSync2, openSync, closeSync } = await import("fs");
28351
+ const fd = openSync(ipcPath, "w");
28352
+ writeFileSync2(fd, config3.appendPrompt + "\r");
28353
+ closeSync(fd);
28354
+ console.log(`Sent prompt to FIFO: ${ipcPath}`);
28355
+ }
28356
+ } catch (error) {
28357
+ console.error(`Failed to send prompt: ${error}`);
28170
28358
  process.exit(1);
28171
28359
  }
28172
- const { writeFileSync: writeFileSync2, openSync, closeSync } = await import("fs");
28173
- const fd = openSync(fifoPath, "w");
28174
- writeFileSync2(fd, config3.appendPrompt + "\r");
28175
- closeSync(fd);
28176
- console.log(`Sent prompt to ${fifoPath}`);
28177
28360
  process.exit(0);
28178
28361
  }
28179
28362
  if (!config3.cli) {
@@ -28190,5 +28373,5 @@ var { exitCode } = await cliYes(config3);
28190
28373
  console.log("exiting process");
28191
28374
  process.exit(exitCode ?? 1);
28192
28375
 
28193
- //# debugId=624A56792A6F741964756E2164756E21
28376
+ //# debugId=2519B84A9286C6F364756E2164756E21
28194
28377
  //# sourceMappingURL=cli.js.map
package/dist/index.js CHANGED
@@ -20631,10 +20631,91 @@ import { fromReadable } from "from-node-stream";
20631
20631
  import { createReadStream as createReadStream2, mkdirSync } from "fs";
20632
20632
  import { unlink } from "fs/promises";
20633
20633
  import { dirname } from "path";
20634
+ import { createServer } from "net";
20634
20635
  function createFifoStream(cli, customPath) {
20635
- if (process.platform !== "linux") {
20636
+ if (process.platform === "win32") {
20637
+ return createWindowsNamedPipe(cli, customPath);
20638
+ } else if (process.platform === "linux") {
20639
+ return createLinuxFifo(cli, customPath);
20640
+ } else {
20641
+ logger.warn(`[${cli}-yes] IPC not supported on platform: ${process.platform}`);
20642
+ return null;
20643
+ }
20644
+ }
20645
+ function createWindowsNamedPipe(cli, customPath) {
20646
+ try {
20647
+ let pipePath;
20648
+ if (customPath) {
20649
+ pipePath = customPath;
20650
+ } else {
20651
+ const timestamp = new Date().toISOString().replace(/\D/g, "").slice(0, 17);
20652
+ const randomSuffix = Math.random().toString(36).substring(2, 5);
20653
+ pipePath = `\\\\.\\pipe\\agent-yes-${timestamp}${randomSuffix}`;
20654
+ }
20655
+ logger.info(`[${cli}-yes] Creating Windows named pipe at ${pipePath}`);
20656
+ const server = createServer();
20657
+ let connection = null;
20658
+ let isClosing = false;
20659
+ const stream = new ReadableStream({
20660
+ start(controller) {
20661
+ server.on("connection", (socket) => {
20662
+ connection = socket;
20663
+ logger.info(`[${cli}-yes] Client connected to named pipe`);
20664
+ socket.on("data", (chunk) => {
20665
+ const data = chunk.toString();
20666
+ logger.debug(`[${cli}-yes] Received data via named pipe: ${data}`);
20667
+ controller.enqueue(data);
20668
+ });
20669
+ socket.on("end", () => {
20670
+ logger.debug(`[${cli}-yes] Client disconnected from named pipe`);
20671
+ connection = null;
20672
+ });
20673
+ socket.on("error", (error) => {
20674
+ logger.warn(`[${cli}-yes] Named pipe socket error:`, error);
20675
+ if (!isClosing) {
20676
+ controller.error(error);
20677
+ }
20678
+ });
20679
+ });
20680
+ server.on("error", (error) => {
20681
+ logger.warn(`[${cli}-yes] Named pipe server error:`, error);
20682
+ if (!isClosing) {
20683
+ controller.error(error);
20684
+ }
20685
+ });
20686
+ server.listen(pipePath, () => {
20687
+ logger.info(`[${cli}-yes] Named pipe server listening at ${pipePath}`);
20688
+ });
20689
+ },
20690
+ cancel() {
20691
+ isClosing = true;
20692
+ if (connection) {
20693
+ connection.end();
20694
+ }
20695
+ server.close();
20696
+ }
20697
+ });
20698
+ const cleanup = async () => {
20699
+ isClosing = true;
20700
+ if (connection) {
20701
+ connection.end();
20702
+ }
20703
+ server.close();
20704
+ logger.info(`[${cli}-yes] Cleaned up Windows named pipe at ${pipePath}`);
20705
+ };
20706
+ process.on("exit", () => cleanup().catch(() => null));
20707
+ process.on("SIGINT", () => cleanup().catch(() => null));
20708
+ process.on("SIGTERM", () => cleanup().catch(() => null));
20709
+ return {
20710
+ stream,
20711
+ cleanup
20712
+ };
20713
+ } catch (error) {
20714
+ logger.warn(`[${cli}-yes] Failed to create Windows named pipe:`, error);
20636
20715
  return null;
20637
20716
  }
20717
+ }
20718
+ function createLinuxFifo(cli, customPath) {
20638
20719
  let fifoPath = null;
20639
20720
  let fifoStream = null;
20640
20721
  try {
@@ -20730,7 +20811,7 @@ var init_fifo = __esm(() => {
20730
20811
  });
20731
20812
 
20732
20813
  // ts/pidStore.ts
20733
- import { mkdir as mkdir3 } from "fs/promises";
20814
+ import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
20734
20815
  import path9 from "path";
20735
20816
 
20736
20817
  class SqliteAdapter {
@@ -20774,15 +20855,16 @@ class SqliteAdapter {
20774
20855
 
20775
20856
  class PidStore {
20776
20857
  db;
20777
- baseDir;
20858
+ storeDir;
20778
20859
  dbPath;
20779
20860
  constructor(workingDir) {
20780
- this.baseDir = path9.resolve(workingDir, ".agent-yes");
20781
- this.dbPath = path9.join(this.baseDir, "pid.sqlite");
20861
+ this.storeDir = path9.resolve(workingDir, ".agent-yes");
20862
+ this.dbPath = path9.join(this.storeDir, "pid.sqlite");
20782
20863
  }
20783
20864
  async init() {
20784
- await mkdir3(path9.join(this.baseDir, "logs"), { recursive: true });
20785
- await mkdir3(path9.join(this.baseDir, "fifo"), { recursive: true });
20865
+ await mkdir3(path9.join(this.storeDir, "logs"), { recursive: true });
20866
+ await mkdir3(path9.join(this.storeDir, "fifo"), { recursive: true });
20867
+ await this.ensureGitignore();
20786
20868
  this.db = new SqliteAdapter;
20787
20869
  await this.db.init(this.dbPath);
20788
20870
  this.db.run("PRAGMA journal_mode=WAL");
@@ -20854,10 +20936,14 @@ class PidStore {
20854
20936
  logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
20855
20937
  }
20856
20938
  getLogPath(pid) {
20857
- return path9.resolve(this.baseDir, "logs", `${pid}.log`);
20939
+ return path9.resolve(this.storeDir, "logs", `${pid}.log`);
20858
20940
  }
20859
20941
  getFifoPath(pid) {
20860
- return path9.resolve(this.baseDir, "fifo", `${pid}.stdin`);
20942
+ if (process.platform === "win32") {
20943
+ return `\\\\.\\pipe\\agent-yes-${pid}`;
20944
+ } else {
20945
+ return path9.resolve(this.storeDir, "fifo", `${pid}.stdin`);
20946
+ }
20861
20947
  }
20862
20948
  async cleanStaleRecords() {
20863
20949
  const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
@@ -20886,6 +20972,28 @@ class PidStore {
20886
20972
  return false;
20887
20973
  }
20888
20974
  }
20975
+ async ensureGitignore() {
20976
+ const gitignorePath = path9.join(this.storeDir, ".gitignore");
20977
+ const gitignoreContent = `# Auto-generated .gitignore for agent-yes
20978
+ # Ignore all log files and runtime data
20979
+ logs/
20980
+ fifo/
20981
+ *.sqlite
20982
+ *.sqlite-*
20983
+ *.log
20984
+ *.raw.log
20985
+ *.lines.log
20986
+ *.debug.log
20987
+ `;
20988
+ try {
20989
+ await writeFile3(gitignorePath, gitignoreContent, { flag: "wx" });
20990
+ logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
20991
+ } catch (error) {
20992
+ if (error.code !== "EEXIST") {
20993
+ logger.warn(`[pidStore] Failed to create .gitignore:`, error);
20994
+ }
20995
+ }
20996
+ }
20889
20997
  static async findActiveFifo(workingDir) {
20890
20998
  const store = new PidStore(workingDir);
20891
20999
  await store.init();
@@ -21024,8 +21132,11 @@ function getDefaultConfig() {
21024
21132
  fatal: []
21025
21133
  },
21026
21134
  amp: {
21027
- help: "",
21028
- install: "npm i -g @sourcegraph/amp",
21135
+ help: "https://ampcode.com/",
21136
+ install: {
21137
+ bash: "curl -fsSL https://ampcode.com/install.sh | bash",
21138
+ npm: "npm i -g @sourcegraph/amp"
21139
+ },
21029
21140
  enter: [
21030
21141
  /^.{0,4} Approve /
21031
21142
  ]
@@ -21195,7 +21306,7 @@ init_pidStore();
21195
21306
  await init_pty();
21196
21307
  var import_winston2 = __toESM(require_winston(), 1);
21197
21308
  import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
21198
- import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
21309
+ import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
21199
21310
  import path11 from "path";
21200
21311
  var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
21201
21312
  var CLIS_CONFIG = config.clis;
@@ -21544,15 +21655,15 @@ ${prompt}` : prefix;
21544
21655
  }).by((s) => {
21545
21656
  if (!useFifo)
21546
21657
  return s;
21547
- const fifoResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
21548
- if (!fifoResult)
21658
+ const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
21659
+ if (!ipcResult)
21549
21660
  return s;
21550
- pendingExitCode.promise.finally(() => fifoResult.cleanup());
21661
+ pendingExitCode.promise.finally(() => ipcResult.cleanup());
21551
21662
  process.stderr.write(`
21552
21663
  Append prompts: ${cli}-yes --append-prompt '...'
21553
21664
 
21554
21665
  `);
21555
- return s.merge(fifoResult.stream);
21666
+ return s.merge(ipcResult.stream);
21556
21667
  }).onStart(async function promptOnStart() {
21557
21668
  logger.debug("Sending prompt message: " + JSON.stringify(prompt));
21558
21669
  if (prompt)
@@ -21574,7 +21685,7 @@ ${prompt}` : prefix;
21574
21685
  return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
21575
21686
  logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
21576
21687
  return f.forEach(async (chars) => {
21577
- await writeFile3(rawLogPath, chars, { flag: "a" }).catch(() => null);
21688
+ await writeFile4(rawLogPath, chars, { flag: "a" }).catch(() => null);
21578
21689
  }).run();
21579
21690
  }).catch(() => f.run());
21580
21691
  }).by(function consoleResponder(e) {
@@ -21646,7 +21757,7 @@ ${prompt}` : prefix;
21646
21757
  })).to(fromWritable(process.stdout));
21647
21758
  if (logPath) {
21648
21759
  await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
21649
- await writeFile3(logPath, terminalRender.render()).catch(() => null);
21760
+ await writeFile4(logPath, terminalRender.render()).catch(() => null);
21650
21761
  logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
21651
21762
  }
21652
21763
  const exitCode = await pendingExitCode.promise;
@@ -21658,7 +21769,7 @@ ${prompt}` : prefix;
21658
21769
  logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
21659
21770
  const logFilePath = path11.resolve(logFile);
21660
21771
  await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
21661
- await writeFile3(logFilePath, terminalRender.render());
21772
+ await writeFile4(logFilePath, terminalRender.render());
21662
21773
  }
21663
21774
  return { exitCode, logs: terminalRender.render() };
21664
21775
  async function sendEnter(waitms = 1000) {
@@ -21677,6 +21788,15 @@ ${prompt}` : prefix;
21677
21788
  resolve();
21678
21789
  }, 1000))
21679
21790
  ]);
21791
+ await Promise.race([
21792
+ nextStdout.wait(),
21793
+ new Promise((resolve) => setTimeout(() => {
21794
+ if (!nextStdout.ready) {
21795
+ shell.write("\r");
21796
+ }
21797
+ resolve();
21798
+ }, 3000))
21799
+ ]);
21680
21800
  }
21681
21801
  async function sendMessage3(message, { waitForReady = true } = {}) {
21682
21802
  if (waitForReady)
@@ -21725,5 +21845,5 @@ export {
21725
21845
  CLIS_CONFIG
21726
21846
  };
21727
21847
 
21728
- //# debugId=41F67CAFCE0253CB64756E2164756E21
21848
+ //# debugId=6E96076BD519CF5364756E2164756E21
21729
21849
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-yes",
3
- "version": "1.35.1",
3
+ "version": "1.36.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
  "ai",
package/ts/cli.ts CHANGED
@@ -10,18 +10,48 @@ import { PidStore } from "./pidStore.ts";
10
10
  // Parse CLI arguments
11
11
  const config = parseCliArgs(process.argv);
12
12
 
13
- // Handle --append-prompt: write to active FIFO and exit
13
+ // Handle --append-prompt: write to active IPC (FIFO/Named Pipe) and exit
14
14
  if (config.appendPrompt) {
15
- const fifoPath = await PidStore.findActiveFifo(process.cwd());
16
- if (!fifoPath) {
17
- console.error("No active agent with FIFO found in current directory.");
15
+ const ipcPath = await PidStore.findActiveFifo(process.cwd());
16
+ if (!ipcPath) {
17
+ console.error("No active agent with IPC found in current directory.");
18
+ process.exit(1);
19
+ }
20
+
21
+ try {
22
+ if (process.platform === "win32") {
23
+ // Windows named pipe
24
+ const { connect } = await import("net");
25
+ await new Promise<void>((resolve, reject) => {
26
+ const client = connect(ipcPath);
27
+ client.on('connect', () => {
28
+ client.write(config.appendPrompt + "\r");
29
+ client.end();
30
+ console.log(`Sent prompt to Windows named pipe: ${ipcPath}`);
31
+ resolve();
32
+ });
33
+ client.on('error', (error) => {
34
+ console.error(`Failed to connect to named pipe: ${error}`);
35
+ reject(error);
36
+ });
37
+ // Timeout after 5 seconds
38
+ setTimeout(() => {
39
+ client.destroy();
40
+ reject(new Error('Connection timeout'));
41
+ }, 5000);
42
+ });
43
+ } else {
44
+ // Linux FIFO (original implementation)
45
+ const { writeFileSync, openSync, closeSync } = await import("fs");
46
+ const fd = openSync(ipcPath, "w");
47
+ writeFileSync(fd, config.appendPrompt + "\r");
48
+ closeSync(fd);
49
+ console.log(`Sent prompt to FIFO: ${ipcPath}`);
50
+ }
51
+ } catch (error) {
52
+ console.error(`Failed to send prompt: ${error}`);
18
53
  process.exit(1);
19
54
  }
20
- const { writeFileSync, openSync, closeSync } = await import("fs");
21
- const fd = openSync(fifoPath, "w");
22
- writeFileSync(fd, config.appendPrompt + "\r");
23
- closeSync(fd);
24
- console.log(`Sent prompt to ${fifoPath}`);
25
55
  process.exit(0);
26
56
  }
27
57
 
package/ts/index.ts CHANGED
@@ -580,14 +580,14 @@ export default async function agentYes({
580
580
  });
581
581
  })
582
582
 
583
- // read from FIFO if available, e.g. /tmp/agent-yes-*.stdin, which can be used to send additional input from other processes
583
+ // read from IPC stream if available (FIFO on Linux, Named Pipes on Windows)
584
584
  .by((s) => {
585
585
  if (!useFifo) return s;
586
- const fifoResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
587
- if (!fifoResult) return s;
588
- pendingExitCode.promise.finally(() => fifoResult.cleanup());
586
+ const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
587
+ if (!ipcResult) return s;
588
+ pendingExitCode.promise.finally(() => ipcResult.cleanup());
589
589
  process.stderr.write(`\n Append prompts: ${cli}-yes --append-prompt '...'\n\n`);
590
- return s.merge(fifoResult.stream);
590
+ return s.merge(ipcResult.stream);
591
591
  })
592
592
 
593
593
  // .map((e) => e.replaceAll('\x1a', '')) // remove ctrl+z from user's input, to prevent bug (but this seems bug)
@@ -808,6 +808,19 @@ export default async function agentYes({
808
808
  }, 1000),
809
809
  ),
810
810
  ]);
811
+
812
+ // retry the second time if not received any output in 3 second after sending Enter
813
+ await Promise.race([
814
+ nextStdout.wait(),
815
+ new Promise<void>((resolve) =>
816
+ setTimeout(() => {
817
+ if (!nextStdout.ready) {
818
+ shell.write("\r");
819
+ }
820
+ resolve();
821
+ }, 3000),
822
+ ),
823
+ ]);
811
824
  }
812
825
 
813
826
  async function sendMessage(message: string, { waitForReady = true } = {}) {
@@ -27,6 +27,10 @@ export function parseCliArgs(argv: string[]) {
27
27
  "$0 claude --idle=30s -- solve all todos in my codebase, commit one by one",
28
28
  "Run Claude with a 30 seconds idle timeout, and the prompt is everything after `--`",
29
29
  )
30
+ .example(
31
+ "$0 claude --stdpush",
32
+ "Run Claude with external stdin input enabled via --append-prompt",
33
+ )
30
34
  // TODO: add a --docker option, will tell cli.ts to start docker process with tty and handles all stdio forwarding
31
35
 
32
36
  .option("robust", {
@@ -91,12 +95,13 @@ export function parseCliArgs(argv: string[]) {
91
95
  })
92
96
  .option("append-prompt", {
93
97
  type: "string",
94
- description: "Send a prompt to the active agent's FIFO stdin in current directory",
98
+ description: "Send a prompt to the active agent's stdin in current directory",
95
99
  })
96
- .option("fifo", {
100
+ .option("stdpush", {
97
101
  type: "boolean",
98
- description: "Enable FIFO input stream for additional stdin input (Linux only)",
102
+ description: "Enable external input stream to push additional data to stdin",
99
103
  default: false,
104
+ alias: ["ipc", "fifo"], // backward compatibility
100
105
  })
101
106
  .positional("cli", {
102
107
  describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
@@ -191,6 +196,6 @@ export function parseCliArgs(argv: string[]) {
191
196
  resume: parsedArgv.continue, // Note: intentional use resume here to avoid preserved keyword (continue)
192
197
  useSkills: parsedArgv.useSkills,
193
198
  appendPrompt: parsedArgv.appendPrompt,
194
- useFifo: parsedArgv.fifo,
199
+ useFifo: parsedArgv.stdpush || parsedArgv.ipc || parsedArgv.fifo, // Support --stdpush, --ipc, and --fifo (backward compatibility)
195
200
  };
196
201
  }
package/ts/pidStore.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { mkdir } from "fs/promises";
1
+ import { mkdir, writeFile } from "fs/promises";
2
2
  import path from "path";
3
3
  import { logger } from "./logger.ts";
4
4
 
@@ -67,17 +67,20 @@ class SqliteAdapter {
67
67
 
68
68
  export class PidStore {
69
69
  protected db!: SqliteAdapter;
70
- private baseDir: string;
70
+ private storeDir: string;
71
71
  private dbPath: string;
72
72
 
73
73
  constructor(workingDir: string) {
74
- this.baseDir = path.resolve(workingDir, ".agent-yes");
75
- this.dbPath = path.join(this.baseDir, "pid.sqlite");
74
+ this.storeDir = path.resolve(workingDir, ".agent-yes");
75
+ this.dbPath = path.join(this.storeDir, "pid.sqlite");
76
76
  }
77
77
 
78
78
  async init(): Promise<void> {
79
- await mkdir(path.join(this.baseDir, "logs"), { recursive: true });
80
- await mkdir(path.join(this.baseDir, "fifo"), { recursive: true });
79
+ await mkdir(path.join(this.storeDir, "logs"), { recursive: true });
80
+ await mkdir(path.join(this.storeDir, "fifo"), { recursive: true });
81
+
82
+ // Auto-generate .gitignore for .agent-yes directory
83
+ await this.ensureGitignore();
81
84
 
82
85
  this.db = new SqliteAdapter();
83
86
  await this.db.init(this.dbPath);
@@ -182,11 +185,17 @@ export class PidStore {
182
185
  }
183
186
 
184
187
  getLogPath(pid: number): string {
185
- return path.resolve(this.baseDir, "logs", `${pid}.log`);
188
+ return path.resolve(this.storeDir, "logs", `${pid}.log`);
186
189
  }
187
190
 
188
191
  getFifoPath(pid: number): string {
189
- return path.resolve(this.baseDir, "fifo", `${pid}.stdin`);
192
+ if (process.platform === "win32") {
193
+ // Windows named pipe format
194
+ return `\\\\.\\pipe\\agent-yes-${pid}`;
195
+ } else {
196
+ // Linux FIFO file path
197
+ return path.resolve(this.storeDir, "fifo", `${pid}.stdin`);
198
+ }
190
199
  }
191
200
 
192
201
  async cleanStaleRecords(): Promise<void> {
@@ -226,6 +235,31 @@ export class PidStore {
226
235
  }
227
236
  }
228
237
 
238
+ private async ensureGitignore(): Promise<void> {
239
+ const gitignorePath = path.join(this.storeDir, ".gitignore");
240
+ const gitignoreContent = `# Auto-generated .gitignore for agent-yes
241
+ # Ignore all log files and runtime data
242
+ logs/
243
+ fifo/
244
+ *.sqlite
245
+ *.sqlite-*
246
+ *.log
247
+ *.raw.log
248
+ *.lines.log
249
+ *.debug.log
250
+ `;
251
+
252
+ try {
253
+ await writeFile(gitignorePath, gitignoreContent, { flag: 'wx' }); // wx = create only if doesn't exist
254
+ logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
255
+ } catch (error: any) {
256
+ if (error.code !== 'EEXIST') {
257
+ logger.warn(`[pidStore] Failed to create .gitignore:`, error);
258
+ }
259
+ // If file exists, that's fine - don't overwrite existing gitignore
260
+ }
261
+ }
262
+
229
263
  static async findActiveFifo(workingDir: string): Promise<string | null> {
230
264
  const store = new PidStore(workingDir);
231
265
  await store.init();