agent-yes 1.72.4 → 1.73.2

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
@@ -1,23 +1,22 @@
1
1
  #!/usr/bin/env bun
2
- import { c as PidStore, o as name, s as version, t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-Bqw9gxey.js";
3
- import { t as logger } from "./logger-CX77vJDA.js";
2
+ import { n as logger } from "./logger-B9h0djqx.js";
3
+ import { n as version, t as name } from "./package-DpfHTSW2.js";
4
4
  import { argv } from "process";
5
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";
9
- import { execaCommand } from "execa";
9
+ import { existsSync, lstatSync, mkdirSync, readlinkSync, unlinkSync } from "fs";
10
10
  import { chmod, copyFile, mkdir, readFile, writeFile } from "fs/promises";
11
- import path from "path";
12
11
  import { homedir } from "os";
13
- import { existsSync, mkdirSync, unlinkSync } from "fs";
12
+ import path from "path";
14
13
 
15
14
  //#region ts/parseCliArgs.ts
16
15
  /**
17
16
  * Parse CLI arguments the same way cli.ts does
18
17
  * This is a test helper that mirrors the parsing logic in cli.ts
19
18
  */
20
- function parseCliArgs(argv) {
19
+ function parseCliArgs(argv, supportedClis) {
21
20
  const scriptBaseName = argv[1]?.split(/[/\\]/).at(-1)?.replace(/(\.[jt]s)?$/, "") || "";
22
21
  const CLI_ALIASES = { cy: "claude" };
23
22
  const cliName = (() => {
@@ -129,7 +128,7 @@ function parseCliArgs(argv) {
129
128
  }).positional("cli", {
130
129
  describe: "The AI CLI to run, e.g., claude, codex, copilot, cursor, gemini",
131
130
  type: "string",
132
- choices: SUPPORTED_CLIS,
131
+ choices: supportedClis,
133
132
  demandOption: false,
134
133
  default: cliName
135
134
  }).help().version(false).option("version", {
@@ -156,26 +155,53 @@ function parseCliArgs(argv) {
156
155
  if (key === "continue") yargsConsumed.add("-c");
157
156
  }
158
157
  });
158
+ const positionalPromptWords = [];
159
159
  const cliArgsForSpawn = (() => {
160
- if (parsedArgv._[0] && !cliName) return rawArgs.slice((cliArgIndex ?? 0) + 1, dashIndex ?? void 0);
161
- else if (cliName) {
160
+ if (parsedArgv._[0] && !cliName) {
161
+ const allAfterCli = rawArgs.slice((cliArgIndex ?? 0) + 1, dashIndex ?? void 0);
162
+ const result = [];
163
+ for (let i = 0; i < allAfterCli.length; i++) {
164
+ const arg = allAfterCli[i];
165
+ if (arg.startsWith("-")) {
166
+ result.push(arg);
167
+ if (!arg.includes("=") && i + 1 < allAfterCli.length) {
168
+ const nextArg = allAfterCli[i + 1];
169
+ if (nextArg && !nextArg.startsWith("-")) {
170
+ result.push(nextArg);
171
+ i++;
172
+ }
173
+ }
174
+ } else positionalPromptWords.push(arg);
175
+ }
176
+ return result;
177
+ } else if (cliName) {
162
178
  const result = [];
163
179
  const argsToCheck = rawArgs.slice(0, dashIndex ?? void 0);
164
180
  for (let i = 0; i < argsToCheck.length; i++) {
165
181
  const arg = argsToCheck[i];
166
182
  if (!arg) continue;
167
183
  const [flag] = arg.split("=");
168
- if (flag && yargsConsumed.has(flag)) {
184
+ if (flag && yargsConsumed.has(flag) || flag?.startsWith("--no-") && yargsConsumed.has(`--${flag.slice(5)}`)) {
169
185
  if (!arg.includes("=") && i + 1 < argsToCheck.length) {
170
186
  const nextArg = argsToCheck[i + 1];
171
187
  if (nextArg && !nextArg.startsWith("-")) i++;
172
188
  }
173
- } else result.push(arg);
189
+ } else if (arg.startsWith("-")) {
190
+ result.push(arg);
191
+ if (!arg.includes("=") && i + 1 < argsToCheck.length) {
192
+ const nextArg = argsToCheck[i + 1];
193
+ if (nextArg && !nextArg.startsWith("-")) {
194
+ result.push(nextArg);
195
+ i++;
196
+ }
197
+ }
198
+ } else positionalPromptWords.push(arg);
174
199
  }
175
200
  return result;
176
201
  }
177
202
  return [];
178
203
  })();
204
+ const positionalPrompt = positionalPromptWords.join(" ") || void 0;
179
205
  const dashPrompt = dashIndex === void 0 ? void 0 : rawArgs.slice(dashIndex + 1).join(" ");
180
206
  if (parsedArgv.exitOnIdle !== void 0) console.warn("\x1B[33m⚠ Warning: --exit-on-idle and -e are deprecated. Please use --timeout instead.\x1B[0m");
181
207
  return {
@@ -183,7 +209,11 @@ function parseCliArgs(argv) {
183
209
  env: process.env,
184
210
  cli: cliName || parsedArgv.cli || (dashIndex !== 0 ? parsedArgv._[0]?.toString()?.replace?.(/-yes$/, "") : void 0),
185
211
  cliArgs: [...cliArgsForSpawn, ...parsedArgv.yes ? ["--dangerously-skip-permissions"] : []],
186
- prompt: [parsedArgv.prompt, dashPrompt].filter(Boolean).join(" ") || void 0,
212
+ prompt: [
213
+ parsedArgv.prompt,
214
+ positionalPrompt,
215
+ dashPrompt
216
+ ].filter(Boolean).join(" ") || void 0,
187
217
  install: parsedArgv.install,
188
218
  exitOnIdle: Number((parsedArgv.timeout || parsedArgv.idle || parsedArgv.exitOnIdle)?.replace(/.*/, (e) => String(ms(e))) || 0),
189
219
  queue: parsedArgv.queue,
@@ -242,7 +272,12 @@ function detectPackageManager() {
242
272
  */
243
273
  async function checkAndAutoUpdate() {
244
274
  if (process.env.AGENT_YES_NO_UPDATE) return;
245
- if (process.env.AGENT_YES_UPDATED === version) return;
275
+ if (process.env.AGENT_YES_UPDATED) return;
276
+ if (import.meta.url.startsWith("file://") && !import.meta.url.includes("node_modules")) {
277
+ const scriptDir = path.dirname(new URL(import.meta.url).pathname);
278
+ const repoRoot = path.resolve(scriptDir, "..");
279
+ if (existsSync(path.join(repoRoot, ".git"))) return;
280
+ }
246
281
  try {
247
282
  let latestVersion;
248
283
  const cache = await readUpdateCache();
@@ -265,6 +300,7 @@ async function runInstall(latestVersion) {
265
300
  const installCmd = detectPackageManager() === "bun" ? `bun add -g agent-yes@${latestVersion}` : `npm install -g agent-yes@${latestVersion}`;
266
301
  process.stderr.write(`\x1b[33m[agent-yes] Updating ${version} → ${latestVersion}…\x1b[0m\n`);
267
302
  try {
303
+ const { execaCommand } = await import("execa");
268
304
  await execaCommand(installCmd, { stdio: "inherit" });
269
305
  process.stderr.write(`\x1b[32m[agent-yes] Updated to ${latestVersion}\x1b[0m\n`);
270
306
  return true;
@@ -321,10 +357,47 @@ function compareVersions(v1, v2) {
321
357
  return 0;
322
358
  }
323
359
  /**
360
+ * Detect how agent-yes was installed.
361
+ * Returns a short label: "git", "bun link", "bun", "npm", "npx", or "unknown"
362
+ */
363
+ function detectInstallMethod() {
364
+ try {
365
+ const scriptDir = path.dirname(new URL(import.meta.url).pathname);
366
+ if (!scriptDir.includes("node_modules")) {
367
+ const repoRoot = path.resolve(scriptDir, "..");
368
+ if (existsSync(path.join(repoRoot, ".git"))) return "git";
369
+ return "source";
370
+ }
371
+ const nodeModulesEntry = scriptDir.replace(/\/dist$/, "");
372
+ try {
373
+ if (lstatSync(nodeModulesEntry).isSymbolicLink()) {
374
+ const target = readlinkSync(nodeModulesEntry);
375
+ const resolvedTarget = path.resolve(path.dirname(nodeModulesEntry), target);
376
+ if (existsSync(path.join(resolvedTarget, ".git"))) return "bun link (git)";
377
+ return "bun link";
378
+ }
379
+ } catch {}
380
+ if (scriptDir.includes(".bun/")) return "bun";
381
+ if (scriptDir.includes(".npm/")) return "npx";
382
+ if (process.env.npm_execpath?.includes("bun")) return "bun";
383
+ if (process.env.npm_config_user_agent?.startsWith("bun")) return "bun";
384
+ if (process.env.npm_config_user_agent?.startsWith("npm")) return "npm";
385
+ return "npm";
386
+ } catch {
387
+ return "unknown";
388
+ }
389
+ }
390
+ /**
391
+ * Format version string with install method
392
+ */
393
+ function versionString() {
394
+ return `agent-yes v${version} (${detectInstallMethod()})`;
395
+ }
396
+ /**
324
397
  * Display version information with async latest version check
325
398
  */
326
399
  async function displayVersion() {
327
- console.log(version);
400
+ console.log(versionString());
328
401
  const latestVersion = await fetchLatestVersion();
329
402
  if (latestVersion) {
330
403
  const comparison = compareVersions(version, latestVersion);
@@ -466,6 +539,53 @@ async function downloadBinary(verbose = false) {
466
539
  return binaryPath;
467
540
  }
468
541
  /**
542
+ * Get the version of a Rust binary by running it with --version
543
+ */
544
+ function getRustBinaryVersion(binaryPath) {
545
+ try {
546
+ const match = execFileSync(binaryPath, ["--version"], {
547
+ timeout: 5e3,
548
+ encoding: "utf8",
549
+ stdio: [
550
+ "ignore",
551
+ "pipe",
552
+ "ignore"
553
+ ]
554
+ }).match(/(\d+\.\d+\.\d+)/);
555
+ return match ? match[1] : null;
556
+ } catch {
557
+ return null;
558
+ }
559
+ }
560
+ /**
561
+ * Check if a binary path is inside a git repo (dev build), and rebuild if outdated.
562
+ * Returns the same path if up-to-date or rebuilt, undefined if rebuild failed.
563
+ */
564
+ function autoRebuildIfOutdated(binaryPath, verbose) {
565
+ if (!binaryPath.includes("/target/release") && !binaryPath.includes("/target/debug")) return true;
566
+ const binaryVersion = getRustBinaryVersion(binaryPath);
567
+ if (verbose) console.log(`[rust] Binary version: ${binaryVersion}, package version: ${version}`);
568
+ if (binaryVersion === version) return true;
569
+ const rsDir = binaryPath.replace(/\/target\/(release|debug)\/agent-yes.*$/, "");
570
+ if (!existsSync(path.join(rsDir, "Cargo.toml"))) {
571
+ if (verbose) console.log(`[rust] Cannot find Cargo.toml at ${rsDir}, skipping rebuild`);
572
+ return true;
573
+ }
574
+ process.stderr.write(`\x1b[33m[rust] Binary outdated (${binaryVersion ?? "unknown"} → ${version}), rebuilding…\x1b[0m\n`);
575
+ try {
576
+ execFileSync("cargo", ["build", ...binaryPath.includes("/target/release") ? ["--release"] : []], {
577
+ cwd: rsDir,
578
+ stdio: "inherit",
579
+ timeout: 3e5
580
+ });
581
+ process.stderr.write(`\x1b[32m[rust] Rebuild complete\x1b[0m\n`);
582
+ return true;
583
+ } catch {
584
+ process.stderr.write(`\x1b[31m[rust] Auto-rebuild failed, using outdated binary\x1b[0m\n`);
585
+ return true;
586
+ }
587
+ }
588
+ /**
469
589
  * Get or download the Rust binary
470
590
  */
471
591
  async function getRustBinary(options = {}) {
@@ -474,6 +594,7 @@ async function getRustBinary(options = {}) {
474
594
  const existing = findRustBinary(verbose);
475
595
  if (existing) {
476
596
  if (verbose) console.log(`[rust] Using existing binary: ${existing}`);
597
+ autoRebuildIfOutdated(existing, verbose);
477
598
  return existing;
478
599
  }
479
600
  }
@@ -506,15 +627,23 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
506
627
 
507
628
  //#endregion
508
629
  //#region ts/cli.ts
630
+ {
631
+ const rawArgs = process.argv.slice(2);
632
+ if (rawArgs[0] === "-v" || rawArgs.includes("--version")) {
633
+ console.log(versionString());
634
+ process.exit(0);
635
+ }
636
+ }
509
637
  await checkAndAutoUpdate();
638
+ logger.info(versionString());
510
639
  const config = parseCliArgs(process.argv);
511
640
  if (config.tray) {
512
- const { startTray } = await import("./tray-CPpdxTV-.js");
641
+ const { startTray } = await import("./tray-Bzb1owBN.js");
513
642
  await startTray();
514
643
  await new Promise(() => {});
515
644
  }
516
645
  {
517
- const { ensureTray } = await import("./tray-CPpdxTV-.js");
646
+ const { ensureTray } = await import("./tray-Bzb1owBN.js");
518
647
  ensureTray();
519
648
  }
520
649
  if (config.useRust) {
@@ -528,6 +657,7 @@ if (config.useRust) {
528
657
  }
529
658
  }
530
659
  if (rustBinary) {
660
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-C7sGMdKJ.js");
531
661
  const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
532
662
  if (config.verbose) {
533
663
  console.log(`[rust] Using binary: ${rustBinary}`);
@@ -557,6 +687,7 @@ if (config.showVersion) {
557
687
  process.exit(0);
558
688
  }
559
689
  if (config.appendPrompt) {
690
+ const { PidStore } = await import("./pidStore-B4yDm3TL.js");
560
691
  const ipcPath = await PidStore.findActiveFifo(process.cwd());
561
692
  if (!ipcPath) {
562
693
  console.error("No active agent with IPC found in current directory.");
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- import { a as AgentContext, i as config, l as removeControlCharacters, n as CLIS_CONFIG, r as agentYes } from "./SUPPORTED_CLIS-Bqw9gxey.js";
2
- import "./logger-CX77vJDA.js";
1
+ import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-CsdLrLod.js";
2
+ import "./logger-B9h0djqx.js";
3
+ import "./pidStore-CPrgJSJi.js";
3
4
 
4
5
  export { AgentContext, CLIS_CONFIG, config, agentYes as default, removeControlCharacters };
@@ -0,0 +1,51 @@
1
+ //#region ts/logger.ts
2
+ let _inner = null;
3
+ let _initPromise = null;
4
+ const _queue = [];
5
+ function init() {
6
+ if (_initPromise) return _initPromise;
7
+ _initPromise = import("winston").then(({ default: winston }) => {
8
+ const logFormat = winston.format.combine(winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), winston.format.printf(({ timestamp, level, message, ...meta }) => {
9
+ return `${timestamp} [${level}]: ${message}${Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : ""}`;
10
+ }));
11
+ _inner = winston.createLogger({
12
+ level: process.env.VERBOSE ? "debug" : "info",
13
+ format: logFormat,
14
+ transports: [new winston.transports.Console({ format: winston.format.combine(winston.format.colorize(), logFormat) })],
15
+ silent: false
16
+ });
17
+ for (const { level, msg, meta } of _queue.splice(0)) _inner[level](msg, ...meta);
18
+ });
19
+ return _initPromise;
20
+ }
21
+ function makeMethod(level) {
22
+ return (msg, ...meta) => {
23
+ if (_inner) _inner[level](msg, ...meta);
24
+ else {
25
+ _queue.push({
26
+ level,
27
+ msg,
28
+ meta
29
+ });
30
+ init().catch((e) => console.error("[logger] Failed to load winston:", e));
31
+ }
32
+ };
33
+ }
34
+ /** Add a winston transport. Awaits logger initialization first. */
35
+ async function addTransport(transport) {
36
+ await init();
37
+ _inner.add(transport);
38
+ }
39
+ const logger = {
40
+ error: makeMethod("error"),
41
+ warn: makeMethod("warn"),
42
+ info: makeMethod("info"),
43
+ http: makeMethod("http"),
44
+ verbose: makeMethod("verbose"),
45
+ debug: makeMethod("debug"),
46
+ silly: makeMethod("silly")
47
+ };
48
+
49
+ //#endregion
50
+ export { logger as n, addTransport as t };
51
+ //# sourceMappingURL=logger-B9h0djqx.js.map
@@ -0,0 +1,7 @@
1
+ //#region package.json
2
+ var name = "agent-yes";
3
+ var version = "1.73.1";
4
+
5
+ //#endregion
6
+ export { version as n, name as t };
7
+ //# sourceMappingURL=package-DpfHTSW2.js.map
@@ -0,0 +1,4 @@
1
+ import "./logger-B9h0djqx.js";
2
+ import { t as PidStore } from "./pidStore-CPrgJSJi.js";
3
+
4
+ export { PidStore };
@@ -0,0 +1,319 @@
1
+ import { n as logger } from "./logger-B9h0djqx.js";
2
+ import { closeSync, existsSync, fsyncSync, openSync } from "fs";
3
+ import { appendFile, mkdir, readFile, rename, writeFile } from "fs/promises";
4
+ import path from "path";
5
+ import { lock } from "proper-lockfile";
6
+
7
+ //#region ts/JsonlStore.ts
8
+ /**
9
+ * A lightweight NeDB-style JSONL persistence layer.
10
+ *
11
+ * - Append-only writes (one JSON object per line)
12
+ * - Same `_id` → last line wins (fields merged)
13
+ * - `$$deleted` lines act as tombstones
14
+ * - Crash recovery: skip partial last line, recover from temp file
15
+ * - Multi-process safe via proper-lockfile (reads don't need lock)
16
+ * - Compact on close: deduplicates into clean file via atomic rename
17
+ */
18
+ var JsonlStore = class {
19
+ filePath;
20
+ tempPath;
21
+ docs = /* @__PURE__ */ new Map();
22
+ constructor(filePath) {
23
+ this.filePath = filePath;
24
+ this.tempPath = filePath + "~";
25
+ }
26
+ /**
27
+ * Load all records from the JSONL file. No lock needed.
28
+ * Handles crash recovery: partial last line skipped, temp file recovery.
29
+ */
30
+ async load() {
31
+ await mkdir(path.dirname(this.filePath), { recursive: true });
32
+ if (!existsSync(this.filePath) && existsSync(this.tempPath)) {
33
+ logger.debug("[JsonlStore] Recovering from temp file");
34
+ await rename(this.tempPath, this.filePath);
35
+ }
36
+ this.docs = /* @__PURE__ */ new Map();
37
+ let raw = "";
38
+ try {
39
+ raw = await readFile(this.filePath, "utf-8");
40
+ } catch (err) {
41
+ if (err.code === "ENOENT") return this.docs;
42
+ throw err;
43
+ }
44
+ const lines = raw.split("\n");
45
+ let corruptCount = 0;
46
+ for (const line of lines) {
47
+ const trimmed = line.trim();
48
+ if (!trimmed) continue;
49
+ try {
50
+ const doc = JSON.parse(trimmed);
51
+ if (!doc._id) continue;
52
+ if (doc.$$deleted) this.docs.delete(doc._id);
53
+ else {
54
+ const existing = this.docs.get(doc._id);
55
+ if (existing) this.docs.set(doc._id, {
56
+ ...existing,
57
+ ...doc
58
+ });
59
+ else this.docs.set(doc._id, doc);
60
+ }
61
+ } catch {
62
+ corruptCount++;
63
+ }
64
+ }
65
+ if (corruptCount > 0) logger.debug(`[JsonlStore] Skipped ${corruptCount} corrupt line(s) in ${this.filePath}`);
66
+ return this.docs;
67
+ }
68
+ /** Get all live documents. */
69
+ getAll() {
70
+ return Array.from(this.docs.values());
71
+ }
72
+ /** Find a document by _id. */
73
+ getById(id) {
74
+ return this.docs.get(id);
75
+ }
76
+ /** Find documents matching a predicate. */
77
+ find(predicate) {
78
+ return this.getAll().filter(predicate);
79
+ }
80
+ /** Find first document matching a predicate. */
81
+ findOne(predicate) {
82
+ for (const doc of this.docs.values()) if (predicate(doc)) return doc;
83
+ }
84
+ /**
85
+ * Append a new document. Acquires lock.
86
+ * If no _id is provided, one is generated.
87
+ */
88
+ async append(doc) {
89
+ const id = doc._id || generateId();
90
+ const { _id: _, ...rest } = doc;
91
+ const fullDoc = {
92
+ _id: id,
93
+ ...rest
94
+ };
95
+ return await this.withLock(async () => {
96
+ await appendFile(this.filePath, JSON.stringify(fullDoc) + "\n");
97
+ const existing = this.docs.get(fullDoc._id);
98
+ if (existing) this.docs.set(fullDoc._id, {
99
+ ...existing,
100
+ ...fullDoc
101
+ });
102
+ else this.docs.set(fullDoc._id, fullDoc);
103
+ return fullDoc;
104
+ });
105
+ }
106
+ /**
107
+ * Update a document by _id. Appends a merge line. Acquires lock.
108
+ */
109
+ async updateById(id, patch) {
110
+ await this.withLock(async () => {
111
+ const line = {
112
+ _id: id,
113
+ ...patch
114
+ };
115
+ await appendFile(this.filePath, JSON.stringify(line) + "\n");
116
+ const existing = this.docs.get(id);
117
+ if (existing) this.docs.set(id, {
118
+ ...existing,
119
+ ...patch
120
+ });
121
+ });
122
+ }
123
+ /**
124
+ * Delete a document by _id. Appends a tombstone. Acquires lock.
125
+ */
126
+ async deleteById(id) {
127
+ await this.withLock(async () => {
128
+ const tombstone = {
129
+ _id: id,
130
+ $$deleted: true
131
+ };
132
+ await appendFile(this.filePath, JSON.stringify(tombstone) + "\n");
133
+ this.docs.delete(id);
134
+ });
135
+ }
136
+ /**
137
+ * Compact the file: deduplicate entries, remove tombstones.
138
+ * Writes to temp file, fsyncs, then atomic renames.
139
+ * Acquires lock.
140
+ */
141
+ async compact() {
142
+ const lines = Array.from(this.docs.values()).map((doc) => {
143
+ const { _id, $$deleted: _$$deleted, ...rest } = doc;
144
+ return JSON.stringify({
145
+ _id,
146
+ ...rest
147
+ });
148
+ }).join("\n");
149
+ const content = lines ? lines + "\n" : "";
150
+ try {
151
+ await this.withLock(async () => {
152
+ await writeFile(this.tempPath, content);
153
+ const fd = openSync(this.tempPath, "r");
154
+ fsyncSync(fd);
155
+ closeSync(fd);
156
+ await rename(this.tempPath, this.filePath);
157
+ });
158
+ } catch {
159
+ await writeFile(this.filePath, content);
160
+ }
161
+ }
162
+ async withLock(fn) {
163
+ const dir = path.dirname(this.filePath);
164
+ let release;
165
+ try {
166
+ release = await lock(dir, {
167
+ lockfilePath: this.filePath + ".lock",
168
+ retries: {
169
+ retries: 5,
170
+ minTimeout: 50,
171
+ maxTimeout: 500
172
+ }
173
+ });
174
+ return await fn();
175
+ } finally {
176
+ if (release) await release();
177
+ }
178
+ }
179
+ };
180
+ let idCounter = 0;
181
+ function generateId() {
182
+ return Date.now().toString(36) + (idCounter++).toString(36) + Math.random().toString(36).slice(2, 6);
183
+ }
184
+
185
+ //#endregion
186
+ //#region ts/pidStore.ts
187
+ var PidStore = class PidStore {
188
+ storeDir;
189
+ store;
190
+ constructor(workingDir) {
191
+ this.storeDir = path.resolve(workingDir, ".agent-yes");
192
+ this.store = new JsonlStore(path.join(this.storeDir, "pid-records.jsonl"));
193
+ }
194
+ async init() {
195
+ try {
196
+ await this.ensureGitignore();
197
+ await this.store.load();
198
+ await this.cleanStaleRecords();
199
+ } catch (error) {
200
+ logger.warn("[pidStore] Failed to initialize:", error);
201
+ }
202
+ }
203
+ async registerProcess({ pid, cli, args, prompt, cwd }) {
204
+ const now = Date.now();
205
+ const record = {
206
+ pid,
207
+ cli,
208
+ args: JSON.stringify(args),
209
+ prompt,
210
+ cwd,
211
+ logFile: path.resolve(this.getLogDir(), `${pid}.log`),
212
+ fifoFile: this.getFifoPath(pid),
213
+ status: "active",
214
+ exitReason: "",
215
+ startedAt: now
216
+ };
217
+ const existing = this.store.findOne((doc) => doc.pid === pid);
218
+ if (existing) await this.store.updateById(existing._id, record);
219
+ else await this.store.append(record);
220
+ const result = this.store.findOne((doc) => doc.pid === pid);
221
+ if (!result) {
222
+ const allRecords = this.store.getAll();
223
+ logger.error(`[pidStore] Failed to find record for PID ${pid}. All records:`, allRecords);
224
+ throw new Error(`Failed to register process ${pid}`);
225
+ }
226
+ logger.debug(`[pidStore] Registered process ${pid}`);
227
+ return result;
228
+ }
229
+ async updateStatus(pid, status, extra) {
230
+ const existing = this.store.findOne((doc) => doc.pid === pid);
231
+ if (!existing) return;
232
+ const patch = { status };
233
+ if (extra?.exitReason !== void 0) patch.exitReason = extra.exitReason;
234
+ if (extra?.exitCode !== void 0) patch.exitCode = extra.exitCode;
235
+ await this.store.updateById(existing._id, patch);
236
+ logger.debug(`[pidStore] Updated process ${pid} status=${status}`);
237
+ }
238
+ getAllRecords() {
239
+ return this.store.getAll();
240
+ }
241
+ getLogDir() {
242
+ return path.resolve(this.storeDir, "logs");
243
+ }
244
+ getFifoPath(pid) {
245
+ if (process.platform === "win32") return `\\\\.\\pipe\\agent-yes-${pid}`;
246
+ else return path.resolve(this.storeDir, "fifo", `${pid}.stdin`);
247
+ }
248
+ async cleanStaleRecords() {
249
+ const activeRecords = this.store.find((r) => r.status !== "exited");
250
+ for (const record of activeRecords) if (!this.isProcessAlive(record.pid)) {
251
+ await this.store.updateById(record._id, {
252
+ status: "exited",
253
+ exitReason: "stale-cleanup"
254
+ });
255
+ logger.debug(`[pidStore] Cleaned stale record for PID ${record.pid}`);
256
+ }
257
+ }
258
+ async close() {
259
+ try {
260
+ await this.store.compact();
261
+ } catch (error) {
262
+ logger.debug("[pidStore] Compact on close failed:", error);
263
+ }
264
+ logger.debug("[pidStore] Database compacted and closed");
265
+ }
266
+ isProcessAlive(pid) {
267
+ try {
268
+ process.kill(pid, 0);
269
+ return true;
270
+ } catch {
271
+ return false;
272
+ }
273
+ }
274
+ async ensureGitignore() {
275
+ const gitignorePath = path.join(this.storeDir, ".gitignore");
276
+ const gitignoreContent = `# Auto-generated .gitignore for agent-yes
277
+ # Ignore all log files and runtime data
278
+ logs/
279
+ fifo/
280
+ pid-db/
281
+ *.jsonl
282
+ *.jsonl~
283
+ *.jsonl.lock
284
+ *.sqlite
285
+ *.sqlite-*
286
+ *.log
287
+ *.raw.log
288
+ *.lines.log
289
+ *.debug.log
290
+
291
+ # Ignore .gitignore itself
292
+ .gitignore
293
+
294
+ `;
295
+ try {
296
+ await mkdir(this.storeDir, { recursive: true });
297
+ await writeFile(gitignorePath, gitignoreContent, { flag: "wx" });
298
+ logger.debug(`[pidStore] Created .gitignore in ${this.storeDir}`);
299
+ } catch (error) {
300
+ if (error.code !== "EEXIST") logger.warn(`[pidStore] Failed to create .gitignore:`, error);
301
+ }
302
+ }
303
+ static async findActiveFifo(workingDir) {
304
+ try {
305
+ const store = new PidStore(workingDir);
306
+ await store.init();
307
+ const records = store.store.find((r) => r.status !== "exited").sort((a, b) => b.startedAt - a.startedAt);
308
+ await store.close();
309
+ return records[0]?.fifoFile ?? null;
310
+ } catch (error) {
311
+ logger.warn("[pidStore] findActiveFifo failed:", error);
312
+ return null;
313
+ }
314
+ }
315
+ };
316
+
317
+ //#endregion
318
+ export { PidStore as t };
319
+ //# sourceMappingURL=pidStore-CPrgJSJi.js.map
@@ -1,8 +1,8 @@
1
1
  import { execSync } from "child_process";
2
+ import { existsSync } from "fs";
2
3
  import { mkdir, readFile, rename, writeFile } from "fs/promises";
3
- import path from "path";
4
4
  import { homedir } from "os";
5
- import { existsSync } from "fs";
5
+ import path from "path";
6
6
 
7
7
  //#region ts/runningLock.ts
8
8
  const getLockDir = () => path.join(process.env.CLAUDE_YES_HOME || homedir(), ".claude-yes");
@@ -260,4 +260,4 @@ function shouldUseLock(_cwd) {
260
260
 
261
261
  //#endregion
262
262
  export { shouldUseLock as i, getRunningAgentCount as n, releaseLock as r, acquireLock as t };
263
- //# sourceMappingURL=runningLock-BBI_URhR.js.map
263
+ //# sourceMappingURL=runningLock-DQWJSptq.js.map