claude-yes 1.83.0 → 1.85.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.
@@ -1,6 +1,6 @@
1
- import { t as CLIS_CONFIG } from "./ts-DbdWuoGq.js";
1
+ import { t as CLIS_CONFIG } from "./ts-BTCVz_nZ.js";
2
2
  import "./logger-B9h0djqx.js";
3
- import "./versionChecker-Ct-4UPeG.js";
3
+ import "./versionChecker-Cir2ZoFL.js";
4
4
  import "./pidStore-C1JXxoPi.js";
5
5
  import "./globalPidIndex-Cr-g75QF.js";
6
6
 
@@ -9,4 +9,4 @@ const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
9
9
 
10
10
  //#endregion
11
11
  export { SUPPORTED_CLIS };
12
- //# sourceMappingURL=SUPPORTED_CLIS-DkXclUge.js.map
12
+ //# sourceMappingURL=SUPPORTED_CLIS-DnCV2Fj1.js.map
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import { n as logger } from "./logger-B9h0djqx.js";
3
- import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-Ct-4UPeG.js";
3
+ import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-Cir2ZoFL.js";
4
4
  import { argv } from "process";
5
5
  import { execFileSync, spawn } from "child_process";
6
6
  import ms from "ms";
@@ -42,6 +42,10 @@ function parseCliArgs(argv, supportedClis) {
42
42
  type: "boolean",
43
43
  description: "Prepend SKILL.md header from current directory to the prompt (helpful for non-Claude agents)",
44
44
  default: false
45
+ }).option("swarm-hint", {
46
+ type: "boolean",
47
+ description: "Inject peer discovery hint into agent system prompt when other agents are running (use --no-swarm-hint to opt out)",
48
+ default: true
45
49
  }).option("timeout", {
46
50
  type: "string",
47
51
  description: "Exit after a period of inactivity, e.g., \"5s\" or \"1m\"",
@@ -221,6 +225,7 @@ function parseCliArgs(argv, supportedClis) {
221
225
  verbose: parsedArgv.verbose,
222
226
  resume: parsedArgv.continue,
223
227
  useSkills: parsedArgv.useSkills,
228
+ swarmHint: parsedArgv.swarmHint,
224
229
  appendPrompt: parsedArgv.appendPrompt,
225
230
  useStdinAppend: Boolean(parsedArgv.stdpush || parsedArgv.ipc || parsedArgv.fifo),
226
231
  showVersion: parsedArgv.version,
@@ -475,7 +480,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
475
480
  }
476
481
  }
477
482
  {
478
- const { isSubcommand, runSubcommand } = await import("./subcommands-Vt_yQiEZ.js");
483
+ const { isSubcommand, runSubcommand } = await import("./subcommands-BwWcA9uo.js");
479
484
  if (isSubcommand(process.argv[2])) {
480
485
  const code = await runSubcommand(process.argv);
481
486
  process.exit(code ?? 0);
@@ -504,7 +509,7 @@ if (config.useRust) {
504
509
  }
505
510
  }
506
511
  if (rustBinary) {
507
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-DkXclUge.js");
512
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-DnCV2Fj1.js");
508
513
  const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
509
514
  if (config.verbose) {
510
515
  console.log(`[rust] Using binary: ${rustBinary}`);
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-DbdWuoGq.js";
1
+ import { a as removeControlCharacters, i as AgentContext, n as agentYes, r as config, t as CLIS_CONFIG } from "./ts-BTCVz_nZ.js";
2
2
  import "./logger-B9h0djqx.js";
3
- import "./versionChecker-Ct-4UPeG.js";
3
+ import "./versionChecker-Cir2ZoFL.js";
4
4
  import "./pidStore-C1JXxoPi.js";
5
5
  import "./globalPidIndex-Cr-g75QF.js";
6
6
 
@@ -1,12 +1,13 @@
1
1
  import "./logger-B9h0djqx.js";
2
2
  import { r as readGlobalPids } from "./globalPidIndex-Cr-g75QF.js";
3
+ import yargs from "yargs";
3
4
  import { appendFile, mkdir, open, readFile, stat, writeFile } from "fs/promises";
4
5
  import { homedir } from "os";
5
6
  import path from "path";
6
7
 
7
8
  //#region ts/subcommands.ts
8
9
  /**
9
- * `cy ls / read / cat / tail / head / send` subcommand implementations.
10
+ * `ay ls / read / cat / tail / head / send` subcommand implementations.
10
11
  *
11
12
  * Mirrors the principles of koho's `terminal-ws-lib.ts` (session list, render
12
13
  * via @xterm/headless, keyword-keyed input) — but file-based instead of via
@@ -61,7 +62,7 @@ async function compactNotes() {
61
62
  /**
62
63
  * Read the per-cwd TS PidStore JSONL and convert to the global record shape,
63
64
  * so pre-existing TS agents that were spawned before the global-index mirror
64
- * shipped still show up in `cy ls`. Merging is done in `mergeRecords`.
65
+ * shipped still show up in `ay ls`. Merging is done in `mergeRecords`.
65
66
  */
66
67
  async function readLocalTsPids(cwd) {
67
68
  const jsonlPath = path.join(cwd, ".agent-yes", "pid-records.jsonl");
@@ -118,6 +119,7 @@ const SUBCOMMANDS = new Set([
118
119
  "ls",
119
120
  "list",
120
121
  "ps",
122
+ "status",
121
123
  "read",
122
124
  "cat",
123
125
  "tail",
@@ -126,6 +128,7 @@ const SUBCOMMANDS = new Set([
126
128
  "restart",
127
129
  "note"
128
130
  ]);
131
+ const IDLE_THRESHOLD_MS = 60 * 1e3;
129
132
  function isSubcommand(name) {
130
133
  return !!name && SUBCOMMANDS.has(name);
131
134
  }
@@ -142,6 +145,7 @@ async function runSubcommand(argv) {
142
145
  case "ls":
143
146
  case "list":
144
147
  case "ps": return await cmdLs(rest);
148
+ case "status": return await cmdStatus(rest);
145
149
  case "read":
146
150
  case "cat": return await cmdRead(rest, { mode: "cat" });
147
151
  case "tail": return await cmdRead(rest, { mode: "tail" });
@@ -153,53 +157,10 @@ async function runSubcommand(argv) {
153
157
  }
154
158
  } catch (err) {
155
159
  const msg = err instanceof Error ? err.message : String(err);
156
- process.stderr.write(`cy ${sub}: ${msg}\n`);
160
+ process.stderr.write(`ay ${sub}: ${msg}\n`);
157
161
  return 1;
158
162
  }
159
163
  }
160
- function parseArgs(rest) {
161
- const flags = {};
162
- const positional = [];
163
- for (let i = 0; i < rest.length; i++) {
164
- const arg = rest[i];
165
- if (arg.startsWith("--")) {
166
- const eq = arg.indexOf("=");
167
- if (eq >= 0) flags[arg.slice(2, eq)] = arg.slice(eq + 1);
168
- else {
169
- const key = arg.slice(2);
170
- const next = rest[i + 1];
171
- if ([
172
- "all",
173
- "active",
174
- "follow",
175
- "json",
176
- "latest"
177
- ].includes(key) || !next || next.startsWith("-")) flags[key] = true;
178
- else {
179
- flags[key] = next;
180
- i++;
181
- }
182
- }
183
- } else if (arg.startsWith("-") && arg.length > 1) if (arg === "-n") {
184
- flags["n"] = rest[i + 1] ?? "";
185
- i++;
186
- } else flags[arg.slice(1)] = true;
187
- else positional.push(arg);
188
- }
189
- return {
190
- flags,
191
- positional
192
- };
193
- }
194
- function commonOpts(flags) {
195
- return {
196
- all: !!flags.all,
197
- active: !!flags.active,
198
- cwdScope: typeof flags.cwd === "string" ? path.resolve(flags.cwd) : flags.cwd === true ? process.cwd() : null,
199
- latest: !!flags.latest,
200
- json: !!flags.json
201
- };
202
- }
203
164
  function matchKeyword(record, keyword) {
204
165
  if (!keyword) return true;
205
166
  const kw = keyword.toLowerCase();
@@ -239,9 +200,44 @@ async function resolveOne(keyword, opts) {
239
200
  throw new Error(`keyword "${keyword}" matched ${matches.length} agents — disambiguate by pid or pass --latest:\n${lines}`);
240
201
  }
241
202
  async function cmdLs(rest) {
242
- const { flags, positional } = parseArgs(rest);
243
- const opts = commonOpts(flags);
244
- const keyword = positional[0];
203
+ const y = yargs(rest).usage("Usage: ay ls [keyword] [options]\n ay list [keyword] [options]\n ay ps [keyword] [options]\n\nList running agents. Optionally filter by keyword (pid, cwd substring, or prompt substring).").option("all", {
204
+ type: "boolean",
205
+ default: false,
206
+ description: "Show all agents including exited ones"
207
+ }).option("active", {
208
+ type: "boolean",
209
+ default: false,
210
+ description: "Only show agents with an alive process"
211
+ }).option("json", {
212
+ type: "boolean",
213
+ default: false,
214
+ description: "Output as JSON array"
215
+ }).option("latest", {
216
+ type: "boolean",
217
+ default: false,
218
+ description: "Show only the most recent agent"
219
+ }).option("cwd", {
220
+ type: "string",
221
+ description: "Restrict to agents whose cwd starts with dir"
222
+ }).option("help", {
223
+ alias: "h",
224
+ type: "boolean",
225
+ default: false,
226
+ description: "Show this help"
227
+ }).example("ay ls", "list running agents").example("ay ls --all", "include exited agents").example("ay ls --json", "machine-readable output").example("ay ls symval", "filter by cwd/prompt keyword").help(false).version(false).exitProcess(false);
228
+ const argv = await y.parseAsync();
229
+ if (argv.help || argv.h) {
230
+ process.stdout.write(await y.getHelp() + "\n");
231
+ return 0;
232
+ }
233
+ const keyword = argv._[0] !== void 0 ? String(argv._[0]) : void 0;
234
+ const opts = {
235
+ all: argv.all,
236
+ active: argv.active,
237
+ json: argv.json,
238
+ latest: argv.latest,
239
+ cwdScope: typeof argv.cwd === "string" ? path.resolve(argv.cwd) : null
240
+ };
245
241
  const records = await listRecords(keyword, opts);
246
242
  if (opts.json) {
247
243
  process.stdout.write(JSON.stringify(records, null, 2) + "\n");
@@ -262,7 +258,6 @@ async function cmdLs(rest) {
262
258
  };
263
259
  const fixedWidth = widths.pid + widths.cli + widths.status + widths.age + widths.cwd + 10;
264
260
  const promptBudget = Math.max(20, termWidth - fixedWidth - 1);
265
- const IDLE_THRESHOLD_MS = 60 * 1e3;
266
261
  const notes = await readNotes();
267
262
  const rows = await Promise.all(records.map(async (r) => {
268
263
  let displayStatus;
@@ -277,8 +272,8 @@ async function cmdLs(rest) {
277
272
  if (note) {
278
273
  label = truncate(note, promptBudget);
279
274
  hasNote = true;
280
- } else if (r.log_file && displayStatus !== "stopped") label = truncate(await extractActivity(r.log_file) ?? r.prompt ?? "", promptBudget);
281
- else label = truncate(r.prompt ?? "", promptBudget);
275
+ } else if (r.log_file && displayStatus !== "stopped") label = truncate(await extractActivity(r.log_file) ?? (r.prompt ? `→ ${r.prompt}` : ""), promptBudget);
276
+ else label = truncate(r.prompt ? `→ ${r.prompt}` : "", promptBudget);
282
277
  return {
283
278
  pid: String(r.pid),
284
279
  cli: r.cli,
@@ -312,14 +307,17 @@ async function cmdLs(rest) {
312
307
  const stopped = rows.find((r) => !r._alive);
313
308
  const hints = ["\n"];
314
309
  if (alive) {
315
- hints.push(` cy tail ${alive.pid} # view latest output\n`);
316
- hints.push(` cy tail -f ${alive.pid} # follow live output\n`);
317
- hints.push(` cy send ${alive.pid} "next: ..." # send a prompt\n`);
318
- hints.push(` cy send ${alive.pid} "" --code=ctrl-c # interrupt\n`);
319
- hints.push(` cy note ${alive.pid} "what it's doing" # set a note\n`);
310
+ hints.push(` ay status ${alive.pid} # JSON status snapshot\n`);
311
+ hints.push(` ay status ${alive.pid} --watch # stream changes as JSON\n`);
312
+ hints.push(` ay tail ${alive.pid} # view latest output\n`);
313
+ hints.push(` ay tail -f ${alive.pid} # follow live output\n`);
314
+ hints.push(` ay send ${alive.pid} "next: ..." # send a prompt (keyword: pid, cwd, or prompt substring)\n`);
315
+ hints.push(` ay send ${alive.pid} "" --code=ctrl-c # interrupt\n`);
316
+ hints.push(` ay note ${alive.pid} "what it's doing" # set a note\n`);
317
+ hints.push(` ay ls --json # machine-readable list for scripts/agents\n`);
320
318
  }
321
- if (stopped) hints.push(` cy restart ${stopped.pid} # restart stopped agent\n`);
322
- if (!alive && !stopped) hints.push(` cy ls --all # show exited agents\n`);
319
+ if (stopped) hints.push(` ay restart ${stopped.pid} # restart stopped agent\n`);
320
+ if (!alive && !stopped) hints.push(` ay ls --all # show exited agents\n`);
323
321
  process.stderr.write(hints.join(""));
324
322
  }
325
323
  return 0;
@@ -343,11 +341,36 @@ function truncate(s, n) {
343
341
  return s.slice(0, n - 1) + "…";
344
342
  }
345
343
  async function cmdRead(rest, { mode }) {
346
- const { flags, positional } = parseArgs(rest);
347
- const opts = commonOpts(flags);
348
- const keyword = positional[0];
349
- const follow = !!(flags.f || flags.follow);
350
- const nFlag = typeof flags.n === "string" ? Number(flags.n) : void 0;
344
+ const argv = await yargs(rest).usage("Usage: ay read/cat/tail/head <keyword> [options]").option("follow", {
345
+ alias: "f",
346
+ type: "boolean",
347
+ default: false,
348
+ description: "Follow log output (Ctrl-C to stop)"
349
+ }).option("n", {
350
+ type: "number",
351
+ description: "Number of lines (default: 96 for tail/head)"
352
+ }).option("all", {
353
+ type: "boolean",
354
+ default: false,
355
+ description: "Include exited agents"
356
+ }).option("latest", {
357
+ type: "boolean",
358
+ default: false,
359
+ description: "Use most recent match when multiple match"
360
+ }).option("cwd", {
361
+ type: "string",
362
+ description: "Restrict to agents under this dir"
363
+ }).help(false).version(false).exitProcess(false).parseAsync();
364
+ const opts = {
365
+ all: argv.all,
366
+ active: false,
367
+ json: false,
368
+ latest: argv.latest,
369
+ cwdScope: typeof argv.cwd === "string" ? path.resolve(argv.cwd) : null
370
+ };
371
+ const keyword = argv._[0] !== void 0 ? String(argv._[0]) : void 0;
372
+ const follow = argv.follow;
373
+ const nFlag = argv.n;
351
374
  const n = nFlag !== void 0 && Number.isFinite(nFlag) && nFlag > 0 ? Math.floor(nFlag) : mode === "cat" ? 0 : 96;
352
375
  const record = await resolveOne(keyword, opts);
353
376
  const logPath = record.log_file;
@@ -392,8 +415,8 @@ async function cmdRead(rest, { mode }) {
392
415
  return 0;
393
416
  }
394
417
  process.stderr.write(`
395
- cy ls # list all agents
396
- cy tail -f ${record.pid} # follow live output\n cy send ${record.pid} "next: ..." # send a prompt\n cy send ${record.pid} "" --code=ctrl-c # interrupt\n`);
418
+ ay ls # list all agents
419
+ ay tail -f ${record.pid} # follow live output\n ay send ${record.pid} "next: ..." # send a prompt\n ay send ${record.pid} "" --code=ctrl-c # interrupt\n`);
397
420
  return 0;
398
421
  }
399
422
  /**
@@ -473,15 +496,23 @@ function extractActivityFromLines(lines) {
473
496
  return !s || /^─+$/.test(s) || s.startsWith("? for shortcuts") || /^esc to interrupt/i.test(s) || /\d+%\s*until auto-compact/i.test(s) || /^\/model\s+/i.test(s) || /^⧉\s+In\s+/i.test(s) || /^●\s+(high|medium|low)\s*[·•]/i.test(s) || /^[·•]\s*\d+\s+(left|request)/i.test(s);
474
497
  };
475
498
  const clean = lines.filter((l) => !isChrome(l));
476
- const thinkingLine = clean.find((l) => /^[^\w\s❯>⎿✓✗]\s+[A-Z]\w+[….]/u.test(l.trim()) || /still thinking/i.test(l));
499
+ const isSpinnerLine = (l) => /^[^\w\s❯>⎿✓✗]\s+[A-Z]\w+[….]/u.test(l.trim()) || /still thinking/i.test(l);
500
+ let lastPromptIdx = -1;
501
+ let lastSpinnerIdx = -1;
502
+ for (let i = clean.length - 1; i >= 0; i--) {
503
+ const l = clean[i].trim();
504
+ if (lastPromptIdx === -1 && l.startsWith("❯")) lastPromptIdx = i;
505
+ if (lastSpinnerIdx === -1 && isSpinnerLine(l)) lastSpinnerIdx = i;
506
+ if (lastPromptIdx !== -1 && lastSpinnerIdx !== -1) break;
507
+ }
508
+ if (lastPromptIdx > lastSpinnerIdx) {
509
+ const text = clean[lastPromptIdx].trim().replace(/^❯\s*/, "").trim();
510
+ return text ? `» ${text}` : null;
511
+ }
512
+ const thinkingLine = clean.find((l) => isSpinnerLine(l));
477
513
  if (thinkingLine) {
478
514
  const m = /^.\s+(\w+[^(]*)(?:\s*\(|$)/u.exec(thinkingLine.trim());
479
- return m ? `✳ ${m[1].trim()}` : "thinking…";
480
- }
481
- const promptLines = clean.filter((l) => /^❯\s+/.test(l.trim()));
482
- if (promptLines.length > 0) {
483
- const text = promptLines[promptLines.length - 1].trim().replace(/^❯\s+/, "").trim();
484
- if (text) return `» ${text}`;
515
+ return m?.[1] ? `✳ ${m[1].trim()}` : "thinking…";
485
516
  }
486
517
  const cookIdx = clean.findIndex((l) => /^✻\s+/.test(l.trim()));
487
518
  if (cookIdx >= 0) {
@@ -498,12 +529,33 @@ function extractActivityFromLines(lines) {
498
529
  return null;
499
530
  }
500
531
  async function cmdSend(rest) {
501
- const { flags, positional } = parseArgs(rest);
502
- const opts = commonOpts(flags);
503
- const keyword = positional[0];
504
- const rawMessage = positional.slice(1).join(" ");
505
- if (!keyword) throw new Error("usage: cy send <keyword> <msg|-> [--code=enter|esc|ctrl-c|ctrl-y|tab|none]");
506
- const trailing = controlCodeFromName(typeof flags.code === "string" ? flags.code.toLowerCase() : "enter");
532
+ const argv = await yargs(rest).usage("Usage: ay send <keyword> <msg|-> [options]").option("code", {
533
+ type: "string",
534
+ default: "enter",
535
+ description: "Trailing control code (enter|esc|ctrl-c|ctrl-y|tab|none)"
536
+ }).option("all", {
537
+ type: "boolean",
538
+ default: false,
539
+ description: "Include exited agents"
540
+ }).option("latest", {
541
+ type: "boolean",
542
+ default: false,
543
+ description: "Use most recent match"
544
+ }).option("cwd", {
545
+ type: "string",
546
+ description: "Restrict to agents under this dir"
547
+ }).help(false).version(false).exitProcess(false).parseAsync();
548
+ const opts = {
549
+ all: argv.all,
550
+ active: false,
551
+ json: false,
552
+ latest: argv.latest,
553
+ cwdScope: typeof argv.cwd === "string" ? path.resolve(argv.cwd) : null
554
+ };
555
+ const keyword = argv._[0] !== void 0 ? String(argv._[0]) : void 0;
556
+ const rawMessage = argv._.slice(1).map(String).join(" ");
557
+ if (!keyword) throw new Error("usage: ay send <keyword> <msg|-> [--code=enter|esc|ctrl-c|ctrl-y|tab|none]");
558
+ const trailing = controlCodeFromName(argv.code.toLowerCase());
507
559
  const record = await resolveOne(keyword, opts);
508
560
  const fifoPath = record.fifo_file;
509
561
  if (!fifoPath) throw new Error(`pid ${record.pid}: no fifo_file recorded — agent was not started with --stdpush (or was spawned by Rust which doesn't yet support FIFO IPC; see ROADMAP item 10)`);
@@ -513,14 +565,18 @@ async function cmdSend(rest) {
513
565
  for await (const chunk of process.stdin) chunks.push(chunk);
514
566
  body = Buffer.concat(chunks).toString("utf-8").trimEnd();
515
567
  } else body = rawMessage;
516
- if (body && trailing) {
517
- await writeToIpc(fifoPath, body);
568
+ const sourcePid = process.env.AGENT_YES_PID ? Number(process.env.AGENT_YES_PID) : null;
569
+ const talkBack = sourcePid ? `\n(from AGENT_YES_PID=${sourcePid} — reply: ay send ${sourcePid} "...")` : "";
570
+ const fullBody = body + talkBack;
571
+ if (fullBody && trailing) {
572
+ await writeToIpc(fifoPath, fullBody);
518
573
  await new Promise((r) => setTimeout(r, 200));
519
574
  await writeToIpc(fifoPath, trailing);
520
- } else await writeToIpc(fifoPath, body + trailing);
575
+ } else await writeToIpc(fifoPath, fullBody + trailing);
521
576
  const payload = body + trailing;
522
577
  process.stdout.write(`sent to pid ${record.pid} (${record.cli}): ${truncate(payload, 80)}\n`);
523
- process.stderr.write(`\n cy tail ${record.pid} # watch output\n cy ls # list all agents\n`);
578
+ const replyHint = sourcePid ? ` ay send ${sourcePid} "..." # reply to sender\n` : "";
579
+ process.stderr.write(`\n` + replyHint + ` ay tail ${record.pid} # watch output\n ay ls # list all agents\n`);
524
580
  return 0;
525
581
  }
526
582
  function controlCodeFromName(name) {
@@ -576,15 +632,24 @@ async function writeToIpc(ipcPath, payload) {
576
632
  }
577
633
  }
578
634
  async function cmdRestart(rest) {
579
- const { flags, positional } = parseArgs(rest);
635
+ const argv = await yargs(rest).usage("Usage: ay restart <keyword>").option("latest", {
636
+ type: "boolean",
637
+ default: false,
638
+ description: "Use most recent match"
639
+ }).option("cwd", {
640
+ type: "string",
641
+ description: "Restrict to agents under this dir"
642
+ }).help(false).version(false).exitProcess(false).parseAsync();
580
643
  const opts = {
581
- ...commonOpts(flags),
582
- all: true
644
+ all: true,
645
+ active: false,
646
+ json: false,
647
+ latest: argv.latest,
648
+ cwdScope: typeof argv.cwd === "string" ? path.resolve(argv.cwd) : null
583
649
  };
584
- const keyword = positional[0];
585
- const record = await resolveOne(keyword, opts);
650
+ const record = await resolveOne(argv._[0] !== void 0 ? String(argv._[0]) : void 0, opts);
586
651
  if (isPidAlive(record.pid)) {
587
- process.stderr.write(`pid ${record.pid} is still running — stop it first or use cy send\n`);
652
+ process.stderr.write(`pid ${record.pid} is still running — stop it first or use ay send\n`);
588
653
  return 1;
589
654
  }
590
655
  const args = ["--cli=" + record.cli];
@@ -599,18 +664,20 @@ async function cmdRestart(rest) {
599
664
  ]
600
665
  });
601
666
  process.stdout.write(`restarted ${record.cli} in ${shortenPath(record.cwd)} (new pid: ${proc.pid})\n`);
602
- process.stderr.write(`\n cy tail ${proc.pid} # watch output\n cy ls # list all agents\n`);
667
+ process.stderr.write(`\n ay tail ${proc.pid} # watch output\n ay ls # list all agents\n`);
603
668
  return 0;
604
669
  }
605
670
  async function cmdNote(rest) {
606
- const { flags, positional } = parseArgs(rest);
607
- const opts = commonOpts(flags);
608
- const keyword = positional[0];
609
- const note = positional.slice(1).join(" ");
610
- if (!keyword) throw new Error("usage: cy note <keyword> [\"note text\"] (omit text to clear)");
671
+ const argv = await yargs(rest).usage("Usage: ay note <keyword> [\"note text\"]").help(false).version(false).exitProcess(false).parseAsync();
672
+ const keyword = argv._[0] !== void 0 ? String(argv._[0]) : void 0;
673
+ const note = argv._.slice(1).map(String).join(" ");
674
+ if (!keyword) throw new Error("usage: ay note <keyword> [\"note text\"] (omit text to clear)");
611
675
  const record = await resolveOne(keyword, {
612
- ...opts,
613
- all: true
676
+ all: true,
677
+ active: false,
678
+ json: false,
679
+ latest: false,
680
+ cwdScope: null
614
681
  });
615
682
  if (!note) {
616
683
  await writeNote(record.pid, "");
@@ -620,10 +687,101 @@ async function cmdNote(rest) {
620
687
  }
621
688
  await writeNote(record.pid, note);
622
689
  process.stdout.write(`note set for pid ${record.pid}: ${note}\n`);
623
- process.stderr.write(`\n cy ls # see updated note in list\n`);
690
+ process.stderr.write(`\n ay ls # see updated note in list\n`);
691
+ return 0;
692
+ }
693
+ async function snapshotStatus(record) {
694
+ const alive = isPidAlive(record.pid);
695
+ let state;
696
+ let logMtimeMs = null;
697
+ if (!alive) state = "stopped";
698
+ else if (record.log_file) {
699
+ logMtimeMs = await stat(record.log_file).then((s) => s.mtimeMs).catch(() => null);
700
+ state = logMtimeMs !== null && Date.now() - logMtimeMs > IDLE_THRESHOLD_MS ? "idle" : "active";
701
+ } else state = "active";
702
+ const activity = state !== "stopped" && record.log_file ? await extractActivity(record.log_file) : null;
703
+ const note = (await readNotes()).get(record.pid) ?? null;
704
+ return {
705
+ pid: record.pid,
706
+ cli: record.cli,
707
+ cwd: record.cwd,
708
+ state,
709
+ activity,
710
+ note,
711
+ log_mtime_ms: logMtimeMs,
712
+ started_at: record.started_at,
713
+ age_ms: Date.now() - record.started_at,
714
+ exit_code: record.exit_code,
715
+ exit_reason: record.exit_reason,
716
+ log_file: record.log_file ?? null
717
+ };
718
+ }
719
+ async function cmdStatus(rest) {
720
+ const argv = await yargs(rest).usage("Usage: ay status <keyword> [options]").option("watch", {
721
+ alias: "w",
722
+ type: "boolean",
723
+ default: false,
724
+ description: "Stream changes as JSON"
725
+ }).option("interval", {
726
+ type: "number",
727
+ default: 2,
728
+ description: "Poll interval in seconds"
729
+ }).option("latest", {
730
+ type: "boolean",
731
+ default: false,
732
+ description: "Use most recent match"
733
+ }).option("cwd", {
734
+ type: "string",
735
+ description: "Restrict to agents under this dir"
736
+ }).help(false).version(false).exitProcess(false).parseAsync();
737
+ const opts = {
738
+ all: true,
739
+ active: false,
740
+ json: false,
741
+ latest: argv.latest,
742
+ cwdScope: typeof argv.cwd === "string" ? path.resolve(argv.cwd) : null
743
+ };
744
+ const keyword = argv._[0] !== void 0 ? String(argv._[0]) : void 0;
745
+ if (!keyword) throw new Error("usage: ay status <keyword> [--watch] [--interval=N]");
746
+ const watch = argv.watch;
747
+ const intervalFlag = argv.interval;
748
+ const intervalMs = Math.max(500, (Number.isFinite(intervalFlag) ? intervalFlag : 2) * 1e3);
749
+ const record = await resolveOne(keyword, opts);
750
+ const emit = (snap, ts) => {
751
+ const out = ts !== void 0 ? {
752
+ ts,
753
+ ...snap
754
+ } : snap;
755
+ process.stdout.write(JSON.stringify(out) + "\n");
756
+ };
757
+ if (!watch) {
758
+ emit(await snapshotStatus(record));
759
+ return 0;
760
+ }
761
+ process.stderr.write(`watching pid ${record.pid} every ${intervalMs / 1e3}s… (Ctrl-C to stop)\n`);
762
+ let prev = null;
763
+ const tick = async () => {
764
+ const snap = await snapshotStatus(record);
765
+ if (prev === null || snap.state !== prev.state || snap.activity !== prev.activity || snap.exit_code !== prev.exit_code) {
766
+ emit(snap, Date.now());
767
+ prev = {
768
+ state: snap.state,
769
+ activity: snap.activity,
770
+ exit_code: snap.exit_code
771
+ };
772
+ }
773
+ };
774
+ await tick();
775
+ await new Promise((resolve) => {
776
+ const timer = setInterval(tick, intervalMs);
777
+ process.on("SIGINT", () => {
778
+ clearInterval(timer);
779
+ resolve();
780
+ });
781
+ });
624
782
  return 0;
625
783
  }
626
784
 
627
785
  //#endregion
628
786
  export { isSubcommand, runSubcommand };
629
- //# sourceMappingURL=subcommands-Vt_yQiEZ.js.map
787
+ //# sourceMappingURL=subcommands-BwWcA9uo.js.map
@@ -1,7 +1,8 @@
1
1
  import { n as logger, t as addTransport } from "./logger-B9h0djqx.js";
2
- import { r as getInstalledPackage } from "./versionChecker-Ct-4UPeG.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-Cir2ZoFL.js";
3
3
  import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-C22d9SRJ.js";
4
4
  import { t as PidStore } from "./pidStore-C1JXxoPi.js";
5
+ import { r as readGlobalPids } from "./globalPidIndex-Cr-g75QF.js";
5
6
  import { arch, platform } from "process";
6
7
  import { execSync } from "child_process";
7
8
  import { closeSync, constants, createReadStream, existsSync, mkdirSync, openSync } from "fs";
@@ -1062,7 +1063,7 @@ const CLIS_CONFIG = config.clis;
1062
1063
  * });
1063
1064
  * ```
1064
1065
  */
1065
- 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, idleAction }) {
1066
+ 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, idleAction, swarmHint = true }) {
1066
1067
  if (!cli) throw new Error(`cli is required`);
1067
1068
  const conf = CLIS_CONFIG[cli] || DIE(`Unsupported cli tool: ${cli}, current process.argv: ${process.argv.join(" ")}`);
1068
1069
  const workingDir = cwd ?? process.cwd();
@@ -1139,6 +1140,18 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
1139
1140
  } catch (error) {
1140
1141
  if (verbose) logger.warn("[skills] Failed to inject SKILL.md header:", { error });
1141
1142
  }
1143
+ if (swarmHint) try {
1144
+ const peers = await readGlobalPids({ liveOnly: true });
1145
+ if (peers.length > 0) {
1146
+ const hint = `${peers.length} peer agent${peers.length > 1 ? "s are" : " is"} running. Before asking the user for input on any domain-specific topic (design, testing, architecture, etc.), check for relevant peers first: \`ay ls --json\` (see \`prompt\` field for their role). Ask one: \`ay send <pid> <question>\`. Read reply: \`ay tail <pid>\`. Do not use interactive forms or user prompts when a peer can answer.`;
1147
+ if (cli === "claude") cliArgs = [
1148
+ "--append-system-prompt",
1149
+ hint,
1150
+ ...cliArgs
1151
+ ];
1152
+ prompt = prompt ? `[${hint}]\n\n${prompt}` : hint;
1153
+ }
1154
+ } catch {}
1142
1155
  if (resume) if (cli === "codex" && resume) {
1143
1156
  const storedSessionId = await getSessionForCwd(workingDir);
1144
1157
  if (storedSessionId) {
@@ -1171,6 +1184,7 @@ async function agentYes({ cli, cliArgs = [], prompt, robust = true, cwd, env, ex
1171
1184
  prompt = void 0;
1172
1185
  } else logger.warn(`Unknown promptArg format: ${cliConf.promptArg}`);
1173
1186
  const ptyEnv = { ...env ?? process.env };
1187
+ ptyEnv.AGENT_YES_PID = String(process.pid);
1174
1188
  const ptyOptions = {
1175
1189
  name: "xterm-color",
1176
1190
  ...getTerminalDimensions(),
@@ -1679,4 +1693,4 @@ function sleep(ms) {
1679
1693
 
1680
1694
  //#endregion
1681
1695
  export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
1682
- //# sourceMappingURL=ts-DbdWuoGq.js.map
1696
+ //# sourceMappingURL=ts-BTCVz_nZ.js.map
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
7
7
 
8
8
  //#region package.json
9
9
  var name = "claude-yes";
10
- var version = "1.83.0";
10
+ var version = "1.85.0";
11
11
 
12
12
  //#endregion
13
13
  //#region ts/versionChecker.ts
@@ -221,4 +221,4 @@ async function displayVersion() {
221
221
 
222
222
  //#endregion
223
223
  export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
224
- //# sourceMappingURL=versionChecker-Ct-4UPeG.js.map
224
+ //# sourceMappingURL=versionChecker-Cir2ZoFL.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-yes",
3
- "version": "1.83.0",
3
+ "version": "1.85.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",