agent-yes 1.236.0 → 1.237.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.
Files changed (75) hide show
  1. package/dist/{JsonlStore-CWOA3aDH.js → JsonlStore-CPGIR0Wy.js} +1 -1
  2. package/dist/SUPPORTED_CLIS-C0RwjYrz.js +11 -0
  3. package/dist/{SUPPORTED_CLIS-C7bkkXue.js → SUPPORTED_CLIS-CDrJz9Xo.js} +2 -2
  4. package/dist/{agent-yes.config-BhjzWavn.js → agent-yes.config-DPtMM0S-.js} +2 -2
  5. package/dist/{agentShare-BxAaZ-UR.js → agentShare-Cl_J3dfx.js} +9 -9
  6. package/dist/{agentYesHome-CtHb5b71.js → agentYesHome-CtmsY6I-.js} +1 -1
  7. package/dist/browser-B3dOptjL.js +311 -0
  8. package/dist/browser-BRMyG4JA.js +13514 -0
  9. package/dist/callback-CFbkvqTh.js +12 -0
  10. package/dist/{callback-B1AWp2tC.js → callback-D0_AeyN1.js} +6 -6
  11. package/dist/{callbackCore-CcbVa8r2.js → callbackCore-CvmGSvrj.js} +1 -1
  12. package/dist/{callbackCore-Me97qn68.js → callbackCore-DAYcemCC.js} +1 -1
  13. package/dist/{channels-Lsot9pyU.js → channels-BiGUYTuz.js} +2 -2
  14. package/dist/{channels-DHXLnU4r.js → channels-CMNMFJlY.js} +6 -6
  15. package/dist/channels.js +6 -310
  16. package/dist/chunk-cZBX9HZv.js +20 -0
  17. package/dist/cli.js +11 -11
  18. package/dist/{configShared-BXz2vi4Q.js → configShared-9wVlbPyC.js} +1 -1
  19. package/dist/{cwdConflictWarn-ArYYtOGy.js → cwdConflictWarn-DWHWlBxS.js} +2 -2
  20. package/dist/{cwdDeprecation-BGX20-Fe.js → cwdDeprecation-Cd8Ykm2t.js} +1 -1
  21. package/dist/{e2e-CYlKpfxa.js → e2e-CEIdJGZ7.js} +1 -1
  22. package/dist/{expose-ByT4ef7C.js → expose-DROTwbyU.js} +1 -1
  23. package/dist/{forkNested-Bai0Q7BL.js → forkNested-DqPisz9d.js} +2 -2
  24. package/dist/{globalPidIndex-Ca4sTr1b.js → globalPidIndex-D9DOSd-c.js} +1 -1
  25. package/dist/index.js +7 -7
  26. package/dist/{messageLog-zVGWLX7w.js → messageLog-C-YIzhRj.js} +1 -1
  27. package/dist/{nodeRuntime-fVRbz6w6.js → nodeRuntime-Bf88NPqj.js} +2 -2
  28. package/dist/{notifyDaemon-Cxb0-5a0.js → notifyDaemon-D_8TRVHt.js} +8 -8
  29. package/dist/{openBrowser-DL-EO8Hi.js → openBrowser-ChLcPELv.js} +1 -1
  30. package/dist/{peer-68ZwnxLs.js → peer-B5JKF4BP.js} +3 -3
  31. package/dist/peer-D5lr1Afv.js +4 -0
  32. package/dist/{pidStore-Hjba3K6Q.js → pidStore-6EZd5DUv.js} +4 -4
  33. package/dist/pidStore-bCVS2Ldt.js +6 -0
  34. package/dist/{reaper-iQXyufgp.js → reaper-DP49VCKx.js} +2 -2
  35. package/dist/{reaper-pJpMYKmj.js → reaper-IhkB_RO0.js} +1 -1
  36. package/dist/{remotes-CF1LJLxY.js → remotes-BClMgQZW.js} +3 -3
  37. package/dist/{remotes-BDdfhL6N.js → remotes-Bem6WIyU.js} +3 -3
  38. package/dist/{runningLock-BFk3Mo8K.js → runningLock-DBoONoM-.js} +1 -1
  39. package/dist/{rustBinary-CFSG7it2.js → rustBinary-Bb9qJZ5w.js} +2 -2
  40. package/dist/{schedule-CXHdiUHa.js → schedule-B8Erb3y6.js} +11 -11
  41. package/dist/{serve-DEEwIlVV.js → serve-QejbNTr-.js} +187 -43
  42. package/dist/{setup-QfDtv5tw.js → setup-Dzi5Cc3g.js} +3 -3
  43. package/dist/{share-CDER9qNq.js → share--aHaPSjt.js} +2 -2
  44. package/dist/{share-D4K0JnHg.js → share-B9u8-I3y.js} +2 -2
  45. package/dist/{spawnGate-PwzImpOw.js → spawnGate-Bo_LFgt9.js} +3 -3
  46. package/dist/spawnGate-CuWCd2im.js +5 -0
  47. package/dist/{store-BXJERNbW.js → store-Ck0XRn-K.js} +1 -1
  48. package/dist/{subcommands-_Ci82sb1.js → subcommands-DFr-5FOL.js} +26 -21
  49. package/dist/{subcommands-m2DRpvHt.js → subcommands-ymJWO2iv.js} +7 -7
  50. package/dist/terminal-vNeFNLT8.js +138 -0
  51. package/dist/terminal.js +3 -0
  52. package/dist/{todoAutomation-x6guaQXc.js → todoAutomation-Buo457VO.js} +2 -2
  53. package/dist/{todoCli-CAMVVz9u.js → todoCli-CNNR9Czu.js} +4 -4
  54. package/dist/{tray-CF8xRQqt.js → tray-D5qFaqlS.js} +2 -2
  55. package/dist/{ts-D1FDmhc-.js → ts-Dd1FK7sR.js} +11 -28
  56. package/dist/{versionChecker-DJEtU1JU.js → versionChecker-XfEBINhH.js} +2 -2
  57. package/dist/{webrtcLink-CEYNs0pt.js → webrtcLink-VQhWmKOw.js} +2 -2
  58. package/dist/{webrtcRemote-CNC_bMH6.js → webrtcRemote-DJDtCTpj.js} +3 -3
  59. package/dist/widgets.js +7 -0
  60. package/dist/{workspaceConfig-CuGjX2_R.js → workspaceConfig-B7HaQ-MI.js} +2 -2
  61. package/dist/{ws-C7B4xWQl.js → ws-Dun8gGiV.js} +9 -9
  62. package/package.json +13 -1
  63. package/ts/serve.ts +144 -5
  64. package/ts/subcommands.ts +6 -0
  65. package/ts/termToken.spec.ts +44 -0
  66. package/ts/termToken.ts +85 -0
  67. package/ts/terminal/browser.ts +607 -0
  68. package/ts/terminal.spec.ts +50 -0
  69. package/ts/terminal.ts +245 -0
  70. package/ts/widgets.ts +14 -0
  71. package/dist/SUPPORTED_CLIS-BDXbzEWF.js +0 -11
  72. package/dist/callback-Dtk0wMsl.js +0 -12
  73. package/dist/peer-CX4qQx5U.js +0 -4
  74. package/dist/pidStore-Cp3HekUh.js +0 -6
  75. package/dist/spawnGate-C21TL4f2.js +0 -5
@@ -68,4 +68,4 @@ async function offerOpenInBrowser(url, prompt = "Open in browser now? [Y/n] ") {
68
68
 
69
69
  //#endregion
70
70
  export { offerOpenInBrowser };
71
- //# sourceMappingURL=openBrowser-DL-EO8Hi.js.map
71
+ //# sourceMappingURL=openBrowser-ChLcPELv.js.map
@@ -1,5 +1,5 @@
1
- import { a as computeTranscriptHash, c as open, d as randomHex, f as seal, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, s as deriveDirKeys, t as CONFIRM_TIMEOUT_MS } from "./e2e-CYlKpfxa.js";
2
- import { i as opsMissing, s as isValidOp, t as haveVector } from "./store-BXJERNbW.js";
1
+ import { a as computeTranscriptHash, c as open, d as randomHex, f as seal, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, s as deriveDirKeys, t as CONFIRM_TIMEOUT_MS } from "./e2e-CEIdJGZ7.js";
2
+ import { i as opsMissing, s as isValidOp, t as haveVector } from "./store-Ck0XRn-K.js";
3
3
 
4
4
  //#region ts/channels/peer.ts
5
5
  const SIGNAL_SUBPROTOCOL = "ay-signal-1";
@@ -363,4 +363,4 @@ var ChannelPeer = class {
363
363
 
364
364
  //#endregion
365
365
  export { ChannelPeer as t };
366
- //# sourceMappingURL=peer-68ZwnxLs.js.map
366
+ //# sourceMappingURL=peer-B5JKF4BP.js.map
@@ -0,0 +1,4 @@
1
+ import "./e2e-CEIdJGZ7.js";
2
+ import { t as ChannelPeer } from "./peer-B5JKF4BP.js";
3
+
4
+ export { ChannelPeer };
@@ -1,7 +1,7 @@
1
1
  import { n as logger } from "./logger-CDIsZ-Pp.js";
2
- import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
3
- import { t as JsonlStore } from "./JsonlStore-CWOA3aDH.js";
4
- import { a as updateGlobalPidStatus, n as maybeCompactGlobalPids, r as pruneOldLogs, t as appendGlobalPid } from "./globalPidIndex-Ca4sTr1b.js";
2
+ import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
3
+ import { t as JsonlStore } from "./JsonlStore-CPGIR0Wy.js";
4
+ import { a as updateGlobalPidStatus, n as maybeCompactGlobalPids, r as pruneOldLogs, t as appendGlobalPid } from "./globalPidIndex-D9DOSd-c.js";
5
5
  import { mkdir, writeFile } from "fs/promises";
6
6
  import path from "path";
7
7
  import { randomBytes } from "node:crypto";
@@ -188,4 +188,4 @@ pid-db/
188
188
 
189
189
  //#endregion
190
190
  export { PidStore as t };
191
- //# sourceMappingURL=pidStore-Hjba3K6Q.js.map
191
+ //# sourceMappingURL=pidStore-6EZd5DUv.js.map
@@ -0,0 +1,6 @@
1
+ import "./logger-CDIsZ-Pp.js";
2
+ import "./JsonlStore-CPGIR0Wy.js";
3
+ import "./globalPidIndex-D9DOSd-c.js";
4
+ import { t as PidStore } from "./pidStore-6EZd5DUv.js";
5
+
6
+ export { PidStore };
@@ -1,4 +1,4 @@
1
- import { t as agentYesHome } from "./agentYesHome-CtHb5b71.js";
1
+ import { t as agentYesHome } from "./agentYesHome-CtmsY6I-.js";
2
2
  import { appendFile, mkdir, readFile, readdir, rename, unlink, writeFile } from "fs/promises";
3
3
  import path from "path";
4
4
 
@@ -107,4 +107,4 @@ async function pruneStaleActivityMarkers() {
107
107
 
108
108
  //#endregion
109
109
  export { register as n, sweep as r, pgidForWrapper as t };
110
- //# sourceMappingURL=reaper-iQXyufgp.js.map
110
+ //# sourceMappingURL=reaper-DP49VCKx.js.map
@@ -1,3 +1,3 @@
1
- import { n as register, r as sweep, t as pgidForWrapper } from "./reaper-iQXyufgp.js";
1
+ import { n as register, r as sweep, t as pgidForWrapper } from "./reaper-DP49VCKx.js";
2
2
 
3
3
  export { sweep };
@@ -1,5 +1,5 @@
1
- import "./e2e-CYlKpfxa.js";
2
- import "./webrtcLink-CEYNs0pt.js";
3
- import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-BDdfhL6N.js";
1
+ import "./e2e-CEIdJGZ7.js";
2
+ import "./webrtcLink-VQhWmKOw.js";
3
+ import { a as resolveRemoteSpec, i as readRemotes, n as deleteRemoteAlias, o as writeRemoteAlias, r as parseDirectRemoteSpec, t as cmdRemote } from "./remotes-Bem6WIyU.js";
4
4
 
5
5
  export { cmdRemote };
@@ -1,4 +1,4 @@
1
- import { n as isWebrtcSpec } from "./webrtcLink-CEYNs0pt.js";
1
+ import { n as isWebrtcSpec } from "./webrtcLink-VQhWmKOw.js";
2
2
  import { mkdir, readFile, writeFile } from "fs/promises";
3
3
  import { homedir } from "os";
4
4
  import path from "path";
@@ -86,7 +86,7 @@ async function resolveRemoteSpec(spec) {
86
86
  * The bridge lives for the rest of the process (torn down on `process.exit`).
87
87
  */
88
88
  async function resolveWebrtc(link, keyword) {
89
- const { startWebrtcBridge } = await import("./webrtcRemote-CNC_bMH6.js");
89
+ const { startWebrtcBridge } = await import("./webrtcRemote-DJDtCTpj.js");
90
90
  const bridge = await startWebrtcBridge(link);
91
91
  return {
92
92
  url: bridge.baseUrl,
@@ -173,4 +173,4 @@ async function cmdRemote(rest) {
173
173
 
174
174
  //#endregion
175
175
  export { resolveRemoteSpec as a, readRemotes as i, deleteRemoteAlias as n, writeRemoteAlias as o, parseDirectRemoteSpec as r, cmdRemote as t };
176
- //# sourceMappingURL=remotes-BDdfhL6N.js.map
176
+ //# sourceMappingURL=remotes-Bem6WIyU.js.map
@@ -277,4 +277,4 @@ function shouldUseLock(_cwd) {
277
277
 
278
278
  //#endregion
279
279
  export { shouldUseLock as i, getRunningAgentCount as n, releaseLock as r, acquireLock as t };
280
- //# sourceMappingURL=runningLock-BFk3Mo8K.js.map
280
+ //# sourceMappingURL=runningLock-DBoONoM-.js.map
@@ -1,4 +1,4 @@
1
- import { r as getInstalledPackage } from "./versionChecker-DJEtU1JU.js";
1
+ import { r as getInstalledPackage } from "./versionChecker-XfEBINhH.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-CFSG7it2.js.map
228
+ //# sourceMappingURL=rustBinary-Bb9qJZ5w.js.map
@@ -1,14 +1,14 @@
1
- import "./ts-D1FDmhc-.js";
2
1
  import "./logger-CDIsZ-Pp.js";
3
- import "./versionChecker-DJEtU1JU.js";
4
- import "./todoAutomation-x6guaQXc.js";
5
- import "./JsonlStore-CWOA3aDH.js";
6
- import "./globalPidIndex-Ca4sTr1b.js";
7
- import "./pidStore-Hjba3K6Q.js";
8
- import "./messageLog-zVGWLX7w.js";
9
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-C7bkkXue.js";
10
- import { d as resolveSpawnCwd } from "./workspaceConfig-CuGjX2_R.js";
11
- import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-fVRbz6w6.js";
2
+ import "./versionChecker-XfEBINhH.js";
3
+ import "./ts-Dd1FK7sR.js";
4
+ import "./todoAutomation-Buo457VO.js";
5
+ import "./JsonlStore-CPGIR0Wy.js";
6
+ import "./globalPidIndex-D9DOSd-c.js";
7
+ import "./pidStore-6EZd5DUv.js";
8
+ import "./messageLog-C-YIzhRj.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CDrJz9Xo.js";
10
+ import { d as resolveSpawnCwd } from "./workspaceConfig-B7HaQ-MI.js";
11
+ import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-Bf88NPqj.js";
12
12
  import { createHash } from "node:crypto";
13
13
 
14
14
  //#region ts/oxmgrService.ts
@@ -153,4 +153,4 @@ async function cmdSchedule(rest) {
153
153
 
154
154
  //#endregion
155
155
  export { cmdSchedule };
156
- //# sourceMappingURL=schedule-CXHdiUHa.js.map
156
+ //# sourceMappingURL=schedule-B8Erb3y6.js.map
@@ -1,25 +1,25 @@
1
- import { i as answerAsk, l as CLAUDE_SESSION_PIN_ENV, o as listAsks } from "./ts-D1FDmhc-.js";
2
1
  import "./logger-CDIsZ-Pp.js";
3
- import { r as getInstalledPackage } from "./versionChecker-DJEtU1JU.js";
4
- import { t as findSpawnHiddenLauncher } from "./rustBinary-CFSG7it2.js";
5
- import { t as agentYesHome$1 } from "./agentYesHome-CtHb5b71.js";
6
- import { x as removeControlCharacters } from "./todoAutomation-x6guaQXc.js";
7
- import "./JsonlStore-CWOA3aDH.js";
8
- import { a as updateGlobalPidStatus } from "./globalPidIndex-Ca4sTr1b.js";
9
- import "./pidStore-Hjba3K6Q.js";
10
- import { r as recordInbox } from "./messageLog-zVGWLX7w.js";
11
- import { t as pgidForWrapper } from "./reaper-iQXyufgp.js";
12
- import "./e2e-CYlKpfxa.js";
13
- import "./configShared-BXz2vi4Q.js";
14
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-C7bkkXue.js";
15
- import { A as renderLogTailLines, D as readPtysize, E as readNotes, J as isTransientLockMkdirError, M as renderRawLogLines, N as resolveOne, O as recentMessageEdges, R as snapshotStatus, S as listRecords, W as writeToIpc, b as isUserTyping, f as extractNeedsInput, j as renderRawLog, k as recentReadEdges, l as deriveLiveStatus, nt as TYPING_BADGE, o as controlCodeFromName, p as extractTaskCounts, u as extractBadges } from "./subcommands-_Ci82sb1.js";
16
- import "./webrtcLink-CEYNs0pt.js";
17
- import "./remotes-BDdfhL6N.js";
18
- import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-Me97qn68.js";
19
- import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-B1AWp2tC.js";
20
- import { a as getSpawnHook, c as hasProvisionHook, d as resolveSpawnCwd, i as getProvisionRoot, l as hasSpawnHook, r as getProvisionHook, u as isProvisionAllowed } from "./workspaceConfig-CuGjX2_R.js";
21
- import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-fVRbz6w6.js";
22
- import { r as spawnRejectionReason } from "./spawnGate-PwzImpOw.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-XfEBINhH.js";
3
+ import { t as findSpawnHiddenLauncher } from "./rustBinary-Bb9qJZ5w.js";
4
+ import { i as answerAsk, l as CLAUDE_SESSION_PIN_ENV, o as listAsks } from "./ts-Dd1FK7sR.js";
5
+ import { t as agentYesHome$1 } from "./agentYesHome-CtmsY6I-.js";
6
+ import { x as removeControlCharacters } from "./todoAutomation-Buo457VO.js";
7
+ import "./JsonlStore-CPGIR0Wy.js";
8
+ import { a as updateGlobalPidStatus } from "./globalPidIndex-D9DOSd-c.js";
9
+ import "./pidStore-6EZd5DUv.js";
10
+ import { r as recordInbox } from "./messageLog-C-YIzhRj.js";
11
+ import { t as pgidForWrapper } from "./reaper-DP49VCKx.js";
12
+ import "./e2e-CEIdJGZ7.js";
13
+ import "./configShared-9wVlbPyC.js";
14
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-CDrJz9Xo.js";
15
+ import { A as renderLogTailLines, D as readPtysize, E as readNotes, J as isTransientLockMkdirError, M as renderRawLogLines, N as resolveOne, O as recentMessageEdges, R as snapshotStatus, S as listRecords, W as writeToIpc, b as isUserTyping, f as extractNeedsInput, j as renderRawLog, k as recentReadEdges, l as deriveLiveStatus, nt as TYPING_BADGE, o as controlCodeFromName, p as extractTaskCounts, u as extractBadges } from "./subcommands-DFr-5FOL.js";
16
+ import "./webrtcLink-VQhWmKOw.js";
17
+ import "./remotes-Bem6WIyU.js";
18
+ import { i as frameVisitorMessage, s as verifyCapability, t as MAX_CALLBACK_MSG_BYTES } from "./callbackCore-DAYcemCC.js";
19
+ import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-D0_AeyN1.js";
20
+ import { a as getSpawnHook, c as hasProvisionHook, d as resolveSpawnCwd, i as getProvisionRoot, l as hasSpawnHook, r as getProvisionHook, u as isProvisionAllowed } from "./workspaceConfig-B7HaQ-MI.js";
21
+ import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-Bf88NPqj.js";
22
+ import { r as spawnRejectionReason } from "./spawnGate-Bo_LFgt9.js";
23
23
  import yargs from "yargs";
24
24
  import { appendFile, mkdir, open, readFile, rename, rm, stat, unlink, writeFile } from "fs/promises";
25
25
  import { arch, cpus, freemem, homedir, hostname, loadavg, platform, totalmem, uptime, userInfo } from "os";
@@ -27,8 +27,61 @@ import path from "path";
27
27
  import { execFileSync } from "node:child_process";
28
28
  import { existsSync, renameSync, watch, writeFileSync } from "node:fs";
29
29
  import { fileURLToPath } from "node:url";
30
- import { randomBytes, timingSafeEqual } from "crypto";
30
+ import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
31
31
 
32
+ //#region ts/termToken.ts
33
+ const PREFIX = "ayt1";
34
+ /** Dedicated HMAC key derived from the master token (so the token isn't signed with the raw master). */
35
+ function keyFor(masterToken) {
36
+ return createHash("sha256").update("ay/term/token/v1\n" + masterToken).digest();
37
+ }
38
+ /** True for anything shaped like a scoped terminal token (cheap pre-check before verify). */
39
+ function isTermToken(tok) {
40
+ return typeof tok === "string" && tok.startsWith(PREFIX + ".");
41
+ }
42
+ /** Mint a scoped token bound to `scope.pid`, signed with the master token. */
43
+ function mintTermToken(masterToken, scope) {
44
+ const body = `${PREFIX}.${Buffer.from(JSON.stringify({
45
+ p: scope.pid,
46
+ w: scope.canSend ? 1 : 0,
47
+ x: Math.floor(scope.exp)
48
+ })).toString("base64url")}`;
49
+ return `${body}.${createHmac("sha256", keyFor(masterToken)).update(body).digest().toString("base64url")}`;
50
+ }
51
+ /**
52
+ * Verify a scoped token against the master token. Returns the scope if the
53
+ * signature is valid AND it hasn't expired, else null. Fail-closed on any
54
+ * malformed input. `nowSec` is injectable for tests.
55
+ */
56
+ function verifyTermToken(masterToken, tok, nowSec = Math.floor(Date.now() / 1e3)) {
57
+ if (!isTermToken(tok)) return null;
58
+ const parts = tok.split(".");
59
+ if (parts.length !== 3) return null;
60
+ const body = `${parts[0]}.${parts[1]}`;
61
+ const expected = createHmac("sha256", keyFor(masterToken)).update(body).digest();
62
+ let got;
63
+ try {
64
+ got = Buffer.from(parts[2], "base64url");
65
+ } catch {
66
+ return null;
67
+ }
68
+ if (got.length !== expected.length || !timingSafeEqual(got, expected)) return null;
69
+ let obj;
70
+ try {
71
+ obj = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
72
+ } catch {
73
+ return null;
74
+ }
75
+ if (typeof obj.p !== "string" || !obj.p) return null;
76
+ if (typeof obj.x !== "number" || !Number.isFinite(obj.x) || obj.x <= nowSec) return null;
77
+ return {
78
+ pid: obj.p,
79
+ canSend: obj.w === 1,
80
+ exp: obj.x
81
+ };
82
+ }
83
+
84
+ //#endregion
32
85
  //#region ts/terminalReply.ts
33
86
  /**
34
87
  * Is this /api/send payload PURELY terminal auto-reply chatter — the responses
@@ -405,11 +458,93 @@ function tokenEqual(provided, expectedToken) {
405
458
  const maxLen = Math.max(provided.length, expectedToken.length);
406
459
  return timingSafeEqual(Buffer.from(provided.padEnd(maxLen, "\0")), Buffer.from(expectedToken.padEnd(maxLen, "\0"))) && provided.length === expectedToken.length;
407
460
  }
408
- function checkAuth(req, expectedToken) {
461
+ function authorizeRequest(req, expectedToken) {
409
462
  const auth = req.headers.get("authorization") ?? "";
410
- if (auth.startsWith("Bearer ")) return tokenEqual(auth.slice(7), expectedToken);
411
- const q = new URL(req.url).searchParams.get("token");
412
- return q ? tokenEqual(q, expectedToken) : false;
463
+ const provided = (auth.startsWith("Bearer ") ? auth.slice(7) : null) ?? new URL(req.url).searchParams.get("token") ?? "";
464
+ if (!provided) return null;
465
+ if (tokenEqual(provided, expectedToken)) return { kind: "master" };
466
+ if (isTermToken(provided)) {
467
+ const scope = verifyTermToken(expectedToken, provided);
468
+ if (scope) return {
469
+ kind: "scoped",
470
+ scope
471
+ };
472
+ }
473
+ return null;
474
+ }
475
+ function isTermCorsPath(p) {
476
+ return /^\/api\/(tail|size)\/.+$/.test(p) || p === "/api/send";
477
+ }
478
+ function withTermCors(req, res) {
479
+ if (!res) return res;
480
+ if (isTermCorsPath(new URL(req.url).pathname)) try {
481
+ res.headers.set("Access-Control-Allow-Origin", "*");
482
+ res.headers.set("Vary", "Origin");
483
+ } catch {}
484
+ return res;
485
+ }
486
+ function termCorsPreflight() {
487
+ return new Response(null, {
488
+ status: 204,
489
+ headers: {
490
+ "Access-Control-Allow-Origin": "*",
491
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
492
+ "Access-Control-Allow-Headers": "content-type, authorization",
493
+ "Access-Control-Max-Age": "600"
494
+ }
495
+ });
496
+ }
497
+ /** Does `keyword` resolve to the exact pid a scoped token is bound to? */
498
+ async function scopedKeywordOk(keyword, scope) {
499
+ try {
500
+ const rec = await resolveOne(keyword, defaultOpts({ all: true }));
501
+ return String(rec.pid) === String(scope.pid);
502
+ } catch {
503
+ return false;
504
+ }
505
+ }
506
+ /**
507
+ * Confine a scoped token to its capability. Returns a 403 Response when the
508
+ * request is outside the token's grant, or null when it's allowed to proceed.
509
+ * Allowed: GET /api/tail|size/<kw> for the bound pid; POST /api/send for the bound
510
+ * pid IFF the token is interactive (canSend). Everything else is denied.
511
+ */
512
+ async function scopedGate(scope, method, p) {
513
+ const forbid = (m) => new Response(m, { status: 403 });
514
+ const m = /^\/api\/(?:tail|size)\/(.+)$/.exec(p);
515
+ if (method === "GET" && m) return await scopedKeywordOk(decodeURIComponent(m[1]), scope) ? null : forbid("scoped token: not bound to this agent");
516
+ if (method === "POST" && p === "/api/send") {
517
+ if (!scope.canSend) return forbid("scoped token is read-only");
518
+ return null;
519
+ }
520
+ const rz = /^\/api\/resize\/(.+)$/.exec(p);
521
+ if (method === "POST" && rz) {
522
+ if (!scope.canSend) return forbid("scoped token is read-only");
523
+ return await scopedKeywordOk(decodeURIComponent(rz[1]), scope) ? null : forbid("scoped token: not bound to this agent");
524
+ }
525
+ return forbid("scoped token: route not permitted");
526
+ }
527
+ /**
528
+ * Mint a scoped terminal-embed token locally (no daemon round-trip): read the
529
+ * master token file, resolve the keyword to a concrete pid, and sign. Used by
530
+ * `ay term mint`. Throws if there's no serve token or the agent can't be resolved.
531
+ */
532
+ async function mintScopedTermToken(keyword, opts) {
533
+ const master = await loadTokenReadOnly();
534
+ if (!master) throw new Error("no serve token at ~/.agent-yes/.serve-token — run `ay serve` once on this host to create it");
535
+ const rec = await resolveOne(keyword, defaultOpts({ all: true }));
536
+ const pid = String(rec.pid);
537
+ const exp = Math.floor(Date.now() / 1e3) + Math.max(1, Math.floor(opts.ttlSec));
538
+ return {
539
+ token: mintTermToken(master, {
540
+ pid,
541
+ canSend: opts.canSend,
542
+ exp
543
+ }),
544
+ pid,
545
+ exp,
546
+ canSend: opts.canSend
547
+ };
413
548
  }
414
549
  const defaultOpts = (overrides = {}) => ({
415
550
  all: false,
@@ -943,7 +1078,7 @@ async function cmdServeDaemon(sub, args) {
943
1078
  let shareLink = null;
944
1079
  let shareLinkMinted = false;
945
1080
  if (webrtcDaemon) try {
946
- const { loadOrCreateShareRoom, shareLinkFromRoomUrl } = await import("./share-CDER9qNq.js");
1081
+ const { loadOrCreateShareRoom, shareLinkFromRoomUrl } = await import("./share--aHaPSjt.js");
947
1082
  const explicit = explicitWebrtcUrl(effArgs);
948
1083
  shareLink = shareLinkFromRoomUrl(explicit ?? await loadOrCreateShareRoom());
949
1084
  shareLinkMinted = !explicit;
@@ -952,7 +1087,7 @@ async function cmdServeDaemon(sub, args) {
952
1087
  if (!webrtcDaemon) return;
953
1088
  if (shareLink) {
954
1089
  process.stdout.write(`\nshared over WebRTC — open this link (the token is eaten from the URL on open):\n ${shareLink}\n` + (shareLinkMinted ? ` (persistent room — same link across restarts; delete ~/.agent-yes/.share-room to rotate)\n` : ``));
955
- const { offerOpenInBrowser } = await import("./openBrowser-DL-EO8Hi.js");
1090
+ const { offerOpenInBrowser } = await import("./openBrowser-ChLcPELv.js");
956
1091
  await offerOpenInBrowser(shareLink);
957
1092
  } else process.stdout.write("\nthe WebRTC share link carries a secret, so the daemon does NOT log it —\nread it from ~/.agent-yes/.share-link (mode 0600). The room persists in\n~/.agent-yes/.share-room, so the link survives restarts.\n");
958
1093
  };
@@ -1591,9 +1726,15 @@ Options:
1591
1726
  for (const pid of negoApplied.keys()) scheduleNego(pid);
1592
1727
  }, 5e3);
1593
1728
  const apiFetch = async (req, srv) => {
1594
- if (!checkAuth(req, token)) return new Response("Unauthorized", { status: 401 });
1595
1729
  const url = new URL(req.url);
1596
1730
  const p = url.pathname;
1731
+ if (req.method === "OPTIONS" && isTermCorsPath(p)) return termCorsPreflight();
1732
+ const authResult = authorizeRequest(req, token);
1733
+ if (!authResult) return withTermCors(req, new Response("Unauthorized", { status: 401 }));
1734
+ if (authResult.kind === "scoped") {
1735
+ const denied = await scopedGate(authResult.scope, req.method, p);
1736
+ if (denied) return withTermCors(req, denied);
1737
+ }
1597
1738
  if (p === "/api/mux" && srv && req.headers.get("upgrade")?.toLowerCase() === "websocket") {
1598
1739
  const muxToken = url.searchParams.get("token") || "";
1599
1740
  if (srv.upgrade(req, { data: { muxToken } })) return void 0;
@@ -2038,7 +2179,7 @@ Options:
2038
2179
  }
2039
2180
  });
2040
2181
  if (req.method === "GET" && p === "/api/ws") {
2041
- const ws = await import("./ws-C7B4xWQl.js");
2182
+ const ws = await import("./ws-Dun8gGiV.js");
2042
2183
  try {
2043
2184
  await ws.loadProvision();
2044
2185
  } catch (e) {
@@ -2058,7 +2199,7 @@ Options:
2058
2199
  if (req.method === "GET" && p === "/api/ws/status") {
2059
2200
  const dirRaw = url.searchParams.get("path");
2060
2201
  if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
2061
- const ws = await import("./ws-C7B4xWQl.js");
2202
+ const ws = await import("./ws-Dun8gGiV.js");
2062
2203
  let prov;
2063
2204
  try {
2064
2205
  prov = await ws.loadProvision();
@@ -2124,6 +2265,8 @@ Options:
2124
2265
  pid: record.pid,
2125
2266
  cols: size?.cols ?? null,
2126
2267
  rows: size?.rows ?? null,
2268
+ cwd: record.cwd,
2269
+ cli: record.cli,
2127
2270
  nego: true
2128
2271
  });
2129
2272
  } catch (e) {
@@ -2249,6 +2392,7 @@ Options:
2249
2392
  }
2250
2393
  const { keyword, msg = "", code = "enter", from = null } = body;
2251
2394
  if (!keyword || typeof keyword !== "string") return new Response("missing keyword", { status: 400 });
2395
+ if (authResult.kind === "scoped" && !await scopedKeywordOk(keyword, authResult.scope)) return new Response("scoped token: not bound to this agent", { status: 403 });
2252
2396
  try {
2253
2397
  const record = await resolveOne(keyword, defaultOpts());
2254
2398
  if (!record.fifo_file) return new Response(`pid ${record.pid}: no fifo_file`, { status: 409 });
@@ -2647,7 +2791,7 @@ Options:
2647
2791
  const perm = body.perm ?? "r";
2648
2792
  if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
2649
2793
  try {
2650
- const { createScopedShare } = await import("./agentShare-BxAaZ-UR.js");
2794
+ const { createScopedShare } = await import("./agentShare-Cl_J3dfx.js");
2651
2795
  const share = await createScopedShare({
2652
2796
  agent: body.agent,
2653
2797
  perm,
@@ -2662,12 +2806,12 @@ Options:
2662
2806
  }
2663
2807
  }
2664
2808
  if (req.method === "GET" && p === "/api/shares") {
2665
- const { listShares } = await import("./agentShare-BxAaZ-UR.js");
2809
+ const { listShares } = await import("./agentShare-Cl_J3dfx.js");
2666
2810
  return Response.json(listShares());
2667
2811
  }
2668
2812
  const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
2669
2813
  if (req.method === "DELETE" && revokeM) {
2670
- const { revokeShare } = await import("./agentShare-BxAaZ-UR.js");
2814
+ const { revokeShare } = await import("./agentShare-Cl_J3dfx.js");
2671
2815
  const ok = revokeShare(decodeURIComponent(revokeM[1]));
2672
2816
  return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
2673
2817
  }
@@ -2681,7 +2825,7 @@ Options:
2681
2825
  const port = Number(body.port);
2682
2826
  if (!Number.isInteger(port) || port < 1 || port > 65535) return new Response("valid port required", { status: 400 });
2683
2827
  try {
2684
- const { ensureExposure } = await import("./expose-ByT4ef7C.js");
2828
+ const { ensureExposure } = await import("./expose-DROTwbyU.js");
2685
2829
  const h = await ensureExposure(port, body.relay);
2686
2830
  return Response.json({
2687
2831
  id: h.id,
@@ -2695,12 +2839,12 @@ Options:
2695
2839
  }
2696
2840
  }
2697
2841
  if (req.method === "GET" && p === "/api/exposes") {
2698
- const { listExposures } = await import("./expose-ByT4ef7C.js");
2842
+ const { listExposures } = await import("./expose-DROTwbyU.js");
2699
2843
  return Response.json(listExposures());
2700
2844
  }
2701
2845
  const unexposeM = /^\/api\/expose\/(\d+)$/.exec(p);
2702
2846
  if (req.method === "DELETE" && unexposeM) {
2703
- const { stopExposure } = await import("./expose-ByT4ef7C.js");
2847
+ const { stopExposure } = await import("./expose-DROTwbyU.js");
2704
2848
  const ok = stopExposure(Number(unexposeM[1]));
2705
2849
  return new Response(ok ? "revoked" : "no such exposure", { status: ok ? 200 : 404 });
2706
2850
  }
@@ -2817,7 +2961,7 @@ Options:
2817
2961
  if (req.method === "GET" && p === "/icon.svg") return serveUiFile("icon.svg", "image/svg+xml");
2818
2962
  if (req.method === "GET" && p === "/favicon.ico") return new Response(null, { status: 204 });
2819
2963
  if (p.startsWith("/cb/")) return handleCallback(req, p);
2820
- return apiFetch(req, srv);
2964
+ return withTermCors(req, await apiFetch(req, srv));
2821
2965
  };
2822
2966
  const serverOpts = {
2823
2967
  hostname: host,
@@ -2919,7 +3063,7 @@ Options:
2919
3063
  const webrtcVal = argv.webrtc ?? argv.share;
2920
3064
  const explicitUrl = typeof webrtcVal === "string" && webrtcVal.startsWith("webrtc://") ? webrtcVal : void 0;
2921
3065
  try {
2922
- const { startShare, loadOrCreateShareRoom } = await import("./share-CDER9qNq.js");
3066
+ const { startShare, loadOrCreateShareRoom } = await import("./share--aHaPSjt.js");
2923
3067
  const linkFile = path.join(process.env.AGENT_YES_HOME ?? path.join(homedir(), ".agent-yes"), ".share-link");
2924
3068
  const announce = async (room, link, rotated) => {
2925
3069
  const lead = rotated ? "the room was rejected by signaling (stale generation) — rotated to a fresh link" : "shared over WebRTC — open this link (the token is eaten from the URL on open)";
@@ -2927,7 +3071,7 @@ Options:
2927
3071
  const persistNote = explicitUrl ? "\n" : ` (persistent room — same link across restarts; delete ~/.agent-yes/.share-room to rotate)\n\n`;
2928
3072
  process.stdout.write(`${wantHttp ? "\n" : ""}${lead}:\n ${link}\n` + persistNote);
2929
3073
  if (!rotated) {
2930
- const { offerOpenInBrowser } = await import("./openBrowser-DL-EO8Hi.js");
3074
+ const { offerOpenInBrowser } = await import("./openBrowser-ChLcPELv.js");
2931
3075
  await offerOpenInBrowser(link);
2932
3076
  }
2933
3077
  } else {
@@ -2969,7 +3113,7 @@ Options:
2969
3113
  const shutdown = (resolve) => {
2970
3114
  if (heartbeat) clearInterval(heartbeat);
2971
3115
  closeShare?.();
2972
- import("./agentShare-BxAaZ-UR.js").then((m) => m.revokeAllShares()).catch(() => {});
3116
+ import("./agentShare-Cl_J3dfx.js").then((m) => m.revokeAllShares()).catch(() => {});
2973
3117
  server?.stop();
2974
3118
  Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
2975
3119
  };
@@ -2981,5 +3125,5 @@ Options:
2981
3125
  }
2982
3126
 
2983
3127
  //#endregion
2984
- export { cmdServe, resolveLocalServeUrl };
2985
- //# sourceMappingURL=serve-DEEwIlVV.js.map
3128
+ export { cmdServe, mintScopedTermToken, resolveLocalServeUrl };
3129
+ //# sourceMappingURL=serve-QejbNTr-.js.map
@@ -1,4 +1,4 @@
1
- import { f as setWorkspaceRoot, s as getWorkspaceRoot } from "./workspaceConfig-CuGjX2_R.js";
1
+ import { f as setWorkspaceRoot, s as getWorkspaceRoot } from "./workspaceConfig-B7HaQ-MI.js";
2
2
  import { existsSync } from "node:fs";
3
3
  import { stdin, stdout } from "node:process";
4
4
  import { createInterface } from "node:readline/promises";
@@ -32,7 +32,7 @@ async function cmdSetup(rest) {
32
32
  if (!existsSync(abs)) process.stderr.write(` note: that directory doesn't exist yet — create it, or agents spawned there will fail\n`);
33
33
  if (noShare) return 0;
34
34
  process.stdout.write(`\nsharing this machine to agent-yes.com…\n`);
35
- const { cmdServe } = await import("./serve-DEEwIlVV.js");
35
+ const { cmdServe } = await import("./serve-QejbNTr-.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-QfDtv5tw.js.map
45
+ //# sourceMappingURL=setup-Dzi5Cc3g.js.map
@@ -1,4 +1,4 @@
1
- import "./e2e-CYlKpfxa.js";
2
- import { a as startShare, i as shareLinkFromRoomUrl, n as importRTC, r as loadOrCreateShareRoom, t as getIceServers } from "./share-D4K0JnHg.js";
1
+ import "./e2e-CEIdJGZ7.js";
2
+ import { a as startShare, i as shareLinkFromRoomUrl, n as importRTC, r as loadOrCreateShareRoom, t as getIceServers } from "./share-B9u8-I3y.js";
3
3
 
4
4
  export { getIceServers, importRTC, loadOrCreateShareRoom, shareLinkFromRoomUrl, startShare };
@@ -1,4 +1,4 @@
1
- import { a as computeTranscriptHash, c as open$1, d as randomHex, f as seal, i as MAX_CHUNK, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, r as MARKER, s as deriveDirKeys, t as CONFIRM_TIMEOUT_MS, u as parseSecret } from "./e2e-CYlKpfxa.js";
1
+ import { a as computeTranscriptHash, c as open$1, d as randomHex, f as seal, i as MAX_CHUNK, l as packEnvelope, n as FLAG_CONFIRM, o as deriveAuthToken, p as unpackEnvelope, r as MARKER, s as deriveDirKeys, t as CONFIRM_TIMEOUT_MS, u as parseSecret } from "./e2e-CEIdJGZ7.js";
2
2
  import { mkdir, readFile, writeFile } from "fs/promises";
3
3
  import { homedir } from "os";
4
4
  import path from "path";
@@ -627,4 +627,4 @@ async function startShare(opts) {
627
627
 
628
628
  //#endregion
629
629
  export { startShare as a, shareLinkFromRoomUrl as i, importRTC as n, loadOrCreateShareRoom as r, getIceServers as t };
630
- //# sourceMappingURL=share-D4K0JnHg.js.map
630
+ //# sourceMappingURL=share-B9u8-I3y.js.map
@@ -1,5 +1,5 @@
1
- import { i as readGlobalPids } from "./globalPidIndex-Ca4sTr1b.js";
2
- import { n as getMinFreeMb, o as getSpawnWaitMs, t as getMaxAgents } from "./workspaceConfig-CuGjX2_R.js";
1
+ import { i as readGlobalPids } from "./globalPidIndex-D9DOSd-c.js";
2
+ import { n as getMinFreeMb, o as getSpawnWaitMs, t as getMaxAgents } from "./workspaceConfig-B7HaQ-MI.js";
3
3
  import { readFile } from "fs/promises";
4
4
 
5
5
  //#region ts/spawnGate.ts
@@ -104,4 +104,4 @@ async function waitForSpawnCapacity(opts) {
104
104
 
105
105
  //#endregion
106
106
  export { waitForSpawnCapacity as i, spawnGateEnabled as n, spawnRejectionReason as r, memAvailableMb as t };
107
- //# sourceMappingURL=spawnGate-PwzImpOw.js.map
107
+ //# sourceMappingURL=spawnGate-Bo_LFgt9.js.map
@@ -0,0 +1,5 @@
1
+ import "./logger-CDIsZ-Pp.js";
2
+ import "./globalPidIndex-D9DOSd-c.js";
3
+ import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-Bo_LFgt9.js";
4
+
5
+ export { waitForSpawnCapacity };
@@ -211,4 +211,4 @@ function opsMissing(local, remoteHave) {
211
211
 
212
212
  //#endregion
213
213
  export { renderThread as a, makeOp as c, formatHlc as d, hlcSend as f, opsMissing as i, opId as l, maxHlc as n, sortOps as o, parseHlc as p, mergeOps as r, isValidOp as s, haveVector as t, compareHlc as u };
214
- //# sourceMappingURL=store-BXJERNbW.js.map
214
+ //# sourceMappingURL=store-Ck0XRn-K.js.map