agent-yes 1.243.0 → 1.244.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.
@@ -1,8 +1,8 @@
1
- import { t as CLIS_CONFIG } from "./ts-BsDT2lOc.js";
1
+ import { t as CLIS_CONFIG } from "./ts-D2grRG_i.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-D3kdP3Fg.js.map
8
+ //# sourceMappingURL=SUPPORTED_CLIS-CeruMQj2.js.map
@@ -1,11 +1,11 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-DcSPUIKL.js";
3
- import "./ts-BsDT2lOc.js";
2
+ import "./versionChecker-Cx2CsrJE.js";
3
+ import "./ts-D2grRG_i.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-D3kdP3Fg.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CeruMQj2.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-EgLhiiQR.js";
6
+ import { P as resolveOne } from "./subcommands-ajxDry2d.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-BIovDNhe.js.map
232
+ //# sourceMappingURL=agentShare-b3Y8UlNj.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-D2s9Nzi0.js.map
13489
+ //# sourceMappingURL=browser-C5pEBVVH.js.map
@@ -1,5 +1,5 @@
1
1
  import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
2
- import { P as resolveOne } from "./subcommands-EgLhiiQR.js";
2
+ import { P as resolveOne } from "./subcommands-ajxDry2d.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-CaM7aRcM.js");
75
+ const { resolveLocalServeUrl } = await import("./serve-ktPRdJcG.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-CuHw2QQm.js.map
190
+ //# sourceMappingURL=callback-DLDnhsdY.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-EgLhiiQR.js";
6
+ import "./subcommands-ajxDry2d.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-CuHw2QQm.js";
10
+ import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-DLDnhsdY.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-DcSPUIKL.js";
5
- import { n as getRustBinary } from "./rustBinary-CZqnLN5u.js";
4
+ import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-Cx2CsrJE.js";
5
+ import { n as getRustBinary } from "./rustBinary-DoWrLcGE.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-2pI7R0TC.js");
288
+ const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken } = await import("./subcommands-6bHT1YHD.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-BaBC0uuR.js");
298
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-nvFA0STw.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-BaBC0uuR.js");
349
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-nvFA0STw.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-DcSPUIKL.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-BsDT2lOc.js";
2
+ import "./versionChecker-Cx2CsrJE.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-D2grRG_i.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-EgLhiiQR.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-ajxDry2d.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-Ua7IBDgC.js.map
592
+ //# sourceMappingURL=notifyDaemon-ENAuKS2b.js.map
@@ -1,4 +1,4 @@
1
- import { r as getInstalledPackage } from "./versionChecker-DcSPUIKL.js";
1
+ import { r as getInstalledPackage } from "./versionChecker-Cx2CsrJE.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-CZqnLN5u.js.map
228
+ //# sourceMappingURL=rustBinary-DoWrLcGE.js.map
@@ -1,12 +1,12 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-DcSPUIKL.js";
3
- import "./ts-BsDT2lOc.js";
2
+ import "./versionChecker-Cx2CsrJE.js";
3
+ import "./ts-D2grRG_i.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-D3kdP3Fg.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CeruMQj2.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-BJdJgWqf.js.map
156
+ //# sourceMappingURL=schedule-BwqlZin-.js.map
@@ -1,7 +1,7 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import { r as getInstalledPackage } from "./versionChecker-DcSPUIKL.js";
3
- import { t as findSpawnHiddenLauncher } from "./rustBinary-CZqnLN5u.js";
4
- import { i as answerAsk, l as CLAUDE_SESSION_PIN_ENV, o as listAsks } from "./ts-BsDT2lOc.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-Cx2CsrJE.js";
3
+ import { t as findSpawnHiddenLauncher } from "./rustBinary-DoWrLcGE.js";
4
+ import { i as answerAsk, l as CLAUDE_SESSION_PIN_ENV, o as listAsks } from "./ts-D2grRG_i.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,12 +11,12 @@ 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-D3kdP3Fg.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-EgLhiiQR.js";
14
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CeruMQj2.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-ajxDry2d.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-CuHw2QQm.js";
19
+ import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-DLDnhsdY.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";
@@ -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
  }
@@ -2293,7 +2294,7 @@ Options:
2293
2294
  }
2294
2295
  });
2295
2296
  if (req.method === "GET" && p === "/api/ws") {
2296
- const ws = await import("./ws-CBCJiNuC.js");
2297
+ const ws = await import("./ws-BLiLY0VO.js");
2297
2298
  try {
2298
2299
  await ws.loadProvision();
2299
2300
  } catch (e) {
@@ -2313,7 +2314,7 @@ Options:
2313
2314
  if (req.method === "GET" && p === "/api/ws/status") {
2314
2315
  const dirRaw = url.searchParams.get("path");
2315
2316
  if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
2316
- const ws = await import("./ws-CBCJiNuC.js");
2317
+ const ws = await import("./ws-BLiLY0VO.js");
2317
2318
  let prov;
2318
2319
  try {
2319
2320
  prov = await ws.loadProvision();
@@ -2823,6 +2824,7 @@ Options:
2823
2824
  }
2824
2825
  const viewer = String(b.viewer ?? "").slice(0, 64);
2825
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 });
2826
2828
  const prevAgent = presence.get(viewer)?.agent;
2827
2829
  const cap = sanitizeCap(b.cap);
2828
2830
  if (b.agent == null) presence.delete(viewer);
@@ -3043,7 +3045,7 @@ Options:
3043
3045
  const perm = body.perm ?? "r";
3044
3046
  if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
3045
3047
  try {
3046
- const { createScopedShare } = await import("./agentShare-BIovDNhe.js");
3048
+ const { createScopedShare } = await import("./agentShare-b3Y8UlNj.js");
3047
3049
  const share = await createScopedShare({
3048
3050
  agent: body.agent,
3049
3051
  perm,
@@ -3058,12 +3060,12 @@ Options:
3058
3060
  }
3059
3061
  }
3060
3062
  if (req.method === "GET" && p === "/api/shares") {
3061
- const { listShares } = await import("./agentShare-BIovDNhe.js");
3063
+ const { listShares } = await import("./agentShare-b3Y8UlNj.js");
3062
3064
  return Response.json(listShares());
3063
3065
  }
3064
3066
  const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
3065
3067
  if (req.method === "DELETE" && revokeM) {
3066
- const { revokeShare } = await import("./agentShare-BIovDNhe.js");
3068
+ const { revokeShare } = await import("./agentShare-b3Y8UlNj.js");
3067
3069
  const ok = revokeShare(decodeURIComponent(revokeM[1]));
3068
3070
  return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
3069
3071
  }
@@ -3365,7 +3367,7 @@ Options:
3365
3367
  const shutdown = (resolve) => {
3366
3368
  if (heartbeat) clearInterval(heartbeat);
3367
3369
  closeShare?.();
3368
- import("./agentShare-BIovDNhe.js").then((m) => m.revokeAllShares()).catch(() => {});
3370
+ import("./agentShare-b3Y8UlNj.js").then((m) => m.revokeAllShares()).catch(() => {});
3369
3371
  server?.stop();
3370
3372
  Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
3371
3373
  };
@@ -3378,4 +3380,4 @@ Options:
3378
3380
 
3379
3381
  //#endregion
3380
3382
  export { cmdServe, loadTokenReadOnly, mintScopedTermToken, resolveDaemonHttpBase, resolveLocalServeUrl };
3381
- //# sourceMappingURL=serve-CaM7aRcM.js.map
3383
+ //# sourceMappingURL=serve-ktPRdJcG.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-CaM7aRcM.js");
35
+ const { cmdServe } = await import("./serve-ktPRdJcG.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-DyS9tOWJ.js.map
45
+ //# sourceMappingURL=setup-C2broQdo.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-EgLhiiQR.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-ajxDry2d.js";
7
7
  import "./webrtcLink-BMYneHbu.js";
8
8
  import "./remotes-BxQnNxQv.js";
9
9
 
@@ -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-BSWcimSy.js");
1270
+ const { cmdTerm } = await import("./terminal-CXgfj7y8.js");
1271
1271
  return cmdTerm(rest);
1272
1272
  }
1273
1273
  case "widget": {
1274
- const { cmdWidget } = await import("./widget-BmfbQXJA.js");
1274
+ const { cmdWidget } = await import("./widget-CdCt2-of.js");
1275
1275
  return cmdWidget(rest);
1276
1276
  }
1277
1277
  case "mint": {
1278
- const { cmdMint } = await import("./widget-BmfbQXJA.js");
1278
+ const { cmdMint } = await import("./widget-CdCt2-of.js");
1279
1279
  return cmdMint(rest);
1280
1280
  }
1281
1281
  case "serve": {
1282
- const { cmdServe } = await import("./serve-CaM7aRcM.js");
1282
+ const { cmdServe } = await import("./serve-ktPRdJcG.js");
1283
1283
  return cmdServe(rest);
1284
1284
  }
1285
1285
  case "setup": {
1286
- const { cmdSetup } = await import("./setup-DyS9tOWJ.js");
1286
+ const { cmdSetup } = await import("./setup-C2broQdo.js");
1287
1287
  return cmdSetup(rest);
1288
1288
  }
1289
1289
  case "ws": {
1290
- const { cmdWs } = await import("./ws-CBCJiNuC.js");
1290
+ const { cmdWs } = await import("./ws-BLiLY0VO.js");
1291
1291
  return cmdWs(rest);
1292
1292
  }
1293
1293
  case "schedule": {
1294
- const { cmdSchedule } = await import("./schedule-BJdJgWqf.js");
1294
+ const { cmdSchedule } = await import("./schedule-BwqlZin-.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-DVM4WNj_.js");
1306
+ const { cmdCallback } = await import("./callback-DWFVOwR1.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-Ua7IBDgC.js");
4345
+ const { ensureDaemon } = await import("./notifyDaemon-ENAuKS2b.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-Ua7IBDgC.js");
4419
+ const daemon = await import("./notifyDaemon-ENAuKS2b.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-EgLhiiQR.js.map
4446
+ //# sourceMappingURL=subcommands-ajxDry2d.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-CaM7aRcM.js");
101
+ const { mintScopedTermToken } = await import("./serve-ktPRdJcG.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-BSWcimSy.js.map
138
+ //# sourceMappingURL=terminal-CXgfj7y8.js.map
package/dist/terminal.js CHANGED
@@ -1,3 +1,3 @@
1
- import { t as AyTerminal } from "./browser-D2s9Nzi0.js";
1
+ import { t as AyTerminal } from "./browser-C5pEBVVH.js";
2
2
 
3
3
  export { AyTerminal, AyTerminal as default };
@@ -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-DcSPUIKL.js";
3
+ import { r as getInstalledPackage } from "./versionChecker-Cx2CsrJE.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-BsDT2lOc.js.map
2030
+ //# sourceMappingURL=ts-D2grRG_i.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.243.0";
10
+ var version = "1.244.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-DcSPUIKL.js.map
218
+ //# sourceMappingURL=versionChecker-Cx2CsrJE.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-CaM7aRcM.js");
31
+ const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-ktPRdJcG.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-CaM7aRcM.js");
189
+ const { mintScopedTermToken } = await import("./serve-ktPRdJcG.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-BmfbQXJA.js.map
205
+ //# sourceMappingURL=widget-CdCt2-of.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-D2s9Nzi0.js";
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-EgLhiiQR.js";
6
+ import { C as listRecords } from "./subcommands-ajxDry2d.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-CBCJiNuC.js.map
421
+ //# sourceMappingURL=ws-BLiLY0VO.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.243.0",
3
+ "version": "1.244.0",
4
4
  "description": "A wrapper tool that automates interactions with various AI CLI tools by automatically handling common prompts and responses.",
5
5
  "keywords": [
6
6
  "ai",
package/ts/serve.ts CHANGED
@@ -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/")) {
@@ -3640,6 +3647,13 @@ export async function cmdServe(rest: string[]): Promise<number> {
3640
3647
  }
3641
3648
  const viewer = String(b.viewer ?? "").slice(0, 64);
3642
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 });
3643
3657
  // The agent this viewer WAS on — if the entry moves (agent switch) or
3644
3658
  // clears, that agent's negotiated size must be recomputed (grow-back).
3645
3659
  const prevAgent = presence.get(viewer)?.agent;
@@ -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));