agent-yes 1.225.0 → 1.226.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-ldWdY2jy.js → SUPPORTED_CLIS-Cn3T86CJ.js} +3 -3
- package/dist/{SUPPORTED_CLIS-nDMA0vtp.js → SUPPORTED_CLIS-Cnig_ONj.js} +2 -2
- package/dist/{agentShare-BLl0-SpO.js → agentShare-Cue9mqvJ.js} +3 -3
- package/dist/{callback-CCZfvMHZ.js → callback-DyJC_81s.js} +3 -3
- package/dist/{callback-CuWuj9gy.js → callback-Lsz9mZiC.js} +3 -3
- package/dist/cli.js +12 -8
- package/dist/cwdConflictWarn-CnxkLs7T.js +64 -0
- package/dist/{expose-CGpMiQxp.js → expose-CKWXAkzK.js} +1 -1
- package/dist/{forkNested-BLa3Mz_t.js → forkNested-DJ2QzBsc.js} +1 -1
- package/dist/index.js +2 -2
- package/dist/{nodeRuntime-DoBOoeUW.js → nodeRuntime-CR0NwnnO.js} +1 -1
- package/dist/{notifyDaemon-DF7_EjVu.js → notifyDaemon-BoE83_av.js} +3 -3
- package/dist/{openBrowser-D_qKXZNj.js → openBrowser-D9VVE6cq.js} +1 -1
- package/dist/{remotes-D-jPl9Fj.js → remotes-BtXom7Rp.js} +2 -2
- package/dist/{remotes-C_YlVvr9.js → remotes-DZ_G2wkM.js} +1 -1
- package/dist/{rustBinary-DsKB37nM.js → rustBinary-BHXs5BZD.js} +2 -2
- package/dist/{schedule-KFStEXIX.js → schedule-Dd26IiBu.js} +6 -6
- package/dist/{serve-BBrh1z4b.js → serve-CC1SbBXS.js} +22 -22
- package/dist/{setup-DvP49xV5.js → setup-Cz9t2H2g.js} +3 -3
- package/dist/{spawnGate-nUBaOXoG.js → spawnGate-CfcpmQmk.js} +1 -1
- package/dist/{spawnGate-Vmd1d9OQ.js → spawnGate-ChYCj6Dm.js} +2 -2
- package/dist/{subcommands-T3C9EhOr.js → subcommands-Clrx40Id.js} +22 -14
- package/dist/{subcommands-DMoKYWpB.js → subcommands-PPDhW0bB.js} +2 -2
- package/dist/{todoCli-dk8WNgcS.js → todoCli-D8bL164c.js} +1 -1
- package/dist/{tray-CIm-5aWB.js → tray-BZqJtEmL.js} +1 -1
- package/dist/{ts-BPtf-Tpg.js → ts-C27ZwDyZ.js} +2 -2
- package/dist/{versionChecker-defO9ozI.js → versionChecker-B5TdNLCF.js} +2 -2
- package/dist/{webrtcRemote-CWogO7Qa.js → webrtcRemote-C974zjSt.js} +1 -1
- package/dist/{workspaceConfig-dHHBQh0F.js → workspaceConfig-BRl-GwSN.js} +1 -1
- package/dist/{ws-DLkxWjt9.js → ws-D9H2UXCC.js} +4 -4
- package/package.json +1 -1
- package/ts/cli.ts +9 -0
- package/ts/cwdConflictWarn.spec.ts +60 -0
- package/ts/cwdConflictWarn.ts +97 -0
- package/ts/subcommands.spec.ts +12 -0
- package/ts/subcommands.ts +27 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import "./ts-
|
|
1
|
+
import "./ts-C27ZwDyZ.js";
|
|
2
2
|
import "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import "./versionChecker-
|
|
3
|
+
import "./versionChecker-B5TdNLCF.js";
|
|
4
4
|
import "./JsonlStore-Bm5Nj6v_.js";
|
|
5
5
|
import "./globalPidIndex-CoNr7tS8.js";
|
|
6
6
|
import "./pidStore-DCqpU_bI.js";
|
|
7
7
|
import "./messageLog-Bb_Ie3Ck.js";
|
|
8
8
|
import "./todoAutomation-fxtfT_44.js";
|
|
9
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
9
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-Cnig_ONj.js";
|
|
10
10
|
|
|
11
11
|
export { SUPPORTED_CLIS };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { t as CLIS_CONFIG } from "./ts-C27ZwDyZ.js";
|
|
2
2
|
|
|
3
3
|
//#region ts/SUPPORTED_CLIS.ts
|
|
4
4
|
const SUPPORTED_CLIS = Object.keys(CLIS_CONFIG);
|
|
5
5
|
|
|
6
6
|
//#endregion
|
|
7
7
|
export { SUPPORTED_CLIS as t };
|
|
8
|
-
//# sourceMappingURL=SUPPORTED_CLIS-
|
|
8
|
+
//# sourceMappingURL=SUPPORTED_CLIS-Cnig_ONj.js.map
|
|
@@ -2,10 +2,10 @@ import "./logger-CDIsZ-Pp.js";
|
|
|
2
2
|
import "./globalPidIndex-CoNr7tS8.js";
|
|
3
3
|
import "./messageLog-Bb_Ie3Ck.js";
|
|
4
4
|
import "./configShared-nnIwDYY-.js";
|
|
5
|
-
import { M as resolveOne } from "./subcommands-
|
|
5
|
+
import { M as resolveOne } from "./subcommands-Clrx40Id.js";
|
|
6
6
|
import "./e2e-D5jaSHyY.js";
|
|
7
7
|
import "./webrtcLink-DknpJQ0y.js";
|
|
8
|
-
import "./remotes-
|
|
8
|
+
import "./remotes-BtXom7Rp.js";
|
|
9
9
|
import { r as startShare } from "./share-BwEUEHfy.js";
|
|
10
10
|
|
|
11
11
|
//#region ts/agentShare.ts
|
|
@@ -229,4 +229,4 @@ function transformEvent(rawEvent, agentId, forwarded) {
|
|
|
229
229
|
|
|
230
230
|
//#endregion
|
|
231
231
|
export { createScopedShare, listShares, revokeAllShares, revokeShare };
|
|
232
|
-
//# sourceMappingURL=agentShare-
|
|
232
|
+
//# sourceMappingURL=agentShare-Cue9mqvJ.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
|
|
2
|
-
import { M as resolveOne } from "./subcommands-
|
|
2
|
+
import { M as resolveOne } from "./subcommands-Clrx40Id.js";
|
|
3
3
|
import { a as mintCapability, o as parseExpires } from "./callbackCore-CgnOT1Cp.js";
|
|
4
4
|
import { randomBytes } from "node:crypto";
|
|
5
5
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
@@ -72,7 +72,7 @@ async function resolveBase(flag) {
|
|
|
72
72
|
if (flag) return flag;
|
|
73
73
|
if (process.env.AGENT_YES_CALLBACK_BASE) return process.env.AGENT_YES_CALLBACK_BASE;
|
|
74
74
|
try {
|
|
75
|
-
const { resolveLocalServeUrl } = await import("./serve-
|
|
75
|
+
const { resolveLocalServeUrl } = await import("./serve-CC1SbBXS.js");
|
|
76
76
|
const url = await resolveLocalServeUrl();
|
|
77
77
|
if (url) return url;
|
|
78
78
|
} catch {}
|
|
@@ -187,4 +187,4 @@ async function cmdCallback(rest) {
|
|
|
187
187
|
|
|
188
188
|
//#endregion
|
|
189
189
|
export { loadOrCreateCallbackSecret as i, isCallbackRevoked as n, loadCallbackSecretReadOnly as r, cmdCallback as t };
|
|
190
|
-
//# sourceMappingURL=callback-
|
|
190
|
+
//# sourceMappingURL=callback-DyJC_81s.js.map
|
|
@@ -2,11 +2,11 @@ import "./logger-CDIsZ-Pp.js";
|
|
|
2
2
|
import "./globalPidIndex-CoNr7tS8.js";
|
|
3
3
|
import "./messageLog-Bb_Ie3Ck.js";
|
|
4
4
|
import "./configShared-nnIwDYY-.js";
|
|
5
|
-
import "./subcommands-
|
|
5
|
+
import "./subcommands-Clrx40Id.js";
|
|
6
6
|
import "./e2e-D5jaSHyY.js";
|
|
7
7
|
import "./webrtcLink-DknpJQ0y.js";
|
|
8
|
-
import "./remotes-
|
|
8
|
+
import "./remotes-BtXom7Rp.js";
|
|
9
9
|
import "./callbackCore-CgnOT1Cp.js";
|
|
10
|
-
import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-
|
|
10
|
+
import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-DyJC_81s.js";
|
|
11
11
|
|
|
12
12
|
export { cmdCallback };
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { t as invokedCliName } from "./invokedCli-uqM2YYA7.js";
|
|
3
3
|
import { n as logger } from "./logger-CDIsZ-Pp.js";
|
|
4
|
-
import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-
|
|
5
|
-
import { n as getRustBinary } from "./rustBinary-
|
|
4
|
+
import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-B5TdNLCF.js";
|
|
5
|
+
import { n as getRustBinary } from "./rustBinary-BHXs5BZD.js";
|
|
6
6
|
import { argv } from "process";
|
|
7
7
|
import { spawn } from "child_process";
|
|
8
8
|
import ms from "ms";
|
|
@@ -285,7 +285,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
|
|
|
285
285
|
const rawArg = process.argv[2];
|
|
286
286
|
const managerCommands = !invokedCliName(process.argv);
|
|
287
287
|
const isHelpFlag = rawArg === "-h" || rawArg === "--help";
|
|
288
|
-
const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-
|
|
288
|
+
const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-PPDhW0bB.js");
|
|
289
289
|
if (isHelpFlag && process.argv.length === 3) {
|
|
290
290
|
await cmdHelp(managerCommands);
|
|
291
291
|
process.exit(0);
|
|
@@ -299,16 +299,16 @@ await checkAndAutoUpdate();
|
|
|
299
299
|
logger.info(versionString());
|
|
300
300
|
const config = parseCliArgs(process.argv);
|
|
301
301
|
if (config.tray) {
|
|
302
|
-
const { startTray } = await import("./tray-
|
|
302
|
+
const { startTray } = await import("./tray-BZqJtEmL.js");
|
|
303
303
|
await startTray();
|
|
304
304
|
await new Promise(() => {});
|
|
305
305
|
}
|
|
306
306
|
{
|
|
307
|
-
const { ensureTray } = await import("./tray-
|
|
307
|
+
const { ensureTray } = await import("./tray-BZqJtEmL.js");
|
|
308
308
|
ensureTray();
|
|
309
309
|
}
|
|
310
310
|
if (!config.showVersion && !config.appendPrompt && !config.tray) {
|
|
311
|
-
const { waitForSpawnCapacity } = await import("./spawnGate-
|
|
311
|
+
const { waitForSpawnCapacity } = await import("./spawnGate-CfcpmQmk.js");
|
|
312
312
|
await waitForSpawnCapacity({
|
|
313
313
|
onWait: (reason, waitedMs) => {
|
|
314
314
|
if (config.verbose || waitedMs === 0) console.error(`[agent-yes] spawn gate: ${reason} — waiting…`);
|
|
@@ -316,6 +316,10 @@ if (!config.showVersion && !config.appendPrompt && !config.tray) {
|
|
|
316
316
|
onProceedAnyway: (reason, waitedMs) => console.error(`[agent-yes] spawn gate: ${reason} — waited ${Math.round(waitedMs / 1e3)}s, proceeding anyway`)
|
|
317
317
|
});
|
|
318
318
|
}
|
|
319
|
+
if (!config.showVersion && !config.appendPrompt && !config.tray) {
|
|
320
|
+
const { warnIfCwdOccupied } = await import("./cwdConflictWarn-CnxkLs7T.js");
|
|
321
|
+
await warnIfCwdOccupied(process.argv);
|
|
322
|
+
}
|
|
319
323
|
if (config.useRust) {
|
|
320
324
|
let rustBinary;
|
|
321
325
|
try {
|
|
@@ -327,14 +331,14 @@ if (config.useRust) {
|
|
|
327
331
|
}
|
|
328
332
|
}
|
|
329
333
|
if (rustBinary) {
|
|
330
|
-
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-
|
|
334
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-Cn3T86CJ.js");
|
|
331
335
|
const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
|
|
332
336
|
if (config.verbose) {
|
|
333
337
|
console.log(`[rust] Using binary: ${rustBinary}`);
|
|
334
338
|
console.log(`[rust] Args: ${rustArgs.join(" ")}`);
|
|
335
339
|
}
|
|
336
340
|
const attach = config.attach || process.env.AGENT_YES_ATTACH === "1";
|
|
337
|
-
const { shouldForkNested, buildSpawnTutorial, waitForFifo } = await import("./forkNested-
|
|
341
|
+
const { shouldForkNested, buildSpawnTutorial, waitForFifo } = await import("./forkNested-DJ2QzBsc.js");
|
|
338
342
|
if (shouldForkNested({
|
|
339
343
|
isTTY: Boolean(process.stdout.isTTY),
|
|
340
344
|
ayPid: process.env.AGENT_YES_PID,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import "./logger-CDIsZ-Pp.js";
|
|
2
|
+
import { i as readGlobalPids } from "./globalPidIndex-CoNr7tS8.js";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
//#region ts/cwdConflictWarn.ts
|
|
6
|
+
/**
|
|
7
|
+
* Pre-launch warning: another live agent is already working in THIS exact
|
|
8
|
+
* directory. Two agents sharing one working tree clobber each other's edits,
|
|
9
|
+
* builds, and dev-server ports — so we warn (stderr, non-fatal) and hand the
|
|
10
|
+
* user a copy-pasteable git-worktree isolation command.
|
|
11
|
+
*
|
|
12
|
+
* Lives in cli.ts's launch path (before the --rust dispatch) so it covers BOTH
|
|
13
|
+
* the Rust and TypeScript runtimes with one check. The launching agent isn't
|
|
14
|
+
* registered in the pid index yet, so every same-cwd match here is a genuine
|
|
15
|
+
* pre-existing peer, never itself.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* POSIX single-quote a shell token so a copy-pasted recovery command survives
|
|
19
|
+
* spaces, quotes, `$`, `;`, `&`, etc. Safe-charset tokens pass through unquoted
|
|
20
|
+
* so the common case (`ay claude -- fix`) stays readable. Empty string → `''`.
|
|
21
|
+
*/
|
|
22
|
+
function shQuote(s) {
|
|
23
|
+
if (s === "") return "''";
|
|
24
|
+
if (/^[A-Za-z0-9,._+@%/:=-]+$/.test(s)) return s;
|
|
25
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Pure renderer — given the peers already in `cwd`, the cwd, and the original
|
|
29
|
+
* `ay …` command, produce the warning text (or null when there's no conflict).
|
|
30
|
+
* Separated from IO so the message/branching is unit-tested without a live index.
|
|
31
|
+
*/
|
|
32
|
+
function formatCwdConflictWarning(occupants, cwd, origCmd) {
|
|
33
|
+
if (occupants.length === 0) return null;
|
|
34
|
+
const wt = `${path.basename(cwd) || "agent"}-work`;
|
|
35
|
+
const list = occupants.slice(0, 3).map((r) => ` ${r.pid} ${r.cli}`).join("\n");
|
|
36
|
+
const more = occupants.length > 3 ? `\n …and ${occupants.length - 3} more` : "";
|
|
37
|
+
const cmd = origCmd.trim() || "ay <cli> …";
|
|
38
|
+
const branch = shQuote(wt);
|
|
39
|
+
const dir = shQuote(`../${wt}`);
|
|
40
|
+
return `\n⚠ ${occupants.length} agent${occupants.length > 1 ? "s are" : " is"} already running in this directory (${cwd}):\n${list}${more}\n Parallel agents in one working tree clobber each other's files, builds, and ports.\n To isolate this run in its own git worktree, cancel (Ctrl-C) and instead:\n git worktree add -b ${branch} ${dir} && cd ${dir} && ${cmd}\n (set AGENT_YES_NO_CWD_WARN=1 to silence)\n\n`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* IO wrapper: discover live same-cwd peers and print the warning to stderr.
|
|
44
|
+
* Best-effort and swallow-all — a discovery hiccup must NEVER block a launch.
|
|
45
|
+
* No-op when AGENT_YES_NO_CWD_WARN=1.
|
|
46
|
+
*/
|
|
47
|
+
async function warnIfCwdOccupied(rawArgv) {
|
|
48
|
+
if (process.env.AGENT_YES_NO_CWD_WARN === "1") return;
|
|
49
|
+
try {
|
|
50
|
+
const here = path.resolve(process.cwd());
|
|
51
|
+
const msg = formatCwdConflictWarning((await readGlobalPids({ liveOnly: true })).filter((r) => path.resolve(r.cwd) === here).map((r) => ({
|
|
52
|
+
pid: r.pid,
|
|
53
|
+
cli: r.cli
|
|
54
|
+
})), here, ["ay", ...rawArgv.slice(2)].map(shQuote).join(" "));
|
|
55
|
+
if (msg) {
|
|
56
|
+
process.stderr.write(msg);
|
|
57
|
+
if (process.stdout.isTTY) await new Promise((r) => setTimeout(r, 2500));
|
|
58
|
+
}
|
|
59
|
+
} catch {}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
export { warnIfCwdOccupied };
|
|
64
|
+
//# sourceMappingURL=cwdConflictWarn-CnxkLs7T.js.map
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { i as AgentContext, n as agentYes, o as removeControlCharacters, r as config, t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { i as AgentContext, n as agentYes, o as removeControlCharacters, r as config, t as CLIS_CONFIG } from "./ts-C27ZwDyZ.js";
|
|
2
2
|
import "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import "./versionChecker-
|
|
3
|
+
import "./versionChecker-B5TdNLCF.js";
|
|
4
4
|
import "./JsonlStore-Bm5Nj6v_.js";
|
|
5
5
|
import "./globalPidIndex-CoNr7tS8.js";
|
|
6
6
|
import "./pidStore-DCqpU_bI.js";
|
|
@@ -2,10 +2,10 @@ import { n as logger } from "./logger-CDIsZ-Pp.js";
|
|
|
2
2
|
import "./globalPidIndex-CoNr7tS8.js";
|
|
3
3
|
import "./messageLog-Bb_Ie3Ck.js";
|
|
4
4
|
import "./configShared-nnIwDYY-.js";
|
|
5
|
-
import { $ as daemonLockOwnerPath, G as gcInboxes, J as listInboxParents, K as hostId, Q as daemonLockDir, S as listRecords, W as appendEvent, X as readInbox, Y as liveWatchers, Z as shouldStealLock, _ as isPidAlive, c as deriveLiveState, et as notifyDir, k as renderLogTailLines } from "./subcommands-
|
|
5
|
+
import { $ as daemonLockOwnerPath, G as gcInboxes, J as listInboxParents, K as hostId, Q as daemonLockDir, S as listRecords, W as appendEvent, X as readInbox, Y as liveWatchers, Z as shouldStealLock, _ as isPidAlive, c as deriveLiveState, et as notifyDir, k as renderLogTailLines } from "./subcommands-Clrx40Id.js";
|
|
6
6
|
import "./e2e-D5jaSHyY.js";
|
|
7
7
|
import "./webrtcLink-DknpJQ0y.js";
|
|
8
|
-
import "./remotes-
|
|
8
|
+
import "./remotes-BtXom7Rp.js";
|
|
9
9
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
11
|
import { execFile } from "node:child_process";
|
|
@@ -589,4 +589,4 @@ async function ensureDaemon() {
|
|
|
589
589
|
|
|
590
590
|
//#endregion
|
|
591
591
|
export { daemonStatus, ensureDaemon, requestDaemonStop, runDaemon };
|
|
592
|
-
//# sourceMappingURL=notifyDaemon-
|
|
592
|
+
//# sourceMappingURL=notifyDaemon-BoE83_av.js.map
|
|
@@ -86,7 +86,7 @@ async function resolveRemoteSpec(spec) {
|
|
|
86
86
|
* The bridge lives for the rest of the process (torn down on `process.exit`).
|
|
87
87
|
*/
|
|
88
88
|
async function resolveWebrtc(link, keyword) {
|
|
89
|
-
const { startWebrtcBridge } = await import("./webrtcRemote-
|
|
89
|
+
const { startWebrtcBridge } = await import("./webrtcRemote-C974zjSt.js");
|
|
90
90
|
const bridge = await startWebrtcBridge(link);
|
|
91
91
|
return {
|
|
92
92
|
url: bridge.baseUrl,
|
|
@@ -173,4 +173,4 @@ async function cmdRemote(rest) {
|
|
|
173
173
|
|
|
174
174
|
//#endregion
|
|
175
175
|
export { resolveRemoteSpec as a, readRemotes as i, deleteRemoteAlias as n, writeRemoteAlias as o, parseDirectRemoteSpec as r, cmdRemote as t };
|
|
176
|
-
//# sourceMappingURL=remotes-
|
|
176
|
+
//# sourceMappingURL=remotes-BtXom7Rp.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./e2e-D5jaSHyY.js";
|
|
2
2
|
import "./webrtcLink-DknpJQ0y.js";
|
|
3
|
-
import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-
|
|
3
|
+
import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-BtXom7Rp.js";
|
|
4
4
|
|
|
5
5
|
export { cmdRemote };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
1
|
+
import { r as getInstalledPackage } from "./versionChecker-B5TdNLCF.js";
|
|
2
2
|
import { execFileSync } from "child_process";
|
|
3
3
|
import { existsSync, mkdirSync, unlinkSync } from "fs";
|
|
4
4
|
import { chmod, copyFile } from "fs/promises";
|
|
@@ -225,4 +225,4 @@ async function getRustBinary(options = {}) {
|
|
|
225
225
|
|
|
226
226
|
//#endregion
|
|
227
227
|
export { getRustBinary as n, findSpawnHiddenLauncher as t };
|
|
228
|
-
//# sourceMappingURL=rustBinary-
|
|
228
|
+
//# sourceMappingURL=rustBinary-BHXs5BZD.js.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import "./ts-
|
|
1
|
+
import "./ts-C27ZwDyZ.js";
|
|
2
2
|
import "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import "./versionChecker-
|
|
3
|
+
import "./versionChecker-B5TdNLCF.js";
|
|
4
4
|
import "./JsonlStore-Bm5Nj6v_.js";
|
|
5
5
|
import "./globalPidIndex-CoNr7tS8.js";
|
|
6
6
|
import "./pidStore-DCqpU_bI.js";
|
|
7
7
|
import "./messageLog-Bb_Ie3Ck.js";
|
|
8
8
|
import "./todoAutomation-fxtfT_44.js";
|
|
9
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
10
|
-
import { d as resolveSpawnCwd } from "./workspaceConfig-
|
|
11
|
-
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-
|
|
9
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-Cnig_ONj.js";
|
|
10
|
+
import { d as resolveSpawnCwd } from "./workspaceConfig-BRl-GwSN.js";
|
|
11
|
+
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-CR0NwnnO.js";
|
|
12
12
|
import { createHash } from "node:crypto";
|
|
13
13
|
|
|
14
14
|
//#region ts/oxmgrService.ts
|
|
@@ -153,4 +153,4 @@ async function cmdSchedule(rest) {
|
|
|
153
153
|
|
|
154
154
|
//#endregion
|
|
155
155
|
export { cmdSchedule };
|
|
156
|
-
//# sourceMappingURL=schedule-
|
|
156
|
+
//# sourceMappingURL=schedule-Dd26IiBu.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as CLAUDE_SESSION_PIN_ENV } from "./ts-
|
|
1
|
+
import { a as CLAUDE_SESSION_PIN_ENV } from "./ts-C27ZwDyZ.js";
|
|
2
2
|
import "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
4
|
-
import { t as findSpawnHiddenLauncher } from "./rustBinary-
|
|
3
|
+
import { r as getInstalledPackage } from "./versionChecker-B5TdNLCF.js";
|
|
4
|
+
import { t as findSpawnHiddenLauncher } from "./rustBinary-BHXs5BZD.js";
|
|
5
5
|
import { t as agentYesHome$1 } from "./agentYesHome-CtHb5b71.js";
|
|
6
6
|
import "./JsonlStore-Bm5Nj6v_.js";
|
|
7
7
|
import { a as updateGlobalPidStatus } from "./globalPidIndex-CoNr7tS8.js";
|
|
@@ -10,16 +10,16 @@ import { r as recordInbox } from "./messageLog-Bb_Ie3Ck.js";
|
|
|
10
10
|
import { t as pgidForWrapper } from "./reaper-BNKvujYy.js";
|
|
11
11
|
import "./todoAutomation-fxtfT_44.js";
|
|
12
12
|
import "./configShared-nnIwDYY-.js";
|
|
13
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
14
|
-
import { A as renderRawLog, D as recentMessageEdges, E as readPtysize, L as snapshotStatus, M as resolveOne, O as recentReadEdges, S as listRecords, T as readNotes, U as writeToIpc, b as isUserTyping, f as extractNeedsInput, j as renderRawLogLines, k as renderLogTailLines, l as deriveLiveStatus, o as controlCodeFromName, p as extractTaskCounts, q as isTransientLockMkdirError, tt as TYPING_BADGE, u as extractBadges } from "./subcommands-
|
|
13
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-Cnig_ONj.js";
|
|
14
|
+
import { A as renderRawLog, D as recentMessageEdges, E as readPtysize, L as snapshotStatus, M as resolveOne, O as recentReadEdges, S as listRecords, T as readNotes, U as writeToIpc, b as isUserTyping, f as extractNeedsInput, j as renderRawLogLines, k as renderLogTailLines, l as deriveLiveStatus, o as controlCodeFromName, p as extractTaskCounts, q as isTransientLockMkdirError, tt as TYPING_BADGE, u as extractBadges } from "./subcommands-Clrx40Id.js";
|
|
15
15
|
import "./e2e-D5jaSHyY.js";
|
|
16
16
|
import "./webrtcLink-DknpJQ0y.js";
|
|
17
|
-
import "./remotes-
|
|
17
|
+
import "./remotes-BtXom7Rp.js";
|
|
18
18
|
import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-CgnOT1Cp.js";
|
|
19
|
-
import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-
|
|
20
|
-
import { a as getSpawnHook, c as hasProvisionHook, d as resolveSpawnCwd, i as getProvisionRoot, l as hasSpawnHook, r as getProvisionHook, u as isProvisionAllowed } from "./workspaceConfig-
|
|
21
|
-
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-
|
|
22
|
-
import { r as spawnRejectionReason } from "./spawnGate-
|
|
19
|
+
import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-DyJC_81s.js";
|
|
20
|
+
import { a as getSpawnHook, c as hasProvisionHook, d as resolveSpawnCwd, i as getProvisionRoot, l as hasSpawnHook, r as getProvisionHook, u as isProvisionAllowed } from "./workspaceConfig-BRl-GwSN.js";
|
|
21
|
+
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-CR0NwnnO.js";
|
|
22
|
+
import { r as spawnRejectionReason } from "./spawnGate-ChYCj6Dm.js";
|
|
23
23
|
import yargs from "yargs";
|
|
24
24
|
import { appendFile, mkdir, open, readFile, rename, rm, stat, unlink, writeFile } from "fs/promises";
|
|
25
25
|
import { arch, cpus, freemem, homedir, hostname, loadavg, platform, totalmem, uptime, userInfo } from "os";
|
|
@@ -952,7 +952,7 @@ async function cmdServeDaemon(sub, args) {
|
|
|
952
952
|
if (!webrtcDaemon) return;
|
|
953
953
|
if (shareLink) {
|
|
954
954
|
process.stdout.write(`\nshared over WebRTC — open this link (the token is eaten from the URL on open):\n ${shareLink}\n` + (shareLinkMinted ? ` (persistent room — same link across restarts; delete ~/.agent-yes/.share-room to rotate)\n` : ``));
|
|
955
|
-
const { offerOpenInBrowser } = await import("./openBrowser-
|
|
955
|
+
const { offerOpenInBrowser } = await import("./openBrowser-D9VVE6cq.js");
|
|
956
956
|
await offerOpenInBrowser(shareLink);
|
|
957
957
|
} else process.stdout.write("\nthe WebRTC share link carries a secret, so the daemon does NOT log it —\nread it from ~/.agent-yes/.share-link (mode 0600). The room persists in\n~/.agent-yes/.share-room, so the link survives restarts.\n");
|
|
958
958
|
};
|
|
@@ -1992,7 +1992,7 @@ Options:
|
|
|
1992
1992
|
}
|
|
1993
1993
|
});
|
|
1994
1994
|
if (req.method === "GET" && p === "/api/ws") {
|
|
1995
|
-
const ws = await import("./ws-
|
|
1995
|
+
const ws = await import("./ws-D9H2UXCC.js");
|
|
1996
1996
|
try {
|
|
1997
1997
|
await ws.loadProvision();
|
|
1998
1998
|
} catch (e) {
|
|
@@ -2012,7 +2012,7 @@ Options:
|
|
|
2012
2012
|
if (req.method === "GET" && p === "/api/ws/status") {
|
|
2013
2013
|
const dirRaw = url.searchParams.get("path");
|
|
2014
2014
|
if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
|
|
2015
|
-
const ws = await import("./ws-
|
|
2015
|
+
const ws = await import("./ws-D9H2UXCC.js");
|
|
2016
2016
|
let prov;
|
|
2017
2017
|
try {
|
|
2018
2018
|
prov = await ws.loadProvision();
|
|
@@ -2601,7 +2601,7 @@ Options:
|
|
|
2601
2601
|
const perm = body.perm ?? "r";
|
|
2602
2602
|
if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
|
|
2603
2603
|
try {
|
|
2604
|
-
const { createScopedShare } = await import("./agentShare-
|
|
2604
|
+
const { createScopedShare } = await import("./agentShare-Cue9mqvJ.js");
|
|
2605
2605
|
const share = await createScopedShare({
|
|
2606
2606
|
agent: body.agent,
|
|
2607
2607
|
perm,
|
|
@@ -2616,12 +2616,12 @@ Options:
|
|
|
2616
2616
|
}
|
|
2617
2617
|
}
|
|
2618
2618
|
if (req.method === "GET" && p === "/api/shares") {
|
|
2619
|
-
const { listShares } = await import("./agentShare-
|
|
2619
|
+
const { listShares } = await import("./agentShare-Cue9mqvJ.js");
|
|
2620
2620
|
return Response.json(listShares());
|
|
2621
2621
|
}
|
|
2622
2622
|
const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
|
|
2623
2623
|
if (req.method === "DELETE" && revokeM) {
|
|
2624
|
-
const { revokeShare } = await import("./agentShare-
|
|
2624
|
+
const { revokeShare } = await import("./agentShare-Cue9mqvJ.js");
|
|
2625
2625
|
const ok = revokeShare(decodeURIComponent(revokeM[1]));
|
|
2626
2626
|
return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
|
|
2627
2627
|
}
|
|
@@ -2635,7 +2635,7 @@ Options:
|
|
|
2635
2635
|
const port = Number(body.port);
|
|
2636
2636
|
if (!Number.isInteger(port) || port < 1 || port > 65535) return new Response("valid port required", { status: 400 });
|
|
2637
2637
|
try {
|
|
2638
|
-
const { ensureExposure } = await import("./expose-
|
|
2638
|
+
const { ensureExposure } = await import("./expose-CKWXAkzK.js");
|
|
2639
2639
|
const h = await ensureExposure(port, body.relay);
|
|
2640
2640
|
return Response.json({
|
|
2641
2641
|
id: h.id,
|
|
@@ -2649,12 +2649,12 @@ Options:
|
|
|
2649
2649
|
}
|
|
2650
2650
|
}
|
|
2651
2651
|
if (req.method === "GET" && p === "/api/exposes") {
|
|
2652
|
-
const { listExposures } = await import("./expose-
|
|
2652
|
+
const { listExposures } = await import("./expose-CKWXAkzK.js");
|
|
2653
2653
|
return Response.json(listExposures());
|
|
2654
2654
|
}
|
|
2655
2655
|
const unexposeM = /^\/api\/expose\/(\d+)$/.exec(p);
|
|
2656
2656
|
if (req.method === "DELETE" && unexposeM) {
|
|
2657
|
-
const { stopExposure } = await import("./expose-
|
|
2657
|
+
const { stopExposure } = await import("./expose-CKWXAkzK.js");
|
|
2658
2658
|
const ok = stopExposure(Number(unexposeM[1]));
|
|
2659
2659
|
return new Response(ok ? "revoked" : "no such exposure", { status: ok ? 200 : 404 });
|
|
2660
2660
|
}
|
|
@@ -2881,7 +2881,7 @@ Options:
|
|
|
2881
2881
|
const persistNote = explicitUrl ? "\n" : ` (persistent room — same link across restarts; delete ~/.agent-yes/.share-room to rotate)\n\n`;
|
|
2882
2882
|
process.stdout.write(`${wantHttp ? "\n" : ""}${lead}:\n ${link}\n` + persistNote);
|
|
2883
2883
|
if (!rotated) {
|
|
2884
|
-
const { offerOpenInBrowser } = await import("./openBrowser-
|
|
2884
|
+
const { offerOpenInBrowser } = await import("./openBrowser-D9VVE6cq.js");
|
|
2885
2885
|
await offerOpenInBrowser(link);
|
|
2886
2886
|
}
|
|
2887
2887
|
} else {
|
|
@@ -2923,7 +2923,7 @@ Options:
|
|
|
2923
2923
|
const shutdown = (resolve) => {
|
|
2924
2924
|
if (heartbeat) clearInterval(heartbeat);
|
|
2925
2925
|
closeShare?.();
|
|
2926
|
-
import("./agentShare-
|
|
2926
|
+
import("./agentShare-Cue9mqvJ.js").then((m) => m.revokeAllShares()).catch(() => {});
|
|
2927
2927
|
server?.stop();
|
|
2928
2928
|
Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
|
|
2929
2929
|
};
|
|
@@ -2936,4 +2936,4 @@ Options:
|
|
|
2936
2936
|
|
|
2937
2937
|
//#endregion
|
|
2938
2938
|
export { cmdServe, resolveLocalServeUrl };
|
|
2939
|
-
//# sourceMappingURL=serve-
|
|
2939
|
+
//# sourceMappingURL=serve-CC1SbBXS.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as setWorkspaceRoot, s as getWorkspaceRoot } from "./workspaceConfig-
|
|
1
|
+
import { f as setWorkspaceRoot, s as getWorkspaceRoot } from "./workspaceConfig-BRl-GwSN.js";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { stdin, stdout } from "node:process";
|
|
4
4
|
import { createInterface } from "node:readline/promises";
|
|
@@ -32,7 +32,7 @@ async function cmdSetup(rest) {
|
|
|
32
32
|
if (!existsSync(abs)) process.stderr.write(` note: that directory doesn't exist yet — create it, or agents spawned there will fail\n`);
|
|
33
33
|
if (noShare) return 0;
|
|
34
34
|
process.stdout.write(`\nsharing this machine to agent-yes.com…\n`);
|
|
35
|
-
const { cmdServe } = await import("./serve-
|
|
35
|
+
const { cmdServe } = await import("./serve-CC1SbBXS.js");
|
|
36
36
|
return cmdServe([
|
|
37
37
|
"install",
|
|
38
38
|
"--share",
|
|
@@ -42,4 +42,4 @@ async function cmdSetup(rest) {
|
|
|
42
42
|
|
|
43
43
|
//#endregion
|
|
44
44
|
export { cmdSetup };
|
|
45
|
-
//# sourceMappingURL=setup-
|
|
45
|
+
//# sourceMappingURL=setup-Cz9t2H2g.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
2
|
import "./globalPidIndex-CoNr7tS8.js";
|
|
3
|
-
import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-
|
|
3
|
+
import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-ChYCj6Dm.js";
|
|
4
4
|
|
|
5
5
|
export { waitForSpawnCapacity };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as readGlobalPids } from "./globalPidIndex-CoNr7tS8.js";
|
|
2
|
-
import { n as getMinFreeMb, o as getSpawnWaitMs, t as getMaxAgents } from "./workspaceConfig-
|
|
2
|
+
import { n as getMinFreeMb, o as getSpawnWaitMs, t as getMaxAgents } from "./workspaceConfig-BRl-GwSN.js";
|
|
3
3
|
import { readFile } from "fs/promises";
|
|
4
4
|
|
|
5
5
|
//#region ts/spawnGate.ts
|
|
@@ -104,4 +104,4 @@ async function waitForSpawnCapacity(opts) {
|
|
|
104
104
|
|
|
105
105
|
//#endregion
|
|
106
106
|
export { waitForSpawnCapacity as i, spawnGateEnabled as n, spawnRejectionReason as r, memAvailableMb as t };
|
|
107
|
-
//# sourceMappingURL=spawnGate-
|
|
107
|
+
//# sourceMappingURL=spawnGate-ChYCj6Dm.js.map
|
|
@@ -5,7 +5,7 @@ import { a as updateGlobalPidStatus, i as readGlobalPids } from "./globalPidInde
|
|
|
5
5
|
import { a as recordOutbox, i as recordMessage, n as readMailbox, t as partyMatches } from "./messageLog-Bb_Ie3Ck.js";
|
|
6
6
|
import { t as loadSharedCliDefaults } from "./configShared-nnIwDYY-.js";
|
|
7
7
|
import { n as isWebrtcSpec } from "./webrtcLink-DknpJQ0y.js";
|
|
8
|
-
import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-
|
|
8
|
+
import { a as resolveRemoteSpec, i as readRemotes } from "./remotes-BtXom7Rp.js";
|
|
9
9
|
import ms from "ms";
|
|
10
10
|
import yargs from "yargs";
|
|
11
11
|
import { appendFile, mkdir, open, readFile, readdir, rename, rm, stat, writeFile } from "fs/promises";
|
|
@@ -1239,35 +1239,35 @@ async function runSubcommand(argv) {
|
|
|
1239
1239
|
case "restart": return await cmdRestart(rest);
|
|
1240
1240
|
case "note": return await cmdNote(rest);
|
|
1241
1241
|
case "todo": {
|
|
1242
|
-
const { runTodoSubcommand } = await import("./todoCli-
|
|
1242
|
+
const { runTodoSubcommand } = await import("./todoCli-D8bL164c.js");
|
|
1243
1243
|
return runTodoSubcommand(rest);
|
|
1244
1244
|
}
|
|
1245
1245
|
case "serve": {
|
|
1246
|
-
const { cmdServe } = await import("./serve-
|
|
1246
|
+
const { cmdServe } = await import("./serve-CC1SbBXS.js");
|
|
1247
1247
|
return cmdServe(rest);
|
|
1248
1248
|
}
|
|
1249
1249
|
case "setup": {
|
|
1250
|
-
const { cmdSetup } = await import("./setup-
|
|
1250
|
+
const { cmdSetup } = await import("./setup-Cz9t2H2g.js");
|
|
1251
1251
|
return cmdSetup(rest);
|
|
1252
1252
|
}
|
|
1253
1253
|
case "ws": {
|
|
1254
|
-
const { cmdWs } = await import("./ws-
|
|
1254
|
+
const { cmdWs } = await import("./ws-D9H2UXCC.js");
|
|
1255
1255
|
return cmdWs(rest);
|
|
1256
1256
|
}
|
|
1257
1257
|
case "schedule": {
|
|
1258
|
-
const { cmdSchedule } = await import("./schedule-
|
|
1258
|
+
const { cmdSchedule } = await import("./schedule-Dd26IiBu.js");
|
|
1259
1259
|
return cmdSchedule(rest);
|
|
1260
1260
|
}
|
|
1261
1261
|
case "remote": {
|
|
1262
|
-
const { cmdRemote } = await import("./remotes-
|
|
1262
|
+
const { cmdRemote } = await import("./remotes-DZ_G2wkM.js");
|
|
1263
1263
|
return cmdRemote(rest);
|
|
1264
1264
|
}
|
|
1265
1265
|
case "expose": {
|
|
1266
|
-
const { cmdExpose } = await import("./expose-
|
|
1266
|
+
const { cmdExpose } = await import("./expose-CKWXAkzK.js");
|
|
1267
1267
|
return cmdExpose(rest);
|
|
1268
1268
|
}
|
|
1269
1269
|
case "callback": {
|
|
1270
|
-
const { cmdCallback } = await import("./callback-
|
|
1270
|
+
const { cmdCallback } = await import("./callback-Lsz9mZiC.js");
|
|
1271
1271
|
return cmdCallback(rest);
|
|
1272
1272
|
}
|
|
1273
1273
|
case "reap":
|
|
@@ -1305,7 +1305,7 @@ async function cmdHelp(managerCommands = true) {
|
|
|
1305
1305
|
const wsLines = managerCommands ? " ay ws ls [--status] list <owner>/<repo>/tree/<branch> workspaces\n ay ws new <owner>/<repo>[@branch] clone/refresh a workspace (ay ws help for more)\n" : ``;
|
|
1306
1306
|
const self = process.env.AGENT_YES_PID ? await resolveSender() : null;
|
|
1307
1307
|
const agentSection = self ? await buildAgentContextSection(self) : "";
|
|
1308
|
-
process.stdout.write(agentSection + "ay - agent-yes CLI\n\nManagement:\n ay ls [keyword] list running agents\n ay tail [-f] [-n N] <keyword> last N lines (96), -f to follow\n ay read <keyword> [page opts] paginate: --last/--head N, --range A:B,\n --before-line L [--limit N]\n ay cat <keyword> full log\n ay head <keyword> first N lines\n ay send <keyword> <msg> send a message\n ay msgs [keyword] [--in|--out] inter-agent message log (sent + received)\n ay key <keyword> <key...> send raw keystrokes (down/up/enter/esc/…) — drives menus\n ay select <keyword> <N> pick option N of a needs_input selection menu\n ay attach <keyword> interactive attach (detach: Ctrl-\\)\n ay stop <keyword> graceful shutdown (/exit for claude/codex)\n ay exit <keyword> [reason] graceful shutdown, recording who/why (= 'ay send <kw> exit')\n ay restart <keyword> [--fresh] stop (if live) + relaunch resuming the session; --fresh replays the prompt\n ay status <keyword> agent status snapshot\n ay result <keyword> [--wait] pull an agent's structured result envelope\n ay result set '<json>' (inside an agent) deposit your result envelope\n ay reap kill process groups leaked by dead agents\n" + wsLines + "\nRemote:\n" + setupLine + " ay schedule <when> <cli> -- <msg> run an agent on a schedule (HH:MM or cron)\n ay serve [--port N] start HTTP API server (prints token)\n ay serve status show serve daemon/server status\n ay remote add <alias> http://<token>@<host>:<port>\n ay remote ls / rm <alias> manage saved remotes\n ay expose <port> share localhost:<port> at https://<id>.agent-yes.com (private link)\n ay callback --expires 7d mint an embeddable message-me widget for one agent\n ay ls <token>@<host>:<port> connect inline (no alias needed)\n ay send <token>@<host>:<port>:<kw> <msg>\n\nRun an agent:\n ay [claude|codex|gemini|...] [options] -- [prompt]\n ay claude -- \"fix the bug in auth.ts\"\n ay claude --help full agent-runner options\n\nLabs (examples at https://github.com/snomiao/agent-yes/tree/main/lab):\n local-role-play/ designer + builder on one machine\n http-remote/ ay serve remote access demo\n p2p-pairing/ libp2p P2P (needs: cargo build --features swarm)\n");
|
|
1308
|
+
process.stdout.write(agentSection + "ay - agent-yes CLI\n\nManagement:\n ay ls [keyword] list running agents\n ay tail [-f] [-n N] <keyword> last N lines (96), -f to follow\n ay read <keyword> [page opts] paginate: --last/--head N, --range A:B,\n --before-line L [--limit N]\n ay cat <keyword> full log\n ay head <keyword> first N lines\n ay send <keyword> <msg> send a message (keyword '.' = agent in this cwd)\n ay msgs [keyword] [--in|--out] inter-agent message log (sent + received)\n ay key <keyword> <key...> send raw keystrokes (down/up/enter/esc/…) — drives menus\n ay select <keyword> <N> pick option N of a needs_input selection menu\n ay attach <keyword> interactive attach (detach: Ctrl-\\)\n ay stop <keyword> graceful shutdown (/exit for claude/codex)\n ay exit <keyword> [reason] graceful shutdown, recording who/why (= 'ay send <kw> exit')\n ay restart <keyword> [--fresh] stop (if live) + relaunch resuming the session; --fresh replays the prompt\n ay status <keyword> agent status snapshot\n ay result <keyword> [--wait] pull an agent's structured result envelope\n ay result set '<json>' (inside an agent) deposit your result envelope\n ay reap kill process groups leaked by dead agents\n" + wsLines + "\nRemote:\n" + setupLine + " ay schedule <when> <cli> -- <msg> run an agent on a schedule (HH:MM or cron)\n ay serve [--port N] start HTTP API server (prints token)\n ay serve status show serve daemon/server status\n ay remote add <alias> http://<token>@<host>:<port>\n ay remote ls / rm <alias> manage saved remotes\n ay expose <port> share localhost:<port> at https://<id>.agent-yes.com (private link)\n ay callback --expires 7d mint an embeddable message-me widget for one agent\n ay ls <token>@<host>:<port> connect inline (no alias needed)\n ay send <token>@<host>:<port>:<kw> <msg>\n\nRun an agent:\n ay [claude|codex|gemini|...] [options] -- [prompt]\n ay claude -- \"fix the bug in auth.ts\"\n ay claude --help full agent-runner options\n\nLabs (examples at https://github.com/snomiao/agent-yes/tree/main/lab):\n local-role-play/ designer + builder on one machine\n http-remote/ ay serve remote access demo\n p2p-pairing/ libp2p P2P (needs: cargo build --features swarm)\n");
|
|
1309
1309
|
return 0;
|
|
1310
1310
|
}
|
|
1311
1311
|
function matchKeyword(record, keyword) {
|
|
@@ -1315,6 +1315,7 @@ function matchKeyword(record, keyword) {
|
|
|
1315
1315
|
if (record.pid === Number(keyword)) return true;
|
|
1316
1316
|
return !!(record.agent_id && record.agent_id.toLowerCase().startsWith(kw));
|
|
1317
1317
|
}
|
|
1318
|
+
if (kw === "." || kw === "./") return path.resolve(record.cwd) === path.resolve(process.cwd());
|
|
1318
1319
|
if (record.cwd.toLowerCase().includes(kw)) return true;
|
|
1319
1320
|
if (record.cli.toLowerCase() === kw) return true;
|
|
1320
1321
|
if (record.prompt && record.prompt.toLowerCase().includes(kw)) return true;
|
|
@@ -1684,7 +1685,7 @@ async function fetchRemoteRecordsRaw(url, token, opts) {
|
|
|
1684
1685
|
let base = url;
|
|
1685
1686
|
let bearer = token;
|
|
1686
1687
|
if (isWebrtcSpec(url)) {
|
|
1687
|
-
const { startWebrtcBridge } = await import("./webrtcRemote-
|
|
1688
|
+
const { startWebrtcBridge } = await import("./webrtcRemote-C974zjSt.js");
|
|
1688
1689
|
bridge = await startWebrtcBridge(url);
|
|
1689
1690
|
base = bridge.baseUrl;
|
|
1690
1691
|
bearer = bridge.token;
|
|
@@ -3107,6 +3108,13 @@ async function cmdSend(rest) {
|
|
|
3107
3108
|
wrapped: Boolean(nonce)
|
|
3108
3109
|
});
|
|
3109
3110
|
if (!confirmed) process.stderr.write(`\nwarning: couldn't confirm the CLI acted on it after ${SEND_SUBMIT_MAX_RETRIES + 1} attempt(s) — it may still be sitting unsubmitted in the prompt. Last screen:\n` + lastScreen.slice(-8).map((l) => ` ${l}`).join("\n") + "\n");
|
|
3111
|
+
if (record.log_file) {
|
|
3112
|
+
const tail = await renderLogTailLines(record.log_file, 10) ?? [];
|
|
3113
|
+
let end = tail.length;
|
|
3114
|
+
while (end > 0 && tail[end - 1].trim() === "") end--;
|
|
3115
|
+
const trimmed = tail.slice(0, end);
|
|
3116
|
+
if (trimmed.length) process.stderr.write(`\n── pid ${record.pid} · last ${trimmed.length} line${trimmed.length === 1 ? "" : "s"} ──\n` + trimmed.map((l) => ` ${l}`).join("\n") + `\n`);
|
|
3117
|
+
}
|
|
3110
3118
|
const replyHint = sender.agent ? ` ay send ${replyTarget} "..." # reply to sender\n` : "";
|
|
3111
3119
|
process.stderr.write(`\n` + replyHint + ` ay tail ${record.pid} # watch output\n ay ls # list all agents\n`);
|
|
3112
3120
|
if (codeName === "ctrl-c" || codeName === "ctrlc") {
|
|
@@ -4279,7 +4287,7 @@ async function cmdNotify(rest) {
|
|
|
4279
4287
|
}
|
|
4280
4288
|
const ensure = async () => {
|
|
4281
4289
|
if (!argv["ensure-daemon"]) return;
|
|
4282
|
-
const { ensureDaemon } = await import("./notifyDaemon-
|
|
4290
|
+
const { ensureDaemon } = await import("./notifyDaemon-BoE83_av.js");
|
|
4283
4291
|
await ensureDaemon().catch(() => null);
|
|
4284
4292
|
};
|
|
4285
4293
|
await heartbeatWatcher(parent, selfStartedAt);
|
|
@@ -4353,7 +4361,7 @@ async function cmdNotifyCursor(args) {
|
|
|
4353
4361
|
}
|
|
4354
4362
|
async function cmdNotifyd(rest) {
|
|
4355
4363
|
const sub = rest[0] ?? "status";
|
|
4356
|
-
const daemon = await import("./notifyDaemon-
|
|
4364
|
+
const daemon = await import("./notifyDaemon-BoE83_av.js");
|
|
4357
4365
|
switch (sub) {
|
|
4358
4366
|
case "run": return daemon.runDaemon();
|
|
4359
4367
|
case "once": return daemon.runDaemon({ once: true });
|
|
@@ -4380,4 +4388,4 @@ async function cmdNotifyd(rest) {
|
|
|
4380
4388
|
|
|
4381
4389
|
//#endregion
|
|
4382
4390
|
export { daemonLockOwnerPath as $, renderRawLog as A, submitAndConfirm as B, matchKeyword as C, recentMessageEdges as D, readPtysize as E, restartHintLines as F, gcInboxes as G, writeKeysPaced as H, runSubcommand as I, listInboxParents as J, hostId as K, snapshotStatus as L, resolveOne as M, resolveReadWindow as N, recentReadEdges as O, resolveResumeArgs as P, daemonLockDir as Q, stdinActivityPath as R, listRecords as S, readNotes as T, writeToIpc as U, waitForLogQuiet as V, appendEvent as W, readInbox as X, liveWatchers as Y, shouldStealLock as Z, isPidAlive as _, cmdHelp as a, isUserTyping as b, deriveLiveState as c, extractMenu as d, notifyDir as et, extractNeedsInput as f, isExitRequest as g, isAgentStuck as h, backoffWhileTyping as i, renderRawLogLines as j, renderLogTailLines as k, deriveLiveStatus as l, finalizedLines as m, READ_PAGE_DEFAULT as n, controlCodeFromName as o, extractTaskCounts as p, isTransientLockMkdirError as q, TYPING_WINDOW_MS as r, cursorAbs as s, GRACEFUL_EXIT_COMMANDS as t, TYPING_BADGE as tt, extractBadges as u, isSlashCommand as v, menuSelectKeys as w, lastStdinAt as x, isSubcommand as y, stopTipForCli as z };
|
|
4383
|
-
//# sourceMappingURL=subcommands-
|
|
4391
|
+
//# sourceMappingURL=subcommands-Clrx40Id.js.map
|
|
@@ -2,9 +2,9 @@ import "./logger-CDIsZ-Pp.js";
|
|
|
2
2
|
import "./globalPidIndex-CoNr7tS8.js";
|
|
3
3
|
import "./messageLog-Bb_Ie3Ck.js";
|
|
4
4
|
import "./configShared-nnIwDYY-.js";
|
|
5
|
-
import { A as renderRawLog, B as submitAndConfirm, C as matchKeyword, D as recentMessageEdges, E as readPtysize, F as restartHintLines, H as writeKeysPaced, I as runSubcommand, L as snapshotStatus, M as resolveOne, N as resolveReadWindow, O as recentReadEdges, P as resolveResumeArgs, R as stdinActivityPath, S as listRecords, T as readNotes, U as writeToIpc, V as waitForLogQuiet, _ as isPidAlive, a as cmdHelp, b as isUserTyping, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as renderRawLogLines, k as renderLogTailLines, l as deriveLiveStatus, m as finalizedLines, n as READ_PAGE_DEFAULT, o as controlCodeFromName, p as extractTaskCounts, r as TYPING_WINDOW_MS, s as cursorAbs, t as GRACEFUL_EXIT_COMMANDS, u as extractBadges, v as isSlashCommand, w as menuSelectKeys, x as lastStdinAt, y as isSubcommand, z as stopTipForCli } from "./subcommands-
|
|
5
|
+
import { A as renderRawLog, B as submitAndConfirm, C as matchKeyword, D as recentMessageEdges, E as readPtysize, F as restartHintLines, H as writeKeysPaced, I as runSubcommand, L as snapshotStatus, M as resolveOne, N as resolveReadWindow, O as recentReadEdges, P as resolveResumeArgs, R as stdinActivityPath, S as listRecords, T as readNotes, U as writeToIpc, V as waitForLogQuiet, _ as isPidAlive, a as cmdHelp, b as isUserTyping, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as renderRawLogLines, k as renderLogTailLines, l as deriveLiveStatus, m as finalizedLines, n as READ_PAGE_DEFAULT, o as controlCodeFromName, p as extractTaskCounts, r as TYPING_WINDOW_MS, s as cursorAbs, t as GRACEFUL_EXIT_COMMANDS, u as extractBadges, v as isSlashCommand, w as menuSelectKeys, x as lastStdinAt, y as isSubcommand, z as stopTipForCli } from "./subcommands-Clrx40Id.js";
|
|
6
6
|
import "./e2e-D5jaSHyY.js";
|
|
7
7
|
import "./webrtcLink-DknpJQ0y.js";
|
|
8
|
-
import "./remotes-
|
|
8
|
+
import "./remotes-BtXom7Rp.js";
|
|
9
9
|
|
|
10
10
|
export { cmdHelp, isSubcommand, runSubcommand };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-B5TdNLCF.js";
|
|
3
3
|
import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
|
|
4
4
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-CNMl13dC.js";
|
|
5
5
|
import { i as readGlobalPids } from "./globalPidIndex-CoNr7tS8.js";
|
|
@@ -1919,4 +1919,4 @@ function sleep(ms) {
|
|
|
1919
1919
|
|
|
1920
1920
|
//#endregion
|
|
1921
1921
|
export { CLAUDE_SESSION_PIN_ENV as a, AgentContext as i, agentYes as n, removeControlCharacters as o, config as r, CLIS_CONFIG as t };
|
|
1922
|
-
//# sourceMappingURL=ts-
|
|
1922
|
+
//# sourceMappingURL=ts-C27ZwDyZ.js.map
|
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "url";
|
|
|
7
7
|
|
|
8
8
|
//#region package.json
|
|
9
9
|
var name = "agent-yes";
|
|
10
|
-
var version = "1.
|
|
10
|
+
var version = "1.226.0";
|
|
11
11
|
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region ts/versionChecker.ts
|
|
@@ -215,4 +215,4 @@ async function displayVersion() {
|
|
|
215
215
|
|
|
216
216
|
//#endregion
|
|
217
217
|
export { versionString as i, displayVersion as n, getInstalledPackage as r, checkAndAutoUpdate as t };
|
|
218
|
-
//# sourceMappingURL=versionChecker-
|
|
218
|
+
//# sourceMappingURL=versionChecker-B5TdNLCF.js.map
|
|
@@ -193,4 +193,4 @@ function resolveSpawnCwd(input) {
|
|
|
193
193
|
|
|
194
194
|
//#endregion
|
|
195
195
|
export { getSpawnHook as a, hasProvisionHook as c, resolveSpawnCwd as d, setWorkspaceRoot as f, getProvisionRoot as i, hasSpawnHook as l, getMinFreeMb as n, getSpawnWaitMs as o, getProvisionHook as r, getWorkspaceRoot as s, getMaxAgents as t, isProvisionAllowed as u };
|
|
196
|
-
//# sourceMappingURL=workspaceConfig-
|
|
196
|
+
//# sourceMappingURL=workspaceConfig-BRl-GwSN.js.map
|
|
@@ -2,11 +2,11 @@ import "./logger-CDIsZ-Pp.js";
|
|
|
2
2
|
import "./globalPidIndex-CoNr7tS8.js";
|
|
3
3
|
import "./messageLog-Bb_Ie3Ck.js";
|
|
4
4
|
import "./configShared-nnIwDYY-.js";
|
|
5
|
-
import { S as listRecords } from "./subcommands-
|
|
5
|
+
import { S as listRecords } from "./subcommands-Clrx40Id.js";
|
|
6
6
|
import "./e2e-D5jaSHyY.js";
|
|
7
7
|
import "./webrtcLink-DknpJQ0y.js";
|
|
8
|
-
import "./remotes-
|
|
9
|
-
import { i as getProvisionRoot } from "./workspaceConfig-
|
|
8
|
+
import "./remotes-BtXom7Rp.js";
|
|
9
|
+
import { i as getProvisionRoot } from "./workspaceConfig-BRl-GwSN.js";
|
|
10
10
|
import { existsSync } from "fs";
|
|
11
11
|
import { lstat, opendir } from "fs/promises";
|
|
12
12
|
import path from "path";
|
|
@@ -418,4 +418,4 @@ async function cmdWs(args) {
|
|
|
418
418
|
|
|
419
419
|
//#endregion
|
|
420
420
|
export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, workspaceStatus };
|
|
421
|
-
//# sourceMappingURL=ws-
|
|
421
|
+
//# sourceMappingURL=ws-D9H2UXCC.js.map
|
package/package.json
CHANGED
package/ts/cli.ts
CHANGED
|
@@ -83,6 +83,15 @@ if (!config.showVersion && !config.appendPrompt && !config.tray) {
|
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
// Warn if another live agent already occupies this cwd — two agents in one
|
|
87
|
+
// working tree clobber each other's files/builds/ports. Sits alongside the
|
|
88
|
+
// spawn gate (real-launch only) and BEFORE the --rust dispatch so it covers both
|
|
89
|
+
// runtimes. Best-effort, non-blocking; silence with AGENT_YES_NO_CWD_WARN=1.
|
|
90
|
+
if (!config.showVersion && !config.appendPrompt && !config.tray) {
|
|
91
|
+
const { warnIfCwdOccupied } = await import("./cwdConflictWarn.ts");
|
|
92
|
+
await warnIfCwdOccupied(process.argv);
|
|
93
|
+
}
|
|
94
|
+
|
|
86
95
|
// Handle --rust: spawn the Rust binary instead, fall back to TypeScript if unavailable
|
|
87
96
|
if (config.useRust) {
|
|
88
97
|
let rustBinary: string | undefined;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { formatCwdConflictWarning, shQuote } from "./cwdConflictWarn.ts";
|
|
3
|
+
|
|
4
|
+
describe("cwdConflictWarn.formatCwdConflictWarning", () => {
|
|
5
|
+
const cwd = "/code/proj/tree/main";
|
|
6
|
+
|
|
7
|
+
it("returns null when no peers occupy the cwd", () => {
|
|
8
|
+
expect(formatCwdConflictWarning([], cwd, "ay claude")).toBeNull();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("warns and suggests a git-worktree command for a single peer", () => {
|
|
12
|
+
const msg = formatCwdConflictWarning([{ pid: 111, cli: "claude" }], cwd, "ay claude -- fix");
|
|
13
|
+
expect(msg).toContain("1 agent is already running in this directory (/code/proj/tree/main)");
|
|
14
|
+
expect(msg).toContain("111 claude");
|
|
15
|
+
// uses `git worktree add` (not `git clone .`) — worktree name = dir + branch
|
|
16
|
+
expect(msg).toContain("git worktree add -b main-work ../main-work && cd ../main-work");
|
|
17
|
+
expect(msg).not.toContain("git clone");
|
|
18
|
+
// original command is appended so the suggestion is copy-pasteable
|
|
19
|
+
expect(msg).toContain("&& ay claude -- fix");
|
|
20
|
+
expect(msg).toContain("AGENT_YES_NO_CWD_WARN=1");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("pluralizes and lists at most 3 peers with an overflow count", () => {
|
|
24
|
+
const peers = [1, 2, 3, 4, 5].map((n) => ({ pid: n, cli: "codex" }));
|
|
25
|
+
const msg = formatCwdConflictWarning(peers, cwd, "ay codex")!;
|
|
26
|
+
expect(msg).toContain("5 agents are already running");
|
|
27
|
+
expect(msg).toContain("1 codex");
|
|
28
|
+
expect(msg).toContain("3 codex");
|
|
29
|
+
expect(msg).not.toContain("4 codex"); // capped at 3 listed
|
|
30
|
+
expect(msg).toContain("…and 2 more");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("falls back to a placeholder when cwd has no basename or command is empty", () => {
|
|
34
|
+
const msg = formatCwdConflictWarning([{ pid: 9, cli: "gemini" }], "/", " ")!;
|
|
35
|
+
expect(msg).toContain("../agent-work"); // basename('/') is empty → 'agent'
|
|
36
|
+
expect(msg).toContain("&& ay <cli> …"); // empty origCmd → placeholder
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe("cwdConflictWarn.shQuote", () => {
|
|
41
|
+
it("passes safe tokens through unquoted", () => {
|
|
42
|
+
expect(shQuote("ay")).toBe("ay");
|
|
43
|
+
expect(shQuote("claude")).toBe("claude");
|
|
44
|
+
expect(shQuote("--")).toBe("--");
|
|
45
|
+
expect(shQuote("../main-work")).toBe("../main-work");
|
|
46
|
+
expect(shQuote("main-work_2.3")).toBe("main-work_2.3");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("single-quotes tokens with spaces or shell metacharacters", () => {
|
|
50
|
+
expect(shQuote("fix the bug")).toBe("'fix the bug'");
|
|
51
|
+
expect(shQuote("a;rm -rf b")).toBe("'a;rm -rf b'");
|
|
52
|
+
expect(shQuote("$HOME")).toBe("'$HOME'");
|
|
53
|
+
expect(shQuote("")).toBe("''");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("escapes embedded single quotes safely", () => {
|
|
57
|
+
// POSIX close-quote / escaped-quote / reopen-quote dance
|
|
58
|
+
expect(shQuote("it's")).toBe(`'it'\\''s'`);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-launch warning: another live agent is already working in THIS exact
|
|
3
|
+
* directory. Two agents sharing one working tree clobber each other's edits,
|
|
4
|
+
* builds, and dev-server ports — so we warn (stderr, non-fatal) and hand the
|
|
5
|
+
* user a copy-pasteable git-worktree isolation command.
|
|
6
|
+
*
|
|
7
|
+
* Lives in cli.ts's launch path (before the --rust dispatch) so it covers BOTH
|
|
8
|
+
* the Rust and TypeScript runtimes with one check. The launching agent isn't
|
|
9
|
+
* registered in the pid index yet, so every same-cwd match here is a genuine
|
|
10
|
+
* pre-existing peer, never itself.
|
|
11
|
+
*/
|
|
12
|
+
import path from "path";
|
|
13
|
+
import { readGlobalPids, type GlobalPidRecord } from "./globalPidIndex.ts";
|
|
14
|
+
|
|
15
|
+
/** A pre-existing peer for the warning: just what we render. */
|
|
16
|
+
export interface CwdOccupant {
|
|
17
|
+
pid: number;
|
|
18
|
+
cli: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* POSIX single-quote a shell token so a copy-pasted recovery command survives
|
|
23
|
+
* spaces, quotes, `$`, `;`, `&`, etc. Safe-charset tokens pass through unquoted
|
|
24
|
+
* so the common case (`ay claude -- fix`) stays readable. Empty string → `''`.
|
|
25
|
+
*/
|
|
26
|
+
export function shQuote(s: string): string {
|
|
27
|
+
if (s === "") return "''";
|
|
28
|
+
if (/^[A-Za-z0-9,._+@%/:=-]+$/.test(s)) return s;
|
|
29
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Pure renderer — given the peers already in `cwd`, the cwd, and the original
|
|
34
|
+
* `ay …` command, produce the warning text (or null when there's no conflict).
|
|
35
|
+
* Separated from IO so the message/branching is unit-tested without a live index.
|
|
36
|
+
*/
|
|
37
|
+
export function formatCwdConflictWarning(
|
|
38
|
+
occupants: CwdOccupant[],
|
|
39
|
+
cwd: string,
|
|
40
|
+
origCmd: string,
|
|
41
|
+
): string | null {
|
|
42
|
+
if (occupants.length === 0) return null;
|
|
43
|
+
// Worktree name doubles as the new dir AND the new branch. `git worktree add`
|
|
44
|
+
// (not `git clone .`) is the correct primitive: it resolves the repo root even
|
|
45
|
+
// from a subdir, shares the object store, and creates the branch in one step.
|
|
46
|
+
const wt = `${path.basename(cwd) || "agent"}-work`;
|
|
47
|
+
const list = occupants
|
|
48
|
+
.slice(0, 3)
|
|
49
|
+
.map((r) => ` ${r.pid} ${r.cli}`)
|
|
50
|
+
.join("\n");
|
|
51
|
+
const more = occupants.length > 3 ? `\n …and ${occupants.length - 3} more` : "";
|
|
52
|
+
const cmd = origCmd.trim() || "ay <cli> …";
|
|
53
|
+
const branch = shQuote(wt);
|
|
54
|
+
const dir = shQuote(`../${wt}`);
|
|
55
|
+
return (
|
|
56
|
+
`\n⚠ ${occupants.length} agent${occupants.length > 1 ? "s are" : " is"} already running in this directory (${cwd}):\n` +
|
|
57
|
+
`${list}${more}\n` +
|
|
58
|
+
` Parallel agents in one working tree clobber each other's files, builds, and ports.\n` +
|
|
59
|
+
` To isolate this run in its own git worktree, cancel (Ctrl-C) and instead:\n` +
|
|
60
|
+
` git worktree add -b ${branch} ${dir} && cd ${dir} && ${cmd}\n` +
|
|
61
|
+
` (set AGENT_YES_NO_CWD_WARN=1 to silence)\n\n`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* IO wrapper: discover live same-cwd peers and print the warning to stderr.
|
|
67
|
+
* Best-effort and swallow-all — a discovery hiccup must NEVER block a launch.
|
|
68
|
+
* No-op when AGENT_YES_NO_CWD_WARN=1.
|
|
69
|
+
*/
|
|
70
|
+
export async function warnIfCwdOccupied(rawArgv: string[]): Promise<void> {
|
|
71
|
+
if (process.env.AGENT_YES_NO_CWD_WARN === "1") return;
|
|
72
|
+
try {
|
|
73
|
+
const here = path.resolve(process.cwd());
|
|
74
|
+
const occupants: CwdOccupant[] = (await readGlobalPids({ liveOnly: true }))
|
|
75
|
+
.filter((r: GlobalPidRecord) => path.resolve(r.cwd) === here)
|
|
76
|
+
.map((r) => ({ pid: r.pid, cli: r.cli }));
|
|
77
|
+
// Shell-quote each argv token so the suggested command reproduces the
|
|
78
|
+
// original launch even with spaces/quotes in a prompt (e.g. a multi-word
|
|
79
|
+
// `-- "fix the bug"`). We can't recover the user's exact original quoting
|
|
80
|
+
// from argv, but per-token quoting is copy-paste-correct.
|
|
81
|
+
const origCmd = ["ay", ...rawArgv.slice(2)].map(shQuote).join(" ");
|
|
82
|
+
const msg = formatCwdConflictWarning(occupants, here, origCmd);
|
|
83
|
+
if (msg) {
|
|
84
|
+
process.stderr.write(msg);
|
|
85
|
+
// Interactive CLIs (claude/codex/gemini) switch to the alternate screen
|
|
86
|
+
// buffer on startup, which clears the terminal — the warning would flash
|
|
87
|
+
// and vanish before a human could read it. Hold briefly (only on a real
|
|
88
|
+
// conflict, only when attached to a TTY) so they get a beat to Ctrl-C and
|
|
89
|
+
// switch to a worktree. Non-TTY / detached launches skip the pause.
|
|
90
|
+
if (process.stdout.isTTY) {
|
|
91
|
+
await new Promise((r) => setTimeout(r, 2500));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} catch {
|
|
95
|
+
// Non-fatal — never block launching the agent over a warning.
|
|
96
|
+
}
|
|
97
|
+
}
|
package/ts/subcommands.spec.ts
CHANGED
|
@@ -336,6 +336,18 @@ describe("subcommands.matchKeyword", () => {
|
|
|
336
336
|
expect(matchKeyword(r, "parser")).toBe(false);
|
|
337
337
|
});
|
|
338
338
|
|
|
339
|
+
it("treats '.' / './' as the current working directory (exact cwd match)", async () => {
|
|
340
|
+
const { matchKeyword } = await loadModule();
|
|
341
|
+
const here = { ...baseRecord, cwd: process.cwd() };
|
|
342
|
+
const elsewhere = { ...baseRecord, cwd: "/some/other/place" };
|
|
343
|
+
// sibling agent in this exact cwd resolves
|
|
344
|
+
expect(matchKeyword(here, ".")).toBe(true);
|
|
345
|
+
expect(matchKeyword(here, "./")).toBe(true);
|
|
346
|
+
// an agent in a different cwd (even a subdir/parent) does not
|
|
347
|
+
expect(matchKeyword(elsewhere, ".")).toBe(false);
|
|
348
|
+
expect(matchKeyword({ ...baseRecord, cwd: process.cwd() + "/sub" }, ".")).toBe(false);
|
|
349
|
+
});
|
|
350
|
+
|
|
339
351
|
it("matches by agent_id prefix", async () => {
|
|
340
352
|
const { matchKeyword } = await loadModule();
|
|
341
353
|
const r = { ...baseRecord, agent_id: "a1b2c3d4e5f6" };
|
package/ts/subcommands.ts
CHANGED
|
@@ -612,7 +612,7 @@ export async function cmdHelp(managerCommands = true): Promise<number> {
|
|
|
612
612
|
` --before-line L [--limit N]\n` +
|
|
613
613
|
` ay cat <keyword> full log\n` +
|
|
614
614
|
` ay head <keyword> first N lines\n` +
|
|
615
|
-
` ay send <keyword> <msg> send a message\n` +
|
|
615
|
+
` ay send <keyword> <msg> send a message (keyword '.' = agent in this cwd)\n` +
|
|
616
616
|
` ay msgs [keyword] [--in|--out] inter-agent message log (sent + received)\n` +
|
|
617
617
|
` ay key <keyword> <key...> send raw keystrokes (down/up/enter/esc/…) — drives menus\n` +
|
|
618
618
|
` ay select <keyword> <N> pick option N of a needs_input selection menu\n` +
|
|
@@ -676,6 +676,14 @@ export function matchKeyword(record: GlobalPidRecord, keyword: string): boolean
|
|
|
676
676
|
if (record.pid === Number(keyword)) return true;
|
|
677
677
|
return !!(record.agent_id && record.agent_id.toLowerCase().startsWith(kw));
|
|
678
678
|
}
|
|
679
|
+
// 1b. `.` / `./` — shell convention for "the current directory": target the
|
|
680
|
+
// agent whose cwd IS process.cwd() (exact match). Lets `ay send .` reach the
|
|
681
|
+
// sibling agent running in this same dir without typing its pid or a path
|
|
682
|
+
// fragment. Repurposed from the (near-useless) substring behavior — a lone `.`
|
|
683
|
+
// was in almost every path, so it never selected anything meaningful.
|
|
684
|
+
if (kw === "." || kw === "./") {
|
|
685
|
+
return path.resolve(record.cwd) === path.resolve(process.cwd());
|
|
686
|
+
}
|
|
679
687
|
// 2. cwd contains keyword
|
|
680
688
|
if (record.cwd.toLowerCase().includes(kw)) return true;
|
|
681
689
|
// 3. cli exact (lowercase)
|
|
@@ -3192,6 +3200,24 @@ async function cmdSend(rest: string[]): Promise<number> {
|
|
|
3192
3200
|
);
|
|
3193
3201
|
}
|
|
3194
3202
|
|
|
3203
|
+
// Echo the tail of the target's screen so the sender sees, inline, whether the
|
|
3204
|
+
// message landed and how the agent reacted — no separate `ay tail` round-trip.
|
|
3205
|
+
// Rendered fresh from the log after the settle/confirm wait above, so it
|
|
3206
|
+
// reflects the post-submit state. Best-effort: a missing/empty log just skips.
|
|
3207
|
+
if (record.log_file) {
|
|
3208
|
+
const tail = (await renderLogTailLines(record.log_file, 10)) ?? [];
|
|
3209
|
+
let end = tail.length;
|
|
3210
|
+
while (end > 0 && tail[end - 1]!.trim() === "") end--; // drop trailing blanks
|
|
3211
|
+
const trimmed = tail.slice(0, end);
|
|
3212
|
+
if (trimmed.length) {
|
|
3213
|
+
process.stderr.write(
|
|
3214
|
+
`\n── pid ${record.pid} · last ${trimmed.length} line${trimmed.length === 1 ? "" : "s"} ──\n` +
|
|
3215
|
+
trimmed.map((l) => ` ${l}`).join("\n") +
|
|
3216
|
+
`\n`,
|
|
3217
|
+
);
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
|
|
3195
3221
|
const replyHint = sender.agent
|
|
3196
3222
|
? ` ay send ${replyTarget} "..." # reply to sender\n`
|
|
3197
3223
|
: "";
|