agent-yes 1.241.0 → 1.243.0-beta.579.1
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-BXTRXVhU.js → SUPPORTED_CLIS-GdCVJMMr.js} +2 -2
- package/dist/{SUPPORTED_CLIS-D2o95DmW.js → SUPPORTED_CLIS-S4ojAM-G.js} +3 -3
- package/dist/{agentShare-B7pv4n5U.js → agentShare-BoBeAnvX.js} +2 -2
- package/dist/{browser-D2s9Nzi0.js → browser-C5pEBVVH.js} +52 -1
- package/dist/{callback-LzenuKtz.js → callback-CXGpMnF9.js} +2 -2
- package/dist/{callback-KOcQklM_.js → callback-ClxIRUe8.js} +3 -3
- package/dist/cli.js +5 -5
- package/dist/index.js +2 -2
- package/dist/{notifyDaemon-CeDkisCv.js → notifyDaemon-B5MzTdlN.js} +2 -2
- package/dist/{rustBinary-CFpO-1Si.js → rustBinary-BQfAGsP1.js} +2 -2
- package/dist/{schedule-DJJre7xc.js → schedule-YeMh-VJF.js} +4 -4
- package/dist/{serve-DpzVMaXc.js → serve-CqU8xkLF.js} +79 -26
- package/dist/{setup-C0_DmU6X.js → setup-CGkSgbE8.js} +2 -2
- package/dist/{subcommands-BPTVjPEs.js → subcommands-3_ufv34d.js} +11 -11
- package/dist/{subcommands-BHQFZh43.js → subcommands-DMN0ow0k.js} +1 -1
- package/dist/{terminal-Byuiy9nW.js → terminal-D6idrXwY.js} +2 -2
- package/dist/terminal.js +1 -1
- package/dist/{ts-CyUQ58Ht.js → ts-CvwjBKbN.js} +2 -2
- package/dist/{versionChecker-BzfCavve.js → versionChecker-Clt46j3c.js} +2 -2
- package/dist/{widget-Bx7xH9AE.js → widget-BPCw2Vhm.js} +3 -3
- package/dist/widgets.js +1 -1
- package/dist/{ws-G1j8No5N.js → ws-CkSYDYiN.js} +2 -2
- package/package.json +1 -1
- package/ts/serve.ts +104 -23
- package/ts/terminal/browser.ts +53 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as CLIS_CONFIG } from "./ts-
|
|
1
|
+
import { t as CLIS_CONFIG } from "./ts-CvwjBKbN.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-GdCVJMMr.js.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import "./ts-
|
|
2
|
+
import "./versionChecker-Clt46j3c.js";
|
|
3
|
+
import "./ts-CvwjBKbN.js";
|
|
4
4
|
import "./todoAutomation-Buo457VO.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-D9DOSd-c.js";
|
|
7
7
|
import "./pidStore-6EZd5DUv.js";
|
|
8
8
|
import "./messageLog-C-YIzhRj.js";
|
|
9
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
9
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-GdCVJMMr.js";
|
|
10
10
|
|
|
11
11
|
export { SUPPORTED_CLIS };
|
|
@@ -3,7 +3,7 @@ import "./globalPidIndex-D9DOSd-c.js";
|
|
|
3
3
|
import "./messageLog-C-YIzhRj.js";
|
|
4
4
|
import "./e2e-CEIdJGZ7.js";
|
|
5
5
|
import "./configShared-9wVlbPyC.js";
|
|
6
|
-
import { P as resolveOne } from "./subcommands-
|
|
6
|
+
import { P as resolveOne } from "./subcommands-3_ufv34d.js";
|
|
7
7
|
import "./webrtcLink-BMYneHbu.js";
|
|
8
8
|
import "./remotes-BxQnNxQv.js";
|
|
9
9
|
import { a as startShare } from "./share-BGl3wutJ.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-BoBeAnvX.js.map
|
|
@@ -13009,6 +13009,8 @@ var AyTerminal = class {
|
|
|
13009
13009
|
badgeEl;
|
|
13010
13010
|
started = false;
|
|
13011
13011
|
writable = false;
|
|
13012
|
+
capViewerId = "";
|
|
13013
|
+
capTimer = null;
|
|
13012
13014
|
constructor(info) {
|
|
13013
13015
|
const o = typeof info === "string" || typeof info === "number" ? { pid: info } : info;
|
|
13014
13016
|
if (o.pid === void 0 || o.pid === null || o.pid === "") throw new Error("AyTerminal: need a pid/keyword");
|
|
@@ -13019,6 +13021,48 @@ var AyTerminal = class {
|
|
|
13019
13021
|
this.controls = o.controls ?? "auto";
|
|
13020
13022
|
this.token = o.token ?? discoverToken();
|
|
13021
13023
|
this.title = o.title ?? `#${this.pid}`;
|
|
13024
|
+
this.capViewerId = `wterm-${this.pid}-${Math.random().toString(36).slice(2, 8)}`;
|
|
13025
|
+
}
|
|
13026
|
+
/**
|
|
13027
|
+
* Report this panel's readable capacity as a size cap (interactive only), so the
|
|
13028
|
+
* daemon's negotiation (3a/3b) can shrink the shared PTY to what the panel shows —
|
|
13029
|
+
* the "drag the widget to resize the agent" behavior, but through the same
|
|
13030
|
+
* smallest-client-wins negotiation as every other viewer (bounded by the operator's
|
|
13031
|
+
* local terminal + the 40×10 floor), NOT a raw /api/resize that scrambled everyone.
|
|
13032
|
+
* Debounced so a drag doesn't spam. Read-only widgets never report (pure observers).
|
|
13033
|
+
*/
|
|
13034
|
+
reportCap(cols, rows) {
|
|
13035
|
+
if (this.readOnly || !this.capViewerId) return;
|
|
13036
|
+
const g = globalThis;
|
|
13037
|
+
clearTimeout(this.capTimer);
|
|
13038
|
+
this.capTimer = setTimeout(() => {
|
|
13039
|
+
g.fetch(this.url("/api/presence"), {
|
|
13040
|
+
method: "POST",
|
|
13041
|
+
headers: { "content-type": "application/json" },
|
|
13042
|
+
body: JSON.stringify({
|
|
13043
|
+
viewer: this.capViewerId,
|
|
13044
|
+
agent: this.pid,
|
|
13045
|
+
cap: {
|
|
13046
|
+
cols,
|
|
13047
|
+
rows
|
|
13048
|
+
}
|
|
13049
|
+
})
|
|
13050
|
+
}).catch(() => {});
|
|
13051
|
+
}, 250);
|
|
13052
|
+
}
|
|
13053
|
+
/** Withdraw this widget's size cap (closed/minimized) → the daemon re-negotiates without it. */
|
|
13054
|
+
withdrawCap() {
|
|
13055
|
+
if (this.readOnly || !this.capViewerId) return;
|
|
13056
|
+
const g = globalThis;
|
|
13057
|
+
clearTimeout(this.capTimer);
|
|
13058
|
+
g.fetch(this.url("/api/presence"), {
|
|
13059
|
+
method: "POST",
|
|
13060
|
+
headers: { "content-type": "application/json" },
|
|
13061
|
+
body: JSON.stringify({
|
|
13062
|
+
viewer: this.capViewerId,
|
|
13063
|
+
agent: null
|
|
13064
|
+
})
|
|
13065
|
+
}).catch(() => {});
|
|
13022
13066
|
}
|
|
13023
13067
|
/** URL to a daemon API path with the token appended as a query param (EventSource can't set headers). */
|
|
13024
13068
|
url(path) {
|
|
@@ -13097,6 +13141,7 @@ var AyTerminal = class {
|
|
|
13097
13141
|
}
|
|
13098
13142
|
/** Tear down the stream, the terminal, and the mounted widget. */
|
|
13099
13143
|
close() {
|
|
13144
|
+
this.withdrawCap();
|
|
13100
13145
|
this.es?.close();
|
|
13101
13146
|
this.es = void 0;
|
|
13102
13147
|
this.term?.dispose();
|
|
@@ -13141,6 +13186,11 @@ var AyTerminal = class {
|
|
|
13141
13186
|
if (!xt || !xt.offsetWidth || !xt.offsetHeight) return;
|
|
13142
13187
|
const s = Math.min(1, wrap.clientWidth / xt.offsetWidth, wrap.clientHeight / xt.offsetHeight);
|
|
13143
13188
|
inner.style.transform = `scale(${s})`;
|
|
13189
|
+
if (!this.readOnly && this.term?.cols) {
|
|
13190
|
+
const capCols = Math.max(1, Math.floor(wrap.clientWidth * this.term.cols / xt.offsetWidth));
|
|
13191
|
+
const capRows = Math.max(1, Math.floor(wrap.clientHeight * this.term.rows / xt.offsetHeight));
|
|
13192
|
+
this.reportCap(capCols, capRows);
|
|
13193
|
+
}
|
|
13144
13194
|
};
|
|
13145
13195
|
if (inline) try {
|
|
13146
13196
|
const cs = g.getComputedStyle?.(target);
|
|
@@ -13172,6 +13222,7 @@ var AyTerminal = class {
|
|
|
13172
13222
|
panel.classList.toggle("open", on);
|
|
13173
13223
|
toggle.style.display = on ? "none" : "";
|
|
13174
13224
|
if (on) reflow();
|
|
13225
|
+
else this.withdrawCap();
|
|
13175
13226
|
};
|
|
13176
13227
|
toggle.addEventListener("click", () => showPanel(true));
|
|
13177
13228
|
root.getElementById("min")?.addEventListener("click", () => showPanel(false));
|
|
@@ -13435,4 +13486,4 @@ const XTERM_CSS = `
|
|
|
13435
13486
|
|
|
13436
13487
|
//#endregion
|
|
13437
13488
|
export { AyTerminal as t };
|
|
13438
|
-
//# sourceMappingURL=browser-
|
|
13489
|
+
//# sourceMappingURL=browser-C5pEBVVH.js.map
|
|
@@ -3,10 +3,10 @@ import "./globalPidIndex-D9DOSd-c.js";
|
|
|
3
3
|
import "./messageLog-C-YIzhRj.js";
|
|
4
4
|
import "./e2e-CEIdJGZ7.js";
|
|
5
5
|
import "./configShared-9wVlbPyC.js";
|
|
6
|
-
import "./subcommands-
|
|
6
|
+
import "./subcommands-3_ufv34d.js";
|
|
7
7
|
import "./webrtcLink-BMYneHbu.js";
|
|
8
8
|
import "./remotes-BxQnNxQv.js";
|
|
9
9
|
import "./callbackCore-Dd28_cBM.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-ClxIRUe8.js";
|
|
11
11
|
|
|
12
12
|
export { cmdCallback };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
|
|
2
|
-
import { P as resolveOne } from "./subcommands-
|
|
2
|
+
import { P as resolveOne } from "./subcommands-3_ufv34d.js";
|
|
3
3
|
import { a as mintCapability, o as parseExpires } from "./callbackCore-Dd28_cBM.js";
|
|
4
4
|
import { randomBytes } from "node:crypto";
|
|
5
5
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
@@ -72,7 +72,7 @@ async function resolveBase(flag) {
|
|
|
72
72
|
if (flag) return flag;
|
|
73
73
|
if (process.env.AGENT_YES_CALLBACK_BASE) return process.env.AGENT_YES_CALLBACK_BASE;
|
|
74
74
|
try {
|
|
75
|
-
const { resolveLocalServeUrl } = await import("./serve-
|
|
75
|
+
const { resolveLocalServeUrl } = await import("./serve-CqU8xkLF.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-ClxIRUe8.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { t as invokedCliName } from "./invokedCli-uqM2YYA7.js";
|
|
3
3
|
import { n as logger } from "./logger-CDIsZ-Pp.js";
|
|
4
|
-
import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-
|
|
5
|
-
import { n as getRustBinary } from "./rustBinary-
|
|
4
|
+
import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-Clt46j3c.js";
|
|
5
|
+
import { n as getRustBinary } from "./rustBinary-BQfAGsP1.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-DMN0ow0k.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-S4ojAM-G.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-S4ojAM-G.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, c as AgentContext, i as answerAsk, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-
|
|
2
|
+
import "./versionChecker-Clt46j3c.js";
|
|
3
|
+
import { a as hasTodoStore, c as AgentContext, i as answerAsk, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-CvwjBKbN.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-Buo457VO.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-D9DOSd-c.js";
|
|
@@ -3,7 +3,7 @@ import "./globalPidIndex-D9DOSd-c.js";
|
|
|
3
3
|
import "./messageLog-C-YIzhRj.js";
|
|
4
4
|
import "./e2e-CEIdJGZ7.js";
|
|
5
5
|
import "./configShared-9wVlbPyC.js";
|
|
6
|
-
import { $ as shouldStealLock, C as listRecords, J as hostId, K as appendEvent, Q as readInbox, X as listInboxParents, Z as liveWatchers, _ as isPidAlive, c as deriveLiveState, et as daemonLockDir, j as renderLogTailLines, nt as notifyDir, q as gcInboxes, tt as daemonLockOwnerPath } from "./subcommands-
|
|
6
|
+
import { $ as shouldStealLock, C as listRecords, J as hostId, K as appendEvent, Q as readInbox, X as listInboxParents, Z as liveWatchers, _ as isPidAlive, c as deriveLiveState, et as daemonLockDir, j as renderLogTailLines, nt as notifyDir, q as gcInboxes, tt as daemonLockOwnerPath } from "./subcommands-3_ufv34d.js";
|
|
7
7
|
import "./webrtcLink-BMYneHbu.js";
|
|
8
8
|
import "./remotes-BxQnNxQv.js";
|
|
9
9
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "fs/promises";
|
|
@@ -589,4 +589,4 @@ async function ensureDaemon() {
|
|
|
589
589
|
|
|
590
590
|
//#endregion
|
|
591
591
|
export { daemonStatus, ensureDaemon, requestDaemonStop, runDaemon };
|
|
592
|
-
//# sourceMappingURL=notifyDaemon-
|
|
592
|
+
//# sourceMappingURL=notifyDaemon-B5MzTdlN.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as getInstalledPackage } from "./versionChecker-
|
|
1
|
+
import { r as getInstalledPackage } from "./versionChecker-Clt46j3c.js";
|
|
2
2
|
import { execFileSync } from "child_process";
|
|
3
3
|
import { existsSync, mkdirSync, unlinkSync } from "fs";
|
|
4
4
|
import { chmod, copyFile } from "fs/promises";
|
|
@@ -225,4 +225,4 @@ async function getRustBinary(options = {}) {
|
|
|
225
225
|
|
|
226
226
|
//#endregion
|
|
227
227
|
export { getRustBinary as n, findSpawnHiddenLauncher as t };
|
|
228
|
-
//# sourceMappingURL=rustBinary-
|
|
228
|
+
//# sourceMappingURL=rustBinary-BQfAGsP1.js.map
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import "./logger-CDIsZ-Pp.js";
|
|
2
|
-
import "./versionChecker-
|
|
3
|
-
import "./ts-
|
|
2
|
+
import "./versionChecker-Clt46j3c.js";
|
|
3
|
+
import "./ts-CvwjBKbN.js";
|
|
4
4
|
import "./todoAutomation-Buo457VO.js";
|
|
5
5
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
6
6
|
import "./globalPidIndex-D9DOSd-c.js";
|
|
7
7
|
import "./pidStore-6EZd5DUv.js";
|
|
8
8
|
import "./messageLog-C-YIzhRj.js";
|
|
9
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
9
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-GdCVJMMr.js";
|
|
10
10
|
import { d as resolveSpawnCwd } from "./workspaceConfig-DOHygA2x.js";
|
|
11
11
|
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-BtL6Oo1o.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-YeMh-VJF.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 { i as answerAsk, l as CLAUDE_SESSION_PIN_ENV, o as listAsks } from "./ts-
|
|
2
|
+
import { r as getInstalledPackage } from "./versionChecker-Clt46j3c.js";
|
|
3
|
+
import { t as findSpawnHiddenLauncher } from "./rustBinary-BQfAGsP1.js";
|
|
4
|
+
import { i as answerAsk, l as CLAUDE_SESSION_PIN_ENV, o as listAsks } from "./ts-CvwjBKbN.js";
|
|
5
5
|
import { t as agentYesHome$1 } from "./agentYesHome-CtmsY6I-.js";
|
|
6
6
|
import { x as removeControlCharacters } from "./todoAutomation-Buo457VO.js";
|
|
7
7
|
import "./JsonlStore-CPGIR0Wy.js";
|
|
@@ -11,17 +11,17 @@ import { r as recordInbox } from "./messageLog-C-YIzhRj.js";
|
|
|
11
11
|
import { t as pgidForWrapper } from "./reaper-DP49VCKx.js";
|
|
12
12
|
import "./e2e-CEIdJGZ7.js";
|
|
13
13
|
import "./configShared-9wVlbPyC.js";
|
|
14
|
-
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-
|
|
15
|
-
import { A as recentReadEdges, C as listRecords, D as readNotes, G as writeToIpc, M as renderRawLog, N as renderRawLogLines, O as readPtysize, P as resolveOne, Y as isTransientLockMkdirError, f as extractNeedsInput, j as renderLogTailLines, k as recentMessageEdges, l as deriveLiveStatus, o as controlCodeFromName, p as extractTaskCounts, rt as TYPING_BADGE, u as extractBadges, x as isUserTyping, z as snapshotStatus } from "./subcommands-
|
|
14
|
+
import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-GdCVJMMr.js";
|
|
15
|
+
import { A as recentReadEdges, C as listRecords, D as readNotes, G as writeToIpc, M as renderRawLog, N as renderRawLogLines, O as readPtysize, P as resolveOne, Y as isTransientLockMkdirError, f as extractNeedsInput, j as renderLogTailLines, k as recentMessageEdges, l as deriveLiveStatus, o as controlCodeFromName, p as extractTaskCounts, rt as TYPING_BADGE, u as extractBadges, x as isUserTyping, z as snapshotStatus } from "./subcommands-3_ufv34d.js";
|
|
16
16
|
import "./webrtcLink-BMYneHbu.js";
|
|
17
17
|
import "./remotes-BxQnNxQv.js";
|
|
18
18
|
import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-Dd28_cBM.js";
|
|
19
|
-
import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-
|
|
19
|
+
import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-ClxIRUe8.js";
|
|
20
20
|
import { a as getSpawnHook, c as hasProvisionHook, d as resolveSpawnCwd, i as getProvisionRoot, l as hasSpawnHook, r as getProvisionHook, u as isProvisionAllowed } from "./workspaceConfig-DOHygA2x.js";
|
|
21
21
|
import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-BtL6Oo1o.js";
|
|
22
22
|
import { r as spawnRejectionReason } from "./spawnGate-BxgS_GlF.js";
|
|
23
23
|
import yargs from "yargs";
|
|
24
|
-
import { appendFile, mkdir, open, readFile, rename, rm, stat, unlink, writeFile } from "fs/promises";
|
|
24
|
+
import { appendFile, mkdir, open, readFile, readdir, rename, rm, stat, unlink, writeFile } from "fs/promises";
|
|
25
25
|
import { arch, cpus, freemem, homedir, hostname, loadavg, platform, totalmem, uptime, userInfo } from "os";
|
|
26
26
|
import path from "path";
|
|
27
27
|
import { execFileSync } from "node:child_process";
|
|
@@ -493,7 +493,7 @@ function authorizeRequest(req, expectedToken) {
|
|
|
493
493
|
return null;
|
|
494
494
|
}
|
|
495
495
|
function isTermCorsPath(p) {
|
|
496
|
-
return /^\/api\/(tail|size)\/.+$/.test(p) || p === "/api/send" || /^\/api\/resize\/.+$/.test(p) || p.startsWith("/api/widget/");
|
|
496
|
+
return /^\/api\/(tail|size)\/.+$/.test(p) || p === "/api/send" || p === "/api/presence" || /^\/api\/resize\/.+$/.test(p) || p.startsWith("/api/widget/");
|
|
497
497
|
}
|
|
498
498
|
function withTermCors(req, res) {
|
|
499
499
|
if (!res) return res;
|
|
@@ -537,6 +537,7 @@ async function scopedGate(scope, method, p) {
|
|
|
537
537
|
if (method === "POST" && p === "/api/send") return needs("send");
|
|
538
538
|
const rz = /^\/api\/resize\/(.+)$/.exec(p);
|
|
539
539
|
if (method === "POST" && rz) return needs("resize") ?? (await scopedKeywordOk(decodeURIComponent(rz[1]), scope) ? null : forbid("scoped token: not bound to this agent"));
|
|
540
|
+
if (method === "POST" && p === "/api/presence") return needs("resize");
|
|
540
541
|
if (p.startsWith("/api/widget/")) return needs("read");
|
|
541
542
|
return forbid("scoped token: route not permitted");
|
|
542
543
|
}
|
|
@@ -1720,6 +1721,46 @@ Options:
|
|
|
1720
1721
|
};
|
|
1721
1722
|
const presence = /* @__PURE__ */ new Map();
|
|
1722
1723
|
const PRESENCE_TTL_MS = 12e3;
|
|
1724
|
+
const CAP_TTL_MS = 12e3;
|
|
1725
|
+
const daemonTag = `d${process.pid}`;
|
|
1726
|
+
const capsDir = (pid) => path.join(agentYesHome(), "caps", String(pid));
|
|
1727
|
+
const capFile = (pid, key) => path.join(capsDir(pid), key.replace(/[^\w.:-]/g, "_"));
|
|
1728
|
+
const publishCap = async (pid, viewer, cap, role) => {
|
|
1729
|
+
try {
|
|
1730
|
+
await mkdir(capsDir(pid), { recursive: true });
|
|
1731
|
+
await writeFile(capFile(pid, `${daemonTag}:${viewer}`), `${cap.cols} ${cap.rows} ${Date.now()} ${role}\n`);
|
|
1732
|
+
} catch {}
|
|
1733
|
+
};
|
|
1734
|
+
const withdrawCap = async (pid, viewer) => {
|
|
1735
|
+
await unlink(capFile(pid, `${daemonTag}:${viewer}`)).catch(() => {});
|
|
1736
|
+
};
|
|
1737
|
+
const readSharedCaps = async (pid) => {
|
|
1738
|
+
let files;
|
|
1739
|
+
try {
|
|
1740
|
+
files = await readdir(capsDir(pid));
|
|
1741
|
+
} catch {
|
|
1742
|
+
return [];
|
|
1743
|
+
}
|
|
1744
|
+
const now = Date.now();
|
|
1745
|
+
const caps = [];
|
|
1746
|
+
for (const f of files) {
|
|
1747
|
+
const fp = path.join(capsDir(pid), f);
|
|
1748
|
+
try {
|
|
1749
|
+
const parts = (await readFile(fp, "utf-8")).trim().split(/\s+/);
|
|
1750
|
+
const ts = Number(parts[2]);
|
|
1751
|
+
if (!Number.isFinite(ts) || now - ts > CAP_TTL_MS) {
|
|
1752
|
+
await unlink(fp).catch(() => {});
|
|
1753
|
+
continue;
|
|
1754
|
+
}
|
|
1755
|
+
const cap = sanitizeCap({
|
|
1756
|
+
cols: Number(parts[0]),
|
|
1757
|
+
rows: Number(parts[1])
|
|
1758
|
+
});
|
|
1759
|
+
if (cap) caps.push(cap);
|
|
1760
|
+
} catch {}
|
|
1761
|
+
}
|
|
1762
|
+
return caps;
|
|
1763
|
+
};
|
|
1723
1764
|
const negoApplied = /* @__PURE__ */ new Map();
|
|
1724
1765
|
const negoTimers = /* @__PURE__ */ new Map();
|
|
1725
1766
|
const negoCapsGoneAt = /* @__PURE__ */ new Map();
|
|
@@ -1740,24 +1781,29 @@ Options:
|
|
|
1740
1781
|
}
|
|
1741
1782
|
};
|
|
1742
1783
|
const winsizePathFor = (pid) => path.join(process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes"), "winsize", String(pid));
|
|
1743
|
-
const liveCapsFor = (pid) => {
|
|
1744
|
-
const now = Date.now();
|
|
1745
|
-
const caps = [];
|
|
1746
|
-
for (const v of presence.values()) if (now - v.ts <= PRESENCE_TTL_MS && String(v.agent) === String(pid) && v.cap) caps.push(v.cap);
|
|
1747
|
-
return caps;
|
|
1748
|
-
};
|
|
1749
1784
|
const applyNego = async (pid) => {
|
|
1750
1785
|
negoTimers.delete(pid);
|
|
1751
|
-
const
|
|
1786
|
+
const caps = await readSharedCaps(pid);
|
|
1787
|
+
const eff = negotiateSize(caps);
|
|
1752
1788
|
const file = winsizePathFor(pid);
|
|
1753
1789
|
const prev = negoApplied.get(pid);
|
|
1754
1790
|
try {
|
|
1755
1791
|
if (eff) {
|
|
1756
1792
|
negoCapsGoneAt.delete(pid);
|
|
1757
1793
|
if (prev && Math.abs(prev.cols - eff.cols) <= 1 && Math.abs(prev.rows - eff.rows) <= 1) return;
|
|
1794
|
+
try {
|
|
1795
|
+
const curr = (await readFile(file, "utf-8")).trim().split(/\s+/);
|
|
1796
|
+
if (Number(curr[0]) === eff.cols && Number(curr[1]) === eff.rows) {
|
|
1797
|
+
negoApplied.set(pid, {
|
|
1798
|
+
cols: eff.cols,
|
|
1799
|
+
rows: eff.rows,
|
|
1800
|
+
content: ""
|
|
1801
|
+
});
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1804
|
+
} catch {}
|
|
1758
1805
|
const content = `${eff.cols} ${eff.rows} ${Date.now()}\n`;
|
|
1759
|
-
|
|
1760
|
-
process.stderr.write(`[api/resize] pid=${pid} ${eff.cols}x${eff.rows} src=presence-nego caps=${liveCapsFor(pid).length} viewers=${srcViewers || "-"}\n`);
|
|
1806
|
+
process.stderr.write(`[api/resize] pid=${pid} ${eff.cols}x${eff.rows} src=presence-nego daemon=${daemonTag} caps=${caps.length}\n`);
|
|
1761
1807
|
await mkdir(path.dirname(file), { recursive: true });
|
|
1762
1808
|
await writeFile(file, content);
|
|
1763
1809
|
negoApplied.set(pid, {
|
|
@@ -2248,7 +2294,7 @@ Options:
|
|
|
2248
2294
|
}
|
|
2249
2295
|
});
|
|
2250
2296
|
if (req.method === "GET" && p === "/api/ws") {
|
|
2251
|
-
const ws = await import("./ws-
|
|
2297
|
+
const ws = await import("./ws-CkSYDYiN.js");
|
|
2252
2298
|
try {
|
|
2253
2299
|
await ws.loadProvision();
|
|
2254
2300
|
} catch (e) {
|
|
@@ -2268,7 +2314,7 @@ Options:
|
|
|
2268
2314
|
if (req.method === "GET" && p === "/api/ws/status") {
|
|
2269
2315
|
const dirRaw = url.searchParams.get("path");
|
|
2270
2316
|
if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
|
|
2271
|
-
const ws = await import("./ws-
|
|
2317
|
+
const ws = await import("./ws-CkSYDYiN.js");
|
|
2272
2318
|
let prov;
|
|
2273
2319
|
try {
|
|
2274
2320
|
prov = await ws.loadProvision();
|
|
@@ -2778,7 +2824,9 @@ Options:
|
|
|
2778
2824
|
}
|
|
2779
2825
|
const viewer = String(b.viewer ?? "").slice(0, 64);
|
|
2780
2826
|
if (!viewer) return new Response("missing viewer", { status: 400 });
|
|
2827
|
+
if (authResult.kind === "scoped" && b.agent != null && String(b.agent) !== authResult.scope.pid) return new Response("scoped token: not bound to this agent", { status: 403 });
|
|
2781
2828
|
const prevAgent = presence.get(viewer)?.agent;
|
|
2829
|
+
const cap = sanitizeCap(b.cap);
|
|
2782
2830
|
if (b.agent == null) presence.delete(viewer);
|
|
2783
2831
|
else presence.set(viewer, {
|
|
2784
2832
|
viewer,
|
|
@@ -2786,10 +2834,15 @@ Options:
|
|
|
2786
2834
|
cols: Math.max(0, Math.floor(Number(b.cols) || 0)),
|
|
2787
2835
|
rows: Math.max(0, Math.floor(Number(b.rows) || 0)),
|
|
2788
2836
|
sel: typeof b.sel === "string" ? b.sel.slice(0, 200) : null,
|
|
2789
|
-
cap
|
|
2837
|
+
cap,
|
|
2790
2838
|
ts: Date.now()
|
|
2791
2839
|
});
|
|
2792
|
-
if (
|
|
2840
|
+
if (prevAgent != null && String(prevAgent) !== String(b.agent ?? "")) await withdrawCap(Number(prevAgent), viewer);
|
|
2841
|
+
if (b.agent != null) {
|
|
2842
|
+
if (cap) await publishCap(Number(b.agent), viewer, cap, "viewer");
|
|
2843
|
+
else await withdrawCap(Number(b.agent), viewer);
|
|
2844
|
+
scheduleNego(Number(b.agent));
|
|
2845
|
+
}
|
|
2793
2846
|
if (prevAgent != null && String(prevAgent) !== String(b.agent ?? "")) scheduleNego(Number(prevAgent));
|
|
2794
2847
|
return new Response(null, { status: 204 });
|
|
2795
2848
|
}
|
|
@@ -2992,7 +3045,7 @@ Options:
|
|
|
2992
3045
|
const perm = body.perm ?? "r";
|
|
2993
3046
|
if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
|
|
2994
3047
|
try {
|
|
2995
|
-
const { createScopedShare } = await import("./agentShare-
|
|
3048
|
+
const { createScopedShare } = await import("./agentShare-BoBeAnvX.js");
|
|
2996
3049
|
const share = await createScopedShare({
|
|
2997
3050
|
agent: body.agent,
|
|
2998
3051
|
perm,
|
|
@@ -3007,12 +3060,12 @@ Options:
|
|
|
3007
3060
|
}
|
|
3008
3061
|
}
|
|
3009
3062
|
if (req.method === "GET" && p === "/api/shares") {
|
|
3010
|
-
const { listShares } = await import("./agentShare-
|
|
3063
|
+
const { listShares } = await import("./agentShare-BoBeAnvX.js");
|
|
3011
3064
|
return Response.json(listShares());
|
|
3012
3065
|
}
|
|
3013
3066
|
const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
|
|
3014
3067
|
if (req.method === "DELETE" && revokeM) {
|
|
3015
|
-
const { revokeShare } = await import("./agentShare-
|
|
3068
|
+
const { revokeShare } = await import("./agentShare-BoBeAnvX.js");
|
|
3016
3069
|
const ok = revokeShare(decodeURIComponent(revokeM[1]));
|
|
3017
3070
|
return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
|
|
3018
3071
|
}
|
|
@@ -3314,7 +3367,7 @@ Options:
|
|
|
3314
3367
|
const shutdown = (resolve) => {
|
|
3315
3368
|
if (heartbeat) clearInterval(heartbeat);
|
|
3316
3369
|
closeShare?.();
|
|
3317
|
-
import("./agentShare-
|
|
3370
|
+
import("./agentShare-BoBeAnvX.js").then((m) => m.revokeAllShares()).catch(() => {});
|
|
3318
3371
|
server?.stop();
|
|
3319
3372
|
Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
|
|
3320
3373
|
};
|
|
@@ -3327,4 +3380,4 @@ Options:
|
|
|
3327
3380
|
|
|
3328
3381
|
//#endregion
|
|
3329
3382
|
export { cmdServe, loadTokenReadOnly, mintScopedTermToken, resolveDaemonHttpBase, resolveLocalServeUrl };
|
|
3330
|
-
//# sourceMappingURL=serve-
|
|
3383
|
+
//# sourceMappingURL=serve-CqU8xkLF.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-CqU8xkLF.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-CGkSgbE8.js.map
|
|
@@ -1267,31 +1267,31 @@ async function runSubcommand(argv) {
|
|
|
1267
1267
|
return cmdCh(rest);
|
|
1268
1268
|
}
|
|
1269
1269
|
case "term": {
|
|
1270
|
-
const { cmdTerm } = await import("./terminal-
|
|
1270
|
+
const { cmdTerm } = await import("./terminal-D6idrXwY.js");
|
|
1271
1271
|
return cmdTerm(rest);
|
|
1272
1272
|
}
|
|
1273
1273
|
case "widget": {
|
|
1274
|
-
const { cmdWidget } = await import("./widget-
|
|
1274
|
+
const { cmdWidget } = await import("./widget-BPCw2Vhm.js");
|
|
1275
1275
|
return cmdWidget(rest);
|
|
1276
1276
|
}
|
|
1277
1277
|
case "mint": {
|
|
1278
|
-
const { cmdMint } = await import("./widget-
|
|
1278
|
+
const { cmdMint } = await import("./widget-BPCw2Vhm.js");
|
|
1279
1279
|
return cmdMint(rest);
|
|
1280
1280
|
}
|
|
1281
1281
|
case "serve": {
|
|
1282
|
-
const { cmdServe } = await import("./serve-
|
|
1282
|
+
const { cmdServe } = await import("./serve-CqU8xkLF.js");
|
|
1283
1283
|
return cmdServe(rest);
|
|
1284
1284
|
}
|
|
1285
1285
|
case "setup": {
|
|
1286
|
-
const { cmdSetup } = await import("./setup-
|
|
1286
|
+
const { cmdSetup } = await import("./setup-CGkSgbE8.js");
|
|
1287
1287
|
return cmdSetup(rest);
|
|
1288
1288
|
}
|
|
1289
1289
|
case "ws": {
|
|
1290
|
-
const { cmdWs } = await import("./ws-
|
|
1290
|
+
const { cmdWs } = await import("./ws-CkSYDYiN.js");
|
|
1291
1291
|
return cmdWs(rest);
|
|
1292
1292
|
}
|
|
1293
1293
|
case "schedule": {
|
|
1294
|
-
const { cmdSchedule } = await import("./schedule-
|
|
1294
|
+
const { cmdSchedule } = await import("./schedule-YeMh-VJF.js");
|
|
1295
1295
|
return cmdSchedule(rest);
|
|
1296
1296
|
}
|
|
1297
1297
|
case "remote": {
|
|
@@ -1303,7 +1303,7 @@ async function runSubcommand(argv) {
|
|
|
1303
1303
|
return cmdExpose(rest);
|
|
1304
1304
|
}
|
|
1305
1305
|
case "callback": {
|
|
1306
|
-
const { cmdCallback } = await import("./callback-
|
|
1306
|
+
const { cmdCallback } = await import("./callback-CXGpMnF9.js");
|
|
1307
1307
|
return cmdCallback(rest);
|
|
1308
1308
|
}
|
|
1309
1309
|
case "reap":
|
|
@@ -4342,7 +4342,7 @@ async function cmdNotify(rest) {
|
|
|
4342
4342
|
}
|
|
4343
4343
|
const ensure = async () => {
|
|
4344
4344
|
if (!argv["ensure-daemon"]) return;
|
|
4345
|
-
const { ensureDaemon } = await import("./notifyDaemon-
|
|
4345
|
+
const { ensureDaemon } = await import("./notifyDaemon-B5MzTdlN.js");
|
|
4346
4346
|
await ensureDaemon().catch(() => null);
|
|
4347
4347
|
};
|
|
4348
4348
|
await heartbeatWatcher(parent, selfStartedAt);
|
|
@@ -4416,7 +4416,7 @@ async function cmdNotifyCursor(args) {
|
|
|
4416
4416
|
}
|
|
4417
4417
|
async function cmdNotifyd(rest) {
|
|
4418
4418
|
const sub = rest[0] ?? "status";
|
|
4419
|
-
const daemon = await import("./notifyDaemon-
|
|
4419
|
+
const daemon = await import("./notifyDaemon-B5MzTdlN.js");
|
|
4420
4420
|
switch (sub) {
|
|
4421
4421
|
case "run": return daemon.runDaemon();
|
|
4422
4422
|
case "once": return daemon.runDaemon({ once: true });
|
|
@@ -4443,4 +4443,4 @@ async function cmdNotifyd(rest) {
|
|
|
4443
4443
|
|
|
4444
4444
|
//#endregion
|
|
4445
4445
|
export { shouldStealLock as $, recentReadEdges as A, stdinActivityPath as B, listRecords as C, readNotes as D, readAgentPtysize as E, resolveReadWindow as F, writeToIpc as G, submitAndConfirm as H, resolveResumeArgs as I, hostId as J, appendEvent as K, restartHintLines as L, renderRawLog as M, renderRawLogLines as N, readPtysize as O, resolveOne as P, readInbox as Q, runSubcommand as R, lastStdinAt as S, menuSelectKeys as T, waitForLogQuiet as U, stopTipForCli as V, writeKeysPaced as W, listInboxParents as X, isTransientLockMkdirError as Y, liveWatchers as Z, isPidAlive as _, cmdHelp as a, isUnknownManagerToken as b, deriveLiveState as c, extractMenu as d, daemonLockDir as et, extractNeedsInput as f, isExitRequest as g, isAgentStuck as h, backoffWhileTyping as i, renderLogTailLines as j, recentMessageEdges as k, deriveLiveStatus as l, finalizedLines as m, READ_PAGE_DEFAULT as n, notifyDir as nt, controlCodeFromName as o, extractTaskCounts as p, gcInboxes as q, TYPING_WINDOW_MS as r, TYPING_BADGE as rt, cursorAbs as s, GRACEFUL_EXIT_COMMANDS as t, daemonLockOwnerPath as tt, extractBadges as u, isSlashCommand as v, matchKeyword as w, isUserTyping as x, isSubcommand as y, snapshotStatus as z };
|
|
4446
|
-
//# sourceMappingURL=subcommands-
|
|
4446
|
+
//# sourceMappingURL=subcommands-3_ufv34d.js.map
|
|
@@ -3,7 +3,7 @@ import "./globalPidIndex-D9DOSd-c.js";
|
|
|
3
3
|
import "./messageLog-C-YIzhRj.js";
|
|
4
4
|
import "./e2e-CEIdJGZ7.js";
|
|
5
5
|
import "./configShared-9wVlbPyC.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-
|
|
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-3_ufv34d.js";
|
|
7
7
|
import "./webrtcLink-BMYneHbu.js";
|
|
8
8
|
import "./remotes-BxQnNxQv.js";
|
|
9
9
|
|
|
@@ -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-CqU8xkLF.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-D6idrXwY.js.map
|
package/dist/terminal.js
CHANGED
|
@@ -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-Clt46j3c.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-Buo457VO.js";
|
|
6
6
|
import { i as shouldUseLock, r as releaseLock, t as acquireLock } from "./runningLock-DBoONoM-.js";
|
|
@@ -2027,4 +2027,4 @@ function sleep(ms) {
|
|
|
2027
2027
|
|
|
2028
2028
|
//#endregion
|
|
2029
2029
|
export { hasTodoStore as a, AgentContext as c, answerAsk as i, CLAUDE_SESSION_PIN_ENV as l, agentYes as n, listAsks as o, config as r, listAsksForProject as s, CLIS_CONFIG as t };
|
|
2030
|
-
//# sourceMappingURL=ts-
|
|
2030
|
+
//# sourceMappingURL=ts-CvwjBKbN.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.243.0-beta.579.1";
|
|
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-Clt46j3c.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-CqU8xkLF.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-CqU8xkLF.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-BPCw2Vhm.js.map
|
package/dist/widgets.js
CHANGED
|
@@ -2,7 +2,7 @@ import "./e2e-CEIdJGZ7.js";
|
|
|
2
2
|
import "./channels-BiGUYTuz.js";
|
|
3
3
|
import "./peer-B5JKF4BP.js";
|
|
4
4
|
import { t as AyChannel } from "./browser-B3dOptjL.js";
|
|
5
|
-
import { t as AyTerminal } from "./browser-
|
|
5
|
+
import { t as AyTerminal } from "./browser-C5pEBVVH.js";
|
|
6
6
|
import { AyWidget } from "./widget.js";
|
|
7
7
|
|
|
8
8
|
export { AyChannel, AyTerminal, AyWidget };
|
|
@@ -3,7 +3,7 @@ import "./globalPidIndex-D9DOSd-c.js";
|
|
|
3
3
|
import "./messageLog-C-YIzhRj.js";
|
|
4
4
|
import "./e2e-CEIdJGZ7.js";
|
|
5
5
|
import "./configShared-9wVlbPyC.js";
|
|
6
|
-
import { C as listRecords } from "./subcommands-
|
|
6
|
+
import { C as listRecords } from "./subcommands-3_ufv34d.js";
|
|
7
7
|
import "./webrtcLink-BMYneHbu.js";
|
|
8
8
|
import "./remotes-BxQnNxQv.js";
|
|
9
9
|
import { i as getProvisionRoot } from "./workspaceConfig-DOHygA2x.js";
|
|
@@ -418,4 +418,4 @@ async function cmdWs(args) {
|
|
|
418
418
|
|
|
419
419
|
//#endregion
|
|
420
420
|
export { WS_JSON_SCHEMA, cmdWs, collectWorkspaces, isPathInside, loadProvision, workspaceStatus };
|
|
421
|
-
//# sourceMappingURL=ws-
|
|
421
|
+
//# sourceMappingURL=ws-CkSYDYiN.js.map
|
package/package.json
CHANGED
package/ts/serve.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { appendFile, mkdir, open, readFile, stat, unlink, writeFile } from "fs/promises";
|
|
1
|
+
import { appendFile, mkdir, open, readdir, readFile, stat, unlink, writeFile } from "fs/promises";
|
|
2
2
|
import { existsSync, renameSync, watch, writeFileSync } from "node:fs";
|
|
3
3
|
import { execFileSync } from "node:child_process";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -244,6 +244,7 @@ function isTermCorsPath(p: string): boolean {
|
|
|
244
244
|
return (
|
|
245
245
|
/^\/api\/(tail|size)\/.+$/.test(p) ||
|
|
246
246
|
p === "/api/send" ||
|
|
247
|
+
p === "/api/presence" ||
|
|
247
248
|
/^\/api\/resize\/.+$/.test(p) ||
|
|
248
249
|
p.startsWith("/api/widget/")
|
|
249
250
|
);
|
|
@@ -320,6 +321,12 @@ async function scopedGate(
|
|
|
320
321
|
: forbid("scoped token: not bound to this agent"))
|
|
321
322
|
);
|
|
322
323
|
}
|
|
324
|
+
// A viewer reporting its size CAP (3c widget drag-resize) participates in the
|
|
325
|
+
// resize negotiation, so it needs the resize cap; the presence handler binds the
|
|
326
|
+
// reported `agent` to the token's pid.
|
|
327
|
+
if (method === "POST" && p === "/api/presence") {
|
|
328
|
+
return needs("resize");
|
|
329
|
+
}
|
|
323
330
|
// Widget sensor routes: require the 'read' cap; the widget-route handlers do the
|
|
324
331
|
// fine-grained viewer-binding (and the 'screenshot' cap check for that kind).
|
|
325
332
|
if (p.startsWith("/api/widget/")) {
|
|
@@ -2092,6 +2099,63 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
2092
2099
|
>();
|
|
2093
2100
|
const PRESENCE_TTL_MS = 12_000;
|
|
2094
2101
|
|
|
2102
|
+
// ── Shared cap store (3a: multi-daemon size negotiation) ────────────────────
|
|
2103
|
+
// Presence is in-memory PER DAEMON, so multiple `ay serve` processes (the HTTP
|
|
2104
|
+
// daemon + each `--webrtc share` daemon) used to negotiate independently and
|
|
2105
|
+
// fight over the single winsize file (cross-process last-writer-wins). Instead
|
|
2106
|
+
// every daemon publishes each viewer's size cap to a SHARED on-disk store —
|
|
2107
|
+
// ~/.agent-yes/caps/<pid>/<daemon>:<viewer> — and negotiation reads the WHOLE
|
|
2108
|
+
// store (all daemons' viewers + the local-tty cap, 3b). Deterministic min +
|
|
2109
|
+
// read-before-write means every daemon converges on the same winsize instead of
|
|
2110
|
+
// clobbering each other. Lock-free: one writer per file (a daemon owns its own
|
|
2111
|
+
// viewers' entries), short TTL prunes tabs that vanished without a clean clear.
|
|
2112
|
+
const CAP_TTL_MS = 12_000;
|
|
2113
|
+
const daemonTag = `d${process.pid}`; // unique per daemon process
|
|
2114
|
+
const capsDir = (pid: number) => path.join(agentYesHome(), "caps", String(pid));
|
|
2115
|
+
const capFile = (pid: number, key: string) =>
|
|
2116
|
+
path.join(capsDir(pid), key.replace(/[^\w.:-]/g, "_"));
|
|
2117
|
+
const publishCap = async (pid: number, viewer: string, cap: SizeCap, role: string) => {
|
|
2118
|
+
try {
|
|
2119
|
+
await mkdir(capsDir(pid), { recursive: true });
|
|
2120
|
+
await writeFile(
|
|
2121
|
+
capFile(pid, `${daemonTag}:${viewer}`),
|
|
2122
|
+
`${cap.cols} ${cap.rows} ${Date.now()} ${role}\n`,
|
|
2123
|
+
);
|
|
2124
|
+
} catch {
|
|
2125
|
+
/* best-effort */
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
const withdrawCap = async (pid: number, viewer: string) => {
|
|
2129
|
+
await unlink(capFile(pid, `${daemonTag}:${viewer}`)).catch(() => {});
|
|
2130
|
+
};
|
|
2131
|
+
// Read every live cap for a pid across ALL daemons; prune expired files.
|
|
2132
|
+
const readSharedCaps = async (pid: number): Promise<SizeCap[]> => {
|
|
2133
|
+
let files: string[];
|
|
2134
|
+
try {
|
|
2135
|
+
files = await readdir(capsDir(pid));
|
|
2136
|
+
} catch {
|
|
2137
|
+
return [];
|
|
2138
|
+
}
|
|
2139
|
+
const now = Date.now();
|
|
2140
|
+
const caps: SizeCap[] = [];
|
|
2141
|
+
for (const f of files) {
|
|
2142
|
+
const fp = path.join(capsDir(pid), f);
|
|
2143
|
+
try {
|
|
2144
|
+
const parts = (await readFile(fp, "utf-8")).trim().split(/\s+/);
|
|
2145
|
+
const ts = Number(parts[2]);
|
|
2146
|
+
if (!Number.isFinite(ts) || now - ts > CAP_TTL_MS) {
|
|
2147
|
+
await unlink(fp).catch(() => {}); // stale (its writer vanished) — prune
|
|
2148
|
+
continue;
|
|
2149
|
+
}
|
|
2150
|
+
const cap = sanitizeCap({ cols: Number(parts[0]), rows: Number(parts[1]) });
|
|
2151
|
+
if (cap) caps.push(cap);
|
|
2152
|
+
} catch {
|
|
2153
|
+
/* unreadable/racing — skip */
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
return caps;
|
|
2157
|
+
};
|
|
2158
|
+
|
|
2095
2159
|
// ── PTY size negotiation — tmux's "smallest client wins" ──────────────────
|
|
2096
2160
|
// Writable viewers report their readable capacity (`cap`) alongside their
|
|
2097
2161
|
// presence; we resize the agent's PTY to the elementwise min across live caps
|
|
@@ -2137,17 +2201,12 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
2137
2201
|
"winsize",
|
|
2138
2202
|
String(pid),
|
|
2139
2203
|
);
|
|
2140
|
-
const liveCapsFor = (pid: number): SizeCap[] => {
|
|
2141
|
-
const now = Date.now();
|
|
2142
|
-
const caps: SizeCap[] = [];
|
|
2143
|
-
for (const v of presence.values())
|
|
2144
|
-
if (now - v.ts <= PRESENCE_TTL_MS && String(v.agent) === String(pid) && v.cap)
|
|
2145
|
-
caps.push(v.cap);
|
|
2146
|
-
return caps;
|
|
2147
|
-
};
|
|
2148
2204
|
const applyNego = async (pid: number) => {
|
|
2149
2205
|
negoTimers.delete(pid);
|
|
2150
|
-
|
|
2206
|
+
// Negotiate over the SHARED cap store — every daemon's viewers (+ the local
|
|
2207
|
+
// tty cap, 3b) — so all daemons compute the same min and converge.
|
|
2208
|
+
const caps = await readSharedCaps(pid);
|
|
2209
|
+
const eff = negotiateSize(caps);
|
|
2151
2210
|
const file = winsizePathFor(pid);
|
|
2152
2211
|
const prev = negoApplied.get(pid);
|
|
2153
2212
|
try {
|
|
@@ -2158,20 +2217,25 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
2158
2217
|
// SIGWINCH reflow on every re-visit is exactly the churn users notice.
|
|
2159
2218
|
if (prev && Math.abs(prev.cols - eff.cols) <= 1 && Math.abs(prev.rows - eff.rows) <= 1)
|
|
2160
2219
|
return;
|
|
2220
|
+
// Cross-daemon convergence: if the winsize file ALREADY holds this size (a
|
|
2221
|
+
// sibling daemon negotiated the same min), do NOT rewrite/re-SIGWINCH — else
|
|
2222
|
+
// two daemons thrash the PTY with same-size, different-timestamp writes.
|
|
2223
|
+
try {
|
|
2224
|
+
const curr = (await readFile(file, "utf-8")).trim().split(/\s+/);
|
|
2225
|
+
if (Number(curr[0]) === eff.cols && Number(curr[1]) === eff.rows) {
|
|
2226
|
+
negoApplied.set(pid, { cols: eff.cols, rows: eff.rows, content: "" });
|
|
2227
|
+
return;
|
|
2228
|
+
}
|
|
2229
|
+
} catch {
|
|
2230
|
+
/* no winsize file yet — fall through and write it */
|
|
2231
|
+
}
|
|
2161
2232
|
const content = `${eff.cols} ${eff.rows} ${Date.now()}\n`;
|
|
2162
|
-
//
|
|
2163
|
-
//
|
|
2164
|
-
//
|
|
2165
|
-
// HERE, which otherwise leaves no trace and looks like "nobody pushed".
|
|
2166
|
-
const srcViewers = [...presence.values()]
|
|
2167
|
-
.filter(
|
|
2168
|
-
(v) => Date.now() - v.ts <= PRESENCE_TTL_MS && String(v.agent) === String(pid) && v.cap,
|
|
2169
|
-
)
|
|
2170
|
-
.map((v) => v.viewer)
|
|
2171
|
-
.join(",");
|
|
2233
|
+
// Trace the negotiated resize + this daemon's identity (multi-daemon topology:
|
|
2234
|
+
// the HTTP daemon and each --webrtc share daemon each negotiate off the shared
|
|
2235
|
+
// store; the trace shows which one wrote, so a resize-fight is diagnosable).
|
|
2172
2236
|
process.stderr.write(
|
|
2173
2237
|
`[api/resize] pid=${pid} ${eff.cols}x${eff.rows} src=presence-nego ` +
|
|
2174
|
-
`
|
|
2238
|
+
`daemon=${daemonTag} caps=${caps.length}\n`,
|
|
2175
2239
|
);
|
|
2176
2240
|
await mkdir(path.dirname(file), { recursive: true });
|
|
2177
2241
|
await writeFile(file, content);
|
|
@@ -3583,9 +3647,17 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
3583
3647
|
}
|
|
3584
3648
|
const viewer = String(b.viewer ?? "").slice(0, 64);
|
|
3585
3649
|
if (!viewer) return new Response("missing viewer", { status: 400 });
|
|
3650
|
+
// A scoped token may only report presence/caps for the agent it's bound to.
|
|
3651
|
+
if (
|
|
3652
|
+
authResult.kind === "scoped" &&
|
|
3653
|
+
b.agent != null &&
|
|
3654
|
+
String(b.agent) !== authResult.scope.pid
|
|
3655
|
+
)
|
|
3656
|
+
return new Response("scoped token: not bound to this agent", { status: 403 });
|
|
3586
3657
|
// The agent this viewer WAS on — if the entry moves (agent switch) or
|
|
3587
3658
|
// clears, that agent's negotiated size must be recomputed (grow-back).
|
|
3588
3659
|
const prevAgent = presence.get(viewer)?.agent;
|
|
3660
|
+
const cap = sanitizeCap(b.cap);
|
|
3589
3661
|
if (b.agent == null) presence.delete(viewer);
|
|
3590
3662
|
else
|
|
3591
3663
|
presence.set(viewer, {
|
|
@@ -3594,10 +3666,19 @@ export async function cmdServe(rest: string[]): Promise<number> {
|
|
|
3594
3666
|
cols: Math.max(0, Math.floor(Number(b.cols) || 0)),
|
|
3595
3667
|
rows: Math.max(0, Math.floor(Number(b.rows) || 0)),
|
|
3596
3668
|
sel: typeof b.sel === "string" ? b.sel.slice(0, 200) : null,
|
|
3597
|
-
cap
|
|
3669
|
+
cap,
|
|
3598
3670
|
ts: Date.now(),
|
|
3599
3671
|
});
|
|
3600
|
-
|
|
3672
|
+
// Mirror this viewer's SIZE cap into the shared cap store so sibling daemons
|
|
3673
|
+
// negotiate off it too. A cleared/agent-switched/cap-less viewer withdraws its
|
|
3674
|
+
// cap (from the old agent) so its size stops counting immediately, not on TTL.
|
|
3675
|
+
if (prevAgent != null && String(prevAgent) !== String(b.agent ?? ""))
|
|
3676
|
+
await withdrawCap(Number(prevAgent), viewer);
|
|
3677
|
+
if (b.agent != null) {
|
|
3678
|
+
if (cap) await publishCap(Number(b.agent), viewer, cap, "viewer");
|
|
3679
|
+
else await withdrawCap(Number(b.agent), viewer);
|
|
3680
|
+
scheduleNego(Number(b.agent));
|
|
3681
|
+
}
|
|
3601
3682
|
if (prevAgent != null && String(prevAgent) !== String(b.agent ?? ""))
|
|
3602
3683
|
scheduleNego(Number(prevAgent));
|
|
3603
3684
|
return new Response(null, { status: 204 });
|
package/ts/terminal/browser.ts
CHANGED
|
@@ -57,6 +57,8 @@ export class AyTerminal {
|
|
|
57
57
|
private badgeEl?: any; // the interactive/read-only header badge (flipped on a 403)
|
|
58
58
|
private started = false;
|
|
59
59
|
private writable = false; // flips false on the first /api/send 403 (token is read-only)
|
|
60
|
+
private capViewerId = ""; // stable presence id for this widget's size cap (interactive)
|
|
61
|
+
private capTimer: any = null; // debounce for cap reports on drag-resize
|
|
60
62
|
|
|
61
63
|
constructor(info: string | number | AyTerminalInfo) {
|
|
62
64
|
const o: AyTerminalInfo =
|
|
@@ -70,6 +72,44 @@ export class AyTerminal {
|
|
|
70
72
|
this.controls = o.controls ?? "auto";
|
|
71
73
|
this.token = o.token ?? discoverToken();
|
|
72
74
|
this.title = o.title ?? `#${this.pid}`;
|
|
75
|
+
this.capViewerId = `wterm-${this.pid}-${Math.random().toString(36).slice(2, 8)}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Report this panel's readable capacity as a size cap (interactive only), so the
|
|
80
|
+
* daemon's negotiation (3a/3b) can shrink the shared PTY to what the panel shows —
|
|
81
|
+
* the "drag the widget to resize the agent" behavior, but through the same
|
|
82
|
+
* smallest-client-wins negotiation as every other viewer (bounded by the operator's
|
|
83
|
+
* local terminal + the 40×10 floor), NOT a raw /api/resize that scrambled everyone.
|
|
84
|
+
* Debounced so a drag doesn't spam. Read-only widgets never report (pure observers).
|
|
85
|
+
*/
|
|
86
|
+
private reportCap(cols: number, rows: number): void {
|
|
87
|
+
if (this.readOnly || !this.capViewerId) return;
|
|
88
|
+
const g = globalThis as any;
|
|
89
|
+
clearTimeout(this.capTimer);
|
|
90
|
+
this.capTimer = setTimeout(() => {
|
|
91
|
+
void g
|
|
92
|
+
.fetch(this.url("/api/presence"), {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: { "content-type": "application/json" },
|
|
95
|
+
body: JSON.stringify({ viewer: this.capViewerId, agent: this.pid, cap: { cols, rows } }),
|
|
96
|
+
})
|
|
97
|
+
.catch(() => {});
|
|
98
|
+
}, 250);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Withdraw this widget's size cap (closed/minimized) → the daemon re-negotiates without it. */
|
|
102
|
+
private withdrawCap(): void {
|
|
103
|
+
if (this.readOnly || !this.capViewerId) return;
|
|
104
|
+
const g = globalThis as any;
|
|
105
|
+
clearTimeout(this.capTimer);
|
|
106
|
+
void g
|
|
107
|
+
.fetch(this.url("/api/presence"), {
|
|
108
|
+
method: "POST",
|
|
109
|
+
headers: { "content-type": "application/json" },
|
|
110
|
+
body: JSON.stringify({ viewer: this.capViewerId, agent: null }),
|
|
111
|
+
})
|
|
112
|
+
.catch(() => {});
|
|
73
113
|
}
|
|
74
114
|
|
|
75
115
|
/** URL to a daemon API path with the token appended as a query param (EventSource can't set headers). */
|
|
@@ -170,6 +210,7 @@ export class AyTerminal {
|
|
|
170
210
|
|
|
171
211
|
/** Tear down the stream, the terminal, and the mounted widget. */
|
|
172
212
|
close(): void {
|
|
213
|
+
this.withdrawCap(); // stop counting this panel's size in the shared negotiation
|
|
173
214
|
this.es?.close();
|
|
174
215
|
this.es = undefined;
|
|
175
216
|
this.term?.dispose();
|
|
@@ -220,6 +261,15 @@ export class AyTerminal {
|
|
|
220
261
|
if (!xt || !xt.offsetWidth || !xt.offsetHeight) return;
|
|
221
262
|
const s = Math.min(1, wrap.clientWidth / xt.offsetWidth, wrap.clientHeight / xt.offsetHeight);
|
|
222
263
|
inner.style.transform = `scale(${s})`;
|
|
264
|
+
// 3c: an interactive panel reports how many cols/rows it can show as a size
|
|
265
|
+
// cap (derived from the wrap vs the native grid's pixel size), so dragging the
|
|
266
|
+
// widget renegotiates the shared PTY — through the daemon's min, bounded by the
|
|
267
|
+
// operator's local cap + floor, never a raw resize.
|
|
268
|
+
if (!this.readOnly && this.term?.cols) {
|
|
269
|
+
const capCols = Math.max(1, Math.floor((wrap.clientWidth * this.term.cols) / xt.offsetWidth));
|
|
270
|
+
const capRows = Math.max(1, Math.floor((wrap.clientHeight * this.term.rows) / xt.offsetHeight));
|
|
271
|
+
this.reportCap(capCols, capRows);
|
|
272
|
+
}
|
|
223
273
|
};
|
|
224
274
|
|
|
225
275
|
if (inline) {
|
|
@@ -263,7 +313,10 @@ export class AyTerminal {
|
|
|
263
313
|
const showPanel = (on: boolean) => {
|
|
264
314
|
panel.classList.toggle("open", on);
|
|
265
315
|
toggle.style.display = on ? "none" : "";
|
|
316
|
+
// Minimizing hides the panel → withdraw its size cap so it stops constraining
|
|
317
|
+
// the shared PTY; opening re-reports via reflow.
|
|
266
318
|
if (on) reflow();
|
|
319
|
+
else this.withdrawCap();
|
|
267
320
|
};
|
|
268
321
|
toggle.addEventListener("click", () => showPanel(true));
|
|
269
322
|
root.getElementById("min")?.addEventListener("click", () => showPanel(false));
|