agent-yes 1.246.5 → 1.247.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 (33) hide show
  1. package/dist/SUPPORTED_CLIS-B1DPQLRV.js +11 -0
  2. package/dist/{SUPPORTED_CLIS-ia9b-P1k.js → SUPPORTED_CLIS-DUALQTec.js} +2 -2
  3. package/dist/{agentShare-BazKWNQQ.js → agentShare-Clx5QcyE.js} +2 -2
  4. package/dist/{callback-Csr8_-FG.js → callback-BPAlieXe.js} +2 -2
  5. package/dist/{callback-DyyjF-fr.js → callback-DPd9PJQA.js} +3 -3
  6. package/dist/cli.js +7 -7
  7. package/dist/index.js +3 -3
  8. package/dist/{notifyDaemon-DDPfMGlw.js → notifyDaemon-CAML5u0d.js} +2 -2
  9. package/dist/{pidStore-bCVS2Ldt.js → pidStore-Bg7wdjxY.js} +1 -1
  10. package/dist/{pidStore-6EZd5DUv.js → pidStore-vnX0bgra.js} +5 -3
  11. package/dist/{rustBinary-DuwxRidk.js → rustBinary-BU3E3uMi.js} +2 -2
  12. package/dist/{schedule-CWBHxQxk.js → schedule-C8wzhq0y.js} +6 -6
  13. package/dist/{serve-DyZpvp4C.js → serve-D_DP0VBy.js} +28 -19
  14. package/dist/{setup-JqletyDD.js → setup-DIa8Y-lx.js} +3 -3
  15. package/dist/{spawnGate-BxgS_GlF.js → spawnGate-BFJPdHCQ.js} +2 -2
  16. package/dist/{spawnGate-Dc3odVqo.js → spawnGate-Djr4KlF5.js} +1 -1
  17. package/dist/{subcommands-BL_SWFDC.js → subcommands-DeHlaNOY.js} +12 -12
  18. package/dist/{subcommands-CdWAGc4C.js → subcommands-WJz-UHyC.js} +1 -1
  19. package/dist/{terminal-BFq0mWdQ.js → terminal-MnictO_E.js} +2 -2
  20. package/dist/{ts-B51ZLoJC.js → ts-rCPxI3aR.js} +54 -5
  21. package/dist/{versionChecker-D5ir842c.js → versionChecker-Du1qdZR9.js} +2 -2
  22. package/dist/{widget-BXlREJHQ.js → widget-U6HkHQcz.js} +3 -3
  23. package/dist/{workspaceConfig-DOHygA2x.js → workspaceConfig-CpilQzMY.js} +24 -2
  24. package/dist/{ws-C6gfqPHM.js → ws-1vGWz9c9.js} +3 -3
  25. package/package.json +1 -1
  26. package/ts/agentPermissions.spec.ts +117 -0
  27. package/ts/agentPermissions.ts +80 -0
  28. package/ts/globalPidIndex.ts +8 -0
  29. package/ts/index.ts +10 -0
  30. package/ts/pidStore.ts +7 -0
  31. package/ts/serve.ts +47 -1
  32. package/ts/workspaceConfig.ts +30 -0
  33. package/dist/SUPPORTED_CLIS-D3b_1q8z.js +0 -11
@@ -0,0 +1,11 @@
1
+ import "./logger-CDIsZ-Pp.js";
2
+ import "./versionChecker-Du1qdZR9.js";
3
+ import "./ts-rCPxI3aR.js";
4
+ import "./todoAutomation-Buo457VO.js";
5
+ import "./JsonlStore-CPGIR0Wy.js";
6
+ import "./globalPidIndex-D9DOSd-c.js";
7
+ import "./pidStore-vnX0bgra.js";
8
+ import "./messageLog-C-YIzhRj.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DUALQTec.js";
10
+
11
+ export { SUPPORTED_CLIS };
@@ -1,8 +1,8 @@
1
- import { t as CLIS_CONFIG } from "./ts-B51ZLoJC.js";
1
+ import { t as CLIS_CONFIG } from "./ts-rCPxI3aR.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-ia9b-P1k.js.map
8
+ //# sourceMappingURL=SUPPORTED_CLIS-DUALQTec.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-IBbnn9b8.js";
6
- import { P as resolveOne } from "./subcommands-BL_SWFDC.js";
6
+ import { P as resolveOne } from "./subcommands-DeHlaNOY.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-BazKWNQQ.js.map
232
+ //# sourceMappingURL=agentShare-Clx5QcyE.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-IBbnn9b8.js";
6
- import "./subcommands-BL_SWFDC.js";
6
+ import "./subcommands-DeHlaNOY.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-DyyjF-fr.js";
10
+ import { i as loadOrCreateCallbackSecret, n as isCallbackRevoked, r as loadCallbackSecretReadOnly, t as cmdCallback } from "./callback-DPd9PJQA.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-BL_SWFDC.js";
2
+ import { P as resolveOne } from "./subcommands-DeHlaNOY.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 { chmodSync, readFileSync, renameSync, writeFileSync } from "node:fs";
@@ -72,7 +72,7 @@ async function resolveBase(flag) {
72
72
  if (flag) return flag;
73
73
  if (process.env.AGENT_YES_CALLBACK_BASE) return process.env.AGENT_YES_CALLBACK_BASE;
74
74
  try {
75
- const { resolveLocalServeUrl } = await import("./serve-DyZpvp4C.js");
75
+ const { resolveLocalServeUrl } = await import("./serve-D_DP0VBy.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-DyyjF-fr.js.map
190
+ //# sourceMappingURL=callback-DPd9PJQA.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-D5ir842c.js";
5
- import { n as getRustBinary } from "./rustBinary-DuwxRidk.js";
4
+ import { i as versionString, n as displayVersion, t as checkAndAutoUpdate } from "./versionChecker-Du1qdZR9.js";
5
+ import { n as getRustBinary } from "./rustBinary-BU3E3uMi.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-CdWAGc4C.js");
288
+ const { isSubcommand, runSubcommand, cmdHelp, isUnknownManagerToken } = await import("./subcommands-WJz-UHyC.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-D3b_1q8z.js");
298
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-B1DPQLRV.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);
@@ -323,7 +323,7 @@ if (config.tray) {
323
323
  ensureTray();
324
324
  }
325
325
  if (!config.showVersion && !config.appendPrompt && !config.tray) {
326
- const { waitForSpawnCapacity } = await import("./spawnGate-Dc3odVqo.js");
326
+ const { waitForSpawnCapacity } = await import("./spawnGate-Djr4KlF5.js");
327
327
  await waitForSpawnCapacity({
328
328
  onWait: (reason, waitedMs) => {
329
329
  if (config.verbose || waitedMs === 0) console.error(`[agent-yes] spawn gate: ${reason} — waiting…`);
@@ -346,7 +346,7 @@ if (config.useRust) {
346
346
  }
347
347
  }
348
348
  if (rustBinary) {
349
- const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-D3b_1q8z.js");
349
+ const { SUPPORTED_CLIS } = await import("./SUPPORTED_CLIS-B1DPQLRV.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}`);
@@ -411,7 +411,7 @@ if (config.showVersion) {
411
411
  process.exit(0);
412
412
  }
413
413
  if (config.appendPrompt) {
414
- const { PidStore } = await import("./pidStore-bCVS2Ldt.js");
414
+ const { PidStore } = await import("./pidStore-Bg7wdjxY.js");
415
415
  const ipcPath = await PidStore.findActiveFifo(process.cwd());
416
416
  if (!ipcPath) {
417
417
  console.error("No active agent with IPC found in current directory.");
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-D5ir842c.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-B51ZLoJC.js";
2
+ import "./versionChecker-Du1qdZR9.js";
3
+ import { a as hasTodoStore, i as answerAsk, l as AgentContext, n as agentYes, o as listAsks, r as config, s as listAsksForProject, t as CLIS_CONFIG } from "./ts-rCPxI3aR.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";
7
- import "./pidStore-6EZd5DUv.js";
7
+ import "./pidStore-vnX0bgra.js";
8
8
  import "./messageLog-C-YIzhRj.js";
9
9
 
10
10
  export { AgentContext, CLIS_CONFIG, CycleError, DONE_STATE, LIFECYCLES, ORPHANED_STATE, TodoStore, answerAsk, canTransition, config, agentYes as default, describeBlock, hasTodoStore, initialState, isKnownKind, listAsks, listAsksForProject, monitorHint, nextStates, openBlockers, openStore, reconcileTodos, removeControlCharacters, renderDigest, renderTree, requiredGate, statesOf, unblockedTasks };
@@ -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-IBbnn9b8.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-BL_SWFDC.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-DeHlaNOY.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-DDPfMGlw.js.map
592
+ //# sourceMappingURL=notifyDaemon-CAML5u0d.js.map
@@ -1,6 +1,6 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
2
  import "./JsonlStore-CPGIR0Wy.js";
3
3
  import "./globalPidIndex-D9DOSd-c.js";
4
- import { t as PidStore } from "./pidStore-6EZd5DUv.js";
4
+ import { t as PidStore } from "./pidStore-vnX0bgra.js";
5
5
 
6
6
  export { PidStore };
@@ -24,7 +24,7 @@ var PidStore = class PidStore {
24
24
  logger.warn("[pidStore] Failed to initialize:", error);
25
25
  }
26
26
  }
27
- async registerProcess({ pid, cli, args, prompt, cwd, wrapperPid, parentPid }) {
27
+ async registerProcess({ pid, cli, args, prompt, cwd, wrapperPid, parentPid, permissions }) {
28
28
  const now = Date.now();
29
29
  const argsJson = JSON.stringify(args);
30
30
  const logFile = this.getRawLogPath(pid);
@@ -36,6 +36,7 @@ var PidStore = class PidStore {
36
36
  pid,
37
37
  cli,
38
38
  args: argsJson,
39
+ permissions,
39
40
  prompt,
40
41
  cwd,
41
42
  logFile,
@@ -67,7 +68,8 @@ var PidStore = class PidStore {
67
68
  started_at: now,
68
69
  wrapper_pid: wrapperPid ?? null,
69
70
  parent_pid: parentPid ?? null,
70
- agent_id: agentId
71
+ agent_id: agentId,
72
+ permissions: permissions ?? null
71
73
  }).then(() => maybeCompactGlobalPids()).catch(() => null);
72
74
  return result;
73
75
  }
@@ -188,4 +190,4 @@ pid-db/
188
190
 
189
191
  //#endregion
190
192
  export { PidStore as t };
191
- //# sourceMappingURL=pidStore-6EZd5DUv.js.map
193
+ //# sourceMappingURL=pidStore-vnX0bgra.js.map
@@ -1,4 +1,4 @@
1
- import { r as getInstalledPackage } from "./versionChecker-D5ir842c.js";
1
+ import { r as getInstalledPackage } from "./versionChecker-Du1qdZR9.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-DuwxRidk.js.map
228
+ //# sourceMappingURL=rustBinary-BU3E3uMi.js.map
@@ -1,13 +1,13 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-D5ir842c.js";
3
- import "./ts-B51ZLoJC.js";
2
+ import "./versionChecker-Du1qdZR9.js";
3
+ import "./ts-rCPxI3aR.js";
4
4
  import "./todoAutomation-Buo457VO.js";
5
5
  import "./JsonlStore-CPGIR0Wy.js";
6
6
  import "./globalPidIndex-D9DOSd-c.js";
7
- import "./pidStore-6EZd5DUv.js";
7
+ import "./pidStore-vnX0bgra.js";
8
8
  import "./messageLog-C-YIzhRj.js";
9
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-ia9b-P1k.js";
10
- import { d as resolveSpawnCwd } from "./workspaceConfig-DOHygA2x.js";
9
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DUALQTec.js";
10
+ import { f as resolveSpawnCwd } from "./workspaceConfig-CpilQzMY.js";
11
11
  import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-BtL6Oo1o.js";
12
12
  import { createHash } from "node:crypto";
13
13
 
@@ -153,4 +153,4 @@ async function cmdSchedule(rest) {
153
153
 
154
154
  //#endregion
155
155
  export { cmdSchedule };
156
- //# sourceMappingURL=schedule-CWBHxQxk.js.map
156
+ //# sourceMappingURL=schedule-C8wzhq0y.js.map
@@ -1,25 +1,25 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
- import { r as getInstalledPackage } from "./versionChecker-D5ir842c.js";
3
- import { t as findSpawnHiddenLauncher } from "./rustBinary-DuwxRidk.js";
4
- import { i as answerAsk, l as CLAUDE_SESSION_PIN_ENV, o as listAsks } from "./ts-B51ZLoJC.js";
2
+ import { r as getInstalledPackage } from "./versionChecker-Du1qdZR9.js";
3
+ import { t as findSpawnHiddenLauncher } from "./rustBinary-BU3E3uMi.js";
4
+ import { c as permissionBadge, i as answerAsk, o as listAsks, u as CLAUDE_SESSION_PIN_ENV } from "./ts-rCPxI3aR.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";
8
8
  import { a as updateGlobalPidStatus } from "./globalPidIndex-D9DOSd-c.js";
9
- import "./pidStore-6EZd5DUv.js";
9
+ import "./pidStore-vnX0bgra.js";
10
10
  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-IBbnn9b8.js";
14
- import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-ia9b-P1k.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-BL_SWFDC.js";
14
+ import { t as SUPPORTED_CLIS } from "./SUPPORTED_CLIS-DUALQTec.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-DeHlaNOY.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-DyyjF-fr.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-DOHygA2x.js";
19
+ import { n as isCallbackRevoked, r as loadCallbackSecretReadOnly } from "./callback-DPd9PJQA.js";
20
+ import { a as getProvisionRoot, d as isProvisionAllowed, f as resolveSpawnCwd, i as getProvisionHook, l as hasProvisionHook, o as getSpawnHook, t as allowsSkipPermissions, u as hasSpawnHook } from "./workspaceConfig-CpilQzMY.js";
21
21
  import { n as liveEnv, t as ensureNodeRuntime } from "./nodeRuntime-BtL6Oo1o.js";
22
- import { r as spawnRejectionReason } from "./spawnGate-BxgS_GlF.js";
22
+ import { r as spawnRejectionReason } from "./spawnGate-BFJPdHCQ.js";
23
23
  import yargs from "yargs";
24
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";
@@ -2151,7 +2151,11 @@ Options:
2151
2151
  size: await sizeOf(r.pid),
2152
2152
  inputs: [textIn, envIn],
2153
2153
  outputs: [textOut],
2154
- renderHints: await hintsOf(r)
2154
+ renderHints: await hintsOf(r),
2155
+ configPublic: {
2156
+ permissions: r.permissions ?? null,
2157
+ permissionBadge: permissionBadge(r.permissions)
2158
+ }
2155
2159
  })));
2156
2160
  nodes.push({
2157
2161
  id: envNodeId,
@@ -2181,7 +2185,8 @@ Options:
2181
2185
  kill: true,
2182
2186
  spawn: true,
2183
2187
  spawnHook: hasSpawnHook(),
2184
- provision: hasProvisionHook()
2188
+ provision: hasProvisionHook(),
2189
+ skipPermissions: allowsSkipPermissions()
2185
2190
  }
2186
2191
  }
2187
2192
  });
@@ -2296,11 +2301,12 @@ Options:
2296
2301
  kill: true,
2297
2302
  spawn: true,
2298
2303
  spawnHook: hasSpawnHook(),
2299
- provision: hasProvisionHook()
2304
+ provision: hasProvisionHook(),
2305
+ skipPermissions: allowsSkipPermissions()
2300
2306
  }
2301
2307
  });
2302
2308
  if (req.method === "GET" && p === "/api/ws") {
2303
- const ws = await import("./ws-C6gfqPHM.js");
2309
+ const ws = await import("./ws-1vGWz9c9.js");
2304
2310
  try {
2305
2311
  await ws.loadProvision();
2306
2312
  } catch (e) {
@@ -2320,7 +2326,7 @@ Options:
2320
2326
  if (req.method === "GET" && p === "/api/ws/status") {
2321
2327
  const dirRaw = url.searchParams.get("path");
2322
2328
  if (!dirRaw) return new Response("missing ?path=<workspace dir>", { status: 400 });
2323
- const ws = await import("./ws-C6gfqPHM.js");
2329
+ const ws = await import("./ws-1vGWz9c9.js");
2324
2330
  let prov;
2325
2331
  try {
2326
2332
  prov = await ws.loadProvision();
@@ -2888,6 +2894,8 @@ Options:
2888
2894
  const cli = String(body.cli ?? "claude");
2889
2895
  if (!SUPPORTED_CLIS.includes(cli)) return new Response(`unsupported cli: ${cli}`, { status: 400 });
2890
2896
  const prompt = String(body.prompt ?? "");
2897
+ const wantsSkipPermissions = body.yes === true;
2898
+ if (wantsSkipPermissions && !allowsSkipPermissions()) return new Response("this environment does not permit skip-permissions agents (caps.skipPermissions=false) — spawn without `yes`, or set \"allowSkipPermissions\": true in ~/.agent-yes/config.json (or AGENT_YES_ALLOW_SKIP_PERMISSIONS=1) on the host", { status: 403 });
2891
2899
  const reject = await spawnRejectionReason();
2892
2900
  if (reject) return new Response(reject, { status: 429 });
2893
2901
  let cwd;
@@ -2983,6 +2991,7 @@ Options:
2983
2991
  const ayBin = Bun.which("ay") ?? process.argv[1];
2984
2992
  const agentArgv = [
2985
2993
  ...process.platform === "win32" && ayBin.toLowerCase().endsWith(".exe") ? [ayBin] : [process.execPath, ayBin],
2994
+ ...wantsSkipPermissions ? ["-y"] : [],
2986
2995
  cli,
2987
2996
  ...prompt ? ["--", prompt] : []
2988
2997
  ];
@@ -3070,7 +3079,7 @@ Options:
3070
3079
  const perm = body.perm ?? "r";
3071
3080
  if (perm !== "r" && perm !== "rw") return new Response(`invalid perm ${perm} (want r or rw)`, { status: 400 });
3072
3081
  try {
3073
- const { createScopedShare } = await import("./agentShare-BazKWNQQ.js");
3082
+ const { createScopedShare } = await import("./agentShare-Clx5QcyE.js");
3074
3083
  const share = await createScopedShare({
3075
3084
  agent: body.agent,
3076
3085
  perm,
@@ -3085,12 +3094,12 @@ Options:
3085
3094
  }
3086
3095
  }
3087
3096
  if (req.method === "GET" && p === "/api/shares") {
3088
- const { listShares } = await import("./agentShare-BazKWNQQ.js");
3097
+ const { listShares } = await import("./agentShare-Clx5QcyE.js");
3089
3098
  return Response.json(listShares());
3090
3099
  }
3091
3100
  const revokeM = /^\/api\/share\/([^/]+)$/.exec(p);
3092
3101
  if (req.method === "DELETE" && revokeM) {
3093
- const { revokeShare } = await import("./agentShare-BazKWNQQ.js");
3102
+ const { revokeShare } = await import("./agentShare-Clx5QcyE.js");
3094
3103
  const ok = revokeShare(decodeURIComponent(revokeM[1]));
3095
3104
  return new Response(ok ? "revoked" : "no such share", { status: ok ? 200 : 404 });
3096
3105
  }
@@ -3392,7 +3401,7 @@ Options:
3392
3401
  const shutdown = (resolve) => {
3393
3402
  if (heartbeat) clearInterval(heartbeat);
3394
3403
  closeShare?.();
3395
- import("./agentShare-BazKWNQQ.js").then((m) => m.revokeAllShares()).catch(() => {});
3404
+ import("./agentShare-Clx5QcyE.js").then((m) => m.revokeAllShares()).catch(() => {});
3396
3405
  server?.stop();
3397
3406
  Promise.resolve(releaseHostLock?.()).catch(() => {}).then(resolve);
3398
3407
  };
@@ -3405,4 +3414,4 @@ Options:
3405
3414
 
3406
3415
  //#endregion
3407
3416
  export { cmdServe, loadTokenReadOnly, mintScopedTermToken, resolveDaemonHttpBase, resolveLocalServeUrl };
3408
- //# sourceMappingURL=serve-DyZpvp4C.js.map
3417
+ //# sourceMappingURL=serve-D_DP0VBy.js.map
@@ -1,4 +1,4 @@
1
- import { f as setWorkspaceRoot, s as getWorkspaceRoot } from "./workspaceConfig-DOHygA2x.js";
1
+ import { c as getWorkspaceRoot, p as setWorkspaceRoot } from "./workspaceConfig-CpilQzMY.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-DyZpvp4C.js");
35
+ const { cmdServe } = await import("./serve-D_DP0VBy.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-JqletyDD.js.map
45
+ //# sourceMappingURL=setup-DIa8Y-lx.js.map
@@ -1,5 +1,5 @@
1
1
  import { i as readGlobalPids } from "./globalPidIndex-D9DOSd-c.js";
2
- import { n as getMinFreeMb, o as getSpawnWaitMs, t as getMaxAgents } from "./workspaceConfig-DOHygA2x.js";
2
+ import { n as getMaxAgents, r as getMinFreeMb, s as getSpawnWaitMs } from "./workspaceConfig-CpilQzMY.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-BxgS_GlF.js.map
107
+ //# sourceMappingURL=spawnGate-BFJPdHCQ.js.map
@@ -1,5 +1,5 @@
1
1
  import "./logger-CDIsZ-Pp.js";
2
2
  import "./globalPidIndex-D9DOSd-c.js";
3
- import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-BxgS_GlF.js";
3
+ import { i as waitForSpawnCapacity, n as spawnGateEnabled, r as spawnRejectionReason, t as memAvailableMb } from "./spawnGate-BFJPdHCQ.js";
4
4
 
5
5
  export { waitForSpawnCapacity };
@@ -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-BFq0mWdQ.js");
1270
+ const { cmdTerm } = await import("./terminal-MnictO_E.js");
1271
1271
  return cmdTerm(rest);
1272
1272
  }
1273
1273
  case "widget": {
1274
- const { cmdWidget } = await import("./widget-BXlREJHQ.js");
1274
+ const { cmdWidget } = await import("./widget-U6HkHQcz.js");
1275
1275
  return cmdWidget(rest);
1276
1276
  }
1277
1277
  case "mint": {
1278
- const { cmdMint } = await import("./widget-BXlREJHQ.js");
1278
+ const { cmdMint } = await import("./widget-U6HkHQcz.js");
1279
1279
  return cmdMint(rest);
1280
1280
  }
1281
1281
  case "serve": {
1282
- const { cmdServe } = await import("./serve-DyZpvp4C.js");
1282
+ const { cmdServe } = await import("./serve-D_DP0VBy.js");
1283
1283
  return cmdServe(rest);
1284
1284
  }
1285
1285
  case "setup": {
1286
- const { cmdSetup } = await import("./setup-JqletyDD.js");
1286
+ const { cmdSetup } = await import("./setup-DIa8Y-lx.js");
1287
1287
  return cmdSetup(rest);
1288
1288
  }
1289
1289
  case "ws": {
1290
- const { cmdWs } = await import("./ws-C6gfqPHM.js");
1290
+ const { cmdWs } = await import("./ws-1vGWz9c9.js");
1291
1291
  return cmdWs(rest);
1292
1292
  }
1293
1293
  case "schedule": {
1294
- const { cmdSchedule } = await import("./schedule-CWBHxQxk.js");
1294
+ const { cmdSchedule } = await import("./schedule-C8wzhq0y.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-Csr8_-FG.js");
1306
+ const { cmdCallback } = await import("./callback-BPAlieXe.js");
1307
1307
  return cmdCallback(rest);
1308
1308
  }
1309
1309
  case "reap":
@@ -3706,7 +3706,7 @@ async function cmdAttach(rest) {
3706
3706
  const winsizeDir = path.join(ayHome, "winsize");
3707
3707
  await mkdir(winsizeDir, { recursive: true });
3708
3708
  const winsizePath = path.join(winsizeDir, String(record.pid));
3709
- const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-DyZpvp4C.js");
3709
+ const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-D_DP0VBy.js");
3710
3710
  const daemonBase = await resolveDaemonHttpBase().catch(() => null);
3711
3711
  const daemonToken = daemonBase ? await loadTokenReadOnly().catch(() => null) ?? "" : "";
3712
3712
  const capViewer = `attach:${process.pid}`;
@@ -4403,7 +4403,7 @@ async function cmdNotify(rest) {
4403
4403
  }
4404
4404
  const ensure = async () => {
4405
4405
  if (!argv["ensure-daemon"]) return;
4406
- const { ensureDaemon } = await import("./notifyDaemon-DDPfMGlw.js");
4406
+ const { ensureDaemon } = await import("./notifyDaemon-CAML5u0d.js");
4407
4407
  await ensureDaemon().catch(() => null);
4408
4408
  };
4409
4409
  await heartbeatWatcher(parent, selfStartedAt);
@@ -4477,7 +4477,7 @@ async function cmdNotifyCursor(args) {
4477
4477
  }
4478
4478
  async function cmdNotifyd(rest) {
4479
4479
  const sub = rest[0] ?? "status";
4480
- const daemon = await import("./notifyDaemon-DDPfMGlw.js");
4480
+ const daemon = await import("./notifyDaemon-CAML5u0d.js");
4481
4481
  switch (sub) {
4482
4482
  case "run": return daemon.runDaemon();
4483
4483
  case "once": return daemon.runDaemon({ once: true });
@@ -4504,4 +4504,4 @@ async function cmdNotifyd(rest) {
4504
4504
 
4505
4505
  //#endregion
4506
4506
  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 };
4507
- //# sourceMappingURL=subcommands-BL_SWFDC.js.map
4507
+ //# sourceMappingURL=subcommands-DeHlaNOY.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-IBbnn9b8.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-BL_SWFDC.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-DeHlaNOY.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-DyZpvp4C.js");
101
+ const { mintScopedTermToken } = await import("./serve-D_DP0VBy.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-BFq0mWdQ.js.map
138
+ //# sourceMappingURL=terminal-MnictO_E.js.map
@@ -1,11 +1,11 @@
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-D5ir842c.js";
3
+ import { r as getInstalledPackage } from "./versionChecker-Du1qdZR9.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";
7
7
  import { i as readGlobalPids } from "./globalPidIndex-D9DOSd-c.js";
8
- import { t as PidStore } from "./pidStore-6EZd5DUv.js";
8
+ import { t as PidStore } from "./pidStore-vnX0bgra.js";
9
9
  import { r as recordInbox } from "./messageLog-C-YIzhRj.js";
10
10
  import { n as register, r as sweep } from "./reaper-DP49VCKx.js";
11
11
  import { arch, platform } from "process";
@@ -1252,6 +1252,49 @@ async function notifyWebhook(status, details, cwd = process.cwd()) {
1252
1252
  }
1253
1253
  }
1254
1254
 
1255
+ //#endregion
1256
+ //#region ts/agentPermissions.ts
1257
+ /**
1258
+ * Flags that disable a CLI's confirmation gate, recognised regardless of what
1259
+ * `yesArgs` the config declares.
1260
+ *
1261
+ * The configured `yesArgs` are the flags `-y` APPENDS; a user is free to pass
1262
+ * the same flag directly, and a config that omits `yesArgs` entirely (some CLIs
1263
+ * deliberately have none) must not make a genuinely dangerous flag invisible.
1264
+ * So the check is the union: configured flags OR any of these.
1265
+ */
1266
+ const DANGEROUS_FLAGS = new Set([
1267
+ "--dangerously-skip-permissions",
1268
+ "--dangerously-bypass-approvals-and-sandbox",
1269
+ "--yolo",
1270
+ "--full-auto"
1271
+ ]);
1272
+ /** `--flag=value` and `--flag value` must compare equal — match on the flag part. */
1273
+ function flagName(arg) {
1274
+ const eq = arg.indexOf("=");
1275
+ return eq === -1 ? arg : arg.slice(0, eq);
1276
+ }
1277
+ function derivePermissions(opts) {
1278
+ const configured = new Set((opts.yesArgs ?? []).map(flagName).filter(Boolean));
1279
+ return {
1280
+ skip_permissions: opts.cliArgs.some((a) => {
1281
+ const name = flagName(a);
1282
+ return configured.has(name) || DANGEROUS_FLAGS.has(name);
1283
+ }),
1284
+ robust: Boolean(opts.robust),
1285
+ auto_continue: Boolean(opts.autoContinue)
1286
+ };
1287
+ }
1288
+ /**
1289
+ * One-word posture for a badge. `skip` is the only one that changes what the
1290
+ * agent is ALLOWED to do; the wrapper flags change only how it recovers, so
1291
+ * they never soften the label.
1292
+ */
1293
+ function permissionBadge(p) {
1294
+ if (!p) return null;
1295
+ return p.skip_permissions ? "skip" : "prompt";
1296
+ }
1297
+
1255
1298
  //#endregion
1256
1299
  //#region ts/askApi.ts
1257
1300
  /**
@@ -1548,7 +1591,13 @@ async function agentYes({ cli, cliArgs = [], skipPermissions = false, prompt, ro
1548
1591
  prompt,
1549
1592
  cwd: workingDir,
1550
1593
  wrapperPid: process.pid,
1551
- parentPid
1594
+ parentPid,
1595
+ permissions: derivePermissions({
1596
+ cliArgs,
1597
+ yesArgs: cliConf.yesArgs,
1598
+ robust,
1599
+ autoContinue: Boolean(robust && cliConf.restoreArgs?.length)
1600
+ })
1552
1601
  });
1553
1602
  } catch (error) {
1554
1603
  logger.warn(`[pidStore] Failed to register process ${shell.pid}:`, error);
@@ -2105,5 +2154,5 @@ function sleep(ms) {
2105
2154
  }
2106
2155
 
2107
2156
  //#endregion
2108
- 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 };
2109
- //# sourceMappingURL=ts-B51ZLoJC.js.map
2157
+ export { hasTodoStore as a, permissionBadge as c, answerAsk as i, AgentContext as l, agentYes as n, listAsks as o, config as r, listAsksForProject as s, CLIS_CONFIG as t, CLAUDE_SESSION_PIN_ENV as u };
2158
+ //# sourceMappingURL=ts-rCPxI3aR.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.246.5";
10
+ var version = "1.247.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-D5ir842c.js.map
218
+ //# sourceMappingURL=versionChecker-Du1qdZR9.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-DyZpvp4C.js");
31
+ const { resolveDaemonHttpBase, loadTokenReadOnly } = await import("./serve-D_DP0VBy.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-DyZpvp4C.js");
189
+ const { mintScopedTermToken } = await import("./serve-D_DP0VBy.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-BXlREJHQ.js.map
205
+ //# sourceMappingURL=widget-U6HkHQcz.js.map
@@ -190,7 +190,29 @@ function resolveSpawnCwd(input) {
190
190
  if (v.includes("/") || v.includes("\\") || path.isAbsolute(v)) return path.resolve(v);
191
191
  return path.join(root, v);
192
192
  }
193
+ /**
194
+ * Whether this environment permits spawning agents that skip the CLI's own
195
+ * permission gate (`-y` / `--dangerously-skip-permissions` and equivalents).
196
+ *
197
+ * This is an ENVIRONMENT capability, not a per-request preference: a restricted
198
+ * host publishes `caps.skipPermissions: false` on its env node and `/api/spawn`
199
+ * refuses such a request, host-enforced the way agentShare's default-deny is.
200
+ * A client can't talk its way past it by asking differently.
201
+ *
202
+ * Defaults to TRUE so nothing changes for an existing host — restricting is an
203
+ * explicit opt-in, via `~/.agent-yes/config.json` (`"allowSkipPermissions": false`)
204
+ * or env `AGENT_YES_ALLOW_SKIP_PERMISSIONS=0`. Only an explicit falsy value
205
+ * restricts; anything unset or unparseable leaves the environment permissive
206
+ * rather than silently locking spawns out.
207
+ *
208
+ * Issue #236.
209
+ */
210
+ function allowsSkipPermissions() {
211
+ const raw = process.env.AGENT_YES_ALLOW_SKIP_PERMISSIONS?.trim();
212
+ if (raw !== void 0 && raw !== "") return !/^(0|false|no|off)$/i.test(raw);
213
+ return readConfig().allowSkipPermissions !== false;
214
+ }
193
215
 
194
216
  //#endregion
195
- export { getSpawnHook as a, hasProvisionHook as c, resolveSpawnCwd as d, setWorkspaceRoot as f, getProvisionRoot as i, hasSpawnHook as l, getMinFreeMb as n, getSpawnWaitMs as o, getProvisionHook as r, getWorkspaceRoot as s, getMaxAgents as t, isProvisionAllowed as u };
196
- //# sourceMappingURL=workspaceConfig-DOHygA2x.js.map
217
+ export { getProvisionRoot as a, getWorkspaceRoot as c, isProvisionAllowed as d, resolveSpawnCwd as f, getProvisionHook as i, hasProvisionHook as l, getMaxAgents as n, getSpawnHook as o, setWorkspaceRoot as p, getMinFreeMb as r, getSpawnWaitMs as s, allowsSkipPermissions as t, hasSpawnHook as u };
218
+ //# sourceMappingURL=workspaceConfig-CpilQzMY.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-IBbnn9b8.js";
6
- import { C as listRecords } from "./subcommands-BL_SWFDC.js";
6
+ import { C as listRecords } from "./subcommands-DeHlaNOY.js";
7
7
  import "./webrtcLink-BMYneHbu.js";
8
8
  import "./remotes-BxQnNxQv.js";
9
- import { i as getProvisionRoot } from "./workspaceConfig-DOHygA2x.js";
9
+ import { a as getProvisionRoot } from "./workspaceConfig-CpilQzMY.js";
10
10
  import { existsSync } from "fs";
11
11
  import { lstat, opendir } from "fs/promises";
12
12
  import path from "path";
@@ -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-C6gfqPHM.js.map
421
+ //# sourceMappingURL=ws-1vGWz9c9.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-yes",
3
- "version": "1.246.5",
3
+ "version": "1.247.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",
@@ -0,0 +1,117 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import { derivePermissions, permissionBadge } from "./agentPermissions.ts";
3
+ import { allowsSkipPermissions } from "./workspaceConfig.ts";
4
+
5
+ // Issue #236. The pid record is the only place the answer to "was this agent
6
+ // allowed to act without confirmation?" survives — the global index carries no
7
+ // argv, and the wrapper's own flags never reach the CLI's args at all.
8
+
9
+ describe("derivePermissions", () => {
10
+ const YES = ["--dangerously-skip-permissions"];
11
+
12
+ it("detects the configured yolo flag", () => {
13
+ expect(
14
+ derivePermissions({ cliArgs: ["--print", ...YES], yesArgs: YES }).skip_permissions,
15
+ ).toBe(true);
16
+ });
17
+
18
+ it("detects a dangerous flag the config never declared", () => {
19
+ // A CLI with no yesArgs must still not hide a flag that disables its gate —
20
+ // the check is the union of configured and known-dangerous, not just config.
21
+ expect(derivePermissions({ cliArgs: ["--yolo"] }).skip_permissions).toBe(true);
22
+ expect(
23
+ derivePermissions({ cliArgs: ["--dangerously-bypass-approvals-and-sandbox"] })
24
+ .skip_permissions,
25
+ ).toBe(true);
26
+ });
27
+
28
+ it("matches the flag part of an --flag=value form", () => {
29
+ expect(derivePermissions({ cliArgs: ["--full-auto=true"] }).skip_permissions).toBe(true);
30
+ });
31
+
32
+ it("does not flag ordinary args", () => {
33
+ expect(
34
+ derivePermissions({ cliArgs: ["--model", "opus", "--continue"], yesArgs: YES })
35
+ .skip_permissions,
36
+ ).toBe(false);
37
+ expect(derivePermissions({ cliArgs: [] }).skip_permissions).toBe(false);
38
+ });
39
+
40
+ it("records the wrapper flags independently of the CLI's", () => {
41
+ const p = derivePermissions({ cliArgs: [], robust: true, autoContinue: true });
42
+ expect(p).toEqual({ skip_permissions: false, robust: true, auto_continue: true });
43
+ });
44
+
45
+ it("defaults every flag to false rather than undefined", () => {
46
+ // The record is serialized to JSON and read by both runtimes; an absent
47
+ // boolean would read as "unknown" where we mean "no".
48
+ expect(derivePermissions({ cliArgs: [] })).toEqual({
49
+ skip_permissions: false,
50
+ robust: false,
51
+ auto_continue: false,
52
+ });
53
+ });
54
+
55
+ it("ignores an empty yesArgs entry rather than matching everything", () => {
56
+ // A config with a stray "" must not make every arg look like a yolo flag.
57
+ expect(derivePermissions({ cliArgs: ["--model"], yesArgs: [""] }).skip_permissions).toBe(false);
58
+ });
59
+ });
60
+
61
+ describe("permissionBadge", () => {
62
+ it("reports skip only when the CLI gate is off", () => {
63
+ expect(permissionBadge({ skip_permissions: true, robust: false, auto_continue: false })).toBe(
64
+ "skip",
65
+ );
66
+ expect(permissionBadge({ skip_permissions: false, robust: false, auto_continue: false })).toBe(
67
+ "prompt",
68
+ );
69
+ });
70
+
71
+ it("never lets the wrapper flags soften the label", () => {
72
+ // robust/auto_continue change how the agent RECOVERS, not what it may do.
73
+ expect(permissionBadge({ skip_permissions: true, robust: true, auto_continue: true })).toBe(
74
+ "skip",
75
+ );
76
+ });
77
+
78
+ it("has nothing to show for a record with no stamp (pre-#236 agent)", () => {
79
+ expect(permissionBadge(null)).toBeNull();
80
+ expect(permissionBadge(undefined)).toBeNull();
81
+ });
82
+ });
83
+
84
+ describe("allowsSkipPermissions", () => {
85
+ const original = process.env.AGENT_YES_ALLOW_SKIP_PERMISSIONS;
86
+ afterEach(() => {
87
+ if (original === undefined) delete process.env.AGENT_YES_ALLOW_SKIP_PERMISSIONS;
88
+ else process.env.AGENT_YES_ALLOW_SKIP_PERMISSIONS = original;
89
+ });
90
+
91
+ it("is permissive by default — restricting is an opt-in", () => {
92
+ delete process.env.AGENT_YES_ALLOW_SKIP_PERMISSIONS;
93
+ expect(allowsSkipPermissions()).toBe(true);
94
+ });
95
+
96
+ it("is restricted by an explicit falsy env value", () => {
97
+ for (const v of ["0", "false", "no", "off", "FALSE"]) {
98
+ process.env.AGENT_YES_ALLOW_SKIP_PERMISSIONS = v;
99
+ expect(allowsSkipPermissions()).toBe(false);
100
+ }
101
+ });
102
+
103
+ it("stays permissive for any other value, including garbage", () => {
104
+ // Failing closed here would lock spawns out of a host over a typo; the
105
+ // enforcement point is an explicit opt-in, so an unparseable value must not
106
+ // silently become a restriction.
107
+ for (const v of ["1", "true", "yes", "on", "banana"]) {
108
+ process.env.AGENT_YES_ALLOW_SKIP_PERMISSIONS = v;
109
+ expect(allowsSkipPermissions()).toBe(true);
110
+ }
111
+ });
112
+
113
+ it("treats an empty env value as unset (falls through to config)", () => {
114
+ process.env.AGENT_YES_ALLOW_SKIP_PERMISSIONS = " ";
115
+ expect(allowsSkipPermissions()).toBe(true);
116
+ });
117
+ });
@@ -0,0 +1,80 @@
1
+ /**
2
+ * The permission posture an agent was actually spawned with — derived once at
3
+ * registration and stamped into the pid record so it can be audited later.
4
+ *
5
+ * Why record it rather than re-derive on read: the global index carries no argv,
6
+ * and the wrapper's own flags (`--robust`, auto-continue) never appear in the
7
+ * CLI's args at all. Without stamping, "was this agent running with permission
8
+ * checks disabled?" is unanswerable after the fact — which is precisely the
9
+ * question an operator looking at a fleet of agents needs answered.
10
+ *
11
+ * Mirrored by `derive_permissions` in rs/src/agentPermissions.rs — keep in sync.
12
+ *
13
+ * Issue #236.
14
+ */
15
+
16
+ export interface AgentPermissions {
17
+ /**
18
+ * The wrapped CLI got its "yolo" flag — the per-CLI `yesArgs` appended by
19
+ * `-y`/`--yes`, or the same flag passed through directly. This is the one that
20
+ * matters for audit: it disables the CLI's own confirmation gate, so the agent
21
+ * can edit files and run commands with no human in the loop.
22
+ */
23
+ skip_permissions: boolean;
24
+ /** agent-yes `--robust`: restart the CLI automatically when it crashes. */
25
+ robust: boolean;
26
+ /** agent-yes auto-continue: resume the prior session on restart. */
27
+ auto_continue: boolean;
28
+ }
29
+
30
+ /**
31
+ * Flags that disable a CLI's confirmation gate, recognised regardless of what
32
+ * `yesArgs` the config declares.
33
+ *
34
+ * The configured `yesArgs` are the flags `-y` APPENDS; a user is free to pass
35
+ * the same flag directly, and a config that omits `yesArgs` entirely (some CLIs
36
+ * deliberately have none) must not make a genuinely dangerous flag invisible.
37
+ * So the check is the union: configured flags OR any of these.
38
+ */
39
+ const DANGEROUS_FLAGS = new Set([
40
+ "--dangerously-skip-permissions",
41
+ "--dangerously-bypass-approvals-and-sandbox",
42
+ "--yolo",
43
+ "--full-auto",
44
+ ]);
45
+
46
+ /** `--flag=value` and `--flag value` must compare equal — match on the flag part. */
47
+ function flagName(arg: string): string {
48
+ const eq = arg.indexOf("=");
49
+ return eq === -1 ? arg : arg.slice(0, eq);
50
+ }
51
+
52
+ export function derivePermissions(opts: {
53
+ /** The args handed to the wrapped CLI (after yesArgs were appended). */
54
+ cliArgs: readonly string[];
55
+ /** The CLI's configured "yolo" flags, if it declares any. */
56
+ yesArgs?: readonly string[];
57
+ robust?: boolean;
58
+ autoContinue?: boolean;
59
+ }): AgentPermissions {
60
+ const configured = new Set((opts.yesArgs ?? []).map(flagName).filter(Boolean));
61
+ const skip = opts.cliArgs.some((a) => {
62
+ const name = flagName(a);
63
+ return configured.has(name) || DANGEROUS_FLAGS.has(name);
64
+ });
65
+ return {
66
+ skip_permissions: skip,
67
+ robust: Boolean(opts.robust),
68
+ auto_continue: Boolean(opts.autoContinue),
69
+ };
70
+ }
71
+
72
+ /**
73
+ * One-word posture for a badge. `skip` is the only one that changes what the
74
+ * agent is ALLOWED to do; the wrapper flags change only how it recovers, so
75
+ * they never soften the label.
76
+ */
77
+ export function permissionBadge(p: AgentPermissions | null | undefined): "skip" | "prompt" | null {
78
+ if (!p) return null;
79
+ return p.skip_permissions ? "skip" : "prompt";
80
+ }
@@ -1,5 +1,6 @@
1
1
  import { appendFile, mkdir, readFile, rename, unlink, writeFile } from "fs/promises";
2
2
  import { homedir } from "os";
3
+ import type { AgentPermissions } from "./agentPermissions.ts";
3
4
  import path from "path";
4
5
  import { lock } from "proper-lockfile";
5
6
  import { logger } from "./logger.ts";
@@ -57,6 +58,13 @@ export interface GlobalPidRecord {
57
58
  // (snake_case). Currently per-process; cross-restart re-binding is a follow-up
58
59
  // (see docs/agent-sharing.md). Preserved verbatim through merges/compaction.
59
60
  agent_id?: string | null;
61
+ // The permission posture this agent was SPAWNED with — whether the wrapped CLI
62
+ // got its "yolo" flag, plus the wrapper's own robust/auto-continue flags. The
63
+ // index carries no argv and the wrapper flags never reach the CLI's args at
64
+ // all, so without stamping this at registration "was this agent running with
65
+ // permission checks off?" is unanswerable after the fact. See
66
+ // ts/agentPermissions.ts (mirrored in rs/src/agent_permissions.rs).
67
+ permissions?: AgentPermissions | null;
60
68
  }
61
69
 
62
70
  /**
package/ts/index.ts CHANGED
@@ -44,6 +44,7 @@ import { globalAgentRegistry } from "./agentRegistry.ts";
44
44
  import { notifyWebhook } from "./webhookNotifier.ts";
45
45
  import { readGlobalPids } from "./globalPidIndex.ts";
46
46
  import * as reaper from "./reaper.ts";
47
+ import { derivePermissions } from "./agentPermissions.ts";
47
48
 
48
49
  export { removeControlCharacters };
49
50
  export { AgentContext };
@@ -510,6 +511,15 @@ export default async function agentYes({
510
511
  wrapperPid: process.pid,
511
512
  // The parent agent's wrapper pid (inherited AGENT_YES_PID), for the tree.
512
513
  parentPid,
514
+ // Audit trail: what this agent is actually allowed to do. `auto_continue`
515
+ // is robust AND a CLI that declares restoreArgs — robust alone only
516
+ // restarts, it resumes nothing.
517
+ permissions: derivePermissions({
518
+ cliArgs,
519
+ yesArgs: cliConf.yesArgs,
520
+ robust,
521
+ autoContinue: Boolean(robust && cliConf.restoreArgs?.length),
522
+ }),
513
523
  });
514
524
  } catch (error) {
515
525
  logger.warn(`[pidStore] Failed to register process ${shell.pid}:`, error);
package/ts/pidStore.ts CHANGED
@@ -4,6 +4,7 @@ import path from "path";
4
4
  import { logger } from "./logger.ts";
5
5
  import { JsonlStore } from "./JsonlStore.ts";
6
6
  import { agentYesHome } from "./agentYesHome.ts";
7
+ import type { AgentPermissions } from "./agentPermissions.ts";
7
8
  import {
8
9
  appendGlobalPid,
9
10
  maybeCompactGlobalPids,
@@ -26,6 +27,8 @@ export interface PidRecord {
26
27
  startedAt: number;
27
28
  // Stable id minted at registration; mirrored to the global index as `agent_id`.
28
29
  agentId?: string;
30
+ /** Permission posture at spawn time; mirrored to the global index. */
31
+ permissions?: AgentPermissions;
29
32
  }
30
33
 
31
34
  export class PidStore {
@@ -59,6 +62,7 @@ export class PidStore {
59
62
  cwd,
60
63
  wrapperPid,
61
64
  parentPid,
65
+ permissions,
62
66
  }: {
63
67
  pid: number;
64
68
  cli: string;
@@ -67,6 +71,7 @@ export class PidStore {
67
71
  cwd: string;
68
72
  wrapperPid?: number;
69
73
  parentPid?: number;
74
+ permissions?: AgentPermissions;
70
75
  }): Promise<PidRecord> {
71
76
  const now = Date.now();
72
77
  const argsJson = JSON.stringify(args);
@@ -91,6 +96,7 @@ export class PidStore {
91
96
  pid,
92
97
  cli,
93
98
  args: argsJson,
99
+ permissions,
94
100
  prompt,
95
101
  cwd,
96
102
  logFile,
@@ -133,6 +139,7 @@ export class PidStore {
133
139
  wrapper_pid: wrapperPid ?? null,
134
140
  parent_pid: parentPid ?? null,
135
141
  agent_id: agentId,
142
+ permissions: permissions ?? null,
136
143
  })
137
144
  .then(() => maybeCompactGlobalPids())
138
145
  .catch(() => null);
package/ts/serve.ts CHANGED
@@ -38,6 +38,7 @@ import {
38
38
  type CommonOpts,
39
39
  } from "./subcommands.ts";
40
40
  import { answerAsk, listAsks } from "./askApi.ts";
41
+ import { permissionBadge } from "./agentPermissions.ts";
41
42
  import { TYPING_BADGE } from "./badges.ts";
42
43
  import { isTermToken, mintTermToken, verifyTermToken, type TermScope } from "./termToken.ts";
43
44
  import { isCallbackRevoked, loadCallbackSecretReadOnly } from "./callback.ts";
@@ -65,6 +66,7 @@ import {
65
66
  hasSpawnHook,
66
67
  isProvisionAllowed,
67
68
  resolveSpawnCwd,
69
+ allowsSkipPermissions,
68
70
  } from "./workspaceConfig.ts";
69
71
 
70
72
  const DEFAULT_PORT = 0;
@@ -2749,6 +2751,16 @@ export async function cmdServe(rest: string[]): Promise<number> {
2749
2751
  inputs: [textIn, envIn],
2750
2752
  outputs: [textOut],
2751
2753
  renderHints: await hintsOf(r),
2754
+ // What this agent is actually permitted to do, stamped at spawn (see
2755
+ // ts/agentPermissions.ts). Carried on the node so the viewer can badge
2756
+ // the env edge — "skip" means the CLI's confirmation gate is off, i.e.
2757
+ // this agent edits and executes with no human in the loop. Null for
2758
+ // agents registered before the stamp existed, which the viewer renders
2759
+ // as "unknown" rather than as safe.
2760
+ configPublic: {
2761
+ permissions: r.permissions ?? null,
2762
+ permissionBadge: permissionBadge(r.permissions),
2763
+ },
2752
2764
  })),
2753
2765
  );
2754
2766
  // The host environment node: identity + capability flags only (no cwd,
@@ -2776,6 +2788,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
2776
2788
  spawn: true,
2777
2789
  spawnHook: hasSpawnHook(),
2778
2790
  provision: hasProvisionHook(),
2791
+ skipPermissions: allowsSkipPermissions(),
2779
2792
  },
2780
2793
  },
2781
2794
  } as unknown as (typeof nodes)[number]); // configPublic is envelope-legal but absent from the agent-node literal type
@@ -2919,6 +2932,10 @@ export async function cmdServe(rest: string[]): Promise<number> {
2919
2932
  spawn: true, // /api/spawn is always on; hooks below shape it
2920
2933
  spawnHook: hasSpawnHook(),
2921
2934
  provision: hasProvisionHook(),
2935
+ // Whether this environment permits spawning agents with the CLI's own
2936
+ // permission gate disabled. Host-enforced in /api/spawn — a client
2937
+ // that asks anyway gets a 403, not a downgrade.
2938
+ skipPermissions: allowsSkipPermissions(),
2922
2939
  },
2923
2940
  });
2924
2941
  }
@@ -3739,6 +3756,7 @@ export async function cmdServe(rest: string[]): Promise<number> {
3739
3756
  cwd?: string;
3740
3757
  from?: string;
3741
3758
  prompt?: string;
3759
+ yes?: boolean;
3742
3760
  fork?: { fromCwd?: string; branch?: string };
3743
3761
  };
3744
3762
  try {
@@ -3751,6 +3769,26 @@ export async function cmdServe(rest: string[]): Promise<number> {
3751
3769
  return new Response(`unsupported cli: ${cli}`, { status: 400 });
3752
3770
  const prompt = String(body.prompt ?? "");
3753
3771
 
3772
+ // Capability enforcement, BEFORE admission control and any provisioning: a
3773
+ // request that this environment will never honour must fail immediately,
3774
+ // not after cloning a repo. `yes` appends the CLI's own "yolo" flag, which
3775
+ // disables its confirmation gate — so a restricted environment refuses it
3776
+ // outright rather than silently downgrading to a safe spawn (which would
3777
+ // hand back an agent that looks like what was asked for and isn't). The
3778
+ // environment declares the cap on its env node / GET /api/host, and it is
3779
+ // enforced HERE, host-side, the way agentShare's default-deny is: a client
3780
+ // cannot ask its way past it. Issue #236.
3781
+ const wantsSkipPermissions = body.yes === true;
3782
+ if (wantsSkipPermissions && !allowsSkipPermissions()) {
3783
+ return new Response(
3784
+ `this environment does not permit skip-permissions agents ` +
3785
+ `(caps.skipPermissions=false) — spawn without \`yes\`, or set ` +
3786
+ `"allowSkipPermissions": true in ~/.agent-yes/config.json ` +
3787
+ `(or AGENT_YES_ALLOW_SKIP_PERMISSIONS=1) on the host`,
3788
+ { status: 403 },
3789
+ );
3790
+ }
3791
+
3754
3792
  // Admission control BEFORE any provisioning (clone/worktree) so a capped
3755
3793
  // request fails fast without doing expensive work. Enforces the optional
3756
3794
  // concurrency cap + memory floor that keep a fan-out of agents from
@@ -3946,7 +3984,15 @@ export async function cmdServe(rest: string[]): Promise<number> {
3946
3984
  process.platform === "win32" && ayBin.toLowerCase().endsWith(".exe")
3947
3985
  ? [ayBin]
3948
3986
  : [process.execPath, ayBin];
3949
- const agentArgv = [...ayCmd, cli, ...(prompt ? ["--", prompt] : [])];
3987
+ // `-y` goes BEFORE the prompt separator so it is parsed as an agent-yes
3988
+ // flag (global flags precede the CLI's own args), and only after the
3989
+ // capability check above has allowed it.
3990
+ const agentArgv = [
3991
+ ...ayCmd,
3992
+ ...(wantsSkipPermissions ? ["-y"] : []),
3993
+ cli,
3994
+ ...(prompt ? ["--", prompt] : []),
3995
+ ];
3950
3996
  // don't leak our Claude Code session into the agent
3951
3997
  const agentEnv = freshAgentEnv();
3952
3998
  // Correlation id: the spawn response returns the `ay` LAUNCHER pid, which is
@@ -34,6 +34,13 @@ interface Config {
34
34
  * so it is intentionally NOT settable over the network.
35
35
  */
36
36
  provisionHook?: string;
37
+ /**
38
+ * Whether this environment permits spawning agents with the CLI's permission
39
+ * gate disabled (`-y` / `--dangerously-skip-permissions` and friends).
40
+ * Defaults to TRUE — the historical behaviour — so a host opts IN to being
41
+ * restricted. See {@link allowsSkipPermissions}.
42
+ */
43
+ allowSkipPermissions?: boolean;
37
44
  /**
38
45
  * Max number of concurrently-live agents the daemon will admit via
39
46
  * `/api/spawn`. `0`/unset = unlimited (current behavior). See {@link getMaxAgents}.
@@ -263,3 +270,26 @@ export function resolveSpawnCwd(input?: string): string {
263
270
  if (v.includes("/") || v.includes("\\") || path.isAbsolute(v)) return path.resolve(v);
264
271
  return path.join(root, v);
265
272
  }
273
+
274
+ /**
275
+ * Whether this environment permits spawning agents that skip the CLI's own
276
+ * permission gate (`-y` / `--dangerously-skip-permissions` and equivalents).
277
+ *
278
+ * This is an ENVIRONMENT capability, not a per-request preference: a restricted
279
+ * host publishes `caps.skipPermissions: false` on its env node and `/api/spawn`
280
+ * refuses such a request, host-enforced the way agentShare's default-deny is.
281
+ * A client can't talk its way past it by asking differently.
282
+ *
283
+ * Defaults to TRUE so nothing changes for an existing host — restricting is an
284
+ * explicit opt-in, via `~/.agent-yes/config.json` (`"allowSkipPermissions": false`)
285
+ * or env `AGENT_YES_ALLOW_SKIP_PERMISSIONS=0`. Only an explicit falsy value
286
+ * restricts; anything unset or unparseable leaves the environment permissive
287
+ * rather than silently locking spawns out.
288
+ *
289
+ * Issue #236.
290
+ */
291
+ export function allowsSkipPermissions(): boolean {
292
+ const raw = process.env.AGENT_YES_ALLOW_SKIP_PERMISSIONS?.trim();
293
+ if (raw !== undefined && raw !== "") return !/^(0|false|no|off)$/i.test(raw);
294
+ return readConfig().allowSkipPermissions !== false;
295
+ }
@@ -1,11 +0,0 @@
1
- import "./logger-CDIsZ-Pp.js";
2
- import "./versionChecker-D5ir842c.js";
3
- import "./ts-B51ZLoJC.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-ia9b-P1k.js";
10
-
11
- export { SUPPORTED_CLIS };