agent-yes 1.257.0 → 1.258.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-BPPX9iGs.js → SUPPORTED_CLIS-DTjWc_om.js} +2 -2
- package/dist/{SUPPORTED_CLIS-BNRnFFc2.js → SUPPORTED_CLIS-Dov9qOQf.js} +3 -3
- package/dist/{agentShare-aCSONMZp.js → agentShare-n39adLst.js} +2 -2
- package/dist/{callback-CpGhgUwm.js → callback-irtAFEXY.js} +3 -3
- package/dist/{callback-CzYsRWjX.js → callback-tnnB0ibj.js} +2 -2
- package/dist/cli.js +5 -5
- package/dist/index.js +2 -2
- package/dist/{notifyDaemon-Cvnvfqw8.js → notifyDaemon-BKaX7tHT.js} +2 -2
- package/dist/{rustBinary-DWzZGM4A.js → rustBinary-BjMf3hJs.js} +2 -2
- package/dist/{schedule-ChwwFCgQ.js → schedule-D19dfoUv.js} +4 -4
- package/dist/{serve-DQPkrKcN.js → serve-CrQavO4J.js} +16 -16
- package/dist/{setup-uZqYF0KT.js → setup-D1en_TN3.js} +2 -2
- package/dist/subcommands-B7iBIPXn.js +10 -0
- package/dist/{subcommands-B04Jcb4a.js → subcommands-bd-cHNKW.js} +69 -26
- package/dist/{terminal-sCD-7D_2.js → terminal-eRiT4Zbo.js} +2 -2
- package/dist/{trayApp-CCN3zyo7.js → trayApp-BBNKEQbP.js} +2 -2
- package/dist/trayApp-Cef9w_n4.js +5 -0
- package/dist/{ts-Ct3yd-1m.js → ts-CvUvWb2n.js} +29 -4
- package/dist/{versionChecker-bcw3nJay.js → versionChecker-BKFAk759.js} +2 -2
- package/dist/{widget-B7NK6egy.js → widget-C1GqFymh.js} +3 -3
- package/dist/{ws-BkOJQeeZ.js → ws-CWPlW7ia.js} +2 -2
- package/dist/{ws-BlISbGY8.js → ws-DgHuhAPq.js} +2 -2
- package/lab/ui/console-logic.js +6 -3
- package/lab/ui/index.html +27 -5
- package/package.json +1 -1
- package/ts/index.ts +42 -2
- package/ts/needsInput.spec.ts +38 -0
- package/ts/needsInput.ts +7 -3
- package/ts/serve.ts +2 -1
- package/ts/subcommands.spec.ts +26 -0
- package/ts/subcommands.ts +63 -6
- package/ts/todoParse.spec.ts +30 -0
- package/ts/todoParse.ts +19 -5
- package/dist/subcommands-dNgWfaKE.js +0 -10
- package/dist/trayApp-HLGzyGrP.js +0 -5
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { t as CLIS_CONFIG } from "./ts-CvUvWb2n.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-DTjWc_om.js.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import "./ts-
|
|
2
|
+
import "./versionChecker-BKFAk759.js";
|
|
3
|
+
import "./ts-CvUvWb2n.js";
|
|
4
4
|
import "./todoAutomation-BQRW614S.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-Dq4KY2IV.js";
|
|
7
7
|
import "./pidStore-Cmcc8Oej.js";
|
|
8
8
|
import "./messageLog-BYFwioFY.js";
|
|
9
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
9
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DTjWc_om.js";
|
|
10
10
|
|
|
11
11
|
export { SUPPORTED_CLIS };
|
|
@@ -3,7 +3,7 @@ import "./globalPidIndex-Dq4KY2IV.js";
|
|
|
3
3
|
import "./messageLog-BYFwioFY.js";
|
|
4
4
|
import "./e2e-CUMZC53I.js";
|
|
5
5
|
import "./configShared-DtHMBCl7.js";
|
|
6
|
-
import {
|
|
6
|
+
import { I as resolveOne } from "./subcommands-bd-cHNKW.js";
|
|
7
7
|
import "./webrtcLink-CS4D-3G1.js";
|
|
8
8
|
import "./remotes-Dy4Rg8Yp.js";
|
|
9
9
|
import { a as startShare } from "./share-B-e_9WBx.js";
|
|
@@ -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-n39adLst.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
|
|
2
|
-
import {
|
|
2
|
+
import { I as resolveOne } from "./subcommands-bd-cHNKW.js";
|
|
3
3
|
import { a as mintCapability, o as parseExpires } from "./callbackCore-Cg3Ye0ZS.js";
|
|
4
4
|
import { randomBytes } from "node:crypto";
|
|
5
5
|
import { chmodSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
@@ -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-CrQavO4J.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-irtAFEXY.js.map
|
|
@@ -3,10 +3,10 @@ import "./globalPidIndex-Dq4KY2IV.js";
|
|
|
3
3
|
import "./messageLog-BYFwioFY.js";
|
|
4
4
|
import "./e2e-CUMZC53I.js";
|
|
5
5
|
import "./configShared-DtHMBCl7.js";
|
|
6
|
-
import "./subcommands-
|
|
6
|
+
import "./subcommands-bd-cHNKW.js";
|
|
7
7
|
import "./webrtcLink-CS4D-3G1.js";
|
|
8
8
|
import "./remotes-Dy4Rg8Yp.js";
|
|
9
9
|
import "./callbackCore-Cg3Ye0ZS.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-irtAFEXY.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 { r as getRustBinary } from "./rustBinary-
|
|
4
|
+
import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-BKFAk759.js";
|
|
5
|
+
import { r as getRustBinary } from "./rustBinary-BjMf3hJs.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, isUnknownManagerToken } = await import("./subcommands-
|
|
288
|
+
const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken } = await import("./subcommands-B7iBIPXn.js");
|
|
289
289
|
if (isHelpFlag && process.argv.length === 3) {
|
|
290
290
|
await cmdHelp(managerCommands);
|
|
291
291
|
process.exit(0);
|
|
@@ -295,7 +295,7 @@ function buildRustArgs(argv, cliFromScript, supportedClis) {
|
|
|
295
295
|
process.exit(code ?? 0);
|
|
296
296
|
}
|
|
297
297
|
{
|
|
298
|
-
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-
|
|
298
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-Dov9qOQf.js");
|
|
299
299
|
if (isUnknownManagerToken(rawArg, managerCommands, SUPPORTED_CLIS)) {
|
|
300
300
|
process.stderr.write(`ay: unknown subcommand or CLI '${rawArg}'.\n See 'ay help' for subcommands. To run an agent, name a CLI:\n 'ay <cli> …' (e.g. 'ay claude …') or 'ay --cli <cli> …'.\n`);
|
|
301
301
|
process.exit(1);
|
|
@@ -346,7 +346,7 @@ if (config.useRust) {
|
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
if (rustBinary) {
|
|
349
|
-
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-
|
|
349
|
+
const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-Dov9qOQf.js");
|
|
350
350
|
const rustArgs = buildRustArgs(process.argv, config.cli, SUPPORTED_CLIS);
|
|
351
351
|
if (config.verbose) {
|
|
352
352
|
console.log(`[rust] Using binary: ${rustBinary}`);
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-
|
|
2
|
+
import "./versionChecker-BKFAk759.js";
|
|
3
|
+
import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-CvUvWb2n.js";
|
|
4
4
|
import { _ as isKnownKind, a as renderTree, b as statesOf, c as monitorHint, d as openStore, f as DONE_STATE, g as initialState, h as canTransition, i as renderDigest, l as CycleError, m as ORPHANED_STATE, o as unblockedTasks, p as LIFECYCLES, r as openBlockers, s as describeBlock, t as reconcileTodos, u as TodoStore, v as nextStates, x as removeControlCharacters, y as requiredGate } from "./todoAutomation-BQRW614S.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-Dq4KY2IV.js";
|
|
@@ -3,7 +3,7 @@ import "./globalPidIndex-Dq4KY2IV.js";
|
|
|
3
3
|
import "./messageLog-BYFwioFY.js";
|
|
4
4
|
import "./e2e-CUMZC53I.js";
|
|
5
5
|
import "./configShared-DtHMBCl7.js";
|
|
6
|
-
import { $ as
|
|
6
|
+
import { $ as liveWatchers, J as appendEvent, N as renderLogTailLines, Q as listInboxParents, X as hostId, Y as gcInboxes, et as readInbox, it as notifyDir, l as deriveLiveState, nt as daemonLockDir, rt as daemonLockOwnerPath, tt as shouldStealLock, v as isPidAlive, w as listRecords } from "./subcommands-bd-cHNKW.js";
|
|
7
7
|
import "./webrtcLink-CS4D-3G1.js";
|
|
8
8
|
import "./remotes-Dy4Rg8Yp.js";
|
|
9
9
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
|
|
@@ -836,4 +836,4 @@ async function ensureDaemon() {
|
|
|
836
836
|
|
|
837
837
|
//#endregion
|
|
838
838
|
export { daemonStatus, ensureDaemon, requestDaemonStop, runDaemon };
|
|
839
|
-
//# sourceMappingURL=notifyDaemon-
|
|
839
|
+
//# sourceMappingURL=notifyDaemon-BKaX7tHT.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
1
|
+
import { r as getInstalledPackage } from "./versionChecker-BKFAk759.js";
|
|
2
2
|
import { execFileSync } from "child_process";
|
|
3
3
|
import { existsSync, mkdirSync, unlinkSync } from "fs";
|
|
4
4
|
import { chmod, copyFile } from "fs/promises";
|
|
@@ -243,4 +243,4 @@ async function getRustBinary(options = {}) {
|
|
|
243
243
|
|
|
244
244
|
//#endregion
|
|
245
245
|
export { findTrayLauncher as n, getRustBinary as r, findSpawnHiddenLauncher as t };
|
|
246
|
-
//# sourceMappingURL=rustBinary-
|
|
246
|
+
//# sourceMappingURL=rustBinary-BjMf3hJs.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import "./ts-
|
|
2
|
+
import "./versionChecker-BKFAk759.js";
|
|
3
|
+
import "./ts-CvUvWb2n.js";
|
|
4
4
|
import "./todoAutomation-BQRW614S.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-Dq4KY2IV.js";
|
|
7
7
|
import "./pidStore-Cmcc8Oej.js";
|
|
8
8
|
import "./messageLog-BYFwioFY.js";
|
|
9
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
9
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DTjWc_om.js";
|
|
10
10
|
import { f as resolveSpawnCwd } from "./workspaceConfig-Bxuk_MOq.js";
|
|
11
11
|
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-vhOBffJ3.js";
|
|
12
12
|
import { createHash } from "node:crypto";
|
|
@@ -153,4 +153,4 @@ async function cmdSchedule(rest) {
|
|
|
153
153
|
|
|
154
154
|
//#endregion
|
|
155
155
|
export { cmdSchedule };
|
|
156
|
-
//# sourceMappingURL=schedule-
|
|
156
|
+
//# sourceMappingURL=schedule-D19dfoUv.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
3
|
-
import { t as findSpawnHiddenLauncher } from "./rustBinary-
|
|
4
|
-
import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-BKFAk759.js";
|
|
3
|
+
import { t as findSpawnHiddenLauncher } from "./rustBinary-BjMf3hJs.js";
|
|
4
|
+
import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-CvUvWb2n.js";
|
|
5
5
|
import { t as agentYesHome$1 } from "./agentYesHome-CtmsY6I-.js";
|
|
6
6
|
import { x as removeControlCharacters } from "./todoAutomation-BQRW614S.js";
|
|
7
7
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
@@ -11,17 +11,17 @@ import { r as recordInbox } from "./messageLog-BYFwioFY.js";
|
|
|
11
11
|
import { t as pgidForWrapper } from "./reaper-C4BvNylH.js";
|
|
12
12
|
import "./e2e-CUMZC53I.js";
|
|
13
13
|
import "./configShared-DtHMBCl7.js";
|
|
14
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
15
|
-
import { A as
|
|
14
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DTjWc_om.js";
|
|
15
|
+
import { A as readPtysize, F as renderRawLogLines, I as resolveOne, M as recentReadEdges, N as renderLogTailLines, O as readLogForRender, P as renderRawLog, S as isUserTyping, V as snapshotStatus, Z as isTransientLockMkdirError, at as TYPING_BADGE, d as extractBadges, j as recentMessageEdges, k as readNotes, m as extractTaskCounts, p as extractNeedsInput, q as writeToIpc, s as controlCodeFromName, u as deriveLiveStatus, w as listRecords } from "./subcommands-bd-cHNKW.js";
|
|
16
16
|
import "./webrtcLink-CS4D-3G1.js";
|
|
17
17
|
import "./remotes-Dy4Rg8Yp.js";
|
|
18
18
|
import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-Cg3Ye0ZS.js";
|
|
19
|
-
import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-
|
|
19
|
+
import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-irtAFEXY.js";
|
|
20
20
|
import { a as getProvisionRoot, d as isProvisionAllowed, f as resolveSpawnCwd, i as getProvisionHook, l as hasProvisionHook, o as getSpawnHook, t as allowsSkipPermissions, u as hasSpawnHook } from "./workspaceConfig-Bxuk_MOq.js";
|
|
21
21
|
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-vhOBffJ3.js";
|
|
22
|
-
import { i as importProvisionModule } from "./ws-
|
|
22
|
+
import { i as importProvisionModule } from "./ws-DgHuhAPq.js";
|
|
23
23
|
import { r as spawnRejectionReason } from "./spawnGate-D0E1uRP7.js";
|
|
24
|
-
import { i as launchTray } from "./trayApp-
|
|
24
|
+
import { i as launchTray } from "./trayApp-BBNKEQbP.js";
|
|
25
25
|
import yargs from "yargs";
|
|
26
26
|
import { appendFile, mkdir, open, readFile, readdir, rename, rm, stat, unlink, writeFile } from "fs/promises";
|
|
27
27
|
import { arch, cpus, freemem, homedir, hostname, loadavg, platform, totalmem, uptime, userInfo } from "os";
|
|
@@ -2368,7 +2368,7 @@ Options:
|
|
|
2368
2368
|
}
|
|
2369
2369
|
});
|
|
2370
2370
|
if (req.method === "GET" && p === "/api/ws") {
|
|
2371
|
-
const ws = await import("./ws-
|
|
2371
|
+
const ws = await import("./ws-CWPlW7ia.js");
|
|
2372
2372
|
try {
|
|
2373
2373
|
await ws.loadProvision();
|
|
2374
2374
|
} catch (e) {
|
|
@@ -2388,7 +2388,7 @@ Options:
|
|
|
2388
2388
|
if (req.method === "GET" && p === "/api/ws/status") {
|
|
2389
2389
|
const dirRaw = url.searchParams.get("path");
|
|
2390
2390
|
if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
|
|
2391
|
-
const ws = await import("./ws-
|
|
2391
|
+
const ws = await import("./ws-CWPlW7ia.js");
|
|
2392
2392
|
let prov;
|
|
2393
2393
|
try {
|
|
2394
2394
|
prov = await ws.loadProvision();
|
|
@@ -2431,7 +2431,7 @@ Options:
|
|
|
2431
2431
|
try {
|
|
2432
2432
|
const record = await resolveOne(keyword, defaultOpts());
|
|
2433
2433
|
if (!record.log_file) return new Response(`pid ${record.pid}: no log_file`, { status: 404 });
|
|
2434
|
-
const buf = await
|
|
2434
|
+
const buf = await readLogForRender(record.log_file);
|
|
2435
2435
|
const size = await readPtysize(record.pid);
|
|
2436
2436
|
const text = await renderRawLog(buf, {
|
|
2437
2437
|
mode,
|
|
@@ -3145,7 +3145,7 @@ Options:
|
|
|
3145
3145
|
const perm = body.perm ?? "r";
|
|
3146
3146
|
if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
|
|
3147
3147
|
try {
|
|
3148
|
-
const { createScopedShare } = await import("./agentShare-
|
|
3148
|
+
const { createScopedShare } = await import("./agentShare-n39adLst.js");
|
|
3149
3149
|
const share = await createScopedShare({
|
|
3150
3150
|
agent: body.agent,
|
|
3151
3151
|
perm,
|
|
@@ -3160,12 +3160,12 @@ Options:
|
|
|
3160
3160
|
}
|
|
3161
3161
|
}
|
|
3162
3162
|
if (req.method === "GET" && p === "/api/shares") {
|
|
3163
|
-
const { listShares } = await import("./agentShare-
|
|
3163
|
+
const { listShares } = await import("./agentShare-n39adLst.js");
|
|
3164
3164
|
return Response.json(listShares());
|
|
3165
3165
|
}
|
|
3166
3166
|
const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
|
|
3167
3167
|
if (req.method === "DELETE" && revokeM) {
|
|
3168
|
-
const { revokeShare } = await import("./agentShare-
|
|
3168
|
+
const { revokeShare } = await import("./agentShare-n39adLst.js");
|
|
3169
3169
|
const ok = revokeShare(decodeURIComponent(revokeM[1]));
|
|
3170
3170
|
return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
|
|
3171
3171
|
}
|
|
@@ -3467,7 +3467,7 @@ Options:
|
|
|
3467
3467
|
const shutdown = (resolve) => {
|
|
3468
3468
|
if (heartbeat) clearInterval(heartbeat);
|
|
3469
3469
|
closeShare?.();
|
|
3470
|
-
import("./agentShare-
|
|
3470
|
+
import("./agentShare-n39adLst.js").then((m) => m.revokeAllShares()).catch(() => {});
|
|
3471
3471
|
server?.stop();
|
|
3472
3472
|
Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
|
|
3473
3473
|
};
|
|
@@ -3480,4 +3480,4 @@ Options:
|
|
|
3480
3480
|
|
|
3481
3481
|
//#endregion
|
|
3482
3482
|
export { cmdServe, loadTokenReadOnly, mintScopedTermToken, resolveDaemonHttpBase, resolveLocalServeUrl };
|
|
3483
|
-
//# sourceMappingURL=serve-
|
|
3483
|
+
//# sourceMappingURL=serve-CrQavO4J.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-CrQavO4J.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-D1en_TN3.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "./logger-CDIsZ-Pp.js";
|
|
2
|
+
import "./globalPidIndex-Dq4KY2IV.js";
|
|
3
|
+
import "./messageLog-BYFwioFY.js";
|
|
4
|
+
import "./e2e-CUMZC53I.js";
|
|
5
|
+
import "./configShared-DtHMBCl7.js";
|
|
6
|
+
import { A as readPtysize, B as runSubcommand, C as lastStdinAt, D as readAgentPtysize, E as menuSelectKeys, F as renderRawLogLines, G as waitForLogQuiet, H as stdinActivityPath, I as resolveOne, K as writeKeysPaced, L as resolveReadWindow, M as recentReadEdges, N as renderLogTailLines, O as readLogForRender, P as renderRawLog, R as resolveResumeArgs, S as isUserTyping, T as matchKeyword, U as stopTipForCli, V as snapshotStatus, W as submitAndConfirm, _ as isExitRequest, a as backoffWhileTyping, b as isSubcommand, c as cursorAbs, d as extractBadges, f as extractMenu, g as isAgentStuck, h as finalizedLines, i as TYPING_WINDOW_MS, j as recentMessageEdges, k as readNotes, l as deriveLiveState, m as extractTaskCounts, n as MAX_RENDER_BYTES, o as cmdHelp, p as extractNeedsInput, q as writeToIpc, r as READ_PAGE_DEFAULT, s as controlCodeFromName, t as GRACEFUL_EXIT_COMMANDS, u as deriveLiveStatus, v as isPidAlive, w as listRecords, x as isUnknownManagerToken, y as isSlashCommand, z as restartHintLines } from "./subcommands-bd-cHNKW.js";
|
|
7
|
+
import "./webrtcLink-CS4D-3G1.js";
|
|
8
|
+
import "./remotes-Dy4Rg8Yp.js";
|
|
9
|
+
|
|
10
|
+
export { cmdHelp, isSubcommand, isUnknownManagerToken, runSubcommand };
|
|
@@ -120,15 +120,19 @@ function markerOf(line) {
|
|
|
120
120
|
if (PENDING.has(ch)) return "pending";
|
|
121
121
|
return null;
|
|
122
122
|
}
|
|
123
|
+
function isBareAnchor(line) {
|
|
124
|
+
const s = line.trim();
|
|
125
|
+
return s.startsWith(ANCHOR) && s.slice(1).trim() === "";
|
|
126
|
+
}
|
|
123
127
|
/**
|
|
124
128
|
* Find the MOST RECENT confidently-detected todo block in the rendered lines and
|
|
125
129
|
* return its {done, total}. Returns null when none qualifies (caller omits the
|
|
126
130
|
* badge entirely — never shows "0/0").
|
|
127
131
|
*
|
|
128
132
|
* A block is a maximal run of consecutive marker lines. It only counts when it
|
|
129
|
-
* is anchored — the `⎿` glyph
|
|
130
|
-
* directly above it — and has ≥2 marker lines. The last qualifying block
|
|
131
|
-
* since the agent's current todo state is the one drawn most recently.
|
|
133
|
+
* is anchored — the `⎿` glyph sits on the run's FIRST line, or a bare `⎿` sits on
|
|
134
|
+
* the line directly above it — and has ≥2 marker lines. The last qualifying block
|
|
135
|
+
* wins, since the agent's current todo state is the one drawn most recently.
|
|
132
136
|
*/
|
|
133
137
|
function parseTaskCounts(lines) {
|
|
134
138
|
let best = null;
|
|
@@ -139,7 +143,7 @@ function parseTaskCounts(lines) {
|
|
|
139
143
|
i++;
|
|
140
144
|
continue;
|
|
141
145
|
}
|
|
142
|
-
let hasAnchor = i > 0 && lines[i - 1]
|
|
146
|
+
let hasAnchor = i > 0 && isBareAnchor(lines[i - 1]);
|
|
143
147
|
const counts = {
|
|
144
148
|
done: 0,
|
|
145
149
|
inprogress: 0,
|
|
@@ -149,7 +153,7 @@ function parseTaskCounts(lines) {
|
|
|
149
153
|
for (; j < n; j++) {
|
|
150
154
|
const mk = markerOf(lines[j]);
|
|
151
155
|
if (mk === null) break;
|
|
152
|
-
if (lines[j].includes(ANCHOR)) hasAnchor = true;
|
|
156
|
+
if (j === i && lines[j].includes(ANCHOR)) hasAnchor = true;
|
|
153
157
|
counts[mk]++;
|
|
154
158
|
}
|
|
155
159
|
const total = counts.done + counts.inprogress + counts.pending;
|
|
@@ -277,7 +281,7 @@ function classifyNeedsInput(lines, cfg) {
|
|
|
277
281
|
const end = Math.min(lines.length, last + 6);
|
|
278
282
|
return { question: lines.slice(start, end).map((l) => l.trim()).filter((l) => l && !isChromeLine(l)).join(" • ").slice(0, 400) };
|
|
279
283
|
}
|
|
280
|
-
const OPTION_LINE = /^[\s
|
|
284
|
+
const OPTION_LINE = /^[\s❯›>▶◉○●·│*-]*?(\d+)\.\s/;
|
|
281
285
|
/**
|
|
282
286
|
* Parse the selection menu a `needs_input` agent is parked on into a cursor
|
|
283
287
|
* position + the available option numbers, so a caller can compute how far the
|
|
@@ -1394,35 +1398,35 @@ async function runSubcommand(argv) {
|
|
|
1394
1398
|
return cmdCh(rest);
|
|
1395
1399
|
}
|
|
1396
1400
|
case "term": {
|
|
1397
|
-
const { cmdTerm } = await import("./terminal-
|
|
1401
|
+
const { cmdTerm } = await import("./terminal-eRiT4Zbo.js");
|
|
1398
1402
|
return cmdTerm(rest);
|
|
1399
1403
|
}
|
|
1400
1404
|
case "widget": {
|
|
1401
|
-
const { cmdWidget } = await import("./widget-
|
|
1405
|
+
const { cmdWidget } = await import("./widget-C1GqFymh.js");
|
|
1402
1406
|
return cmdWidget(rest);
|
|
1403
1407
|
}
|
|
1404
1408
|
case "mint": {
|
|
1405
|
-
const { cmdMint } = await import("./widget-
|
|
1409
|
+
const { cmdMint } = await import("./widget-C1GqFymh.js");
|
|
1406
1410
|
return cmdMint(rest);
|
|
1407
1411
|
}
|
|
1408
1412
|
case "serve": {
|
|
1409
|
-
const { cmdServe } = await import("./serve-
|
|
1413
|
+
const { cmdServe } = await import("./serve-CrQavO4J.js");
|
|
1410
1414
|
return cmdServe(rest);
|
|
1411
1415
|
}
|
|
1412
1416
|
case "tray": {
|
|
1413
|
-
const { cmdTray } = await import("./trayApp-
|
|
1417
|
+
const { cmdTray } = await import("./trayApp-Cef9w_n4.js");
|
|
1414
1418
|
return cmdTray(rest);
|
|
1415
1419
|
}
|
|
1416
1420
|
case "setup": {
|
|
1417
|
-
const { cmdSetup } = await import("./setup-
|
|
1421
|
+
const { cmdSetup } = await import("./setup-D1en_TN3.js");
|
|
1418
1422
|
return cmdSetup(rest);
|
|
1419
1423
|
}
|
|
1420
1424
|
case "ws": {
|
|
1421
|
-
const { cmdWs } = await import("./ws-
|
|
1425
|
+
const { cmdWs } = await import("./ws-CWPlW7ia.js");
|
|
1422
1426
|
return cmdWs(rest);
|
|
1423
1427
|
}
|
|
1424
1428
|
case "schedule": {
|
|
1425
|
-
const { cmdSchedule } = await import("./schedule-
|
|
1429
|
+
const { cmdSchedule } = await import("./schedule-D19dfoUv.js");
|
|
1426
1430
|
return cmdSchedule(rest);
|
|
1427
1431
|
}
|
|
1428
1432
|
case "remote": {
|
|
@@ -1434,7 +1438,7 @@ async function runSubcommand(argv) {
|
|
|
1434
1438
|
return cmdExpose(rest);
|
|
1435
1439
|
}
|
|
1436
1440
|
case "callback": {
|
|
1437
|
-
const { cmdCallback } = await import("./callback-
|
|
1441
|
+
const { cmdCallback } = await import("./callback-tnnB0ibj.js");
|
|
1438
1442
|
return cmdCallback(rest);
|
|
1439
1443
|
}
|
|
1440
1444
|
case "reap":
|
|
@@ -2452,7 +2456,7 @@ async function cmdRead(rest, { mode }) {
|
|
|
2452
2456
|
throw new Error(`pid ${record.pid}: log file not found at ${logPath}`);
|
|
2453
2457
|
}
|
|
2454
2458
|
if (!stats.isFile()) throw new Error(`pid ${record.pid}: log path is not a file: ${logPath}`);
|
|
2455
|
-
const buf = await
|
|
2459
|
+
const buf = await readLogForRender(logPath);
|
|
2456
2460
|
const size = await readAgentPtysize(record);
|
|
2457
2461
|
const noteLabel = (await readNotes()).get(record.pid);
|
|
2458
2462
|
const header = noteLabel ? `[pid ${record.pid} ${shortenPath(record.cwd)} * ${noteLabel}]` : `[pid ${record.pid} ${shortenPath(record.cwd)}]`;
|
|
@@ -2467,7 +2471,7 @@ async function cmdRead(rest, { mode }) {
|
|
|
2467
2471
|
process.stdout.write(rendered);
|
|
2468
2472
|
if (!rendered.endsWith("\n")) process.stdout.write("\n");
|
|
2469
2473
|
setInterval(() => void recordRead(reader.key, record.pid), 3e4).unref?.();
|
|
2470
|
-
return plain ? followPlainLocal(logPath, buf) : followRawLocal(logPath, buf);
|
|
2474
|
+
return plain ? followPlainLocal(logPath, buf, stats.size) : followRawLocal(logPath, buf, stats.size);
|
|
2471
2475
|
}
|
|
2472
2476
|
const allLines = await renderRawLogLines(buf, {
|
|
2473
2477
|
cols: size?.cols,
|
|
@@ -2585,11 +2589,11 @@ async function watchAppend(logPath, startOffset, onChunk, onStop) {
|
|
|
2585
2589
|
* sequences stripped. Mirrors the historical behaviour, plus prompt signal /
|
|
2586
2590
|
* pipe-close handling.
|
|
2587
2591
|
*/
|
|
2588
|
-
async function followRawLocal(logPath, buf) {
|
|
2592
|
+
async function followRawLocal(logPath, buf, startOffset = buf.length) {
|
|
2589
2593
|
process.stderr.write(`following... (Ctrl-C to stop)\n`);
|
|
2590
2594
|
const ansiRe = /\x1b\[[0-?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-Z\\-_]/g;
|
|
2591
2595
|
const ctrlRe = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
2592
|
-
await watchAppend(logPath,
|
|
2596
|
+
await watchAppend(logPath, startOffset, (chunk) => {
|
|
2593
2597
|
const text = new TextDecoder().decode(chunk).replace(ansiRe, "").replace(ctrlRe, "");
|
|
2594
2598
|
if (text.trim()) process.stdout.write(text.trimStart());
|
|
2595
2599
|
}, () => {});
|
|
@@ -2623,7 +2627,7 @@ function finalizedLines(term, fromAbs) {
|
|
|
2623
2627
|
* settled, so the output is clean, newline-terminated, line-buffered text a
|
|
2624
2628
|
* script can read. On stop, flush the line the cursor is still sitting on.
|
|
2625
2629
|
*/
|
|
2626
|
-
async function followPlainLocal(logPath, buf) {
|
|
2630
|
+
async function followPlainLocal(logPath, buf, startOffset = buf.length) {
|
|
2627
2631
|
process.stderr.write(`following... (plain; Ctrl-C / SIGTERM to stop)\n`);
|
|
2628
2632
|
const { Terminal } = await import("@xterm/headless");
|
|
2629
2633
|
const term = new Terminal({
|
|
@@ -2643,7 +2647,7 @@ async function followPlainLocal(logPath, buf) {
|
|
|
2643
2647
|
for (const line of finalizedLines(term, emitted)) process.stdout.write(line + "\n");
|
|
2644
2648
|
emitted = cursorAbs(term);
|
|
2645
2649
|
};
|
|
2646
|
-
await watchAppend(logPath,
|
|
2650
|
+
await watchAppend(logPath, startOffset, async (chunk) => {
|
|
2647
2651
|
await feed(chunk);
|
|
2648
2652
|
flushCommitted();
|
|
2649
2653
|
}, () => {
|
|
@@ -2686,6 +2690,45 @@ async function readAgentPtysize(record) {
|
|
|
2686
2690
|
return null;
|
|
2687
2691
|
}
|
|
2688
2692
|
/**
|
|
2693
|
+
* Cap on how many trailing bytes of a raw PTY log we read before rendering.
|
|
2694
|
+
*
|
|
2695
|
+
* `renderRawLogLines` replays the bytes through an xterm with a fixed 50000-line
|
|
2696
|
+
* scrollback, so output older than the last ~50k lines is evicted from the result
|
|
2697
|
+
* no matter how much we read. A runaway CLI/TUI capture can reach ~1GB; slurping
|
|
2698
|
+
* the whole file only to throw ~all of it away is a large memory + CPU spike (a
|
|
2699
|
+
* ~1GB Buffer plus a full-stream vterm replay per request). 64 MiB comfortably
|
|
2700
|
+
* overflows the scrollback for any realistic terminal stream, so an oversized log
|
|
2701
|
+
* renders to the SAME lines while the allocation stays bounded.
|
|
2702
|
+
*/
|
|
2703
|
+
const MAX_RENDER_BYTES = 64 * 1024 * 1024;
|
|
2704
|
+
/**
|
|
2705
|
+
* Read a raw PTY log for full-buffer rendering, capped to the trailing
|
|
2706
|
+
* MAX_RENDER_BYTES. Files at or below the cap are read whole (byte-identical to a
|
|
2707
|
+
* plain readFile); larger files return only their tail window. This is the same
|
|
2708
|
+
* tail-window tradeoff `renderLogTailLines` already makes at 32KB, just larger —
|
|
2709
|
+
* the window's first line may be a partial (garbled) render, but it sits at the
|
|
2710
|
+
* scrollback-eviction boundary, ~50k lines above any tail/head/normal view.
|
|
2711
|
+
*
|
|
2712
|
+
* NOTE: the returned buffer is a rendering substrate only; its length is NOT the
|
|
2713
|
+
* file's byte length. Follow/watch callers must seek from the real file size
|
|
2714
|
+
* (`stat().size`), never from this buffer's length.
|
|
2715
|
+
*/
|
|
2716
|
+
async function readLogForRender(logPath, maxBytes = MAX_RENDER_BYTES) {
|
|
2717
|
+
const fh = await open(logPath, "r");
|
|
2718
|
+
try {
|
|
2719
|
+
const { size } = await fh.stat();
|
|
2720
|
+
if (size <= maxBytes) {
|
|
2721
|
+
const data = await fh.readFile();
|
|
2722
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
2723
|
+
}
|
|
2724
|
+
const tmp = Buffer.allocUnsafe(maxBytes);
|
|
2725
|
+
const { bytesRead } = await fh.read(tmp, 0, maxBytes, size - maxBytes);
|
|
2726
|
+
return new Uint8Array(tmp.buffer, tmp.byteOffset, bytesRead);
|
|
2727
|
+
} finally {
|
|
2728
|
+
await fh.close();
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
/**
|
|
2689
2732
|
* Feed the raw PTY bytes through @xterm/headless and emit plain text.
|
|
2690
2733
|
* Same approach as koho's renderTerminalBuffer + agent-yes's XtermProxy.
|
|
2691
2734
|
*/
|
|
@@ -3844,7 +3887,7 @@ async function cmdAttach(rest) {
|
|
|
3844
3887
|
const winsizeDir = path.join(ayHome, "winsize");
|
|
3845
3888
|
await mkdir(winsizeDir, { recursive: true });
|
|
3846
3889
|
const winsizePath = path.join(winsizeDir, String(record.pid));
|
|
3847
|
-
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-
|
|
3890
|
+
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-CrQavO4J.js");
|
|
3848
3891
|
const daemonBase = await resolveDaemonHttpBase().catch(() => null);
|
|
3849
3892
|
const daemonToken = daemonBase ? await loadTokenReadOnly().catch(() => null) ?? "" : "";
|
|
3850
3893
|
const capViewer = `attach:${process.pid}`;
|
|
@@ -4554,7 +4597,7 @@ async function cmdNotify(rest) {
|
|
|
4554
4597
|
}
|
|
4555
4598
|
const ensure = async () => {
|
|
4556
4599
|
if (!argv["ensure-daemon"]) return;
|
|
4557
|
-
const { ensureDaemon } = await import("./notifyDaemon-
|
|
4600
|
+
const { ensureDaemon } = await import("./notifyDaemon-BKaX7tHT.js");
|
|
4558
4601
|
await ensureDaemon().catch(() => null);
|
|
4559
4602
|
};
|
|
4560
4603
|
await heartbeatWatcher(parent, selfStartedAt);
|
|
@@ -4628,7 +4671,7 @@ async function cmdNotifyCursor(args) {
|
|
|
4628
4671
|
}
|
|
4629
4672
|
async function cmdNotifyd(rest) {
|
|
4630
4673
|
const sub = rest[0] ?? "status";
|
|
4631
|
-
const daemon = await import("./notifyDaemon-
|
|
4674
|
+
const daemon = await import("./notifyDaemon-BKaX7tHT.js");
|
|
4632
4675
|
switch (sub) {
|
|
4633
4676
|
case "run": return daemon.runDaemon();
|
|
4634
4677
|
case "once": return daemon.runDaemon({ once: true });
|
|
@@ -4654,5 +4697,5 @@ async function cmdNotifyd(rest) {
|
|
|
4654
4697
|
}
|
|
4655
4698
|
|
|
4656
4699
|
//#endregion
|
|
4657
|
-
export {
|
|
4658
|
-
//# sourceMappingURL=subcommands-
|
|
4700
|
+
export { liveWatchers as $, readPtysize as A, runSubcommand as B, lastStdinAt as C, readAgentPtysize as D, menuSelectKeys as E, renderRawLogLines as F, waitForLogQuiet as G, stdinActivityPath as H, resolveOne as I, appendEvent as J, writeKeysPaced as K, resolveReadWindow as L, recentReadEdges as M, renderLogTailLines as N, readLogForRender as O, renderRawLog as P, listInboxParents as Q, resolveResumeArgs as R, isUserTyping as S, matchKeyword as T, stopTipForCli as U, snapshotStatus as V, submitAndConfirm as W, hostId as X, gcInboxes as Y, isTransientLockMkdirError as Z, isExitRequest as _, backoffWhileTyping as a, TYPING_BADGE as at, isSubcommand as b, cursorAbs as c, extractBadges as d, readInbox as et, extractMenu as f, isAgentStuck as g, finalizedLines as h, TYPING_WINDOW_MS as i, notifyDir as it, recentMessageEdges as j, readNotes as k, deriveLiveState as l, extractTaskCounts as m, MAX_RENDER_BYTES as n, daemonLockDir as nt, cmdHelp as o, extractNeedsInput as p, writeToIpc as q, READ_PAGE_DEFAULT as r, daemonLockOwnerPath as rt, controlCodeFromName as s, GRACEFUL_EXIT_COMMANDS as t, shouldStealLock as tt, deriveLiveStatus as u, isPidAlive as v, listRecords as w, isUnknownManagerToken as x, isSlashCommand as y, restartHintLines as z };
|
|
4701
|
+
//# sourceMappingURL=subcommands-bd-cHNKW.js.map
|
|
@@ -98,7 +98,7 @@ async function cmdTermMint(args) {
|
|
|
98
98
|
if (flags.ro && flags.interactive) throw new Error("--ro and --interactive are mutually exclusive");
|
|
99
99
|
const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
|
|
100
100
|
const canSend = flags.interactive === true;
|
|
101
|
-
const { mintScopedTermToken } = await import("./serve-
|
|
101
|
+
const { mintScopedTermToken } = await import("./serve-CrQavO4J.js");
|
|
102
102
|
const r = await mintScopedTermToken(pid, {
|
|
103
103
|
ttlSec,
|
|
104
104
|
canSend
|
|
@@ -135,4 +135,4 @@ async function cmdTerm(args) {
|
|
|
135
135
|
|
|
136
136
|
//#endregion
|
|
137
137
|
export { cmdTerm };
|
|
138
|
-
//# sourceMappingURL=terminal-
|
|
138
|
+
//# sourceMappingURL=terminal-eRiT4Zbo.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as findTrayLauncher } from "./rustBinary-
|
|
1
|
+
import { n as findTrayLauncher } from "./rustBinary-BjMf3hJs.js";
|
|
2
2
|
import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
@@ -97,4 +97,4 @@ async function cmdTray(args) {
|
|
|
97
97
|
|
|
98
98
|
//#endregion
|
|
99
99
|
export { trayHiddenMarker as a, launchTray as i, hasDesktop as n, isTrayHidden as r, cmdTray as t };
|
|
100
|
-
//# sourceMappingURL=trayApp-
|
|
100
|
+
//# sourceMappingURL=trayApp-BBNKEQbP.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __esmMin, r as __exportAll } from "./chunk-cZBX9HZv.js";
|
|
2
2
|
import { n as logger, t as addTransport } from "./logger-CDIsZ-Pp.js";
|
|
3
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
3
|
+
import { r as getInstalledPackage } from "./versionChecker-BKFAk759.js";
|
|
4
4
|
import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
|
|
5
5
|
import { d as openStore, p as LIFECYCLES, x as removeControlCharacters } from "./todoAutomation-BQRW614S.js";
|
|
6
6
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-DBoONoM-.js";
|
|
@@ -11,7 +11,7 @@ import { n as register, r as sweep } from "./reaper-C4BvNylH.js";
|
|
|
11
11
|
import { arch, platform } from "process";
|
|
12
12
|
import { execSync } from "child_process";
|
|
13
13
|
import { closeSync, constants, createReadStream, existsSync, mkdirSync, openSync } from "fs";
|
|
14
|
-
import { mkdir, readFile, readdir, unlink, writeFile } from "fs/promises";
|
|
14
|
+
import { mkdir, open, readFile, readdir, stat, unlink, writeFile } from "fs/promises";
|
|
15
15
|
import { homedir } from "os";
|
|
16
16
|
import path, { dirname, join } from "path";
|
|
17
17
|
import { fileURLToPath } from "url";
|
|
@@ -1390,6 +1390,28 @@ async function answerAsk(projectRoot, taskId, answer) {
|
|
|
1390
1390
|
|
|
1391
1391
|
//#endregion
|
|
1392
1392
|
//#region ts/index.ts
|
|
1393
|
+
const RAW_LOG_KEEP_BYTES = 80 * 1024 * 1024;
|
|
1394
|
+
const RAW_LOG_TRIGGER_BYTES = 160 * 1024 * 1024;
|
|
1395
|
+
/** Shrink a raw log to its trailing `keepBytes` **in place** (rewrite tail→front
|
|
1396
|
+
* + truncate), returning the new length. Deliberately NOT temp-file+rename:
|
|
1397
|
+
* rename swaps the inode, freezing any live follower (`ay serve` `/api/tail`,
|
|
1398
|
+
* incl. the agent-yes.com viewer over WebRTC) whose fd is bound to the old inode.
|
|
1399
|
+
* Rewriting the same inode lets serve's `if (size < offset) offset = size`
|
|
1400
|
+
* "truncated/rotated" guard resume the stream. Mirrors rs/src/log_files.rs. */
|
|
1401
|
+
async function compactRawLogTail(logPath, keepBytes = RAW_LOG_KEEP_BYTES) {
|
|
1402
|
+
const fh = await open(logPath, "r+");
|
|
1403
|
+
try {
|
|
1404
|
+
const { size } = await fh.stat();
|
|
1405
|
+
if (size <= keepBytes) return size;
|
|
1406
|
+
const buf = Buffer.allocUnsafe(keepBytes);
|
|
1407
|
+
const { bytesRead } = await fh.read(buf, 0, keepBytes, size - keepBytes);
|
|
1408
|
+
await fh.write(buf, 0, bytesRead, 0);
|
|
1409
|
+
await fh.truncate(bytesRead);
|
|
1410
|
+
return bytesRead;
|
|
1411
|
+
} finally {
|
|
1412
|
+
await fh.close();
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1393
1415
|
const config = await import("./agent-yes.config-DzNini0E.js").then((mod) => mod.default || mod);
|
|
1394
1416
|
const CLIS_CONFIG = config.clis;
|
|
1395
1417
|
/**
|
|
@@ -2049,11 +2071,14 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
|
|
|
2049
2071
|
}).forkTo(async function rawLogger(f) {
|
|
2050
2072
|
const rawLogPath = ctx.logPaths.rawLogPath;
|
|
2051
2073
|
if (!rawLogPath) return f.run();
|
|
2052
|
-
return await mkdir(path.dirname(rawLogPath), { recursive: true }).then(() => {
|
|
2074
|
+
return await mkdir(path.dirname(rawLogPath), { recursive: true }).then(async () => {
|
|
2053
2075
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
2076
|
+
let rawWritten = await stat(rawLogPath).then((s) => s.size).catch(() => 0);
|
|
2054
2077
|
return f.forEach(async (chars) => {
|
|
2055
2078
|
if (!usedAltScreen && /\[\?(?:1049|1047|47)h/.test(chars)) usedAltScreen = true;
|
|
2056
2079
|
await writeFile(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
2080
|
+
rawWritten += Buffer.byteLength(chars);
|
|
2081
|
+
if (rawWritten > RAW_LOG_TRIGGER_BYTES) rawWritten = await compactRawLogTail(rawLogPath).catch(() => rawWritten);
|
|
2057
2082
|
}).run();
|
|
2058
2083
|
}).catch(() => f.run());
|
|
2059
2084
|
}).by(function consoleResponder(e) {
|
|
@@ -2155,4 +2180,4 @@ function sleep(ms) {
|
|
|
2155
2180
|
|
|
2156
2181
|
//#endregion
|
|
2157
2182
|
export { hasTodoStore as a, permissionBadge as c, answerAsk as i, AgentContext as l, agentYes as n, listAsks as o, config as r, listAsksForProject as s, CLIS_CONFIG as t, CLAUDE_SESSION_PIN_ENV as u };
|
|
2158
|
-
//# sourceMappingURL=ts-
|
|
2183
|
+
//# sourceMappingURL=ts-CvUvWb2n.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.258.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-BKFAk759.js.map
|
|
@@ -28,7 +28,7 @@ function parseFlags(args, known) {
|
|
|
28
28
|
}
|
|
29
29
|
/** Resolve the local daemon base URL + token (flags override discovery). */
|
|
30
30
|
async function daemonTarget(flags) {
|
|
31
|
-
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-
|
|
31
|
+
const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-CrQavO4J.js");
|
|
32
32
|
const base = typeof flags.base === "string" ? flags.base : await resolveDaemonHttpBase();
|
|
33
33
|
if (!base) throw new Error("no running ay serve daemon found — start `ay serve` or pass --base <url> (e.g. http://127.0.0.1:PORT)");
|
|
34
34
|
const token = typeof flags.token === "string" ? flags.token : await loadTokenReadOnly() ?? "";
|
|
@@ -186,7 +186,7 @@ async function cmdMint(args) {
|
|
|
186
186
|
const bad = caps.filter((c) => !KNOWN_CAPS.has(c));
|
|
187
187
|
if (bad.length) throw new Error(`unknown cap(s): ${bad.join(", ")} (valid: ${[...KNOWN_CAPS].join(", ")})`);
|
|
188
188
|
const ttlSec = parseTtlSec(typeof flags.ttl === "string" ? flags.ttl : "15m");
|
|
189
|
-
const { mintScopedTermToken } = await import("./serve-
|
|
189
|
+
const { mintScopedTermToken } = await import("./serve-CrQavO4J.js");
|
|
190
190
|
const r = await mintScopedTermToken(target, {
|
|
191
191
|
ttlSec,
|
|
192
192
|
caps
|
|
@@ -202,4 +202,4 @@ async function cmdMint(args) {
|
|
|
202
202
|
|
|
203
203
|
//#endregion
|
|
204
204
|
export { cmdMint, cmdWidget };
|
|
205
|
-
//# sourceMappingURL=widget-
|
|
205
|
+
//# sourceMappingURL=widget-C1GqFymh.js.map
|
|
@@ -3,9 +3,9 @@ import "./globalPidIndex-Dq4KY2IV.js";
|
|
|
3
3
|
import "./messageLog-BYFwioFY.js";
|
|
4
4
|
import "./e2e-CUMZC53I.js";
|
|
5
5
|
import "./configShared-DtHMBCl7.js";
|
|
6
|
-
import "./subcommands-
|
|
6
|
+
import "./subcommands-bd-cHNKW.js";
|
|
7
7
|
import "./webrtcLink-CS4D-3G1.js";
|
|
8
8
|
import "./remotes-Dy4Rg8Yp.js";
|
|
9
|
-
import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-
|
|
9
|
+
import { a as isPathInside, c as walkWorkspaces, i as importProvisionModule, l as workspaceStatus, n as cmdWs, o as loadProvision, r as collectWorkspaces, s as resolveOperand, t as WS_JSON_SCHEMA } from "./ws-DgHuhAPq.js";
|
|
10
10
|
|
|
11
11
|
export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, workspaceStatus };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { w as listRecords } from "./subcommands-bd-cHNKW.js";
|
|
2
2
|
import { a as getProvisionRoot } from "./workspaceConfig-Bxuk_MOq.js";
|
|
3
3
|
import { existsSync } from "fs";
|
|
4
4
|
import { lstat, opendir } from "fs/promises";
|
|
@@ -426,4 +426,4 @@ async function cmdWs(args) {
|
|
|
426
426
|
|
|
427
427
|
//#endregion
|
|
428
428
|
export { isPathInside as a, walkWorkspaces as c, importProvisionModule as i, workspaceStatus as l, cmdWs as n, loadProvision as o, collectWorkspaces as r, resolveOperand as s, WS_JSON_SCHEMA as t };
|
|
429
|
-
//# sourceMappingURL=ws-
|
|
429
|
+
//# sourceMappingURL=ws-DgHuhAPq.js.map
|
package/lab/ui/console-logic.js
CHANGED
|
@@ -684,9 +684,12 @@ export function selSegments(sel, myLast, vy, myRows, peerCols, myCols) {
|
|
|
684
684
|
const from = Math.max(rA, vy),
|
|
685
685
|
to = Math.min(rB, vy + myRows - 1);
|
|
686
686
|
for (let r = from; r <= to; r++) {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
687
|
+
// cA/cB are the PEER's columns, so they go through mapC; 0 and myCols are the
|
|
688
|
+
// row's own edges, already in OUR space — mapping them would rescale our own
|
|
689
|
+
// right edge (and could even invert the span when the peer is wider).
|
|
690
|
+
const a = r === rA ? mapC(cA) : 0;
|
|
691
|
+
const b = r === rB ? mapC(cB) : myCols;
|
|
692
|
+
segs.push({ row: r, a: Math.min(a, b), b: Math.max(a, b) });
|
|
690
693
|
}
|
|
691
694
|
return segs;
|
|
692
695
|
}
|
package/lab/ui/index.html
CHANGED
|
@@ -1939,6 +1939,9 @@
|
|
|
1939
1939
|
overflow: hidden;
|
|
1940
1940
|
text-overflow: ellipsis;
|
|
1941
1941
|
}
|
|
1942
|
+
.ctxmenu-item.danger {
|
|
1943
|
+
color: var(--red, #f85149);
|
|
1944
|
+
}
|
|
1942
1945
|
.ctxmenu-sep {
|
|
1943
1946
|
height: 1px;
|
|
1944
1947
|
margin: 4px 6px;
|
|
@@ -4875,6 +4878,7 @@ my.translate = async (text, lang) => {
|
|
|
4875
4878
|
it.className = "ctxmenu-item";
|
|
4876
4879
|
it.textContent = label;
|
|
4877
4880
|
it.setAttribute("role", "menuitem");
|
|
4881
|
+
if (opts && opts.danger) it.classList.add("danger");
|
|
4878
4882
|
if (opts && opts.hint) {
|
|
4879
4883
|
const h = document.createElement("span");
|
|
4880
4884
|
h.className = "ctxmenu-hint";
|
|
@@ -4989,17 +4993,35 @@ my.translate = async (text, lang) => {
|
|
|
4989
4993
|
|
|
4990
4994
|
openCtxMenu(menu, ev);
|
|
4991
4995
|
}
|
|
4992
|
-
// Right-click menu for a left-panel agent row
|
|
4993
|
-
//
|
|
4996
|
+
// Right-click menu for a left-panel agent row. Same agent actions as the
|
|
4997
|
+
// terminal header's ⋯ overflow menu (share / stop / restart / force-kill),
|
|
4998
|
+
// but bound to the RIGHT-CLICKED row rather than the selected agent — so you
|
|
4999
|
+
// can act on an agent without switching to it first. Plus pin/unpin to the
|
|
5000
|
+
// top of the list (a pin also surfaces the agent in /r/'s screen-fixed
|
|
5001
|
+
// palette). View prefs (font size, perf HUD) stay in the ⋯ menu: they're
|
|
5002
|
+
// properties of the terminal pane, not of an agent.
|
|
4994
5003
|
function showAgentMenu(ev, key) {
|
|
4995
5004
|
ev.preventDefault();
|
|
4996
5005
|
hideTermMenu();
|
|
4997
5006
|
const e = entries.find((x) => x._key === key);
|
|
4998
5007
|
if (!e) return;
|
|
4999
|
-
const { menu, addItem } = ctxMenuShell();
|
|
5008
|
+
const { menu, addItem, addSep } = ctxMenuShell();
|
|
5000
5009
|
const name = cliLabel(e) || ident(e) || "pid " + e.pid;
|
|
5001
|
-
|
|
5002
|
-
|
|
5010
|
+
addItem(name, { disabled: true, hint: "pid " + e.pid }, () => {});
|
|
5011
|
+
addSep();
|
|
5012
|
+
if (isPinned(key)) addItem("Unpin from top", { hint: "📌" }, () => togglePin(key));
|
|
5013
|
+
else addItem("Pin to top", { hint: "📌" }, () => togglePin(key));
|
|
5014
|
+
// A shared read-only view can't re-share or steer its host's agent —
|
|
5015
|
+
// mirrors the .app.steer-agent rule that hides these in the ⋯ menu.
|
|
5016
|
+
if (!isReadonlyEnt(e) && !sharePermOf(e)) {
|
|
5017
|
+
addSep();
|
|
5018
|
+
addItem("👁 Share (view-only)", {}, () => shareAgent("r", e));
|
|
5019
|
+
addItem("✏️ Share (read-write)…", {}, () => shareAgent("rw", e));
|
|
5020
|
+
addSep();
|
|
5021
|
+
addItem("⏹ Stop agent", {}, () => stopAgent(false, e));
|
|
5022
|
+
addItem("↻ Restart (resume)", {}, () => restartAgent(e));
|
|
5023
|
+
addItem("✕ Force-kill (SIGKILL)", { danger: true }, () => stopAgent(true, e));
|
|
5024
|
+
}
|
|
5003
5025
|
openCtxMenu(menu, ev);
|
|
5004
5026
|
}
|
|
5005
5027
|
// Lightweight editor: overlay + textarea of `Label | template` lines. Save
|
package/package.json
CHANGED
package/ts/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execaCommandSync, parseCommandString } from "execa";
|
|
2
2
|
import { fromWritable } from "from-node-stream";
|
|
3
|
-
import { mkdir, readFile, unlink, writeFile } from "fs/promises";
|
|
3
|
+
import { mkdir, open, readFile, stat, unlink, writeFile } from "fs/promises";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import DIE from "phpdie";
|
|
6
6
|
import sflow from "sflow";
|
|
@@ -81,6 +81,37 @@ export type { TodoAction, LiveAgent } from "./todoAutomation.ts";
|
|
|
81
81
|
export { listAsks, listAsksForProject, answerAsk, hasTodoStore } from "./askApi.ts";
|
|
82
82
|
export type { AskItem, AnswerInput, AnswerResult } from "./askApi.ts";
|
|
83
83
|
|
|
84
|
+
// Raw PTY logs are an append-only capture; the reader (`readLogForRender`) only
|
|
85
|
+
// ever replays the trailing ~64 MiB, so older bytes are dead weight on disk (a
|
|
86
|
+
// runaway capture was seen at ~1 GB). Once the file passes RAW_LOG_TRIGGER_BYTES,
|
|
87
|
+
// compact it to its last RAW_LOG_KEEP_BYTES (kept above the render window so no
|
|
88
|
+
// visible output is lost). Mirrors the Rust runtime's LogWriter cap in
|
|
89
|
+
// rs/src/log_files.rs — keep the two in sync.
|
|
90
|
+
const RAW_LOG_KEEP_BYTES = 80 * 1024 * 1024;
|
|
91
|
+
const RAW_LOG_TRIGGER_BYTES = 160 * 1024 * 1024;
|
|
92
|
+
|
|
93
|
+
/** Shrink a raw log to its trailing `keepBytes` **in place** (rewrite tail→front
|
|
94
|
+
* + truncate), returning the new length. Deliberately NOT temp-file+rename:
|
|
95
|
+
* rename swaps the inode, freezing any live follower (`ay serve` `/api/tail`,
|
|
96
|
+
* incl. the agent-yes.com viewer over WebRTC) whose fd is bound to the old inode.
|
|
97
|
+
* Rewriting the same inode lets serve's `if (size < offset) offset = size`
|
|
98
|
+
* "truncated/rotated" guard resume the stream. Mirrors rs/src/log_files.rs. */
|
|
99
|
+
async function compactRawLogTail(logPath: string, keepBytes = RAW_LOG_KEEP_BYTES): Promise<number> {
|
|
100
|
+
const fh = await open(logPath, "r+");
|
|
101
|
+
try {
|
|
102
|
+
const { size } = await fh.stat();
|
|
103
|
+
if (size <= keepBytes) return size;
|
|
104
|
+
// Read the tail fully before overwriting the front so it can't be clobbered.
|
|
105
|
+
const buf = Buffer.allocUnsafe(keepBytes);
|
|
106
|
+
const { bytesRead } = await fh.read(buf, 0, keepBytes, size - keepBytes);
|
|
107
|
+
await fh.write(buf, 0, bytesRead, 0);
|
|
108
|
+
await fh.truncate(bytesRead);
|
|
109
|
+
return bytesRead;
|
|
110
|
+
} finally {
|
|
111
|
+
await fh.close();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
84
115
|
export type AgentCliConfig = {
|
|
85
116
|
// cli
|
|
86
117
|
install?:
|
|
@@ -1224,8 +1255,13 @@ export default async function agentYes({
|
|
|
1224
1255
|
|
|
1225
1256
|
// try stream the raw log for realtime debugging, including control chars, note: it will be a huge file
|
|
1226
1257
|
return await mkdir(path.dirname(rawLogPath), { recursive: true })
|
|
1227
|
-
.then(() => {
|
|
1258
|
+
.then(async () => {
|
|
1228
1259
|
logger.debug(`[${cli}-yes] raw logs streaming to ${rawLogPath}`);
|
|
1260
|
+
// Track size (seeded from any pre-existing log) to cap disk growth
|
|
1261
|
+
// without a stat() per chunk. See compactRawLogTail.
|
|
1262
|
+
let rawWritten = await stat(rawLogPath)
|
|
1263
|
+
.then((s) => s.size)
|
|
1264
|
+
.catch(() => 0);
|
|
1229
1265
|
return f
|
|
1230
1266
|
.forEach(async (chars) => {
|
|
1231
1267
|
// Detect alt-screen enter (DECSET 1049/1047/47) so we know whether
|
|
@@ -1234,6 +1270,10 @@ export default async function agentYes({
|
|
|
1234
1270
|
usedAltScreen = true;
|
|
1235
1271
|
}
|
|
1236
1272
|
await writeFile(rawLogPath, chars, { flag: "a" }).catch(() => null);
|
|
1273
|
+
rawWritten += Buffer.byteLength(chars);
|
|
1274
|
+
if (rawWritten > RAW_LOG_TRIGGER_BYTES) {
|
|
1275
|
+
rawWritten = await compactRawLogTail(rawLogPath).catch(() => rawWritten);
|
|
1276
|
+
}
|
|
1237
1277
|
})
|
|
1238
1278
|
.run();
|
|
1239
1279
|
})
|
package/ts/needsInput.spec.ts
CHANGED
|
@@ -113,3 +113,41 @@ test("parseMenu: a 'N.M' version in an option label isn't mistaken for another o
|
|
|
113
113
|
expect(menu!.cursor).toBe(1);
|
|
114
114
|
expect(menu!.options).toEqual([1, 2]);
|
|
115
115
|
});
|
|
116
|
+
|
|
117
|
+
// Claude renders its permission / AskUserQuestion dialogs INSIDE a rounded box,
|
|
118
|
+
// so every option row arrives with a leading "│" border (the shipped config's own
|
|
119
|
+
// markers show this: a typingRespond keyed on '│ Do you want to use this API key\?'
|
|
120
|
+
// and gemini `enter` rows like "│ ● 1. Yes, allow once"). Option rows must still be
|
|
121
|
+
// collected through that border — otherwise `ay select N` can only ever pick the
|
|
122
|
+
// option the cursor already sits on.
|
|
123
|
+
test("parseMenu: collects options through a box border (claude permission dialog)", () => {
|
|
124
|
+
const screen = [
|
|
125
|
+
"╭──────────────────────────────────────────────────────────╮",
|
|
126
|
+
"│ Do you want to proceed? │",
|
|
127
|
+
"│ ❯ 1. Yes │",
|
|
128
|
+
"│ 2. Yes, and don't ask again for rm commands in /repo │",
|
|
129
|
+
"│ 3. No, and tell Claude what to do differently (esc) │",
|
|
130
|
+
"╰──────────────────────────────────────────────────────────╯",
|
|
131
|
+
];
|
|
132
|
+
const menu = parseMenu(screen, claude);
|
|
133
|
+
expect(menu!.cursor).toBe(1);
|
|
134
|
+
expect(menu!.options).toEqual([1, 2, 3]);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("parseMenu: collects boxed bullet rows (gemini '│ ● 1. Yes, allow once')", () => {
|
|
138
|
+
const screen = [
|
|
139
|
+
"│ Apply this change? │",
|
|
140
|
+
"│ ❯ 1. Yes, allow once │",
|
|
141
|
+
"│ ● 2. Yes, allow always │",
|
|
142
|
+
"│ ● 3. No (esc) │",
|
|
143
|
+
];
|
|
144
|
+
const menu = parseMenu(screen, claude);
|
|
145
|
+
expect(menu!.cursor).toBe(1);
|
|
146
|
+
expect(menu!.options).toEqual([1, 2, 3]);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("parseMenu: a boxed 'N.M' version still isn't mistaken for an option", () => {
|
|
150
|
+
const screen = ["│ Cleanup? │", "│ ❯ 1. Delete 3.5GB │", "│ 2. Keep │"];
|
|
151
|
+
const menu = parseMenu(screen, claude);
|
|
152
|
+
expect(menu!.options).toEqual([1, 2]);
|
|
153
|
+
});
|
package/ts/needsInput.ts
CHANGED
|
@@ -76,9 +76,13 @@ export interface MenuState {
|
|
|
76
76
|
question: string;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
// An option row: an optional cursor glyph / bullet, then "N. " (the
|
|
80
|
-
// space rejects version-like "3.5GB" that isn't a menu option).
|
|
81
|
-
|
|
79
|
+
// An option row: an optional box border / cursor glyph / bullet, then "N. " (the
|
|
80
|
+
// trailing space rejects version-like "3.5GB" that isn't a menu option). The `│`
|
|
81
|
+
// matters: claude/gemini render their permission + AskUserQuestion menus inside a
|
|
82
|
+
// rounded box, so real option rows arrive as "│ ❯ 1. Yes" — without it only the
|
|
83
|
+
// cursor row is ever collected and `ay select N` can't reach any other option.
|
|
84
|
+
// Keep `-` last in the class so it stays a literal rather than a range.
|
|
85
|
+
const OPTION_LINE = /^[\s❯›>▶◉○●·│*-]*?(\d+)\.\s/;
|
|
82
86
|
|
|
83
87
|
/**
|
|
84
88
|
* Parse the selection menu a `needs_input` agent is parked on into a cursor
|
package/ts/serve.ts
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
isUserTyping,
|
|
27
27
|
listRecords,
|
|
28
28
|
readNotes,
|
|
29
|
+
readLogForRender,
|
|
29
30
|
readPtysize,
|
|
30
31
|
recentMessageEdges,
|
|
31
32
|
recentReadEdges,
|
|
@@ -3090,7 +3091,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
3090
3091
|
const record = await resolveOne(keyword, defaultOpts());
|
|
3091
3092
|
if (!record.log_file)
|
|
3092
3093
|
return new Response(`pid ${record.pid}: no log_file`, { status: 404 });
|
|
3093
|
-
const buf = await
|
|
3094
|
+
const buf = await readLogForRender(record.log_file);
|
|
3094
3095
|
const size = await readPtysize(record.pid);
|
|
3095
3096
|
const text = await renderRawLog(buf, { mode, n, cols: size?.cols, rows: size?.rows });
|
|
3096
3097
|
return new Response(text, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
|
package/ts/subcommands.spec.ts
CHANGED
|
@@ -28,6 +28,32 @@ async function loadModule() {
|
|
|
28
28
|
return await import("./subcommands.ts");
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
describe("subcommands.readLogForRender", () => {
|
|
32
|
+
it("reads a small file whole (byte-identical)", async () => {
|
|
33
|
+
const { readLogForRender } = await loadModule();
|
|
34
|
+
const p = path.join(testHome, "small.log");
|
|
35
|
+
const body = Buffer.from("hello\nworld\n".repeat(100));
|
|
36
|
+
await writeFile(p, body);
|
|
37
|
+
const got = await readLogForRender(p);
|
|
38
|
+
expect(Buffer.from(got)).toEqual(body);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("caps an oversized file to its trailing window", async () => {
|
|
42
|
+
const { readLogForRender } = await loadModule();
|
|
43
|
+
const p = path.join(testHome, "big.log");
|
|
44
|
+
// 300 KiB of distinct 16-byte lines; cap the read at 64 KiB.
|
|
45
|
+
const lines: string[] = [];
|
|
46
|
+
for (let i = 0; i < 300 * 64; i++) lines.push(String(i).padStart(15, "0"));
|
|
47
|
+
const body = Buffer.from(lines.join("\n") + "\n");
|
|
48
|
+
await writeFile(p, body);
|
|
49
|
+
const cap = 64 * 1024;
|
|
50
|
+
const got = await readLogForRender(p, cap);
|
|
51
|
+
expect(got.byteLength).toBe(cap);
|
|
52
|
+
// The window is the tail: it ends with the file's final bytes.
|
|
53
|
+
expect(Buffer.from(got).subarray(-16)).toEqual(body.subarray(-16));
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
31
57
|
describe("subcommands.controlCodeFromName", () => {
|
|
32
58
|
it("maps named codes to the right control bytes", async () => {
|
|
33
59
|
const { controlCodeFromName } = await loadModule();
|
package/ts/subcommands.ts
CHANGED
|
@@ -2136,7 +2136,7 @@ async function cmdRead(rest: string[], { mode }: ReadOpts): Promise<number> {
|
|
|
2136
2136
|
throw new Error(`pid ${record.pid}: log path is not a file: ${logPath}`);
|
|
2137
2137
|
}
|
|
2138
2138
|
|
|
2139
|
-
const buf = await
|
|
2139
|
+
const buf = await readLogForRender(logPath);
|
|
2140
2140
|
const size = await readAgentPtysize(record);
|
|
2141
2141
|
const notes = await readNotes();
|
|
2142
2142
|
const noteLabel = notes.get(record.pid);
|
|
@@ -2154,7 +2154,12 @@ async function cmdRead(rest: string[], { mode }: ReadOpts): Promise<number> {
|
|
|
2154
2154
|
// `ay tail -f` doesn't "expire" past the send window mid-watch.
|
|
2155
2155
|
const refresh = setInterval(() => void recordRead(reader.key, record.pid), 30_000);
|
|
2156
2156
|
refresh.unref?.();
|
|
2157
|
-
|
|
2157
|
+
// Seed the follow from the log's REAL byte frontier (`stats.size`), not
|
|
2158
|
+
// `buf.length` — `buf` may be a capped tail window, so its length is not the
|
|
2159
|
+
// file offset. `buf` still seeds the terminal render (identical final state).
|
|
2160
|
+
return plain
|
|
2161
|
+
? followPlainLocal(logPath, buf, stats.size)
|
|
2162
|
+
: followRawLocal(logPath, buf, stats.size);
|
|
2158
2163
|
}
|
|
2159
2164
|
|
|
2160
2165
|
// Static read: render the full log once, then window into the rendered lines
|
|
@@ -2293,7 +2298,11 @@ async function watchAppend(
|
|
|
2293
2298
|
* sequences stripped. Mirrors the historical behaviour, plus prompt signal /
|
|
2294
2299
|
* pipe-close handling.
|
|
2295
2300
|
*/
|
|
2296
|
-
async function followRawLocal(
|
|
2301
|
+
async function followRawLocal(
|
|
2302
|
+
logPath: string,
|
|
2303
|
+
buf: Uint8Array,
|
|
2304
|
+
startOffset = buf.length,
|
|
2305
|
+
): Promise<number> {
|
|
2297
2306
|
process.stderr.write(`following... (Ctrl-C to stop)\n`);
|
|
2298
2307
|
// oxlint-disable-next-line no-control-regex -- intentional: strip ANSI/control
|
|
2299
2308
|
const ansiRe = /\x1b\[[0-?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[@-Z\\-_]/g;
|
|
@@ -2301,7 +2310,7 @@ async function followRawLocal(logPath: string, buf: Uint8Array): Promise<number>
|
|
|
2301
2310
|
const ctrlRe = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g;
|
|
2302
2311
|
await watchAppend(
|
|
2303
2312
|
logPath,
|
|
2304
|
-
|
|
2313
|
+
startOffset,
|
|
2305
2314
|
(chunk) => {
|
|
2306
2315
|
const text = new TextDecoder().decode(chunk).replace(ansiRe, "").replace(ctrlRe, "");
|
|
2307
2316
|
if (text.trim()) process.stdout.write(text.trimStart());
|
|
@@ -2355,7 +2364,11 @@ export function finalizedLines(term: PlainTermView, fromAbs: number): string[] {
|
|
|
2355
2364
|
* settled, so the output is clean, newline-terminated, line-buffered text a
|
|
2356
2365
|
* script can read. On stop, flush the line the cursor is still sitting on.
|
|
2357
2366
|
*/
|
|
2358
|
-
async function followPlainLocal(
|
|
2367
|
+
async function followPlainLocal(
|
|
2368
|
+
logPath: string,
|
|
2369
|
+
buf: Uint8Array,
|
|
2370
|
+
startOffset = buf.length,
|
|
2371
|
+
): Promise<number> {
|
|
2359
2372
|
process.stderr.write(`following... (plain; Ctrl-C / SIGTERM to stop)\n`);
|
|
2360
2373
|
const { Terminal } = await import("@xterm/headless");
|
|
2361
2374
|
const term = new Terminal({ cols: 200, rows: 50, scrollback: 50000, allowProposedApi: true });
|
|
@@ -2379,7 +2392,7 @@ async function followPlainLocal(logPath: string, buf: Uint8Array): Promise<numbe
|
|
|
2379
2392
|
|
|
2380
2393
|
await watchAppend(
|
|
2381
2394
|
logPath,
|
|
2382
|
-
|
|
2395
|
+
startOffset,
|
|
2383
2396
|
async (chunk) => {
|
|
2384
2397
|
await feed(chunk);
|
|
2385
2398
|
flushCommitted();
|
|
@@ -2440,6 +2453,50 @@ export async function readAgentPtysize(
|
|
|
2440
2453
|
return null;
|
|
2441
2454
|
}
|
|
2442
2455
|
|
|
2456
|
+
/**
|
|
2457
|
+
* Cap on how many trailing bytes of a raw PTY log we read before rendering.
|
|
2458
|
+
*
|
|
2459
|
+
* `renderRawLogLines` replays the bytes through an xterm with a fixed 50000-line
|
|
2460
|
+
* scrollback, so output older than the last ~50k lines is evicted from the result
|
|
2461
|
+
* no matter how much we read. A runaway CLI/TUI capture can reach ~1GB; slurping
|
|
2462
|
+
* the whole file only to throw ~all of it away is a large memory + CPU spike (a
|
|
2463
|
+
* ~1GB Buffer plus a full-stream vterm replay per request). 64 MiB comfortably
|
|
2464
|
+
* overflows the scrollback for any realistic terminal stream, so an oversized log
|
|
2465
|
+
* renders to the SAME lines while the allocation stays bounded.
|
|
2466
|
+
*/
|
|
2467
|
+
export const MAX_RENDER_BYTES = 64 * 1024 * 1024;
|
|
2468
|
+
|
|
2469
|
+
/**
|
|
2470
|
+
* Read a raw PTY log for full-buffer rendering, capped to the trailing
|
|
2471
|
+
* MAX_RENDER_BYTES. Files at or below the cap are read whole (byte-identical to a
|
|
2472
|
+
* plain readFile); larger files return only their tail window. This is the same
|
|
2473
|
+
* tail-window tradeoff `renderLogTailLines` already makes at 32KB, just larger —
|
|
2474
|
+
* the window's first line may be a partial (garbled) render, but it sits at the
|
|
2475
|
+
* scrollback-eviction boundary, ~50k lines above any tail/head/normal view.
|
|
2476
|
+
*
|
|
2477
|
+
* NOTE: the returned buffer is a rendering substrate only; its length is NOT the
|
|
2478
|
+
* file's byte length. Follow/watch callers must seek from the real file size
|
|
2479
|
+
* (`stat().size`), never from this buffer's length.
|
|
2480
|
+
*/
|
|
2481
|
+
export async function readLogForRender(
|
|
2482
|
+
logPath: string,
|
|
2483
|
+
maxBytes = MAX_RENDER_BYTES,
|
|
2484
|
+
): Promise<Uint8Array> {
|
|
2485
|
+
const fh = await open(logPath, "r");
|
|
2486
|
+
try {
|
|
2487
|
+
const { size } = await fh.stat();
|
|
2488
|
+
if (size <= maxBytes) {
|
|
2489
|
+
const data = await fh.readFile();
|
|
2490
|
+
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
2491
|
+
}
|
|
2492
|
+
const tmp = Buffer.allocUnsafe(maxBytes);
|
|
2493
|
+
const { bytesRead } = await fh.read(tmp, 0, maxBytes, size - maxBytes);
|
|
2494
|
+
return new Uint8Array(tmp.buffer, tmp.byteOffset, bytesRead);
|
|
2495
|
+
} finally {
|
|
2496
|
+
await fh.close();
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2443
2500
|
/**
|
|
2444
2501
|
* Feed the raw PTY bytes through @xterm/headless and emit plain text.
|
|
2445
2502
|
* Same approach as koho's renderTerminalBuffer + agent-yes's XtermProxy.
|
package/ts/todoParse.spec.ts
CHANGED
|
@@ -65,4 +65,34 @@ describe("parseTaskCounts", () => {
|
|
|
65
65
|
expect(parseTaskCounts([])).toBeNull();
|
|
66
66
|
expect(parseTaskCounts(lines("just some logs\nnothing here"))).toBeNull();
|
|
67
67
|
});
|
|
68
|
+
|
|
69
|
+
// The CLI branches EVERY tool result under the same ⎿ glyph, not just todo
|
|
70
|
+
// blocks — and ✓ is an ordinary success glyph in program output. So a ⎿ line
|
|
71
|
+
// that carries its own content is a tool-result header, not a todo anchor;
|
|
72
|
+
// only a BARE ⎿ anchors the markers below it.
|
|
73
|
+
it("does not invent a badge from a test run's ✓ output (⎿ tool-result header)", () => {
|
|
74
|
+
const out = parseTaskCounts(
|
|
75
|
+
lines(
|
|
76
|
+
[
|
|
77
|
+
"⏺ Bash(bun run test)",
|
|
78
|
+
" ⎿ RUN v3.2.4 /repo",
|
|
79
|
+
" ✓ ts/badges.spec.ts (18 tests) 12ms",
|
|
80
|
+
" ✓ ts/needsInput.spec.ts (12 tests) 9ms",
|
|
81
|
+
" ✓ ts/autoRetry.spec.ts (7 tests) 4ms",
|
|
82
|
+
].join("\n"),
|
|
83
|
+
),
|
|
84
|
+
);
|
|
85
|
+
expect(out).toBeNull();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("does not invent a badge from ✓ prose under a ⎿ result header", () => {
|
|
89
|
+
const out = parseTaskCounts(
|
|
90
|
+
lines(
|
|
91
|
+
[" ⎿ Read 120 lines (ctrl+o to expand)", " ✓ Tests pass", " ✓ Lint clean"].join(
|
|
92
|
+
"\n",
|
|
93
|
+
),
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
expect(out).toBeNull();
|
|
97
|
+
});
|
|
68
98
|
});
|
package/ts/todoParse.ts
CHANGED
|
@@ -51,15 +51,27 @@ function markerOf(line: string): Marker | null {
|
|
|
51
51
|
return null;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
// The TUI branches EVERY tool result under the same `⎿` glyph — "⎿ RUN v3.2.4",
|
|
55
|
+
// "⎿ Read 120 lines (ctrl+o to expand)" — not just todo blocks. Such a header
|
|
56
|
+
// carries its own content after the glyph, whereas a todo anchor on the line above
|
|
57
|
+
// its markers is bare. Requiring bare keeps a Bash run that prints ✓ lines (vitest
|
|
58
|
+
// output!) from self-anchoring into a phantom badge, while the todo shapes — the
|
|
59
|
+
// anchor ON the first marker line ("⎿ ☒ Wire up the parser") or a lone "⎿" above
|
|
60
|
+
// them — still qualify.
|
|
61
|
+
function isBareAnchor(line: string): boolean {
|
|
62
|
+
const s = line.trim();
|
|
63
|
+
return s.startsWith(ANCHOR) && s.slice(ANCHOR.length).trim() === "";
|
|
64
|
+
}
|
|
65
|
+
|
|
54
66
|
/**
|
|
55
67
|
* Find the MOST RECENT confidently-detected todo block in the rendered lines and
|
|
56
68
|
* return its {done, total}. Returns null when none qualifies (caller omits the
|
|
57
69
|
* badge entirely — never shows "0/0").
|
|
58
70
|
*
|
|
59
71
|
* A block is a maximal run of consecutive marker lines. It only counts when it
|
|
60
|
-
* is anchored — the `⎿` glyph
|
|
61
|
-
* directly above it — and has ≥2 marker lines. The last qualifying block
|
|
62
|
-
* since the agent's current todo state is the one drawn most recently.
|
|
72
|
+
* is anchored — the `⎿` glyph sits on the run's FIRST line, or a bare `⎿` sits on
|
|
73
|
+
* the line directly above it — and has ≥2 marker lines. The last qualifying block
|
|
74
|
+
* wins, since the agent's current todo state is the one drawn most recently.
|
|
63
75
|
*/
|
|
64
76
|
export function parseTaskCounts(lines: string[]): TaskCounts | null {
|
|
65
77
|
let best: TaskCounts | null = null;
|
|
@@ -71,13 +83,15 @@ export function parseTaskCounts(lines: string[]): TaskCounts | null {
|
|
|
71
83
|
continue;
|
|
72
84
|
}
|
|
73
85
|
// Start of a marker run at i.
|
|
74
|
-
let hasAnchor = i > 0 && lines[i - 1]
|
|
86
|
+
let hasAnchor = i > 0 && isBareAnchor(lines[i - 1]!);
|
|
75
87
|
const counts = { done: 0, inprogress: 0, pending: 0 };
|
|
76
88
|
let j = i;
|
|
77
89
|
for (; j < n; j++) {
|
|
78
90
|
const mk = markerOf(lines[j]!);
|
|
79
91
|
if (mk === null) break;
|
|
80
|
-
|
|
92
|
+
// Only the run's FIRST line can carry the anchor (as the doc says); a ⎿ that
|
|
93
|
+
// turns up mid-run is not an anchor for the run that already started above it.
|
|
94
|
+
if (j === i && lines[j]!.includes(ANCHOR)) hasAnchor = true;
|
|
81
95
|
counts[mk]++;
|
|
82
96
|
}
|
|
83
97
|
const total = counts.done + counts.inprogress + counts.pending;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./globalPidIndex-Dq4KY2IV.js";
|
|
3
|
-
import "./messageLog-BYFwioFY.js";
|
|
4
|
-
import "./e2e-CUMZC53I.js";
|
|
5
|
-
import "./configShared-DtHMBCl7.js";
|
|
6
|
-
import { A as recentReadEdges, B as stdinActivityPath, C as listRecords, D as readNotes, E as readAgentPtysize, F as resolveReadWindow, G as writeToIpc, H as submitAndConfirm, I as resolveResumeArgs, L as restartHintLines, M as renderRawLog, N as renderRawLogLines, O as readPtysize, P as resolveOne, R as runSubcommand, S as lastStdinAt, T as menuSelectKeys, U as waitForLogQuiet, V as stopTipForCli, W as writeKeysPaced, _ as isPidAlive, a as cmdHelp, b as isUnknownManagerToken, c as deriveLiveState, d as extractMenu, f as extractNeedsInput, g as isExitRequest, h as isAgentStuck, i as backoffWhileTyping, j as renderLogTailLines, k as recentMessageEdges, 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 matchKeyword, x as isUserTyping, y as isSubcommand, z as snapshotStatus } from "./subcommands-B04Jcb4a.js";
|
|
7
|
-
import "./webrtcLink-CS4D-3G1.js";
|
|
8
|
-
import "./remotes-Dy4Rg8Yp.js";
|
|
9
|
-
|
|
10
|
-
export { cmdHelp, isSubcommand, isUnknownManagerToken, runSubcommand };
|
package/dist/trayApp-HLGzyGrP.js
DELETED