@songsid/agend 2.3.0-beta.2 → 2.3.0-beta.20

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 (502) hide show
  1. package/README.md +7 -1
  2. package/README.zh-TW.md +7 -1
  3. package/dist/agent-cli-instructions.md +9 -2
  4. package/dist/agent-cli.js +63 -2
  5. package/dist/agent-cli.js.map +1 -1
  6. package/dist/agent-endpoint.js +4 -0
  7. package/dist/agent-endpoint.js.map +1 -1
  8. package/dist/agent-file-read.d.ts +4 -1
  9. package/dist/agent-file-read.js +189 -16
  10. package/dist/agent-file-read.js.map +1 -1
  11. package/dist/agent-whats-new.d.ts +11 -0
  12. package/dist/agent-whats-new.js +29 -5
  13. package/dist/agent-whats-new.js.map +1 -1
  14. package/dist/auth-api.d.ts +30 -1
  15. package/dist/auth-api.js +45 -13
  16. package/dist/auth-api.js.map +1 -1
  17. package/dist/authority/authority-state.d.ts +38 -0
  18. package/dist/authority/authority-state.js +114 -0
  19. package/dist/authority/authority-state.js.map +1 -0
  20. package/dist/authority/session-authorizations.d.ts +43 -0
  21. package/dist/authority/session-authorizations.js +102 -0
  22. package/dist/authority/session-authorizations.js.map +1 -0
  23. package/dist/authority/web-authority.d.ts +120 -0
  24. package/dist/authority/web-authority.js +157 -0
  25. package/dist/authority/web-authority.js.map +1 -0
  26. package/dist/backend/claude-code.d.ts +2 -2
  27. package/dist/backend/claude-code.js +18 -8
  28. package/dist/backend/claude-code.js.map +1 -1
  29. package/dist/backend/codex-metadata.d.ts +8 -0
  30. package/dist/backend/codex-metadata.js +74 -17
  31. package/dist/backend/codex-metadata.js.map +1 -1
  32. package/dist/backend/codex.js +15 -2
  33. package/dist/backend/codex.js.map +1 -1
  34. package/dist/backend/credential-profile.d.ts +2 -0
  35. package/dist/backend/credential-profile.js +2 -0
  36. package/dist/backend/credential-profile.js.map +1 -1
  37. package/dist/backend/types.d.ts +6 -0
  38. package/dist/backend/types.js +15 -0
  39. package/dist/backend/types.js.map +1 -1
  40. package/dist/backend-availability.d.ts +120 -0
  41. package/dist/backend-availability.js +396 -0
  42. package/dist/backend-availability.js.map +1 -0
  43. package/dist/backend-command.d.ts +23 -3
  44. package/dist/backend-command.js +25 -4
  45. package/dist/backend-command.js.map +1 -1
  46. package/dist/bug-report-cli.d.ts +30 -0
  47. package/dist/bug-report-cli.js +138 -0
  48. package/dist/bug-report-cli.js.map +1 -0
  49. package/dist/bug-report.d.ts +47 -0
  50. package/dist/bug-report.js +136 -0
  51. package/dist/bug-report.js.map +1 -0
  52. package/dist/bundled-skills.d.ts +14 -0
  53. package/dist/bundled-skills.js +29 -0
  54. package/dist/bundled-skills.js.map +1 -0
  55. package/dist/cache-ledger.d.ts +16 -3
  56. package/dist/cache-ledger.js +33 -13
  57. package/dist/cache-ledger.js.map +1 -1
  58. package/dist/cache-service.d.ts +55 -3
  59. package/dist/cache-service.js +152 -16
  60. package/dist/cache-service.js.map +1 -1
  61. package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
  62. package/dist/channel/adapters/discord-client-retirement.js +57 -0
  63. package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
  64. package/dist/channel/adapters/discord.d.ts +9 -0
  65. package/dist/channel/adapters/discord.js +49 -4
  66. package/dist/channel/adapters/discord.js.map +1 -1
  67. package/dist/channel/mcp-tools.js +22 -11
  68. package/dist/channel/mcp-tools.js.map +1 -1
  69. package/dist/channel/types.d.ts +6 -0
  70. package/dist/classic-channel-manager.d.ts +10 -5
  71. package/dist/classic-channel-manager.js +12 -9
  72. package/dist/classic-channel-manager.js.map +1 -1
  73. package/dist/cli.js +224 -111
  74. package/dist/cli.js.map +1 -1
  75. package/dist/config-validator.d.ts +6 -0
  76. package/dist/config-validator.js +129 -3
  77. package/dist/config-validator.js.map +1 -1
  78. package/dist/config.d.ts +13 -1
  79. package/dist/config.js +14 -5
  80. package/dist/config.js.map +1 -1
  81. package/dist/cross-instance-notice.d.ts +7 -0
  82. package/dist/cross-instance-notice.js +10 -0
  83. package/dist/cross-instance-notice.js.map +1 -1
  84. package/dist/daemon.d.ts +24 -1
  85. package/dist/daemon.js +151 -19
  86. package/dist/daemon.js.map +1 -1
  87. package/dist/decision-list.d.ts +25 -0
  88. package/dist/decision-list.js +30 -0
  89. package/dist/decision-list.js.map +1 -0
  90. package/dist/delivery-outbox.d.ts +10 -0
  91. package/dist/delivery-outbox.js +17 -1
  92. package/dist/delivery-outbox.js.map +1 -1
  93. package/dist/diagnostic-redaction.d.ts +10 -0
  94. package/dist/diagnostic-redaction.js +167 -0
  95. package/dist/diagnostic-redaction.js.map +1 -0
  96. package/dist/fleet-context.d.ts +10 -0
  97. package/dist/fleet-manager.d.ts +505 -15
  98. package/dist/fleet-manager.js +1870 -204
  99. package/dist/fleet-manager.js.map +1 -1
  100. package/dist/fleet-process-handlers.d.ts +18 -0
  101. package/dist/fleet-process-handlers.js +69 -0
  102. package/dist/fleet-process-handlers.js.map +1 -0
  103. package/dist/fleet-traffic.d.ts +74 -0
  104. package/dist/fleet-traffic.js +196 -0
  105. package/dist/fleet-traffic.js.map +1 -0
  106. package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
  107. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +17 -6
  108. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +6 -1
  109. package/dist/general-knowledge/skills/fleet-config/SKILL.md +2 -0
  110. package/dist/general-knowledge/skills/multi-channel/SKILL.md +3 -2
  111. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  112. package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
  113. package/dist/general-knowledge/skills/web-appearance/SKILL.md +190 -47
  114. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +545 -0
  115. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  116. package/dist/human-delivery-receipts.d.ts +24 -1
  117. package/dist/human-delivery-receipts.js +64 -11
  118. package/dist/human-delivery-receipts.js.map +1 -1
  119. package/dist/instance-config-impact.js +7 -1
  120. package/dist/instance-config-impact.js.map +1 -1
  121. package/dist/instance-lifecycle.d.ts +10 -1
  122. package/dist/instance-lifecycle.js +79 -18
  123. package/dist/instance-lifecycle.js.map +1 -1
  124. package/dist/instance-names.d.ts +4 -0
  125. package/dist/instance-names.js +12 -0
  126. package/dist/instance-names.js.map +1 -0
  127. package/dist/instructions.d.ts +12 -1
  128. package/dist/instructions.js +13 -2
  129. package/dist/instructions.js.map +1 -1
  130. package/dist/locale.js +173 -12
  131. package/dist/locale.js.map +1 -1
  132. package/dist/log-steps.d.ts +1 -0
  133. package/dist/log-steps.js +15 -0
  134. package/dist/log-steps.js.map +1 -1
  135. package/dist/login-controller.d.ts +45 -0
  136. package/dist/login-controller.js +101 -5
  137. package/dist/login-controller.js.map +1 -1
  138. package/dist/ls-attach-resolve.d.ts +96 -0
  139. package/dist/ls-attach-resolve.js +180 -0
  140. package/dist/ls-attach-resolve.js.map +1 -0
  141. package/dist/ls-rows.d.ts +12 -0
  142. package/dist/ls-rows.js +82 -3
  143. package/dist/ls-rows.js.map +1 -1
  144. package/dist/memory-hogs.d.ts +27 -0
  145. package/dist/memory-hogs.js +124 -0
  146. package/dist/memory-hogs.js.map +1 -0
  147. package/dist/needs-you.d.ts +10 -0
  148. package/dist/needs-you.js +2 -1
  149. package/dist/needs-you.js.map +1 -1
  150. package/dist/outbound-handlers.d.ts +11 -0
  151. package/dist/outbound-handlers.js +139 -11
  152. package/dist/outbound-handlers.js.map +1 -1
  153. package/dist/outbound-schemas.d.ts +200 -4
  154. package/dist/outbound-schemas.js +124 -11
  155. package/dist/outbound-schemas.js.map +1 -1
  156. package/dist/public-web-gateway.js +17 -4
  157. package/dist/public-web-gateway.js.map +1 -1
  158. package/dist/public-web-link.d.ts +9 -0
  159. package/dist/public-web-link.js +8 -0
  160. package/dist/public-web-link.js.map +1 -1
  161. package/dist/quickstart-api.d.ts +19 -1
  162. package/dist/quickstart-api.js +94 -4
  163. package/dist/quickstart-api.js.map +1 -1
  164. package/dist/reply-buttons-controller.d.ts +4 -0
  165. package/dist/reply-buttons-controller.js +2 -2
  166. package/dist/reply-buttons-controller.js.map +1 -1
  167. package/dist/restart-progress.d.ts +80 -1
  168. package/dist/restart-progress.js +306 -21
  169. package/dist/restart-progress.js.map +1 -1
  170. package/dist/rollout-index.d.ts +5 -0
  171. package/dist/rollout-index.js +26 -5
  172. package/dist/rollout-index.js.map +1 -1
  173. package/dist/scheduler/db.d.ts +40 -13
  174. package/dist/scheduler/db.js +123 -89
  175. package/dist/scheduler/db.js.map +1 -1
  176. package/dist/scheduler/task-board-text.d.ts +26 -0
  177. package/dist/scheduler/task-board-text.js +135 -0
  178. package/dist/scheduler/task-board-text.js.map +1 -0
  179. package/dist/scheduler/task-board.d.ts +650 -0
  180. package/dist/scheduler/task-board.js +1938 -0
  181. package/dist/scheduler/task-board.js.map +1 -0
  182. package/dist/scheduler/types.d.ts +6 -1
  183. package/dist/search/search-docs.d.ts +58 -0
  184. package/dist/search/search-docs.js +63 -0
  185. package/dist/search/search-docs.js.map +1 -0
  186. package/dist/search/search-index.d.ts +141 -0
  187. package/dist/search/search-index.js +440 -0
  188. package/dist/search/search-index.js.map +1 -0
  189. package/dist/search/search-store.d.ts +122 -0
  190. package/dist/search/search-store.js +236 -0
  191. package/dist/search/search-store.js.map +1 -0
  192. package/dist/search/search-worker.d.ts +1 -0
  193. package/dist/search/search-worker.js +163 -0
  194. package/dist/search/search-worker.js.map +1 -0
  195. package/dist/service-installer.js +12 -0
  196. package/dist/service-installer.js.map +1 -1
  197. package/dist/settings-api.d.ts +23 -0
  198. package/dist/settings-api.js +164 -3
  199. package/dist/settings-api.js.map +1 -1
  200. package/dist/settings-change.js +104 -0
  201. package/dist/settings-change.js.map +1 -1
  202. package/dist/settings-confirmation.d.ts +3 -1
  203. package/dist/settings-confirmation.js +2 -0
  204. package/dist/settings-confirmation.js.map +1 -1
  205. package/dist/settings-effect.js +34 -3
  206. package/dist/settings-effect.js.map +1 -1
  207. package/dist/settings-http-confirmation.d.ts +11 -0
  208. package/dist/settings-http-confirmation.js +10 -0
  209. package/dist/settings-http-confirmation.js.map +1 -1
  210. package/dist/setup-form.d.ts +1 -1
  211. package/dist/setup-form.js +23 -7
  212. package/dist/setup-form.js.map +1 -1
  213. package/dist/spawn-gate.d.ts +1 -0
  214. package/dist/spawn-gate.js +13 -3
  215. package/dist/spawn-gate.js.map +1 -1
  216. package/dist/task-board-tool.d.ts +25 -0
  217. package/dist/task-board-tool.js +154 -0
  218. package/dist/task-board-tool.js.map +1 -0
  219. package/dist/task-board-waker.d.ts +44 -0
  220. package/dist/task-board-waker.js +128 -0
  221. package/dist/task-board-waker.js.map +1 -0
  222. package/dist/tmux-exec-helper.d.ts +94 -0
  223. package/dist/tmux-exec-helper.js +407 -0
  224. package/dist/tmux-exec-helper.js.map +1 -0
  225. package/dist/tmux-manager.d.ts +5 -0
  226. package/dist/tmux-manager.js +42 -11
  227. package/dist/tmux-manager.js.map +1 -1
  228. package/dist/tool-permissions.d.ts +0 -7
  229. package/dist/tool-permissions.js +44 -5
  230. package/dist/tool-permissions.js.map +1 -1
  231. package/dist/topic-commands.d.ts +17 -1
  232. package/dist/topic-commands.js +45 -19
  233. package/dist/topic-commands.js.map +1 -1
  234. package/dist/tunnel/cloudflared.js +37 -2
  235. package/dist/tunnel/cloudflared.js.map +1 -1
  236. package/dist/tunnel/types.d.ts +3 -1
  237. package/dist/tunnel/types.js.map +1 -1
  238. package/dist/types.d.ts +63 -1
  239. package/dist/ui/app-effects.js +90 -32
  240. package/dist/ui/backend-signin.js +297 -0
  241. package/dist/ui/chat-ambient.js +307 -0
  242. package/dist/ui/chat-effect-posters.js +8 -8
  243. package/dist/ui/chat-effects.js +110 -15
  244. package/dist/ui/chat-msg-actions.js +176 -0
  245. package/dist/ui/chat-render.js +21 -3
  246. package/dist/ui/chat-store.js +64 -12
  247. package/dist/ui/chat-strings.js +85 -8
  248. package/dist/ui/chat-thread.js +204 -21
  249. package/dist/ui/effect-trial-controller.js +13 -8
  250. package/dist/ui/effect-trial-panel.js +19 -16
  251. package/dist/ui/effects-waker.js +70 -0
  252. package/dist/ui/fleet-canvas-layout.js +117 -0
  253. package/dist/ui/fleet-canvas.js +555 -0
  254. package/dist/ui/fleet-org.js +27 -12
  255. package/dist/ui/fleet-route-scene.js +207 -0
  256. package/dist/ui/fleet-route-worker.js +21 -0
  257. package/dist/ui/fleet-route.js +88 -0
  258. package/dist/ui/fleet-task-card.js +436 -0
  259. package/dist/ui/fleet-task-common.js +448 -0
  260. package/dist/ui/fleet-tasks.js +535 -0
  261. package/dist/ui/fleet-traffic.js +359 -0
  262. package/dist/ui/fleet-usage.js +435 -0
  263. package/dist/ui/panel-chat.js +264 -66
  264. package/dist/ui/panel-details.js +2 -1
  265. package/dist/ui/panel-fleet.js +65 -83
  266. package/dist/ui/panel-needs.js +4 -2
  267. package/dist/ui/panel-settings.js +56 -11
  268. package/dist/ui/preview.js +3 -2
  269. package/dist/ui/search-dialog.js +349 -0
  270. package/dist/ui/settings-appearance.js +44 -19
  271. package/dist/ui/settings-apply.js +3 -3
  272. package/dist/ui/settings-catalog.js +92 -0
  273. package/dist/ui/settings-confirm.js +7 -2
  274. package/dist/ui/settings-dialogs.js +40 -12
  275. package/dist/ui/settings-effects.js +4 -3
  276. package/dist/ui/settings-guests.js +117 -0
  277. package/dist/ui/settings-learn.js +25 -0
  278. package/dist/ui/settings-model.js +15 -6
  279. package/dist/ui/settings-mods.js +23 -9
  280. package/dist/ui/settings-owner-effects.js +15 -13
  281. package/dist/ui/settings-strings.js +122 -42
  282. package/dist/ui/settings-web-authority.js +91 -0
  283. package/dist/ui/shared/agend-auth.js +1 -1
  284. package/dist/ui/shared/app-i18n.js +11 -2
  285. package/dist/ui/shared/app-prefs.js +17 -4
  286. package/dist/ui/shared/app-route.js +19 -1
  287. package/dist/ui/shared/app-session.js +2 -0
  288. package/dist/ui/shared/app-shell.js +174 -30
  289. package/dist/ui/shared/app-store.js +26 -1
  290. package/dist/ui/shared/app-stream.js +5 -1
  291. package/dist/ui/shared/app-themes.js +140 -7
  292. package/dist/ui/shared/app.css +704 -20
  293. package/dist/ui/shared/app.js +26 -15
  294. package/dist/ui/shared/card-strings.js +8 -0
  295. package/dist/ui/shared/effect-app-runtime.js +68 -19
  296. package/dist/ui/shared/effect-chat-runtime.js +16 -3
  297. package/dist/ui/shared/effect-frame.js +26 -7
  298. package/dist/ui/shared/effect-geometry.js +24 -9
  299. package/dist/ui/shared/effect-owner-source.js +8 -1
  300. package/dist/ui/shared/effect-policy.js +21 -7
  301. package/dist/ui/shared/effect-profiler.js +31 -9
  302. package/dist/ui/shared/effect-registry.js +97 -50
  303. package/dist/ui/shared/effect-stock-snapshot.js +9 -0
  304. package/dist/ui/shared/effect-stock-trust.js +62 -10
  305. package/dist/ui/shared/effect-trial-shadow.js +62 -0
  306. package/dist/ui/shared/effect-trial-source.js +1 -1
  307. package/dist/ui/shared/effect-trial-stage.js +54 -31
  308. package/dist/ui/shared/effect-trial.css +40 -0
  309. package/dist/ui/shared/fx-motion.js +67 -0
  310. package/dist/ui/shared/identity-card.js +100 -11
  311. package/dist/ui/shared/identity-color.js +14 -10
  312. package/dist/ui/shared/instance-nav.js +179 -23
  313. package/dist/ui/shared/owner-css.js +30 -1
  314. package/dist/ui/shared/panel-view.js +24 -4
  315. package/dist/ui/shared/tokens.css +9 -3
  316. package/dist/ui/shared/ui-icons.js +2 -0
  317. package/dist/ui/shared/ui-menu.js +20 -7
  318. package/dist/ui/shared/ui-toast.js +16 -3
  319. package/dist/ui/shared/usage-dialog.js +34 -3
  320. package/dist/ui/shared/view-strings.js +72 -0
  321. package/dist/ui/shared/web-authorize.js +198 -0
  322. package/dist/ui/web-terminal/terminal.css +4 -4
  323. package/dist/ui/web-terminal/terminal.html +1 -1
  324. package/dist/update-launch.d.ts +9 -0
  325. package/dist/update-launch.js +38 -12
  326. package/dist/update-launch.js.map +1 -1
  327. package/dist/usage/format-rich.js +6 -3
  328. package/dist/usage/format-rich.js.map +1 -1
  329. package/dist/usage/i18n-keys.d.ts +1 -1
  330. package/dist/usage/i18n-keys.js +2 -1
  331. package/dist/usage/i18n-keys.js.map +1 -1
  332. package/dist/usage/i18n.d.ts +13 -1
  333. package/dist/usage/i18n.js +29 -0
  334. package/dist/usage/i18n.js.map +1 -1
  335. package/dist/usage/providers.d.ts +81 -2
  336. package/dist/usage/providers.js +240 -38
  337. package/dist/usage/providers.js.map +1 -1
  338. package/dist/usage/usage-api.d.ts +5 -1
  339. package/dist/usage/usage-api.js +184 -58
  340. package/dist/usage/usage-api.js.map +1 -1
  341. package/dist/usage-report.d.ts +158 -0
  342. package/dist/usage-report.js +226 -0
  343. package/dist/usage-report.js.map +1 -0
  344. package/dist/usage-rollup.d.ts +51 -0
  345. package/dist/usage-rollup.js +168 -0
  346. package/dist/usage-rollup.js.map +1 -0
  347. package/dist/user-systemd.d.ts +24 -0
  348. package/dist/user-systemd.js +75 -0
  349. package/dist/user-systemd.js.map +1 -0
  350. package/dist/view-api.d.ts +39 -0
  351. package/dist/view-api.js +69 -6
  352. package/dist/view-api.js.map +1 -1
  353. package/dist/web-ambient.d.ts +72 -0
  354. package/dist/web-ambient.js +161 -0
  355. package/dist/web-ambient.js.map +1 -0
  356. package/dist/web-api.d.ts +98 -14
  357. package/dist/web-api.js +1027 -83
  358. package/dist/web-api.js.map +1 -1
  359. package/dist/web-appearance-policy.d.ts +4 -6
  360. package/dist/web-appearance-policy.js +5 -12
  361. package/dist/web-appearance-policy.js.map +1 -1
  362. package/dist/web-appearance-tools.d.ts +3 -0
  363. package/dist/web-appearance-tools.js +22 -3
  364. package/dist/web-appearance-tools.js.map +1 -1
  365. package/dist/web-appearance-view.d.ts +27 -2
  366. package/dist/web-appearance-view.js +129 -14
  367. package/dist/web-appearance-view.js.map +1 -1
  368. package/dist/web-appearance.d.ts +17 -3
  369. package/dist/web-appearance.js +85 -8
  370. package/dist/web-appearance.js.map +1 -1
  371. package/dist/web-asset-parts.d.ts +2 -2
  372. package/dist/web-asset-parts.js +3 -3
  373. package/dist/web-asset-parts.js.map +1 -1
  374. package/dist/web-auth.js +3 -1
  375. package/dist/web-auth.js.map +1 -1
  376. package/dist/web-backend-login.d.ts +130 -0
  377. package/dist/web-backend-login.js +225 -0
  378. package/dist/web-backend-login.js.map +1 -0
  379. package/dist/web-card.d.ts +14 -0
  380. package/dist/web-card.js +40 -6
  381. package/dist/web-card.js.map +1 -1
  382. package/dist/web-channel-echo.d.ts +7 -1
  383. package/dist/web-channel-echo.js +6 -2
  384. package/dist/web-channel-echo.js.map +1 -1
  385. package/dist/web-chat-history.d.ts +83 -0
  386. package/dist/web-chat-history.js +137 -5
  387. package/dist/web-chat-history.js.map +1 -1
  388. package/dist/web-commands.d.ts +6 -1
  389. package/dist/web-commands.js +1 -1
  390. package/dist/web-commands.js.map +1 -1
  391. package/dist/web-effect-bootstrap.d.ts +12 -0
  392. package/dist/web-effect-bootstrap.js +49 -0
  393. package/dist/web-effect-bootstrap.js.map +1 -0
  394. package/dist/web-effect-bundle.js +46 -1
  395. package/dist/web-effect-bundle.js.map +1 -1
  396. package/dist/web-effect-playback.d.ts +30 -0
  397. package/dist/web-effect-playback.js +71 -0
  398. package/dist/web-effect-playback.js.map +1 -0
  399. package/dist/web-effect-profiles.d.ts +4 -4
  400. package/dist/web-effect-service.d.ts +11 -4
  401. package/dist/web-effect-service.js +25 -4
  402. package/dist/web-effect-service.js.map +1 -1
  403. package/dist/web-effect-tools.d.ts +1 -0
  404. package/dist/web-effect-tools.js +4 -4
  405. package/dist/web-effect-tools.js.map +1 -1
  406. package/dist/web-effect-trials.d.ts +2 -2
  407. package/dist/web-effect-trials.js +3 -3
  408. package/dist/web-effect-trials.js.map +1 -1
  409. package/dist/web-effect-upload.js +1 -1
  410. package/dist/web-effect-upload.js.map +1 -1
  411. package/dist/web-effect-worker.d.ts +1 -1
  412. package/dist/web-effect-worker.js +2 -2
  413. package/dist/web-effect-worker.js.map +1 -1
  414. package/dist/web-effect.d.ts +1 -1
  415. package/dist/web-guest-access.d.ts +126 -0
  416. package/dist/web-guest-access.js +238 -0
  417. package/dist/web-guest-access.js.map +1 -0
  418. package/dist/web-guest-rooms.d.ts +82 -0
  419. package/dist/web-guest-rooms.js +135 -0
  420. package/dist/web-guest-rooms.js.map +1 -0
  421. package/dist/web-host-guard.d.ts +11 -0
  422. package/dist/web-host-guard.js +11 -0
  423. package/dist/web-host-guard.js.map +1 -1
  424. package/dist/web-identity-color.d.ts +1 -1
  425. package/dist/web-identity-color.js +2 -2
  426. package/dist/web-identity-color.js.map +1 -1
  427. package/dist/web-identity-palette.d.ts +1 -1
  428. package/dist/web-identity-palette.js +2 -2
  429. package/dist/web-identity-palette.js.map +1 -1
  430. package/dist/web-image-meta.d.ts +13 -0
  431. package/dist/web-image-meta.js +62 -0
  432. package/dist/web-image-meta.js.map +1 -1
  433. package/dist/web-libavoid.d.ts +14 -0
  434. package/dist/web-libavoid.js +46 -0
  435. package/dist/web-libavoid.js.map +1 -0
  436. package/dist/web-login.d.ts +47 -0
  437. package/dist/web-login.js +115 -0
  438. package/dist/web-login.js.map +1 -1
  439. package/dist/web-mod-agent.d.ts +1 -1
  440. package/dist/web-mod-agent.js +7 -5
  441. package/dist/web-mod-agent.js.map +1 -1
  442. package/dist/web-mod-bundle.d.ts +9 -1
  443. package/dist/web-mod-bundle.js +62 -3
  444. package/dist/web-mod-bundle.js.map +1 -1
  445. package/dist/web-mod-export.d.ts +9 -0
  446. package/dist/web-mod-export.js +21 -0
  447. package/dist/web-mod-export.js.map +1 -1
  448. package/dist/web-mod-store.d.ts +7 -1
  449. package/dist/web-mod-store.js +19 -6
  450. package/dist/web-mod-store.js.map +1 -1
  451. package/dist/web-owner-css-store.d.ts +44 -1
  452. package/dist/web-owner-css-store.js +70 -9
  453. package/dist/web-owner-css-store.js.map +1 -1
  454. package/dist/web-prefs.d.ts +14 -0
  455. package/dist/web-prefs.js +37 -4
  456. package/dist/web-prefs.js.map +1 -1
  457. package/dist/web-preview.d.ts +6 -2
  458. package/dist/web-preview.js +4 -2
  459. package/dist/web-preview.js.map +1 -1
  460. package/dist/web-returning-device.d.ts +41 -0
  461. package/dist/web-returning-device.js +57 -5
  462. package/dist/web-returning-device.js.map +1 -1
  463. package/dist/web-session-authorization.d.ts +132 -0
  464. package/dist/web-session-authorization.js +193 -0
  465. package/dist/web-session-authorization.js.map +1 -0
  466. package/dist/web-session.d.ts +70 -10
  467. package/dist/web-session.js +137 -22
  468. package/dist/web-session.js.map +1 -1
  469. package/dist/web-settings-patch.d.ts +49 -2
  470. package/dist/web-settings-patch.js +145 -1
  471. package/dist/web-settings-patch.js.map +1 -1
  472. package/dist/web-settings-tools.d.ts +94 -0
  473. package/dist/web-settings-tools.js +301 -0
  474. package/dist/web-settings-tools.js.map +1 -0
  475. package/dist/web-shell-routes.d.ts +1 -1
  476. package/dist/web-shell-routes.js +1 -1
  477. package/dist/web-shell-routes.js.map +1 -1
  478. package/dist/web-terminal-http.js +15 -2
  479. package/dist/web-terminal-http.js.map +1 -1
  480. package/dist/web-theme-store.d.ts +39 -0
  481. package/dist/web-theme-store.js +122 -11
  482. package/dist/web-theme-store.js.map +1 -1
  483. package/dist/web-theme.d.ts +31 -0
  484. package/dist/web-theme.js +99 -2
  485. package/dist/web-theme.js.map +1 -1
  486. package/dist/web-upload.d.ts +13 -0
  487. package/dist/web-upload.js +39 -3
  488. package/dist/web-upload.js.map +1 -1
  489. package/dist/windows-shortcuts.d.ts +78 -0
  490. package/dist/windows-shortcuts.js +203 -0
  491. package/dist/windows-shortcuts.js.map +1 -0
  492. package/dist/workflow-templates/default.md +4 -1
  493. package/dist/yaml-shared-nodes.d.ts +25 -0
  494. package/dist/yaml-shared-nodes.js +185 -0
  495. package/dist/yaml-shared-nodes.js.map +1 -0
  496. package/launcher/agend-install.cjs +553 -0
  497. package/launcher/install-admission.cjs +4 -39
  498. package/launcher/postinstall.cjs +14 -12
  499. package/package.json +4 -2
  500. package/scripts/preinstall-guard.cjs +2 -5
  501. package/templates/windows-shortcuts.ps1 +181 -0
  502. package/launcher/old-updater-note.cjs +0 -48
@@ -1,6 +1,7 @@
1
1
  /** #1629: host-issued LOCAL trial paint receipt. No authority, loader, frame factory or pool is created here. */
2
+ import { effectTrialShadow } from "./effect-trial-shadow.js";
2
3
  import { effectHostStyle } from "./effect-host-style.js";
3
- import { effectStockSnapshot } from "./effect-stock-snapshot.js";
4
+ import { effectStockSnapshot, effectStockRefusal } from "./effect-stock-snapshot.js";
4
5
  import { STOCK_EFFECT_BARRIERS } from "./effect-stock-trust.js";
5
6
  const receipts = new WeakMap(), owners = new WeakMap();
6
7
  let serial = 0;
@@ -58,11 +59,13 @@ export function effectTrialStage(receipt, expected, stock) {
58
59
  }
59
60
 
60
61
  /** Only the fixed host TrialPanel supplies these elements and a current server-run lease. Not an agent manifest. */
61
- export function createEffectTrialStage({ window: host, panel, stage, binding: raw, current, ownerCss, onStop = () => {} } = {}) {
62
+ export function createEffectTrialStage({ window: host, panel, stage, binding: raw, current, onStop = () => {} } = {}) {
62
63
  const own = binding(raw);
63
- if (!own || typeof current !== "function" || typeof ownerCss !== "function" || typeof onStop !== "function" || !host?.document || !panel || !stage || owners.has(stage)) return null;
64
- let sheet; try { sheet = effectHostStyle(host); if (!sheet || host.CSS?.supports("contain", "paint") !== true || host.CSS.supports("overflow", "clip") !== true) return null; } catch { return null; }
65
- const receipt = Object.freeze(Object.create(null)), frames = new Set(), listeners = new Set(); let dead = false, constraint = null;
64
+ if (!own || typeof current !== "function" || typeof onStop !== "function" || !host?.document || !panel || !stage || owners.has(stage)) return null;
65
+ const shell = effectTrialShadow(host, panel), hostSheet = effectHostStyle(host);
66
+ let sheet; try { sheet = shell?.sheet; if (!shell || shell.stage !== stage || !hostSheet || !sheet || host.CSS?.supports("contain", "paint") !== true || host.CSS.supports("overflow", "clip") !== true) return null; } catch { return null; }
67
+ const receipt = Object.freeze(Object.create(null)), frames = new Set(), listeners = new Set(); let dead = false, constraint = null, failure = "stage_unavailable";
68
+ const reject = reason => { failure = reason; return null; };
66
69
  const identity = Object.freeze({ key: own.key, id: own.id, instance: own.instance, generation: own.generation, serial: ++serial });
67
70
  const invalidate = reason => {
68
71
  if (dead) return; dead = true; receipts.delete(receipt); if (owners.get(stage) === receipt) owners.delete(stage);
@@ -74,62 +77,81 @@ export function createEffectTrialStage({ window: host, panel, stage, binding: ra
74
77
  };
75
78
  const blur = event => { if (event.target === host) invalidate("blur"); };
76
79
  function check(stock) {
80
+ failure = "trial_layout_unverified";
77
81
  try {
78
82
  // This callback may reenter disposal or replace the owner. Recheck identity after it returns.
79
- if (dead || current(own) !== true || constraint !== null && constraint() !== true || dead || owners.get(stage) !== receipt || ownerCss() !== "off" || dead) return null;
83
+ if (dead || current(own) !== true || constraint !== null && constraint() !== true || dead || owners.get(stage) !== receipt || dead) return reject("trial_current_changed");
80
84
  const proof = effectStockSnapshot(stock), doc = host.document;
81
- if (effectHostStyle(host) !== sheet) return null;
85
+ if (!proof) return reject(effectStockRefusal(stock));
86
+ if (effectHostStyle(host) !== hostSheet || effectTrialShadow(host, panel) !== shell) return reject("trial_style_unavailable");
82
87
  // The own panel MUST still suppress ordinary foreground effects. Never synthesize front:true.
83
- if (!proof || proof.front !== false || doc.visibilityState !== "visible" || doc.hasFocus?.() !== true || doc.fullscreenElement || doc.pictureInPictureElement) return null;
88
+ if (doc.hasFocus?.() !== true) return reject("trial_window_unfocused");
89
+ if (doc.visibilityState !== "visible") return reject("hidden");
90
+ if (proof.front !== false || doc.fullscreenElement || doc.pictureInPictureElement) return reject("trial_overlay_unverified");
84
91
  const split = doc.querySelector(".main > .p-chat > .chat-split");
85
92
  if (!split || doc.querySelectorAll(".main > .p-chat").length !== 1 || doc.querySelectorAll(".chat-split > .pv-panel").length !== 1
86
- || panel.parentElement !== split || panel.ownerDocument !== doc || panel.isConnected !== true || panel.className !== "pv-panel effect-trial-panel" || panel.getAttribute("data-trust") !== "preview") return null;
87
- const children = [...panel.children], names = ["effect-trial-head", "effect-trial-controls", "effect-trial-body", "effect-trial-note"];
88
- if (children.length !== names.length || children.some((el, i) => el.className !== names[i]) || children[2].children.length !== 1 || children[2].firstElementChild !== stage
89
- || stage.className !== "effect-trial-stage" || stage.ownerDocument !== doc || stage.isConnected !== true || stage.hasAttribute("tabindex") || stage.hasAttribute("contenteditable")) return null;
93
+ || panel.parentElement !== split || panel.ownerDocument !== doc || panel.isConnected !== true || panel.className !== "pv-panel effect-trial-panel" || panel.getAttribute("data-trust") !== "preview") return reject("trial_panel_unavailable");
94
+ const children = [...shell.root.children], names = ["effect-trial-style", "effect-trial-head", "effect-trial-controls", "effect-trial-body", "effect-trial-note"];
95
+ if (panel.children.length !== 0 || children.length !== names.length || children.some((el, i) => el.className !== names[i]) || children[3].children.length !== 1 || children[3].firstElementChild !== stage
96
+ || stage.className !== "effect-trial-stage" || stage.ownerDocument !== doc || stage.isConnected !== true || stage.hasAttribute("tabindex") || stage.hasAttribute("contenteditable")) return reject("trial_shadow_unverified");
97
+ for (const control of [shell.head, shell.controls, shell.close, shell.stop, shell.note]) {
98
+ const style = host.getComputedStyle(control);
99
+ if (style.display === "none" || style.visibility !== "visible" || style.opacity !== "1" || !rect(control)) return reject("trial_controls_unavailable");
100
+ }
90
101
  if ([...doc.querySelectorAll(STOCK_EFFECT_BARRIERS)].some(el => el !== panel && visible(host, el))
91
- || [...doc.querySelectorAll(".pv-panel")].some(el => el !== panel && visible(host, el))) return null;
102
+ || [...doc.querySelectorAll(".pv-panel")].some(el => el !== panel && visible(host, el))) return reject("trial_other_overlay");
92
103
  const active = doc.activeElement;
93
- if (active && active !== doc.body && active !== doc.documentElement && (active.matches("input,select,textarea,[contenteditable]") || active.isContentEditable)) return null;
104
+ if (active && active !== doc.body && active !== doc.documentElement && (active.matches("input,select,textarea,[contenteditable]") || active.isContentEditable)) return reject("trial_editable_focus");
94
105
  let el = stage, depth = 0;
95
- while (el) { const s = host.getComputedStyle(el); if (++depth > 128 || el.ownerDocument !== doc || !neutral(s) || s.opacity !== "1" || s.visibility !== "visible" || s.display === "none" || s.contain !== (el === stage ? "paint" : "none")) return null; if (el === doc.documentElement) break; el = el.parentElement; }
96
- if (el !== doc.documentElement) return null;
106
+ while (el) { const s = host.getComputedStyle(el); if (++depth > 128 || el.ownerDocument !== doc || !neutral(s) || s.opacity !== "1" || s.visibility !== "visible" || s.display === "none" || s.contain !== (el === stage ? "paint" : "none")) return reject("trial_ancestor_paint"); if (el === doc.documentElement) break; el = el.parentElement ?? (el.getRootNode?.() === shell.root ? panel : null); }
107
+ if (el !== doc.documentElement) return reject("trial_ancestor_paint");
97
108
  const s = host.getComputedStyle(stage), r = rect(stage), p = rect(panel);
98
109
  if (!r || !p || s.position !== "relative" || s.zIndex !== "0" || s.overflowX !== "clip" || s.overflowY !== "clip"
99
110
  || s.paddingLeft !== "0px" || s.paddingRight !== "0px" || s.paddingTop !== "0px" || s.paddingBottom !== "0px"
100
111
  || ["borderLeftWidth", "borderRightWidth", "borderTopWidth", "borderBottomWidth"].some(k => s[k] !== "0px") || !none(s.boxShadow) || s.outlineStyle !== "none"
101
112
  || r.x < p.x || r.y < p.y || r.x + r.width > p.x + p.width || r.y + r.height > p.y + p.height
102
- || r.x < 0 || r.y < 0 || r.x + r.width > host.innerWidth || r.y + r.height > host.innerHeight) return null;
103
- if ([...stage.children].some(child => ![...frames].some(f => f.element === child))) return null;
113
+ || r.x < 0 || r.y < 0 || r.x + r.width > host.innerWidth || r.y + r.height > host.innerHeight) return reject("trial_clip_unverified");
114
+ if ([...stage.children].some(child => ![...frames].some(f => f.element === child))) return reject("trial_frame_unknown");
104
115
  const width = Math.floor(r.width), height = Math.floor(r.height);
105
- if (width < 1 || height < 1 || width > 4096 || height > 4096 || width * height > 8388608 || dead || owners.get(stage) !== receipt) return null;
106
- if (current(own) !== true || constraint !== null && constraint() !== true || dead || owners.get(stage) !== receipt || ownerCss() !== "off" || dead || stage.isConnected !== true || panel.parentElement !== split) return null;
116
+ if (width < 1 || height < 1 || width > 4096 || height > 4096 || width * height > 8388608 || dead || owners.get(stage) !== receipt) return reject("trial_size_limit");
117
+ if (current(own) !== true || constraint !== null && constraint() !== true || dead || owners.get(stage) !== receipt || dead || stage.isConnected !== true || panel.parentElement !== split) return reject("trial_current_changed");
107
118
  return { x: r.x, y: r.y, width, height };
108
- } catch { return null; }
119
+ } catch { return reject("trial_check_failed"); }
109
120
  }
110
121
  function project(stock) {
111
- const r = check(stock); if (!r) { invalidate("stage_unavailable"); return null; }
122
+ const r = check(stock); if (!r) { invalidate(failure); return null; }
112
123
  return Object.freeze({ root: stage, rect: Object.freeze(r), identity, bind });
113
124
  }
114
125
  function bind(frame, { layer } = {}, stock) {
115
126
  if (frames.size || !["front", "behind"].includes(layer) || frame?.ownerDocument !== host.document || frame.parentElement !== stage || frame.tagName !== "IFRAME") { frame?.remove?.(); return { ok: false }; }
116
127
  // The new frame is temporarily known to this owner before the topology check; it remains hidden until sync.
117
- const token = `agend-effect-trial-${identity.serial}`; let rule, removed = false;
128
+ const token = `agend-effect-trial-${identity.serial}`; let rule, removed = false, shown = false;
118
129
  const remove = () => {
119
130
  if (removed) return; removed = true; frame.remove(); frames.delete(handle);
120
131
  try { frame.classList.remove(token); const i = [...sheet.cssRules].indexOf(rule); if (i >= 0) sheet.deleteRule(i); } catch { /* physically removed first */ }
121
132
  };
122
- const hide = () => { try { rule.style.setProperty("visibility", "hidden", "important"); if (frame.isConnected && host.getComputedStyle(frame).visibility !== "hidden") remove(); } catch { remove(); } };
133
+ const hide = () => {
134
+ shown = false;
135
+ try { rule.style.setProperty("visibility", "hidden", "important"); if (frame.isConnected && host.getComputedStyle(frame).visibility !== "hidden") { remove(); return false; } return !removed; } catch { remove(); return false; }
136
+ };
123
137
  const handle = { ok: true, element: frame, remove, hide,
124
138
  sync(proof) {
125
- hide(); const r = check(proof); if (!r || removed) { invalidate("stage_unavailable"); return false; }
139
+ const r = check(proof); if (!r || removed) { invalidate(failure); return false; }
126
140
  try {
141
+ const matches = visibility => {
142
+ const s = host.getComputedStyle(frame), actual = rect(frame);
143
+ return !!actual && s.position === "absolute" && s.visibility === visibility && s.pointerEvents === "none" && s.zIndex === "0" && s.opacity === (layer === "front" ? "0.85" : "1") && neutral(s)
144
+ && ["x", "y", "width", "height"].every(k => Math.abs(actual[k] - r[k]) < 0.02) && actual.x >= r.x && actual.y >= r.y && actual.x + actual.width <= r.x + r.width && actual.y + actual.height <= r.y + r.height
145
+ && frame.isConnected === true && frame.ownerDocument === host.document && frame.parentElement === stage && !dead && !removed && owners.get(stage) === receipt;
146
+ };
147
+ // Reprove the current stage, clipping and actual frame every tick. Hiding/revealing an
148
+ // unchanged iframe each rAF can starve Firefox's OffscreenCanvas presentation.
149
+ if (shown && matches("visible")) return true;
150
+ if (!hide()) throw Error("local hiding lost");
127
151
  for (const [k, v] of Object.entries({ left: "0px", top: "0px", width: `${r.width}px`, height: `${r.height}px` })) rule.style.setProperty(k, v, "important");
128
- const s = host.getComputedStyle(frame), actual = rect(frame);
129
- if (!actual || s.position !== "absolute" || s.visibility !== "hidden" || s.pointerEvents !== "none" || s.zIndex !== "0" || s.opacity !== (layer === "front" ? "0.85" : "1") || !neutral(s)
130
- || !["x", "y", "width", "height"].every(k => Math.abs(actual[k] - r[k]) < 0.02) || actual.x < r.x || actual.y < r.y || actual.x + actual.width > r.x + r.width || actual.y + actual.height > r.y + r.height) throw Error("local geometry lost");
131
- rule.style.setProperty("visibility", "visible", "important"); return true;
132
- } catch { invalidate("stage_unavailable"); return false; }
152
+ if (!matches("hidden")) throw Error("local geometry lost");
153
+ rule.style.setProperty("visibility", "visible", "important"); shown = true; return true;
154
+ } catch { invalidate("trial_frame_geometry"); return false; }
133
155
  },
134
156
  };
135
157
  frames.add(handle);
@@ -137,7 +159,8 @@ export function createEffectTrialStage({ window: host, panel, stage, binding: ra
137
159
  const i = sheet.insertRule(`.${token}{}`, sheet.cssRules.length); rule = sheet.cssRules[i];
138
160
  for (const [k, v] of Object.entries({ position: "absolute", visibility: "hidden", "pointer-events": "none", "z-index": "0", opacity: layer === "front" ? "0.85" : "1", border: "0px", margin: "0px", padding: "0px", "box-sizing": "border-box", "min-width": "0px", "min-height": "0px", "max-width": "none", "max-height": "none", outline: "none", "box-shadow": "none", "background-color": "transparent", animation: "none", transition: "none" })) rule.style.setProperty(k, v, "important");
139
161
  frame.classList.add(token);
140
- if (host.getComputedStyle(frame).visibility !== "hidden" || !check(stock)) throw Error("initial local hiding lost");
162
+ if (host.getComputedStyle(frame).visibility !== "hidden") throw Error("initial local hiding lost");
163
+ if (!check(stock)) { remove(); invalidate(failure); return { ok: false }; }
141
164
  } catch { remove(); invalidate("stage_unavailable"); return { ok: false }; }
142
165
  return handle;
143
166
  }
@@ -0,0 +1,40 @@
1
+ /* #2039: fixed closed-shadow Trial chrome; no inherited owner-CSS typography, parts or slots. */
2
+ :host {
3
+ all: initial !important;
4
+ box-sizing: border-box !important;
5
+ display: flex !important;
6
+ flex: 0 0 45% !important;
7
+ flex-direction: column !important;
8
+ align-self: stretch !important;
9
+ width: 45% !important;
10
+ min-width: 320px !important;
11
+ max-width: calc(100% - 368px) !important;
12
+ min-height: 0 !important;
13
+ height: auto !important;
14
+ position: relative !important;
15
+ z-index: 1 !important;
16
+ overflow: clip !important;
17
+ background: #ffffff !important;
18
+ color: #1b1b1f !important;
19
+ font: 400 16px/1.4 system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", emoji !important;
20
+ direction: ltr !important;
21
+ unicode-bidi: isolate !important;
22
+ text-align: start !important;
23
+ visibility: visible !important;
24
+ opacity: 1 !important;
25
+ }
26
+ :host([data-effect-trial-theme="dark"]) { background: #202024 !important; color: #f0f0f4 !important; }
27
+ :host::before, :host::after { all: initial !important; content: none !important; display: none !important; }
28
+ *, *::before, *::after { box-sizing: border-box; }
29
+ [hidden] { display: none !important; }
30
+ .effect-trial-head, .effect-trial-controls, .effect-trial-note { position: relative; z-index: 1; padding: 12px; margin: 0; }
31
+ .effect-trial-head { display: flex; align-items: center; gap: 8px; border-bottom: 1px solid currentColor; }
32
+ .effect-trial-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
33
+ button { appearance: auto; display: inline-block; font: inherit; color: inherit; background: transparent; border: 1px solid currentColor; border-radius: 6px; padding: 8px 12px; cursor: pointer; }
34
+ button:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
35
+ .effect-trial-body { flex: 1; min-height: 0; display: flex; padding: 12px; }
36
+ .effect-trial-stage { position: relative; z-index: 0; flex: 1; min-width: 0; min-height: 0; contain: paint; overflow: clip; padding: 0; border: 0; outline: none; box-shadow: none; }
37
+ .effect-trial-note { font-size: 14px; }
38
+ @media (max-width: 899px) {
39
+ :host { position: fixed !important; inset: 0 !important; z-index: 37 !important; width: auto !important; min-width: 0 !important; max-width: none !important; padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left) !important; }
40
+ }
@@ -0,0 +1,67 @@
1
+ // #2117 (the user's direction, hmsg-3c166c26): agents' effects play whatever the system's reduced-motion setting says,
2
+ // unless this device chose "Effects: follow the system's reduced-motion setting". One per-device switch (not synced:
3
+ // it is about this screen), shared by ambient effects and Canvas Worker effects; it also works on the public link.
4
+ export const FX_FOLLOW_REDUCED_MOTION_KEY = "agend_fx_follow_reduced_motion";
5
+ /** The one-time chat note "your system asks for reduced motion; effects are on" was shown on this device. */
6
+ export const FX_MOTION_NOTE_KEY = "agend_fx_motion_note_seen";
7
+ const listeners = new Set();
8
+ let pageChoice = null, noteShown = false;
9
+
10
+ /** Whether this device asked effects to follow the system's reduced-motion setting (default: no). */
11
+ export function followsReducedMotion() {
12
+ if (pageChoice !== null) return pageChoice;
13
+ try { return globalThis.localStorage.getItem(FX_FOLLOW_REDUCED_MOTION_KEY) === "1"; } catch { return false; }
14
+ }
15
+ export function setFollowsReducedMotion(on) {
16
+ pageChoice = !!on;
17
+ try { if (on) globalThis.localStorage.setItem(FX_FOLLOW_REDUCED_MOTION_KEY, "1"); else globalThis.localStorage.removeItem(FX_FOLLOW_REDUCED_MOTION_KEY); } catch { /* this page only */ }
18
+ for (const fn of [...listeners]) { try { fn(); } catch { /* a listener's own */ } }
19
+ }
20
+ /** `fn()` when the switch or the system's answer moves (this tab, another tab, the OS). Returns the unsubscribe. */
21
+ export function onMotionChange(fn) {
22
+ listeners.add(fn);
23
+ const onStorage = (e) => {
24
+ if (!e || e.key === FX_FOLLOW_REDUCED_MOTION_KEY || e.key === null) {
25
+ pageChoice = e?.key === FX_FOLLOW_REDUCED_MOTION_KEY ? e.newValue === "1" : null;
26
+ fn();
27
+ }
28
+ };
29
+ let q = null;
30
+ try { q = typeof globalThis.matchMedia === "function" ? globalThis.matchMedia("(prefers-reduced-motion: reduce)") : null; } catch { q = null; }
31
+ try { globalThis.addEventListener && globalThis.addEventListener("storage", onStorage); } catch { /* none */ }
32
+ try { if (q && q.addEventListener) q.addEventListener("change", fn); } catch { /* read again on the next render */ }
33
+ return () => {
34
+ listeners.delete(fn);
35
+ try { globalThis.removeEventListener && globalThis.removeEventListener("storage", onStorage); } catch { /* gone */ }
36
+ try { if (q && q.removeEventListener) q.removeEventListener("change", fn); } catch { /* gone */ }
37
+ };
38
+ }
39
+ /** Whether the system asks for reduced motion (false when it can't say: the note is only for a clear yes). */
40
+ export function systemReducesMotion(win = globalThis) {
41
+ try { return typeof win.matchMedia === "function" && win.matchMedia("(prefers-reduced-motion: reduce)").matches === true; } catch { return false; }
42
+ }
43
+ /**
44
+ * The one-time note (the user's direction): the system asks for reduced motion, this device does not follow it, and the
45
+ * note was not shown here before. Showing it marks it shown.
46
+ */
47
+ export function motionNoteDue(win = globalThis) {
48
+ if (noteShown || followsReducedMotion() || !systemReducesMotion(win)) return false;
49
+ try { return globalThis.localStorage.getItem(FX_MOTION_NOTE_KEY) !== "1"; } catch { return true; }
50
+ }
51
+ export function markMotionNoteShown() {
52
+ noteShown = true;
53
+ try { globalThis.localStorage.setItem(FX_MOTION_NOTE_KEY, "1"); } catch { /* shown again next time: harmless */ }
54
+ }
55
+
56
+ /**
57
+ * True when effects stay still here: this device follows the system's setting and the system asks for reduced motion
58
+ * (or cannot say — then still, as asked for). With the switch off (the default), never.
59
+ */
60
+ export function motionBlocked(win = globalThis) {
61
+ if (!followsReducedMotion()) return false;
62
+ try {
63
+ if (typeof win.matchMedia !== "function") return true;
64
+ const q = win.matchMedia("(prefers-reduced-motion: reduce)");
65
+ return !q || typeof q.matches !== "boolean" || q.matches;
66
+ } catch { return true; }
67
+ }
@@ -4,7 +4,8 @@
4
4
  //
5
5
  // Nothing the agent wrote is markup: the tagline and bio are text nodes (never linkified), the pictures are same-origin
6
6
  // <img> elements whose URLs are checked here again, and sizes are class tokens only (card-s | card-m | card-l, heights in
7
- // app.css) — no style attribute, no CSSOM size (#1300). The size is a viewer's choice: every card's default
7
+ // app.css) — no style attribute, no CSSOM size (#1300). #2086: the banner's focus is a position, not a size: one custom
8
+ // property set through the CSSOM (`--id-focus`), and the banner is never drawn wider than BANNER_MAX_ASPECT : 1. The size is a viewer's choice: every card's default
8
9
  // (`card.size`) and the cards set apart from it (`card.sizeByInstance`, at most 200), synced like the other preferences.
9
10
  import { html, useEffect, useState } from "./app-html.js";
10
11
  import { t } from "./app-i18n.js";
@@ -13,6 +14,28 @@ import { onPrefsChanged, prefInForce, savePref } from "./app-prefs.js";
13
14
  import "./card-strings.js";
14
15
 
15
16
  export const CARD_SIZES = ["s", "m", "l"];
17
+ /**
18
+ * #2086: the widest a banner is ever drawn (width : height) — app.css caps its width at this many times its size's
19
+ * tallest height. So the band of the picture shown everywhere is (picture's aspect ÷ this) of its height, at the focus.
20
+ */
21
+ export const BANNER_MAX_ASPECT = 5;
22
+ /**
23
+ * #2086 (#2089 review): the narrowest a card draws its banner — 9 : 4 (app.css caps a banner's height at its box's width ÷ 2.25, on
24
+ * every layout) — which crops a wide picture's sides. Every card is between this and BANNER_MAX_ASPECT, so the area shown on every screen is
25
+ * the narrowest box's width (centred) × the widest box's height (at the focus).
26
+ */
27
+ export const BANNER_MIN_ASPECT = 9 / 4;
28
+ /** The share of a picture's height a box of `boxAspect` shows (1: all of it; a narrower box crops the sides instead). */
29
+ export const bannerShownHeight = (pictureAspect, boxAspect) => Math.min(1, pictureAspect / boxAspect);
30
+ /** The share of a picture's width a box of `boxAspect` shows, centred (1: all of it). */
31
+ export const bannerShownWidth = (pictureAspect, boxAspect) => Math.min(1, boxAspect / pictureAspect);
32
+ /** The area every screen shows, as shares of the picture: { left, top, width, height } at focus `f`. */
33
+ export function bannerSafeArea(pictureAspect, f) {
34
+ const width = bannerShownWidth(pictureAspect, BANNER_MIN_ASPECT), height = bannerShownHeight(pictureAspect, BANNER_MAX_ASPECT);
35
+ return { left: (1 - width) / 2, top: bannerBandTop(height, f), width, height };
36
+ }
37
+ /** That band's top, as a share of the picture's height, at focus `f` (0–100) — object-position's own rule. */
38
+ export const bannerBandTop = (shown, f) => (1 - shown) * (f / 100);
16
39
  export const MAX_CARD_SIZES = 200;
17
40
  const own = (o, k) => !!o && Object.prototype.hasOwnProperty.call(o, k);
18
41
  const readLocal = (k) => { try { return localStorage.getItem(k); } catch { return null; } };
@@ -82,6 +105,9 @@ export function checkCard(name, body) {
82
105
  const v = body[k];
83
106
  if (v && typeof v === "object" && typeof v.text === "string" && v.text.length && v.text.length <= MAX[k] && (v.by === "human" || v.by === "agent")) out[k] = { text: v.text, by: v.by };
84
107
  }
108
+ // #2086: the banner's focus, a whole number 0 (top) … 100 (bottom).
109
+ const f = body.banner_focus;
110
+ if (f && typeof f === "object" && Number.isInteger(f.value) && f.value >= 0 && f.value <= 100 && (f.by === "human" || f.by === "agent")) out.banner_focus = { value: f.value, by: f.by };
85
111
  return Object.keys(out).length ? out : null;
86
112
  }
87
113
  // #1889 review: per instance, an epoch that moves whenever the version this page wants changes (a clear included).
@@ -135,30 +161,93 @@ function SizeControl({ name, size }) {
135
161
  }
136
162
 
137
163
  /**
138
- * The card. `compact`: the chat header's own small size (no size control). Nothing when the card is empty. The
164
+ * #2217 hotfix (Prism): pictures that failed to load on this page, by src — shared, so the chat's card menu judges a card
165
+ * as drawn (a broken banner is not drawn, and then the card cannot fold), not by its metadata alone.
166
+ */
167
+ export const brokenPictures = createStore({});
168
+ const markBroken = (src) => { if (src && !brokenPictures.get()[src]) brokenPictures.set((s) => ({ ...s, [src]: true })); };
169
+ const drawn = (card, slot) => !!(card && card[slot] && !brokenPictures.get()[card[slot].src]);
170
+ /**
171
+ * #2217: whether a card can fold its row away and keep the banner — a banner drawn, and something on its row (a picture
172
+ * drawn, a tagline or a bio). The chat's card menu enables Show picture and bio only then.
173
+ */
174
+ export const cardFoldable = (card) => !!(card && drawn(card, "banner") && (drawn(card, "portrait") || card.tagline || card.bio));
175
+
176
+ /**
177
+ * The card. `compact`: the chat header's own small size (no size control; the banner still follows the size choice,
178
+ * #2038). Nothing when the card is empty. The
139
179
  * tagline and bio say whose they are (title), since a person's field wins over the agent's.
180
+ * #2217: `rowHidden` — the chat's picture and bio folded away, the banner kept. The user (2026-10-20): no control on the
181
+ * card at all — the chat header's two buttons show / hide the card and fold / unfold its row. Only a card with a banner
182
+ * and something on its row folds (cardFoldable; else it would be the card hidden).
140
183
  */
141
- export function IdentityCard({ name, card, compact = false, sizeControl = !compact }) {
184
+ export function IdentityCard({ name, card, compact = false, sizeControl = !compact, rowHidden = false }) {
142
185
  useStore(cardSizeStore);
143
- const [broken, setBroken] = useState({});
186
+ const broken = useStore(brokenPictures);
144
187
  if (!card) return null;
145
188
  const size = compact ? "c" : cardSizeFor(name);
189
+ // #2038: the chat header's card is its own small size, but its banner follows the person's size choice too.
190
+ const bannerSize = compact ? ` bs-${cardSizeFor(name)}` : "";
146
191
  const whose = (f) => t(f.by === "human" ? "card.byHuman" : "card.byAgent");
147
- const pic = (slot, cls, alt) => card[slot] && broken[slot] !== card[slot].src
148
- ? html`<img class=${cls} src=${card[slot].src} alt=${alt} title=${whose(card[slot])} decoding="async" onError=${() => setBroken({ ...broken, [slot]: card[slot].src })} />` : null;
149
- return html`<section class=${`id-card card-${size}`} aria-label=${t("card.label", name)}>
150
- ${pic("banner", "id-banner", "")}
151
- <div class="id-row">
152
- ${pic("portrait", "id-portrait", t("card.portraitAlt", name))}
192
+ const pic = (slot, cls, alt) => card[slot] && !broken[card[slot].src]
193
+ ? html`<img class=${cls} src=${card[slot].src} alt=${alt} title=${whose(card[slot])} decoding="async" onError=${() => markBroken(card[slot].src)} />` : null;
194
+ // #2086: the banner at its focus; on a screen wider than BANNER_MAX_ASPECT it is centred over a blurred copy of itself.
195
+ const focus = card.banner_focus ? card.banner_focus.value : 50;
196
+ const atFocus = (el) => { if (el && el.style) el.style.setProperty("--id-focus", `${focus}%`); };
197
+ const banner = pic("banner", "id-banner", "");
198
+ const portrait = pic("portrait", "id-portrait", t("card.portraitAlt", name));
199
+ const rowShown = !(rowHidden && banner && cardFoldable(card));
200
+ return html`<section class=${`id-card card-${size}${bannerSize}${rowShown ? "" : " row-hidden"}`} aria-label=${t("card.label", name)}>
201
+ ${banner ? html`<div class="id-banner-box" ref=${atFocus}><img class="id-banner-fill" src=${card.banner.src} alt="" aria-hidden="true" decoding="async" />${banner}</div>` : null}
202
+ ${rowShown ? html`<div class="id-row">
203
+ ${portrait}
153
204
  <div class="id-text">
154
205
  ${card.tagline ? html`<p class="id-tagline" title=${whose(card.tagline)}>${card.tagline.text}</p>` : null}
155
206
  ${card.bio ? html`<p class="id-bio" title=${whose(card.bio)}>${card.bio.text}</p>` : null}
156
207
  </div>
157
208
  ${sizeControl ? html`<${SizeControl} name=${name} size=${size} />` : null}
158
- </div>
209
+ </div>` : null}
159
210
  </section>`;
160
211
  }
161
212
 
213
+ // ── #2086: the banner's focus, set in View's Edit profile — the whole picture, what each screen shows of it ──
214
+ /**
215
+ * #2089 review: the picture the focus preview shows — a file just chosen (a blob URL this owns: released when another is
216
+ * chosen and when the dialog closes) or the banner drawn now (a server URL, never released).
217
+ */
218
+ export function useBannerPreview() {
219
+ const [preview, setPreview] = useState(null);
220
+ useEffect(() => () => { if (preview && preview.blob) { try { URL.revokeObjectURL(preview.blob); } catch { /* already gone */ } } }, [preview]);
221
+ return [preview, {
222
+ fromFile(file) { let url = null; try { url = URL.createObjectURL(file); } catch { return; } setPreview({ src: url, blob: url }); },
223
+ fromSrc(src) { setPreview({ src }); },
224
+ }];
225
+ }
226
+ /** A phone draws an M card's banner at about 3 : 1 (app.css, ≤479 px) — a guide for that size, not every phone card. */
227
+ export const BANNER_PHONE_ASPECT = 3;
228
+ /**
229
+ * The banner whole, with the band every screen shows at this focus (dashed; outside it shaded) and the band a phone
230
+ * shows (solid) — measured from the picture itself once it has loaded. Positions go through the CSSOM (#1300).
231
+ */
232
+ export function BannerFocusPreview({ src, focus }) {
233
+ const [size, setSize] = useState(null);
234
+ if (!src) return null;
235
+ const ar = size ? size.w / size.h : null;
236
+ const put = (el, a) => { for (const k of ["left", "top", "width", "height"]) el.style.setProperty(k, `${(a[k] * 100).toFixed(2)}%`); };
237
+ // Every screen: the safe area (both crops). The phone guide: an M card on a phone, as drawn there (both crops too).
238
+ const safe = (el) => { if (el && el.style && ar) put(el, bannerSafeArea(ar, focus)); };
239
+ const phone = (el) => {
240
+ if (!el || !el.style || !ar) return;
241
+ const width = bannerShownWidth(ar, BANNER_PHONE_ASPECT), height = bannerShownHeight(ar, BANNER_PHONE_ASPECT);
242
+ put(el, { left: (1 - width) / 2, top: bannerBandTop(height, focus), width, height });
243
+ };
244
+ return html`<div class="bf-wrap">
245
+ <img class="bf-pic" src=${src} alt="" onLoad=${(e) => { const i = e.currentTarget; if (i.naturalWidth && i.naturalHeight) setSize({ w: i.naturalWidth, h: i.naturalHeight }); }} />
246
+ ${ar ? html`<div class="bf-band bf-phone" ref=${phone}><span>${t("card.bannerPhone")}</span></div>
247
+ <div class="bf-band bf-safe" ref=${safe}><span>${t("card.bannerSafe")}</span></div>` : null}
248
+ </div>`;
249
+ }
250
+
162
251
  // ── A person's picture for the card (View's Edit profile), fitted before it is sent (r4.1 Q3 (b)) ──
163
252
  /**
164
253
  * `file` fitted to `limit` ({ max_width, max_height, max_bytes }): as it is when it already fits; otherwise, once the
@@ -3,13 +3,13 @@
3
3
  // (`color`, `color_show`); this module resolves them as src/web-identity-color.ts does (a test pins the two equal),
4
4
  // paints the sidebar row through the CSSOM (no style attribute, #1300), and holds the Color dialog.
5
5
  // colour: a person's pick > the agent's (themes shown) > its own bot's role colour > automatic (a few soft colours)
6
- // places: a person's choice > the agent's (themes shown) > this host's default (color.show) > ring + bar
6
+ // places: a person's choice > the agent's (themes shown) > this host's default (color.show) > all three (#2056)
7
7
  // Settings → Web appearance can turn colours off for the host (color.off): nothing is painted, every pick is kept.
8
8
  import { html, useEffect, useState } from "./app-html.js";
9
9
  import { createStore, useStore } from "./app-store.js";
10
10
  import { onPrefsChanged, prefInForce, savePref } from "./app-prefs.js";
11
11
  import { register, t } from "./app-i18n.js";
12
- import { themesShown, themesStore } from "./app-themes.js";
12
+ import { pageNow, themesShown, themesStore } from "./app-themes.js";
13
13
  import { Dialog } from "./ui-dialog.js";
14
14
  import { toast } from "./ui-toast.js";
15
15
 
@@ -30,7 +30,7 @@ export const AUTO_PALETTE = [
30
30
  { id: "moss", light: "#5b7340", dark: "#a9c48d" }, { id: "slate", light: "#5f6b78", dark: "#aeb8c4" },
31
31
  ];
32
32
  export const PLACEMENTS = ["name", "bar", "ring"];
33
- export const DEFAULT_PLACEMENTS = ["bar", "ring"];
33
+ export const DEFAULT_PLACEMENTS = ["name", "bar", "ring"]; // #2056: all three where nobody chose (was ring + bar)
34
34
  const HEX = /^#[0-9a-f]{6}$/;
35
35
  const presetOf = (c) => (typeof c === "string" && c.startsWith("preset:") ? IDENTITY_PALETTE.find((p) => p.id === c.slice(7)) : undefined);
36
36
  const autoOf = (c) => (typeof c === "string" && c.startsWith("auto:") ? AUTO_PALETTE.find((p) => p.id === c.slice(5)) : undefined);
@@ -63,16 +63,20 @@ export function contrast(a, b) {
63
63
  const [l1, l2] = [luminance(a), luminance(b)].sort((x, y) => y - x);
64
64
  return (l1 + 0.05) / (l2 + 0.05);
65
65
  }
66
- /** The shade of `hex` name text uses: itself if readable, else the nearest step toward black (light) or white (dark). */
67
- export function readableShade(hex, mode) {
68
- if (!HEX.test(hex)) return TEXT[mode];
66
+ /**
67
+ * The shade of `hex` name text uses: itself if readable, else the nearest step toward black (light) or white (dark).
68
+ * `page` (#2196): an agent's colours on the page now — names must read on its background and sidebar instead.
69
+ */
70
+ export function readableShade(hex, mode, page = null) {
71
+ const backgrounds = page ? [page.bg, page.sidebar] : BG[mode], text = page ? page.text : TEXT[mode];
72
+ if (!HEX.test(hex)) return text;
69
73
  const toward = mode === "light" ? 0 : 255;
70
74
  const ch = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));
71
75
  for (let step = 0; step <= 20; step++) {
72
76
  const shade = `#${ch.map((c) => Math.round(c + (toward - c) * (step / 20)).toString(16).padStart(2, "0")).join("")}`;
73
- if (BG[mode].every((bg) => contrast(shade, bg) >= 4.5)) return shade;
77
+ if (backgrounds.every((bg) => contrast(shade, bg) >= 4.5)) return shade;
74
78
  }
75
- return TEXT[mode];
79
+ return text;
76
80
  }
77
81
 
78
82
  // ── Resolution ──
@@ -115,7 +119,7 @@ export function colorsOff() {
115
119
  const f = prefInForce("color.off");
116
120
  return f ? f.value === true : readLocal("agend_color_off") === "on";
117
121
  }
118
- /** The default places (null: back to ring + bar). */
122
+ /** The default places (null: back to all three, #2056). */
119
123
  export function setDefaultPlaces(list) {
120
124
  const v = list === null ? null : placesOk(list);
121
125
  const same = v && v.length === DEFAULT_PLACEMENTS.length && v.every((p, i) => p === DEFAULT_PLACEMENTS[i]);
@@ -135,7 +139,7 @@ export function identityOf(it, opts = {}) {
135
139
  const light = colorValue(c.color, "light"), dark = colorValue(c.color, "dark");
136
140
  return {
137
141
  color: c.color, source: c.source, show: p.show, showSource: p.source, off: opts.off ?? colorsOff(),
138
- light, dark, nameLight: readableShade(light, "light"), nameDark: readableShade(dark, "dark"),
142
+ light, dark, nameLight: readableShade(light, "light", pageNow("light")), nameDark: readableShade(dark, "dark", pageNow("dark")),
139
143
  };
140
144
  }
141
145
  /** The row's classes for its identity colour ("" when colours are off or shown nowhere). */