@songsid/agend 2.3.0-beta.1 → 2.3.0-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 (351) hide show
  1. package/dist/agent-cli-instructions.md +5 -2
  2. package/dist/agent-cli.js +43 -7
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-endpoint.js +4 -0
  5. package/dist/agent-endpoint.js.map +1 -1
  6. package/dist/agent-file-read.d.ts +14 -6
  7. package/dist/agent-file-read.js +207 -19
  8. package/dist/agent-file-read.js.map +1 -1
  9. package/dist/agent-whats-new.d.ts +11 -0
  10. package/dist/agent-whats-new.js +29 -15
  11. package/dist/agent-whats-new.js.map +1 -1
  12. package/dist/auth-api.d.ts +30 -1
  13. package/dist/auth-api.js +45 -13
  14. package/dist/auth-api.js.map +1 -1
  15. package/dist/authority/authority-state.d.ts +38 -0
  16. package/dist/authority/authority-state.js +114 -0
  17. package/dist/authority/authority-state.js.map +1 -0
  18. package/dist/authority/session-authorizations.d.ts +43 -0
  19. package/dist/authority/session-authorizations.js +102 -0
  20. package/dist/authority/session-authorizations.js.map +1 -0
  21. package/dist/authority/web-authority.d.ts +120 -0
  22. package/dist/authority/web-authority.js +157 -0
  23. package/dist/authority/web-authority.js.map +1 -0
  24. package/dist/backend/claude-code.d.ts +2 -2
  25. package/dist/backend/claude-code.js +10 -5
  26. package/dist/backend/claude-code.js.map +1 -1
  27. package/dist/backend/types.d.ts +14 -0
  28. package/dist/backend/types.js +25 -0
  29. package/dist/backend/types.js.map +1 -1
  30. package/dist/backend-availability.d.ts +120 -0
  31. package/dist/backend-availability.js +396 -0
  32. package/dist/backend-availability.js.map +1 -0
  33. package/dist/backend-command.d.ts +21 -3
  34. package/dist/backend-command.js +23 -4
  35. package/dist/backend-command.js.map +1 -1
  36. package/dist/bundled-skills.d.ts +14 -0
  37. package/dist/bundled-skills.js +29 -0
  38. package/dist/bundled-skills.js.map +1 -0
  39. package/dist/cache-analysis.d.ts +47 -1
  40. package/dist/cache-analysis.js +68 -8
  41. package/dist/cache-analysis.js.map +1 -1
  42. package/dist/cache-ledger.d.ts +16 -3
  43. package/dist/cache-ledger.js +33 -13
  44. package/dist/cache-ledger.js.map +1 -1
  45. package/dist/cache-report-tool.d.ts +17 -0
  46. package/dist/cache-report-tool.js +40 -0
  47. package/dist/cache-report-tool.js.map +1 -0
  48. package/dist/cache-service.d.ts +70 -3
  49. package/dist/cache-service.js +178 -17
  50. package/dist/cache-service.js.map +1 -1
  51. package/dist/channel/adapters/discord.d.ts +7 -0
  52. package/dist/channel/adapters/discord.js +35 -0
  53. package/dist/channel/adapters/discord.js.map +1 -1
  54. package/dist/channel/mcp-tools.js +22 -10
  55. package/dist/channel/mcp-tools.js.map +1 -1
  56. package/dist/channel/types.d.ts +6 -0
  57. package/dist/classic-channel-manager.d.ts +10 -5
  58. package/dist/classic-channel-manager.js +12 -9
  59. package/dist/classic-channel-manager.js.map +1 -1
  60. package/dist/cli.js +130 -31
  61. package/dist/cli.js.map +1 -1
  62. package/dist/config-validator.js +103 -4
  63. package/dist/config-validator.js.map +1 -1
  64. package/dist/daemon.d.ts +7 -0
  65. package/dist/daemon.js +63 -16
  66. package/dist/daemon.js.map +1 -1
  67. package/dist/decision-list.d.ts +25 -0
  68. package/dist/decision-list.js +30 -0
  69. package/dist/decision-list.js.map +1 -0
  70. package/dist/delivery-outbox.d.ts +10 -0
  71. package/dist/delivery-outbox.js +12 -1
  72. package/dist/delivery-outbox.js.map +1 -1
  73. package/dist/fleet-context.d.ts +10 -0
  74. package/dist/fleet-manager.d.ts +417 -11
  75. package/dist/fleet-manager.js +1387 -109
  76. package/dist/fleet-manager.js.map +1 -1
  77. package/dist/fleet-traffic.d.ts +74 -0
  78. package/dist/fleet-traffic.js +196 -0
  79. package/dist/fleet-traffic.js.map +1 -0
  80. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +20 -5
  81. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +6 -1
  82. package/dist/general-knowledge/skills/multi-channel/SKILL.md +3 -2
  83. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  84. package/dist/general-knowledge/skills/web-appearance/SKILL.md +257 -23
  85. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +476 -0
  86. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  87. package/dist/human-delivery-receipts.d.ts +24 -1
  88. package/dist/human-delivery-receipts.js +64 -11
  89. package/dist/human-delivery-receipts.js.map +1 -1
  90. package/dist/instance-config-impact.js +3 -1
  91. package/dist/instance-config-impact.js.map +1 -1
  92. package/dist/instance-names.d.ts +4 -0
  93. package/dist/instance-names.js +12 -0
  94. package/dist/instance-names.js.map +1 -0
  95. package/dist/instructions.d.ts +12 -1
  96. package/dist/instructions.js +13 -2
  97. package/dist/instructions.js.map +1 -1
  98. package/dist/locale.js +100 -8
  99. package/dist/locale.js.map +1 -1
  100. package/dist/ls-attach-resolve.d.ts +95 -0
  101. package/dist/ls-attach-resolve.js +174 -0
  102. package/dist/ls-attach-resolve.js.map +1 -0
  103. package/dist/memory-hogs.d.ts +27 -0
  104. package/dist/memory-hogs.js +124 -0
  105. package/dist/memory-hogs.js.map +1 -0
  106. package/dist/outbound-handlers.d.ts +10 -0
  107. package/dist/outbound-handlers.js +122 -2
  108. package/dist/outbound-handlers.js.map +1 -1
  109. package/dist/outbound-schemas.d.ts +164 -4
  110. package/dist/outbound-schemas.js +99 -3
  111. package/dist/outbound-schemas.js.map +1 -1
  112. package/dist/public-web-gateway.js +8 -2
  113. package/dist/public-web-gateway.js.map +1 -1
  114. package/dist/public-web-link.d.ts +9 -0
  115. package/dist/public-web-link.js +8 -0
  116. package/dist/public-web-link.js.map +1 -1
  117. package/dist/quickstart-api.d.ts +10 -1
  118. package/dist/quickstart-api.js +12 -4
  119. package/dist/quickstart-api.js.map +1 -1
  120. package/dist/reply-buttons-controller.d.ts +4 -0
  121. package/dist/reply-buttons-controller.js +2 -2
  122. package/dist/reply-buttons-controller.js.map +1 -1
  123. package/dist/restart-progress.d.ts +65 -1
  124. package/dist/restart-progress.js +236 -10
  125. package/dist/restart-progress.js.map +1 -1
  126. package/dist/rollout-index.d.ts +5 -0
  127. package/dist/rollout-index.js +26 -5
  128. package/dist/rollout-index.js.map +1 -1
  129. package/dist/scheduler/scheduler.d.ts +12 -0
  130. package/dist/scheduler/scheduler.js +83 -10
  131. package/dist/scheduler/scheduler.js.map +1 -1
  132. package/dist/service-installer.d.ts +2 -1
  133. package/dist/service-installer.js +18 -3
  134. package/dist/service-installer.js.map +1 -1
  135. package/dist/settings-api.d.ts +19 -0
  136. package/dist/settings-api.js +137 -2
  137. package/dist/settings-api.js.map +1 -1
  138. package/dist/settings-change.js +104 -0
  139. package/dist/settings-change.js.map +1 -1
  140. package/dist/settings-effect.js +17 -1
  141. package/dist/settings-effect.js.map +1 -1
  142. package/dist/tmux-manager.d.ts +5 -0
  143. package/dist/tmux-manager.js +16 -0
  144. package/dist/tmux-manager.js.map +1 -1
  145. package/dist/tool-permissions.d.ts +4 -6
  146. package/dist/tool-permissions.js +53 -5
  147. package/dist/tool-permissions.js.map +1 -1
  148. package/dist/topic-commands.d.ts +7 -1
  149. package/dist/topic-commands.js +18 -4
  150. package/dist/topic-commands.js.map +1 -1
  151. package/dist/types.d.ts +48 -1
  152. package/dist/ui/app-effects.js +77 -31
  153. package/dist/ui/chat-ambient.js +307 -0
  154. package/dist/ui/chat-effect-posters.js +8 -8
  155. package/dist/ui/chat-effects.js +101 -13
  156. package/dist/ui/chat-render.js +5 -2
  157. package/dist/ui/chat-strings.js +59 -6
  158. package/dist/ui/chat-thread.js +149 -21
  159. package/dist/ui/effect-trial-controller.js +13 -8
  160. package/dist/ui/effect-trial-panel.js +19 -16
  161. package/dist/ui/fleet-cache.js +23 -1
  162. package/dist/ui/fleet-canvas-layout.js +111 -0
  163. package/dist/ui/fleet-canvas.js +525 -0
  164. package/dist/ui/fleet-org.js +27 -12
  165. package/dist/ui/fleet-traffic.js +343 -0
  166. package/dist/ui/fleet-usage.js +401 -0
  167. package/dist/ui/panel-chat.js +127 -49
  168. package/dist/ui/panel-details.js +2 -1
  169. package/dist/ui/panel-fleet.js +41 -16
  170. package/dist/ui/panel-settings.js +26 -8
  171. package/dist/ui/preview.js +3 -2
  172. package/dist/ui/settings-appearance.js +42 -18
  173. package/dist/ui/settings-catalog.js +92 -0
  174. package/dist/ui/settings-dialogs.js +40 -12
  175. package/dist/ui/settings-effects.js +4 -3
  176. package/dist/ui/settings-guests.js +117 -0
  177. package/dist/ui/settings-learn.js +25 -0
  178. package/dist/ui/settings-model.js +15 -6
  179. package/dist/ui/settings-mods.js +23 -9
  180. package/dist/ui/settings-owner-effects.js +9 -9
  181. package/dist/ui/settings-strings.js +120 -42
  182. package/dist/ui/settings-web-authority.js +91 -0
  183. package/dist/ui/shared/agend-auth.js +1 -1
  184. package/dist/ui/shared/app-i18n.js +4 -2
  185. package/dist/ui/shared/app-prefs.js +5 -4
  186. package/dist/ui/shared/app-route.js +1 -1
  187. package/dist/ui/shared/app-session.js +2 -0
  188. package/dist/ui/shared/app-shell.js +75 -9
  189. package/dist/ui/shared/app-store.js +26 -1
  190. package/dist/ui/shared/app-stream.js +3 -1
  191. package/dist/ui/shared/app-themes.js +24 -6
  192. package/dist/ui/shared/app.css +364 -16
  193. package/dist/ui/shared/app.js +21 -14
  194. package/dist/ui/shared/card-strings.js +4 -0
  195. package/dist/ui/shared/effect-app-runtime.js +68 -19
  196. package/dist/ui/shared/effect-chat-runtime.js +16 -3
  197. package/dist/ui/shared/effect-frame.js +26 -7
  198. package/dist/ui/shared/effect-geometry.js +24 -9
  199. package/dist/ui/shared/effect-policy.js +21 -7
  200. package/dist/ui/shared/effect-profiler.js +31 -9
  201. package/dist/ui/shared/effect-registry.js +87 -48
  202. package/dist/ui/shared/effect-stock-snapshot.js +9 -0
  203. package/dist/ui/shared/effect-stock-trust.js +62 -10
  204. package/dist/ui/shared/effect-trial-shadow.js +62 -0
  205. package/dist/ui/shared/effect-trial-source.js +1 -1
  206. package/dist/ui/shared/effect-trial-stage.js +54 -31
  207. package/dist/ui/shared/effect-trial.css +40 -0
  208. package/dist/ui/shared/fx-motion.js +67 -0
  209. package/dist/ui/shared/identity-card.js +75 -4
  210. package/dist/ui/shared/identity-color.js +3 -3
  211. package/dist/ui/shared/instance-nav.js +194 -28
  212. package/dist/ui/shared/panel-view.js +24 -4
  213. package/dist/ui/shared/tokens.css +9 -3
  214. package/dist/ui/shared/ui-icons.js +1 -0
  215. package/dist/ui/shared/usage-dialog.js +22 -2
  216. package/dist/ui/shared/view-strings.js +68 -2
  217. package/dist/ui/shared/web-authorize.js +151 -0
  218. package/dist/ui/signin.html +1 -1
  219. package/dist/ui/web-terminal/terminal.css +4 -4
  220. package/dist/usage/providers.d.ts +28 -0
  221. package/dist/usage/providers.js +126 -36
  222. package/dist/usage/providers.js.map +1 -1
  223. package/dist/usage-report.d.ts +158 -0
  224. package/dist/usage-report.js +226 -0
  225. package/dist/usage-report.js.map +1 -0
  226. package/dist/usage-rollup.d.ts +51 -0
  227. package/dist/usage-rollup.js +168 -0
  228. package/dist/usage-rollup.js.map +1 -0
  229. package/dist/view-api.d.ts +39 -0
  230. package/dist/view-api.js +65 -4
  231. package/dist/view-api.js.map +1 -1
  232. package/dist/web-ambient.d.ts +72 -0
  233. package/dist/web-ambient.js +161 -0
  234. package/dist/web-ambient.js.map +1 -0
  235. package/dist/web-api.d.ts +69 -5
  236. package/dist/web-api.js +362 -45
  237. package/dist/web-api.js.map +1 -1
  238. package/dist/web-appearance-policy.d.ts +4 -6
  239. package/dist/web-appearance-policy.js +5 -12
  240. package/dist/web-appearance-policy.js.map +1 -1
  241. package/dist/web-appearance-tools.d.ts +3 -0
  242. package/dist/web-appearance-tools.js +22 -3
  243. package/dist/web-appearance-tools.js.map +1 -1
  244. package/dist/web-appearance-view.d.ts +27 -2
  245. package/dist/web-appearance-view.js +129 -14
  246. package/dist/web-appearance-view.js.map +1 -1
  247. package/dist/web-appearance.d.ts +17 -3
  248. package/dist/web-appearance.js +82 -7
  249. package/dist/web-appearance.js.map +1 -1
  250. package/dist/web-asset-parts.d.ts +5 -10
  251. package/dist/web-asset-parts.js +3 -3
  252. package/dist/web-asset-parts.js.map +1 -1
  253. package/dist/web-auth.js +3 -1
  254. package/dist/web-auth.js.map +1 -1
  255. package/dist/web-card.d.ts +14 -0
  256. package/dist/web-card.js +40 -6
  257. package/dist/web-card.js.map +1 -1
  258. package/dist/web-channel-echo.d.ts +7 -1
  259. package/dist/web-channel-echo.js +6 -2
  260. package/dist/web-channel-echo.js.map +1 -1
  261. package/dist/web-chat-history.d.ts +46 -0
  262. package/dist/web-chat-history.js +80 -3
  263. package/dist/web-chat-history.js.map +1 -1
  264. package/dist/web-commands.d.ts +1 -0
  265. package/dist/web-effect-bootstrap.d.ts +12 -0
  266. package/dist/web-effect-bootstrap.js +49 -0
  267. package/dist/web-effect-bootstrap.js.map +1 -0
  268. package/dist/web-effect-bundle.js +46 -1
  269. package/dist/web-effect-bundle.js.map +1 -1
  270. package/dist/web-effect-playback.d.ts +30 -0
  271. package/dist/web-effect-playback.js +71 -0
  272. package/dist/web-effect-playback.js.map +1 -0
  273. package/dist/web-effect-profiles.d.ts +4 -4
  274. package/dist/web-effect-service.d.ts +11 -4
  275. package/dist/web-effect-service.js +28 -5
  276. package/dist/web-effect-service.js.map +1 -1
  277. package/dist/web-effect-tools.d.ts +1 -0
  278. package/dist/web-effect-tools.js +8 -5
  279. package/dist/web-effect-tools.js.map +1 -1
  280. package/dist/web-effect-trials.d.ts +4 -4
  281. package/dist/web-effect-trials.js +6 -6
  282. package/dist/web-effect-trials.js.map +1 -1
  283. package/dist/web-effect-upload.d.ts +2 -4
  284. package/dist/web-effect-upload.js +3 -8
  285. package/dist/web-effect-upload.js.map +1 -1
  286. package/dist/web-effect-worker.d.ts +1 -1
  287. package/dist/web-effect-worker.js +2 -2
  288. package/dist/web-effect-worker.js.map +1 -1
  289. package/dist/web-effect.d.ts +14 -0
  290. package/dist/web-effect.js +21 -0
  291. package/dist/web-effect.js.map +1 -1
  292. package/dist/web-guest-access.d.ts +125 -0
  293. package/dist/web-guest-access.js +234 -0
  294. package/dist/web-guest-access.js.map +1 -0
  295. package/dist/web-guest-rooms.d.ts +82 -0
  296. package/dist/web-guest-rooms.js +135 -0
  297. package/dist/web-guest-rooms.js.map +1 -0
  298. package/dist/web-identity-color.d.ts +1 -1
  299. package/dist/web-identity-color.js +2 -2
  300. package/dist/web-identity-color.js.map +1 -1
  301. package/dist/web-identity-palette.d.ts +1 -1
  302. package/dist/web-identity-palette.js +2 -2
  303. package/dist/web-identity-palette.js.map +1 -1
  304. package/dist/web-login.d.ts +47 -0
  305. package/dist/web-login.js +115 -0
  306. package/dist/web-login.js.map +1 -1
  307. package/dist/web-mod-agent.d.ts +1 -1
  308. package/dist/web-mod-agent.js +12 -8
  309. package/dist/web-mod-agent.js.map +1 -1
  310. package/dist/web-mod-bundle.d.ts +14 -1
  311. package/dist/web-mod-bundle.js +68 -3
  312. package/dist/web-mod-bundle.js.map +1 -1
  313. package/dist/web-mod-export.d.ts +9 -0
  314. package/dist/web-mod-export.js +21 -0
  315. package/dist/web-mod-export.js.map +1 -1
  316. package/dist/web-mod-store.d.ts +7 -1
  317. package/dist/web-mod-store.js +21 -7
  318. package/dist/web-mod-store.js.map +1 -1
  319. package/dist/web-prefs.d.ts +14 -0
  320. package/dist/web-prefs.js +24 -4
  321. package/dist/web-prefs.js.map +1 -1
  322. package/dist/web-preview.d.ts +6 -2
  323. package/dist/web-preview.js +4 -2
  324. package/dist/web-preview.js.map +1 -1
  325. package/dist/web-returning-device.d.ts +41 -0
  326. package/dist/web-returning-device.js +57 -5
  327. package/dist/web-returning-device.js.map +1 -1
  328. package/dist/web-session-authorization.d.ts +132 -0
  329. package/dist/web-session-authorization.js +193 -0
  330. package/dist/web-session-authorization.js.map +1 -0
  331. package/dist/web-session.d.ts +70 -10
  332. package/dist/web-session.js +137 -22
  333. package/dist/web-session.js.map +1 -1
  334. package/dist/web-settings-patch.d.ts +49 -2
  335. package/dist/web-settings-patch.js +145 -1
  336. package/dist/web-settings-patch.js.map +1 -1
  337. package/dist/web-settings-tools.d.ts +89 -0
  338. package/dist/web-settings-tools.js +270 -0
  339. package/dist/web-settings-tools.js.map +1 -0
  340. package/dist/web-shell-routes.d.ts +1 -1
  341. package/dist/web-shell-routes.js +1 -1
  342. package/dist/web-shell-routes.js.map +1 -1
  343. package/dist/web-theme-store.d.ts +39 -0
  344. package/dist/web-theme-store.js +122 -11
  345. package/dist/web-theme-store.js.map +1 -1
  346. package/dist/web-theme.d.ts +2 -0
  347. package/dist/web-theme.js +10 -1
  348. package/dist/web-theme.js.map +1 -1
  349. package/dist/workflow-templates/default.md +1 -1
  350. package/package.json +1 -1
  351. package/templates/systemd.service.ejs +8 -0
@@ -7,7 +7,7 @@ import { Toasts } from "./ui-toast.js";
7
7
  import { ConfirmHost } from "./ui-confirm.js";
8
8
  import { ColorDialogHost } from "./identity-color.js";
9
9
  import { t, lang, setLang, onLang } from "./app-i18n.js";
10
- import { appStore, createStore, useStore } from "./app-store.js";
10
+ import { appStore, createStore, guestBadge, guestPage, useStore } from "./app-store.js";
11
11
  import { navStore } from "./app-nav.js";
12
12
  import { chatPath, viewPath, settingsPath, routeKey, NEEDS_PATH, detailsPath, fleetPath } from "./app-route.js";
13
13
  import { SessionMenu } from "./app-session.js";
@@ -39,6 +39,25 @@ let newInstanceOpener = null;
39
39
  export function setNewInstanceOpener(fn) { newInstanceOpener = fn; }
40
40
  export function requestNewInstance() { if (newInstanceOpener) newInstanceOpener(); }
41
41
 
42
+ /**
43
+ * #2074: whether this page's session may make an agent — an admin's (/auth/session's tier); a guest's create is refused.
44
+ * Asked once per page; a session that ends takes the buttons away. A display hint only: the create route decides.
45
+ */
46
+ export const canCreateStore = createStore({ value: false });
47
+ let canCreateOf = null; // the AgendAuth asked (one per page)
48
+ export function useCanCreate() {
49
+ const s = useStore(canCreateStore);
50
+ useEffect(() => {
51
+ const auth = typeof window !== "undefined" ? window.AgendAuth : undefined;
52
+ if (!auth || typeof auth.canWrite !== "function" || canCreateOf === auth) return;
53
+ canCreateOf = auth;
54
+ canCreateStore.set({ value: false });
55
+ Promise.resolve(auth.canWrite()).then((v) => { if (canCreateOf === auth && !auth.sessionEnded?.()) canCreateStore.set({ value: v === true }); }, () => {});
56
+ auth.onSessionEnd?.(() => { if (canCreateOf === auth) canCreateStore.set({ value: false }); });
57
+ }, []);
58
+ return s.value;
59
+ }
60
+
42
61
  /** An app-level dialog (New instance): rendered by the shell until closed, whatever panel is showing. */
43
62
  export function showDialog(Component, props = {}) { shellStore.set({ dialog: { Component, props } }); }
44
63
  export function closeDialog() { shellStore.set({ dialog: null }); }
@@ -247,6 +266,7 @@ export function signInHref() {
247
266
  function Sidebar({ route, onNewInstance, viewOnly }) {
248
267
  const app = useStore(appStore);
249
268
  const shell = useStore(shellStore);
269
+ const canCreate = useCanCreate();
250
270
  // #1675: the Fleet panel is "Fleet overview"'s (one current row); the "Fleet" row is current on an instance's Details.
251
271
  const on = (panel) => !!route && (panel === "fleet" ? route.panel === "details" : route.panel === panel);
252
272
  const openInstance = openInstanceOf(route);
@@ -271,6 +291,22 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
271
291
  <${SidebarResize} />
272
292
  </aside>`;
273
293
  }
294
+ // #1920 phase 3: a guest's sidebar — its own agents to pick from, who it is signed in as, and its session; no fleet,
295
+ // Needs you, View, Settings, new agent or widget (each is an admin's, and the server refuses a guest them anyway).
296
+ if (guestPage()) {
297
+ return html`<aside id="sidebar" class="sidebar" aria-label=${t("app.menu")}>
298
+ <div class="side-head" data-trust="navigation">
299
+ <a class="brand" href="/ui" onClick=${closeDrawer}>${t("app.brand")}</a>
300
+ <button type="button" class="icon-btn side-collapse" onClick=${toggleSidebar} aria-label=${narrow() ? t("app.closeMenu") : t("app.collapse")} title=${narrow() ? t("app.closeMenu") : t("app.collapse")} aria-controls="sidebar"><${Icon} name="sidebar" /></button>
301
+ </div>
302
+ <${InstanceNav} route=${route} items=${app.instances} loaded=${app.ready !== false} exec=${app.exec} awaiting=${app.awaiting} onPick=${closeDrawer} />
303
+ <div class="side-foot" data-trust="navigation">
304
+ <${GuestChip} />
305
+ <${SessionMenu} />
306
+ </div>
307
+ <${SidebarResize} />
308
+ </aside>`;
309
+ }
274
310
  // #1675: the whole fleet, on its Org chart (#1389), from anywhere — top left, so at the top of a phone's drawer too. The
275
311
  // "Fleet" row under it goes to the open instance's Details (#1523 N2); this one is the Fleet panel, any of its tabs.
276
312
  const onFleet = !!route && route.panel === "fleet";
@@ -280,13 +316,13 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
280
316
  <div class="side-head" data-trust="navigation">
281
317
  <a class="brand" href="/ui" onClick=${closeDrawer}>${t("app.brand")}</a>
282
318
  <button type="button" class="icon-btn side-collapse" onClick=${toggleSidebar} aria-label=${narrow() ? t("app.closeMenu") : t("app.collapse")} title=${narrow() ? t("app.closeMenu") : t("app.collapse")} aria-controls="sidebar"><${Icon} name="sidebar" /></button>
283
- <button type="button" class="icon-btn" onClick=${onNewInstance} aria-label=${t("app.newInstance")} title=${t("app.newInstance")}><${Icon} name="plus" /></button>
284
319
  </div>
285
320
  <nav data-trust="navigation" class="side-nav" aria-label=${t("app.menu")}>
286
321
  ${overview}
287
322
  ${navLink("needs", NEEDS_PATH, "inbox", t("app.needsNav"), needsCount)}
288
323
  ${navLink("fleet", openInstance ? detailsPath(openInstance) : "/ui/fleet", "fleet", t("app.fleet"))}
289
324
  ${navLink("view", "/view", "view", t("app.view"))}
325
+ ${canCreate && onNewInstance ? html`<button type="button" class="side-row side-new" onClick=${onNewInstance}><${Icon} name="plus" /><span class="grow">${t("app.newAgent")}</span></button>` : null}
290
326
  </nav>
291
327
  ${shell.side ? html`<${shell.side.Component} />` : html`<${InstanceNav} route=${route} items=${app.instances} loaded=${app.ready !== false}
292
328
  exec=${app.exec} awaiting=${app.awaiting} onPick=${closeDrawer} />`}
@@ -299,6 +335,17 @@ function Sidebar({ route, onNewInstance, viewOnly }) {
299
335
  </aside>`;
300
336
  }
301
337
 
338
+ /** #1920 phase 3: "Guest · <name> (<platform>)" — who this guest's page is signed in as; what a guest sees, in its title. */
339
+ const PLATFORM_NAMES = { discord: "Discord", telegram: "Telegram" };
340
+ function GuestChip() {
341
+ const { name, platform } = guestBadge();
342
+ const where = PLATFORM_NAMES[platform] || platform;
343
+ const label = name ? (where ? t("app.guestAsOn", name, where) : t("app.guestAs", name)) : t("app.guestChip");
344
+ // Inside .side-foot (a marked, stock-trusted element): no trust marker of its own — effect-stock-trust's closed inventory
345
+ // refuses any element it does not know, which would hide a guest's static effect posters (#2101 review).
346
+ return html`<p class="guest-chip" title=${t("app.guestHint")}><${Icon} name="user" size=${14} /><span class="grow">${label}</span></p>`;
347
+ }
348
+
302
349
  /** #1629 r4-4: the person's own sidebar widget (their synced preference), with the fleet's counts. */
303
350
  function SidebarWidget({ app }) {
304
351
  useStore(sidebarWidgetStore);
@@ -347,14 +394,17 @@ function PrefsPopover() {
347
394
  * The header every panel shows: ☰ (phone, or a collapsed sidebar), its title and status, then its actions. `nav`
348
395
  * (#1523 N2): an instance page's view switch — beside the title on a wide screen, a row of tabs under it on a phone.
349
396
  */
350
- export function PanelHeader({ title, sub, children, headingRef, nav }) {
397
+ export function PanelHeader({ title, sub, children, headingRef, nav, notice }) {
351
398
  const shell = useStore(shellStore);
399
+ const canCreate = useCanCreate() && !!newInstanceOpener;
352
400
  return html`<header data-trust="header" class=${`panel-head${shell.collapsed ? " collapsed" : ""}`}>
353
401
  <button type="button" id="sbOpen" class="icon-btn sb-open" onClick=${() => (narrow() ? openDrawer() : toggleSidebar())}
354
402
  aria-label=${narrow() ? t("app.openMenu") : t("app.expand")} title=${narrow() ? t("app.openMenu") : t("app.expand")} aria-controls="sidebar" aria-expanded=${shell.drawer ? "true" : "false"}><${Icon} name="menu" /></button>
403
+ ${canCreate && shell.collapsed ? html`<button type="button" class="icon-btn sb-new" onClick=${requestNewInstance} aria-label=${t("app.newAgent")} title=${t("app.newAgent")}><${Icon} name="plus" /></button>` : null}
355
404
  <div class="panel-title"><h1 ref=${headingRef} tabindex="-1">${title}</h1>${sub ? html`<div class="panel-sub">${sub}</div>` : null}</div>
356
405
  ${nav || null}
357
406
  <div class="panel-actions">${children}</div>
407
+ ${notice || null}
358
408
  </header>`;
359
409
  }
360
410
 
@@ -384,6 +434,8 @@ function BottomTabs({ route, viewOnly }) {
384
434
  ${tab(signInHref(), "user", t("app.signIn"), false)}
385
435
  </nav>`;
386
436
  }
437
+ // #1920: a guest has only its chats (the drawer lists them): no tabs to switch between.
438
+ if (guestPage()) return null;
387
439
  return html`<nav data-trust="navigation" class="tabs" aria-label=${t("app.menu")}>
388
440
  ${tab(chatHref, "chat", t("app.chat"), route && route.panel === "chat", anyAwaiting)}
389
441
  ${tab(NEEDS_PATH, "inbox", t("app.needsTab"), route && route.panel === "needs", (app.needs || []).length, t("app.needsCount", (app.needs || []).length))}
@@ -435,8 +487,21 @@ export function PendingChanges({ inline = false } = {}) {
435
487
  const { pendingChanges } = useStore(appStore);
436
488
  const list = pendingChanges || [];
437
489
  useTick(list.some(p => p.state === "pending"));
490
+ // #2168: inline (Settings' own column), a request that has just started waiting is brought into view — on a phone the
491
+ // person applied far down the list, and the card that says where to confirm it sat above the screen. Once per request.
492
+ const box = useRef(null), shown = useRef(new Set());
493
+ useEffect(() => {
494
+ if (!inline || !box.current) return;
495
+ for (const p of list) {
496
+ if (p.state !== "pending" || shown.current.has(p.id)) continue;
497
+ shown.current.add(p.id);
498
+ const card = box.current.querySelector(`[data-pending="${p.id}"]`);
499
+ const still = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
500
+ if (card && typeof card.scrollIntoView === "function") card.scrollIntoView({ block: "nearest", behavior: still ? "auto" : "smooth" });
501
+ }
502
+ });
438
503
  if (!list.length) return null;
439
- return html`<div data-trust="confirmation" class=${`pending-stack${inline ? " inline" : ""}`} role="region" aria-label=${t("app.pendingTitle")}>${list.map(p => html`<section key=${p.id} class=${`pending-card ${p.state}`} role="status">
504
+ return html`<div data-trust="confirmation" ref=${box} class=${`pending-stack${inline ? " inline" : ""}`} role="region" aria-label=${t("app.pendingTitle")}>${list.map(p => html`<section key=${p.id} data-pending=${p.id} class=${`pending-card ${p.state}`} role="status">
440
505
  <div class="pending-head"><${Icon} name=${p.state === "applied" ? "check" : p.state === "pending" || p.state === "applying" ? "clock" : "alert"} size=${16} />
441
506
  <strong>${t(`app.pending_${p.state}`)}</strong>
442
507
  ${p.state === "pending" ? html`<span class="pending-left">${t("app.pendingLeft", mmss(p.deadline - NOW()))}</span>` : null}
@@ -508,23 +573,24 @@ export function Shell({ panels, onNewInstance, viewOnly = false }) {
508
573
  vv.addEventListener("resize", onResize);
509
574
  return () => vv.removeEventListener("resize", onResize);
510
575
  }, []);
511
- const cls = ["shell", shell.collapsed ? "sb-collapsed" : "", shell.drawer ? "sb-open" : "", shell.keyboard ? "kb-open" : ""].filter(Boolean).join(" ");
576
+ const guest = guestPage(); // #1920: a guest's page — no operations, usage, pending changes or owner CSS
577
+ const cls = ["shell", shell.collapsed ? "sb-collapsed" : "", shell.drawer ? "sb-open" : "", shell.keyboard ? "kb-open" : "", guest ? "guest" : ""].filter(Boolean).join(" ");
512
578
  return html`<div class=${cls}>
513
579
  <a data-trust="navigation" class="skip" href="#main">${t("app.skip")}</a>
514
580
  <${Sidebar} route=${nav.route} onNewInstance=${onNewInstance} viewOnly=${viewOnly} />
515
581
  <div class="scrim" onClick=${closeDrawer} aria-hidden="true"></div>
516
582
  <main id="main" class="main" tabindex="-1" inert=${shell.drawer && narrow() ? true : undefined}>
517
583
  <${ConnectionLine} />
518
- ${viewOnly ? null : html`<${OperationLine} route=${nav.route} />`}
584
+ ${viewOnly || guest ? null : html`<${OperationLine} route=${nav.route} />`}
519
585
  <${Outlet} route=${nav.route} seq=${nav.seq} panels=${panels} />
520
586
  </main>
521
- <${UsageRail} route=${nav.route} />
587
+ ${guest ? null : html`<${UsageRail} route=${nav.route} />`}
522
588
  <${BottomTabs} route=${nav.route} viewOnly=${viewOnly} />
523
589
  ${shell.dialog ? html`<${shell.dialog.Component} ...${shell.dialog.props} onClose=${closeDialog} />` : null}
524
- ${viewOnly || (nav.route && nav.route.panel === "settings") ? null : html`<${PendingChanges} />`}
590
+ ${viewOnly || guest || (nav.route && nav.route.panel === "settings") ? null : html`<${PendingChanges} />`}
525
591
  <${ConfirmHost} />
526
592
  <${ColorDialogHost} />
527
- ${viewOnly ? null : html`<${OwnerCssKeepBar} />`}
593
+ ${viewOnly || guest ? null : html`<${OwnerCssKeepBar} />`}
528
594
  <${Toasts} />
529
595
  </div>`;
530
596
  }
@@ -26,6 +26,20 @@ export function createStore(initial) {
26
26
  export const appStore = createStore({ ready: false, instances: [], uptime: 0, exec: {}, awaiting: {}, connection: "connecting", needs: [], connections: null,
27
27
  hydration: "none", retryHydration: null });
28
28
 
29
+ /**
30
+ * #1920 phase 3: this page is a guest's — the server says so on <body> (data-tier="guest"). A guest sees only its own
31
+ * agents' chats: no fleet, Needs you, View, Settings, filters, commands or new agent, and nothing it may not read is asked
32
+ * for (each would be refused). The server checks every request regardless; this only keeps the page to what works.
33
+ */
34
+ export function guestPage() {
35
+ return typeof document !== "undefined" && !!document.body && document.body.dataset.tier === "guest";
36
+ }
37
+ /** Who a guest's page is signed in as: its web name and its platform (the server's, on <body>). */
38
+ export function guestBadge() {
39
+ const d = typeof document !== "undefined" && document.body ? document.body.dataset : {};
40
+ return { name: d.guestName || "", platform: d.guestPlatform || "" };
41
+ }
42
+
29
43
  /** Fold one status frame (stream or poll) into the store. */
30
44
  export function applyStatus(d) {
31
45
  if (!d || !Array.isArray(d.instances)) return;
@@ -42,7 +56,18 @@ export function applyStatus(d) {
42
56
  // #1629: the agents' themes' revision (app-themes.js re-reads them when it moves).
43
57
  themesRev: typeof d.themes_rev === "number" ? d.themes_rev : null,
44
58
  // #1685: host memory pressure slowing or holding new agents ("elevated" | "critical"), else null.
45
- hostMemory: d.host_memory === "elevated" || d.host_memory === "critical" ? d.host_memory : null });
59
+ hostMemory: d.host_memory === "elevated" || d.host_memory === "critical" ? d.host_memory : null,
60
+ // #2015: while it lasts, the largest processes in the fleet and whose they are (at most 3; anything else dropped).
61
+ hostMemoryTop: hostMemoryTop(d.host_memory_top) });
62
+ }
63
+
64
+ /** #2015: the status frame's host_memory_top, as the dashboard keeps it: well-formed entries only, at most 3. */
65
+ export function hostMemoryTop(raw) {
66
+ if (!Array.isArray(raw)) return [];
67
+ return raw.slice(0, 3).flatMap(p => p && typeof p.name === "string" && Number.isSafeInteger(p.pid) && Number.isSafeInteger(p.rssBytes) && p.rssBytes >= 0
68
+ && ["fleet", "tmux", "instance", "other"].includes(p.owner)
69
+ ? [{ name: p.name.slice(0, 64), pid: p.pid, rssBytes: p.rssBytes, owner: p.owner, ...(p.owner === "instance" && typeof p.instance === "string" ? { instance: p.instance.slice(0, 128) } : {}) }]
70
+ : []);
46
71
  }
47
72
 
48
73
  /** One "activity" event: an instance started or stopped working. */
@@ -30,7 +30,9 @@
30
30
  // - suspend()/resume(): the page is leaving (pagehide) / came back from the back-forward cache.
31
31
 
32
32
  // #1218: steps_tick — an instance's transcript moved while a Log watches it (SSE only: a poll page asks the Log itself).
33
- const EVENTS = ["status", "message", "agent_reply_live", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons", "steps_tick", "clock"];
33
+ // #1918: traffic — a message between instances moved; delegation — a task opened, or its report closed it (SSE only: the
34
+ // org canvas reads /ui/traffic when it has no stream).
35
+ const EVENTS = ["status", "message", "agent_reply_live", "delivery", "deliveries", "prompt", "prompts", "prompt_resolved", "activity", "needs", "reply_buttons", "steps_tick", "clock", "traffic", "delegation"];
34
36
  const MAX_HELD = 1000; // live events held during one catch-up read; more → read again afterwards
35
37
  const RETRY_DELAYS = [1000, 2000, 4000]; // after the first failed catch-up read; then it waits for Retry
36
38
  const POLL_LIMIT_MS = 10000; // a poll that has not answered by then counts as failed
@@ -10,8 +10,11 @@ import { t } from "./app-i18n.js";
10
10
  import { toast } from "./ui-toast.js";
11
11
  import { confirmDialog } from "./ui-confirm.js";
12
12
 
13
- /** { rev, themes: { <name>: theme }, locked: [<name>], widgets: { <name>: { <slot>: widget } } } as GET /ui/themes said (rev -1: not read yet). */
14
- export const themesStore = createStore({ rev: -1, themes: {}, locked: [], widgets: {}, shown: true });
13
+ /**
14
+ * { rev, themes: { <name>: theme }, locked: [<name>], widgets: { <name>: { <slot>: widget } }, ambient: { <name>: { loop?, click? } } }
15
+ * as GET /ui/themes said (rev -1: not read yet).
16
+ */
17
+ export const themesStore = createStore({ rev: -1, themes: {}, locked: [], widgets: {}, ambient: {}, shown: true });
15
18
  const own = (o, k) => !!o && Object.prototype.hasOwnProperty.call(o, k);
16
19
 
17
20
  const COLOR = /^#[0-9a-f]{6}$/;
@@ -30,14 +33,15 @@ function labelOk(s) {
30
33
  return n >= 1 && n <= 24;
31
34
  }
32
35
 
33
- // Public sessions cannot write host prefs. Keep their explicit switch apart from boot-cached host defaults.
36
+ // Public/guest sessions cannot write host prefs. Keep their explicit browser switch apart from boot-cached defaults.
37
+ // Keep the existing public key for compatibility; both read-only viewer surfaces share this device choice.
34
38
  const PUBLIC_FX_SHOW = "agend_public_fx_show";
35
39
  let publicFxChoice = (() => { try { const v = localStorage.getItem(PUBLIC_FX_SHOW); return v === "on" ? true : v === "off" ? false : null; } catch { return null; } })();
36
40
 
37
41
  /** Whether this page shows agents' themes now: the viewer's switch (default on), and never in safe mode. */
38
42
  export function themesShown() {
39
43
  if (safeMode()) return false;
40
- if (publicLink() && publicFxChoice !== null) return publicFxChoice;
44
+ if (localAppearanceViewer() && publicFxChoice !== null) return publicFxChoice;
41
45
  try {
42
46
  const f = prefInForce("fx.show"); // this page's choice, else the host's, else the default
43
47
  if (f) return f.value !== false;
@@ -46,7 +50,7 @@ export function themesShown() {
46
50
  }
47
51
  /** The viewer's switch (Settings → Appearance): kept with the person's preferences, and in force on this page at once. */
48
52
  export function setThemesShown(on) {
49
- if (publicLink()) {
53
+ if (localAppearanceViewer()) {
50
54
  publicFxChoice = !!on;
51
55
  try { localStorage.setItem(PUBLIC_FX_SHOW, on ? "on" : "off"); } catch { /* the in-memory choice still applies */ }
52
56
  } else savePref("fx.show", on ? null : false);
@@ -122,7 +126,8 @@ async function read(rev) {
122
126
  if (!body || typeof body !== "object") break;
123
127
  themesStore.set({ rev: typeof body.rev === "number" ? body.rev : want, themes: body.themes && typeof body.themes === "object" ? body.themes : {},
124
128
  locked: Array.isArray(body.locked) ? body.locked.filter((n) => typeof n === "string") : [],
125
- widgets: body.widgets && typeof body.widgets === "object" && !Array.isArray(body.widgets) ? body.widgets : {} });
129
+ widgets: body.widgets && typeof body.widgets === "object" && !Array.isArray(body.widgets) ? body.widgets : {},
130
+ ambient: body.ambient && typeof body.ambient === "object" && !Array.isArray(body.ambient) ? body.ambient : {} });
126
131
  if (want === wanted) break;
127
132
  }
128
133
  } finally { reading = false; }
@@ -144,6 +149,7 @@ export function startThemes() {
144
149
  }
145
150
 
146
151
  const publicLink = () => typeof document !== "undefined" && !!document.body && document.body.dataset.publicLink === "1";
152
+ const localAppearanceViewer = () => publicLink() || typeof document !== "undefined" && document.body?.dataset.tier === "guest";
147
153
 
148
154
  /** A person's Reset or Lock of an agent's theme (an admin session; never over the public link). */
149
155
  async function themeAction(name, what, body) {
@@ -169,6 +175,18 @@ async function removeWidget(name, slot) {
169
175
  else toast(t("chat.widgetRemoved", name));
170
176
  }
171
177
 
178
+ /** #2117: a person's Clear of an agent's ambient, one kind ("loop" or "click"). */
179
+ export async function clearAmbient(name, which) {
180
+ let r;
181
+ try {
182
+ const res = await fetch(`/ui/themes/${encodeURIComponent(name)}/ambient`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ which }) });
183
+ r = await res.json().catch(() => ({}));
184
+ if (!res.ok) r = { error: r && r.error ? r.error : `HTTP ${res.status}` };
185
+ } catch (err) { r = { error: err && err.message ? err.message : "network" }; }
186
+ if (r && r.error) toast(t("chat.themeFailed", r.error), false);
187
+ else toast(t("chat.ambientCleared", name));
188
+ }
189
+
172
190
  /** The chat's and Details' ⋯ entries for an agent's theme: Lock/Unlock, Reset… and its widgets' Remove — none over the public link. */
173
191
  export function themeMenuItems(name) {
174
192
  if (publicLink()) return [];