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.
- package/dist/{SUPPORTED_CLIS-DkXclUge.js → SUPPORTED_CLIS-DnCV2Fj1.js} +3 -3
- package/dist/cli.js +8 -3
- package/dist/index.js +2 -2
- package/dist/{subcommands-Vt_yQiEZ.js → subcommands-BwWcA9uo.js} +257 -99
- package/dist/{ts-DbdWuoGq.js → ts-BTCVz_nZ.js} +17 -3
- package/dist/{versionChecker-Ct-4UPeG.js → versionChecker-Cir2ZoFL.js} +2 -2
- package/package.json +1 -1
- package/ts/index.ts +21 -0
- package/ts/parseCliArgs.ts +7 -0
- package/ts/subcommands.spec.ts +478 -35
- package/ts/subcommands.ts +348 -129
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { t as CLIS_CONFIG } from "./ts-BTCVz_nZ.js";
|
|
2
2
|
import "./logger-B9h0djqx.js";
|
|
3
|
-
import "./versionChecker-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
* `
|
|
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 `
|
|
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(`
|
|
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
|
|
243
|
-
|
|
244
|
-
|
|
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
|
|
281
|
-
else label = truncate(r.prompt
|
|
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(`
|
|
316
|
-
hints.push(`
|
|
317
|
-
hints.push(`
|
|
318
|
-
hints.push(`
|
|
319
|
-
hints.push(`
|
|
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(`
|
|
322
|
-
if (!alive && !stopped) hints.push(`
|
|
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
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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
|
-
|
|
396
|
-
|
|
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
|
|
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
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
-
|
|
517
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
582
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
607
|
-
const
|
|
608
|
-
const
|
|
609
|
-
|
|
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
|
-
|
|
613
|
-
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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-
|
|
224
|
+
//# sourceMappingURL=versionChecker-Cir2ZoFL.js.map
|
package/package.json
CHANGED