agent-yes 1.62.2 → 1.64.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Agent-Yes! for Claude/Codex/Gemini/Cursor/Copilot/Qwen/Auggie
2
2
 
3
- A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses. Originally designed for Claude CLI, now supports multiple AI coding assistants.
3
+ A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses. Originally designed for Claude CLI, now supports multiple AI coding assistants. Rewritten in Rust for improved performance and reliability.
4
4
 
5
5
  ⚠️ **Important Security Warning**: Only run this on trusted repositories. This tool automatically responds to prompts and can execute commands without user confirmation. Be aware of potential prompt injection attacks where malicious code or instructions could be embedded in files or user inputs to manipulate the automated responses.
6
6
 
@@ -2,15 +2,16 @@ import { t as logger } from "./logger-CX77vJDA.js";
2
2
  import { arch, platform } from "process";
3
3
  import { execSync } from "child_process";
4
4
  import { execaCommandSync, parseCommandString } from "execa";
5
- import { fromWritable } from "from-node-stream";
6
- import { appendFile, mkdir, readFile, readdir, rename, writeFile } from "fs/promises";
5
+ import { fromReadable, fromWritable } from "from-node-stream";
6
+ import { appendFile, mkdir, readFile, readdir, rename, unlink, writeFile } from "fs/promises";
7
7
  import path, { dirname, join } from "path";
8
8
  import DIE from "phpdie";
9
9
  import sflow from "sflow";
10
10
  import { TerminalRenderStream } from "terminal-render";
11
11
  import { homedir } from "os";
12
12
  import winston from "winston";
13
- import { closeSync, existsSync, fsyncSync, mkdirSync, openSync } from "fs";
13
+ import { closeSync, constants, createReadStream, existsSync, fsyncSync, mkdirSync, openSync } from "fs";
14
+ import { createServer } from "net";
14
15
  import { lock } from "proper-lockfile";
15
16
  import { execSync as execSync$1 } from "node:child_process";
16
17
  import { fileURLToPath } from "url";
@@ -422,6 +423,163 @@ function shouldUseLock(_cwd) {
422
423
  return true;
423
424
  }
424
425
 
426
+ //#endregion
427
+ //#region ts/beta/fifo.ts
428
+ /**
429
+ * Creates an IPC stream (FIFO on Linux, Named Pipes on Windows) for additional stdin input
430
+ * @param cli - The CLI name for logging purposes
431
+ * @param customPath - Optional custom path for the IPC file; if provided, uses this instead of generating a path
432
+ * @returns An object with stream and cleanup function, or null if failed
433
+ */
434
+ async function createFifoStream(cli, customPath) {
435
+ if (process.platform === "win32") return await createWindowsNamedPipe(cli, customPath);
436
+ else if (process.platform === "linux") return await createLinuxFifo(cli, customPath);
437
+ else {
438
+ logger.warn(`[${cli}-yes] IPC not supported on platform: ${process.platform}`);
439
+ return null;
440
+ }
441
+ }
442
+ /**
443
+ * Creates a Windows named pipe for IPC
444
+ */
445
+ async function createWindowsNamedPipe(cli, customPath) {
446
+ try {
447
+ let pipePath;
448
+ if (customPath) pipePath = customPath;
449
+ else pipePath = `\\\\.\\pipe\\agent-yes-${(/* @__PURE__ */ new Date()).toISOString().replace(/\D/g, "").slice(0, 17)}${Math.random().toString(36).substring(2, 5)}`;
450
+ logger.info(`[${cli}-yes] Creating Windows named pipe at ${pipePath}`);
451
+ const server = createServer();
452
+ let connection = null;
453
+ let isClosing = false;
454
+ const stream = new ReadableStream({
455
+ start(controller) {
456
+ server.on("connection", (socket) => {
457
+ connection = socket;
458
+ logger.info(`[${cli}-yes] Client connected to named pipe`);
459
+ socket.on("data", (chunk) => {
460
+ const data = chunk.toString();
461
+ logger.debug(`[${cli}-yes] Received data via named pipe: ${data}`);
462
+ controller.enqueue(data);
463
+ });
464
+ socket.on("end", () => {
465
+ logger.debug(`[${cli}-yes] Client disconnected from named pipe`);
466
+ connection = null;
467
+ });
468
+ socket.on("error", (error) => {
469
+ logger.warn(`[${cli}-yes] Named pipe socket error:`, error);
470
+ if (!isClosing) controller.error(error);
471
+ });
472
+ });
473
+ server.on("error", (error) => {
474
+ logger.warn(`[${cli}-yes] Named pipe server error:`, error);
475
+ if (!isClosing) controller.error(error);
476
+ });
477
+ server.listen(pipePath, () => {
478
+ logger.info(`[${cli}-yes] Named pipe server listening at ${pipePath}`);
479
+ });
480
+ },
481
+ cancel() {
482
+ isClosing = true;
483
+ if (connection) connection.end();
484
+ server.close();
485
+ }
486
+ });
487
+ const cleanup = async () => {
488
+ isClosing = true;
489
+ if (connection) connection.end();
490
+ server.close();
491
+ logger.info(`[${cli}-yes] Cleaned up Windows named pipe at ${pipePath}`);
492
+ };
493
+ process.on("exit", () => cleanup().catch(() => null));
494
+ process.on("SIGINT", () => cleanup().catch(() => null));
495
+ process.on("SIGTERM", () => cleanup().catch(() => null));
496
+ return {
497
+ stream,
498
+ [Symbol.asyncDispose]: cleanup
499
+ };
500
+ } catch (error) {
501
+ logger.warn(`[${cli}-yes] Failed to create Windows named pipe:`, error);
502
+ return null;
503
+ }
504
+ }
505
+ /**
506
+ * Creates a Linux FIFO for IPC (original implementation)
507
+ */
508
+ async function createLinuxFifo(cli, customPath) {
509
+ let fifoPath = null;
510
+ let fifoStream = null;
511
+ logger.debug(`[${cli}-yes] Creating Linux FIFO with customPath: ${customPath}`);
512
+ try {
513
+ if (customPath) fifoPath = customPath;
514
+ else fifoPath = `/tmp/agent-yes-${(/* @__PURE__ */ new Date()).toISOString().replace(/\D/g, "").slice(0, 17)}${Math.random().toString(36).substring(2, 5)}.stdin`;
515
+ try {
516
+ mkdirSync(dirname(fifoPath), { recursive: true });
517
+ } catch (dirError) {
518
+ logger.warn(`[${cli}-yes] Failed to create FIFO directory: ${dirError}`);
519
+ return null;
520
+ }
521
+ const escapedPath = fifoPath.replace(/'/g, "'\"'\"'");
522
+ const mkfifoResult = execaCommandSync(`mkfifo '${escapedPath}'`, { reject: false });
523
+ if (mkfifoResult.exitCode !== 0) {
524
+ logger.warn(`[${cli}-yes] mkfifo command failed with exit code ${mkfifoResult.exitCode}`);
525
+ logger.warn(`[${cli}-yes] Command: mkfifo '${escapedPath}'`);
526
+ if (mkfifoResult.stderr) logger.warn(`[${cli}-yes] mkfifo stderr: ${mkfifoResult.stderr}`);
527
+ if (mkfifoResult.stdout) logger.warn(`[${cli}-yes] mkfifo stdout: ${mkfifoResult.stdout}`);
528
+ return null;
529
+ }
530
+ logger.info(`[${cli}-yes] Created FIFO at ${fifoPath}`);
531
+ try {
532
+ fifoStream = createReadStream("", {
533
+ fd: openSync(fifoPath, constants.O_RDONLY | constants.O_NONBLOCK),
534
+ autoClose: true
535
+ });
536
+ const dummyWriteFd = openSync(fifoPath, constants.O_WRONLY | constants.O_NONBLOCK);
537
+ logger.info(`[${cli}-yes] FIFO opened for reading`);
538
+ const cleanupFifo = async () => {
539
+ try {
540
+ closeSync(dummyWriteFd);
541
+ } catch {}
542
+ if (fifoStream) try {
543
+ fifoStream.close();
544
+ logger.debug(`[${cli}-yes] Closed FIFO stream`);
545
+ } catch (error) {
546
+ logger.debug(`[${cli}-yes] Error closing FIFO stream:`, { error });
547
+ }
548
+ if (fifoPath) try {
549
+ await unlink(fifoPath).catch(() => null);
550
+ logger.info(`[${cli}-yes] Cleaned up FIFO at ${fifoPath}`);
551
+ } catch {}
552
+ };
553
+ process.on("exit", () => {
554
+ if (fifoPath) unlink(fifoPath).catch(() => null);
555
+ });
556
+ process.on("SIGINT", async () => {
557
+ await cleanupFifo();
558
+ });
559
+ process.on("SIGTERM", async () => {
560
+ await cleanupFifo();
561
+ });
562
+ return {
563
+ stream: sflow(fromReadable(fifoStream)).map((buffer) => buffer.toString()),
564
+ [Symbol.asyncDispose]: cleanupFifo
565
+ };
566
+ } catch (error) {
567
+ logger.warn(`[${cli}-yes] Failed to open FIFO at ${fifoPath}:`, { error });
568
+ if (error instanceof Error) {
569
+ logger.warn(`[${cli}-yes] Error details: ${error.message}`);
570
+ if (error.stack) logger.debug(`[${cli}-yes] Stack trace: ${error.stack}`);
571
+ }
572
+ if (fifoPath) unlink(fifoPath).catch(() => null);
573
+ return null;
574
+ }
575
+ } catch (error) {
576
+ logger.warn(`[${cli}-yes] Failed to create FIFO:`, { error });
577
+ if (error instanceof Error) logger.warn(`[${cli}-yes] Error details: ${error.message}`);
578
+ if (fifoPath) unlink(fifoPath).catch(() => null);
579
+ return null;
580
+ }
581
+ }
582
+
425
583
  //#endregion
426
584
  //#region ts/JsonlStore.ts
427
585
  /**
@@ -792,19 +950,13 @@ var ReadyManager = class {
792
950
  async function sendEnter(context, waitms = 1e3) {
793
951
  const st = Date.now();
794
952
  await context.idleWaiter.wait(waitms);
795
- const et = Date.now();
796
- logger.debug(`sendingEnter| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`);
953
+ logger.debug(`sendEnter| idleWait took ${String(Date.now() - st)}ms`);
797
954
  context.nextStdout.unready();
798
955
  context.shell.write("\r");
799
- logger.debug(`enterSent| idleWaiter.wait(${String(waitms)}) took ${String(et - st)}ms`);
800
- await Promise.race([context.nextStdout.wait(), new Promise((resolve) => setTimeout(() => {
801
- if (!context.nextStdout.isReady) context.shell.write("\r");
802
- resolve();
803
- }, 1e3))]);
804
- await Promise.race([context.nextStdout.wait(), new Promise((resolve) => setTimeout(() => {
956
+ for (const ms of [1e3, 3e3]) await Promise.race([context.nextStdout.wait(), new Promise((resolve) => setTimeout(() => {
805
957
  if (!context.nextStdout.isReady) context.shell.write("\r");
806
958
  resolve();
807
- }, 3e3))]);
959
+ }, ms))]);
808
960
  }
809
961
  /**
810
962
  * Send a message to the shell
@@ -907,7 +1059,7 @@ function tryCatch(catchFn, fn) {
907
1059
  //#endregion
908
1060
  //#region package.json
909
1061
  var name = "agent-yes";
910
- var version = "1.62.2";
1062
+ var version = "1.64.0";
911
1063
 
912
1064
  //#endregion
913
1065
  //#region ts/pty-fix.ts
@@ -1363,7 +1515,7 @@ const CLIS_CONFIG = config.clis;
1363
1515
  * });
1364
1516
  * ```
1365
1517
  */
1366
- async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, exitOnIdle, logFile, removeControlCharactersFromStdout = false, verbose = false, queue = false, install = false, resume = false, useSkills = false, useStdinAppend: _useStdinAppend = false, autoYes = true }) {
1518
+ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, exitOnIdle, logFile, removeControlCharactersFromStdout = false, verbose = false, queue = false, install = false, resume = false, useSkills = false, useStdinAppend = false, autoYes = true }) {
1367
1519
  if (!cli) throw new Error(`cli is required`);
1368
1520
  const conf = CLIS_CONFIG[cli] || DIE(`Unsupported cli tool: ${cli}, current process.argv: ${process.argv.join(" ")}`);
1369
1521
  const workingDir = cwd ?? process.cwd();
@@ -1484,6 +1636,12 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
1484
1636
  install,
1485
1637
  ptyOptions
1486
1638
  });
1639
+ function onData(data) {
1640
+ const currentPid = shell.pid;
1641
+ outputWriter.write(data);
1642
+ globalAgentRegistry.appendStdout(currentPid, data);
1643
+ }
1644
+ shell.onData(onData);
1487
1645
  try {
1488
1646
  await pidStore.registerProcess({
1489
1647
  pid: shell.pid,
@@ -1531,12 +1689,6 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
1531
1689
  if (!ctx.stdinFirstReady.isReady) ctx.stdinFirstReady.ready();
1532
1690
  });
1533
1691
  const pendingExitCode = Promise.withResolvers();
1534
- function onData(data) {
1535
- const currentPid = shell.pid;
1536
- outputWriter.write(data);
1537
- globalAgentRegistry.appendStdout(currentPid, data);
1538
- }
1539
- shell.onData(onData);
1540
1692
  shell.onExit(async function onExit({ exitCode }) {
1541
1693
  const exitedPid = shell.pid;
1542
1694
  globalAgentRegistry.unregister(exitedPid);
@@ -1842,7 +1994,14 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
1842
1994
  }
1843
1995
  return out;
1844
1996
  };
1845
- })()).onStart(async function promptOnStart() {
1997
+ })()).by(async (s) => {
1998
+ if (!useStdinAppend) return s;
1999
+ const ipcResult = await createFifoStream(cli, pidStore.getFifoPath(shell.pid));
2000
+ if (!ipcResult) return s;
2001
+ pendingExitCode.promise.finally(async () => await ipcResult[Symbol.asyncDispose]());
2002
+ process.stderr.write(`\n Append prompts: ${cli}-yes --append-prompt '...'\n\n`);
2003
+ return s.merge(ipcResult.stream);
2004
+ }).confluenceByConcat().onStart(async function promptOnStart() {
1846
2005
  logger.debug("Sending prompt message: " + JSON.stringify(prompt));
1847
2006
  if (prompt) await sendMessage(ctx.messageContext, prompt);
1848
2007
  }).by({
@@ -1953,4 +2112,4 @@ const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
1953
2112
 
1954
2113
  //#endregion
1955
2114
  export { AgentContext as a, PidStore as c, config as i, removeControlCharacters as l, CLIS_CONFIG as n, name as o, agentYes as r, version as s, SUPPORTED_CLIS as t };
1956
- //# sourceMappingURL=SUPPORTED_CLIS-CxaWfAAA.js.map
2115
+ //# sourceMappingURL=SUPPORTED_CLIS-DXou-_yV.js.map
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bun
2
- import { c as PidStore, o as name, s as version, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CxaWfAAA.js";
2
+ import { c as PidStore, o as name, s as version, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DXou-_yV.js";
3
3
  import { t as logger } from "./logger-CX77vJDA.js";
4
4
  import { argv } from "process";
5
5
  import { spawn } from "child_process";
@@ -85,8 +85,8 @@ function parseCliArgs(argv) {
85
85
  default: "yes"
86
86
  }).option("rust", {
87
87
  type: "boolean",
88
- description: "Use the Rust implementation instead of TypeScript",
89
- default: false
88
+ description: "Use the Rust implementation (enabled by default, use --no-rust for TypeScript)",
89
+ default: true
90
90
  }).option("swarm", {
91
91
  type: "string",
92
92
  description: `Enable swarm mode for multi-agent P2P networking (requires --rust).
@@ -271,10 +271,11 @@ function getBinDir() {
271
271
  */
272
272
  function findRustBinary(verbose = false) {
273
273
  const binaryName = getBinaryName();
274
+ const ext = process.platform === "win32" ? ".exe" : "";
274
275
  const searchPaths = [
276
+ path.resolve(import.meta.dirname ?? import.meta.dir, `../rs/target/release/agent-yes${ext}`),
277
+ path.resolve(import.meta.dirname ?? import.meta.dir, `../rs/target/debug/agent-yes${ext}`),
275
278
  path.join(getBinDir(), binaryName),
276
- path.resolve(import.meta.dirname ?? import.meta.dir, "../rs/target/release/agent-yes"),
277
- path.resolve(import.meta.dirname ?? import.meta.dir, "../rs/target/debug/agent-yes"),
278
279
  path.join(getBinDir(), binaryName)
279
280
  ];
280
281
  if (verbose) {
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as AgentContext, i as config, l as removeControlCharacters, n as CLIS_CONFIG, r as agentYes } from "./SUPPORTED_CLIS-CxaWfAAA.js";
1
+ import { a as AgentContext, i as config, l as removeControlCharacters, n as CLIS_CONFIG, r as agentYes } from "./SUPPORTED_CLIS-DXou-_yV.js";
2
2
  import "./logger-CX77vJDA.js";
3
3
 
4
4
  export { AgentContext, CLIS_CONFIG, config, agentYes as default, removeControlCharacters };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.62.2",
3
+ "version": "1.64.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/index.ts CHANGED
@@ -14,7 +14,6 @@ import pty, { ptyPackage } from "./pty.ts";
14
14
  import { removeControlCharacters } from "./removeControlCharacters.ts";
15
15
  import { acquireLock, releaseLock, shouldUseLock } from "./runningLock.ts";
16
16
  import { logger } from "./logger.ts";
17
- // oxlint-disable-next-line no-unused-vars -- kept for FIFO re-enable (see TODO at index.ts:833)
18
17
  import { createFifoStream } from "./beta/fifo.ts";
19
18
  import { PidStore } from "./pidStore.ts";
20
19
  import { SUPPORTED_CLIS } from "./SUPPORTED_CLIS.ts";
@@ -118,7 +117,7 @@ export default async function agentYes({
118
117
  install = false,
119
118
  resume = false,
120
119
  useSkills = false,
121
- useStdinAppend: _useStdinAppend = false,
120
+ useStdinAppend = false,
122
121
  autoYes = true,
123
122
  }: {
124
123
  cli: SUPPORTED_CLIS;
@@ -328,6 +327,15 @@ export default async function agentYes({
328
327
  ptyOptions,
329
328
  });
330
329
 
330
+ // Attach data handler IMMEDIATELY after spawn to avoid losing early PTY output.
331
+ // node-pty emits 'data' events eagerly — if no listener is attached, events are lost.
332
+ function onData(data: string) {
333
+ const currentPid = shell.pid;
334
+ outputWriter.write(data);
335
+ globalAgentRegistry.appendStdout(currentPid, data);
336
+ }
337
+ shell.onData(onData);
338
+
331
339
  // Register process in pidStore (non-blocking - failures should not prevent agent from running)
332
340
  try {
333
341
  await pidStore.registerProcess({ pid: shell.pid, cli, args: cliArgs, prompt, cwd: workingDir });
@@ -387,16 +395,6 @@ export default async function agentYes({
387
395
 
388
396
  const pendingExitCode = Promise.withResolvers<number | null>();
389
397
 
390
- function onData(data: string) {
391
- const currentPid = shell.pid; // Capture PID before any potential shell reassignment
392
- // Write eagerly — TerminalRenderStream never exerts backpressure,
393
- // so the PTY is always drained and the child process never blocks.
394
- outputWriter.write(data);
395
- // append to agent registry for MCP server
396
- globalAgentRegistry.appendStdout(currentPid, data);
397
- }
398
-
399
- shell.onData(onData);
400
398
  shell.onExit(async function onExit({ exitCode }) {
401
399
  const exitedPid = shell.pid; // Capture PID immediately before any shell reassignment
402
400
  // Unregister from agent registry
@@ -833,18 +831,17 @@ export default async function agentYes({
833
831
  })(),
834
832
  )
835
833
 
836
- // TODO(sno): Read from IPC stream if available (FIFO on Linux, Named Pipes on Windows)
837
- // .by(async (s) => {
838
- // if (!useStdinAppend) return s;
839
- // const fifoPath = pidStore.getFifoPath(shell.pid);
840
- // if (!fifoPath) return s; // Skip if no valid path
841
- // const ipcResult = await createFifoStream(cli, fifoPath);
842
- // if (!ipcResult) return s;
843
- // pendingExitCode.promise.finally(async() => await ipcResult[Symbol.asyncDispose]());
844
- // process.stderr.write(`\n Append prompts: ${cli}-yes --append-prompt '...'\n\n`);
845
- // return s.merge(ipcResult.stream);
846
- // })
847
- // .confluenceByConcat() // necessary when .by() above is async
834
+ // Read from IPC stream if available (FIFO on Linux, Named Pipes on Windows)
835
+ .by(async (s) => {
836
+ if (!useStdinAppend) return s;
837
+ const fifoPath = pidStore.getFifoPath(shell.pid);
838
+ const ipcResult = await createFifoStream(cli, fifoPath);
839
+ if (!ipcResult) return s;
840
+ pendingExitCode.promise.finally(async () => await ipcResult[Symbol.asyncDispose]());
841
+ process.stderr.write(`\n Append prompts: ${cli}-yes --append-prompt '...'\n\n`);
842
+ return s.merge(ipcResult.stream);
843
+ })
844
+ .confluenceByConcat() // necessary because .by() above is async
848
845
 
849
846
  // .map((e) => e.replaceAll('\x1a', '')) // remove ctrl+z from user's input, to prevent bug (but this seems bug)
850
847
  // .forEach(e => appendFile('.cache/io.log', "input |" + JSON.stringify(e) + '\n')) // for debugging
@@ -121,8 +121,8 @@ export function parseCliArgs(argv: string[]) {
121
121
  })
122
122
  .option("rust", {
123
123
  type: "boolean",
124
- description: "Use the Rust implementation instead of TypeScript",
125
- default: false,
124
+ description: "Use the Rust implementation (enabled by default, use --no-rust for TypeScript)",
125
+ default: true,
126
126
  })
127
127
  .option("swarm", {
128
128
  type: "string",
package/ts/rustBinary.ts CHANGED
@@ -61,13 +61,14 @@ export function getBinDir(): string {
61
61
  export function findRustBinary(verbose = false): string | undefined {
62
62
  const binaryName = getBinaryName();
63
63
 
64
+ const ext = process.platform === "win32" ? ".exe" : "";
64
65
  const searchPaths = [
65
- // 1. Check in npm package bin directory
66
- path.join(getBinDir(), binaryName),
66
+ // 1. Check relative to this script (in the repo during development)
67
+ path.resolve(import.meta.dirname ?? import.meta.dir, `../rs/target/release/agent-yes${ext}`),
68
+ path.resolve(import.meta.dirname ?? import.meta.dir, `../rs/target/debug/agent-yes${ext}`),
67
69
 
68
- // 2. Check relative to this script (in the repo during development)
69
- path.resolve(import.meta.dirname ?? import.meta.dir, "../rs/target/release/agent-yes"),
70
- path.resolve(import.meta.dirname ?? import.meta.dir, "../rs/target/debug/agent-yes"),
70
+ // 2. Check in npm package bin directory
71
+ path.join(getBinDir(), binaryName),
71
72
 
72
73
  // 3. Check in user's cache directory
73
74
  path.join(getBinDir(), binaryName),