agent-yes 1.67.0 → 1.68.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.
@@ -1059,7 +1059,7 @@ function tryCatch(catchFn, fn) {
1059
1059
  //#endregion
1060
1060
  //#region package.json
1061
1061
  var name = "agent-yes";
1062
- var version = "1.67.0";
1062
+ var version = "1.68.0";
1063
1063
 
1064
1064
  //#endregion
1065
1065
  //#region ts/pty-fix.ts
@@ -2139,4 +2139,4 @@ const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
2139
2139
 
2140
2140
  //#endregion
2141
2141
  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 };
2142
- //# sourceMappingURL=SUPPORTED_CLIS-CmSMCHW2.js.map
2142
+ //# sourceMappingURL=SUPPORTED_CLIS-Cl2oCgKo.js.map
package/dist/cli.js CHANGED
@@ -1,13 +1,15 @@
1
1
  #!/usr/bin/env bun
2
- import { c as PidStore, o as name, s as version, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CmSMCHW2.js";
2
+ import { c as PidStore, o as name, s as version, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-Cl2oCgKo.js";
3
3
  import { t as logger } from "./logger-CX77vJDA.js";
4
4
  import { argv } from "process";
5
5
  import { spawn } from "child_process";
6
6
  import ms from "ms";
7
7
  import yargs from "yargs";
8
8
  import { hideBin } from "yargs/helpers";
9
- import { chmod, copyFile } from "fs/promises";
9
+ import { execaCommand } from "execa";
10
+ import { chmod, copyFile, mkdir, readFile, writeFile } from "fs/promises";
10
11
  import path from "path";
12
+ import { homedir } from "os";
11
13
  import { existsSync, mkdirSync, unlinkSync } from "fs";
12
14
 
13
15
  //#region ts/parseCliArgs.ts
@@ -202,6 +204,62 @@ function parseCliArgs(argv) {
202
204
 
203
205
  //#endregion
204
206
  //#region ts/versionChecker.ts
207
+ const CACHE_DIR = path.join(homedir(), ".cache", "agent-yes");
208
+ const CACHE_FILE = path.join(CACHE_DIR, "update-check.json");
209
+ const TTL_MS = 3600 * 1e3;
210
+ async function readUpdateCache() {
211
+ try {
212
+ const raw = await readFile(CACHE_FILE, "utf8");
213
+ return JSON.parse(raw);
214
+ } catch {
215
+ return null;
216
+ }
217
+ }
218
+ async function writeUpdateCache(data) {
219
+ await mkdir(CACHE_DIR, { recursive: true });
220
+ await writeFile(CACHE_FILE, JSON.stringify(data));
221
+ }
222
+ function detectPackageManager() {
223
+ if (process.env.BUN_INSTALL || process.env.npm_execpath?.includes("bun")) return "bun";
224
+ return "npm";
225
+ }
226
+ /**
227
+ * Check for updates and auto-install if a newer version is available.
228
+ * Uses a 1-hour TTL cache to avoid hitting the registry on every run.
229
+ * All errors are swallowed — network issues must never break the tool.
230
+ * Set AGENT_YES_NO_UPDATE=1 to opt out.
231
+ */
232
+ async function checkAndAutoUpdate() {
233
+ if (process.env.AGENT_YES_NO_UPDATE) return;
234
+ try {
235
+ const cache = await readUpdateCache();
236
+ if (cache && Date.now() - cache.checkedAt < TTL_MS) {
237
+ if (compareVersions(version, cache.latestVersion) < 0) await runInstall(cache.latestVersion);
238
+ return;
239
+ }
240
+ const latestVersion = await fetchLatestVersion();
241
+ if (!latestVersion) return;
242
+ await writeUpdateCache({
243
+ checkedAt: Date.now(),
244
+ latestVersion
245
+ });
246
+ if (compareVersions(version, latestVersion) < 0) await runInstall(latestVersion);
247
+ } catch {}
248
+ }
249
+ async function runInstall(latestVersion) {
250
+ const installArgs = detectPackageManager() === "bun" ? `bun add -g agent-yes@${latestVersion}` : `npm install -g agent-yes@${latestVersion}`;
251
+ process.stderr.write(`\x1b[33m[agent-yes] Updating ${version} → ${latestVersion}…\x1b[0m\n`);
252
+ try {
253
+ await execaCommand(installArgs, { stdio: "inherit" });
254
+ await writeUpdateCache({
255
+ checkedAt: 0,
256
+ latestVersion
257
+ });
258
+ process.stderr.write(`\x1b[32m[agent-yes] Updated to ${latestVersion}\x1b[0m\n`);
259
+ } catch {
260
+ process.stderr.write(`\x1b[31m[agent-yes] Auto-update failed. Run: ${installArgs}\x1b[0m\n`);
261
+ }
262
+ }
205
263
  /**
206
264
  * Fetch the latest version of the package from npm registry
207
265
  */
@@ -415,6 +473,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
415
473
 
416
474
  //#endregion
417
475
  //#region ts/cli.ts
476
+ const updateCheckPromise = checkAndAutoUpdate();
418
477
  const config = parseCliArgs(process.argv);
419
478
  if (config.useRust) {
420
479
  let rustBinary;
@@ -504,6 +563,7 @@ const { exitCode } = await cliYes({
504
563
  ...config,
505
564
  autoYes: config.autoYes
506
565
  });
566
+ await updateCheckPromise;
507
567
  console.log("exiting process");
508
568
  process.exit(exitCode ?? 1);
509
569
 
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-CmSMCHW2.js";
1
+ import { a as AgentContext, i as config, l as removeControlCharacters, n as CLIS_CONFIG, r as agentYes } from "./SUPPORTED_CLIS-Cl2oCgKo.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.67.0",
3
+ "version": "1.68.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
@@ -5,10 +5,13 @@ import { parseCliArgs } from "./parseCliArgs.ts";
5
5
  import { SUPPORTED_CLIS } from "./SUPPORTED_CLIS.ts";
6
6
  import { logger } from "./logger.ts";
7
7
  import { PidStore } from "./pidStore.ts";
8
- import { displayVersion } from "./versionChecker.ts";
8
+ 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();
14
+
12
15
  // Parse CLI arguments
13
16
  const config = parseCliArgs(process.argv);
14
17
 
@@ -134,5 +137,9 @@ if (config.verbose) {
134
137
 
135
138
  const { default: cliYes } = await import("./index.ts");
136
139
  const { exitCode } = await cliYes({ ...config, autoYes: config.autoYes });
140
+
141
+ // Apply update if one was found during the session
142
+ await updateCheckPromise;
143
+
137
144
  console.log("exiting process");
138
145
  process.exit(exitCode ?? 1);
@@ -1,5 +1,17 @@
1
1
  import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
2
- import { compareVersions, fetchLatestVersion, displayVersion } from "./versionChecker";
2
+ import {
3
+ checkAndAutoUpdate,
4
+ compareVersions,
5
+ fetchLatestVersion,
6
+ displayVersion,
7
+ } from "./versionChecker";
8
+
9
+ vi.mock("execa", () => ({ execaCommand: vi.fn().mockResolvedValue({}) }));
10
+ vi.mock("fs/promises", () => ({
11
+ mkdir: vi.fn().mockResolvedValue(undefined),
12
+ readFile: vi.fn(),
13
+ writeFile: vi.fn().mockResolvedValue(undefined),
14
+ }));
3
15
 
4
16
  describe("versionChecker", () => {
5
17
  describe("compareVersions", () => {
@@ -64,6 +76,107 @@ describe("versionChecker", () => {
64
76
  });
65
77
  });
66
78
 
79
+ describe("checkAndAutoUpdate", () => {
80
+ beforeEach(() => {
81
+ vi.clearAllMocks();
82
+ vi.stubGlobal("fetch", vi.fn());
83
+ vi.spyOn(process.stderr, "write").mockImplementation(() => true);
84
+ delete process.env.AGENT_YES_NO_UPDATE;
85
+ delete process.env.BUN_INSTALL;
86
+ });
87
+
88
+ afterEach(() => {
89
+ vi.restoreAllMocks();
90
+ });
91
+
92
+ it("should skip when AGENT_YES_NO_UPDATE is set", async () => {
93
+ process.env.AGENT_YES_NO_UPDATE = "1";
94
+ await checkAndAutoUpdate();
95
+ expect(fetch).not.toHaveBeenCalled();
96
+ });
97
+
98
+ it("should use cached result within TTL and not install when up-to-date", async () => {
99
+ const { readFile } = await import("fs/promises");
100
+ vi.mocked(readFile).mockResolvedValueOnce(
101
+ JSON.stringify({ checkedAt: Date.now(), latestVersion: "0.0.1" }) as any,
102
+ );
103
+ await checkAndAutoUpdate();
104
+ expect(fetch).not.toHaveBeenCalled();
105
+ expect(process.stderr.write).not.toHaveBeenCalled();
106
+ });
107
+
108
+ it("should install from cache when cached version is newer and within TTL", async () => {
109
+ const { readFile } = await import("fs/promises");
110
+ const { execaCommand } = await import("execa");
111
+ vi.mocked(readFile).mockResolvedValueOnce(
112
+ JSON.stringify({ checkedAt: Date.now(), latestVersion: "999.0.0" }) as any,
113
+ );
114
+ await checkAndAutoUpdate();
115
+ expect(execaCommand).toHaveBeenCalled();
116
+ });
117
+
118
+ it("should fetch and write cache when stale, install if behind", async () => {
119
+ const { readFile, writeFile } = await import("fs/promises");
120
+ const { execaCommand } = await import("execa");
121
+ vi.mocked(readFile).mockRejectedValueOnce(new Error("no cache"));
122
+ vi.mocked(fetch).mockResolvedValue({
123
+ ok: true,
124
+ json: async () => ({ version: "999.0.0" }),
125
+ } as Response);
126
+ await checkAndAutoUpdate();
127
+ expect(writeFile).toHaveBeenCalled();
128
+ expect(execaCommand).toHaveBeenCalled();
129
+ });
130
+
131
+ it("should fetch and write cache but not install if up-to-date", async () => {
132
+ const { readFile, writeFile } = await import("fs/promises");
133
+ const { execaCommand } = await import("execa");
134
+ vi.mocked(readFile).mockRejectedValueOnce(new Error("no cache"));
135
+ vi.mocked(fetch).mockResolvedValue({
136
+ ok: true,
137
+ json: async () => ({ version: "0.0.1" }),
138
+ } as Response);
139
+ await checkAndAutoUpdate();
140
+ expect(writeFile).toHaveBeenCalled();
141
+ expect(execaCommand).not.toHaveBeenCalled();
142
+ });
143
+
144
+ it("should silently handle fetch failure", async () => {
145
+ const { readFile } = await import("fs/promises");
146
+ vi.mocked(readFile).mockRejectedValueOnce(new Error("no cache"));
147
+ vi.mocked(fetch).mockRejectedValue(new Error("network error"));
148
+ await expect(checkAndAutoUpdate()).resolves.toBeUndefined();
149
+ });
150
+
151
+ it("should use bun when BUN_INSTALL is set", async () => {
152
+ process.env.BUN_INSTALL = "/home/user/.bun";
153
+ const { readFile } = await import("fs/promises");
154
+ const { execaCommand } = await import("execa");
155
+ vi.mocked(readFile).mockRejectedValueOnce(new Error("no cache"));
156
+ vi.mocked(fetch).mockResolvedValue({
157
+ ok: true,
158
+ json: async () => ({ version: "999.0.0" }),
159
+ } as Response);
160
+ await checkAndAutoUpdate();
161
+ expect(vi.mocked(execaCommand).mock.calls[0]?.[0]).toContain("bun");
162
+ });
163
+
164
+ it("should print error and not throw when install fails", async () => {
165
+ const { readFile } = await import("fs/promises");
166
+ const { execaCommand } = await import("execa");
167
+ vi.mocked(readFile).mockRejectedValueOnce(new Error("no cache"));
168
+ vi.mocked(fetch).mockResolvedValue({
169
+ ok: true,
170
+ json: async () => ({ version: "999.0.0" }),
171
+ } as Response);
172
+ vi.mocked(execaCommand).mockRejectedValueOnce(new Error("install failed"));
173
+ await expect(checkAndAutoUpdate()).resolves.toBeUndefined();
174
+ expect(process.stderr.write).toHaveBeenCalledWith(
175
+ expect.stringContaining("Auto-update failed"),
176
+ );
177
+ });
178
+ });
179
+
67
180
  describe("displayVersion", () => {
68
181
  beforeEach(() => {
69
182
  vi.stubGlobal("fetch", vi.fn());
@@ -1,5 +1,86 @@
1
+ import { execaCommand } from "execa";
2
+ import { mkdir, readFile, writeFile } from "fs/promises";
3
+ import { homedir } from "os";
4
+ import path from "path";
1
5
  import pkg from "../package.json" with { type: "json" };
2
6
 
7
+ const CACHE_DIR = path.join(homedir(), ".cache", "agent-yes");
8
+ const CACHE_FILE = path.join(CACHE_DIR, "update-check.json");
9
+ const TTL_MS = 60 * 60 * 1000; // 1 hour
10
+
11
+ type UpdateCache = { checkedAt: number; latestVersion: string };
12
+
13
+ async function readUpdateCache(): Promise<UpdateCache | null> {
14
+ try {
15
+ const raw = await readFile(CACHE_FILE, "utf8");
16
+ return JSON.parse(raw) as UpdateCache;
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+
22
+ async function writeUpdateCache(data: UpdateCache): Promise<void> {
23
+ await mkdir(CACHE_DIR, { recursive: true });
24
+ await writeFile(CACHE_FILE, JSON.stringify(data));
25
+ }
26
+
27
+ function detectPackageManager(): string {
28
+ if (process.env.BUN_INSTALL || process.env.npm_execpath?.includes("bun")) return "bun";
29
+ return "npm";
30
+ }
31
+
32
+ /**
33
+ * Check for updates and auto-install if a newer version is available.
34
+ * Uses a 1-hour TTL cache to avoid hitting the registry on every run.
35
+ * All errors are swallowed — network issues must never break the tool.
36
+ * Set AGENT_YES_NO_UPDATE=1 to opt out.
37
+ */
38
+ export async function checkAndAutoUpdate(): Promise<void> {
39
+ if (process.env.AGENT_YES_NO_UPDATE) return;
40
+
41
+ try {
42
+ // Check cache TTL
43
+ const cache = await readUpdateCache();
44
+ 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;
50
+ }
51
+
52
+ // Fetch latest from registry
53
+ const latestVersion = await fetchLatestVersion();
54
+ if (!latestVersion) return;
55
+
56
+ await writeUpdateCache({ checkedAt: Date.now(), latestVersion });
57
+
58
+ if (compareVersions(pkg.version, latestVersion) < 0) {
59
+ await runInstall(latestVersion);
60
+ }
61
+ } catch {
62
+ // Silently ignore all errors
63
+ }
64
+ }
65
+
66
+ async function runInstall(latestVersion: string): Promise<void> {
67
+ const pm = detectPackageManager();
68
+ const installArgs =
69
+ pm === "bun"
70
+ ? `bun add -g agent-yes@${latestVersion}`
71
+ : `npm install -g agent-yes@${latestVersion}`;
72
+
73
+ process.stderr.write(`\x1b[33m[agent-yes] Updating ${pkg.version} → ${latestVersion}…\x1b[0m\n`);
74
+ try {
75
+ await execaCommand(installArgs, { stdio: "inherit" });
76
+ // Clear cache so next run re-checks
77
+ await writeUpdateCache({ checkedAt: 0, latestVersion });
78
+ process.stderr.write(`\x1b[32m[agent-yes] Updated to ${latestVersion}\x1b[0m\n`);
79
+ } catch {
80
+ process.stderr.write(`\x1b[31m[agent-yes] Auto-update failed. Run: ${installArgs}\x1b[0m\n`);
81
+ }
82
+ }
83
+
3
84
  /**
4
85
  * Fetch the latest version of the package from npm registry
5
86
  */