claude-yes 1.161.0 → 1.164.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-DYTnLX8C.js → SUPPORTED_CLIS-C_J_okdw.js} +2 -2
- package/dist/SUPPORTED_CLIS-CmJam_wA.js +8 -0
- package/dist/cli.js +4 -4
- package/dist/index.js +3 -3
- package/dist/pidStore-5qyLX3Fh.js +5 -0
- package/dist/{pidStore-fqXqTKkh.js → pidStore-BfoBWUjc.js} +3 -2
- package/dist/{schedule-CCvB7SCT.js → schedule-B-Ncgklt.js} +5 -5
- package/dist/{serve-BRARQjsC.js → serve-yVh9Y6ot.js} +70 -17
- package/dist/{setup-Cx7jDKtC.js → setup-BmYrvUsz.js} +2 -2
- package/dist/{subcommands-DGkBxWS5.js → subcommands-BbKngO7F.js} +7 -6
- package/dist/{subcommands-5AXvxB0S.js → subcommands-C-aCmtre.js} +1 -1
- package/dist/{ts-CRo3qQWb.js → ts-BzyVSzo1.js} +4 -3
- package/dist/{versionChecker-DrjR4P0K.js → versionChecker-CCHuozmQ.js} +2 -2
- package/lab/ui/console-logic.js +22 -6
- package/lab/ui/index.html +25 -10
- package/package.json +1 -1
- package/ts/index.ts +6 -0
- package/ts/pidStore.ts +8 -2
- package/ts/serve.ts +130 -28
- package/ts/subcommands.ts +15 -10
- package/dist/SUPPORTED_CLIS-CHmQfHCh.js +0 -8
- package/dist/pidStore-DfHh3Yt0.js +0 -5
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { t as CLIS_CONFIG } from "./ts-BzyVSzo1.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-C_J_okdw.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import "./ts-BzyVSzo1.js";
|
|
2
|
+
import "./logger-CDIsZ-Pp.js";
|
|
3
|
+
import "./versionChecker-CCHuozmQ.js";
|
|
4
|
+
import "./pidStore-BfoBWUjc.js";
|
|
5
|
+
import "./globalPidIndex-DlmmJlO8.js";
|
|
6
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-C_J_okdw.js";
|
|
7
|
+
|
|
8
|
+
export { SUPPORTED_CLIS };
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-
|
|
4
|
+
import { i as versionString, n as displayVersion, r as getInstalledPackage, t as checkAndAutoUpdate } from "./versionChecker-CCHuozmQ.js";
|
|
5
5
|
import { argv } from "process";
|
|
6
6
|
import { execFileSync, spawn } from "child_process";
|
|
7
7
|
import ms from "ms";
|
|
@@ -481,7 +481,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
|
|
|
481
481
|
const rawArg = process.argv[2];
|
|
482
482
|
const managerCommands = !invokedCliName(process.argv);
|
|
483
483
|
const isHelpFlag = rawArg === "-h" || rawArg === "--help";
|
|
484
|
-
const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-
|
|
484
|
+
const { isSubcommand, runSubcommand, cmdHelp } = await import("./subcommands-C-aCmtre.js");
|
|
485
485
|
if (isHelpFlag && process.argv.length === 3) {
|
|
486
486
|
cmdHelp(managerCommands);
|
|
487
487
|
process.exit(0);
|
|
@@ -514,7 +514,7 @@ if (config.useRust) {
|
|
|
514
514
|
}
|
|
515
515
|
}
|
|
516
516
|
if (rustBinary) {
|
|
517
|
-
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-
|
|
517
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-CmJam_wA.js");
|
|
518
518
|
const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
|
|
519
519
|
if (config.verbose) {
|
|
520
520
|
console.log(`[rust] Using binary: ${rustBinary}`);
|
|
@@ -544,7 +544,7 @@ if (config.showVersion) {
|
|
|
544
544
|
process.exit(0);
|
|
545
545
|
}
|
|
546
546
|
if (config.appendPrompt) {
|
|
547
|
-
const { PidStore } = await import("./pidStore-
|
|
547
|
+
const { PidStore } = await import("./pidStore-5qyLX3Fh.js");
|
|
548
548
|
const ipcPath = await PidStore.findActiveFifo(process.cwd());
|
|
549
549
|
if (!ipcPath) {
|
|
550
550
|
console.error("No active agent with IPC found in current directory.");
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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-BzyVSzo1.js";
|
|
2
2
|
import "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import "./versionChecker-
|
|
4
|
-
import "./pidStore-
|
|
3
|
+
import "./versionChecker-CCHuozmQ.js";
|
|
4
|
+
import "./pidStore-BfoBWUjc.js";
|
|
5
5
|
import "./globalPidIndex-DlmmJlO8.js";
|
|
6
6
|
|
|
7
7
|
export { AgentContext, CLIS_CONFIG, config, agentYes as default, removeControlCharacters };
|
|
@@ -209,8 +209,9 @@ var PidStore = class PidStore {
|
|
|
209
209
|
const argsJson = JSON.stringify(args);
|
|
210
210
|
const logFile = this.getRawLogPath(pid);
|
|
211
211
|
const fifoFile = this.getFifoPath(pid);
|
|
212
|
+
const injected = process.env.AGENT_YES_AGENT_ID;
|
|
212
213
|
const existing = this.store.findOne((doc) => doc.pid === pid);
|
|
213
|
-
const agentId = existing?.agentId ?? randomBytes(6).toString("hex");
|
|
214
|
+
const agentId = existing?.agentId ?? (injected && /^[0-9a-f]{6,32}$/i.test(injected) ? injected : randomBytes(6).toString("hex"));
|
|
214
215
|
const record = {
|
|
215
216
|
pid,
|
|
216
217
|
cli,
|
|
@@ -367,4 +368,4 @@ pid-db/
|
|
|
367
368
|
|
|
368
369
|
//#endregion
|
|
369
370
|
export { PidStore as t };
|
|
370
|
-
//# sourceMappingURL=pidStore-
|
|
371
|
+
//# sourceMappingURL=pidStore-BfoBWUjc.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import "./ts-
|
|
1
|
+
import "./ts-BzyVSzo1.js";
|
|
2
2
|
import "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import "./versionChecker-
|
|
4
|
-
import "./pidStore-
|
|
3
|
+
import "./versionChecker-CCHuozmQ.js";
|
|
4
|
+
import "./pidStore-BfoBWUjc.js";
|
|
5
5
|
import "./globalPidIndex-DlmmJlO8.js";
|
|
6
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
6
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-C_J_okdw.js";
|
|
7
7
|
import { o as resolveSpawnCwd } from "./workspaceConfig-B0Q9-q2B.js";
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
|
|
@@ -141,4 +141,4 @@ async function cmdSchedule(rest) {
|
|
|
141
141
|
|
|
142
142
|
//#endregion
|
|
143
143
|
export { cmdSchedule };
|
|
144
|
-
//# sourceMappingURL=schedule-
|
|
144
|
+
//# sourceMappingURL=schedule-B-Ncgklt.js.map
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import "./ts-
|
|
1
|
+
import "./ts-BzyVSzo1.js";
|
|
2
2
|
import "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
4
|
-
import "./pidStore-
|
|
3
|
+
import { r as getInstalledPackage } from "./versionChecker-CCHuozmQ.js";
|
|
4
|
+
import "./pidStore-BfoBWUjc.js";
|
|
5
5
|
import { a as updateGlobalPidStatus } from "./globalPidIndex-DlmmJlO8.js";
|
|
6
6
|
import { t as pgidForWrapper } from "./reaper-C-eWAxIj.js";
|
|
7
7
|
import "./configShared-CEyhl0WH.js";
|
|
8
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
8
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-C_J_okdw.js";
|
|
9
9
|
import "./e2e-Bfw7qL9O.js";
|
|
10
10
|
import "./webrtcLink-CBZkZ-LT.js";
|
|
11
11
|
import "./remotes-DBCvpp3B.js";
|
|
12
12
|
import { a as isProvisionAllowed, i as hasSpawnHook, n as getSpawnHook, o as resolveSpawnCwd, t as getProvisionRoot } from "./workspaceConfig-B0Q9-q2B.js";
|
|
13
|
-
import { D as writeToIpc, T as snapshotStatus, _ as readPtysize, b as resolveOne, c as extractTaskCounts, g as readNotes, i as controlCodeFromName, m as listRecords, o as deriveLiveStatus, v as renderRawLog } from "./subcommands-
|
|
13
|
+
import { D as writeToIpc, T as snapshotStatus, _ as readPtysize, b as resolveOne, c as extractTaskCounts, g as readNotes, i as controlCodeFromName, m as listRecords, o as deriveLiveStatus, s as extractNeedsInput, v as renderRawLog } from "./subcommands-BbKngO7F.js";
|
|
14
14
|
import yargs from "yargs";
|
|
15
15
|
import { mkdir, open, readFile, stat, unlink, writeFile } from "fs/promises";
|
|
16
16
|
import { homedir, hostname, userInfo } from "os";
|
|
@@ -625,6 +625,24 @@ Options:
|
|
|
625
625
|
return null;
|
|
626
626
|
}
|
|
627
627
|
};
|
|
628
|
+
const niCache = /* @__PURE__ */ new Map();
|
|
629
|
+
const logNeedsInput = async (logFile, cli) => {
|
|
630
|
+
if (!logFile) return null;
|
|
631
|
+
try {
|
|
632
|
+
const { size, mtimeMs } = await stat(logFile);
|
|
633
|
+
const hit = niCache.get(logFile);
|
|
634
|
+
if (hit && hit.size === size && hit.mtimeMs === mtimeMs) return hit.question;
|
|
635
|
+
const question = (await extractNeedsInput(logFile, cli))?.question ?? null;
|
|
636
|
+
niCache.set(logFile, {
|
|
637
|
+
size,
|
|
638
|
+
mtimeMs,
|
|
639
|
+
question
|
|
640
|
+
});
|
|
641
|
+
return question;
|
|
642
|
+
} catch {
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
645
|
+
};
|
|
628
646
|
const GIT_DEBOUNCE_MS = 800;
|
|
629
647
|
const GIT_SAFETY_MS = 6e4;
|
|
630
648
|
const runGit = async (args, cwd) => {
|
|
@@ -643,17 +661,43 @@ Options:
|
|
|
643
661
|
}
|
|
644
662
|
};
|
|
645
663
|
const parseGitStatus = (out) => {
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
const
|
|
664
|
+
let branch = null;
|
|
665
|
+
let ahead = 0;
|
|
666
|
+
let behind = 0;
|
|
667
|
+
let changed = 0;
|
|
668
|
+
let pins = 0;
|
|
669
|
+
let subDirty = 0;
|
|
670
|
+
for (const line of out.split("\n")) {
|
|
671
|
+
if (line.length === 0) continue;
|
|
672
|
+
if (line[0] === "#") {
|
|
673
|
+
const head = /^# branch\.head (.+)$/.exec(line);
|
|
674
|
+
if (head) {
|
|
675
|
+
branch = head[1] === "(detached)" ? null : head[1];
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
const ab = /^# branch\.ab \+(\d+) -(\d+)/.exec(line);
|
|
679
|
+
if (ab) {
|
|
680
|
+
ahead = Number(ab[1]);
|
|
681
|
+
behind = Number(ab[2]);
|
|
682
|
+
}
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
const type = line[0];
|
|
686
|
+
if (type === "?") changed++;
|
|
687
|
+
else if (type === "u") changed++;
|
|
688
|
+
else if (type === "1" || type === "2") {
|
|
689
|
+
const sub = line.split(" ")[2] ?? "N...";
|
|
690
|
+
if (sub[0] === "S") if (sub[1] === "C") pins++;
|
|
691
|
+
else subDirty++;
|
|
692
|
+
else changed++;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
653
695
|
return {
|
|
654
696
|
branch,
|
|
655
697
|
dirty: changed > 0,
|
|
656
698
|
changed,
|
|
699
|
+
pins,
|
|
700
|
+
subDirty,
|
|
657
701
|
ahead,
|
|
658
702
|
behind
|
|
659
703
|
};
|
|
@@ -676,7 +720,7 @@ Options:
|
|
|
676
720
|
try {
|
|
677
721
|
const out = await runGit([
|
|
678
722
|
"status",
|
|
679
|
-
"--porcelain",
|
|
723
|
+
"--porcelain=v2",
|
|
680
724
|
"--branch"
|
|
681
725
|
], root);
|
|
682
726
|
if (out != null) rw.val = parseGitStatus(out);
|
|
@@ -717,9 +761,11 @@ Options:
|
|
|
717
761
|
};
|
|
718
762
|
const withMeta = async (r) => {
|
|
719
763
|
const status = await deriveLiveStatus(r);
|
|
764
|
+
const question = status !== "exited" && !r.unresponsive ? await logNeedsInput(r.log_file, r.cli) : null;
|
|
720
765
|
return {
|
|
721
766
|
...r,
|
|
722
|
-
status: status
|
|
767
|
+
status: status === "exited" ? status : r.unresponsive ? "stuck" : question ? "needs_input" : status,
|
|
768
|
+
question,
|
|
723
769
|
title: await logTitle(r.log_file),
|
|
724
770
|
git: status === "exited" ? null : await gitStatus(r.cwd),
|
|
725
771
|
tasks: status === "exited" ? null : await logTasks(r.log_file)
|
|
@@ -1200,6 +1246,7 @@ Options:
|
|
|
1200
1246
|
...prompt ? ["--", prompt] : []
|
|
1201
1247
|
];
|
|
1202
1248
|
const agentEnv = freshAgentEnv();
|
|
1249
|
+
const agentId = randomBytes(6).toString("hex");
|
|
1203
1250
|
try {
|
|
1204
1251
|
const hook = getSpawnHook();
|
|
1205
1252
|
if (hook) {
|
|
@@ -1218,7 +1265,8 @@ Options:
|
|
|
1218
1265
|
env: {
|
|
1219
1266
|
...agentEnv,
|
|
1220
1267
|
AGENT_YES_CWD: cwd,
|
|
1221
|
-
AGENT_YES_CLI: cli
|
|
1268
|
+
AGENT_YES_CLI: cli,
|
|
1269
|
+
AGENT_YES_AGENT_ID: agentId
|
|
1222
1270
|
},
|
|
1223
1271
|
stdin: "ignore",
|
|
1224
1272
|
stdout: "ignore",
|
|
@@ -1239,6 +1287,7 @@ Options:
|
|
|
1239
1287
|
return Response.json({
|
|
1240
1288
|
ok: true,
|
|
1241
1289
|
pid: child.pid,
|
|
1290
|
+
agentId,
|
|
1242
1291
|
cli,
|
|
1243
1292
|
cwd,
|
|
1244
1293
|
hook: true,
|
|
@@ -1248,7 +1297,10 @@ Options:
|
|
|
1248
1297
|
const child = Bun.spawn(agentArgv, {
|
|
1249
1298
|
cwd,
|
|
1250
1299
|
detached: true,
|
|
1251
|
-
env:
|
|
1300
|
+
env: {
|
|
1301
|
+
...agentEnv,
|
|
1302
|
+
AGENT_YES_AGENT_ID: agentId
|
|
1303
|
+
},
|
|
1252
1304
|
stdin: "ignore",
|
|
1253
1305
|
stdout: "ignore",
|
|
1254
1306
|
stderr: "ignore"
|
|
@@ -1257,6 +1309,7 @@ Options:
|
|
|
1257
1309
|
return Response.json({
|
|
1258
1310
|
ok: true,
|
|
1259
1311
|
pid: child.pid,
|
|
1312
|
+
agentId,
|
|
1260
1313
|
cli,
|
|
1261
1314
|
cwd,
|
|
1262
1315
|
...provisioned ? { provisioned } : {}
|
|
@@ -1389,4 +1442,4 @@ Options:
|
|
|
1389
1442
|
|
|
1390
1443
|
//#endregion
|
|
1391
1444
|
export { cmdServe };
|
|
1392
|
-
//# sourceMappingURL=serve-
|
|
1445
|
+
//# sourceMappingURL=serve-yVh9Y6ot.js.map
|
|
@@ -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-yVh9Y6ot.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-BmYrvUsz.js.map
|
|
@@ -556,15 +556,15 @@ async function runSubcommand(argv) {
|
|
|
556
556
|
case "restart": return await cmdRestart(rest);
|
|
557
557
|
case "note": return await cmdNote(rest);
|
|
558
558
|
case "serve": {
|
|
559
|
-
const { cmdServe } = await import("./serve-
|
|
559
|
+
const { cmdServe } = await import("./serve-yVh9Y6ot.js");
|
|
560
560
|
return cmdServe(rest);
|
|
561
561
|
}
|
|
562
562
|
case "setup": {
|
|
563
|
-
const { cmdSetup } = await import("./setup-
|
|
563
|
+
const { cmdSetup } = await import("./setup-BmYrvUsz.js");
|
|
564
564
|
return cmdSetup(rest);
|
|
565
565
|
}
|
|
566
566
|
case "schedule": {
|
|
567
|
-
const { cmdSchedule } = await import("./schedule-
|
|
567
|
+
const { cmdSchedule } = await import("./schedule-B-Ncgklt.js");
|
|
568
568
|
return cmdSchedule(rest);
|
|
569
569
|
}
|
|
570
570
|
case "remote": {
|
|
@@ -913,7 +913,8 @@ async function runRemoteSpawn(remote, hint, spec) {
|
|
|
913
913
|
}
|
|
914
914
|
const r = await res.json();
|
|
915
915
|
process.stdout.write(`spawned ${r.cli} on ${remote.url} in ${r.cwd}${r.hook ? " (via spawn hook)" : ""}${r.provisioned ? ` (${r.provisioned.action})` : ""}\n`);
|
|
916
|
-
process.stderr.write(`\n ay
|
|
916
|
+
if (r.agentId && !hint.includes("://")) process.stderr.write(`\n ay tail ${hint}:${r.agentId} # watch its output\n ay status ${hint}:${r.agentId} --wait # block until it needs you\n`);
|
|
917
|
+
else process.stderr.write(`\n ay ls ${hint} # the new ${r.cli} agent appears here\n`);
|
|
917
918
|
return 0;
|
|
918
919
|
}
|
|
919
920
|
async function runRemoteStatus(remote) {
|
|
@@ -1933,7 +1934,7 @@ async function cmdSend(rest) {
|
|
|
1933
1934
|
const trailing = controlCodeFromName(codeName);
|
|
1934
1935
|
const record = await resolveOne(keyword, opts);
|
|
1935
1936
|
const fifoPath = record.fifo_file;
|
|
1936
|
-
if (!fifoPath) throw new Error(`pid ${record.pid}: no fifo_file recorded — agent
|
|
1937
|
+
if (!fifoPath) throw new Error(`pid ${record.pid}: no fifo_file recorded — this agent didn't register a stdin FIFO (an older agent, or one not started with --stdpush). Restarting it (ay restart ${record.pid}) re-registers one.`);
|
|
1937
1938
|
let body;
|
|
1938
1939
|
if (rawMessage === "-") {
|
|
1939
1940
|
const chunks = [];
|
|
@@ -2794,4 +2795,4 @@ async function cmdResultSet(rest) {
|
|
|
2794
2795
|
|
|
2795
2796
|
//#endregion
|
|
2796
2797
|
export { restartHintLines as C, writeToIpc as D, stopTipForCli as E, resolveResumeArgs as S, snapshotStatus as T, readPtysize as _, cursorAbs as a, resolveOne as b, extractTaskCounts as c, isExitRequest as d, isPidAlive as f, readNotes as g, matchKeyword as h, controlCodeFromName as i, finalizedLines as l, listRecords as m, READ_PAGE_DEFAULT as n, deriveLiveStatus as o, isSubcommand as p, cmdHelp as r, extractNeedsInput as s, GRACEFUL_EXIT_COMMANDS as t, isAgentStuck as u, renderRawLog as v, runSubcommand as w, resolveReadWindow as x, renderRawLogLines as y };
|
|
2797
|
-
//# sourceMappingURL=subcommands-
|
|
2798
|
+
//# sourceMappingURL=subcommands-BbKngO7F.js.map
|
|
@@ -4,6 +4,6 @@ import "./configShared-CEyhl0WH.js";
|
|
|
4
4
|
import "./e2e-Bfw7qL9O.js";
|
|
5
5
|
import "./webrtcLink-CBZkZ-LT.js";
|
|
6
6
|
import "./remotes-DBCvpp3B.js";
|
|
7
|
-
import { C as restartHintLines, D as writeToIpc, E as stopTipForCli, S as resolveResumeArgs, T as snapshotStatus, _ as readPtysize, a as cursorAbs, b as resolveOne, c as extractTaskCounts, d as isExitRequest, f as isPidAlive, g as readNotes, h as matchKeyword, i as controlCodeFromName, l as finalizedLines, m as listRecords, n as READ_PAGE_DEFAULT, o as deriveLiveStatus, p as isSubcommand, r as cmdHelp, s as extractNeedsInput, t as GRACEFUL_EXIT_COMMANDS, u as isAgentStuck, v as renderRawLog, w as runSubcommand, x as resolveReadWindow, y as renderRawLogLines } from "./subcommands-
|
|
7
|
+
import { C as restartHintLines, D as writeToIpc, E as stopTipForCli, S as resolveResumeArgs, T as snapshotStatus, _ as readPtysize, a as cursorAbs, b as resolveOne, c as extractTaskCounts, d as isExitRequest, f as isPidAlive, g as readNotes, h as matchKeyword, i as controlCodeFromName, l as finalizedLines, m as listRecords, n as READ_PAGE_DEFAULT, o as deriveLiveStatus, p as isSubcommand, r as cmdHelp, s as extractNeedsInput, t as GRACEFUL_EXIT_COMMANDS, u as isAgentStuck, v as renderRawLog, w as runSubcommand, x as resolveReadWindow, y as renderRawLogLines } from "./subcommands-BbKngO7F.js";
|
|
8
8
|
|
|
9
9
|
export { cmdHelp, isSubcommand, runSubcommand };
|
|
@@ -1,8 +1,8 @@
|
|
|
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-CCHuozmQ.js";
|
|
3
3
|
import { t as agentYesHome } from "./agentYesHome-_eJa3DaX.js";
|
|
4
4
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-V4qvXgAw.js";
|
|
5
|
-
import { t as PidStore } from "./pidStore-
|
|
5
|
+
import { t as PidStore } from "./pidStore-BfoBWUjc.js";
|
|
6
6
|
import { i as readGlobalPids } from "./globalPidIndex-DlmmJlO8.js";
|
|
7
7
|
import { n as register, r as sweep } from "./reaper-C-eWAxIj.js";
|
|
8
8
|
import { arch, platform } from "process";
|
|
@@ -1216,6 +1216,7 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
|
|
|
1216
1216
|
const inheritedAyPid = Number(ptyEnv.AGENT_YES_PID);
|
|
1217
1217
|
const parentPid = Number.isInteger(inheritedAyPid) && inheritedAyPid > 0 ? inheritedAyPid : void 0;
|
|
1218
1218
|
ptyEnv.AGENT_YES_PID = String(process.pid);
|
|
1219
|
+
delete ptyEnv.AGENT_YES_AGENT_ID;
|
|
1219
1220
|
if (cliConf?.env) for (const [key, raw] of Object.entries(cliConf.env)) {
|
|
1220
1221
|
let unresolved = false;
|
|
1221
1222
|
const value = raw.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g, (_, name, fallback) => {
|
|
@@ -1802,4 +1803,4 @@ function sleep(ms) {
|
|
|
1802
1803
|
|
|
1803
1804
|
//#endregion
|
|
1804
1805
|
export { removeControlCharacters as a, AgentContext as i, agentYes as n, config as r, CLIS_CONFIG as t };
|
|
1805
|
-
//# sourceMappingURL=ts-
|
|
1806
|
+
//# sourceMappingURL=ts-BzyVSzo1.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.164.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-CCHuozmQ.js.map
|
package/lab/ui/console-logic.js
CHANGED
|
@@ -153,14 +153,19 @@ export function tagsFor(e) {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// Compact git indicator from the record's `git` snapshot (server-side
|
|
156
|
-
// `git status --porcelain --branch`): "±3" changed files, "
|
|
157
|
-
//
|
|
158
|
-
//
|
|
156
|
+
// `git status --porcelain=v2 --branch`): "±3" real changed files, "⑂2"
|
|
157
|
+
// submodule pin-bumps, "⊙1" submodule internal dirt, "↑1" ahead, "↓2" behind.
|
|
158
|
+
// Pins/sub-dirt are split out of "±" so submodule drift (constant in a repo with
|
|
159
|
+
// many submodules) never buries the real file edits. Returns "" when there's no
|
|
160
|
+
// git info or the tree is clean and in sync, so a tidy repo adds no noise. Branch
|
|
161
|
+
// itself is shown via the path identity.
|
|
159
162
|
export function gitLabel(e) {
|
|
160
163
|
const g = e.git;
|
|
161
164
|
if (!g) return "";
|
|
162
165
|
const parts = [];
|
|
163
166
|
if (g.changed > 0) parts.push("±" + g.changed);
|
|
167
|
+
if (g.pins > 0) parts.push("⑂" + g.pins);
|
|
168
|
+
if (g.subDirty > 0) parts.push("⊙" + g.subDirty);
|
|
164
169
|
if (g.ahead > 0) parts.push("↑" + g.ahead);
|
|
165
170
|
if (g.behind > 0) parts.push("↓" + g.behind);
|
|
166
171
|
return parts.join(" ");
|
|
@@ -521,10 +526,21 @@ export function fitTransform(gridW, gridH, paneW, paneH) {
|
|
|
521
526
|
|
|
522
527
|
// Browser-tab title: "<glyph> <selected agent title> - agent-yes", or the bare
|
|
523
528
|
// console title when nothing is selected (blank/whitespace name). The leading
|
|
524
|
-
// glyph mirrors the agent's status dot —
|
|
525
|
-
// shows liveness at a glance
|
|
529
|
+
// glyph mirrors the agent's status dot — ⌨ needs_input ("your turn"), ⚠ stuck,
|
|
530
|
+
// ● active, ○ idle, ✗ exited — so the tab shows liveness at a glance even in a
|
|
531
|
+
// background tab; an unknown status adds no glyph.
|
|
526
532
|
export function statusGlyph(status) {
|
|
527
|
-
return status === "
|
|
533
|
+
return status === "needs_input"
|
|
534
|
+
? "⌨"
|
|
535
|
+
: status === "stuck"
|
|
536
|
+
? "⚠"
|
|
537
|
+
: status === "active"
|
|
538
|
+
? "●"
|
|
539
|
+
: status === "idle"
|
|
540
|
+
? "○"
|
|
541
|
+
: status === "exited"
|
|
542
|
+
? "✗"
|
|
543
|
+
: "";
|
|
528
544
|
}
|
|
529
545
|
export function docTitle(name, status) {
|
|
530
546
|
const n = name && String(name).trim();
|
package/lab/ui/index.html
CHANGED
|
@@ -891,6 +891,11 @@
|
|
|
891
891
|
color: var(--green);
|
|
892
892
|
border-color: #2a3a2a;
|
|
893
893
|
}
|
|
894
|
+
/* The pending question when an agent needs_input — blue accent to match the
|
|
895
|
+
needs_input dot, reading as "your turn / here's what it's asking". */
|
|
896
|
+
.detail.ask {
|
|
897
|
+
color: var(--accent);
|
|
898
|
+
}
|
|
894
899
|
.detail {
|
|
895
900
|
color: var(--muted);
|
|
896
901
|
font-size: 12.5px;
|
|
@@ -3187,13 +3192,19 @@
|
|
|
3187
3192
|
);
|
|
3188
3193
|
}
|
|
3189
3194
|
|
|
3190
|
-
// A small git chip (±changed ↑ahead ↓behind) for a row,
|
|
3191
|
-
//
|
|
3195
|
+
// A small git chip (±changed ⑂pins ⊙sub-dirty ↑ahead ↓behind) for a row,
|
|
3196
|
+
// amber when the tree has real file changes. Submodule pin-drift shows as a
|
|
3197
|
+
// muted "⑂" that never turns the chip amber, so it can't bury real edits.
|
|
3198
|
+
// Empty for clean/in-sync repos and non-git cwds — no noise.
|
|
3192
3199
|
function gitChipHtml(e) {
|
|
3193
3200
|
const label = gitLabel(e);
|
|
3194
3201
|
if (!label) return "";
|
|
3195
3202
|
const g = e.git || {};
|
|
3196
|
-
const tip =
|
|
3203
|
+
const tip =
|
|
3204
|
+
`git: ${g.changed || 0} changed file${(g.changed || 0) === 1 ? "" : "s"}` +
|
|
3205
|
+
(g.pins ? ` · ${g.pins} submodule pin-bump${g.pins === 1 ? "" : "s"}` : "") +
|
|
3206
|
+
(g.subDirty ? ` · ${g.subDirty} submodule dirty` : "") +
|
|
3207
|
+
` · ${g.ahead || 0} ahead · ${g.behind || 0} behind`;
|
|
3197
3208
|
return `<span class="git${g.dirty ? " dirty" : ""}" title="${esc(tip)}">${esc(label)}</span>`;
|
|
3198
3209
|
}
|
|
3199
3210
|
|
|
@@ -3285,7 +3296,13 @@
|
|
|
3285
3296
|
${gitChipHtml(e)}
|
|
3286
3297
|
<span class="age">${age(e)}</span></div>
|
|
3287
3298
|
${e.title ? `<div class="rowtitle" title="${esc(e.title)}">${esc(e.title)}</div>` : ""}
|
|
3288
|
-
${
|
|
3299
|
+
${
|
|
3300
|
+
e.status === "needs_input" && e.question
|
|
3301
|
+
? `<div class="detail ask" title="${esc(e.question)}">⌨ ${esc(e.question)}</div>`
|
|
3302
|
+
: e.prompt
|
|
3303
|
+
? `<div class="detail" title="${esc(e.prompt)}">${esc(e.prompt)}</div>`
|
|
3304
|
+
: ""
|
|
3305
|
+
}
|
|
3289
3306
|
<div class="rowtags">${tags}</div>
|
|
3290
3307
|
</div>`;
|
|
3291
3308
|
})
|
|
@@ -3918,7 +3935,7 @@
|
|
|
3918
3935
|
return `<div class="omni-row omni-spawn${sc}" data-i="${i}">
|
|
3919
3936
|
<span class="dot active"></span>
|
|
3920
3937
|
<div class="omni-main">
|
|
3921
|
-
<div class="omni-title">⑂ Fork <b>${esc(r.srcBranch)}</b> & run <span style="opacity:.55">(
|
|
3938
|
+
<div class="omni-title">⑂ Fork <b>${esc(r.srcBranch)}</b> & run <span style="opacity:.55">(clean — committed work only)</span></div>
|
|
3922
3939
|
<div class="omni-sub">${esc(r.fromCwd)} → new branch <b>${esc(r.branch)}</b> · ⏎ to edit & launch</div>
|
|
3923
3940
|
</div></div>`;
|
|
3924
3941
|
}
|
|
@@ -4050,14 +4067,12 @@
|
|
|
4050
4067
|
return;
|
|
4051
4068
|
}
|
|
4052
4069
|
if (row && row.kind === "fork") {
|
|
4053
|
-
// Editable at launch (auto-slug is the default)
|
|
4070
|
+
// Editable at launch (auto-slug is the default). The fork is clean —
|
|
4071
|
+
// committed work only, the source's uncommitted changes stay put.
|
|
4054
4072
|
// Fork from the source PINNED on the row (row.fromCwd), not a freshly
|
|
4055
4073
|
// re-resolved anchor — the anchor can drift as the list refreshes, but the
|
|
4056
4074
|
// branch we fork from must be the one the row was built for.
|
|
4057
|
-
const branch = prompt(
|
|
4058
|
-
"Fork to a new branch (carries your uncommitted work):",
|
|
4059
|
-
row.branch,
|
|
4060
|
-
);
|
|
4075
|
+
const branch = prompt("Fork to a new branch (clean — committed work only):", row.branch);
|
|
4061
4076
|
if (!branch || !branch.trim()) return; // cancelled — leave the omnibox open
|
|
4062
4077
|
closeOmni(false);
|
|
4063
4078
|
await spawnAndSelect(
|
package/package.json
CHANGED
package/ts/index.ts
CHANGED
|
@@ -374,6 +374,12 @@ export default async function agentYes({
|
|
|
374
374
|
const parentPid =
|
|
375
375
|
Number.isInteger(inheritedAyPid) && inheritedAyPid > 0 ? inheritedAyPid : undefined;
|
|
376
376
|
ptyEnv.AGENT_YES_PID = String(process.pid);
|
|
377
|
+
// A caller-injected AGENT_YES_AGENT_ID (from `ay serve`'s /api/spawn) is meant
|
|
378
|
+
// for THIS agent's record only — pidStore.registerProcess reads it from our own
|
|
379
|
+
// env. Strip it from the wrapped CLI's env so the agent's subagents (a nested
|
|
380
|
+
// `ay`) don't inherit it and register under the same id (which would make that
|
|
381
|
+
// id ambiguous). The wrapper's own process.env still carries it for pidStore.
|
|
382
|
+
delete ptyEnv.AGENT_YES_AGENT_ID;
|
|
377
383
|
// Inject per-CLI env (e.g. glm → Z.AI endpoint). Expand ${VAR} against the
|
|
378
384
|
// launching env; skip entries whose vars are unset so we never blank out an
|
|
379
385
|
// inherited value (e.g. ANTHROPIC_AUTH_TOKEN when ZAI_API_KEY isn't exported).
|
package/ts/pidStore.ts
CHANGED
|
@@ -77,9 +77,15 @@ export class PidStore {
|
|
|
77
77
|
const fifoFile = this.getFifoPath(pid);
|
|
78
78
|
|
|
79
79
|
// Upsert by pid. Reuse an existing record's agent id so re-registration
|
|
80
|
-
// (e.g. status churn) keeps the id stable;
|
|
80
|
+
// (e.g. status churn) keeps the id stable; else adopt a caller-injected
|
|
81
|
+
// AGENT_YES_AGENT_ID (so `ay serve`'s /api/spawn can hand back an id that
|
|
82
|
+
// addresses this exact agent — index.ts strips it from the wrapped CLI's env
|
|
83
|
+
// so subagents don't inherit it); else mint a fresh 12-hex id.
|
|
84
|
+
const injected = process.env.AGENT_YES_AGENT_ID;
|
|
81
85
|
const existing = this.store.findOne((doc) => doc.pid === pid);
|
|
82
|
-
const agentId =
|
|
86
|
+
const agentId =
|
|
87
|
+
existing?.agentId ??
|
|
88
|
+
(injected && /^[0-9a-f]{6,32}$/i.test(injected) ? injected : randomBytes(6).toString("hex"));
|
|
83
89
|
|
|
84
90
|
const record: Omit<PidRecord, "_id"> = {
|
|
85
91
|
pid,
|
package/ts/serve.ts
CHANGED
|
@@ -9,6 +9,7 @@ import yargs from "yargs";
|
|
|
9
9
|
import {
|
|
10
10
|
controlCodeFromName,
|
|
11
11
|
deriveLiveStatus,
|
|
12
|
+
extractNeedsInput,
|
|
12
13
|
extractTaskCounts,
|
|
13
14
|
listRecords,
|
|
14
15
|
readNotes,
|
|
@@ -172,12 +173,15 @@ function loginShellEnv(): Record<string, string> | null {
|
|
|
172
173
|
// Delimiters fence off the env dump from any banner/prompt noise the rc files
|
|
173
174
|
// print to stdout; `env -0` is NUL-separated so values with newlines survive.
|
|
174
175
|
const delim = "_AY_SHELL_ENV_DELIM_";
|
|
175
|
-
const res = Bun.spawnSync(
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
176
|
+
const res = Bun.spawnSync(
|
|
177
|
+
[shell, "-ilc", `printf %s "${delim}"; env -0; printf %s "${delim}"`],
|
|
178
|
+
{
|
|
179
|
+
stdin: "ignore",
|
|
180
|
+
stderr: "ignore",
|
|
181
|
+
timeout: 5_000,
|
|
182
|
+
env: process.env as Record<string, string>,
|
|
183
|
+
},
|
|
184
|
+
);
|
|
181
185
|
const out = res.stdout?.toString() ?? "";
|
|
182
186
|
const start = out.indexOf(delim);
|
|
183
187
|
const end = out.lastIndexOf(delim);
|
|
@@ -930,8 +934,37 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
930
934
|
}
|
|
931
935
|
};
|
|
932
936
|
|
|
937
|
+
// Per-agent "waiting on you" detection: the agent is parked on an interactive
|
|
938
|
+
// menu it did NOT auto-resolve (config `needsInput` patterns). Same source and
|
|
939
|
+
// classifier as `ay ls` / `ay status`, so the console's dot matches the CLI's
|
|
940
|
+
// needs_input. Cached per (size, mtime) exactly like logTitle/logTasks — each
|
|
941
|
+
// miss renders a log window through xterm, so the 1s list tick stays cheap on
|
|
942
|
+
// an idle fleet. Returns the pending question text (surfaced in the UI), or
|
|
943
|
+
// null when the agent isn't blocked.
|
|
944
|
+
const niCache = new Map<string, { size: number; mtimeMs: number; question: string | null }>();
|
|
945
|
+
const logNeedsInput = async (
|
|
946
|
+
logFile: string | null | undefined,
|
|
947
|
+
cli: string,
|
|
948
|
+
): Promise<string | null> => {
|
|
949
|
+
if (!logFile) return null;
|
|
950
|
+
try {
|
|
951
|
+
const { size, mtimeMs } = await stat(logFile);
|
|
952
|
+
const hit = niCache.get(logFile);
|
|
953
|
+
if (hit && hit.size === size && hit.mtimeMs === mtimeMs) return hit.question;
|
|
954
|
+
const ni = await extractNeedsInput(logFile, cli);
|
|
955
|
+
const question = ni?.question ?? null;
|
|
956
|
+
niCache.set(logFile, { size, mtimeMs, question });
|
|
957
|
+
return question;
|
|
958
|
+
} catch {
|
|
959
|
+
return null;
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
|
|
933
963
|
// Per-repo git snapshot for the list (branch + dirty/changed + ahead/behind, from
|
|
934
|
-
// one `git status --porcelain --branch`).
|
|
964
|
+
// one `git status --porcelain=v2 --branch`). v2 (not v1) so the submodule field
|
|
965
|
+
// lets us split real file changes from submodule pin-drift, which would otherwise
|
|
966
|
+
// inflate `changed` — in a superproject with many submodules the constant gitlink
|
|
967
|
+
// drift buries the real edits. WATCHER-INVALIDATED, not polled: a read
|
|
935
968
|
// returns the cached snapshot instantly and NEVER spawns `git status` on the
|
|
936
969
|
// request path. A per-repo-root fs watcher recomputes (debounced) only when the
|
|
937
970
|
// repo actually changes, so an idle fleet costs ~0 git processes. The old design
|
|
@@ -942,7 +975,9 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
942
975
|
interface GitInfo {
|
|
943
976
|
branch: string | null;
|
|
944
977
|
dirty: boolean;
|
|
945
|
-
changed: number;
|
|
978
|
+
changed: number; // real file changes (excludes submodule pin-bumps & internal dirt)
|
|
979
|
+
pins: number; // submodule gitlinks pointing at new commit(s) — pin-bump/drift
|
|
980
|
+
subDirty: number; // submodule has internal changes but its recorded pin is unchanged
|
|
946
981
|
ahead: number;
|
|
947
982
|
behind: number;
|
|
948
983
|
}
|
|
@@ -964,16 +999,55 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
964
999
|
}
|
|
965
1000
|
};
|
|
966
1001
|
const parseGitStatus = (out: string): GitInfo => {
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
const
|
|
975
|
-
|
|
976
|
-
|
|
1002
|
+
// porcelain=v2 --branch: "# branch.*" headers then one line per changed entry.
|
|
1003
|
+
let branch: string | null = null;
|
|
1004
|
+
let ahead = 0;
|
|
1005
|
+
let behind = 0;
|
|
1006
|
+
let changed = 0; // real file changes
|
|
1007
|
+
let pins = 0; // submodule pin-bumps (gitlink → new commit)
|
|
1008
|
+
let subDirty = 0; // submodule internal dirt, recorded pin unchanged
|
|
1009
|
+
for (const line of out.split("\n")) {
|
|
1010
|
+
if (line.length === 0) continue;
|
|
1011
|
+
if (line[0] === "#") {
|
|
1012
|
+
// "# branch.head <name|(detached)>" and "# branch.ab +A -B" (ab absent
|
|
1013
|
+
// when there's no upstream). branch.head carries the name even on an
|
|
1014
|
+
// unborn branch, so no special-casing needed.
|
|
1015
|
+
const head = /^# branch\.head (.+)$/.exec(line);
|
|
1016
|
+
if (head) {
|
|
1017
|
+
branch = head[1] === "(detached)" ? null : head[1]!;
|
|
1018
|
+
continue;
|
|
1019
|
+
}
|
|
1020
|
+
const ab = /^# branch\.ab \+(\d+) -(\d+)/.exec(line);
|
|
1021
|
+
if (ab) {
|
|
1022
|
+
ahead = Number(ab[1]);
|
|
1023
|
+
behind = Number(ab[2]);
|
|
1024
|
+
}
|
|
1025
|
+
continue;
|
|
1026
|
+
}
|
|
1027
|
+
// Changed-entry lines. Untracked ("?") and unmerged ("u") are always real
|
|
1028
|
+
// work; ignored ("!") never appears (we don't pass --ignored). For ordinary
|
|
1029
|
+
// ("1") / renamed ("2") entries the 3rd space-delimited token is the
|
|
1030
|
+
// submodule field <sub>: "N..." for a normal path, or "S<c><m><u>" for a
|
|
1031
|
+
// submodule where c=C means its gitlink moved to new commit(s) (pin-bump),
|
|
1032
|
+
// and m/u flag internal dirty/untracked with the recorded pin unchanged.
|
|
1033
|
+
// Paths (which may contain spaces) come after token 2, so counting by token
|
|
1034
|
+
// index is robust without -z.
|
|
1035
|
+
const type = line[0];
|
|
1036
|
+
if (type === "?") {
|
|
1037
|
+
changed++;
|
|
1038
|
+
} else if (type === "u") {
|
|
1039
|
+
changed++;
|
|
1040
|
+
} else if (type === "1" || type === "2") {
|
|
1041
|
+
const sub = line.split(" ")[2] ?? "N...";
|
|
1042
|
+
if (sub[0] === "S") {
|
|
1043
|
+
if (sub[1] === "C") pins++;
|
|
1044
|
+
else subDirty++;
|
|
1045
|
+
} else {
|
|
1046
|
+
changed++;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
return { branch, dirty: changed > 0, changed, pins, subDirty, ahead, behind };
|
|
977
1051
|
};
|
|
978
1052
|
// cwd -> repo root ("" = resolved, not a repo). Resolved once per cwd via a cheap
|
|
979
1053
|
// `git rev-parse --show-toplevel` (no tree scan) and cached, so many agents in the
|
|
@@ -999,7 +1073,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
999
1073
|
if (rw.busy) return void recompute(root, rw); // re-arm if one is in flight
|
|
1000
1074
|
rw.busy = true;
|
|
1001
1075
|
try {
|
|
1002
|
-
const out = await runGit(["status", "--porcelain", "--branch"], root);
|
|
1076
|
+
const out = await runGit(["status", "--porcelain=v2", "--branch"], root);
|
|
1003
1077
|
if (out != null) rw.val = parseGitStatus(out);
|
|
1004
1078
|
} finally {
|
|
1005
1079
|
rw.busy = false;
|
|
@@ -1051,12 +1125,23 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
1051
1125
|
// the LIVE status here — same liveness+log-mtime basis as `ay ls` — so the
|
|
1052
1126
|
// console's dot (and the browser tab glyph) flips to idle in step with `ay ls`.
|
|
1053
1127
|
const status = await deriveLiveStatus(r);
|
|
1128
|
+
// "Waiting on you": alive, quiet, but parked on an unanswered menu. Checked
|
|
1129
|
+
// only for live agents, and skipped when unresponsive (the Rust wedge signal
|
|
1130
|
+
// wins) — mirroring deriveLiveState's precedence in `ay ls` so the console's
|
|
1131
|
+
// dot and the CLI agree.
|
|
1132
|
+
const question =
|
|
1133
|
+
status !== "exited" && !r.unresponsive ? await logNeedsInput(r.log_file, r.cli) : null;
|
|
1054
1134
|
return {
|
|
1055
1135
|
...r,
|
|
1056
|
-
//
|
|
1057
|
-
//
|
|
1058
|
-
//
|
|
1059
|
-
|
|
1136
|
+
// Precedence: exited stays exited; the Rust supervisor's unresponsive flag is
|
|
1137
|
+
// an authoritative wedge signal (`stuck`); then a blocked menu (`needs_input`);
|
|
1138
|
+
// else the base live status — so the console's dot matches `ay ls`. (A dead
|
|
1139
|
+
// agent is never unresponsive — Rust clears the flag on exit.)
|
|
1140
|
+
status:
|
|
1141
|
+
status === "exited" ? status : r.unresponsive ? "stuck" : question ? "needs_input" : status,
|
|
1142
|
+
// The pending menu/question text when needs_input, for the console to show
|
|
1143
|
+
// WHAT the agent is waiting on. Null otherwise.
|
|
1144
|
+
question,
|
|
1060
1145
|
title: await logTitle(r.log_file),
|
|
1061
1146
|
git: status === "exited" ? null : await gitStatus(r.cwd),
|
|
1062
1147
|
// Task progress from the rendered todo block (null when none detected → no
|
|
@@ -1642,9 +1727,11 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
1642
1727
|
return new Response("fork requires a non-empty fromCwd and branch", { status: 400 });
|
|
1643
1728
|
const from = typeof body.from === "string" ? body.from.trim() : "";
|
|
1644
1729
|
if (fork) {
|
|
1645
|
-
// Fork the anchor agent's branch
|
|
1646
|
-
//
|
|
1647
|
-
//
|
|
1730
|
+
// Fork the anchor agent's branch into a new sibling worktree via
|
|
1731
|
+
// codehost/provision (git worktree off HEAD, no clone), then spawn the
|
|
1732
|
+
// agent there. The fork is clean — committed work only; the source's
|
|
1733
|
+
// uncommitted changes stay put (codehost forkWorktree defaults wip:false,
|
|
1734
|
+
// and we don't opt in).
|
|
1648
1735
|
let prov: {
|
|
1649
1736
|
forkWorktree: (o: { fromCwd: string; branch: string; wsRoot?: string }) => Promise<{
|
|
1650
1737
|
ok: boolean;
|
|
@@ -1763,6 +1850,14 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
1763
1850
|
const agentArgv = [...ayCmd, cli, ...(prompt ? ["--", prompt] : [])];
|
|
1764
1851
|
// don't leak our Claude Code session into the agent
|
|
1765
1852
|
const agentEnv = freshAgentEnv();
|
|
1853
|
+
// Correlation id: the spawn response returns the `ay` LAUNCHER pid, which is
|
|
1854
|
+
// NOT the agent's registered pid — so the caller can't find the agent it just
|
|
1855
|
+
// spawned. Mint a 12-hex id (the agent_id format), inject it as
|
|
1856
|
+
// AGENT_YES_AGENT_ID, and return it. Both runtimes adopt it as their agent_id
|
|
1857
|
+
// (instead of minting a random one) and strip it from the wrapped CLI's env so
|
|
1858
|
+
// subagents don't inherit and collide. The caller can then address the agent
|
|
1859
|
+
// immediately: `ay <verb> <remote>:<agentId>`.
|
|
1860
|
+
const agentId = randomBytes(6).toString("hex");
|
|
1766
1861
|
// Detach the agent into its OWN session (setsid). When `ay serve` runs WITH a
|
|
1767
1862
|
// controlling terminal (started in a shell rather than as a headless daemon),
|
|
1768
1863
|
// an undetached child inherits the daemon's session + controlling tty and lands
|
|
@@ -1792,7 +1887,12 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
1792
1887
|
const child = Bun.spawn([shell, "-c", script, "ay-spawn", ...agentArgv], {
|
|
1793
1888
|
cwd,
|
|
1794
1889
|
detached: true,
|
|
1795
|
-
env: {
|
|
1890
|
+
env: {
|
|
1891
|
+
...agentEnv,
|
|
1892
|
+
AGENT_YES_CWD: cwd,
|
|
1893
|
+
AGENT_YES_CLI: cli,
|
|
1894
|
+
AGENT_YES_AGENT_ID: agentId,
|
|
1895
|
+
},
|
|
1796
1896
|
stdin: "ignore",
|
|
1797
1897
|
stdout: "ignore",
|
|
1798
1898
|
stderr: Bun.file(errPath),
|
|
@@ -1829,6 +1929,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
1829
1929
|
return Response.json({
|
|
1830
1930
|
ok: true,
|
|
1831
1931
|
pid: child.pid,
|
|
1932
|
+
agentId,
|
|
1832
1933
|
cli,
|
|
1833
1934
|
cwd,
|
|
1834
1935
|
hook: true,
|
|
@@ -1838,7 +1939,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
1838
1939
|
const child = Bun.spawn(agentArgv, {
|
|
1839
1940
|
cwd,
|
|
1840
1941
|
detached: true,
|
|
1841
|
-
env: agentEnv,
|
|
1942
|
+
env: { ...agentEnv, AGENT_YES_AGENT_ID: agentId },
|
|
1842
1943
|
stdin: "ignore",
|
|
1843
1944
|
stdout: "ignore",
|
|
1844
1945
|
stderr: "ignore",
|
|
@@ -1847,6 +1948,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
1847
1948
|
return Response.json({
|
|
1848
1949
|
ok: true,
|
|
1849
1950
|
pid: child.pid,
|
|
1951
|
+
agentId,
|
|
1850
1952
|
cli,
|
|
1851
1953
|
cwd,
|
|
1852
1954
|
...(provisioned ? { provisioned } : {}),
|
package/ts/subcommands.ts
CHANGED
|
@@ -897,6 +897,7 @@ async function runRemoteSpawn(
|
|
|
897
897
|
pid: number;
|
|
898
898
|
cli: string;
|
|
899
899
|
cwd: string;
|
|
900
|
+
agentId?: string;
|
|
900
901
|
hook?: boolean;
|
|
901
902
|
provisioned?: { action: string };
|
|
902
903
|
};
|
|
@@ -905,15 +906,19 @@ async function runRemoteSpawn(
|
|
|
905
906
|
`${r.hook ? " (via spawn hook)" : ""}` +
|
|
906
907
|
`${r.provisioned ? ` (${r.provisioned.action})` : ""}\n`,
|
|
907
908
|
);
|
|
908
|
-
//
|
|
909
|
-
//
|
|
910
|
-
//
|
|
911
|
-
//
|
|
912
|
-
//
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
909
|
+
// `/api/spawn` returns a correlation `agentId` that the agent adopts as its
|
|
910
|
+
// agent_id — so we address the EXACT agent by it (no pid guessing, no race). A
|
|
911
|
+
// webrtc:// / share-link target isn't `:keyword`-addressable, so the keyword
|
|
912
|
+
// hint is only for an alias / token@host:port. Older remotes omit agentId →
|
|
913
|
+
// fall back to pointing at `ay ls`.
|
|
914
|
+
if (r.agentId && !hint.includes("://")) {
|
|
915
|
+
process.stderr.write(
|
|
916
|
+
`\n ay tail ${hint}:${r.agentId} # watch its output\n` +
|
|
917
|
+
` ay status ${hint}:${r.agentId} --wait # block until it needs you\n`,
|
|
918
|
+
);
|
|
919
|
+
} else {
|
|
920
|
+
process.stderr.write(`\n ay ls ${hint} # the new ${r.cli} agent appears here\n`);
|
|
921
|
+
}
|
|
917
922
|
return 0;
|
|
918
923
|
}
|
|
919
924
|
|
|
@@ -2258,7 +2263,7 @@ async function cmdSend(rest: string[]): Promise<number> {
|
|
|
2258
2263
|
const fifoPath = record.fifo_file;
|
|
2259
2264
|
if (!fifoPath) {
|
|
2260
2265
|
throw new Error(
|
|
2261
|
-
`pid ${record.pid}: no fifo_file recorded — agent
|
|
2266
|
+
`pid ${record.pid}: no fifo_file recorded — this agent didn't register a stdin FIFO (an older agent, or one not started with --stdpush). Restarting it (ay restart ${record.pid}) re-registers one.`,
|
|
2262
2267
|
);
|
|
2263
2268
|
}
|
|
2264
2269
|
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import "./ts-CRo3qQWb.js";
|
|
2
|
-
import "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import "./versionChecker-DrjR4P0K.js";
|
|
4
|
-
import "./pidStore-fqXqTKkh.js";
|
|
5
|
-
import "./globalPidIndex-DlmmJlO8.js";
|
|
6
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DYTnLX8C.js";
|
|
7
|
-
|
|
8
|
-
export { SUPPORTED_CLIS };
|