claude-yes 1.72.2 → 1.72.4

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.
@@ -815,7 +815,7 @@ function tryCatch(catchFn, fn) {
815
815
  //#endregion
816
816
  //#region package.json
817
817
  var name = "agent-yes";
818
- var version = "1.72.2";
818
+ var version = "1.72.4";
819
819
 
820
820
  //#endregion
821
821
  //#region ts/pty-fix.ts
@@ -1895,4 +1895,4 @@ const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
1895
1895
 
1896
1896
  //#endregion
1897
1897
  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 };
1898
- //# sourceMappingURL=SUPPORTED_CLIS-D9eEHdvo.js.map
1898
+ //# sourceMappingURL=SUPPORTED_CLIS-Bqw9gxey.js.map
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env bun
2
- import { c as PidStore, o as name, s as version, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-D9eEHdvo.js";
2
+ import { c as PidStore, o as name, s as version, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-Bqw9gxey.js";
3
3
  import { t as logger } from "./logger-CX77vJDA.js";
4
4
  import { argv } from "process";
5
- import { spawn } from "child_process";
5
+ import { execFileSync, spawn } from "child_process";
6
6
  import ms from "ms";
7
7
  import yargs from "yargs";
8
8
  import { hideBin } from "yargs/helpers";
@@ -225,44 +225,72 @@ async function writeUpdateCache(data) {
225
225
  await writeFile(CACHE_FILE, JSON.stringify(data));
226
226
  }
227
227
  function detectPackageManager() {
228
- if (process.env.BUN_INSTALL || process.env.npm_execpath?.includes("bun")) return "bun";
228
+ if (process.env.BUN_INSTALL || process.execPath?.includes("bun") || process.env.npm_execpath?.includes("bun")) return "bun";
229
229
  return "npm";
230
230
  }
231
231
  /**
232
- * Check for updates and auto-install if a newer version is available.
232
+ * Check for updates, auto-install if newer version is available, and re-exec
233
+ * so the current invocation always runs the latest code.
234
+ *
233
235
  * Uses a 1-hour TTL cache to avoid hitting the registry on every run.
234
236
  * All errors are swallowed — network issues must never break the tool.
235
237
  * Set AGENT_YES_NO_UPDATE=1 to opt out.
238
+ *
239
+ * The AGENT_YES_UPDATED env var prevents infinite re-exec loops:
240
+ * after updating we re-exec with AGENT_YES_UPDATED=<version> so the
241
+ * new process skips the update check.
236
242
  */
237
243
  async function checkAndAutoUpdate() {
238
244
  if (process.env.AGENT_YES_NO_UPDATE) return;
245
+ if (process.env.AGENT_YES_UPDATED === version) return;
239
246
  try {
247
+ let latestVersion;
240
248
  const cache = await readUpdateCache();
241
- if (cache && Date.now() - cache.checkedAt < TTL_MS) {
242
- if (compareVersions(version, cache.latestVersion) < 0) await runInstall(cache.latestVersion);
243
- return;
249
+ if (cache && Date.now() - cache.checkedAt < TTL_MS) latestVersion = cache.latestVersion;
250
+ else {
251
+ const fetched = await fetchLatestVersion();
252
+ if (!fetched) return;
253
+ latestVersion = fetched;
254
+ await writeUpdateCache({
255
+ checkedAt: Date.now(),
256
+ latestVersion
257
+ });
258
+ }
259
+ if (compareVersions(version, latestVersion) < 0) {
260
+ if (await runInstall(latestVersion)) reExec(latestVersion);
244
261
  }
245
- const latestVersion = await fetchLatestVersion();
246
- if (!latestVersion) return;
247
- await writeUpdateCache({
248
- checkedAt: Date.now(),
249
- latestVersion
250
- });
251
- if (compareVersions(version, latestVersion) < 0) await runInstall(latestVersion);
252
262
  } catch {}
253
263
  }
254
264
  async function runInstall(latestVersion) {
255
- const installArgs = detectPackageManager() === "bun" ? `bun add -g agent-yes@${latestVersion}` : `npm install -g agent-yes@${latestVersion}`;
265
+ const installCmd = detectPackageManager() === "bun" ? `bun add -g agent-yes@${latestVersion}` : `npm install -g agent-yes@${latestVersion}`;
256
266
  process.stderr.write(`\x1b[33m[agent-yes] Updating ${version} → ${latestVersion}…\x1b[0m\n`);
257
267
  try {
258
- await execaCommand(installArgs, { stdio: "inherit" });
259
- await writeUpdateCache({
260
- checkedAt: 0,
261
- latestVersion
262
- });
268
+ await execaCommand(installCmd, { stdio: "inherit" });
263
269
  process.stderr.write(`\x1b[32m[agent-yes] Updated to ${latestVersion}\x1b[0m\n`);
270
+ return true;
264
271
  } catch {
265
- process.stderr.write(`\x1b[31m[agent-yes] Auto-update failed. Run: ${installArgs}\x1b[0m\n`);
272
+ process.stderr.write(`\x1b[31m[agent-yes] Auto-update failed. Run: ${installCmd}\x1b[0m\n`);
273
+ return false;
274
+ }
275
+ }
276
+ /**
277
+ * Re-exec the current process so the newly installed version runs.
278
+ * Sets AGENT_YES_UPDATED=<version> to prevent an infinite loop.
279
+ */
280
+ function reExec(version) {
281
+ const [bin, ...args] = process.argv;
282
+ process.stderr.write(`\x1b[36m[agent-yes] Restarting with v${version}…\x1b[0m\n`);
283
+ try {
284
+ execFileSync(bin, args, {
285
+ stdio: "inherit",
286
+ env: {
287
+ ...process.env,
288
+ AGENT_YES_UPDATED: version
289
+ }
290
+ });
291
+ process.exit(0);
292
+ } catch (err) {
293
+ process.exit(err.status ?? 1);
266
294
  }
267
295
  }
268
296
  /**
@@ -478,7 +506,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
478
506
 
479
507
  //#endregion
480
508
  //#region ts/cli.ts
481
- const updateCheckPromise = checkAndAutoUpdate();
509
+ await checkAndAutoUpdate();
482
510
  const config = parseCliArgs(process.argv);
483
511
  if (config.tray) {
484
512
  const { startTray } = await import("./tray-CPpdxTV-.js");
@@ -581,7 +609,6 @@ const { exitCode } = await cliYes({
581
609
  ...config,
582
610
  autoYes: config.autoYes
583
611
  });
584
- await updateCheckPromise;
585
612
  console.log("exiting process");
586
613
  process.exit(exitCode ?? 1);
587
614
 
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-D9eEHdvo.js";
1
+ import { a as AgentContext, i as config, l as removeControlCharacters, n as CLIS_CONFIG, r as agentYes } from "./SUPPORTED_CLIS-Bqw9gxey.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": "claude-yes",
3
- "version": "1.72.2",
3
+ "version": "1.72.4",
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",
@@ -2,21 +2,30 @@ import { describe, expect, it, beforeEach, afterEach } from "vitest";
2
2
  import { JsonlStore } from "./JsonlStore";
3
3
  import { rm, readFile, writeFile, mkdir } from "fs/promises";
4
4
  import path from "path";
5
+ import os from "os";
5
6
 
6
- const TEST_DIR = "/tmp/jsonlstore-test-" + process.pid;
7
+ const TEST_DIR = path.join(os.tmpdir(), "jsonlstore-test-" + process.pid);
7
8
  const TEST_FILE = path.join(TEST_DIR, "test.jsonl");
8
9
 
9
10
  describe("JsonlStore", () => {
10
11
  let store: JsonlStore;
11
12
 
12
13
  beforeEach(async () => {
13
- await rm(TEST_DIR, { recursive: true, force: true });
14
+ try {
15
+ await rm(TEST_DIR, { recursive: true, force: true });
16
+ } catch {
17
+ // ignore cleanup failures (e.g. Windows lock files from previous test)
18
+ }
14
19
  await mkdir(TEST_DIR, { recursive: true });
15
20
  store = new JsonlStore(TEST_FILE);
16
21
  });
17
22
 
18
23
  afterEach(async () => {
19
- await rm(TEST_DIR, { recursive: true, force: true });
24
+ try {
25
+ await rm(TEST_DIR, { recursive: true, force: true });
26
+ } catch {
27
+ // ignore cleanup failures
28
+ }
20
29
  });
21
30
 
22
31
  describe("load", () => {
package/ts/cli.ts CHANGED
@@ -9,8 +9,9 @@ import { checkAndAutoUpdate, displayVersion } from "./versionChecker.ts";
9
9
  import { getRustBinary } from "./rustBinary.ts";
10
10
  import { buildRustArgs } from "./buildRustArgs.ts";
11
11
 
12
- // Start update check in background immediately (runs in parallel with the agent session)
13
- const updateCheckPromise = checkAndAutoUpdate();
12
+ // Check for updates before starting installs & re-execs if a newer version exists.
13
+ // Fast path: cached result (no network), so this adds near-zero latency most of the time.
14
+ await checkAndAutoUpdate();
14
15
 
15
16
  // Parse CLI arguments
16
17
  const config = parseCliArgs(process.argv);
@@ -152,8 +153,5 @@ if (config.verbose) {
152
153
  const { default: cliYes } = await import("./index.ts");
153
154
  const { exitCode } = await cliYes({ ...config, autoYes: config.autoYes });
154
155
 
155
- // Apply update if one was found during the session
156
- await updateCheckPromise;
157
-
158
156
  console.log("exiting process");
159
157
  process.exit(exitCode ?? 1);
@@ -12,14 +12,22 @@ describe("PidStore", () => {
12
12
  let store: PidStore;
13
13
 
14
14
  beforeEach(async () => {
15
- await rm(TEST_DIR, { recursive: true, force: true });
15
+ try {
16
+ await rm(TEST_DIR, { recursive: true, force: true });
17
+ } catch {
18
+ // ignore cleanup failures (e.g. Windows lock files from previous test)
19
+ }
16
20
  store = new PidStore(TEST_DIR);
17
21
  await store.init();
18
22
  });
19
23
 
20
24
  afterEach(async () => {
21
25
  await store.close();
22
- await rm(TEST_DIR, { recursive: true, force: true });
26
+ try {
27
+ await rm(TEST_DIR, { recursive: true, force: true });
28
+ } catch {
29
+ // ignore cleanup failures
30
+ }
23
31
  });
24
32
 
25
33
  describe("registerProcess", () => {
@@ -170,7 +178,11 @@ describe("PidStore", () => {
170
178
 
171
179
  it("should return fifo of most recent non-exited process", async () => {
172
180
  const fifoTestDir = TEST_DIR + "-fifo";
173
- await rm(fifoTestDir, { recursive: true, force: true });
181
+ try {
182
+ await rm(fifoTestDir, { recursive: true, force: true });
183
+ } catch {
184
+ // ignore cleanup failures (e.g. Windows lock files)
185
+ }
174
186
 
175
187
  const fifoStore = new PidStore(fifoTestDir);
176
188
  await fifoStore.init();
@@ -185,7 +197,11 @@ describe("PidStore", () => {
185
197
  expect(fifo!).toContain(`${process.pid}.stdin`);
186
198
  }
187
199
 
188
- await rm(fifoTestDir, { recursive: true, force: true });
200
+ try {
201
+ await rm(fifoTestDir, { recursive: true, force: true });
202
+ } catch {
203
+ // ignore cleanup failures
204
+ }
189
205
  });
190
206
  });
191
207
 
@@ -12,6 +12,14 @@ vi.mock("fs/promises", () => ({
12
12
  readFile: vi.fn(),
13
13
  writeFile: vi.fn().mockResolvedValue(undefined),
14
14
  }));
15
+ vi.mock("child_process", () => ({
16
+ execFileSync: vi.fn(() => {
17
+ // Simulate successful re-exec by throwing an exit-like error
18
+ const err = new Error("re-exec") as any;
19
+ err.status = 0;
20
+ throw err;
21
+ }),
22
+ }));
15
23
 
16
24
  describe("versionChecker", () => {
17
25
  describe("compareVersions", () => {
@@ -81,7 +89,10 @@ describe("versionChecker", () => {
81
89
  vi.clearAllMocks();
82
90
  vi.stubGlobal("fetch", vi.fn());
83
91
  vi.spyOn(process.stderr, "write").mockImplementation(() => true);
92
+ // Use a mock for process.exit to prevent actual exit in tests
93
+ vi.spyOn(process, "exit").mockImplementation(() => undefined as never);
84
94
  delete process.env.AGENT_YES_NO_UPDATE;
95
+ delete process.env.AGENT_YES_UPDATED;
85
96
  delete process.env.BUN_INSTALL;
86
97
  });
87
98
 
@@ -95,6 +106,13 @@ describe("versionChecker", () => {
95
106
  expect(fetch).not.toHaveBeenCalled();
96
107
  });
97
108
 
109
+ it("should skip when AGENT_YES_UPDATED matches current version", async () => {
110
+ const pkg = await import("../package.json");
111
+ process.env.AGENT_YES_UPDATED = pkg.default.version;
112
+ await checkAndAutoUpdate();
113
+ expect(fetch).not.toHaveBeenCalled();
114
+ });
115
+
98
116
  it("should use cached result within TTL and not install when up-to-date", async () => {
99
117
  const { readFile } = await import("fs/promises");
100
118
  vi.mocked(readFile).mockResolvedValueOnce(
@@ -105,19 +123,23 @@ describe("versionChecker", () => {
105
123
  expect(process.stderr.write).not.toHaveBeenCalled();
106
124
  });
107
125
 
108
- it("should install from cache when cached version is newer and within TTL", async () => {
126
+ it("should install and re-exec from cache when cached version is newer and within TTL", async () => {
109
127
  const { readFile } = await import("fs/promises");
110
128
  const { execaCommand } = await import("execa");
129
+ const { execFileSync } = await import("child_process");
111
130
  vi.mocked(readFile).mockResolvedValueOnce(
112
131
  JSON.stringify({ checkedAt: Date.now(), latestVersion: "999.0.0" }) as any,
113
132
  );
114
133
  await checkAndAutoUpdate();
115
134
  expect(execaCommand).toHaveBeenCalled();
135
+ expect(execFileSync).toHaveBeenCalled();
136
+ expect(process.exit).toHaveBeenCalled();
116
137
  });
117
138
 
118
- it("should fetch and write cache when stale, install if behind", async () => {
139
+ it("should fetch and write cache when stale, install and re-exec if behind", async () => {
119
140
  const { readFile, writeFile } = await import("fs/promises");
120
141
  const { execaCommand } = await import("execa");
142
+ const { execFileSync } = await import("child_process");
121
143
  vi.mocked(readFile).mockRejectedValueOnce(new Error("no cache"));
122
144
  vi.mocked(fetch).mockResolvedValue({
123
145
  ok: true,
@@ -126,6 +148,7 @@ describe("versionChecker", () => {
126
148
  await checkAndAutoUpdate();
127
149
  expect(writeFile).toHaveBeenCalled();
128
150
  expect(execaCommand).toHaveBeenCalled();
151
+ expect(execFileSync).toHaveBeenCalled();
129
152
  });
130
153
 
131
154
  it("should fetch and write cache but not install if up-to-date", async () => {
@@ -1,3 +1,4 @@
1
+ import { execFileSync } from "child_process";
1
2
  import { execaCommand } from "execa";
2
3
  import { mkdir, readFile, writeFile } from "fs/promises";
3
4
  import { homedir } from "os";
@@ -25,59 +26,92 @@ async function writeUpdateCache(data: UpdateCache): Promise<void> {
25
26
  }
26
27
 
27
28
  function detectPackageManager(): string {
28
- if (process.env.BUN_INSTALL || process.env.npm_execpath?.includes("bun")) return "bun";
29
+ if (
30
+ process.env.BUN_INSTALL ||
31
+ process.execPath?.includes("bun") ||
32
+ process.env.npm_execpath?.includes("bun")
33
+ )
34
+ return "bun";
29
35
  return "npm";
30
36
  }
31
37
 
32
38
  /**
33
- * Check for updates and auto-install if a newer version is available.
39
+ * Check for updates, auto-install if newer version is available, and re-exec
40
+ * so the current invocation always runs the latest code.
41
+ *
34
42
  * Uses a 1-hour TTL cache to avoid hitting the registry on every run.
35
43
  * All errors are swallowed — network issues must never break the tool.
36
44
  * Set AGENT_YES_NO_UPDATE=1 to opt out.
45
+ *
46
+ * The AGENT_YES_UPDATED env var prevents infinite re-exec loops:
47
+ * after updating we re-exec with AGENT_YES_UPDATED=<version> so the
48
+ * new process skips the update check.
37
49
  */
38
50
  export async function checkAndAutoUpdate(): Promise<void> {
39
51
  if (process.env.AGENT_YES_NO_UPDATE) return;
40
52
 
53
+ // Prevent infinite re-exec: if we just updated to this version, skip
54
+ if (process.env.AGENT_YES_UPDATED === pkg.version) return;
55
+
41
56
  try {
57
+ let latestVersion: string | undefined;
58
+
42
59
  // Check cache TTL
43
60
  const cache = await readUpdateCache();
44
61
  if (cache && Date.now() - cache.checkedAt < TTL_MS) {
45
- // Use cached result
46
- if (compareVersions(pkg.version, cache.latestVersion) < 0) {
47
- await runInstall(cache.latestVersion);
48
- }
49
- return;
62
+ latestVersion = cache.latestVersion;
63
+ } else {
64
+ // Fetch latest from registry
65
+ const fetched = await fetchLatestVersion();
66
+ if (!fetched) return;
67
+ latestVersion = fetched;
68
+ await writeUpdateCache({ checkedAt: Date.now(), latestVersion });
50
69
  }
51
70
 
52
- // Fetch latest from registry
53
- const latestVersion = await fetchLatestVersion();
54
- if (!latestVersion) return;
55
-
56
- await writeUpdateCache({ checkedAt: Date.now(), latestVersion });
57
-
58
71
  if (compareVersions(pkg.version, latestVersion) < 0) {
59
- await runInstall(latestVersion);
72
+ const installed = await runInstall(latestVersion);
73
+ if (installed) {
74
+ reExec(latestVersion);
75
+ }
60
76
  }
61
77
  } catch {
62
78
  // Silently ignore all errors
63
79
  }
64
80
  }
65
81
 
66
- async function runInstall(latestVersion: string): Promise<void> {
82
+ async function runInstall(latestVersion: string): Promise<boolean> {
67
83
  const pm = detectPackageManager();
68
- const installArgs =
84
+ const installCmd =
69
85
  pm === "bun"
70
86
  ? `bun add -g agent-yes@${latestVersion}`
71
87
  : `npm install -g agent-yes@${latestVersion}`;
72
88
 
73
89
  process.stderr.write(`\x1b[33m[agent-yes] Updating ${pkg.version} → ${latestVersion}…\x1b[0m\n`);
74
90
  try {
75
- await execaCommand(installArgs, { stdio: "inherit" });
76
- // Clear cache so next run re-checks
77
- await writeUpdateCache({ checkedAt: 0, latestVersion });
91
+ await execaCommand(installCmd, { stdio: "inherit" });
78
92
  process.stderr.write(`\x1b[32m[agent-yes] Updated to ${latestVersion}\x1b[0m\n`);
93
+ return true;
79
94
  } catch {
80
- process.stderr.write(`\x1b[31m[agent-yes] Auto-update failed. Run: ${installArgs}\x1b[0m\n`);
95
+ process.stderr.write(`\x1b[31m[agent-yes] Auto-update failed. Run: ${installCmd}\x1b[0m\n`);
96
+ return false;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Re-exec the current process so the newly installed version runs.
102
+ * Sets AGENT_YES_UPDATED=<version> to prevent an infinite loop.
103
+ */
104
+ function reExec(version: string): never {
105
+ const [bin, ...args] = process.argv;
106
+ process.stderr.write(`\x1b[36m[agent-yes] Restarting with v${version}…\x1b[0m\n`);
107
+ try {
108
+ execFileSync(bin, args, {
109
+ stdio: "inherit",
110
+ env: { ...process.env, AGENT_YES_UPDATED: version },
111
+ });
112
+ process.exit(0);
113
+ } catch (err: any) {
114
+ process.exit(err.status ?? 1);
81
115
  }
82
116
  }
83
117