claude-yes 1.35.0 → 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}`);
20638
20644
  return null;
20639
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);
20717
+ return null;
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,14 @@ 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
+ },
21142
+ enter: [
21143
+ /^.{0,4} Approve /
21144
+ ]
21031
21145
  }
21032
21146
  }
21033
21147
  });
@@ -21218,7 +21332,7 @@ __export(exports_ts, {
21218
21332
  CLIS_CONFIG: () => CLIS_CONFIG2
21219
21333
  });
21220
21334
  import { fromReadable as fromReadable3, fromWritable as fromWritable2 } from "from-node-stream";
21221
- 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";
21222
21336
  import path13 from "path";
21223
21337
  async function agentYes2({
21224
21338
  cli,
@@ -21565,15 +21679,15 @@ ${prompt}` : prefix;
21565
21679
  }).by((s) => {
21566
21680
  if (!useFifo)
21567
21681
  return s;
21568
- const fifoResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
21569
- if (!fifoResult)
21682
+ const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
21683
+ if (!ipcResult)
21570
21684
  return s;
21571
- pendingExitCode.promise.finally(() => fifoResult.cleanup());
21685
+ pendingExitCode.promise.finally(() => ipcResult.cleanup());
21572
21686
  process.stderr.write(`
21573
21687
  Append prompts: ${cli}-yes --append-prompt '...'
21574
21688
 
21575
21689
  `);
21576
- return s.merge(fifoResult.stream);
21690
+ return s.merge(ipcResult.stream);
21577
21691
  }).onStart(async function promptOnStart() {
21578
21692
  logger.debug("Sending prompt message: " + JSON.stringify(prompt));
21579
21693
  if (prompt)
@@ -21595,7 +21709,7 @@ ${prompt}` : prefix;
21595
21709
  return await mkdir7(path13.dirname(rawLogPath), { recursive: true }).then(() => {
21596
21710
  logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
21597
21711
  return f.forEach(async (chars) => {
21598
- await writeFile5(rawLogPath, chars, { flag: "a" }).catch(() => null);
21712
+ await writeFile7(rawLogPath, chars, { flag: "a" }).catch(() => null);
21599
21713
  }).run();
21600
21714
  }).catch(() => f.run());
21601
21715
  }).by(function consoleResponder(e) {
@@ -21667,7 +21781,7 @@ ${prompt}` : prefix;
21667
21781
  })).to(fromWritable2(process.stdout));
21668
21782
  if (logPath) {
21669
21783
  await mkdir7(path13.dirname(logPath), { recursive: true }).catch(() => null);
21670
- await writeFile5(logPath, terminalRender.render()).catch(() => null);
21784
+ await writeFile7(logPath, terminalRender.render()).catch(() => null);
21671
21785
  logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
21672
21786
  }
21673
21787
  const exitCode = await pendingExitCode.promise;
@@ -21679,7 +21793,7 @@ ${prompt}` : prefix;
21679
21793
  logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
21680
21794
  const logFilePath = path13.resolve(logFile);
21681
21795
  await mkdir7(path13.dirname(logFilePath), { recursive: true }).catch(() => null);
21682
- await writeFile5(logFilePath, terminalRender.render());
21796
+ await writeFile7(logFilePath, terminalRender.render());
21683
21797
  }
21684
21798
  return { exitCode, logs: terminalRender.render() };
21685
21799
  async function sendEnter(waitms = 1000) {
@@ -21698,6 +21812,15 @@ ${prompt}` : prefix;
21698
21812
  resolve5();
21699
21813
  }, 1000))
21700
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
+ ]);
21701
21824
  }
21702
21825
  async function sendMessage3(message, { waitForReady = true } = {}) {
21703
21826
  if (waitForReady)
@@ -21769,7 +21892,7 @@ init_pidStore();
21769
21892
  await init_pty();
21770
21893
  var import_winston2 = __toESM(require_winston(), 1);
21771
21894
  import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
21772
- 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";
21773
21896
  import path11 from "path";
21774
21897
  var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
21775
21898
  var CLIS_CONFIG = config.clis;
@@ -22118,15 +22241,15 @@ ${prompt}` : prefix;
22118
22241
  }).by((s) => {
22119
22242
  if (!useFifo)
22120
22243
  return s;
22121
- const fifoResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
22122
- if (!fifoResult)
22244
+ const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
22245
+ if (!ipcResult)
22123
22246
  return s;
22124
- pendingExitCode.promise.finally(() => fifoResult.cleanup());
22247
+ pendingExitCode.promise.finally(() => ipcResult.cleanup());
22125
22248
  process.stderr.write(`
22126
22249
  Append prompts: ${cli}-yes --append-prompt '...'
22127
22250
 
22128
22251
  `);
22129
- return s.merge(fifoResult.stream);
22252
+ return s.merge(ipcResult.stream);
22130
22253
  }).onStart(async function promptOnStart() {
22131
22254
  logger.debug("Sending prompt message: " + JSON.stringify(prompt));
22132
22255
  if (prompt)
@@ -22148,7 +22271,7 @@ ${prompt}` : prefix;
22148
22271
  return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
22149
22272
  logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
22150
22273
  return f.forEach(async (chars) => {
22151
- await writeFile3(rawLogPath, chars, { flag: "a" }).catch(() => null);
22274
+ await writeFile4(rawLogPath, chars, { flag: "a" }).catch(() => null);
22152
22275
  }).run();
22153
22276
  }).catch(() => f.run());
22154
22277
  }).by(function consoleResponder(e) {
@@ -22220,7 +22343,7 @@ ${prompt}` : prefix;
22220
22343
  })).to(fromWritable(process.stdout));
22221
22344
  if (logPath) {
22222
22345
  await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
22223
- await writeFile3(logPath, terminalRender.render()).catch(() => null);
22346
+ await writeFile4(logPath, terminalRender.render()).catch(() => null);
22224
22347
  logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
22225
22348
  }
22226
22349
  const exitCode = await pendingExitCode.promise;
@@ -22232,7 +22355,7 @@ ${prompt}` : prefix;
22232
22355
  logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
22233
22356
  const logFilePath = path11.resolve(logFile);
22234
22357
  await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
22235
- await writeFile3(logFilePath, terminalRender.render());
22358
+ await writeFile4(logFilePath, terminalRender.render());
22236
22359
  }
22237
22360
  return { exitCode, logs: terminalRender.render() };
22238
22361
  async function sendEnter(waitms = 1000) {
@@ -22251,6 +22374,15 @@ ${prompt}` : prefix;
22251
22374
  resolve();
22252
22375
  }, 1000))
22253
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
+ ]);
22254
22386
  }
22255
22387
  async function sendMessage3(message, { waitForReady = true } = {}) {
22256
22388
  if (waitForReady)
@@ -24129,13 +24261,13 @@ function stringWidth3(string, options = {}) {
24129
24261
  }
24130
24262
 
24131
24263
  // node_modules/y18n/build/lib/platform-shims/node.js
24132
- 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";
24133
24265
  import { format as format3 } from "util";
24134
24266
  import { resolve as resolve3 } from "path";
24135
24267
  var node_default = {
24136
24268
  fs: {
24137
24269
  readFileSync: readFileSync4,
24138
- writeFile: writeFile4
24270
+ writeFile: writeFile5
24139
24271
  },
24140
24272
  format: format3,
24141
24273
  resolve: resolve3,
@@ -27844,8 +27976,8 @@ var package_default = {
27844
27976
 
27845
27977
  // ts/parseCliArgs.ts
27846
27978
  function parseCliArgs(argv) {
27847
- const cliName = argv[1]?.split(/[/\\]/).at(-1)?.replace(/(\.[jt]s)?$/, "").replace(/^(cli|agent)(-yes$)?/, "").replace(/-yes$/, "") || undefined;
27848
- 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", {
27979
+ const cliName = argv[1]?.split(/[/\\]/).at(-1)?.replace(/(\.[jt]s)?$/, "").replace(/^(cli|agent)(-yes$)?/, "").replace(/^ay$/, "").replace(/-yes$/, "") || undefined;
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", {
27849
27981
  type: "boolean",
27850
27982
  default: true,
27851
27983
  description: "re-spawn Claude with --continue if it crashes, only works for claude yet",
@@ -27893,11 +28025,12 @@ function parseCliArgs(argv) {
27893
28025
  alias: "c"
27894
28026
  }).option("append-prompt", {
27895
28027
  type: "string",
27896
- description: "Send a prompt to the active agent's FIFO stdin in current directory"
27897
- }).option("fifo", {
28028
+ description: "Send a prompt to the active agent's stdin in current directory"
28029
+ }).option("stdpush", {
27898
28030
  type: "boolean",
27899
- description: "Enable FIFO input stream for additional stdin input (Linux only)",
27900
- default: false
28031
+ description: "Enable external input stream to push additional data to stdin",
28032
+ default: false,
28033
+ alias: ["ipc", "fifo"]
27901
28034
  }).positional("cli", {
27902
28035
  describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
27903
28036
  type: "string",
@@ -27958,7 +28091,7 @@ function parseCliArgs(argv) {
27958
28091
  return {
27959
28092
  cwd: process.cwd(),
27960
28093
  env: process.env,
27961
- cli: cliName || parsedArgv.cli || parsedArgv._[0]?.toString()?.replace?.(/-yes$/, ""),
28094
+ cli: cliName || parsedArgv.cli || (dashIndex !== 0 ? parsedArgv._[0]?.toString()?.replace?.(/-yes$/, "") : undefined),
27962
28095
  cliArgs: cliArgsForSpawn,
27963
28096
  prompt: [parsedArgv.prompt, dashPrompt].filter(Boolean).join(" ") || undefined,
27964
28097
  install: parsedArgv.install,
@@ -27970,7 +28103,7 @@ function parseCliArgs(argv) {
27970
28103
  resume: parsedArgv.continue,
27971
28104
  useSkills: parsedArgv.useSkills,
27972
28105
  appendPrompt: parsedArgv.appendPrompt,
27973
- useFifo: parsedArgv.fifo
28106
+ useFifo: parsedArgv.stdpush || parsedArgv.ipc || parsedArgv.fifo
27974
28107
  };
27975
28108
  }
27976
28109
 
@@ -27993,7 +28126,7 @@ var logger2 = import_winston3.default.createLogger({
27993
28126
 
27994
28127
  // ts/pidStore.ts
27995
28128
  init_logger();
27996
- import { mkdir as mkdir6 } from "fs/promises";
28129
+ import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
27997
28130
  import path12 from "path";
27998
28131
 
27999
28132
  class SqliteAdapter2 {
@@ -28037,15 +28170,16 @@ class SqliteAdapter2 {
28037
28170
 
28038
28171
  class PidStore2 {
28039
28172
  db;
28040
- baseDir;
28173
+ storeDir;
28041
28174
  dbPath;
28042
28175
  constructor(workingDir) {
28043
- this.baseDir = path12.resolve(workingDir, ".agent-yes");
28044
- 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");
28045
28178
  }
28046
28179
  async init() {
28047
- await mkdir6(path12.join(this.baseDir, "logs"), { recursive: true });
28048
- 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();
28049
28183
  this.db = new SqliteAdapter2;
28050
28184
  await this.db.init(this.dbPath);
28051
28185
  this.db.run("PRAGMA journal_mode=WAL");
@@ -28117,10 +28251,14 @@ class PidStore2 {
28117
28251
  logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
28118
28252
  }
28119
28253
  getLogPath(pid) {
28120
- return path12.resolve(this.baseDir, "logs", `${pid}.log`);
28254
+ return path12.resolve(this.storeDir, "logs", `${pid}.log`);
28121
28255
  }
28122
28256
  getFifoPath(pid) {
28123
- 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
+ }
28124
28262
  }
28125
28263
  async cleanStaleRecords() {
28126
28264
  const activeRecords = this.db.query("SELECT * FROM pid_records WHERE status != 'exited'");
@@ -28149,6 +28287,28 @@ class PidStore2 {
28149
28287
  return false;
28150
28288
  }
28151
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
+ }
28152
28312
  static async findActiveFifo(workingDir) {
28153
28313
  const store = new PidStore2(workingDir);
28154
28314
  await store.init();
@@ -28161,16 +28321,42 @@ class PidStore2 {
28161
28321
  // ts/cli.ts
28162
28322
  var config3 = parseCliArgs(process.argv);
28163
28323
  if (config3.appendPrompt) {
28164
- const fifoPath = await PidStore2.findActiveFifo(process.cwd());
28165
- if (!fifoPath) {
28166
- 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}`);
28167
28358
  process.exit(1);
28168
28359
  }
28169
- const { writeFileSync: writeFileSync2, openSync, closeSync } = await import("fs");
28170
- const fd = openSync(fifoPath, "w");
28171
- writeFileSync2(fd, config3.appendPrompt + "\r");
28172
- closeSync(fd);
28173
- console.log(`Sent prompt to ${fifoPath}`);
28174
28360
  process.exit(0);
28175
28361
  }
28176
28362
  if (!config3.cli) {
@@ -28187,5 +28373,5 @@ var { exitCode } = await cliYes(config3);
28187
28373
  console.log("exiting process");
28188
28374
  process.exit(exitCode ?? 1);
28189
28375
 
28190
- //# debugId=C4007A87ED18C3B264756E2164756E21
28376
+ //# debugId=2519B84A9286C6F364756E2164756E21
28191
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}`);
20636
20642
  return null;
20637
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);
20715
+ return null;
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,14 @@ 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
+ },
21140
+ enter: [
21141
+ /^.{0,4} Approve /
21142
+ ]
21029
21143
  }
21030
21144
  }
21031
21145
  });
@@ -21192,7 +21306,7 @@ init_pidStore();
21192
21306
  await init_pty();
21193
21307
  var import_winston2 = __toESM(require_winston(), 1);
21194
21308
  import { fromReadable as fromReadable2, fromWritable } from "from-node-stream";
21195
- 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";
21196
21310
  import path11 from "path";
21197
21311
  var config = await init_agent_yes_config().then(() => exports_agent_yes_config).then((mod) => mod.default || mod);
21198
21312
  var CLIS_CONFIG = config.clis;
@@ -21541,15 +21655,15 @@ ${prompt}` : prefix;
21541
21655
  }).by((s) => {
21542
21656
  if (!useFifo)
21543
21657
  return s;
21544
- const fifoResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
21545
- if (!fifoResult)
21658
+ const ipcResult = createFifoStream(cli, pidStore.getFifoPath(shell.pid));
21659
+ if (!ipcResult)
21546
21660
  return s;
21547
- pendingExitCode.promise.finally(() => fifoResult.cleanup());
21661
+ pendingExitCode.promise.finally(() => ipcResult.cleanup());
21548
21662
  process.stderr.write(`
21549
21663
  Append prompts: ${cli}-yes --append-prompt '...'
21550
21664
 
21551
21665
  `);
21552
- return s.merge(fifoResult.stream);
21666
+ return s.merge(ipcResult.stream);
21553
21667
  }).onStart(async function promptOnStart() {
21554
21668
  logger.debug("Sending prompt message: " + JSON.stringify(prompt));
21555
21669
  if (prompt)
@@ -21571,7 +21685,7 @@ ${prompt}` : prefix;
21571
21685
  return await mkdir5(path11.dirname(rawLogPath), { recursive: true }).then(() => {
21572
21686
  logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
21573
21687
  return f.forEach(async (chars) => {
21574
- await writeFile3(rawLogPath, chars, { flag: "a" }).catch(() => null);
21688
+ await writeFile4(rawLogPath, chars, { flag: "a" }).catch(() => null);
21575
21689
  }).run();
21576
21690
  }).catch(() => f.run());
21577
21691
  }).by(function consoleResponder(e) {
@@ -21643,7 +21757,7 @@ ${prompt}` : prefix;
21643
21757
  })).to(fromWritable(process.stdout));
21644
21758
  if (logPath) {
21645
21759
  await mkdir5(path11.dirname(logPath), { recursive: true }).catch(() => null);
21646
- await writeFile3(logPath, terminalRender.render()).catch(() => null);
21760
+ await writeFile4(logPath, terminalRender.render()).catch(() => null);
21647
21761
  logger.info(`[${cli}-yes] Full logs saved to ${logPath}`);
21648
21762
  }
21649
21763
  const exitCode = await pendingExitCode.promise;
@@ -21655,7 +21769,7 @@ ${prompt}` : prefix;
21655
21769
  logger.info(`[${cli}-yes] Writing rendered logs to ${logFile}`);
21656
21770
  const logFilePath = path11.resolve(logFile);
21657
21771
  await mkdir5(path11.dirname(logFilePath), { recursive: true }).catch(() => null);
21658
- await writeFile3(logFilePath, terminalRender.render());
21772
+ await writeFile4(logFilePath, terminalRender.render());
21659
21773
  }
21660
21774
  return { exitCode, logs: terminalRender.render() };
21661
21775
  async function sendEnter(waitms = 1000) {
@@ -21674,6 +21788,15 @@ ${prompt}` : prefix;
21674
21788
  resolve();
21675
21789
  }, 1000))
21676
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
+ ]);
21677
21800
  }
21678
21801
  async function sendMessage3(message, { waitForReady = true } = {}) {
21679
21802
  if (waitForReady)
@@ -21722,5 +21845,5 @@ export {
21722
21845
  CLIS_CONFIG
21723
21846
  };
21724
21847
 
21725
- //# debugId=9A92FE5B1254037264756E2164756E21
21848
+ //# debugId=6E96076BD519CF5364756E2164756E21
21726
21849
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-yes",
3
- "version": "1.35.0",
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 } = {}) {
@@ -228,4 +228,21 @@ describe("CLI argument parsing", () => {
228
228
  expect(result.cli).toBe("codex");
229
229
  expect(result.prompt).toBe("Implement feature");
230
230
  });
231
+
232
+ it("should parse ay -- hello command (ay is wrapper, so CLI is undefined)", () => {
233
+ const result = parseCliArgs([
234
+ "node",
235
+ "/path/to/ay",
236
+ "--",
237
+ "hello",
238
+ ]);
239
+
240
+ // "ay" is a wrapper script like "agent-yes", so cliName is stripped to undefined
241
+ // cli.ts will default this to "claude" at runtime
242
+ expect(result.cli).toBeUndefined();
243
+ expect(result.cliArgs).toEqual([]);
244
+ expect(result.prompt).toBe("hello");
245
+ expect(result.verbose).toBe(false);
246
+ expect(result.robust).toBe(true);
247
+ });
231
248
  });
@@ -17,6 +17,7 @@ export function parseCliArgs(argv: string[]) {
17
17
  .at(-1)
18
18
  ?.replace(/(\.[jt]s)?$/, "")
19
19
  .replace(/^(cli|agent)(-yes$)?/, "")
20
+ .replace(/^ay$/, "") // treat standalone "ay" same as "agent-yes"
20
21
  .replace(/-yes$/, "") || undefined;
21
22
 
22
23
  // Parse args with yargs (same logic as cli.ts:16-73)
@@ -26,6 +27,10 @@ export function parseCliArgs(argv: string[]) {
26
27
  "$0 claude --idle=30s -- solve all todos in my codebase, commit one by one",
27
28
  "Run Claude with a 30 seconds idle timeout, and the prompt is everything after `--`",
28
29
  )
30
+ .example(
31
+ "$0 claude --stdpush",
32
+ "Run Claude with external stdin input enabled via --append-prompt",
33
+ )
29
34
  // TODO: add a --docker option, will tell cli.ts to start docker process with tty and handles all stdio forwarding
30
35
 
31
36
  .option("robust", {
@@ -90,12 +95,13 @@ export function parseCliArgs(argv: string[]) {
90
95
  })
91
96
  .option("append-prompt", {
92
97
  type: "string",
93
- 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",
94
99
  })
95
- .option("fifo", {
100
+ .option("stdpush", {
96
101
  type: "boolean",
97
- description: "Enable FIFO input stream for additional stdin input (Linux only)",
102
+ description: "Enable external input stream to push additional data to stdin",
98
103
  default: false,
104
+ alias: ["ipc", "fifo"], // backward compatibility
99
105
  })
100
106
  .positional("cli", {
101
107
  describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
@@ -174,7 +180,7 @@ export function parseCliArgs(argv: string[]) {
174
180
  env: process.env as Record<string, string>,
175
181
  cli: (cliName ||
176
182
  parsedArgv.cli ||
177
- parsedArgv._[0]?.toString()?.replace?.(/-yes$/, "")) as (typeof SUPPORTED_CLIS)[number],
183
+ (dashIndex !== 0 ? parsedArgv._[0]?.toString()?.replace?.(/-yes$/, "") : undefined)) as (typeof SUPPORTED_CLIS)[number],
178
184
  cliArgs: cliArgsForSpawn,
179
185
  prompt: [parsedArgv.prompt, dashPrompt].filter(Boolean).join(" ") || undefined,
180
186
  install: parsedArgv.install,
@@ -190,6 +196,6 @@ export function parseCliArgs(argv: string[]) {
190
196
  resume: parsedArgv.continue, // Note: intentional use resume here to avoid preserved keyword (continue)
191
197
  useSkills: parsedArgv.useSkills,
192
198
  appendPrompt: parsedArgv.appendPrompt,
193
- useFifo: parsedArgv.fifo,
199
+ useFifo: parsedArgv.stdpush || parsedArgv.ipc || parsedArgv.fifo, // Support --stdpush, --ipc, and --fifo (backward compatibility)
194
200
  };
195
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();