@songsid/agend 2.2.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 (437) hide show
  1. package/dist/agent-cli-instructions.md +5 -2
  2. package/dist/agent-cli.js +284 -2
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-endpoint.d.ts +2 -0
  5. package/dist/agent-endpoint.js +29 -0
  6. package/dist/agent-endpoint.js.map +1 -1
  7. package/dist/agent-file-read.d.ts +38 -0
  8. package/dist/agent-file-read.js +317 -0
  9. package/dist/agent-file-read.js.map +1 -0
  10. package/dist/agent-whats-new.d.ts +11 -0
  11. package/dist/agent-whats-new.js +29 -2
  12. package/dist/agent-whats-new.js.map +1 -1
  13. package/dist/atomic-write.js +9 -1
  14. package/dist/atomic-write.js.map +1 -1
  15. package/dist/auth-api.d.ts +30 -1
  16. package/dist/auth-api.js +61 -12
  17. package/dist/auth-api.js.map +1 -1
  18. package/dist/authority/authority-state.d.ts +38 -0
  19. package/dist/authority/authority-state.js +114 -0
  20. package/dist/authority/authority-state.js.map +1 -0
  21. package/dist/authority/session-authorizations.d.ts +43 -0
  22. package/dist/authority/session-authorizations.js +102 -0
  23. package/dist/authority/session-authorizations.js.map +1 -0
  24. package/dist/authority/web-authority.d.ts +120 -0
  25. package/dist/authority/web-authority.js +157 -0
  26. package/dist/authority/web-authority.js.map +1 -0
  27. package/dist/backend/antigravity.js +3 -3
  28. package/dist/backend/antigravity.js.map +1 -1
  29. package/dist/backend/claude-code.d.ts +2 -2
  30. package/dist/backend/claude-code.js +10 -5
  31. package/dist/backend/claude-code.js.map +1 -1
  32. package/dist/backend/launch-effort.js +1 -1
  33. package/dist/backend/launch-effort.js.map +1 -1
  34. package/dist/backend/muse.js +10 -2
  35. package/dist/backend/muse.js.map +1 -1
  36. package/dist/backend/types.d.ts +14 -0
  37. package/dist/backend/types.js +25 -0
  38. package/dist/backend/types.js.map +1 -1
  39. package/dist/backend-availability.d.ts +120 -0
  40. package/dist/backend-availability.js +396 -0
  41. package/dist/backend-availability.js.map +1 -0
  42. package/dist/backend-command.d.ts +21 -3
  43. package/dist/backend-command.js +23 -4
  44. package/dist/backend-command.js.map +1 -1
  45. package/dist/bundled-skills.d.ts +14 -0
  46. package/dist/bundled-skills.js +29 -0
  47. package/dist/bundled-skills.js.map +1 -0
  48. package/dist/cache-analysis.d.ts +47 -1
  49. package/dist/cache-analysis.js +68 -8
  50. package/dist/cache-analysis.js.map +1 -1
  51. package/dist/cache-ledger.d.ts +16 -3
  52. package/dist/cache-ledger.js +33 -13
  53. package/dist/cache-ledger.js.map +1 -1
  54. package/dist/cache-report-tool.d.ts +17 -0
  55. package/dist/cache-report-tool.js +40 -0
  56. package/dist/cache-report-tool.js.map +1 -0
  57. package/dist/cache-service.d.ts +70 -3
  58. package/dist/cache-service.js +178 -17
  59. package/dist/cache-service.js.map +1 -1
  60. package/dist/channel/adapters/discord.d.ts +9 -0
  61. package/dist/channel/adapters/discord.js +52 -2
  62. package/dist/channel/adapters/discord.js.map +1 -1
  63. package/dist/channel/adapters/telegram.d.ts +8 -1
  64. package/dist/channel/adapters/telegram.js +74 -4
  65. package/dist/channel/adapters/telegram.js.map +1 -1
  66. package/dist/channel/mcp-tools.js +48 -2
  67. package/dist/channel/mcp-tools.js.map +1 -1
  68. package/dist/channel/types.d.ts +21 -0
  69. package/dist/classic-channel-manager.d.ts +10 -5
  70. package/dist/classic-channel-manager.js +12 -9
  71. package/dist/classic-channel-manager.js.map +1 -1
  72. package/dist/cli.js +130 -31
  73. package/dist/cli.js.map +1 -1
  74. package/dist/config-validator.js +119 -4
  75. package/dist/config-validator.js.map +1 -1
  76. package/dist/daemon.d.ts +5 -0
  77. package/dist/daemon.js +273 -22
  78. package/dist/daemon.js.map +1 -1
  79. package/dist/decision-list.d.ts +25 -0
  80. package/dist/decision-list.js +30 -0
  81. package/dist/decision-list.js.map +1 -0
  82. package/dist/delivery-outbox.d.ts +10 -0
  83. package/dist/delivery-outbox.js +12 -1
  84. package/dist/delivery-outbox.js.map +1 -1
  85. package/dist/fleet-context.d.ts +15 -0
  86. package/dist/fleet-manager.d.ts +506 -11
  87. package/dist/fleet-manager.js +1784 -130
  88. package/dist/fleet-manager.js.map +1 -1
  89. package/dist/fleet-traffic.d.ts +74 -0
  90. package/dist/fleet-traffic.js +196 -0
  91. package/dist/fleet-traffic.js.map +1 -0
  92. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +20 -5
  93. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +6 -1
  94. package/dist/general-knowledge/skills/multi-channel/SKILL.md +3 -2
  95. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  96. package/dist/general-knowledge/skills/web-appearance/SKILL.md +492 -0
  97. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +476 -0
  98. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  99. package/dist/human-delivery-receipts.d.ts +24 -1
  100. package/dist/human-delivery-receipts.js +64 -11
  101. package/dist/human-delivery-receipts.js.map +1 -1
  102. package/dist/instance-avatar.js +3 -0
  103. package/dist/instance-avatar.js.map +1 -1
  104. package/dist/instance-config-impact.js +6 -1
  105. package/dist/instance-config-impact.js.map +1 -1
  106. package/dist/instance-lifecycle.js +9 -4
  107. package/dist/instance-lifecycle.js.map +1 -1
  108. package/dist/instance-names.d.ts +4 -0
  109. package/dist/instance-names.js +12 -0
  110. package/dist/instance-names.js.map +1 -0
  111. package/dist/instructions.d.ts +12 -1
  112. package/dist/instructions.js +13 -2
  113. package/dist/instructions.js.map +1 -1
  114. package/dist/locale.js +100 -8
  115. package/dist/locale.js.map +1 -1
  116. package/dist/ls-attach-resolve.d.ts +95 -0
  117. package/dist/ls-attach-resolve.js +174 -0
  118. package/dist/ls-attach-resolve.js.map +1 -0
  119. package/dist/memory-hogs.d.ts +27 -0
  120. package/dist/memory-hogs.js +124 -0
  121. package/dist/memory-hogs.js.map +1 -0
  122. package/dist/needs-you-hub.d.ts +4 -0
  123. package/dist/needs-you-hub.js +31 -6
  124. package/dist/needs-you-hub.js.map +1 -1
  125. package/dist/needs-you.d.ts +1 -13
  126. package/dist/needs-you.js +3 -37
  127. package/dist/needs-you.js.map +1 -1
  128. package/dist/outbound-handlers.d.ts +15 -0
  129. package/dist/outbound-handlers.js +152 -11
  130. package/dist/outbound-handlers.js.map +1 -1
  131. package/dist/outbound-schemas.d.ts +228 -4
  132. package/dist/outbound-schemas.js +147 -1
  133. package/dist/outbound-schemas.js.map +1 -1
  134. package/dist/public-web-gateway.js +21 -1
  135. package/dist/public-web-gateway.js.map +1 -1
  136. package/dist/public-web-link.d.ts +9 -0
  137. package/dist/public-web-link.js +8 -0
  138. package/dist/public-web-link.js.map +1 -1
  139. package/dist/quickstart-api.d.ts +10 -1
  140. package/dist/quickstart-api.js +12 -4
  141. package/dist/quickstart-api.js.map +1 -1
  142. package/dist/reply-buttons-controller.d.ts +4 -0
  143. package/dist/reply-buttons-controller.js +2 -2
  144. package/dist/reply-buttons-controller.js.map +1 -1
  145. package/dist/repo-worktree-guard.d.ts +36 -0
  146. package/dist/repo-worktree-guard.js +143 -0
  147. package/dist/repo-worktree-guard.js.map +1 -0
  148. package/dist/restart-progress.d.ts +65 -1
  149. package/dist/restart-progress.js +236 -10
  150. package/dist/restart-progress.js.map +1 -1
  151. package/dist/rollout-index.d.ts +5 -0
  152. package/dist/rollout-index.js +26 -5
  153. package/dist/rollout-index.js.map +1 -1
  154. package/dist/scheduler/scheduler.d.ts +70 -1
  155. package/dist/scheduler/scheduler.js +256 -17
  156. package/dist/scheduler/scheduler.js.map +1 -1
  157. package/dist/service-installer.d.ts +2 -1
  158. package/dist/service-installer.js +18 -3
  159. package/dist/service-installer.js.map +1 -1
  160. package/dist/settings-api.d.ts +19 -0
  161. package/dist/settings-api.js +210 -2
  162. package/dist/settings-api.js.map +1 -1
  163. package/dist/settings-change.js +112 -0
  164. package/dist/settings-change.js.map +1 -1
  165. package/dist/settings-effect.js +32 -2
  166. package/dist/settings-effect.js.map +1 -1
  167. package/dist/settings-http-confirmation.js +5 -0
  168. package/dist/settings-http-confirmation.js.map +1 -1
  169. package/dist/tmux-manager.d.ts +5 -0
  170. package/dist/tmux-manager.js +16 -0
  171. package/dist/tmux-manager.js.map +1 -1
  172. package/dist/tool-permissions.d.ts +4 -6
  173. package/dist/tool-permissions.js +100 -2
  174. package/dist/tool-permissions.js.map +1 -1
  175. package/dist/topic-commands.d.ts +17 -7
  176. package/dist/topic-commands.js +39 -21
  177. package/dist/topic-commands.js.map +1 -1
  178. package/dist/topic-link.d.ts +128 -0
  179. package/dist/topic-link.js +269 -0
  180. package/dist/topic-link.js.map +1 -0
  181. package/dist/types.d.ts +61 -1
  182. package/dist/ui/app-effects.js +233 -0
  183. package/dist/ui/chat-ambient.js +307 -0
  184. package/dist/ui/chat-effect-posters.js +42 -0
  185. package/dist/ui/chat-effects.js +160 -0
  186. package/dist/ui/chat-live-replies.js +58 -0
  187. package/dist/ui/chat-render.js +9 -6
  188. package/dist/ui/chat-store.js +9 -3
  189. package/dist/ui/chat-strings.js +70 -2
  190. package/dist/ui/chat-thread.js +191 -37
  191. package/dist/ui/chat-tour.js +1 -1
  192. package/dist/ui/effect-trial-controller.js +124 -0
  193. package/dist/ui/effect-trial-offer.js +31 -0
  194. package/dist/ui/effect-trial-panel.js +40 -0
  195. package/dist/ui/fleet-cache.js +23 -1
  196. package/dist/ui/fleet-canvas-layout.js +111 -0
  197. package/dist/ui/fleet-canvas.js +525 -0
  198. package/dist/ui/fleet-org.js +27 -12
  199. package/dist/ui/fleet-traffic.js +343 -0
  200. package/dist/ui/fleet-usage.js +401 -0
  201. package/dist/ui/image-lightbox.js +1 -1
  202. package/dist/ui/panel-chat.js +203 -57
  203. package/dist/ui/panel-details.js +20 -6
  204. package/dist/ui/panel-fleet.js +43 -18
  205. package/dist/ui/panel-log.js +6 -6
  206. package/dist/ui/panel-needs.js +3 -3
  207. package/dist/ui/panel-settings.js +34 -13
  208. package/dist/ui/preview-panel.js +25 -9
  209. package/dist/ui/preview.js +3 -2
  210. package/dist/ui/settings-appearance.js +349 -0
  211. package/dist/ui/settings-catalog.js +92 -0
  212. package/dist/ui/settings-dialogs.js +40 -12
  213. package/dist/ui/settings-effects.js +202 -0
  214. package/dist/ui/settings-guests.js +117 -0
  215. package/dist/ui/settings-learn.js +25 -0
  216. package/dist/ui/settings-model.js +15 -6
  217. package/dist/ui/settings-mods.js +271 -0
  218. package/dist/ui/settings-owner-effects.js +80 -0
  219. package/dist/ui/settings-strings.js +333 -10
  220. package/dist/ui/settings-web-authority.js +91 -0
  221. package/dist/ui/shared/agend-auth.js +28 -4
  222. package/dist/ui/shared/agent-widget.js +248 -0
  223. package/dist/ui/shared/app-i18n.js +6 -2
  224. package/dist/ui/shared/app-prefs.js +34 -13
  225. package/dist/ui/shared/app-route.js +24 -2
  226. package/dist/ui/shared/app-session.js +3 -1
  227. package/dist/ui/shared/app-shell.js +102 -23
  228. package/dist/ui/shared/app-store.js +28 -1
  229. package/dist/ui/shared/app-stream.js +14 -7
  230. package/dist/ui/shared/app-themes.js +206 -0
  231. package/dist/ui/shared/app.css +565 -4
  232. package/dist/ui/shared/app.js +23 -10
  233. package/dist/ui/shared/card-strings.js +32 -0
  234. package/dist/ui/shared/effect-app-runtime.js +297 -0
  235. package/dist/ui/shared/effect-baseline.js +64 -0
  236. package/dist/ui/shared/effect-chat-runtime.js +167 -0
  237. package/dist/ui/shared/effect-cursor.js +125 -0
  238. package/dist/ui/shared/effect-frame.js +146 -0
  239. package/dist/ui/shared/effect-geometry.js +137 -0
  240. package/dist/ui/shared/effect-host-style.js +10 -0
  241. package/dist/ui/shared/effect-owner-regions.js +74 -0
  242. package/dist/ui/shared/effect-owner-source.js +115 -0
  243. package/dist/ui/shared/effect-policy.js +151 -0
  244. package/dist/ui/shared/effect-poster-reader.js +98 -0
  245. package/dist/ui/shared/effect-posters.js +117 -0
  246. package/dist/ui/shared/effect-profiler.js +184 -0
  247. package/dist/ui/shared/effect-profiles.js +65 -0
  248. package/dist/ui/shared/effect-registry.js +535 -0
  249. package/dist/ui/shared/effect-runtime-loader.js +234 -0
  250. package/dist/ui/shared/effect-safety.js +153 -0
  251. package/dist/ui/shared/effect-stock-snapshot.js +43 -0
  252. package/dist/ui/shared/effect-stock-trust.js +217 -0
  253. package/dist/ui/shared/effect-trial-shadow.js +62 -0
  254. package/dist/ui/shared/effect-trial-source.js +103 -0
  255. package/dist/ui/shared/effect-trial-stage.js +170 -0
  256. package/dist/ui/shared/effect-trial.css +40 -0
  257. package/dist/ui/shared/fx-motion.js +67 -0
  258. package/dist/ui/shared/header-tools.js +1 -1
  259. package/dist/ui/shared/identity-card.js +273 -0
  260. package/dist/ui/shared/identity-color.js +261 -0
  261. package/dist/ui/shared/instance-nav.js +215 -41
  262. package/dist/ui/shared/owner-css.js +221 -0
  263. package/dist/ui/shared/owner-effect-prefs.js +117 -0
  264. package/dist/ui/shared/panel-view.js +103 -10
  265. package/dist/ui/shared/signin.js +2 -0
  266. package/dist/ui/shared/tokens.css +9 -3
  267. package/dist/ui/shared/ui-dialog.js +1 -1
  268. package/dist/ui/shared/ui-icons.js +3 -0
  269. package/dist/ui/shared/ui-menu.js +1 -1
  270. package/dist/ui/shared/ui-toast.js +1 -1
  271. package/dist/ui/shared/usage-dialog.js +22 -2
  272. package/dist/ui/shared/view-strings.js +98 -2
  273. package/dist/ui/shared/web-authorize.js +151 -0
  274. package/dist/ui/signin.html +1 -0
  275. package/dist/ui/web-terminal/terminal.css +4 -4
  276. package/dist/usage/providers.d.ts +28 -0
  277. package/dist/usage/providers.js +126 -36
  278. package/dist/usage/providers.js.map +1 -1
  279. package/dist/usage-report.d.ts +158 -0
  280. package/dist/usage-report.js +226 -0
  281. package/dist/usage-report.js.map +1 -0
  282. package/dist/usage-rollup.d.ts +51 -0
  283. package/dist/usage-rollup.js +168 -0
  284. package/dist/usage-rollup.js.map +1 -0
  285. package/dist/view-api.d.ts +68 -0
  286. package/dist/view-api.js +249 -8
  287. package/dist/view-api.js.map +1 -1
  288. package/dist/web-ambient.d.ts +72 -0
  289. package/dist/web-ambient.js +161 -0
  290. package/dist/web-ambient.js.map +1 -0
  291. package/dist/web-api.d.ts +111 -5
  292. package/dist/web-api.js +1235 -58
  293. package/dist/web-api.js.map +1 -1
  294. package/dist/web-appearance-limits.d.ts +82 -0
  295. package/dist/web-appearance-limits.js +83 -0
  296. package/dist/web-appearance-limits.js.map +1 -0
  297. package/dist/web-appearance-policy.d.ts +64 -0
  298. package/dist/web-appearance-policy.js +87 -0
  299. package/dist/web-appearance-policy.js.map +1 -0
  300. package/dist/web-appearance-tools.d.ts +53 -0
  301. package/dist/web-appearance-tools.js +124 -0
  302. package/dist/web-appearance-tools.js.map +1 -0
  303. package/dist/web-appearance-view.d.ts +124 -0
  304. package/dist/web-appearance-view.js +278 -0
  305. package/dist/web-appearance-view.js.map +1 -0
  306. package/dist/web-appearance.d.ts +93 -0
  307. package/dist/web-appearance.js +373 -0
  308. package/dist/web-appearance.js.map +1 -0
  309. package/dist/web-asset-parts.d.ts +93 -0
  310. package/dist/web-asset-parts.js +133 -0
  311. package/dist/web-asset-parts.js.map +1 -0
  312. package/dist/web-auth.js +20 -2
  313. package/dist/web-auth.js.map +1 -1
  314. package/dist/web-card.d.ts +110 -0
  315. package/dist/web-card.js +266 -0
  316. package/dist/web-card.js.map +1 -0
  317. package/dist/web-channel-echo.d.ts +7 -1
  318. package/dist/web-channel-echo.js +6 -2
  319. package/dist/web-channel-echo.js.map +1 -1
  320. package/dist/web-chat-history.d.ts +59 -0
  321. package/dist/web-chat-history.js +102 -4
  322. package/dist/web-chat-history.js.map +1 -1
  323. package/dist/web-commands.d.ts +1 -0
  324. package/dist/web-effect-bootstrap.d.ts +12 -0
  325. package/dist/web-effect-bootstrap.js +49 -0
  326. package/dist/web-effect-bootstrap.js.map +1 -0
  327. package/dist/web-effect-bundle.d.ts +28 -0
  328. package/dist/web-effect-bundle.js +171 -0
  329. package/dist/web-effect-bundle.js.map +1 -0
  330. package/dist/web-effect-canonical.d.ts +8 -0
  331. package/dist/web-effect-canonical.js +27 -0
  332. package/dist/web-effect-canonical.js.map +1 -0
  333. package/dist/web-effect-library.d.ts +114 -0
  334. package/dist/web-effect-library.js +530 -0
  335. package/dist/web-effect-library.js.map +1 -0
  336. package/dist/web-effect-playback.d.ts +30 -0
  337. package/dist/web-effect-playback.js +71 -0
  338. package/dist/web-effect-playback.js.map +1 -0
  339. package/dist/web-effect-poster.d.ts +8 -0
  340. package/dist/web-effect-poster.js +52 -0
  341. package/dist/web-effect-poster.js.map +1 -0
  342. package/dist/web-effect-profiles.d.ts +118 -0
  343. package/dist/web-effect-profiles.js +180 -0
  344. package/dist/web-effect-profiles.js.map +1 -0
  345. package/dist/web-effect-service.d.ts +93 -0
  346. package/dist/web-effect-service.js +335 -0
  347. package/dist/web-effect-service.js.map +1 -0
  348. package/dist/web-effect-tools.d.ts +48 -0
  349. package/dist/web-effect-tools.js +129 -0
  350. package/dist/web-effect-tools.js.map +1 -0
  351. package/dist/web-effect-trials.d.ts +86 -0
  352. package/dist/web-effect-trials.js +204 -0
  353. package/dist/web-effect-trials.js.map +1 -0
  354. package/dist/web-effect-upload.d.ts +27 -0
  355. package/dist/web-effect-upload.js +185 -0
  356. package/dist/web-effect-upload.js.map +1 -0
  357. package/dist/web-effect-worker.d.ts +8 -0
  358. package/dist/web-effect-worker.js +170 -0
  359. package/dist/web-effect-worker.js.map +1 -0
  360. package/dist/web-effect.d.ts +103 -0
  361. package/dist/web-effect.js +153 -0
  362. package/dist/web-effect.js.map +1 -0
  363. package/dist/web-guest-access.d.ts +125 -0
  364. package/dist/web-guest-access.js +234 -0
  365. package/dist/web-guest-access.js.map +1 -0
  366. package/dist/web-guest-rooms.d.ts +82 -0
  367. package/dist/web-guest-rooms.js +135 -0
  368. package/dist/web-guest-rooms.js.map +1 -0
  369. package/dist/web-identity-color.d.ts +87 -0
  370. package/dist/web-identity-color.js +209 -0
  371. package/dist/web-identity-color.js.map +1 -0
  372. package/dist/web-identity-palette.d.ts +113 -0
  373. package/dist/web-identity-palette.js +84 -0
  374. package/dist/web-identity-palette.js.map +1 -0
  375. package/dist/web-image-meta.d.ts +25 -0
  376. package/dist/web-image-meta.js +200 -0
  377. package/dist/web-image-meta.js.map +1 -0
  378. package/dist/web-login.d.ts +47 -0
  379. package/dist/web-login.js +115 -0
  380. package/dist/web-login.js.map +1 -1
  381. package/dist/web-mod-agent.d.ts +50 -0
  382. package/dist/web-mod-agent.js +207 -0
  383. package/dist/web-mod-agent.js.map +1 -0
  384. package/dist/web-mod-bundle.d.ts +157 -0
  385. package/dist/web-mod-bundle.js +529 -0
  386. package/dist/web-mod-bundle.js.map +1 -0
  387. package/dist/web-mod-export.d.ts +68 -0
  388. package/dist/web-mod-export.js +100 -0
  389. package/dist/web-mod-export.js.map +1 -0
  390. package/dist/web-mod-store.d.ts +289 -0
  391. package/dist/web-mod-store.js +638 -0
  392. package/dist/web-mod-store.js.map +1 -0
  393. package/dist/web-org.d.ts +3 -3
  394. package/dist/web-org.js +11 -17
  395. package/dist/web-org.js.map +1 -1
  396. package/dist/web-owner-css-store.d.ts +180 -0
  397. package/dist/web-owner-css-store.js +384 -0
  398. package/dist/web-owner-css-store.js.map +1 -0
  399. package/dist/web-owner-css.d.ts +58 -0
  400. package/dist/web-owner-css.js +552 -0
  401. package/dist/web-owner-css.js.map +1 -0
  402. package/dist/web-prefs.d.ts +62 -0
  403. package/dist/web-prefs.js +232 -36
  404. package/dist/web-prefs.js.map +1 -1
  405. package/dist/web-preview.d.ts +15 -3
  406. package/dist/web-preview.js +28 -9
  407. package/dist/web-preview.js.map +1 -1
  408. package/dist/web-returning-device.d.ts +41 -0
  409. package/dist/web-returning-device.js +57 -5
  410. package/dist/web-returning-device.js.map +1 -1
  411. package/dist/web-session-authorization.d.ts +132 -0
  412. package/dist/web-session-authorization.js +193 -0
  413. package/dist/web-session-authorization.js.map +1 -0
  414. package/dist/web-session.d.ts +70 -10
  415. package/dist/web-session.js +137 -22
  416. package/dist/web-session.js.map +1 -1
  417. package/dist/web-settings-patch.d.ts +67 -2
  418. package/dist/web-settings-patch.js +196 -1
  419. package/dist/web-settings-patch.js.map +1 -1
  420. package/dist/web-settings-tools.d.ts +89 -0
  421. package/dist/web-settings-tools.js +270 -0
  422. package/dist/web-settings-tools.js.map +1 -0
  423. package/dist/web-shell-routes.d.ts +2 -2
  424. package/dist/web-shell-routes.js +2 -2
  425. package/dist/web-shell-routes.js.map +1 -1
  426. package/dist/web-theme-store.d.ts +257 -0
  427. package/dist/web-theme-store.js +627 -0
  428. package/dist/web-theme-store.js.map +1 -0
  429. package/dist/web-theme.d.ts +123 -0
  430. package/dist/web-theme.js +416 -0
  431. package/dist/web-theme.js.map +1 -0
  432. package/dist/web-widget.d.ts +72 -0
  433. package/dist/web-widget.js +245 -0
  434. package/dist/web-widget.js.map +1 -0
  435. package/dist/workflow-templates/default.md +1 -1
  436. package/package.json +1 -1
  437. package/templates/systemd.service.ejs +8 -0
@@ -0,0 +1,269 @@
1
+ /**
2
+ * #1990: links to another topic. One place builds "a link to instance X's place (or a world's General) on surface S"
3
+ * from what the adapters already know — Discord guild/channel ids, the Telegram supergroup id, its public @username
4
+ * when it has one, and topic ids — and messages name such a place through a token that each surface renders in its own
5
+ * form, or as plain text when the reader could not open the target.
6
+ *
7
+ * Discord `<#channel>` (clickable in place); in a DM, `https://discord.com/channels/<guild>/<channel>`
8
+ * Telegram `https://t.me/<username>/<topic>` (public group) or `https://t.me/c/<id without -100>/<topic>`, carried by
9
+ * a `text_link` entity on plain text — no parse mode, so nothing in the text needs escaping
10
+ * plain the label alone (a suffix token disappears)
11
+ *
12
+ * The forms are the documented ones; no real client was driven (#1990: the user checks them on the 2.3 beta).
13
+ */
14
+ /** A world's place, for links: its platform, its group and (Telegram) the group's public @username once read. */
15
+ export function worldPlaceOf(world) {
16
+ const username = world.groupId ? world.adapter?.groupUsername?.(world.groupId) : undefined;
17
+ return { type: world.type, ...(world.groupId ? { groupId: world.groupId } : {}), ...(username ? { username } : {}) };
18
+ }
19
+ export const SNOWFLAKE = /^\d{5,25}$/;
20
+ /** A Telegram @username as the platform allows it: 4–32 of [A-Za-z0-9_], starting with a letter. */
21
+ const TELEGRAM_USERNAME = /^[A-Za-z][A-Za-z0-9_]{3,31}$/;
22
+ /** t.me/c/ links take a supergroup's id without its -100 prefix; anything else has no such link. */
23
+ export function telegramInternalId(chatId) {
24
+ const m = /^-100(\d+)$/.exec(chatId);
25
+ return m ? m[1] : undefined;
26
+ }
27
+ /** The t.me path prefix of a group: `<username>` for a public one, `c/<id>` for a private supergroup. */
28
+ function telegramGroupPath(place, chatId = place.groupId ?? "") {
29
+ if (place.username && TELEGRAM_USERNAME.test(place.username) && chatId === place.groupId)
30
+ return place.username;
31
+ const internal = telegramInternalId(chatId);
32
+ return internal ? `c/${internal}` : undefined;
33
+ }
34
+ /** A link to a message (a prompt's own buttons), or undefined when none can be built for this platform/place. */
35
+ export function messageLink(place, at) {
36
+ if (!at.messageId)
37
+ return undefined;
38
+ if (place.type === "discord") {
39
+ const channel = at.threadId ?? at.chatId;
40
+ if (!place.groupId || !SNOWFLAKE.test(place.groupId) || !SNOWFLAKE.test(channel) || !SNOWFLAKE.test(at.messageId))
41
+ return undefined;
42
+ return `https://discord.com/channels/${place.groupId}/${channel}/${at.messageId}`;
43
+ }
44
+ if (place.type === "telegram") {
45
+ const path = telegramGroupPath(place, at.chatId);
46
+ if (!path || !/^\d+$/.test(at.messageId))
47
+ return undefined;
48
+ const topic = at.threadId && at.threadId !== "1" && /^\d+$/.test(at.threadId) ? `${at.threadId}/` : "";
49
+ return `https://t.me/${path}/${topic}${at.messageId}`;
50
+ }
51
+ return undefined;
52
+ }
53
+ /**
54
+ * A browser URL to a topic or channel. Telegram's General topic (1) gets one only when `general` is set: an
55
+ * instance's link never points at General.
56
+ */
57
+ export function topicUrl(place, topicId, opts = {}) {
58
+ if (!place || !topicId)
59
+ return undefined;
60
+ if (place.type === "discord") {
61
+ if (!place.groupId || !SNOWFLAKE.test(place.groupId) || !SNOWFLAKE.test(topicId))
62
+ return undefined;
63
+ return `https://discord.com/channels/${place.groupId}/${topicId}`;
64
+ }
65
+ if (place.type === "telegram") {
66
+ const path = telegramGroupPath(place);
67
+ if (!path || !/^\d+$/.test(topicId) || (topicId === "1" && !opts.general))
68
+ return undefined;
69
+ return `https://t.me/${path}/${topicId}`;
70
+ }
71
+ return undefined;
72
+ }
73
+ /** A way to the instance's own thread: Discord's channel mention (clickable in place), Telegram's topic link. */
74
+ export function instanceLink(place, topicId) {
75
+ if (!topicId)
76
+ return undefined;
77
+ if (place.type === "discord")
78
+ return SNOWFLAKE.test(topicId) ? `<#${topicId}>` : undefined;
79
+ return topicUrl(place, topicId);
80
+ }
81
+ // Private-use code points: no normal text carries them, and a stray one is never taken for a token.
82
+ const OPEN = "";
83
+ const MID = "";
84
+ const CLOSE = "";
85
+ const TOKEN = /([^-]*)([^-]*)/g;
86
+ const MARKERS = /[-]/g;
87
+ function encodeTarget(target) {
88
+ return target.kind === "general" ? "g" : `i:${encodeURIComponent(target.name)}`;
89
+ }
90
+ function decodeTarget(payload) {
91
+ if (payload === "g")
92
+ return { kind: "general" };
93
+ if (!payload.startsWith("i:"))
94
+ return undefined;
95
+ try {
96
+ const name = decodeURIComponent(payload.slice(2));
97
+ return name ? { kind: "instance", name } : undefined;
98
+ }
99
+ catch {
100
+ return undefined;
101
+ }
102
+ }
103
+ /** Name a place in a message: rendered as `label` linked to the target, or as `label` alone. */
104
+ export function placeRef(target, label) {
105
+ return `${OPEN}${encodeTarget(target)}${MID}${label.replace(MARKERS, "")}${CLOSE}`;
106
+ }
107
+ /**
108
+ * A link appended to a message (" → General"): the message's own words stay as they are, and when the place cannot
109
+ * be linked the suffix disappears with its leading space.
110
+ */
111
+ export function placeSuffix(target, label) {
112
+ return ` ${OPEN}s|${encodeTarget(target)}${MID}${label.replace(MARKERS, "")}${CLOSE}`;
113
+ }
114
+ export function hasPlaceRefs(text) {
115
+ return text.includes(OPEN);
116
+ }
117
+ /**
118
+ * Render every token for one surface. `resolve` says how this reader reaches a target (undefined: plain text). The
119
+ * text outside tokens is copied unchanged; `textLinks` is non-empty only on Telegram.
120
+ */
121
+ export function renderPlaceRefs(text, surface, resolve) {
122
+ if (!hasPlaceRefs(text))
123
+ return { text, textLinks: [] };
124
+ const textLinks = [];
125
+ let out = "";
126
+ let last = 0;
127
+ for (const m of text.matchAll(TOKEN)) {
128
+ let before = text.slice(last, m.index);
129
+ last = m.index + m[0].length;
130
+ const suffix = m[1].startsWith("s|");
131
+ const target = decodeTarget(suffix ? m[1].slice(2) : m[1]);
132
+ const label = m[2];
133
+ const link = target && label && surface !== "plain" ? resolve(target) : undefined;
134
+ if (!link) {
135
+ // A suffix is all link: without one it goes, with the space placeSuffix put before it.
136
+ if (suffix)
137
+ before = before.endsWith(" ") ? before.slice(0, -1) : before;
138
+ out += before + (suffix ? "" : label);
139
+ continue;
140
+ }
141
+ out += before;
142
+ const arrow = suffix ? "→ " : "";
143
+ if (surface === "discord") {
144
+ // A mention is clickable in place; a URL (a DM) in angle brackets so Discord adds no embed.
145
+ const ref = "mention" in link ? link.mention : `<${link.url}>`;
146
+ out += suffix ? `${arrow}${ref}` : `${label} (${ref})`;
147
+ }
148
+ else if ("url" in link) {
149
+ out += arrow;
150
+ textLinks.push({ offset: out.length, length: label.length, url: link.url });
151
+ out += label;
152
+ }
153
+ else {
154
+ out += arrow + label;
155
+ }
156
+ }
157
+ out += text.slice(last);
158
+ return { text: out, textLinks };
159
+ }
160
+ /**
161
+ * #1990: an in-app route of the web app for an instance — its chat, or its terminal View — as the web client parses it
162
+ * (src/ui/shared/app-route.js chatPath / viewPath). Undefined for a name no route takes.
163
+ */
164
+ export function webRoute(panel, name) {
165
+ if (!name || name.length > 128 || /[/\\\u0000-\u001f\u007f]/.test(name) || name === "." || name.includes(".."))
166
+ return undefined;
167
+ return panel === "chat" ? `/ui/chat/${encodeURIComponent(name)}` : `/view/${encodeURIComponent(name)}`;
168
+ }
169
+ const WEB_ROUTE = /^\/(?:ui\/chat|view)\/[^/?#\s]+$/;
170
+ export const WEB_TEXT_LINKS_MAX = 16;
171
+ /**
172
+ * #1990: links as the web keeps them — on a status line or a prompt, ranges of its text that open an instance's chat
173
+ * or View in the app. Whatever is not exactly that (out of the text, overlapping, not such a route) is dropped; an
174
+ * empty result is undefined.
175
+ */
176
+ export function webTextLinks(raw, text) {
177
+ if (!Array.isArray(raw))
178
+ return undefined;
179
+ const out = [];
180
+ let end = 0;
181
+ for (const l of raw.slice(0, WEB_TEXT_LINKS_MAX)) {
182
+ if (!l || typeof l !== "object")
183
+ continue;
184
+ const { offset, length, url } = l;
185
+ if (!Number.isSafeInteger(offset) || !Number.isSafeInteger(length) || typeof url !== "string")
186
+ continue;
187
+ const o = offset, n = length;
188
+ if (o < end || n < 1 || o + n > text.length || !WEB_ROUTE.test(url))
189
+ continue;
190
+ try {
191
+ decodeURIComponent(url);
192
+ }
193
+ catch {
194
+ continue;
195
+ }
196
+ out.push({ offset: o, length: n, url });
197
+ end = o + n;
198
+ }
199
+ return out.length ? out : undefined;
200
+ }
201
+ /** Every token as its label, suffixes gone: what a surface that renders no links shows. */
202
+ export function stripPlaceRefs(text) {
203
+ return renderPlaceRefs(text, "plain", () => undefined).text;
204
+ }
205
+ /** Text links that lie wholly inside [start, end), re-based to start; one that crosses the boundary is dropped. */
206
+ export function textLinksWithin(links, start, end) {
207
+ return links.filter(l => l.offset >= start && l.offset + l.length <= end).map(l => ({ ...l, offset: l.offset - start }));
208
+ }
209
+ /**
210
+ * Whether a DM recipient may get links into a group: only a confirmed member (#1990 — never link to what the reader
211
+ * cannot open). One read per (group, user) per `ttlMs`, bounded by `deadlineMs`; a non-member, an error, a timeout or
212
+ * an adapter that cannot tell all mean "no" (plain text). Answers are cached, failures included, so a refusing
213
+ * platform is asked again only after the TTL; concurrent asks share one read.
214
+ */
215
+ export class GroupMembership {
216
+ opts;
217
+ answers = new Map();
218
+ reads = new Map();
219
+ constructor(opts = { now: () => performance.now() }) {
220
+ this.opts = opts;
221
+ }
222
+ async isMember(source, groupId, userId) {
223
+ if (!source.isGroupMember || !groupId || !userId)
224
+ return false;
225
+ const key = `${groupId}\u0000${userId}`;
226
+ const ttl = this.opts.ttlMs ?? 10 * 60_000;
227
+ const cached = this.answers.get(key);
228
+ if (cached && this.opts.now() - cached.at < ttl)
229
+ return cached.member;
230
+ const pending = this.reads.get(key);
231
+ if (pending)
232
+ return pending;
233
+ const read = this.read(source, groupId, userId).then(member => {
234
+ this.answers.delete(key); // re-insert: the map's order is its age, for the bound below
235
+ this.answers.set(key, { member, at: this.opts.now() });
236
+ const max = this.opts.maxEntries ?? 1000;
237
+ while (this.answers.size > max)
238
+ this.answers.delete(this.answers.keys().next().value);
239
+ return member;
240
+ }).finally(() => this.reads.delete(key));
241
+ this.reads.set(key, read);
242
+ return read;
243
+ }
244
+ read(source, groupId, userId) {
245
+ const deadlineMs = this.opts.deadlineMs ?? 5_000;
246
+ return new Promise(resolve => {
247
+ const timer = setTimeout(() => resolve(false), deadlineMs);
248
+ timer.unref?.();
249
+ let asked;
250
+ try {
251
+ asked = source.isGroupMember(groupId, userId);
252
+ }
253
+ catch {
254
+ asked = Promise.resolve(false);
255
+ }
256
+ asked.then(member => { clearTimeout(timer); resolve(member === true); }, () => { clearTimeout(timer); resolve(false); });
257
+ });
258
+ }
259
+ }
260
+ /** #1990: refusals that send the person to General — their reply carries a link to it. */
261
+ export const GENERAL_POINTING_REFUSALS = new Set(["cmd.use_in_general", "profile.general_only"]);
262
+ /**
263
+ * Text from outside (an agent's message, a pane line, a dialog's description) as a place-token-free argument: a
264
+ * message that interpolates it must not let it name a place of its own.
265
+ */
266
+ export function noPlaceMarkers(text) {
267
+ return text.replace(MARKERS, "");
268
+ }
269
+ //# sourceMappingURL=topic-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-link.js","sourceRoot":"","sources":["../src/topic-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH,iHAAiH;AACjH,MAAM,UAAU,YAAY,CAAC,KAA2G;IACtI,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3F,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AACvH,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,YAAY,CAAC;AACtC,oGAAoG;AACpG,MAAM,iBAAiB,GAAG,8BAA8B,CAAC;AAEzD,oGAAoG;AACpG,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9B,CAAC;AAED,yGAAyG;AACzG,SAAS,iBAAiB,CAAC,KAAiB,EAAE,MAAM,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE;IACxE,IAAI,KAAK,CAAC,QAAQ,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,MAAM,KAAK,KAAK,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC,QAAQ,CAAC;IAChH,MAAM,QAAQ,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC5C,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAChD,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,WAAW,CAAC,KAAiB,EAAE,EAA6D;IAC1G,IAAI,CAAC,EAAE,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACpC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,MAAM,CAAC;QACzC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QACpI,OAAO,gCAAgC,KAAK,CAAC,OAAO,IAAI,OAAO,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC;IACpF,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC3D,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,QAAQ,KAAK,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACvG,OAAO,gBAAgB,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;IACxD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,KAA6B,EAAE,OAA2B,EAAE,OAA8B,EAAE;IACnH,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IACzC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,SAAS,CAAC;QACnG,OAAO,gCAAgC,KAAK,CAAC,OAAO,IAAI,OAAO,EAAE,CAAC;IACpE,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,SAAS,CAAC;QAC5F,OAAO,gBAAgB,IAAI,IAAI,OAAO,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,YAAY,CAAC,KAAiB,EAAE,OAA2B;IACzE,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3F,OAAO,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AAClC,CAAC;AAgBD,oGAAoG;AACpG,MAAM,IAAI,GAAG,GAAG,CAAC;AACjB,MAAM,GAAG,GAAG,GAAG,CAAC;AAChB,MAAM,KAAK,GAAG,GAAG,CAAC;AAClB,MAAM,KAAK,GAAG,wBAAwB,CAAC;AACvC,MAAM,OAAO,GAAG,QAAQ,CAAC;AAEzB,SAAS,YAAY,CAAC,MAAmB;IACvC,OAAO,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;AAClF,CAAC;AAED,SAAS,YAAY,CAAC,OAAe;IACnC,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAChD,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,SAAS,CAAC;IAAC,CAAC;AAC/B,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,QAAQ,CAAC,MAAmB,EAAE,KAAa;IACzD,OAAO,GAAG,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC;AACrF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAmB,EAAE,KAAa;IAC5D,OAAO,IAAI,IAAI,KAAK,YAAY,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,OAAqB,EACrB,OAAuD;IAEvD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACxD,MAAM,SAAS,GAAe,EAAE,CAAC;IACjC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC7B,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnB,MAAM,IAAI,GAAG,MAAM,IAAI,KAAK,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,uFAAuF;YACvF,IAAI,MAAM;gBAAE,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACzE,GAAG,IAAI,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACtC,SAAS;QACX,CAAC;QACD,GAAG,IAAI,MAAM,CAAC;QACd,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,4FAA4F;YAC5F,MAAM,GAAG,GAAG,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC;YAC/D,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,GAAG,GAAG,CAAC;QACzD,CAAC;aAAM,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YACzB,GAAG,IAAI,KAAK,CAAC;YACb,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;YAC5E,GAAG,IAAI,KAAK,CAAC;QACf,CAAC;aAAM,CAAC;YACN,GAAG,IAAI,KAAK,GAAG,KAAK,CAAC;QACvB,CAAC;IACH,CAAC;IACD,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAsB,EAAE,IAAY;IAC3D,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,IAAI,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACjI,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;AACzG,CAAC;AAED,MAAM,SAAS,GAAG,kCAAkC,CAAC;AACrD,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAErC;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,GAAY,EAAE,IAAY;IACrD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,GAAG,GAAe,EAAE,CAAC;IAC3B,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,kBAAkB,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,SAAS;QAC1C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAA4B,CAAC;QAC7D,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ;YAAE,SAAS;QACxG,MAAM,CAAC,GAAG,MAAgB,EAAE,CAAC,GAAG,MAAgB,CAAC;QACjD,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QAC9E,IAAI,CAAC;YAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC;QACpD,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QACxC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACtC,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,eAAe,CAAC,KAA0B,EAAE,KAAa,EAAE,GAAW;IACpF,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,KAAK,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;AAC3H,CAAC;AAQD;;;;;GAKG;AACH,MAAM,OAAO,eAAe;IAIG;IAHZ,OAAO,GAAG,IAAI,GAAG,EAA2C,CAAC;IAC7D,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAC;IAE7D,YAA6B,OAAwF,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE;QAAxH,SAAI,GAAJ,IAAI,CAAoH;IAAG,CAAC;IAEzJ,KAAK,CAAC,QAAQ,CAAC,MAAwB,EAAE,OAAe,EAAE,MAAc;QACtE,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC/D,MAAM,GAAG,GAAG,GAAG,OAAO,SAAS,MAAM,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,GAAG,MAAM,CAAC;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,EAAE,GAAG,GAAG;YAAE,OAAO,MAAM,CAAC,MAAM,CAAC;QACtE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YAC5D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAG,6DAA6D;YACzF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACvD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC;YACzC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,GAAG;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAe,CAAC,CAAC;YAChG,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,IAAI,CAAC,MAAwB,EAAE,OAAe,EAAE,MAAc;QACpE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC;QACjD,OAAO,IAAI,OAAO,CAAU,OAAO,CAAC,EAAE;YACpC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC;YAC1D,KAAgC,CAAC,KAAK,EAAE,EAAE,CAAC;YAC5C,IAAI,KAAuB,CAAC;YAC5B,IAAI,CAAC;gBAAC,KAAK,GAAG,MAAM,CAAC,aAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAAC,CAAC;YACjG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3H,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,0FAA0F;AAC1F,MAAM,CAAC,MAAM,yBAAyB,GAAwB,IAAI,GAAG,CAAC,CAAC,oBAAoB,EAAE,sBAAsB,CAAC,CAAC,CAAC;AAEtH;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC"}
package/dist/types.d.ts CHANGED
@@ -345,6 +345,12 @@ export interface WebConfig {
345
345
  echo_to_channel?: boolean;
346
346
  /** Show the AI subscription usage panel on /view and serve /api/ai-usage (default true). */
347
347
  usage_panel?: boolean;
348
+ /**
349
+ * #2122: serve the usage report (Fleet → Usage, GET /ui/usage-report) over the temporary public link too (default
350
+ * false). It is up to 400 days of per-agent, per-model, per-profile activity and amounts — more than the live quota
351
+ * rail or the cache report the link already shows. Guests never get it.
352
+ */
353
+ usage_report_on_public_link?: boolean;
348
354
  /**
349
355
  * #1937: the largest file the web chat takes, in MB (whole number, 1–500; default 50). Never more than
350
356
  * upload_max_total_mb; over the public link a file is at most 95 MB whatever this says (the quick tunnel's limit).
@@ -378,7 +384,7 @@ export interface WebConfig {
378
384
  /**
379
385
  * #1620: how long a web session lasts. Only the LOCAL surface (the dashboard reached directly — loopback, a LAN, a
380
386
  * tailnet) is configurable; a public-link session's limits stay fixed. Hours, 1 ≤ idle_hours ≤ absolute_hours ≤ 720;
381
- * defaults 12 (absolute, from sign-in) and 2 (idle, since the last use). Shortening applies to existing sessions.
387
+ * defaults 48 (absolute, from sign-in) and 48 (idle, since the last use; #1670). Shortening applies to existing sessions.
382
388
  */
383
389
  session?: {
384
390
  local?: {
@@ -404,6 +410,60 @@ export interface WebConfig {
404
410
  * instead of it; web.preview: false turns previews off everywhere.
405
411
  */
406
412
  preview_on_public_link?: boolean;
413
+ /**
414
+ * #1629: agents' own web themes and effects. `agent_edit` (default true): false refuses every agent appearance write,
415
+ * fleet-wide; what is stored stays, and people can still reset and lock.
416
+ */
417
+ themes?: {
418
+ agent_edit?: boolean;
419
+ };
420
+ /**
421
+ * #1629 r4.1 Q3 (b): the identity card's upload limits and each agent's picture quota. Defaults: portrait
422
+ * 1024×1536 / 1536 KiB, banner 1600×600 / 768 KiB, quota 8 files / 4 MiB. A value outside its hard bound is clamped
423
+ * (and warned about); a change applies to new uploads only.
424
+ */
425
+ appearance?: import("./web-appearance-limits.js").AppearanceLimitsConfig;
426
+ /**
427
+ * #1920: guest web sign-in — a non-admin signed in as their own Discord or Telegram account, seeing only the instances
428
+ * they already use in chat (derived on every request). Default off.
429
+ */
430
+ guests?: WebGuestsConfig;
431
+ /**
432
+ * #1939: when a signed-in web session's messages carry authority (docs/design/1939-verified-web-sessions.md §3).
433
+ * S1 records it in receipts only; no agent acts on it yet.
434
+ */
435
+ verified_authority?: WebVerifiedAuthorityConfig;
436
+ }
437
+ /** #1939: fleet.yaml `web.verified_authority` (docs/design/1939-verified-web-sessions.md §0, §3, §10). */
438
+ export interface WebVerifiedAuthorityConfig {
439
+ /**
440
+ * The server switch (§10): web messages carry authority only while it is on (default true, §0.1). Turning it off makes
441
+ * every web authority read as none at once; turning it back on never brings back authority given before.
442
+ */
443
+ enabled?: boolean;
444
+ /** "Only this computer can authorize": only loopback requests qualify (default false: LAN and tailnet too). */
445
+ loopback_only?: boolean;
446
+ /** A session's authorization lasts this many hours after it was given, 1–48 (default 48). */
447
+ max_session_hours?: number;
448
+ }
449
+ /** #1920: fleet.yaml `web.guests`. */
450
+ export interface WebGuestsConfig {
451
+ /** Guest sign-in at all (default false). Turning it off ends every guest session. */
452
+ enabled?: boolean;
453
+ /** Guests may chat (default true); false: read-only. */
454
+ chat?: boolean;
455
+ /**
456
+ * An `open` connection's guests reach nothing until an admin names instances here, per connection id (the user's
457
+ * decision: least privilege, since an open group has no list of people).
458
+ */
459
+ open_instances?: Record<string, string[]>;
460
+ /** An admin's narrowing, per `<connection id>:<user id>`: intersected with the derived scope, never widening it. */
461
+ narrow?: Record<string, string[]>;
462
+ /** A guest session's limits: absolute 1–24 h (default 12), idle 15–720 min (default 120). */
463
+ session?: {
464
+ absolute_hours?: number;
465
+ idle_minutes?: number;
466
+ };
407
467
  }
408
468
  /** `login:` section — remote /login behaviour. */
409
469
  export interface LoginConfig {
@@ -0,0 +1,233 @@
1
+ /** #1629: one session-only app effect owner. Importing this module starts nothing. */
2
+ import { appStore } from "/assets/app-store.js";
3
+ import { motionBlocked, onMotionChange } from "/assets/fx-motion.js";
4
+ import { navStore } from "/assets/app-nav.js";
5
+ import { onPrefsChanged } from "/assets/app-prefs.js";
6
+ import { resolvedMode, themesStore, themesShown } from "/assets/app-themes.js";
7
+ import { ownerCssLifecycle, safeMode } from "/assets/owner-css.js";
8
+ import { constrainedDevice } from "/assets/effect-policy.js";
9
+ import { createAppEffectRuntime } from "/assets/effect-app-runtime.js";
10
+ import { effectBootstrapReady } from "/assets/effect-frame.js";
11
+ import { createEffectCursor } from "/assets/effect-cursor.js";
12
+ import { createOwnerEffectRegions } from "/assets/effect-owner-regions.js";
13
+ import { chatEffectIdentity, effectPlaybackIdentity } from "/assets/effect-chat-runtime.js";
14
+ import { createEffectTrialController } from "./effect-trial-controller.js";
15
+ import { effectTrialMessage } from "./effect-trial-offer.js";
16
+ import { claimPanel, panelVersion, panelStore, openTrialPanel, closePanel } from "./preview-panel.js";
17
+ const owners = new WeakMap();
18
+ export function getAppEffects(host = window) { const value = owners.get(host); return value && !value.dead && value.api?.ok ? value : null; }
19
+
20
+ /** Boot once with the page's Chat store, including when the first visible panel is Fleet. */
21
+ export function startAppEffects({ store, window: host = window, factories = {} } = {}) {
22
+ const existing = owners.get(host);
23
+ if (existing) { if (!existing.dead) existing.bindStore(store); return getAppEffects(host); }
24
+ const playbackIdentity = effectPlaybackIdentity(host), ownerIdentity = chatEffectIdentity(host);
25
+ if (!playbackIdentity || typeof host.AgendAuth?.onSessionEnd !== "function" || typeof host.AgendAuth?.sessionEnded !== "function") return null;
26
+ const doc = host.document, releases = [], ended = new Set(), updates = new Set(), trialUpdates = new Set(); let replyOff = null, replyStore = null, regions = null, cursor = null, cursorStamp = null, trialControl = null, trialIntent = null, trialHint = ownerIdentity ? null : false, trialSerial = 0, trialStamp = null, chatBinding = null;
27
+ const safe = fn => { try { return fn(); } catch { return null; } };
28
+ const hold = off => { if (entry.dead) safe(() => off?.()); else releases.push(off); };
29
+ const entry = { dead: false, api: null,
30
+ cursorSnapshot: () => cursor?.snapshot() ?? { status: "unavailable", id: null },
31
+ gates: () => context(),
32
+ subscribe(fn) { if (typeof fn !== "function" || entry.dead) return () => {}; updates.add(fn); return () => updates.delete(fn); },
33
+ subscribeTrial(fn) { if (typeof fn !== "function" || entry.dead) return () => {}; trialUpdates.add(fn); return () => trialUpdates.delete(fn); },
34
+ onEnd(fn) { if (typeof fn !== "function") return () => {}; if (entry.dead) { safe(fn); return () => {}; } ended.add(fn); return () => ended.delete(fn); },
35
+ bindStore(value) {
36
+ if (entry.dead || value === replyStore) return;
37
+ safe(() => replyOff?.()); replyOff = null; replyStore = value;
38
+ trialControl?.stop(); chatBinding = null; entry.api?.detachChat();
39
+ if (typeof value?.onAgentReply === "function") {
40
+ const off = value.onAgentReply(event => { if (!entry.dead && replyStore === value) entry.api?.reply(event); });
41
+ if (entry.dead || replyStore !== value) safe(() => off?.()); else replyOff = off;
42
+ }
43
+ },
44
+ trialStatus(message) {
45
+ const offer = safe(() => effectTrialMessage(message)), nav = navStore.get();
46
+ const now = safe(() => host.Date.now());
47
+ if (!offer || !Number.isFinite(now) || now >= offer.expiresAt) return "expired";
48
+ if (trialHint === null && !entry.dead) return "checking";
49
+ if (entry.dead || !trialHint || trialControl?.ok !== true) return "localAdmin";
50
+ if (!chatBinding || safe(() => chatBinding.current()) !== true || message.instance !== nav.route?.instance || nav.route?.panel !== "chat") return "chatChanged";
51
+ const state = trialControl.snapshot();
52
+ if (state.phase !== "idle" || state.busy) return "busy";
53
+ return trialPlaybackStatus();
54
+ },
55
+ trialFailure(message) {
56
+ const offer = safe(() => effectTrialMessage(message)), state = trialControl?.snapshot();
57
+ return offer && state?.phase === "idle" && state.offer === offer.offer && !["stopped", "replaced"].includes(state.reason) ? state.reason : null;
58
+ },
59
+ canTry(message) { return entry.trialStatus(message) === "ready"; },
60
+ stopTrial() { trialControl?.stop(); },
61
+ startTrial(message) {
62
+ if (!entry.canTry(message)) return Promise.resolve(false);
63
+ const nav = navStore.get(); trialIntent = { name: message.instance, seq: nav.seq, claim: claimPanel(), handle: null, chat: chatBinding };
64
+ return trialControl.start(message);
65
+ },
66
+ attachChat(options) {
67
+ const nav = navStore.get(), name = options?.name;
68
+ if (entry.dead || !entry.api?.ok || nav.route?.panel !== "chat" || nav.route.instance !== name || typeof options.current !== "function") return null;
69
+ const binding = { current: () => !entry.dead && host.document === doc && navStore.get().seq === nav.seq && navStore.get().route?.panel === "chat" && navStore.get().route?.instance === name && options.current() === true };
70
+ chatBinding = binding; trialControl?.stop();
71
+ if (entry.dead || chatBinding !== binding) return null;
72
+ const handle = entry.api.attachChat({ ...options, current: () => chatBinding === binding && binding.current() });
73
+ if (entry.dead || chatBinding !== binding) { safe(() => handle?.dispose()); return null; }
74
+ if (!handle) chatBinding = null;
75
+ return handle;
76
+ },
77
+ dispose() {
78
+ if (entry.dead) return; entry.dead = true;
79
+ safe(() => trialControl?.dispose()); safe(() => entry.api?.dispose()); safe(() => replyOff?.()); replyOff = null; replyStore = null;
80
+ for (const off of releases.splice(0)) safe(off);
81
+ updates.clear(); trialUpdates.clear(); const listeners = [...ended]; ended.clear(); for (const fn of listeners) safe(fn);
82
+ },
83
+ };
84
+ owners.set(host, entry); // Reentrant setup never constructs another owner.
85
+ let media, coarse;
86
+ function ownerCssForPlayback() {
87
+ if (doc.body.dataset.tier !== "guest") return ownerCssLifecycle.get().state;
88
+ // Guests never install owner CSS. Prove its absence rather than borrowing the uninstalled
89
+ // lifecycle's initial unknown, and refuse unexpected styles instead of trusting a missing id.
90
+ try {
91
+ if (doc.body.dataset.ownerCss || doc.querySelectorAll("#owner-css").length) return "unknown";
92
+ // A CSP-refused or disabled STYLE has no paint. Recheck on every proof so enabling
93
+ // it never borrows an earlier absence verdict (WebKit capture inserts a refused no-op).
94
+ for (const style of doc.querySelectorAll("style")) if (style.sheet && style.sheet.disabled !== true) return "unknown";
95
+ const allowed = new Set(["/assets/tokens.css", "/assets/app.css"]);
96
+ for (const link of doc.querySelectorAll('link[rel~="stylesheet"]')) {
97
+ const url = new URL(link.getAttribute("href"), host.location.origin);
98
+ if (url.origin !== host.location.origin || !allowed.has(url.pathname) || url.search || url.hash) return "unknown";
99
+ }
100
+ return "off";
101
+ } catch { return "unknown"; }
102
+ }
103
+ function guestChatVersion(value) {
104
+ if (doc.body.dataset.tier !== "guest") return null;
105
+ const name = navStore.get().route?.instance, v = value.instances?.find(i => i.name === name)?.effect_chat_v;
106
+ return typeof v === "string" && /^[a-f0-9]{32}$/.test(v) ? v : null;
107
+ }
108
+ function context() {
109
+ return { safe: safeMode(), publicLink: doc.body.dataset.publicLink === "1", reducedMotion: motionBlocked(host), saveData: host.navigator?.connection?.saveData === true,
110
+ hidden: doc.visibilityState !== "visible", enabled: entry.api?.playbackAvailable !== false && typeof host.OffscreenCanvas === "function" && typeof host.Worker === "function" && typeof host.MutationObserver === "function" && typeof host.ResizeObserver === "function",
111
+ show: themesShown(), transportReady: effectBootstrapReady(host, host.location?.origin, doc.body.dataset.effectBoot),
112
+ constrained: constrainedDevice({ memory: host.navigator?.deviceMemory, cores: host.navigator?.hardwareConcurrency, coarse: coarse?.matches === true, width: host.innerWidth }),
113
+ modal: !!doc.querySelector("dialog[open],.menu-list,.pop,[role=alertdialog],.oc-keep,.shell.sb-open"), openInstance: null };
114
+ }
115
+ function trialCurrent(name) {
116
+ const intent = trialIntent, nav = navStore.get();
117
+ return !entry.dead && host.document === doc && !!intent && !!intent.chat && chatBinding === intent.chat && intent.chat.current() === true && intent.name === name && nav.seq === intent.seq && nav.route?.panel === "chat" && nav.route.instance === name
118
+ && (panelVersion() === intent.claim || intent.handle !== null && panelStore.get().open?.handle === intent.handle);
119
+ }
120
+ // One priority order feeds both presentation and redraw identity: false→different-false must redraw.
121
+ function trialPlaybackStatus() {
122
+ const c = context();
123
+ if (c.safe) return "safe";
124
+ if (!c.show) return "effectsOff";
125
+ if (c.reducedMotion) return "reducedMotion";
126
+ if (!c.enabled) return "unsupported";
127
+ if (!c.transportReady) return "transport";
128
+ if (c.publicLink) return "localAdmin";
129
+ if (c.hidden || doc.hasFocus?.() !== true) return "inactive";
130
+ if (c.modal) return "dialog";
131
+ return "ready";
132
+ }
133
+ function trialAllowed() {
134
+ const c = context();
135
+ return !entry.dead && doc.visibilityState === "visible" && doc.hasFocus?.() === true
136
+ && c.enabled && c.show && c.transportReady && !c.safe && !c.publicLink && !c.reducedMotion && !c.hidden && !c.modal;
137
+ }
138
+ function mountTrial(handle) {
139
+ const intent = trialIntent; if (!intent || !trialCurrent(handle.instance) || !handle.current() || !Number.isSafeInteger(++trialSerial)) throw Error("trial_unavailable");
140
+ intent.handle = handle;
141
+ const binding = Object.freeze({ key: `trial:${trialSerial}:${handle.reply.trial}`, id: handle.reply.offer.id, run: handle.reply.trial, instance: handle.instance, generation: trialSerial });
142
+ let stage = null, source = null;
143
+ const cleanup = () => {
144
+ safe(() => source?.stop()); safe(() => stage?.dispose());
145
+ if (panelStore.get().open?.handle === handle) closePanel();
146
+ };
147
+ try {
148
+ openTrialPanel({ key: binding.key, instance: handle.instance, binding, handle,
149
+ onStage(value) {
150
+ stage = value;
151
+ if (!handle.current()) { cleanup(); handle.stop(); return; }
152
+ source = entry.api.attachTrial({ reply: handle.reply, offer: handle.reply.offer.offer, startedAt: handle.startedAt, stage,
153
+ current: handle.current, onStop: handle.stop });
154
+ if (!source) { cleanup(); handle.stop(); }
155
+ },
156
+ });
157
+ } catch (error) { cleanup(); throw error; }
158
+ return cleanup;
159
+ }
160
+ function notifyTrial() {
161
+ if (entry.dead) return;
162
+ const nav = navStore.get(), next = JSON.stringify([trialHint, safe(() => chatBinding?.current()) === true, trialPlaybackStatus(), nav.route?.panel, nav.route?.instance, trialControl?.snapshot()]);
163
+ if (next === trialStamp) return; trialStamp = next;
164
+ for (const fn of [...trialUpdates]) safe(fn);
165
+ }
166
+ const notify = () => { if (!entry.dead) { trialControl?.sync(); notifyTrial(); for (const fn of [...updates]) safe(fn); } };
167
+ const cursorDragging = () => doc.body.classList?.contains("side-resizing") === true || !!doc.querySelector(".chat-split.resizing");
168
+ function syncCursor() {
169
+ if (entry.dead || !cursor) return;
170
+ const c = context();
171
+ cursor.update(entry.api?.cursorSelection?.() ?? null, c.enabled && c.show && c.transportReady && !c.safe && !c.publicLink && !c.reducedMotion && !c.hidden && !c.modal && !cursorDragging());
172
+ }
173
+ try {
174
+ if (appStore.get().connection === "ended") { entry.dispose(); return null; }
175
+ media = host.matchMedia?.("(prefers-reduced-motion: reduce)") ?? { matches: true };
176
+ coarse = host.matchMedia?.("(pointer: coarse)") ?? { matches: false };
177
+ entry.api = (factories.runtime ?? createAppEffectRuntime)({ window: host, current: () => !entry.dead && host.document === doc,
178
+ observe: () => ({ context: context(), ownerCss: ownerCssForPlayback(), mode: resolvedMode() }), onDispose: () => entry.dispose(),
179
+ resolveOwnerTarget: (slot, manifest, proof) => !entry.dead ? regions?.resolve?.(slot, manifest.box, proof) ?? null : null,
180
+ onChange: () => { syncCursor(); notify(); } });
181
+ if (entry.dead || !entry.api.ok) { entry.dispose(); return null; }
182
+ if (ownerIdentity) trialControl = (factories.trialController ?? createEffectTrialController)({ window: host, current: trialCurrent, allowed: trialAllowed, onStart: mountTrial, onChange: notify });
183
+ hold(() => trialControl?.dispose());
184
+ if (ownerIdentity && typeof host.AgendAuth.trialSession === "function") Promise.resolve().then(() => host.AgendAuth.trialSession()).then(value => {
185
+ if (entry.dead) return; trialHint = value?.localAdmin === true && value.epoch === chatEffectIdentity(host)?.epoch; notify();
186
+ }).catch(() => { if (!entry.dead) { trialHint = false; notify(); } });
187
+ hold(panelStore.subscribe(() => { trialControl?.sync(); notifyTrial(); }));
188
+ const ownRegions = ownerIdentity && (factories.regions ?? createOwnerEffectRegions)({ window: host, current: () => !entry.dead && host.document === doc });
189
+ regions = ownRegions?.ok ? ownRegions : null; hold(() => ownRegions?.dispose?.());
190
+ if (entry.dead) return null;
191
+ const ownCursor = ownerIdentity && safe(() => (factories.cursor ?? createEffectCursor)({ window: host, current: () => !entry.dead && host.document === doc,
192
+ readImage: (selection, signal) => entry.api?.cursorImageSettled?.(selection, signal) ?? Promise.resolve(null),
193
+ onChange(value) { const next = JSON.stringify(value); if (next !== cursorStamp) { cursorStamp = next; notify(); } },
194
+ }));
195
+ cursor = ownCursor?.ok ? ownCursor : null; hold(() => ownCursor?.dispose?.());
196
+ if (entry.dead) return null;
197
+ const sync = () => { if (!entry.dead) { trialControl?.sync(); entry.api.sync(); syncCursor(); notifyTrial(); } };
198
+ let revision = appStore.get().themesRev, prefsRevision = appStore.get().prefsRev, guestRevision = guestChatVersion(appStore.get()), navSeq = navStore.get().seq;
199
+ hold(navStore.subscribe(value => { if (entry.dead || value.seq === navSeq) return; navSeq = value.seq; trialControl?.stop(); chatBinding = null; entry.api.detachChat(); syncCursor(); }));
200
+ hold(appStore.subscribe(value => {
201
+ if (entry.dead) return;
202
+ if (value.connection === "ended") { entry.dispose(); return; }
203
+ const guestNext = guestChatVersion(value), chatChanged = value.themesRev !== revision || guestNext !== guestRevision, ownerChanged = value.prefsRev !== prefsRevision;
204
+ revision = value.themesRev; prefsRevision = value.prefsRev; guestRevision = guestNext;
205
+ if (chatChanged) entry.api.changedChat();
206
+ if (ownerChanged) entry.api.changedOwner();
207
+ if (!chatChanged && !ownerChanged) sync();
208
+ }));
209
+ hold(ownerCssLifecycle.subscribe(sync)); hold(themesStore.subscribe(sync)); hold(onPrefsChanged(sync)); hold(onMotionChange(sync));
210
+ if (typeof host.AgendTheme?.onChange === "function") hold(host.AgendTheme.onChange(sync));
211
+ for (const [target, type] of [[media, "change"], [coarse, "change"], [doc, "visibilitychange"], [host, "resize"], [host.navigator?.connection, "change"]]) {
212
+ if (target?.addEventListener) { target.addEventListener(type, sync); hold(() => target.removeEventListener(type, sync)); }
213
+ }
214
+ if (entry.dead) return null;
215
+ let modal = context().modal, dragging = cursorDragging(), queuedSurface = false;
216
+ // Panel commits can happen after navigation and contain no Chat lease. Reproject fixed owner targets
217
+ // once after stock DOM changes. Body-level effect roots/frames/rules do not schedule themselves.
218
+ const surfaceChanged = () => {
219
+ if (entry.dead || queuedSurface) return; queuedSurface = true;
220
+ Promise.resolve().then(() => { queuedSurface = false; sync(); });
221
+ };
222
+ const barriers = typeof host.MutationObserver === "function" ? new host.MutationObserver(records => {
223
+ if (entry.dead) return;
224
+ const value = context().modal, drag = cursorDragging(); if (value !== modal || drag !== dragging) { modal = value; dragging = drag; sync(); }
225
+ if (Array.isArray(records) && records.some(r => r.target?.closest?.("#app") || r.target === doc.getElementById?.("app"))) surfaceChanged();
226
+ }) : null;
227
+ hold(() => barriers?.disconnect());
228
+ if (entry.dead) return null;
229
+ barriers?.observe(doc.documentElement, { subtree: true, childList: true, attributes: true, attributeFilter: ["class", "open", "hidden", "role"] });
230
+ entry.bindStore(store); sync();
231
+ return getAppEffects(host);
232
+ } catch { entry.dispose(); return null; }
233
+ }