@songsid/agend 2.3.1 → 2.3.2-beta.10

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 (338) hide show
  1. package/THIRD_PARTY_NOTICES.md +40 -0
  2. package/dist/agent-cli.js +21 -2
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-endpoint.js +5 -0
  5. package/dist/agent-endpoint.js.map +1 -1
  6. package/dist/antigravity-usage-scan.d.ts +58 -0
  7. package/dist/antigravity-usage-scan.js +257 -0
  8. package/dist/antigravity-usage-scan.js.map +1 -0
  9. package/dist/antigravity-usage-worker.d.ts +1 -0
  10. package/dist/antigravity-usage-worker.js +10 -0
  11. package/dist/antigravity-usage-worker.js.map +1 -0
  12. package/dist/auth-api.js +4 -0
  13. package/dist/auth-api.js.map +1 -1
  14. package/dist/authority/authority-state.d.ts +4 -0
  15. package/dist/authority/authority-state.js +16 -10
  16. package/dist/authority/authority-state.js.map +1 -1
  17. package/dist/authority/session-authorizations.d.ts +7 -1
  18. package/dist/authority/session-authorizations.js +6 -4
  19. package/dist/authority/session-authorizations.js.map +1 -1
  20. package/dist/authority/web-authority.d.ts +19 -6
  21. package/dist/authority/web-authority.js +22 -8
  22. package/dist/authority/web-authority.js.map +1 -1
  23. package/dist/backend/kiro-identity.d.ts +64 -0
  24. package/dist/backend/kiro-identity.js +101 -0
  25. package/dist/backend/kiro-identity.js.map +1 -1
  26. package/dist/backend/kiro-retired-model.d.ts +62 -0
  27. package/dist/backend/kiro-retired-model.js +160 -0
  28. package/dist/backend/kiro-retired-model.js.map +1 -0
  29. package/dist/backend/kiro.d.ts +71 -2
  30. package/dist/backend/kiro.js +352 -11
  31. package/dist/backend/kiro.js.map +1 -1
  32. package/dist/backend/types.d.ts +59 -0
  33. package/dist/backend/types.js.map +1 -1
  34. package/dist/backend-signin-guide.d.ts +1 -0
  35. package/dist/backend-signin-guide.js +9 -0
  36. package/dist/backend-signin-guide.js.map +1 -0
  37. package/dist/backend-signin-pending.d.ts +10 -0
  38. package/dist/backend-signin-pending.js +44 -0
  39. package/dist/backend-signin-pending.js.map +1 -0
  40. package/dist/browser-backend-signins.d.ts +56 -0
  41. package/dist/browser-backend-signins.js +189 -0
  42. package/dist/browser-backend-signins.js.map +1 -0
  43. package/dist/cache-ledger.d.ts +38 -2
  44. package/dist/cache-ledger.js +133 -8
  45. package/dist/cache-ledger.js.map +1 -1
  46. package/dist/cache-prices.d.ts +2 -1
  47. package/dist/cache-prices.js +5 -2
  48. package/dist/cache-prices.js.map +1 -1
  49. package/dist/cache-service.d.ts +68 -0
  50. package/dist/cache-service.js +355 -13
  51. package/dist/cache-service.js.map +1 -1
  52. package/dist/channel/adapters/discord.d.ts +13 -0
  53. package/dist/channel/adapters/discord.js +103 -16
  54. package/dist/channel/adapters/discord.js.map +1 -1
  55. package/dist/channel/mcp-tools.js +34 -7
  56. package/dist/channel/mcp-tools.js.map +1 -1
  57. package/dist/channel/tool-router.js +2 -1
  58. package/dist/channel/tool-router.js.map +1 -1
  59. package/dist/channel/types.d.ts +11 -0
  60. package/dist/classic-channel-manager.d.ts +11 -0
  61. package/dist/classic-channel-manager.js +39 -1
  62. package/dist/classic-channel-manager.js.map +1 -1
  63. package/dist/cli.js +21 -2
  64. package/dist/cli.js.map +1 -1
  65. package/dist/config-validator.d.ts +7 -1
  66. package/dist/config-validator.js +92 -12
  67. package/dist/config-validator.js.map +1 -1
  68. package/dist/config.d.ts +19 -0
  69. package/dist/config.js +31 -1
  70. package/dist/config.js.map +1 -1
  71. package/dist/cpu-quota.d.ts +23 -0
  72. package/dist/cpu-quota.js +86 -0
  73. package/dist/cpu-quota.js.map +1 -0
  74. package/dist/daemon.d.ts +57 -3
  75. package/dist/daemon.js +330 -50
  76. package/dist/daemon.js.map +1 -1
  77. package/dist/dashboard-permissions.d.ts +20 -6
  78. package/dist/dashboard-permissions.js +58 -9
  79. package/dist/dashboard-permissions.js.map +1 -1
  80. package/dist/delivery-outbox.d.ts +12 -1
  81. package/dist/delivery-outbox.js +67 -15
  82. package/dist/delivery-outbox.js.map +1 -1
  83. package/dist/doctor.d.ts +3 -0
  84. package/dist/doctor.js +11 -1
  85. package/dist/doctor.js.map +1 -1
  86. package/dist/event-log.d.ts +5 -0
  87. package/dist/event-log.js +13 -0
  88. package/dist/event-log.js.map +1 -1
  89. package/dist/fleet-manager.d.ts +212 -0
  90. package/dist/fleet-manager.js +914 -111
  91. package/dist/fleet-manager.js.map +1 -1
  92. package/dist/fleet-process-handlers.d.ts +1 -0
  93. package/dist/fleet-process-handlers.js +9 -1
  94. package/dist/fleet-process-handlers.js.map +1 -1
  95. package/dist/forged-envelope-scan.d.ts +9 -0
  96. package/dist/forged-envelope-scan.js +30 -5
  97. package/dist/forged-envelope-scan.js.map +1 -1
  98. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +5 -2
  99. package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +14 -1
  100. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +28 -5
  101. package/dist/general-knowledge/skills/web-appearance/SKILL.md +31 -8
  102. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +138 -59
  103. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +145 -61
  104. package/dist/guest-seen-people.d.ts +38 -0
  105. package/dist/guest-seen-people.js +78 -0
  106. package/dist/guest-seen-people.js.map +1 -0
  107. package/dist/instance-config-impact.js +14 -6
  108. package/dist/instance-config-impact.js.map +1 -1
  109. package/dist/instance-lifecycle.d.ts +20 -0
  110. package/dist/instance-lifecycle.js +71 -13
  111. package/dist/instance-lifecycle.js.map +1 -1
  112. package/dist/kiro-db-reader.d.ts +5 -0
  113. package/dist/kiro-db-reader.js +18 -0
  114. package/dist/kiro-db-reader.js.map +1 -1
  115. package/dist/kiro-engine-status.d.ts +2 -0
  116. package/dist/kiro-engine-status.js +9 -0
  117. package/dist/kiro-engine-status.js.map +1 -1
  118. package/dist/kiro-migrate.d.ts +49 -0
  119. package/dist/kiro-migrate.js +105 -0
  120. package/dist/kiro-migrate.js.map +1 -0
  121. package/dist/kiro-transcript-lane.d.ts +2 -0
  122. package/dist/kiro-transcript-lane.js.map +1 -1
  123. package/dist/kiro-transcript-worker.js +1 -0
  124. package/dist/kiro-transcript-worker.js.map +1 -1
  125. package/dist/kiro-tui-forensic.d.ts +7 -0
  126. package/dist/kiro-tui-forensic.js +110 -0
  127. package/dist/kiro-tui-forensic.js.map +1 -0
  128. package/dist/kiro-usage-run.d.ts +7 -0
  129. package/dist/kiro-usage-run.js +39 -0
  130. package/dist/kiro-usage-run.js.map +1 -0
  131. package/dist/kiro-usage-scan.d.ts +49 -0
  132. package/dist/kiro-usage-scan.js +223 -0
  133. package/dist/kiro-usage-scan.js.map +1 -0
  134. package/dist/kiro-usage-worker.d.ts +1 -0
  135. package/dist/kiro-usage-worker.js +10 -0
  136. package/dist/kiro-usage-worker.js.map +1 -0
  137. package/dist/kiro-usage.d.ts +58 -0
  138. package/dist/kiro-usage.js +310 -0
  139. package/dist/kiro-usage.js.map +1 -0
  140. package/dist/locale.js +120 -12
  141. package/dist/locale.js.map +1 -1
  142. package/dist/log-service.js +1 -1
  143. package/dist/log-service.js.map +1 -1
  144. package/dist/login-url.d.ts +4 -0
  145. package/dist/login-url.js +22 -0
  146. package/dist/login-url.js.map +1 -0
  147. package/dist/mac-auto-restore.d.ts +117 -0
  148. package/dist/mac-auto-restore.js +294 -0
  149. package/dist/mac-auto-restore.js.map +1 -0
  150. package/dist/needs-you-hub.d.ts +2 -1
  151. package/dist/needs-you-hub.js +1 -1
  152. package/dist/needs-you-hub.js.map +1 -1
  153. package/dist/needs-you.d.ts +8 -2
  154. package/dist/needs-you.js +6 -0
  155. package/dist/needs-you.js.map +1 -1
  156. package/dist/notice-delivery.d.ts +16 -0
  157. package/dist/notice-delivery.js +35 -0
  158. package/dist/notice-delivery.js.map +1 -0
  159. package/dist/office-share-page.d.ts +16 -0
  160. package/dist/office-share-page.js +85 -0
  161. package/dist/office-share-page.js.map +1 -0
  162. package/dist/office-share-service.d.ts +91 -0
  163. package/dist/office-share-service.js +176 -0
  164. package/dist/office-share-service.js.map +1 -0
  165. package/dist/office-share.d.ts +258 -0
  166. package/dist/office-share.js +549 -0
  167. package/dist/office-share.js.map +1 -0
  168. package/dist/opencode-usage-scan.d.ts +28 -0
  169. package/dist/opencode-usage-scan.js +92 -0
  170. package/dist/opencode-usage-scan.js.map +1 -0
  171. package/dist/opencode-usage-worker.d.ts +1 -0
  172. package/dist/opencode-usage-worker.js +10 -0
  173. package/dist/opencode-usage-worker.js.map +1 -0
  174. package/dist/outbound-handlers.js +22 -2
  175. package/dist/outbound-handlers.js.map +1 -1
  176. package/dist/outbound-schemas.d.ts +28 -2
  177. package/dist/outbound-schemas.js +29 -2
  178. package/dist/outbound-schemas.js.map +1 -1
  179. package/dist/public-web-gateway.js +16 -2
  180. package/dist/public-web-gateway.js.map +1 -1
  181. package/dist/quickstart-api.js +13 -2
  182. package/dist/quickstart-api.js.map +1 -1
  183. package/dist/quickstart.js +2 -1
  184. package/dist/quickstart.js.map +1 -1
  185. package/dist/remote-card-answer.d.ts +83 -0
  186. package/dist/remote-card-answer.js +208 -0
  187. package/dist/remote-card-answer.js.map +1 -0
  188. package/dist/reply-triggers.d.ts +2 -0
  189. package/dist/reply-triggers.js +3 -0
  190. package/dist/reply-triggers.js.map +1 -0
  191. package/dist/settings-api.d.ts +28 -0
  192. package/dist/settings-api.js +148 -17
  193. package/dist/settings-api.js.map +1 -1
  194. package/dist/settings-change.js +54 -17
  195. package/dist/settings-change.js.map +1 -1
  196. package/dist/settings-effect.js +12 -3
  197. package/dist/settings-effect.js.map +1 -1
  198. package/dist/settings-instance-patch.js +4 -1
  199. package/dist/settings-instance-patch.js.map +1 -1
  200. package/dist/setup-form.d.ts +1 -1
  201. package/dist/setup-form.js +55 -6
  202. package/dist/setup-form.js.map +1 -1
  203. package/dist/setup-host.d.ts +9 -0
  204. package/dist/setup-host.js +127 -6
  205. package/dist/setup-host.js.map +1 -1
  206. package/dist/setup-signin-assets.d.ts +2 -0
  207. package/dist/setup-signin-assets.js +6 -0
  208. package/dist/setup-signin-assets.js.map +1 -0
  209. package/dist/setup-wizard.js +2 -0
  210. package/dist/setup-wizard.js.map +1 -1
  211. package/dist/start-attempt.d.ts +9 -5
  212. package/dist/start-attempt.js +27 -8
  213. package/dist/start-attempt.js.map +1 -1
  214. package/dist/start-failure-chat.d.ts +4 -0
  215. package/dist/start-failure-chat.js +23 -6
  216. package/dist/start-failure-chat.js.map +1 -1
  217. package/dist/start-failure-notice.d.ts +4 -0
  218. package/dist/start-failure-notice.js +8 -0
  219. package/dist/start-failure-notice.js.map +1 -1
  220. package/dist/start-failure.d.ts +25 -0
  221. package/dist/start-failure.js +75 -2
  222. package/dist/start-failure.js.map +1 -1
  223. package/dist/structured-signin-transport.d.ts +8 -0
  224. package/dist/structured-signin-transport.js +79 -0
  225. package/dist/structured-signin-transport.js.map +1 -0
  226. package/dist/structured-signin.d.ts +131 -0
  227. package/dist/structured-signin.js +388 -0
  228. package/dist/structured-signin.js.map +1 -0
  229. package/dist/tool-permissions.js +12 -0
  230. package/dist/tool-permissions.js.map +1 -1
  231. package/dist/topic-commands.js +6 -2
  232. package/dist/topic-commands.js.map +1 -1
  233. package/dist/transcript-sources.d.ts +26 -2
  234. package/dist/transcript-sources.js +103 -40
  235. package/dist/transcript-sources.js.map +1 -1
  236. package/dist/turn-reply-guard.d.ts +25 -0
  237. package/dist/turn-reply-guard.js +111 -12
  238. package/dist/turn-reply-guard.js.map +1 -1
  239. package/dist/types.d.ts +46 -9
  240. package/dist/ui/backend-signin.js +68 -12
  241. package/dist/ui/chat-ambient.js +1 -1
  242. package/dist/ui/chat-effects.js +4 -4
  243. package/dist/ui/chat-render.js +5 -2
  244. package/dist/ui/chat-strings.js +4 -4
  245. package/dist/ui/chat-thread.js +2 -2
  246. package/dist/ui/first-run.js +2 -2
  247. package/dist/ui/fleet-canvas-view.js +114 -0
  248. package/dist/ui/fleet-canvas.js +15 -77
  249. package/dist/ui/fleet-office-editor.js +94 -14
  250. package/dist/ui/fleet-office-layout.js +235 -0
  251. package/dist/ui/fleet-office-model.js +12 -6
  252. package/dist/ui/fleet-office-overview.js +167 -0
  253. package/dist/ui/fleet-office-pack.d.ts +44 -0
  254. package/dist/ui/fleet-office-pack.js +352 -37
  255. package/dist/ui/fleet-office-skin.js +220 -36
  256. package/dist/ui/fleet-office-store.js +112 -7
  257. package/dist/ui/fleet-office-view.js +155 -0
  258. package/dist/ui/fleet-office-zones.js +264 -42
  259. package/dist/ui/fleet-office.js +957 -160
  260. package/dist/ui/fleet-usage.js +26 -21
  261. package/dist/ui/office-share-dialog.js +145 -0
  262. package/dist/ui/office-share-page.js +164 -0
  263. package/dist/ui/panel-chat.js +9 -2
  264. package/dist/ui/panel-details.js +2 -2
  265. package/dist/ui/panel-fleet.js +11 -77
  266. package/dist/ui/panel-log.js +4 -4
  267. package/dist/ui/panel-needs.js +4 -4
  268. package/dist/ui/panel-settings.js +608 -167
  269. package/dist/ui/search-dialog.js +26 -7
  270. package/dist/ui/settings-appearance.js +82 -29
  271. package/dist/ui/settings-apply.js +42 -7
  272. package/dist/ui/settings-dialogs.js +76 -23
  273. package/dist/ui/settings-draft.js +51 -0
  274. package/dist/ui/settings-guests.js +255 -79
  275. package/dist/ui/settings-learn.js +2 -2
  276. package/dist/ui/settings-model.js +16 -6
  277. package/dist/ui/settings-registry.js +146 -0
  278. package/dist/ui/settings-strings.js +116 -44
  279. package/dist/ui/settings-web-authority.js +34 -23
  280. package/dist/ui/shared/app-i18n.js +18 -2
  281. package/dist/ui/shared/app-nav.js +10 -5
  282. package/dist/ui/shared/app-prefs.js +80 -2
  283. package/dist/ui/shared/app-route.js +39 -5
  284. package/dist/ui/shared/app-shell.js +73 -10
  285. package/dist/ui/shared/app-stream.js +3 -1
  286. package/dist/ui/shared/app.css +307 -17
  287. package/dist/ui/shared/app.js +3 -0
  288. package/dist/ui/shared/effect-stock-trust.js +1 -1
  289. package/dist/ui/shared/identity-color.js +4 -4
  290. package/dist/ui/shared/office/cozy.png +0 -0
  291. package/dist/ui/shared/side-panel.js +95 -0
  292. package/dist/ui/shared/signin.js +2 -2
  293. package/dist/ui/shared/ui-dialog.js +6 -1
  294. package/dist/ui/shared/ui-icons.js +2 -0
  295. package/dist/ui/shared/web-authorize.js +13 -12
  296. package/dist/ui/structured-signin.js +115 -0
  297. package/dist/usage-report.d.ts +20 -0
  298. package/dist/usage-report.js +54 -17
  299. package/dist/usage-report.js.map +1 -1
  300. package/dist/usage-rollup.d.ts +9 -1
  301. package/dist/usage-rollup.js +20 -4
  302. package/dist/usage-rollup.js.map +1 -1
  303. package/dist/web-api.d.ts +26 -2
  304. package/dist/web-api.js +361 -5
  305. package/dist/web-api.js.map +1 -1
  306. package/dist/web-auth.js +8 -2
  307. package/dist/web-auth.js.map +1 -1
  308. package/dist/web-backend-login.d.ts +1 -7
  309. package/dist/web-backend-login.js +2 -24
  310. package/dist/web-backend-login.js.map +1 -1
  311. package/dist/web-experimental.d.ts +1 -1
  312. package/dist/web-experimental.js +1 -1
  313. package/dist/web-experimental.js.map +1 -1
  314. package/dist/web-mod-agent.js +2 -2
  315. package/dist/web-mod-agent.js.map +1 -1
  316. package/dist/web-office-acts.d.ts +173 -0
  317. package/dist/web-office-acts.js +285 -0
  318. package/dist/web-office-acts.js.map +1 -0
  319. package/dist/web-office-skins.d.ts +109 -0
  320. package/dist/web-office-skins.js +299 -0
  321. package/dist/web-office-skins.js.map +1 -0
  322. package/dist/web-office-store.d.ts +8 -2
  323. package/dist/web-office-store.js +77 -14
  324. package/dist/web-office-store.js.map +1 -1
  325. package/dist/web-settings-patch.d.ts +8 -1
  326. package/dist/web-settings-patch.js +65 -5
  327. package/dist/web-settings-patch.js.map +1 -1
  328. package/dist/web-shell-routes.d.ts +4 -2
  329. package/dist/web-shell-routes.js +17 -7
  330. package/dist/web-shell-routes.js.map +1 -1
  331. package/dist/working-recovery.d.ts +104 -0
  332. package/dist/working-recovery.js +298 -0
  333. package/dist/working-recovery.js.map +1 -0
  334. package/dist/working-state-journal.d.ts +5 -1
  335. package/dist/working-state-journal.js +31 -3
  336. package/dist/working-state-journal.js.map +1 -1
  337. package/package.json +3 -2
  338. package/templates/windows-shortcuts.ps1 +155 -140
@@ -1,7 +1,10 @@
1
+ import { officeInputPatch } from "./dashboard-permissions.js";
2
+ import { setNoticeMode } from "./notice-delivery.js";
3
+ import { DEFAULT_REPLY_TRIGGERS } from "./reply-triggers.js";
1
4
  import { PUBLIC_TUNNEL_SECRET_ID, PUBLIC_TUNNEL_TOKEN_HINT } from "./public-tunnel-config.js";
2
5
  import { withSpawnHoldReply } from "./spawn-hold-reply.js";
3
6
  import { normalizeSettingsInstancePatch, removesInstanceOverride } from "./settings-instance-patch.js";
4
- import { settingsRequestExecution, settingsRequestLocalAdmin, settingsWrite } from "./settings-request-capability.js";
7
+ import { isSettingsReplay, settingsRequestExecution, settingsRequestLocalAdmin, settingsWrite } from "./settings-request-capability.js";
5
8
  import { noteSettingsWrite, settingsUndo, undoSettingsPaths } from "./settings-transaction.js";
6
9
  import { readBoundedWebBody } from "./web-body.js";
7
10
  import { gatewayRequestContext } from "./web-request-context.js";
@@ -183,6 +186,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
183
186
  const path = url.pathname;
184
187
  if (!isSettingsPath(path))
185
188
  return false;
189
+ // #2667: validated with the ClassicBot rooms there are now — a guest grant naming one is not an unknown name.
190
+ const validateFleet = (config) => validateFleetConfig(config, { rooms: ctx.classicRoomNames?.() ?? [] });
186
191
  const method = req.method ?? "GET";
187
192
  // ── The page: the app shell, which mounts the Settings panel (#1408 step 3) ──
188
193
  if (isSettingsPage(path)) {
@@ -200,6 +205,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
200
205
  if (method === "GET" && path === "/api/settings/schema") {
201
206
  json(res, 200, {
202
207
  ...buildSettingsImpactSchema(),
208
+ reply_triggers_default: DEFAULT_REPLY_TRIGGERS,
203
209
  // Non-null means a restart cannot clear the fleet row, so the page shows
204
210
  // the mismatch instead of offering a button that can never succeed.
205
211
  fleet_signature_mismatch: ctx.fleetSignatureMismatchKeys?.() ?? null,
@@ -210,6 +216,12 @@ export function handleSettingsRequest(req, res, url, ctx) {
210
216
  });
211
217
  return true;
212
218
  }
219
+ // #2347: what the app-wide "Restart now" banner reads — small, so every page can ask after a Save settles.
220
+ if (method === "GET" && path === "/api/settings/restart-pending") {
221
+ const pending = ctx.settingsRestartPending?.() ?? null;
222
+ json(res, 200, pending ? { pending: true, keys: pending.keys, job_id: pending.job_id } : { pending: false });
223
+ return true;
224
+ }
213
225
  if (method === "GET" && path === "/api/settings/fleet") {
214
226
  json(res, 200, redactInlineSecrets(ctx.fleetConfig ?? {}));
215
227
  return true;
@@ -727,6 +739,60 @@ export function handleSettingsRequest(req, res, url, ctx) {
727
739
  json(res, 200, ctx.guestOverview());
728
740
  return true;
729
741
  }
742
+ // #2348: the picker's people (GET) and an admin's "Send sign-in code" (POST: a DM to an applied grant's account, once
743
+ // a minute per account — a code is not a settings change: the grant it needs was already confirmed). Never over the
744
+ // public link; the caller asked again after the body, as the sign-out below.
745
+ if (path === "/api/settings/guests/people" && method === "GET") {
746
+ if (gatewayRequestContext(req)) {
747
+ json(res, 403, { error: "guest_settings_not_over_public_link" });
748
+ return true;
749
+ }
750
+ if (!ctx.guestPeople) {
751
+ json(res, 404, { error: "not available" });
752
+ return true;
753
+ }
754
+ if (!guestSettingsCaller(req, url, ctx)) {
755
+ json(res, 401, { error: "not authorized" });
756
+ return true;
757
+ }
758
+ res.setHeader("Cache-Control", "no-store");
759
+ json(res, 200, ctx.guestPeople());
760
+ return true;
761
+ }
762
+ if (path === "/api/settings/guests/send-code" && method === "POST") {
763
+ if (gatewayRequestContext(req)) {
764
+ json(res, 403, { error: "guest_settings_not_over_public_link" });
765
+ return true;
766
+ }
767
+ if (!ctx.sendGuestCodeByAdmin) {
768
+ json(res, 404, { error: "not available" });
769
+ return true;
770
+ }
771
+ const caller = guestSettingsCaller(req, url, ctx);
772
+ if (!caller) {
773
+ json(res, 401, { error: "not authorized" });
774
+ return true;
775
+ }
776
+ readBody(req, 4096).then(async (buf) => {
777
+ if (!permitWebContinuation(req, res, ctx))
778
+ return;
779
+ if (guestSettingsCaller(req, url, ctx) !== caller)
780
+ return json(res, 401, { error: "no longer authorized" });
781
+ let body;
782
+ try {
783
+ body = JSON.parse(buf.toString("utf-8"));
784
+ }
785
+ catch {
786
+ return json(res, 400, { error: "invalid JSON" });
787
+ }
788
+ if (typeof body?.adapterId !== "string" || !body.adapterId || typeof body.userId !== "string" || !body.userId)
789
+ return json(res, 400, { error: "adapterId and userId required" });
790
+ // #2365 review: the initiating admin's session, asked again after every wait inside the issuance.
791
+ const out = await ctx.sendGuestCodeByAdmin({ adapterId: body.adapterId, userId: body.userId }, caller, () => guestSettingsCaller(req, url, ctx) === caller);
792
+ json(res, out.status, out.body);
793
+ }).catch(() => json(res, 400, { error: "bad request" }));
794
+ return true;
795
+ }
730
796
  if (path === "/api/settings/guests/revoke" && method === "POST") {
731
797
  if (gatewayRequestContext(req)) {
732
798
  json(res, 403, { error: "guest_settings_not_over_public_link" });
@@ -835,13 +901,22 @@ export function handleSettingsRequest(req, res, url, ctx) {
835
901
  }
836
902
  }
837
903
  const { session: sessionPatch, terminal: terminalPatch } = parsed;
904
+ // #2499 review: who is saving, asked now, before the save — a session policy saved with it can end this very session
905
+ // (a shorter sign-in time), and the audit must still name who did it. A confirmation's replay is no one's: null.
906
+ const auditBy = parsed.guests?.grants !== undefined && !isSettingsReplay(req) ? guestSettingsCaller(req, url, ctx) : null;
838
907
  const changes = [];
839
- const web = { ...cfg.web };
908
+ let web = { ...cfg.web };
840
909
  let webTerminal = cfg.web_terminal;
841
910
  if (parsed.canvasWorker !== undefined) {
842
911
  web.experimental = { ...web.experimental, canvas_worker: parsed.canvasWorker };
843
912
  changes.push({ path: ["web", "experimental", "canvas_worker"], value: parsed.canvasWorker });
844
913
  }
914
+ if (parsed.notifyLogin !== undefined) {
915
+ const holder = { defaults: cfg.defaults, web };
916
+ setNoticeMode(holder, "login", parsed.notifyLogin);
917
+ web = holder.web;
918
+ changes.push({ path: ["web", "notify_login"], value: web.notify_login }, { path: ["web", "notice_delivery", "login"], remove: true });
919
+ }
845
920
  if (parsed.echo !== undefined) {
846
921
  web.echo_to_channel = parsed.echo;
847
922
  changes.push({ path: ["web", "echo_to_channel"], value: parsed.echo });
@@ -890,6 +965,16 @@ export function handleSettingsRequest(req, res, url, ctx) {
890
965
  }
891
966
  // #1920 phase 3: guest sign-in (Settings → Web sign-ins → Guests); widening it is confirmed (settings-change.ts).
892
967
  if (parsed.guests) {
968
+ // #2348: a new grant names someone AgEnD has seen in chat, on a connection of this fleet, who is not a fleet admin
969
+ // (admins sign in as admins). One already granted may be edited or removed whatever the list says now.
970
+ for (const [key, grant] of Object.entries(parsed.guests.grants ?? {})) {
971
+ if (grant === null || (cfg.web?.guests?.grants && Object.hasOwn(cfg.web.guests.grants, key)))
972
+ continue;
973
+ const at = key.indexOf(":");
974
+ const refused = ctx.guestGrantRefusal ? ctx.guestGrantRefusal(key.slice(0, at), key.slice(at + 1)) : "guest grants are not available";
975
+ if (refused)
976
+ return json(res, 400, { error: refused, key: "guest_grant_refused", account: key });
977
+ }
893
978
  const applied = applyGuestsPatch(cfg.web?.guests, parsed.guests);
894
979
  if (applied.next)
895
980
  web.guests = applied.next;
@@ -908,8 +993,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
908
993
  }
909
994
  if (!changes.length)
910
995
  return json(res, 200, { ok: true });
911
- const before = validateFleetConfig(cfg);
912
- const after = validateFleetConfig({ ...cfg, web, web_terminal: webTerminal });
996
+ const before = validateFleet(cfg);
997
+ const after = validateFleet({ ...cfg, web, web_terminal: webTerminal });
913
998
  if (rejectIfWorse(res, before, after))
914
999
  return;
915
1000
  const previous = { web: cfg.web, hadWeb: "web" in cfg, terminal: cfg.web_terminal, hadTerminal: "web_terminal" in cfg };
@@ -934,6 +1019,39 @@ export function handleSettingsRequest(req, res, url, ctx) {
934
1019
  if (parsed.canvasWorker !== undefined && (previous.web?.experimental?.canvas_worker === true) !== parsed.canvasWorker) {
935
1020
  ctx.canvasWorkerSettingChanged?.();
936
1021
  }
1022
+ // #2348: a grant taken away (or emptied) ends that person's guest access now — sessions, an outstanding code, and
1023
+ // remembered browsers — not at their next request. A narrowed grant keeps its sessions; they see less from now on.
1024
+ const ended = new Map();
1025
+ for (const [key, grant] of Object.entries(parsed.guests?.grants ?? {})) {
1026
+ if (grant !== null && grant.instances.length)
1027
+ continue;
1028
+ const at = key.indexOf(":");
1029
+ try {
1030
+ ended.set(key, ctx.revokeGuestWebSessions?.({ adapterId: key.slice(0, at), userId: key.slice(at + 1) })?.count ?? 0);
1031
+ }
1032
+ catch (err) {
1033
+ ctx.logger.warn({ err }, "settings: could not end a removed guest's sessions");
1034
+ }
1035
+ }
1036
+ // #2348 delta §5: every grant change is audited, widening (confirmed in General, replayed here) or narrowing (at
1037
+ // once) alike: who, how, the agents added and taken away. Agent names only; never message content. Shown under
1038
+ // Recent changes in Settings → Guests (guestOverview), never to a guest or over the public link.
1039
+ if (parsed.guests?.grants !== undefined && ctx.noteGuestGrantChange) {
1040
+ const was = previous.web?.guests?.grants ?? {}, now = cfg.web?.guests?.grants ?? {};
1041
+ const by = auditBy, via = isSettingsReplay(req) ? "confirmed" : "direct";
1042
+ for (const key of new Set([...Object.keys(was), ...Object.keys(now)])) {
1043
+ const a = new Set(Object.hasOwn(was, key) ? was[key].instances : []), b = new Set(Object.hasOwn(now, key) ? now[key].instances : []);
1044
+ const added = [...b].filter((n) => !a.has(n)), removed = [...a].filter((n) => !b.has(n));
1045
+ if (!added.length && !removed.length)
1046
+ continue;
1047
+ try {
1048
+ ctx.noteGuestGrantChange({ by, via, account: key, added, removed, endedSessions: ended.get(key) ?? 0 });
1049
+ }
1050
+ catch (err) {
1051
+ ctx.logger.warn({ err }, "settings: could not audit a guest grant change");
1052
+ }
1053
+ }
1054
+ }
937
1055
  json(res, 200, { ok: true, warnings: saveWarnings(before, after) });
938
1056
  }).catch(() => json(res, 400, { error: "bad request" }));
939
1057
  return true;
@@ -990,8 +1108,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
990
1108
  const changes = parsed.map(c => c.value === null
991
1109
  ? { path: ["web", "appearance", c.group, c.key], value: undefined, remove: true }
992
1110
  : { path: ["web", "appearance", c.group, c.key], value: c.value });
993
- const before = validateFleetConfig(cfg);
994
- const after = validateFleetConfig({ ...cfg, web });
1111
+ const before = validateFleet(cfg);
1112
+ const after = validateFleet({ ...cfg, web });
995
1113
  if (rejectIfWorse(res, before, after))
996
1114
  return;
997
1115
  const previous = { web: cfg.web, hadWeb: "web" in cfg };
@@ -1031,7 +1149,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
1031
1149
  const restored = restoreRedactedSecrets(body, cfg.defaults);
1032
1150
  if ("path" in restored)
1033
1151
  return json(res, 400, { error: `redacted value has no stored credential: defaults.${restored.path}` });
1034
- const merged = { ...cfg.defaults, ...restored.value };
1152
+ const merged = { ...cfg.defaults, ...officeInputPatch(restored.value) };
1035
1153
  // #1310: locale:null means "clear the key" (user chose Auto). Mirrors
1036
1154
  // how the instance save handles model ("" → delete) and nullable overrides.
1037
1155
  if (body.locale === null || body.locale === "")
@@ -1039,11 +1157,16 @@ export function handleSettingsRequest(req, res, url, ctx) {
1039
1157
  // General → Defaults' "not set" for the tool profile: the key goes (worker for an agent, general for a General).
1040
1158
  if (body.tool_set === null || body.tool_set === "")
1041
1159
  delete merged.tool_set;
1042
- const before = validateFleetConfig(cfg);
1043
- const after = validateFleetConfig({ ...cfg, defaults: merged });
1160
+ const before = validateFleet(cfg);
1161
+ const after = validateFleet({ ...cfg, defaults: merged });
1044
1162
  if (rejectIfWorse(res, before, after))
1045
1163
  return;
1046
- settingsWrite(req, () => { cfg.defaults = merged; ctx.saveFleetConfig(); });
1164
+ settingsWrite(req, () => {
1165
+ cfg.defaults = merged;
1166
+ if (typeof body.tips === "boolean" || body.tips === "dm")
1167
+ setNoticeMode(cfg, "tips", body.tips);
1168
+ ctx.saveFleetConfig();
1169
+ });
1047
1170
  json(res, 200, { ok: true, warnings: saveWarnings(before, after) });
1048
1171
  }).catch(() => json(res, 400, { error: "bad request" }));
1049
1172
  return true;
@@ -1133,8 +1256,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
1133
1256
  }
1134
1257
  const next = { ...cfg, channels: normalizedBody };
1135
1258
  delete next.channel; // channels[] supersedes the legacy single channel
1136
- const before = validateFleetConfig(cfg);
1137
- const after = validateFleetConfig(next);
1259
+ const before = validateFleet(cfg);
1260
+ const after = validateFleet(next);
1138
1261
  if (rejectIfWorse(res, before, after))
1139
1262
  return;
1140
1263
  const previous = { channels: cfg.channels, channel: cfg.channel, hadChannel: "channel" in cfg };
@@ -1185,6 +1308,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
1185
1308
  delete merged.tool_progress;
1186
1309
  if (body.reply_completion_guard === null)
1187
1310
  delete merged.reply_completion_guard;
1311
+ if (body.reply_triggers === null)
1312
+ delete merged.reply_triggers;
1188
1313
  const before = validateClassicBotConfig(classic);
1189
1314
  const after = validateClassicBotConfig({ ...classic, defaults: merged });
1190
1315
  if (rejectIfWorse(res, before, after))
@@ -1234,6 +1359,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
1234
1359
  "model",
1235
1360
  "auto_pause_after",
1236
1361
  "collab",
1362
+ "reply_triggers",
1237
1363
  "context_lines",
1238
1364
  "tool_progress",
1239
1365
  "reply_completion_guard",
@@ -1251,6 +1377,9 @@ export function handleSettingsRequest(req, res, url, ctx) {
1251
1377
  && (typeof body.auto_pause_after !== "number" || !Number.isFinite(body.auto_pause_after) || body.auto_pause_after < 0)) {
1252
1378
  return json(res, 400, { error: "auto_pause_after must be a non-negative finite number" });
1253
1379
  }
1380
+ if (body.reply_triggers !== undefined && body.reply_triggers !== null && typeof body.reply_triggers !== "boolean") {
1381
+ return json(res, 400, { error: "reply_triggers must be a boolean" });
1382
+ }
1254
1383
  if (body.collab !== undefined && typeof body.collab !== "boolean")
1255
1384
  return json(res, 400, { error: "collab must be a boolean" });
1256
1385
  if (body.context_lines !== undefined && (!Number.isInteger(body.context_lines) || body.context_lines < 0)) {
@@ -1290,6 +1419,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
1290
1419
  delete merged.tool_progress;
1291
1420
  if (body.reply_completion_guard === null)
1292
1421
  delete merged.reply_completion_guard;
1422
+ if (body.reply_triggers === null)
1423
+ delete merged.reply_triggers;
1293
1424
  channels[key] = merged;
1294
1425
  const before = validateClassicBotConfig(previous);
1295
1426
  const after = validateClassicBotConfig(classic);
@@ -1509,7 +1640,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
1509
1640
  json(res, 400, { error: `redacted value has no stored credential: instances.${name}.${restored.path}` });
1510
1641
  return;
1511
1642
  }
1512
- const patch = restored.value;
1643
+ const patch = officeInputPatch(restored.value);
1513
1644
  let mergedInst;
1514
1645
  try {
1515
1646
  mergedInst = normalizeSettingsInstancePatch(base, patch);
@@ -1518,8 +1649,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
1518
1649
  json(res, 400, { error: "unsupported_instance_null" });
1519
1650
  return;
1520
1651
  }
1521
- const before = validateFleetConfig(cfg);
1522
- const after = validateFleetConfig({ ...cfg, instances: { ...cfg.instances, [name]: mergedInst } });
1652
+ const before = validateFleet(cfg);
1653
+ const after = validateFleet({ ...cfg, instances: { ...cfg.instances, [name]: mergedInst } });
1523
1654
  if (rejectIfWorse(res, before, after))
1524
1655
  return;
1525
1656
  settingsWrite(req, () => {
@@ -1579,7 +1710,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
1579
1710
  // Settings → Agents → Delete, confirmed: the same removal as delete_instance — the agent stops, nothing of it is
1580
1711
  // left behind (schedules, team places), and its fleet.yaml entry goes.
1581
1712
  const execution = settingsRequestExecution(req), authorization = authorizeExplicitInstanceRemoval("dashboard-confirmed");
1582
- (execution ? ctx.removeInstance(name, authorization, execution) : ctx.removeInstance(name, authorization)).then(() => json(res, 200, { ok: true, deleted: name, warnings: validateFleetConfig(cfg).warnings }), (err) => json(res, 500, { error: err.message }));
1713
+ (execution ? ctx.removeInstance(name, authorization, execution) : ctx.removeInstance(name, authorization)).then(() => json(res, 200, { ok: true, deleted: name, warnings: validateFleet(cfg).warnings }), (err) => json(res, 500, { error: err.message }));
1583
1714
  return true;
1584
1715
  }
1585
1716
  // DELETE never blocks on validation; surface any resulting warnings.
@@ -1588,7 +1719,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
1588
1719
  clearPausedMarker(join(ctx.dataDir, "instances", name));
1589
1720
  ctx.saveFleetConfig();
1590
1721
  });
1591
- json(res, 200, { ok: true, warnings: validateFleetConfig(cfg).warnings });
1722
+ json(res, 200, { ok: true, warnings: validateFleet(cfg).warnings });
1592
1723
  return true;
1593
1724
  }
1594
1725
  if (method === "POST" || method === "PATCH") {